[release] Snap to 78226a8d13

Release-Operation-Build: https://cr-buildbucket.appspot.com/build/8749568851892773009
Change-Id: Ibceef14080b793deeca9500d305ed877e2deec08
diff --git a/BUILD.gn b/BUILD.gn
index d307be4..e496404 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -74,6 +74,20 @@
   # "legacy" version of this argument.
   discoverable_package_labels = []
 
+  # If you add labels to this variable the `exported_fuchsia_package_archive()`
+  # targets captured by these labels will be collected and exposed in the
+  # 'package_archives' build api module. Ordinary `fuchsia_package_archive()`
+  # targets are not captured.
+  #
+  # Note: This variable is only used for metadata collection -- any package
+  # labels added here will still need to be included in the build graph
+  # elsewhere.
+  #
+  # It's usually advisable to use labels of well-defined, curated `group()`s of
+  # packages instead of explicitly adding the labels of the
+  # `exported_fuchsia_package_archive()` targets directly.
+  exported_package_labels = []
+
   # These are arguments used by Infra (and 'fx set') to add tests to a build
   # configuration without necessarily adding them to the assembled product, and
   # validating that they only contain tests of the type in their name.
@@ -191,6 +205,7 @@
     ":images",
     ":licenses",
     ":package-repositories",
+    ":package_archives",
     ":platforms",
     ":prebuilt_binaries",
     ":prebuilt_package_flavors",
@@ -787,6 +802,43 @@
          ] + sdk_archive_labels
 }
 
+# Describes the `exported_package_archive`s labels specified by the gn arg
+# `exported_package_labels` in `$root_build_dir/package_archives.json`.
+#
+# Since some information (like the package's name) cannot be known during the
+# GN gen phase, we instead collect that information during the action/ninja
+# phase, meaning that the full metadata cannot be embed the directly inside
+# `package_archives.json`.
+#
+# Thus, the metadata exposed by this build API module is simply a list of paths
+# to other JSON files; each following this exact schema:
+#
+#   * name
+#     - Required: The name of the archived package.
+#     - Type: string
+#
+#   * label
+#     - Required: GN label of the archived package.
+#     - Type: label_with_toolchain
+#
+#   * path
+#     - Required: Path to the built archive.
+#     - Type: path relative to $root_build_dir
+#
+#   * cpu
+#     - Required: The package's target CPU architecture.
+#     - Type: string
+#
+#   * api_level
+#     - Required: The package's minimum supported API level.
+#     - Type: int
+#
+build_api_module("package_archives") {
+  testonly = true
+  data_keys = [ "exported_package_archives" ]
+  deps = exported_package_labels
+}
+
 # Describes the platforms available for testing, in the file:
 #  "$root_build_dir/platforms.json"
 #
@@ -1749,7 +1801,6 @@
     "//build/images/*",
   ]
   public_deps = [
-    "//:developer_specified_tests",
     "//:hermetic_test_packages",
     "//:test_packages",
   ]
@@ -1783,7 +1834,10 @@
 # by infra or products.
 group("developer_specified_tests") {
   testonly = true
-  visibility = [ ":*" ]
+  visibility = [
+    ":*",
+    "//build/images/updates:universe_packages",
+  ]
   public_deps = developer_test_labels
 }
 
diff --git a/boards/x64/BUILD.gn b/boards/x64/BUILD.gn
index 3b1ef7c..371a983 100644
--- a/boards/x64/BUILD.gn
+++ b/boards/x64/BUILD.gn
@@ -16,15 +16,16 @@
   }
 
   provided_features = [
-    "fuchsia::driver_framework_v2_support",
     "fuchsia::wlan_softmac",
     "fuchsia::paravirtualization",
+    "fuchsia::paver",
   ]
 
   input_bundles = [
     ":main_bundle",
     ":prebuilt_codec_runner",
     ":x64_common",
+    ":paver",
     "//boards/emulation/virtio",
   ]
 
@@ -251,3 +252,7 @@
 board_input_bundle("prebuilt_codec_runner") {
   base_packages = [ "//src/media/codec/codecs/vaapi:codec_runner_intel_gen" ]
 }
+
+board_input_bundle("paver") {
+  bootfs_packages = [ "//src/bringup/bin/paver:package-x64" ]
+}
diff --git a/build/BUILD.gn b/build/BUILD.gn
index cf5d34f..74ec0b9 100644
--- a/build/BUILD.gn
+++ b/build/BUILD.gn
@@ -199,6 +199,7 @@
     "//src/chromium:chromium_web_engine_tests_web_engine_integration_tests",
     "//src/chromium:web_engine_pkg",
     "//src/chromium:web_engine_shell_pkg",
+    "//src/connectivity/bluetooth/core/bt-host:bt-host-oot",
     "//src/connectivity/wlan/drivers/third_party/intel/iwlwifi:iwlwifi",
     "//src/connectivity/wlan/tools/third_party/broadcom:wl_pkg",
     "//src/devices/rtc/drivers/nxp:pcf8563",
diff --git a/build/assembly/BUILD.gn b/build/assembly/BUILD.gn
index 4f94a75..c211375 100644
--- a/build/assembly/BUILD.gn
+++ b/build/assembly/BUILD.gn
@@ -31,7 +31,6 @@
       build_type = "eng"
       feature_set_level = "bootstrap"
       storage = {
-        configure_fshost = true
         filesystems = {
           volume = {
             fvm = {
diff --git a/build/assembly/developer_overrides.gni b/build/assembly/developer_overrides.gni
index 5da6805..88ea1df7 100644
--- a/build/assembly/developer_overrides.gni
+++ b/build/assembly/developer_overrides.gni
@@ -19,10 +19,13 @@
 #       all platform-defined universe packages (such as shell commands) are as
 #       well.
 #
+#   platform
+#     [scope] This is a set of values to override / overlay onto the platform
+#     configuration.
 #
 #   kernel
-#    [scope] This is a set of flags and settings specifically for the kernel.
-#    It's a scope with the following fields (all optional):
+#     [scope] This is a set of flags and settings specifically for the kernel.
+#     It's a scope with the following fields (all optional):
 #
 #    command_line_args (optional; defauilt = [])
 #      [list, strings] A list of kernel command-line arguments to add to the
@@ -51,6 +54,7 @@
     forward_variables_from(invoker,
                            [
                              "developer_only_options",
+                             "platform",
                              "kernel",
                            ])
   }
diff --git a/build/assembly/package_list.gni b/build/assembly/package_list.gni
index ce4533e..70afa91 100644
--- a/build/assembly/package_list.gni
+++ b/build/assembly/package_list.gni
@@ -29,8 +29,13 @@
       "must define a `system_label` argument which points to an assembled_system() invocation")
   assert(defined(invoker.outputs), "must define `outputs`")
   assert(defined(invoker.package_set), "must define `package_set` argument")
-  assert(invoker.package_set == "base" || invoker.package_set == "cache",
-         "must specify either base or cache package set")
+  allowed_package_sets = [
+    "base",
+    "cache",
+  ]
+  assert(allowed_package_sets + [ invoker.package_set ] -
+             [ invoker.package_set ] != allowed_package_sets,
+         "package_set must be one of: ${allowed_package_sets}")
   assert(defined(invoker.contents),
          "must define a `contents` type for dumping package info")
 
diff --git a/build/assembly/cache_packages_from_product_assembler.gni b/build/assembly/packages_from_product_assembler.gni
similarity index 78%
rename from build/assembly/cache_packages_from_product_assembler.gni
rename to build/assembly/packages_from_product_assembler.gni
index 8bd6059..fcf639d 100644
--- a/build/assembly/cache_packages_from_product_assembler.gni
+++ b/build/assembly/packages_from_product_assembler.gni
@@ -9,10 +9,17 @@
 assert(is_fuchsia,
        "Assembly templates can only be used with `$default_toolchain`.")
 
-# Collect a newline-delimited text file of cache packages from the `ffx assembly product` call.
+# Collect a newline-delimited text file of the package manifests for all
+# packages in a given package set from the `ffx assembly product` call.
 #
 # Arguments:
 #
+#   package_set (string, required)
+#     Which package set to get.  Valid values are:
+#       base
+#       cache
+#       on_demand
+#
 #   assembly_label (GN label, required)
 #     Label for the assembled_system() invocation to use, e.g. //build/images/fuchsia.
 #
@@ -30,7 +37,7 @@
 #
 #   testonly
 #   visibility
-template("cache_packages_from_product_assembler") {
+template("packages_from_product_assembler") {
   assert(
       defined(invoker.assembly_label),
       "must define a `assembly_label` argument which points to an assembled_system() invocation")
@@ -40,6 +47,18 @@
   assert(!invoker.is_bazel_assembled || !defined(invoker.namespace),
          "`namespace` is not allowed for Bazel-assembled products!")
 
+  assert(
+      defined(invoker.package_set),
+      "must define a `package_set` argument specifying which package set to list")
+  valid_package_sets = [
+    "base",
+    "cache",
+    "on_demand",
+  ]
+  assert(valid_package_sets + [ invoker.package_set ] -
+             [ invoker.package_set ] != valid_package_sets,
+         "the `package_set` argument must be one of: ${valid_package_sets}")
+
   _assembly_target_name = get_label_info(invoker.assembly_label, "name")
   _assembly_dir = get_label_info(invoker.assembly_label, "dir")
   _assembly_namespace = _assembly_target_name
@@ -66,11 +85,12 @@
                              "testonly",
                              "visibility",
                            ])
-    binary_label =
-        "//build/assembly/scripts:cache_packages_from_product_assembler"
+    binary_label = "//build/assembly/scripts:packages_from_product_assembler"
     args = [
       "--assembly-manifest",
       rebase_path(_assembly_manifest, root_build_dir),
+      "--package-set",
+      invoker.package_set,
       "--output",
       rebase_path(outputs[0], root_build_dir),
     ]
diff --git a/build/assembly/scripts/BUILD.gn b/build/assembly/scripts/BUILD.gn
index cf55167..0a4520d5 100644
--- a/build/assembly/scripts/BUILD.gn
+++ b/build/assembly/scripts/BUILD.gn
@@ -8,8 +8,8 @@
 
 assert(is_host, "Only include assembly build scripts via the host toolchain")
 
-python_binary("cache_packages_from_product_assembler") {
-  main_source = "cache_packages_from_product_assembler.py"
+python_binary("packages_from_product_assembler") {
+  main_source = "packages_from_product_assembler.py"
 }
 
 python_binary("generate_scrutiny_configs") {
diff --git a/build/assembly/scripts/package_list.py b/build/assembly/scripts/package_list.py
index c62ccefb..27b7f20 100644
--- a/build/assembly/scripts/package_list.py
+++ b/build/assembly/scripts/package_list.py
@@ -48,7 +48,10 @@
             for package in contents["packages"][args.package_set]:
                 # Paths in the manifest are relative to the manifest file itself
                 manifest_paths.append(
-                    os.path.join(manifest_path, package[args.contents])
+                    # Normalize the paths to remove internal ../../'s.
+                    os.path.normpath(
+                        os.path.join(manifest_path, package[args.contents])
+                    )
                 )
 
     out_package_manifest_list = {
diff --git a/build/assembly/scripts/cache_packages_from_product_assembler.py b/build/assembly/scripts/packages_from_product_assembler.py
similarity index 71%
rename from build/assembly/scripts/cache_packages_from_product_assembler.py
rename to build/assembly/scripts/packages_from_product_assembler.py
index a297f00..7ef88b5 100644
--- a/build/assembly/scripts/cache_packages_from_product_assembler.py
+++ b/build/assembly/scripts/packages_from_product_assembler.py
@@ -16,7 +16,7 @@
 
 def main():
     parser = argparse.ArgumentParser(
-        description="Parse assembly product output manifest to get cache packages."
+        description="Parse assembly product output manifest to get packages for a particular package set."
     )
     parser.add_argument(
         "--assembly-manifest",
@@ -25,6 +25,11 @@
         help="Path to image_assembly.json created by `ffx assembly product`.",
     )
     parser.add_argument(
+        "--package-set",
+        required=True,
+        help="Package set to get the packages for",
+    )
+    parser.add_argument(
         "--rebase",
         required=False,
         help="Optionally rebase the package manifest paths from the assembly manifest.",
@@ -40,18 +45,22 @@
         args.rebase
     ), "--rebase needs to specify a valid directory path!"
     assembly_manifest = json.load(args.assembly_manifest)
-    cache_package_manifests = [
-        args.rebase.rstrip("/") + "/" + cache_package
-        if args.rebase
-        else cache_package
-        for cache_package in assembly_manifest["cache"]
+    package_manifests = [
+        (
+            # Normalize the rebased path to remove any internal ../..'s.
+            os.path.normpath(args.rebase.rstrip("/") + "/" + package)
+            if args.rebase
+            else package
+        )
+        for package in assembly_manifest[args.package_set]
     ]
     Path(args.output).write_text(
         json.dumps(
             {
-                "content": {"manifests": cache_package_manifests},
+                "content": {"manifests": package_manifests},
                 "version": "1",
-            }
+            },
+            indent=2,
         )
     )
 
diff --git a/build/bazel/assembly/product_configurations/BUILD.bazel b/build/bazel/assembly/product_configurations/BUILD.bazel
index 420e073..0626f65 100644
--- a/build/bazel/assembly/product_configurations/BUILD.bazel
+++ b/build/bazel/assembly/product_configurations/BUILD.bazel
@@ -51,7 +51,6 @@
             "build_type": BUILD_TYPES.ENG,
             "feature_set_level": "bootstrap",
             "storage": {
-                "configure_fshost": True,
                 "filesystems": {
                     "volume": {
                         "fvm": {
diff --git a/build/bazel/bazel_action.gni b/build/bazel/bazel_action.gni
index 15ef34e..6f9ebb1 100644
--- a/build/bazel/bazel_action.gni
+++ b/build/bazel/bazel_action.gni
@@ -580,7 +580,7 @@
     } else if (optimize == "debug") {
       args += [ "--compilation_mode=dbg" ]
     } else if (optimize == "size" || optimize == "speed" ||
-               optimize == "profile") {
+               optimize == "profile" || optimize == "size_lto") {
       args += [ "--compilation_mode=opt" ]
     } else {
       assert("Unsupported mode optimize = $optimize")
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/assembly.bzl b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/assembly.bzl
index a42d390..5abd875 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/assembly.bzl
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/assembly.bzl
@@ -72,6 +72,7 @@
     "//fuchsia/private/assembly:fuchsia_product_configuration.bzl",
     _BUILD_TYPES = "BUILD_TYPES",
     _INPUT_DEVICE_TYPE = "INPUT_DEVICE_TYPE",
+    _fuchsia_prebuilt_product_configuration = "fuchsia_prebuilt_product_configuration",
     _fuchsia_product_configuration = "fuchsia_product_configuration",
 )
 load(
@@ -125,6 +126,7 @@
 fuchsia_package_directory = _fuchsia_package_directory
 fuchsia_package_with_configs = _fuchsia_assemble_package
 fuchsia_product_configuration = _fuchsia_product_configuration
+fuchsia_prebuilt_product_configuration = _fuchsia_prebuilt_product_configuration
 fuchsia_product_ota_config = _fuchsia_product_ota_config
 fuchsia_virtual_device = _fuchsia_virtual_device
 fuchsia_board_configuration = _fuchsia_board_configuration
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/constraints/BUILD.bazel b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/constraints/BUILD.bazel
index 7fa95d7..03349ec 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/constraints/BUILD.bazel
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/constraints/BUILD.bazel
@@ -92,3 +92,40 @@
         ":cpu_riscv64",
     ],
 )
+
+# Variants based configuration
+[
+    selects.config_setting_group(
+        name = "is_%s_api_%s" % (
+            cpu,
+            target_api.api_level,
+        ),
+        match_all = [
+            "@platforms//os:fuchsia",
+            ":cpu_%s" % cpu,
+            ":api_level_%s" % target_api.api_level,
+        ],
+    )
+    for target_api in INTERNAL_ONLY_VALID_TARGET_APIS
+    for cpu in [
+        "arm64",
+        "x64",
+        "riscv64",
+    ]
+]
+
+# Configuration for API level HEAD
+[
+    selects.config_setting_group(
+        name = "is_%s_api_HEAD" % cpu,
+        match_all = [
+            "@platforms//os:fuchsia",
+            ":cpu_%s" % cpu,
+        ],
+    )
+    for cpu in [
+        "arm64",
+        "x64",
+        "riscv64",
+    ]
+]
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_product_bundle.bzl b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_product_bundle.bzl
index 9079e78..7f01918e 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_product_bundle.bzl
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_product_bundle.bzl
@@ -169,6 +169,7 @@
         pb_out_dir,
         platform_scrutiny_config.pre_signing_policy,
         platform_scrutiny_config.pre_signing_goldens_dir,
+        platform_scrutiny_config.pre_signing_goldens,
     ))
     if not is_recovery:
         deps += _verify_route_sources(
@@ -452,7 +453,8 @@
         ffx_tool,
         pb_out_dir,
         pre_signing_policy_file,
-        pre_signing_goldens_dir):
+        pre_signing_goldens_dir,
+        pre_signing_goldens):
     stamp_file = ctx.actions.declare_file(label_name + "_pre_signing.stamp")
     ffx_isolate_dir = ctx.actions.declare_directory(label_name + "_pre_signing.ffx")
     _ffx_invocation = []
@@ -472,7 +474,11 @@
         "set -e",
         " ".join(_ffx_invocation),
     ]
-    inputs = [ffx_tool, pb_out_dir, pre_signing_policy_file]
+
+    # The pre_signing_goldens file list is only specified to avoid providing a dir build input
+    # to bazel. This avoids the "dependency checking of directories is unsound" warning.
+    # The scrutiny invocation itself expects a dir path to be provided.
+    inputs = [ffx_tool, pb_out_dir, pre_signing_policy_file] + pre_signing_goldens
     ctx.actions.run_shell(
         inputs = inputs,
         outputs = [stamp_file, ffx_isolate_dir],
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_product_configuration.bzl b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_product_configuration.bzl
index c1fe3b2..0a2b478 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_product_configuration.bzl
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_product_configuration.bzl
@@ -31,9 +31,15 @@
     TOUCHSCREEN = "touchscreen",
 )
 
-def _create_pkg_detail(dep):
+def _create_pkg_detail(dep, relative = None):
     if FuchsiaPackageInfo in dep:
-        return {"manifest": dep[FuchsiaPackageInfo].package_manifest.path}
+        path = ""
+        if relative:
+            path = dep[FuchsiaPackageInfo].package_manifest.path.removeprefix(relative + "/")
+        else:
+            path = dep[FuchsiaPackageInfo].package_manifest.path
+
+        return {"manifest": path}
 
     package = dep[FuchsiaAssembledPackageInfo].package
     configs = dep[FuchsiaAssembledPackageInfo].configs
@@ -57,13 +63,16 @@
     product_config = json.decode(ctx.attr.product_config)
     product_config_file = ctx.actions.declare_file(ctx.label.name + "_product_config.json")
 
+    relative_base = None
+
+    # If relative_paths is set, relativize paths in the product config relative
+    # to the directory containing the product config.
+    # Otherwise, paths are relative to the execroot.
     if (ctx.attr.relative_paths):
-        # Relativize paths in the product config relative to the directory
-        # containing the product config
-        replace_labels_with_files(product_config, ctx.attr.product_config_labels, relative = product_config_file.dirname)
-    else:
-        # Use absolute paths
-        replace_labels_with_files(product_config, ctx.attr.product_config_labels)
+        relative_base = product_config_file.dirname
+
+    replace_labels_with_files(product_config, ctx.attr.product_config_labels, relative = relative_base)
+
     platform = product_config.get("platform", {})
     build_type = platform.get("build_type")
     product = product_config.get("product", {})
@@ -72,13 +81,13 @@
     output_files = []
     base_pkg_details = []
     for dep in ctx.attr.base_packages:
-        base_pkg_details.append(_create_pkg_detail(dep))
+        base_pkg_details.append(_create_pkg_detail(dep, relative_base))
         output_files += _collect_file_deps(dep)
     packages["base"] = base_pkg_details
 
     cache_pkg_details = []
     for dep in ctx.attr.cache_packages:
-        cache_pkg_details.append(_create_pkg_detail(dep))
+        cache_pkg_details.append(_create_pkg_detail(dep, relative_base))
         output_files += _collect_file_deps(dep)
     packages["cache"] = cache_pkg_details
     product["packages"] = packages
@@ -129,6 +138,36 @@
         ),
     ]
 
+def _fuchsia_prebuilt_product_configuration_impl(ctx):
+    return [
+        DefaultInfo(files = depset(direct = ctx.files.files)),
+        FuchsiaProductConfigInfo(
+            product_config = ctx.file.product_config,
+            build_type = ctx.attr.build_type,
+        ),
+    ]
+
+_fuchsia_prebuilt_product_configuration = rule(
+    doc = "Use a prebuilt product configuration directory for hybrid assembly.",
+    implementation = _fuchsia_prebuilt_product_configuration_impl,
+    toolchains = ["@fuchsia_sdk//fuchsia:toolchain"],
+    attrs = {
+        "product_config": attr.label(
+            doc = "The product assembly input artifacts directory containing the product config.",
+            allow_single_file = True,
+            mandatory = True,
+        ),
+        "files": attr.label_list(
+            doc = "All files referenced by the product config. This should be the entire contents of the product input artifacts directory.",
+            mandatory = True,
+        ),
+        "build_type": attr.string(
+            doc = "Build type of the product config. Must match the prebuilts.",
+            mandatory = True,
+        ),
+    },
+)
+
 _fuchsia_product_configuration = rule(
     doc = """Generates a product configuration file.""",
     implementation = _fuchsia_product_configuration_impl,
@@ -179,6 +218,25 @@
     },
 )
 
+def fuchsia_prebuilt_product_configuration(
+        name,
+        product_config_dir,
+        product_config_filename,
+        build_type,
+        **kwargs):
+    _all_files_target = "{}_all_files".format(name)
+    native.filegroup(
+        name = _all_files_target,
+        srcs = native.glob(["{}/**/*".format(product_config_dir)]),
+    )
+    _fuchsia_prebuilt_product_configuration(
+        name = name,
+        product_config = product_config_dir + "/" + product_config_filename,
+        files = [":{}".format(_all_files_target)],
+        build_type = build_type,
+        **kwargs
+    )
+
 def fuchsia_product_configuration(
         name,
         product_config_json = None,
@@ -187,7 +245,7 @@
         base_driver_packages = None,
         ota_configuration = None,
         relative_paths = False,
-        **kwarg):
+        **kwargs):
     """A new implementation of fuchsia_product_configuration that takes raw a json config.
 
     Args:
@@ -215,7 +273,9 @@
         cache_packages: Fuchsia packages to be included in cache.
         base_driver_packages: Base driver packages to include in product.
         ota_configuration: OTA configuration to use with the product.
-        **kwarg: Common bazel rule args passed through to the implementation rule.
+        relative_paths: Whether to generate an Assembly product configuration
+            with relative path, so it can be relocated.
+        **kwargs: Common bazel rule args passed through to the implementation rule.
     """
 
     json_config = product_config_json
@@ -232,6 +292,6 @@
         cache_packages = cache_packages,
         base_driver_packages = base_driver_packages,
         ota_configuration = ota_configuration,
-        relative_paths = False,
-        **kwarg
+        relative_paths = relative_paths,
+        **kwargs
     )
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_scrutiny_config.bzl b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_scrutiny_config.bzl
index b0f2374..3464264 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_scrutiny_config.bzl
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/fuchsia_scrutiny_config.bzl
@@ -25,6 +25,7 @@
             structured_config_policy = ctx.file.structured_config_policy,
             pre_signing_policy = ctx.file.pre_signing_policy,
             pre_signing_goldens_dir = ctx.file.pre_signing_goldens_dir,
+            pre_signing_goldens = ctx.files.pre_signing_goldens,
         ),
     ]
 
@@ -81,5 +82,9 @@
             doc = "Directory containing golden files for pre-signing checks.",
             allow_single_file = True,
         ),
+        "pre_signing_goldens": attr.label_list(
+            doc = "List of golden files for pre-signing checks to be used as build inputs.",
+            allow_files = True,
+        ),
     },
 )
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/BUILD.bazel b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/BUILD.bazel
index 0248ff0..e2cbdc2 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/BUILD.bazel
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/BUILD.bazel
@@ -13,6 +13,7 @@
     bootfs_packages = ["bootfs_packages_user.txt"],
     component_resolver_allowlist = "component_resolver_allowlist.json5",
     kernel_cmdline = ["kernel_cmdline_user.txt"],
+    pre_signing_goldens = glob(["pre_signing/**"]),
     pre_signing_goldens_dir = "pre_signing",
     pre_signing_policy = "pre_signing_user.json5",
     routes_config_golden = "verify_route_sources_user.json5",
@@ -26,6 +27,7 @@
     bootfs_packages = ["bootfs_packages_userdebug.txt"],
     component_resolver_allowlist = "component_resolver_allowlist.json5",
     kernel_cmdline = ["kernel_cmdline_userdebug.txt"],
+    pre_signing_goldens = glob(["pre_signing/**"]),
     pre_signing_goldens_dir = "pre_signing",
     pre_signing_policy = "pre_signing_userdebug.json5",
     routes_config_golden = "verify_route_sources_userdebug.json5",
@@ -39,6 +41,7 @@
     bootfs_packages = ["bootfs_packages_user.txt"],
     component_resolver_allowlist = "component_resolver_allowlist.json5",
     kernel_cmdline = ["kernel_cmdline_user.txt"],
+    pre_signing_goldens = glob(["pre_signing/**"]),
     pre_signing_goldens_dir = "pre_signing",
     pre_signing_policy = "pre_signing_user.recovery.json5",
     routes_config_golden = "verify_route_sources_user.json5",
@@ -52,6 +55,7 @@
     bootfs_packages = ["bootfs_packages_userdebug.txt"],
     component_resolver_allowlist = "component_resolver_allowlist.json5",
     kernel_cmdline = ["kernel_cmdline_userdebug.txt"],
+    pre_signing_goldens = glob(["pre_signing/**"]),
     pre_signing_goldens_dir = "pre_signing",
     pre_signing_policy = "pre_signing_userdebug.recovery.json5",
     routes_config_golden = "verify_route_sources_userdebug.json5",
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/README.md b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/README.md
index 66765ca..f711561 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/README.md
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/README.md
@@ -8,4 +8,18 @@
 
 In order to deduplicate the policy, the signing server should run the Scrutiny verifiers at signing time. The effort to enable this is tracked at b/311208337.
 
-Please consult with the security team if any checks need to be updated or removed.
\ No newline at end of file
+Please consult with the security team if any checks need to be updated or removed.
+
+## Pre-signing Golden Files
+
+sshd_config_userdebug - this golden file acts a change detector for third_party/openssh-portable/fuchsia/sshd_config. This is currently how the security team ensures a secure sshd configuration for userdebug builds.
+
+To change this file, a migration strategy is recommended as follows:
+1. Notify the security team so back-end changes can be prepared.
+2. Add a copy of the updated sshd_config to the pre_signing/ folder in this dir.
+3. Update the pre_signing_userdebug.json5 policy file to add an entry for the updated golden in the matches_golden check.
+4. Land the CL for steps (2) and (3)
+5. Land the sshd_config change to openssh-portable.
+6. Remove the previous sshd_config_userdebug golden file.
+7. Rename the updated sshd_config to sshd_config_userdebug.
+8. Update pre_signing_userdebug.json5 to only use the new sshd_config_userdebug file in the matches_golden check.
\ No newline at end of file
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/bootfs_packages_user.txt b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/bootfs_packages_user.txt
index b68bdf0..0526403 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/bootfs_packages_user.txt
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/bootfs_packages_user.txt
@@ -36,7 +36,7 @@
 ?minfs
 netdevice-migration
 network-device
-paver
+?paver
 pkg-cache
 platform-bus
 power
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/bootfs_packages_userdebug.txt b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/bootfs_packages_userdebug.txt
index 4c3aa48..d06f2207 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/bootfs_packages_userdebug.txt
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/bootfs_packages_userdebug.txt
@@ -39,7 +39,7 @@
 netdevice-migration
 ?netsvc
 network-device
-paver
+?paver
 pkg-cache
 platform-bus
 power
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/kernel_cmdline_user.txt b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/kernel_cmdline_user.txt
index 67a25df..a2bfa412 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/kernel_cmdline_user.txt
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/kernel_cmdline_user.txt
@@ -8,6 +8,7 @@
 ?kernel.enable-debugging-syscalls=false
 ?kernel.enable-serial-syscalls=false
 ?kernel.oom.behavior=reboot
+?kernel.oom.evict-continuous=true
 ?kernel.page-scanner.lru-action=compress_only
 ?kernel.ppb.borrow-in-supplypages=true
 ?kernel.ppb.borrow-on-mru=true
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/kernel_cmdline_userdebug.txt b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/kernel_cmdline_userdebug.txt
index ee43b93..bfdac46 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/kernel_cmdline_userdebug.txt
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/kernel_cmdline_userdebug.txt
@@ -12,6 +12,7 @@
 ?kernel.enable-serial-syscalls=output-only
 ?kernel.enable-serial-syscalls=true
 ?kernel.oom.behavior=reboot
+?kernel.oom.evict-continuous=true
 ?kernel.page-scanner.lru-action=compress_only
 ?kernel.ppb.borrow-in-supplypages=true
 ?kernel.ppb.borrow-on-mru=true
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing/placeholder b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing/placeholder
deleted file mode 100644
index 2ce361b..0000000
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing/placeholder
+++ /dev/null
@@ -1 +0,0 @@
-TODO(b/303923440): swap this placeholder with the actual golden file
\ No newline at end of file
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing/sshd_config_userdebug b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing/sshd_config_userdebug
new file mode 100644
index 0000000..5b67581
--- /dev/null
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing/sshd_config_userdebug
@@ -0,0 +1,42 @@
+HostKey /data/ssh/ssh_host_ed25519_key
+
+LogLevel ERROR
+
+# Zero or more authorized_keys files may be present under different scenarios:
+#   /data - authorized_keys are typically read from here when running on hardware, copied into minfs
+#           during the paving process.
+#   /boot - authorized_keys should only present be in bootfs when running Fuchsia in an emulator.
+#   /config/data/authorized_keys - This file is not expected to be present on standard builds, only
+#           on those that need to inject keys for special circumstances, such as when being tested
+#           from automated infrastructure.
+#           See go/fuchsia-ssh-for-testing for more informaton on that.
+#
+# These are combined since the sshd will only use the first AuthorizedKeysFile line.
+AuthorizedKeysFile /data/ssh/authorized_keys /boot/data/ssh/authorized_keys /config/data/authorized_keys
+
+# Enable SSH using Certificate Authority-issued SSH credentials.  These are not expected to be
+# present in most builds, and products will add keys to this location in config-data to enable this
+# feature.
+TrustedUserCAKeys /config/data/ssh_ca_pub_keys
+
+# This is an opion specific to the Fuchsia fork which disables validation of the "valid_after" field
+# of CA-signed ssh key certificates, so that ssh can be used when the current time has not been able
+# to be synced with, and the system is using the backstop time.
+IgnoreValidAfter yes
+
+# We disallow password authentication completely (it's unsupported irrespective of this
+# configuration), so all auth is key-based. Bump the MaxAuthTries limit to accommodate users with
+# many keys added to their SSH agent.
+PasswordAuthentication no
+MaxAuthTries 20
+MaxSessions 20
+
+Protocol 2
+TCPKeepAlive yes
+ClientAliveInterval 1
+ClientAliveCountMax 20
+
+Subsystem sftp /pkg/bin/sftp-server
+Subsystem sl4f /pkg/bin/sl4f-server
+
+AcceptEnv FFX_DAEMON_ABI_REVISION
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_user.json5 b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_user.json5
index 5e54ea1a..868d29e 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_user.json5
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_user.json5
@@ -24,6 +24,7 @@
             },
         ],
     },
+    bootfs_file_checks: [],
     package_checks: [
         // Checks involving the system image package.
         {
@@ -33,7 +34,7 @@
                 // tool for use in eng builds.
                 {
                     source: {
-                        MetaContents: "data/static_packages",
+                        PackageMetaContents: "data/static_packages",
                     },
                     state: "Present",
                     content_checks: {
@@ -49,13 +50,13 @@
                 // Ensure that it is absent or empty for user builds.
                 {
                     source: {
-                        MetaContents: "data/cache_packages",
+                        PackageMetaContents: "data/cache_packages",
                     },
                     state: "AbsentOrEmpty",
                 },
                 {
                     source: {
-                        MetaContents: "data/cache_packages.json",
+                        PackageMetaContents: "data/cache_packages.json",
                     },
                     state: "AbsentOrEmpty",
                 },
@@ -64,7 +65,7 @@
                 // The presence of this file disables executability enforcement.
                 {
                     source: {
-                        MetaContents: "data/pkgfs_disable_executability_restrictions",
+                        PackageMetaContents: "data/pkgfs_disable_executability_restrictions",
                     },
                     state: "Absent",
                 },
@@ -95,6 +96,17 @@
                     },
                     state: "Absent",
                 },
+
+                // Ensure sshd_config is absent in user builds.
+                // SSH should not be enabled in user builds.
+                {
+                    source: {
+                        PackageFar: [
+                            "meta/data/sshd-host/sshd_config",
+                        ],
+                    },
+                    state: "Absent",
+                },
             ],
         },
     ],
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_user.recovery.json5 b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_user.recovery.json5
index b8b35b3..f010d04 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_user.recovery.json5
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_user.recovery.json5
@@ -36,6 +36,7 @@
             },
         ],
     },
+    bootfs_file_checks: [],
     package_checks: [
         // Checks involving the system image package.
         {
@@ -45,7 +46,7 @@
                 // tool for use in eng builds.
                 {
                     source: {
-                        MetaContents: "data/static_packages",
+                        PackageMetaContents: "data/static_packages",
                     },
                     state: "Present",
                     content_checks: {
@@ -61,13 +62,13 @@
                 // Ensure that it is absent or empty for user builds.
                 {
                     source: {
-                        MetaContents: "data/cache_packages",
+                        PackageMetaContents: "data/cache_packages",
                     },
                     state: "AbsentOrEmpty",
                 },
                 {
                     source: {
-                        MetaContents: "data/cache_packages.json",
+                        PackageMetaContents: "data/cache_packages.json",
                     },
                     state: "AbsentOrEmpty",
                 },
@@ -76,7 +77,7 @@
                 // The presence of this file disables executability enforcement.
                 {
                     source: {
-                        MetaContents: "data/pkgfs_disable_executability_restrictions",
+                        PackageMetaContents: "data/pkgfs_disable_executability_restrictions",
                     },
                     state: "Absent",
                 },
@@ -84,6 +85,7 @@
         },
 
         // Note: there is no pkg-resolver config check for recovery because pkg-resolver is not
-        // expected to be present on recovery builds.
+        // expected to be present on recovery builds. Similarly, there is no sshd_config check
+        // because sshd is not included in recovery builds.
     ],
 }
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_userdebug.json5 b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_userdebug.json5
index c762e38..0396463 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_userdebug.json5
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_userdebug.json5
@@ -24,6 +24,7 @@
             },
         ],
     },
+    bootfs_file_checks: [],
     package_checks: [
         // Checks involving the system image package.
         {
@@ -33,7 +34,7 @@
                 // tool for use in eng builds.
                 {
                     source: {
-                        MetaContents: "data/static_packages",
+                        PackageMetaContents: "data/static_packages",
                     },
                     state: "Present",
                     content_checks: {
@@ -49,13 +50,13 @@
                 // Ensure that it is absent or empty for userdebug builds.
                 {
                     source: {
-                        MetaContents: "data/cache_packages",
+                        PackageMetaContents: "data/cache_packages",
                     },
                     state: "AbsentOrEmpty",
                 },
                 {
                     source: {
-                        MetaContents: "data/cache_packages.json",
+                        PackageMetaContents: "data/cache_packages.json",
                     },
                     state: "AbsentOrEmpty",
                 },
@@ -64,11 +65,56 @@
                 // The presence of this file disables executability enforcement.
                 {
                     source: {
-                        MetaContents: "data/pkgfs_disable_executability_restrictions",
+                        PackageMetaContents: "data/pkgfs_disable_executability_restrictions",
                     },
                     state: "Absent",
                 },
             ],
         },
+
+        // Checks involving the config data package.
+        {
+            source: {
+                StaticPackages: "config-data",
+            },
+            file_checks: [
+                // Ensure enable_dynamic_configuration is true for userdebug builds.
+                // This allows pkg-resolver to add or rewrite TUF repository rules.
+                {
+                    source: {
+                        PackageFar: [
+                            "meta/data/pkg-resolver/enable_dynamic_config.json",
+                            "meta/data/pkg-resolver/config.json",
+                        ],
+                    },
+                    state: "Present",
+                    content_checks: {
+                        must_contain: [
+                            {
+                                JsonKeyValue: [
+                                    "enable_dynamic_configuration",
+                                    "true",
+                                ],
+                            },
+                        ],
+                    },
+                },
+
+                // Ensure sshd configuration matches expectations for userdebug builds.
+                {
+                    source: {
+                        PackageFar: [
+                            "meta/data/sshd-host/sshd_config",
+                        ],
+                    },
+                    state: "Present",
+                    content_checks: {
+                        matches_golden: [
+                            "sshd_config_userdebug",
+                        ],
+                    },
+                },
+            ],
+        },
     ],
 }
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_userdebug.recovery.json5 b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_userdebug.recovery.json5
index efdc831..d0917f6 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_userdebug.recovery.json5
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/goldens/pre_signing_userdebug.recovery.json5
@@ -36,6 +36,7 @@
             },
         ],
     },
+    bootfs_file_checks: [],
     package_checks: [
         // Checks involving the system image package.
         {
@@ -45,7 +46,7 @@
                 // tool for use in eng builds.
                 {
                     source: {
-                        MetaContents: "data/static_packages",
+                        PackageMetaContents: "data/static_packages",
                     },
                     state: "Present",
                     content_checks: {
@@ -61,13 +62,13 @@
                 // Ensure that it is absent or empty for userdebug builds.
                 {
                     source: {
-                        MetaContents: "data/cache_packages",
+                        PackageMetaContents: "data/cache_packages",
                     },
                     state: "AbsentOrEmpty",
                 },
                 {
                     source: {
-                        MetaContents: "data/cache_packages.json",
+                        PackageMetaContents: "data/cache_packages.json",
                     },
                     state: "AbsentOrEmpty",
                 },
@@ -76,11 +77,15 @@
                 // The presence of this file disables executability enforcement.
                 {
                     source: {
-                        MetaContents: "data/pkgfs_disable_executability_restrictions",
+                        PackageMetaContents: "data/pkgfs_disable_executability_restrictions",
                     },
                     state: "Absent",
                 },
             ],
         },
+
+        // Note: there is no pkg-resolver config check for recovery because pkg-resolver is not
+        // expected to be present on recovery builds. Similarly, there is no sshd_config check
+        // because sshd is not included in recovery builds.
     ],
 }
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/providers.bzl b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/providers.bzl
index 1102d9b..381759d 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/providers.bzl
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/assembly/providers.bzl
@@ -147,6 +147,7 @@
         "structured_config_policy": "File describing the policy of structured config",
         "pre_signing_policy": "File describing the policy of checks required before signing",
         "pre_signing_goldens_dir": "Path to directory containing golden files for pre-signing checks",
+        "pre_signing_goldens": "List of golden files for pre-signing checks to be used as build inputs",
     },
 )
 
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/workflows/fuchsia_task_run_component.bzl b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/workflows/fuchsia_task_run_component.bzl
index 6ddea31..a3ea640 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/workflows/fuchsia_task_run_component.bzl
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/private/workflows/fuchsia_task_run_component.bzl
@@ -53,7 +53,7 @@
     elif component.is_test:
         args = [
             "--ffx",
-            sdk.ffx,
+            sdk.ffx_test,
             "--url",
             url,
         ]
@@ -65,6 +65,10 @@
         return make_fuchsia_task(
             ctx.attr._run_test_component_tool,
             args,
+            runfiles = [
+                sdk.ffx_test_fho_meta,
+                sdk.ffx_test_manifest,
+            ],
         )
     else:
         return make_fuchsia_task(
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/clang_templates/crosstool.BUILD.template b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/clang_templates/crosstool.BUILD.template
index 706f15e..ba32973 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/clang_templates/crosstool.BUILD.template
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/clang_templates/crosstool.BUILD.template
@@ -242,6 +242,9 @@
             # hwasan runtime libraries
             "//:lib/clang/%{CLANG_VERSION}/lib/%s-unknown-fuchsia/libclang_rt.hwasan.so" % cpu,
             "//:lib/clang/%{CLANG_VERSION}/lib/%s-unknown-fuchsia/libclang_rt.hwasan-preinit.a" % cpu,
+
+            # coverage and profiling runtime libraries
+            "//:lib/clang/%{CLANG_VERSION}/lib/%s-unknown-fuchsia/libclang_rt.profile.a" % cpu,
         ],
     )
     for cpu in TARGET_CPUS
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/fuchsia_toolchain_info.bzl b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/fuchsia_toolchain_info.bzl
index db0d3b7..2dd6661 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/fuchsia_toolchain_info.bzl
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/fuchsia_toolchain_info.bzl
@@ -35,6 +35,9 @@
         ffx_scrutiny = ctx.executable.ffx_scrutiny or None,
         ffx_scrutiny_fho_meta = ctx.file.ffx_scrutiny_fho_meta or None,
         ffx_scrutiny_manifest = ctx.file.ffx_scrutiny_manifest or None,
+        ffx_test = ctx.executable.ffx_test or None,
+        ffx_test_fho_meta = ctx.file.ffx_test_fho_meta or None,
+        ffx_test_manifest = ctx.file.ffx_test_manifest or None,
         fssh = ctx.executable.fssh,
         fidlc = ctx.executable.fidlc,
         fidlgen_hlcpp = ctx.executable.fidlgen_hlcpp,
@@ -203,6 +206,20 @@
             doc = "ffx-scrutiny tool metadata.",
             allow_single_file = True,
         ),
+        "ffx_test": attr.label(
+            doc = "ffx-test tool executable.",
+            cfg = "exec",
+            executable = True,
+            allow_single_file = True,
+        ),
+        "ffx_test_fho_meta": attr.label(
+            doc = "ffx-test tool metadata.",
+            allow_single_file = True,
+        ),
+        "ffx_test_manifest": attr.label(
+            doc = "ffx-test tool metadata.",
+            allow_single_file = True,
+        ),
         "fssh": attr.label(
             doc = "fssh tool executable.",
             mandatory = True,
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/constraint.BUILD.template b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/constraint.BUILD.template
deleted file mode 100644
index b7fbca7..0000000
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/constraint.BUILD.template
+++ /dev/null
@@ -1,6 +0,0 @@
-load("@bazel_skylib//lib:selects.bzl", "selects")
-
-selects.config_setting_group(
-    name = "{{name}}",
-    match_all = [{{match_all}}],
-)
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/generate_sdk_build_rules.bzl b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/generate_sdk_build_rules.bzl
index 19774a0..a3b8a17 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/generate_sdk_build_rules.bzl
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/generate_sdk_build_rules.bzl
@@ -36,7 +36,6 @@
     "companion_host_tool": "//fuchsia/workspace/sdk_templates:companion_host_tool.BUILD.template",
     "component_manifest": "//fuchsia/workspace/sdk_templates:component_manifest.BUILD.template",
     "component_manifest_collection": "//fuchsia/workspace/sdk_templates:component_manifest_collection.BUILD.template",
-    "constraint": "//fuchsia/workspace/sdk_templates:constraint.BUILD.template",
     "export_all_files": "//fuchsia/workspace/sdk_templates:export_all_files.BUILD.template",
     "ffx_subtool": "//fuchsia/workspace/sdk_templates:ffx_subtool.BUILD.template",
     "fidl_library": "//fuchsia/workspace/sdk_templates:fidl_library.BUILD.template",
@@ -525,12 +524,16 @@
         return default
     return "//fuchsia/constraints:api_level_%s" % api_level
 
+def _get_api_level(variant):
+    api_level = variant["api_level"]
+    return "HEAD" if _is_undefined_api_level(api_level) else api_level
+
 def _is_undefined_api_level(api_level):
-    return api_level in (-1, "unversioned")
+    return api_level in (-1, "unversioned", "HEAD")
 
 def _api_level_deprecation_message(api_level):
     if _is_undefined_api_level(api_level):
-        return "\"Warning: Dependencies with unspecified API levels are being used, incompatibility may occur.\""
+        return "\"Warning: Dependencies with unstable API levels are being used, incompatibility may occur.\""
     return "None"
 
 # We can't just do f"//:{file}" for file srcs, since the relative dir may have a
@@ -611,14 +614,14 @@
     name = _get_target_name(meta["name"])
     package_variants = [
         struct(
-            name = "%s_%s_api_%s" % (name, variant["arch"], variant["api_level"]),
+            name = "%s_%s_api_%s" % (name, variant["arch"], _get_api_level(variant)),
             files = variant["files"],
             manifest = variant["manifest_file"],
-            deprecation = _api_level_deprecation_message(variant["api_level"]),
-            constraint = "is_%s_api_%s" % (variant["arch"], variant["api_level"]),
+            deprecation = _api_level_deprecation_message(_get_api_level(variant)),
+            constraint = "is_%s_api_%s" % (variant["arch"], _get_api_level(variant)),
             os = "@platforms//os:fuchsia",
             cpu = _FUCHSIA_CPU_CONSTRAINT_MAP[variant["arch"]],
-            api_level = _fuchsia_api_level_constraint(variant["api_level"], None),
+            api_level = _fuchsia_api_level_constraint(_get_api_level(variant), None),
         )
         for variant in meta["variants"]
     ]
@@ -633,19 +636,10 @@
         })
         process_context.files_to_copy[meta["_meta_sdk_root"]].extend(variant.files)
 
-        # Write merged constraint definitions.
-        _merge_template(ctx, build_file, _sdk_template_path(ctx, "constraint"), {
-            "{{name}}": variant.constraint,
-            "{{match_all}}": _get_starlark_list([
-                variant.os,
-                variant.cpu,
-            ] + ([variant.api_level] if variant.api_level else [])),
-        })
-
     _merge_template(ctx, build_file, _sdk_template_path(ctx, "select_alias"), {
         "{{name}}": name,
         "{{select_map}}": _get_starlark_dict({
-            ":%s" % variant.constraint: ":%s" % variant.name
+            "@fuchsia_sdk//fuchsia/constraints:%s" % variant.constraint: ":%s" % variant.name
             for variant in package_variants
         }),
     })
diff --git a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/repository.BUILD.template b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/repository.BUILD.template
index eddd1de..0ed2b42 100644
--- a/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/repository.BUILD.template
+++ b/build/bazel_sdk/bazel_rules_fuchsia/fuchsia/workspace/sdk_templates/repository.BUILD.template
@@ -72,6 +72,9 @@
     ffx_scrutiny = "//tools:{{HOST_CPU}}/ffx_tools/ffx-scrutiny",
     ffx_scrutiny_fho_meta = "//tools:{{HOST_CPU}}/ffx_tools/ffx-scrutiny.json",
     ffx_scrutiny_manifest = "//tools:{{HOST_CPU}}/ffx_tools/ffx-scrutiny-meta.json",
+    ffx_test = "//tools:{{HOST_CPU}}/ffx_tools/ffx-test",
+    ffx_test_fho_meta = "//tools:{{HOST_CPU}}/ffx_tools/ffx-test.json",
+    ffx_test_manifest = "//tools:{{HOST_CPU}}/ffx_tools/ffx-test-meta.json",
     fidlc = "//tools:{{HOST_CPU}}/fidlc",
     fidlgen_cpp = "//tools:{{HOST_CPU}}/fidlgen_cpp",
     fidlgen_hlcpp = "//tools:{{HOST_CPU}}/fidlgen_hlcpp",
diff --git a/build/bazel_sdk/tests/BUILD.bazel b/build/bazel_sdk/tests/BUILD.bazel
index 1475a68..72942e9 100644
--- a/build/bazel_sdk/tests/BUILD.bazel
+++ b/build/bazel_sdk/tests/BUILD.bazel
@@ -29,6 +29,7 @@
         "//fuchsia/assembly:board_configuration_golden_test",
         "//fuchsia/assembly:board_input_bundle_golden_test",
         "//fuchsia/assembly:partitions_config_golden_test",
+        "//fuchsia/assembly:prebuilt_product_config_golden_test",
         "//fuchsia/assembly:product_config_golden_test",
         "//fuchsia/assembly:product_config_with_labels_golden_test",
         "//fuchsia/assembly:product_ota_config_golden_test",
diff --git a/build/bazel_sdk/tests/fuchsia/assembly/BUILD.bazel b/build/bazel_sdk/tests/fuchsia/assembly/BUILD.bazel
index 0fc954b..051d19c 100644
--- a/build/bazel_sdk/tests/fuchsia/assembly/BUILD.bazel
+++ b/build/bazel_sdk/tests/fuchsia/assembly/BUILD.bazel
@@ -15,6 +15,7 @@
     "fuchsia_partitions_configuration",
     "fuchsia_prebuilt_board_input_bundle",
     "fuchsia_prebuilt_package",
+    "fuchsia_prebuilt_product_configuration",
     "fuchsia_product_configuration",
     "fuchsia_product_ota_config",
     "fuchsia_virtual_device",
@@ -170,6 +171,13 @@
     },
 )
 
+fuchsia_prebuilt_product_configuration(
+    name = "prebuilt_product_config",
+    build_type = "userdebug",
+    product_config_dir = "test_data/prebuilt_product_config",
+    product_config_filename = "prebuilt_product_config.json",
+)
+
 fuchsia_product_configuration_test(
     name = "product_config_with_labels_golden_test",
     golden_file = ":test_data/product_config_with_labels_golden_file.json",
@@ -177,6 +185,13 @@
     visibility = ["//visibility:public"],
 )
 
+fuchsia_product_configuration_test(
+    name = "prebuilt_product_config_golden_test",
+    golden_file = ":test_data/prebuilt_product_config_golden.json",
+    product_config = ":prebuilt_product_config",
+    visibility = ["//visibility:public"],
+)
+
 fuchsia_bootstrap_partition(
     name = "bootstrap_partition_3728",
     condition_value = "0xe9000000",
diff --git a/build/bazel_sdk/tests/fuchsia/assembly/test_data/prebuilt_product_config/prebuilt_product_config.json b/build/bazel_sdk/tests/fuchsia/assembly/test_data/prebuilt_product_config/prebuilt_product_config.json
new file mode 100644
index 0000000..c007eb2
--- /dev/null
+++ b/build/bazel_sdk/tests/fuchsia/assembly/test_data/prebuilt_product_config/prebuilt_product_config.json
@@ -0,0 +1,46 @@
+{
+    "platform": {
+        "build_type": "user",
+        "connectivity": {
+            "wlan": {
+                "legacy_privacy_support": true
+            }
+        },
+        "development_support": {
+            "enabled": true
+        },
+        "diagnostics": {
+            "archivist": "default",
+            "additional_serial_log_components": [
+                "/core/session-manager",
+                "/core/session-manager/session:session"
+            ]
+        },
+        "identity": {
+            "password_pinweaver": "required"
+        },
+        "ui": {
+            "supported_input_devices": [
+                "button",
+                "keyboard"
+            ]
+        },
+        "some": {
+            "random": {
+                "path1": true,
+                "int1": 3234234324231434134141234,
+                "string1": "I have a string"
+            }
+        },
+        "another": {
+            "random": {
+                "path1": false,
+                "int": 0,
+                "string2": "false"
+            }
+        }
+    },
+    "product": {
+        "session_url": "fuchsia-pkg://fuchsia.com/test_session#meta/test_session.cm"
+    }
+}
diff --git a/build/bazel_sdk/tests/fuchsia/assembly/test_data/prebuilt_product_config_golden.json b/build/bazel_sdk/tests/fuchsia/assembly/test_data/prebuilt_product_config_golden.json
new file mode 100644
index 0000000..c007eb2
--- /dev/null
+++ b/build/bazel_sdk/tests/fuchsia/assembly/test_data/prebuilt_product_config_golden.json
@@ -0,0 +1,46 @@
+{
+    "platform": {
+        "build_type": "user",
+        "connectivity": {
+            "wlan": {
+                "legacy_privacy_support": true
+            }
+        },
+        "development_support": {
+            "enabled": true
+        },
+        "diagnostics": {
+            "archivist": "default",
+            "additional_serial_log_components": [
+                "/core/session-manager",
+                "/core/session-manager/session:session"
+            ]
+        },
+        "identity": {
+            "password_pinweaver": "required"
+        },
+        "ui": {
+            "supported_input_devices": [
+                "button",
+                "keyboard"
+            ]
+        },
+        "some": {
+            "random": {
+                "path1": true,
+                "int1": 3234234324231434134141234,
+                "string1": "I have a string"
+            }
+        },
+        "another": {
+            "random": {
+                "path1": false,
+                "int": 0,
+                "string2": "false"
+            }
+        }
+    },
+    "product": {
+        "session_url": "fuchsia-pkg://fuchsia.com/test_session#meta/test_session.cm"
+    }
+}
diff --git a/build/components/fuchsia_package.gni b/build/components/fuchsia_package.gni
index 15d11cc..7935a5e 100644
--- a/build/components/fuchsia_package.gni
+++ b/build/components/fuchsia_package.gni
@@ -184,8 +184,12 @@
 
     _files = {
       fini_manifest = "$target_out_dir/${target_name}_manifest"
+
+      # LINT.IfChange
       package_out_dir = "$target_out_dir/$target_name"
       package_manifest = "$package_out_dir/package_manifest.json"
+
+      # LINT.ThenChange(//build/packages/exported_fuchsia_package_archive.gni)
     }
 
     main_target_deps = []
diff --git a/build/components/fuchsia_test_package.gni b/build/components/fuchsia_test_package.gni
index 66b6c3d..546c4e1 100644
--- a/build/components/fuchsia_test_package.gni
+++ b/build/components/fuchsia_test_package.gni
@@ -157,7 +157,6 @@
         testonly = true
         data_deps = [
           ":${test_target}_script_gen",
-          "//src/developer/ffx:test_data($host_toolchain)",
           host_test_component_target,
           test_pilot_target,
         ]
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index c7a1f3d..023c633 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -9,10 +9,12 @@
 import("//build/config/compiler.gni")
 import("//build/config/fuchsia_cxx_version.gni")
 import("//build/config/linker.gni")
+import("//build/config/lto/config.gni")
 import("//build/toolchain/ccache.gni")
 import("//build/toolchain/concurrent_jobs.gni")
 import("//build/toolchain/goma.gni")
 import("//build/toolchain/rbe.gni")
+import("//build/toolchain/toolchain_environment.gni")
 import("//build/toolchain/variant.gni")
 
 if (support_rust) {
@@ -48,6 +50,15 @@
 config("language") {
   cflags_c = [ "-std=c11" ]
   cflags_cc = [ "-std=c++$fuchsia_cxx_version" ]
+
+  if (fuchsia_cxx_version < 20) {
+    # TODO(https://fxbug.dev/42064981): libc++ now marks the C++20
+    # synchronization primitives as deprecated in older C++ standards which
+    # affects Fuchsia since we use these primitives across the codebase. We
+    # temporarily suppress these warnings until C++20 becomes the default.
+    defines = [ "_LIBCPP_DISABLE_DEPRECATION_WARNINGS" ]
+  }
+
   if (current_os == "mac") {
     # macOS needs this to not complain about C++17isms that older macOS
     # system libc++ doesn't support.  But we use our own toolchain's static
@@ -57,7 +68,7 @@
     # libc++ headers mark some symbols as unavailable on macOS by default
     # because the system libc++ doesn't support them.  But we use our own
     # toolchain's static libc++ anyway.
-    defines = [ "_LIBCPP_DISABLE_AVAILABILITY" ]
+    defines += [ "_LIBCPP_DISABLE_AVAILABILITY" ]
   }
 }
 
@@ -380,13 +391,13 @@
   # Override global settings that may disable downloading of outputs.
   # This is useful for targets that are known to be needed for local actions.
   if (rust_rbe_enable) {
-    rustflags = [ "--remote-flag=--download_outputs=true" ]
+    rustflags = [ "--remote-flag=--download_regex=.*" ]
   }
   if (cxx_rbe_enable) {
-    cflags = [ "--remote-flag=--download_outputs=true" ]
+    cflags = [ "--remote-flag=--download_regex=.*" ]
   }
   if (link_rbe_enable) {
-    ldflags = [ "--remote-flag=--download_outputs=true" ]
+    ldflags = [ "--remote-flag=--download_regex=.*" ]
   }
 }
 
@@ -402,6 +413,7 @@
   rustflags = [ "-Copt-level=0" ]
 }
 
+# This is the default optimization level for "debug" builds.
 config("optimize_debug") {
   cflags = [ "-Og" ]
   ldflags = cflags
@@ -447,6 +459,31 @@
   configs = [ ":linker_string_merging" ]
 }
 
+# This is the default optimization level for "non-debug" builds.
+config("optimize_size_lto") {
+  if (zircon_toolchain != false) {
+    configs = [ ":optimize_default" ]
+  } else {
+    # Primarily optimize for size.
+    configs = [ ":optimize_size" ]
+  }
+
+  _is_not_instrumented = toolchain_variant.tags + [ "instrumented" ] -
+                         [ "instrumented" ] == toolchain_variant.tags
+
+  not_needed([ "_is_not_instrumented" ])
+
+  # Enable LTO for Fuchsia targets.
+  # Do not enable LTO for the kernel.
+  # Do not enable LTO for the instrumented variants.
+  # Do not enable LTO (here) for the lto or thinlto variants.
+  if (is_fuchsia && toolchain_environment != "kernel" && _is_not_instrumented &&
+      !is_lto_variant) {
+    # Enable LTO for the binaries that are generated by Clang.
+    configs += [ "//build/config/lto:lto-clang" ]
+  }
+}
+
 config("optimize_speed") {
   cflags = [ "-O3" ]
   ldflags = cflags
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 1da1026..a610821 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -396,6 +396,10 @@
 # Prepend the prefix configs, if any, before the default ones.
 default_common_binary_configs = toolchain_variant.prefix_configs
 
+# Enable the rust compiler's parallel front-end for all binaries.
+default_common_binary_configs +=
+    [ "//build/config/rust:parallel_frontend_threads" ]
+
 # Note that Zircon toolchains and non-Zircon ones have a very different set
 # of default configs for all target types.
 if (zircon_toolchain == false) {
@@ -460,8 +464,6 @@
     ]
   }
 
-  default_common_binary_configs += [ "//build/config/lto:default" ]
-
   # Add and remove configs specified by the variant.
   default_common_binary_configs += toolchain_variant.configs
   default_common_binary_configs -= toolchain_variant.remove_common_configs
@@ -538,12 +540,10 @@
 default_rust_proc_macro_configs = default_shared_library_configs + [
                                     "//build/config/lto",
                                     "//build/config/lto:thinlto",
-                                    "//build/config/lto:default",
                                   ] -
                                   [
                                     "//build/config/lto",
                                     "//build/config/lto:thinlto",
-                                    "//build/config/lto:default",
                                   ]
 
 # Known e2e test libraries. Any tests that transitively depend on these
@@ -2154,6 +2154,16 @@
               "ubsan-fuzzer",
             ] != select_variant
 
+# Whether lto or thinlto variant is enabled.
+is_lto_variant = select_variant + [
+                   "lto",
+                   "thinlto",
+                 ] -
+                 [
+                   "lto",
+                   "thinlto",
+                 ] != select_variant
+
 # Do this only once, in the default toolchain context.    Then
 # clang_toolchain_suite will just pass the results through to every
 # other toolchain via toolchain_args so the work is not repeated.
@@ -3173,12 +3183,10 @@
           configs += [
             "//build/config/lto",
             "//build/config/lto:thinlto",
-            "//build/config/lto:default",
           ]
           configs -= [
             "//build/config/lto",
             "//build/config/lto:thinlto",
-            "//build/config/lto:default",
           ]
         }
 
diff --git a/build/config/compiler.gni b/build/config/compiler.gni
index 238f972..6ac5c84 100644
--- a/build/config/compiler.gni
+++ b/build/config/compiler.gni
@@ -15,6 +15,7 @@
   # * `debug`: "optimized for debugging", light enough to avoid confusion
   # * `default`: default optimization level
   # * `size`:  optimized for space rather than purely for speed
+  # * `size_lto`:  optimize for space and use LTO
   # * `speed`: optimized purely for speed
   # * `sanitizer`: optimized for sanitizers (ASan, etc.)
   # * `profile`: optimized for coverage/profile data collection
@@ -27,6 +28,7 @@
   "debug",
   "default",
   "size",
+  "size_lto",
   "speed",
   "sanitizer",
   "profile",
diff --git a/build/config/fuchsia/rust_target_api_level.gni b/build/config/fuchsia/rust_target_api_level.gni
index fa5ec39..a171018 100644
--- a/build/config/fuchsia/rust_target_api_level.gni
+++ b/build/config/fuchsia/rust_target_api_level.gni
@@ -5,19 +5,22 @@
 import("//build/config/fuchsia/platform_version.gni")
 import("//build/config/fuchsia/target_api_level.gni")
 
-if (override_target_api_level == -1) {
-  # All API levels are less than or equal to "HEAD" (ignoring the HEAD/LEGACY
-  # ambguity problem).
-  #
-  # TODO(https://fxbug.dev/325448727): Account for "LEGACY" here.
+if (override_target_api_level == "PLATFORM") {
+  # All API levels are less than or equal to "PLATFORM".
   rust_lesser_or_equal_fuchsia_api_levels =
-      platform_version.all_numbered_api_levels + [ "HEAD" ]
+      platform_version.all_numbered_api_levels + [
+        "HEAD",
+        "PLATFORM",
+      ]
 
-  # No API levels are greater than "HEAD".
+  # No API levels are greater than "PLATFORM".
   rust_greater_fuchsia_api_levels = []
 } else {
   rust_lesser_or_equal_fuchsia_api_levels = []
-  rust_greater_fuchsia_api_levels = [ "HEAD" ]
+  rust_greater_fuchsia_api_levels = [
+    "HEAD",
+    "PLATFORM",
+  ]
   foreach(level, platform_version.all_numbered_api_levels) {
     if (level <= override_target_api_level) {
       rust_lesser_or_equal_fuchsia_api_levels += [ level ]
diff --git a/build/config/fuchsia/target_api_level.gni b/build/config/fuchsia/target_api_level.gni
index 8391916..800fcbc 100644
--- a/build/config/fuchsia/target_api_level.gni
+++ b/build/config/fuchsia/target_api_level.gni
@@ -4,20 +4,19 @@
 
 declare_args() {
   # Specify a specific target API level for the platform build.
-  # When set to -1, the platform is built targeting HEAD with runtime support
-  # for all supported and sunset API levels.
-  # Must be -1 or a positive integer corresponding to currently supported
-  # (not sunset) API level. This is primarily used by the SDK.
-  # Not all targets support the non-default value. In particular, `:default`
-  # currently fails.
-  override_target_api_level = -1
+  #
+  # For the normal platform build, the API level is "PLATFORM", which is greater
+  # than (that is to say: "newer than") all other API levels.
+  #
+  # If this is _not_ set to "PLATFORM", then it must be set to a positive
+  # integer corresponding to a currently supported (not sunset) API level. In
+  # that case, the build will target the given API level.
+  #
+  # This is primarily used by the IDK. Not all targets support the non-default
+  # value. In particular, `:default` currently fails.
+  override_target_api_level = "PLATFORM"
 }
 
-assert(override_target_api_level == -1 || 0 < override_target_api_level,
-       "Override must be positive integers.")
-assert(override_target_api_level < 1000,
-       "Override must be a numbered API level.")
-
 # TODO(https://fxbug.dev/325448727): Move this value back into the if
 # statement below and prefix it with `_` once the bug is fixed.
 # Due to limitations in Clang, we use `UINT32_MAX` to represent the HEAD API
@@ -28,17 +27,19 @@
 
 # LINT.ThenChange(//zircon/system/public/zircon/availability.h:fuchsia_head_c_value)
 
-if (override_target_api_level == -1) {
-  # The platform is built for "HEAD" by default. "HEAD" is an artificial API
-  # level that represents the bleeding edge of the Fuchsia API surface. It is
-  # not really meant to be used by SDK users unless they want to try some
-  # unreleased APIs.
+if (override_target_api_level == "PLATFORM") {
+  # This should really be a constant that indicates that we're building at
+  # `PLATFORM`, rather than `HEAD` (which we actually don't support yet).
+  #
+  # TODO(https://fxbug.dev/330426357): Switch this to a constant for `PLATFORM`,
+  # once one exists.
   clang_fuchsia_api_level = CLANG_FUCHSIA_HEAD_VALUE
 
-  # By default the FIDL APIs are compiled at the "LEGACY" level. This level is
-  # only meant to be used in the platform itself, SDK users aren't expected to
-  # target it. It's a higher level than the "HEAD" API level, in other words,
-  # "HEAD" is a subset of "LEGACY".
+  # By default the FIDL APIs are compiled at the "LEGACY" level, which is an
+  # older name for the "PLATFORM" API level. This level is only meant to be used
+  # in the platform itself, SDK users aren't expected to target it. It's a
+  # higher level than the "HEAD" API level, in other words, "HEAD" is a subset
+  # of "LEGACY".
   fidl_fuchsia_api_level = "LEGACY"
 
   # Directory name to use for target API level.
@@ -48,11 +49,17 @@
   sdk_prebuilt_base_for_target_api_level =
       "arch/${target_cpu_dir_name_for_target_api_level}"
 } else {
+  # Ensure that `override_target_api_level` is an integer corresponding to a
+  # normal API level.
+  assert(
+      0 < override_target_api_level,
+      "Override must be 'PLATFORM' or a positive integer, not: ${override_target_api_level}")
+  assert(override_target_api_level < 2147483648,
+         "Special API levels should be given by name, not number.")
+
   clang_fuchsia_api_level = override_target_api_level
   fidl_fuchsia_api_level = "$override_target_api_level"
 
-  # If support for named API levels is added and `override_target_api_level` becomes a string,
-  # we will need to ensure the strings are normalized.
   target_cpu_dir_name_for_target_api_level =
       "${target_cpu}-api-${override_target_api_level}"
   sdk_prebuilt_base_for_target_api_level =
diff --git a/build/config/lto/BUILD.gn b/build/config/lto/BUILD.gn
index f4fccc79..c0b749d 100644
--- a/build/config/lto/BUILD.gn
+++ b/build/config/lto/BUILD.gn
@@ -5,38 +5,35 @@
 import("//build/config/lto/config.gni")
 import("//build/toolchain/variant.gni")
 
-# This config is added unconditionally by BUILDCONFIG.gn to pick up the
-# global `use_lto` build argument.  For fine-grained control, leave
-# `use_lto=false` and use `select_variant` to choose the `lto` or `thinlto`
-# variant for some components.
-config("default") {
-  if (use_lto) {
-    if (use_thinlto) {
-      configs = [ ":thinlto" ]
-    } else {
-      configs = [ ":lto" ]
-    }
+config("lto-clang") {
+  cflags = [ "-flto" ]
+
+  if (!is_fuchsia) {
+    cflags += [
+      # Enable whole-program devirtualization and virtual constant propagation.
+      #
+      # TODO(https://fxbug.dev/42075686): Currently fuchsia does not support WPD
+      # because the patches supporting WPD and relative vtables have been
+      # reverted from upstream. Since relative vtables aren't subject to WPD,
+      # this flag is not needed for fuchsia. What limiting this to !is_fuchsia
+      # allows is for me to reland the relevant patches and make debugging
+      # easier once we roll those changes back in.
+      "-fwhole-program-vtables",
+    ]
   }
-}
 
-variant("lto") {
-  common_flags = [
-    "-flto",
-
-    # Enable whole-program devirtualization and virtual constant propagation.
-    "-fwhole-program-vtables",
-  ]
+  ldflags = cflags
 
   # TODO(https://fxbug.dev/42061844): Temporarily disable branch funneling on lto. Branch
   # funneling likely generates bad code involving return values not propagated
   # correctly to other functions. Once this is resolved, come back and remove this.
   if (is_fuchsia) {
     disable_branch_funneling = "-wholeprogramdevirt-branch-funnel-threshold=0"
-    cflags = [
+    cflags += [
       "-mllvm",
       "$disable_branch_funneling",
     ]
-    ldflags = [ "-Wl,-mllvm,$disable_branch_funneling" ]
+    ldflags += [ "-Wl,-mllvm,$disable_branch_funneling" ]
 
     # TODO(https://fxbug.dev/42086180): The linker flags below are required to avoid code
     # generation bugs during LTO. They can be removed once LTO properly handles
@@ -48,15 +45,44 @@
       ]
     }
   }
+}
 
+config("lto-rust") {
   rustflags = [
     "-Clto=fat",
     "-Zdylib-lto",
+    "-Clinker-plugin-lto",
+    "-Zsplit-lto-unit",
   ]
 }
 
-variant("thinlto") {
-  common_flags = [ "-flto=thin" ]
+# This can be appended with:
+# ```
+#   configs += [ "//build/config/lto:no-lto" ]
+# ```
+# in any particular target to disable LTO.
+config("no-lto") {
+  cflags = [ "-fno-lto" ]
+
+  if (!is_fuchsia) {
+    cflags += [ "-fno-whole-program-vtables" ]
+  }
+
+  ldflags = cflags
+
+  rustflags = [ "-Clto=off" ]
+}
+
+variant("lto") {
+  configs = [
+    ":lto-clang",
+    ":lto-rust",
+  ]
+}
+
+config("thinlto-clang") {
+  cflags = [ "-flto=thin" ]
+  ldflags = cflags
 
   # These switches have the same meaning but different spellings for
   # lld-link vs ld.lld.
@@ -68,7 +94,7 @@
     _cache_dir = "--thinlto-cache-dir="
   }
 
-  ldflags = [
+  ldflags += [
     # The ThinLTO driver launches a number of threads in parallel whose
     # number is by default equivalent to the number of cores.  We need
     # to limit the parallelism to avoid aggressive competition between
@@ -91,9 +117,36 @@
       "-Wl,-mllvm,-mattr=+relax",
     ]
   }
+}
 
+config("thinlto-rust") {
   rustflags = [
     "-Clto=thin",
     "-Zdylib-lto",
   ]
+
+  # These switches have the same meaning but different spellings for
+  # lld-link vs ld.lld.
+  if (current_os == "win") {
+    _cache_dir = "/lldltocache:"
+  } else {
+    _cache_dir = "--thinlto-cache-dir="
+  }
+
+  if (is_fuchsia) {
+    # On fuchsia, rustc directly calls lld.
+    rust_linkarg = "-Clink-args"
+  } else {
+    # On all other platforms, rustc calls clang, which calls lld.
+    rust_linkarg = "-Clink-args=-Wl"
+  }
+
+  rustflags += [ "${rust_linkarg}=${_cache_dir}$thinlto_cache_dir" ]
+}
+
+variant("thinlto") {
+  configs = [
+    ":thinlto-clang",
+    ":thinlto-rust",
+  ]
 }
diff --git a/build/config/lto/config.gni b/build/config/lto/config.gni
index f439ada..db5047b 100644
--- a/build/config/lto/config.gni
+++ b/build/config/lto/config.gni
@@ -3,12 +3,6 @@
 # found in the LICENSE file.
 
 declare_args() {
-  # Use link time optimization (LTO).
-  use_lto = false
-
-  # Use ThinLTO variant of LTO if use_lto = true.
-  use_thinlto = true
-
   # Number of parallel ThinLTO jobs.
   thinlto_jobs = 8
 
diff --git a/build/config/rust/BUILD.gn b/build/config/rust/BUILD.gn
index 16e3596..a12ddaf 100644
--- a/build/config/rust/BUILD.gn
+++ b/build/config/rust/BUILD.gn
@@ -31,6 +31,9 @@
 
   # Enable debug assertions, e.g. for overflow checking.
   rust_debug_assertions = is_debug
+
+  # Enable the rust parallel front-end with N threads
+  rust_parallel_frontend_threads = false
 }
 
 # Turns on the rust compilation analysis generator. This will produce a
@@ -103,6 +106,17 @@
   }
 }
 
+config("parallel_frontend_threads") {
+  if (rust_parallel_frontend_threads != false) {
+    # Use the parallel front-end with up to N threads, set by the
+    # rust_parallel_frontend_threads GN arg.
+    rustflags = [
+      "-Z",
+      "threads=${rust_parallel_frontend_threads}",
+    ]
+  }
+}
+
 config("debug_assertions") {
   rustflags = [ "-Cdebug-assertions=yes" ]
 }
@@ -119,14 +133,6 @@
   }
 }
 
-config("lto_disabled") {
-  # Fully disable lto.
-  #
-  # This is the default when -Ccodegen_units=1 or when optimizations are off
-  # (-Copt-level=0)
-  rustflags = [ "-Clto=off" ]
-}
-
 # Enables linker plugin LTO.
 #
 # If an rlib is only ever going to get used later with a -Clto compilation then
@@ -143,11 +149,6 @@
   ]
 }
 
-config("lto_thin") {
-  # Enable "thin" lto across all crates being linked
-  rustflags = [ "-Clto=thin" ]
-}
-
 # Best practices for Rust binaries that go into size-constrained bootfs.
 config("bootfs") {
   # Optimize for size.
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 3413490..1d64781 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -194,13 +194,7 @@
 variant("ubsan") {
   common_flags = []
   if (toolchain_environment == "kernel") {
-    configs = [
-      # Zircon uses kernel-specific ubsan flags.
-      "//zircon/kernel/lib/instrumentation/ubsan",
-
-      # The ubsan variant adds rtti, but that is not used by the kernel variant.
-      "//build/config:no_rtti",
-    ]
+    configs = [ "//src/lib/ubsan-custom:ubsan" ]
   } else {
     common_flags = [ "-fsanitize=undefined" ]
   }
diff --git a/build/config/zircon/BUILD.gn b/build/config/zircon/BUILD.gn
index cfdcb5aa..8275e653 100644
--- a/build/config/zircon/BUILD.gn
+++ b/build/config/zircon/BUILD.gn
@@ -347,8 +347,8 @@
   # which is not PIC-friendly under LTO.
   if ((current_toolchain == shlib_toolchain ||
        toolchain_variant.is_pic_default) &&
-      toolchain_variant.tags + [ "lto" ] - [ "lto" ] !=
-      toolchain_variant.tags) {
+      (optimize == "size_lto" || toolchain_variant.tags + [ "lto" ] -
+                                 [ "lto" ] != toolchain_variant.tags)) {
     cflags = [ "-fno-jump-tables" ]
   }
 }
diff --git a/build/cpp/sdk_shared_library.gni b/build/cpp/sdk_shared_library.gni
index 525317a..89bccc8 100644
--- a/build/cpp/sdk_shared_library.gni
+++ b/build/cpp/sdk_shared_library.gni
@@ -448,7 +448,7 @@
     if (defined(invoker.symbols_api)) {
       args += [ "--ifs" ] + [ get_path_info(invoker.symbols_api, "file") ]
     }
-    if (override_target_api_level != -1) {
+    if (override_target_api_level != "PLATFORM") {
       args += [
         "--api-level",
         "${override_target_api_level}",
diff --git a/build/cpp/sdk_static_library.gni b/build/cpp/sdk_static_library.gni
index b5b24d29..f7ad18e 100644
--- a/build/cpp/sdk_static_library.gni
+++ b/build/cpp/sdk_static_library.gni
@@ -351,7 +351,7 @@
     ]
     args += [ "--deps" ] + rebase_path(sdk_metas, root_build_dir)
     args += [ "--headers" ] + sdk_metadata_headers
-    if (override_target_api_level != -1) {
+    if (override_target_api_level != "PLATFORM") {
       args += [
         "--api-level",
         "${override_target_api_level}",
diff --git a/build/drivers/all_drivers_list.txt b/build/drivers/all_drivers_list.txt
index 42387f6..b8ac195 100644
--- a/build/drivers/all_drivers_list.txt
+++ b/build/drivers/all_drivers_list.txt
@@ -122,6 +122,9 @@
 //src/devices/bus/drivers/platform/test:test-parent-driver
 //src/devices/bus/drivers/platform/test:test-power-driver
 //src/devices/bus/drivers/platform/test:test-spi-driver
+//src/devices/bus/drivers/platform/test/power-integration-test:test-power-child-driver
+//src/devices/bus/drivers/platform/test/power-integration-test:test-power-integration-board-driver
+//src/devices/bus/drivers/platform/test/power-integration-test:test-power-parent-driver
 //src/devices/bus/drivers/platform:platform-bus-driver
 //src/devices/bus/drivers/platform:platform-bus.proxy-driver
 //src/devices/clock/drivers/amlogic-clk:amlogic-clk-driver
@@ -202,8 +205,6 @@
 //src/devices/tests/ddk-firmware-test:ddk-firmware-test
 //src/devices/tests/ddk-lifecycle:ddk-lifecycle-test-driver
 //src/devices/tests/ddk-metadata-test:fuchsia_driver
-//src/devices/tests/ddk-power:ddk-power-test-child-driver
-//src/devices/tests/ddk-power:ddk-power-test-driver
 //src/devices/tests/ddk-topology-test:ddk-topology-test
 //src/devices/tests/driver-inspect-test:fuchsia_driver
 //src/devices/tests/driver-multiname-test:parent_device
diff --git a/build/fidl/fidl.gni b/build/fidl/fidl.gni
index 6271cdc..e76e241 100644
--- a/build/fidl/fidl.gni
+++ b/build/fidl/fidl.gni
@@ -76,9 +76,10 @@
 #     Boolean flag to generate a LibFuzzer fuzz target for all protocols, used
 #     to ensure fuzzers for golden libraries compile successfully.
 #
-#   platform (optional)
-#     Name of the platform this library is versioned under. This is validated
-#     to match the library's actual platform, which is determined as follows:
+#   versioned (optional)
+#     A string of the form PLATFORM or PLATFORM:VERSION. Validates that the
+#     library is versioned under PLATFORM and added at VERSION (if provided).
+#     The library's actual platform is determined as follows:
 #       * If there are no @available attributes, the platform is "unversioned".
 #       * The platform can be explicit with @available(platform="PLATFORM").
 #       * Otherwise, the platform is the first component of the library name.
@@ -197,7 +198,7 @@
     "experimental_flags",
     "goldens_dir",
     "non_fidl_deps",
-    "platform",
+    "versioned",
   ]
   if (is_fidl_toolchain) {
     # Only import the fidl_library template when in the fidl toolchain
diff --git a/build/fidl/fidl_ir.gni b/build/fidl/fidl_ir.gni
index 8875851..213ece2 100644
--- a/build/fidl/fidl_ir.gni
+++ b/build/fidl/fidl_ir.gni
@@ -37,9 +37,9 @@
 #   experimental_flags
 #   goldens_dir
 #   non_fidl_deps
-#   platform
 #   public_deps
 #   testonly
+#   versioned
 #   visibility
 #
 template("fidl_ir") {
diff --git a/build/fidl/fidl_library.gni b/build/fidl/fidl_library.gni
index d5e3503..fe6564d 100644
--- a/build/fidl/fidl_library.gni
+++ b/build/fidl/fidl_library.gni
@@ -41,7 +41,7 @@
 #    - Type: list(path)
 #
 #  * api, available, excluded_checks, experimental_checks, experimental_flags,
-#    goldens_dir, non_fidl_deps, platform, sdk_category, sdk_area
+#    goldens_dir, non_fidl_deps, sdk_category, sdk_area, versioned
 #    - Optional: See //build/fidl/fidl.gni for a description.
 #
 #  * testonly, visibility, public_deps, applicable_licenses
@@ -116,10 +116,10 @@
                              "available",
                              "experimental_flags",
                              "non_fidl_deps",
-                             "platform",
                              "public_deps",
                              "sources",
                              "testonly",
+                             "versioned",
                            ])
     visibility = [ ":*" ]
     fidl_target_name = main_target_name
@@ -130,12 +130,12 @@
     if (!defined(available)) {
       available = [ "fuchsia:$target_api_level" ]
     }
-    if (!defined(platform)) {
-      # TODO(https://fxbug.dev/325669391): Always set a default `platform`.
+    if (!defined(versioned)) {
+      # TODO(https://fxbug.dev/325669391): Always set a default `versioned`.
       if (requires_compatibility_tests && in_fuchsia_namespace) {
-        platform = "fuchsia"
+        versioned = "fuchsia"
       } else if (defined(invoker.testonly) && invoker.testonly) {
-        platform = "unversioned"
+        versioned = "unversioned"
       }
     }
   }
@@ -249,8 +249,12 @@
   # Enforce compatibility checks for all FIDL libraries included in the IDK with
   # platform `fuchsia`.
   if (requires_compatibility_tests) {
-    assert(!defined(invoker.platform) || invoker.platform == "fuchsia",
-           "Cannot override `platform` for SDK FIDL library $library_name")
+    if (defined(invoker.versioned)) {
+      _platform = string_split(invoker.versioned, ":")
+      _platform = _platform[0]
+    }
+    assert(!defined(invoker.versioned) || _platform == "fuchsia",
+           "Cannot override `versioned` for SDK FIDL library $library_name")
     assert(!defined(invoker.available),
            "Cannot override `available` for SDK FIDL library $library_name")
 
@@ -298,7 +302,7 @@
         # be true here, but currently it isn't for vendor SDK libraries. Those
         # libraries likely should be excluded in requires_compatibility_tests.
         if (in_fuchsia_namespace) {
-          platform = "fuchsia"
+          versioned = "fuchsia"
         }
 
         available = [ "fuchsia:$level" ]
diff --git a/build/fidl/fidlc.gni b/build/fidl/fidlc.gni
index 376e79f..fcb2b0f 100644
--- a/build/fidl/fidlc.gni
+++ b/build/fidl/fidlc.gni
@@ -17,9 +17,9 @@
 #   sources (required)
 #   experimental_flags
 #   non_fidl_deps
-#   platform
 #   public_deps
 #   testonly
+#   versioned
 #   visibility
 #
 template("fidlc") {
@@ -91,10 +91,10 @@
       args += [ "--dep-libraries" ] + rebase_path(inputs, root_build_dir)
     }
 
-    if (defined(invoker.platform)) {
+    if (defined(invoker.versioned)) {
       args += [
-        "--platform",
-        invoker.platform,
+        "--versioned",
+        invoker.versioned,
       ]
     }
     foreach(available, invoker.available) {
diff --git a/build/images/bringup/BUILD.gn b/build/images/bringup/BUILD.gn
index 3603240..e6d80a3 100644
--- a/build/images/bringup/BUILD.gn
+++ b/build/images/bringup/BUILD.gn
@@ -54,7 +54,6 @@
     feature_set_level = "bootstrap"
     build_type = "eng"
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "bringup"
         image_mode = "no_image"
diff --git a/build/images/guest/BUILD.gn b/build/images/guest/BUILD.gn
index 8596d2b..b2e4352 100644
--- a/build/images/guest/BUILD.gn
+++ b/build/images/guest/BUILD.gn
@@ -129,7 +129,6 @@
       build_type = "eng"
       feature_set_level = "utility"
       storage = {
-        configure_fshost = true
         filesystems = {
           no_zxcrypt = true
           volume = {
diff --git a/build/images/network-conformance/assemble_network_conformance_system.gni b/build/images/network-conformance/assemble_network_conformance_system.gni
index d1c9446..908409b 100644
--- a/build/images/network-conformance/assemble_network_conformance_system.gni
+++ b/build/images/network-conformance/assemble_network_conformance_system.gni
@@ -53,7 +53,6 @@
         config_type = "none"
       }
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = _image_name
           volume = {
@@ -76,7 +75,6 @@
         config_type = "none"
       }
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = _image_name
         }
diff --git a/build/images/paths.gni b/build/images/paths.gni
index 9f598d7..2e90354 100644
--- a/build/images/paths.gni
+++ b/build/images/paths.gni
@@ -58,9 +58,6 @@
     _images_outdir = get_label_info(labels.images, "target_out_dir") +
                      "/${_bazel_target_name}/product_bundle"
     _assembly_outdir = _images_outdir + "/system_a"
-    bazel_package_manifests_list =
-        get_label_info(labels.images, "target_out_dir") +
-        "/${_bazel_target_name}/manifests/package_manifests.list"
   } else {
     _images_outdir = get_label_info(labels.images, "target_out_dir")
     _assembly_outdir = _images_outdir + "/${labels.assembly_name}"
@@ -81,19 +78,47 @@
       fvm_fastboot = "${_assembly_outdir}/fvm.fastboot.blk"
     }
 
+    # This file is used by fx test, which means that fx test cannot detect which
+    # tests are in base (and need to be updated via ota instead of publishing),
+    # when the assembly target is in Bazel instead of GN.
     base_package_names = "$root_build_dir/base_packages.list"
+
+    # It's not clear that either of these files are used by any tool:
     cache_package_names = "$root_build_dir/cache_packages.list"
     universe_package_names = "$root_build_dir/universe_packages.list"
+
+    # This is an intermediate output file used to construct the universe
+    # packages list, and probably shouldn't be listed in this (shared) gni file.
     manifests_from_metadata =
         "$root_build_dir/package_manifests_from_metadata.list"
 
-    # TODO(https://fxbug.dev/42180818) move these to image-relative paths along with tools' usages
-    base_package_manifests = "$root_build_dir/base_package_manifests.list"
-    cache_package_manifests = "$root_build_dir/cache_package_manifests.list"
-    universe_package_manifests =
-        "$root_build_dir/universe_package_manifests.list"
+    # Where to get the package manifest lists from (for publishing) depends on
+    # whether bazel or GN is performing the assembly.
+    #
+    # These are all intermediates that are processed into a canonical list of
+    # packages.
+    if (use_bazel_images_only) {
+      # Bazel has a single package_manifests.list that it produces
+      bazel_package_manifests_list =
+          get_label_info(labels.images, "target_out_dir") +
+          "/${_bazel_target_name}/manifests/package_manifests.list"
+    } else {
+      # GN has a series of files that are based on product assembly, or a GN
+      # metadata walk in the case of the "universe" package set.
+
+      # TODO(https://fxbug.dev/42180818) move these to image-relative paths along with tools' usages
+      base_package_manifests = "$root_build_dir/base_package_manifests.list"
+      cache_package_manifests = "$root_build_dir/cache_package_manifests.list"
+    }
+
     assembly_cache_package_manifests =
         "$root_build_dir/assembly_cache_packages.list"
+    assembly_ondemand_package_manifests =
+        "$root_build_dir/assembly_ondemand_packages.list"
+
+    # The output file containing (only) packages in universe.
+    universe_package_manifests =
+        "$root_build_dir/universe_package_manifests.list"
 
     # TODO(https://fxbug.dev/42074075): Audit and add the following paths when
     # only Bazel assembly is enabled.
diff --git a/build/images/recovery/BUILD.gn b/build/images/recovery/BUILD.gn
index 9d1eec8..fdb3b75 100644
--- a/build/images/recovery/BUILD.gn
+++ b/build/images/recovery/BUILD.gn
@@ -92,12 +92,6 @@
     # Enable ffx support.
     "//src/connectivity/network/mdns/bundles:services",  # group for transition
 
-    # Basic command-line tools:
-    "//bundles/assembly:third_party_sbase_for_transition",
-
-    # Command-line interface to wlan stack:
-    "//src/connectivity/wlan/wlancfg/tool:for_transition",
-
     # Device side of zxdb & fidlcat:
     "//src/developer/debug/debug_agent",
   ]
@@ -189,10 +183,11 @@
   recovery_fdr_packages -= [ "//src/recovery/system:system_recovery" ]
   recovery_fdr_packages += [ "//src/recovery/system:system_recovery_fdr" ]
 
+  _storage_config = {
+  }
   if (!fxfs_blob) {
     _storage_config = {
       storage = {
-        configure_fshost = true
         filesystems = {
           volume = {
             fvm = {
@@ -206,12 +201,6 @@
         }
       }
     }
-  } else {
-    _storage_config = {
-      storage = {
-        configure_fshost = true
-      }
-    }
   }
 
   product_assembly_configuration("for-eng") {
diff --git a/build/images/updates/BUILD.gn b/build/images/updates/BUILD.gn
index 14f5d0c..9aee618 100644
--- a/build/images/updates/BUILD.gn
+++ b/build/images/updates/BUILD.gn
@@ -2,8 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/assembly/cache_packages_from_product_assembler.gni")
 import("//build/assembly/package_list.gni")
+import("//build/assembly/packages_from_product_assembler.gni")
 import("//build/bazel/bazel_workspace.gni")
 import("//build/images/args.gni")
 import("//build/packages/package_metadata.gni")
@@ -13,6 +13,145 @@
 import("//src/sys/pkg/bin/system-updater/epoch/generate_epoch.gni")
 import("//src/sys/pkg/repositories/devhost/devhost.gni")
 
+# Package publishing
+#
+# While this is called "updates", it's not about OTA as much as it is about
+# package publishing.
+#
+# This file contains targets that gather data from two different places, and
+# then combines that to create a list of "all unique packages in the build",
+# which is then published.
+#
+# The general flow is:
+#
+#  +----------------+    +----------------+
+#  |   The "main"   |    | The "universe" |
+#  | Product Bundle |    |  Package Set   |
+#  +----------------+    +----------------+
+#           |                     |
+#           +----------+----------+
+#                      |
+#                      V
+#               +-------------+
+#               | The devhost |
+#               | Repository  |
+#               +-------------+
+#
+# Note that `fx publish` and `fx build` use different data to produce the set
+# of packages to publish to the repository, and both are in this file.  The
+# flow for `fx build` will be covered first, then `fx publish`. (This matches
+# their order within the file).
+#
+# Also: In "bringup" product configs, this is all a giant no-op, as there are no
+# packages to be published.
+#
+# Entry-Point Targets
+#
+#  //build/updates:updates  -> Create package lists and publish everything
+#
+#  //build/updates:packages -> Used to do metadata walks over "all software
+#                              built for the product", but not usable to gather
+#                              all the packages, as it doesn't have enough info
+#                              to do so via GN metadata.  See the target for
+#                              details.
+#
+#  //build/updates:publish -> publish everything
+#
+#
+# The "universe" package set is constructed in the same manner:  A GN metadata
+# walk is done over the the following:
+#   - //:developer_universe_packages (created from the 'universe_package_labels'
+#                                     GN build argument, in 'args.gn')
+#
+#   - //:discoverable_packages (created from the 'discoverable_package_lables'
+#                               GN build arg, and all "discoverable" tests)
+#
+# The `package_manifests_from_metadata.list` target creates a file of the same
+# name which is a metadata walk for all packages in the above.
+#
+#
+# The packages from assembly need to be gathered.  Depending on if the assembly
+# operation is performed by a Bazel or a GN target, this is done differently:
+#
+# Note:  All "foo.list" files are a file of paths to package manifests, one per
+#        line, relative to the root_build_dir.
+#
+# GN:
+#    base_package_manifests.list
+#    cache_package_manifests.list
+#      These targets (and files of the same name) are created by getting the
+#      list of base and cache packages from the product bundle.
+#
+#    assembly_ondemand_packages.list
+#      This set of packages is pulled from product assembly only (skipping the
+#      need to trigger the product bundle creation in order to get them).
+#
+#    package_manifests_from_metadata.list
+#      This is created by doing a metadata walk over the "universe" packages
+#      which are in the following groups:
+#        //:developer_universe_packages
+#        //:discoverable_packages
+#      These groups' contents are primarily driven by developer-specified GN
+#      build arguments.
+#
+#    universe_package_manifests.list
+#      This file is created from the 'package_manifests_from_metadata.list' by
+#      deduplicating it against the base, cache, and ondemand package lists in
+#      the above files.
+#      NOTE:  This deduplication is possibly no longer needed
+#
+#    all_package_manifests.list
+#      This is created by merging the following files from above:
+#        - base_package_manifests.list
+#        - cache_package_manifests.list
+#        - assembly_ondemand_packages.list
+#        - universe_package_manifests.list
+#
+# Bazel:
+#    assembly_ondemand_packages.list
+#      This set of packages is pulled from product assembly only (skipping the
+#      need to trigger the product bundle creation in order to get them).
+#
+#    package_manifests_from_metadata.list
+#      This is created by doing a metadata walk over the "universe" packages
+#      which are in the following groups:
+#        //:developer_universe_packages
+#        //:discoverable_packages
+#      These groups' contents are primarily driven by developer-specified GN
+#      build arguments.
+#
+#    universe_package_manifests.list
+#      This file is created from the 'package_manifests_from_metadata.list'.
+#      No deduplication is performed.
+#
+#    [labels|files].bazel_package_manifests_list
+#      The bazel_product_bundle() GN template creates this target and file
+#      using the package tool to make a list of all packages that are in the
+#      product bundle.
+#
+#    all_package_manifests.list
+#      This is created by merging the following files from above:
+#        - bazel_package_manifests_list
+#        - universe_package_manifests.list
+#
+# Publishing in fx build
+#
+#    //build/images/updates:publish
+#      After 'all_package_manifests.list' is created, all packages listed in it
+#      are published to the devhost repo.
+#
+# fx publish cache
+#
+#   When just publishing cache, all of the above is skipped.  Instead the
+#   following file is used:
+#
+#    assembly_cache_packages.list
+#      This file is created by taking the list of cache packages from the
+#      output of the product assembly action (not product bundle).
+#      This allows the publishing of cache packages without running the
+#      product bundle creation step.
+#
+
 assert(current_toolchain == default_toolchain,
        "//build/images/* are only valid in the Fuchsia toolchain")
 
@@ -49,8 +188,13 @@
     testonly = true
     visibility = [ ":*" ]
     public_deps = [
+      # The runtime "universe" of packages that's set by the developer.
       "//:developer_universe_packages",
       "//:discoverable_packages",
+
+      # The tests that are added by a developer, and are not verified for their
+      # type.
+      "//:developer_specified_tests",
     ]
   }
 
@@ -97,8 +241,14 @@
   }
 
   #####
-  # These are lists of the packages in the above groups
+  # These are lists of the names of the packages in each package set, sourced
+  # either from assembly's outputs, or from GN metadata walks.  It's not clear
+  # who uses these files (aside from the base_packages.list)
+  # These are intermediate outputs which are used to create the final outputs
 
+  # This file is used by `fx test` to determine if a test package is in the base
+  # package set, and if so, triggers an OTA instead of a resolving of the
+  # package by merkle.
   package_list_from_assembly("base_packages.list") {
     testonly = true
     system_label = labels.images
@@ -141,8 +291,9 @@
       ":all_package_manifests.list",
       ":assembly_cache_packages.list",
       ":base_packages.list",
-      ":cache_packages.list",
-      ":universe_packages.list",
+
+      # ":cache_packages.list",
+      # ":universe_packages.list",
     ]
   }
 
@@ -183,20 +334,10 @@
     ]
   }
 
-  if (use_bazel_images_only) {
-    # Base and cache package_manifests.list files are intentionally left empty
-    # when Bazel assembly is used. The information here will come from Bazel
-    # assembly (fuchsia_product_bundle) instead. See all_package_manifests.list
-    # below.
-    generated_file("base_package_manifests.list") {
-      outputs = [ files.base_package_manifests ]
-      contents = ""
-    }
-    generated_file("cache_package_manifests.list") {
-      outputs = [ files.cache_package_manifests ]
-      contents = ""
-    }
-  } else {
+  if (!use_bazel_images_only) {
+    # When using GN-based assembly, these lists need to be extracted from the
+    # assembly manifest.
+
     package_list_from_assembly("base_package_manifests.list") {
       testonly = true
       system_label = labels.images
@@ -214,12 +355,13 @@
     }
   }
 
-  # Generate a list of cache packages from product assembly for the `fx publish`
-  # tool.
-  cache_packages_from_product_assembler("assembly_cache_packages.list") {
+  # The on_demand package set defined during assembly, so that its packages can
+  # be published along with the universe package set.
+  packages_from_product_assembler("assembly_ondemand_packages.list") {
+    package_set = "on_demand"
     assembly_label = labels.images
     is_bazel_assembled = use_bazel_images_only
-    outputs = [ files.assembly_cache_package_manifests ]
+    outputs = [ files.assembly_ondemand_package_manifests ]
     testonly = true
   }
 
@@ -227,60 +369,107 @@
     testonly = true
     script = "create-universe-package-manifests-list.py"
     depfile = "$root_build_dir/$target_name.d"
-    outputs = [ files.universe_package_manifests ]
-    deps = [
-      ":base_package_manifests.list",
-      ":cache_package_manifests.list",
-      ":package_manifests_from_metadata.list",
-    ]
-
-    inputs = [
-      files.base_package_manifests,
-      files.cache_package_manifests,
-      files.manifests_from_metadata,
-    ]
-
     args = [
       "--depfile",
       rebase_path(depfile, root_build_dir),
-      "-o",
-      rebase_path(outputs[0], root_build_dir),
     ]
-    foreach(input, inputs) {
-      args += [ rebase_path(input, root_build_dir) ]
+
+    # The paths from GN metdaata walk
+    deps = [ ":package_manifests_from_metadata.list" ]
+    inputs = [ files.manifests_from_metadata ]
+    args += [
+      "--metadata-walk-manifests-list",
+      rebase_path(files.manifests_from_metadata, root_build_dir),
+    ]
+
+    # TODO - This action previously used empty package lists for base and cache
+    # packages from assembly, meaning that it just output those packages found
+    # via metadata walk, without stripping any duplicates with assembly.  This
+    # seems incorrect.
+    if (!use_bazel_images_only) {
+      # The package sets from assembly, which need to be stripped from the above
+      deps += [
+        ":assembly_ondemand_packages.list",
+        ":base_package_manifests.list",
+        ":cache_package_manifests.list",
+      ]
+      inputs += [
+        files.base_package_manifests,
+        files.cache_package_manifests,
+        files.assembly_ondemand_package_manifests,
+      ]
+      args += [
+        "--assembly-base-manifests-list",
+        rebase_path(files.base_package_manifests, root_build_dir),
+        "--assembly-cache-manifests-list",
+        rebase_path(files.cache_package_manifests, root_build_dir),
+        "--assembly-ondemand-manifests-list",
+        rebase_path(files.assembly_ondemand_package_manifests, root_build_dir),
+      ]
     }
+
+    # And the output file.
+    outputs = [ files.universe_package_manifests ]
+    args += [
+      "-o",
+      rebase_path(files.universe_package_manifests, root_build_dir),
+    ]
   }
 
   action("all_package_manifests.list") {
     testonly = true
     script = "create-all-package-manifests-list.py"
-    outputs = [ all_package_manifests_list ]
-    deps = []
-    args = rebase_path(outputs, root_build_dir)
-    sources = []
 
-    _manifest_deps = [ ":universe_package_manifests.list" ]
+    # GN legacy-defined universe packages
+    deps = [ ":universe_package_manifests.list" ]
+    inputs = [ files.universe_package_manifests ]
+    args = [
+      "--paths",
+      rebase_path(files.universe_package_manifests, root_build_dir),
+    ]
 
     if (use_bazel_images_only) {
+      # Assemblies in Bazel provide a single file that lists all packages in
+      # base and cache
       deps += [ labels.bazel_package_manifests_list ]
-
-      args +=
-          [ rebase_path(files.bazel_package_manifests_list, root_build_dir) ]
-      sources += [ files.bazel_package_manifests_list ]
+      inputs += [ files.bazel_package_manifests_list ]
+      args += [
+        "--paths",
+        rebase_path(files.bazel_package_manifests_list, root_build_dir),
+      ]
     } else {
-      _manifest_deps += [
+      # Assemblies in GN use a file for each package set.
+      deps += [
         ":base_package_manifests.list",
         ":cache_package_manifests.list",
       ]
+      inputs += [
+        files.base_package_manifests,
+        files.cache_package_manifests,
+      ]
+      args += [
+        "--paths",
+        rebase_path(files.base_package_manifests, root_build_dir),
+        "--paths",
+        rebase_path(files.cache_package_manifests, root_build_dir),
+      ]
     }
 
-    foreach(_dep, _manifest_deps) {
-      deps += [ _dep ]
-      _dep_outputs = []  # tell gn its ok to rewrite each iteration
-      _dep_outputs = get_target_outputs(_dep)
-      args += [ rebase_path(_dep_outputs[0], root_build_dir) ]
-      sources += [ _dep_outputs[0] ]
-    }
+    # The on_demand package set is added via the same mechanism, whether it's a
+    # Bazel or GN-based assembly.
+    deps += [ ":assembly_ondemand_packages.list" ]
+    inputs += [ files.assembly_ondemand_package_manifests ]
+    args += [
+      "--paths",
+      rebase_path(files.assembly_ondemand_package_manifests, root_build_dir),
+    ]
+
+    # And the output file
+    outputs = [ all_package_manifests_list ]
+    args += [
+      "--output",
+      rebase_path(all_package_manifests_list, root_build_dir),
+    ]
   }
 
   _output_repository_dir = "${root_build_dir}/amber-files"
@@ -311,6 +500,21 @@
     }
   }
 
+  # Generate a list of packages for the `fx publish` tool to use, these are
+  # different from those used above to create the `all_package_manifests.list`
+  # files.
+  #
+  # These are defined by assembly, and not by legacy GN arguments.
+
+  # The cache package set from assembly
+  packages_from_product_assembler("assembly_cache_packages.list") {
+    package_set = "cache"
+    assembly_label = labels.images
+    is_bazel_assembled = use_bazel_images_only
+    outputs = [ files.assembly_cache_package_manifests ]
+    testonly = true
+  }
+
   # Allow the incremental publisher to stage the repository keys and root metadata so it can publish
   # without needing to do a full build.
   group("prepare_publish") {
diff --git a/build/images/updates/create-all-package-manifests-list.py b/build/images/updates/create-all-package-manifests-list.py
index 0c70c59..c6731b4 100644
--- a/build/images/updates/create-all-package-manifests-list.py
+++ b/build/images/updates/create-all-package-manifests-list.py
@@ -12,23 +12,25 @@
 
 def main():
     parser = argparse.ArgumentParser()
-    parser.add_argument("output", help="Write to this file")
-    parser.add_argument("paths", nargs="+", help="package manifest lists")
+    parser.add_argument("--output", help="Write to this file")
+    parser.add_argument(
+        "--paths", action="append", help="package manifest lists"
+    )
     args = parser.parse_args()
 
     out = tempfile.NamedTemporaryFile(
         "w", dir=os.path.dirname(args.output), delete=False
     )
     try:
-        manifest_paths = []
+        manifest_paths = set()
         for package_manifest_list_path in args.paths:
             with open(package_manifest_list_path, "r") as f:
                 package_manifest_list = json.load(f)
-                manifest_paths.extend(
+                manifest_paths.update(
                     package_manifest_list["content"]["manifests"]
                 )
         out_package_manifest_list = {
-            "content": {"manifests": manifest_paths},
+            "content": {"manifests": sorted(manifest_paths)},
             "version": "1",
         }
 
diff --git a/build/images/updates/create-universe-package-manifests-list.py b/build/images/updates/create-universe-package-manifests-list.py
index 2d60204..7f8ac6a 100644
--- a/build/images/updates/create-universe-package-manifests-list.py
+++ b/build/images/updates/create-universe-package-manifests-list.py
@@ -10,58 +10,91 @@
 from collections import OrderedDict
 
 
-def read_manifest_list(manifest_list_file):
+def read_manifest_list(maybe_manifest_list_file_path):
     manifest_list = OrderedDict()
-    contents = manifest_list_file.read()
-    if not contents:
-        # `manifest_list_file` can be an empty file...
-        return manifest_list
+    if maybe_manifest_list_file_path:
+        with open(maybe_manifest_list_file_path) as manifest_list_file:
+            contents = manifest_list_file.read()
+            if not contents:
+                # `manifest_list_file` can be an empty file...
+                return manifest_list
 
-    manifest_list_object = json.loads(contents)
-    for manifest_path in manifest_list_object["content"]["manifests"]:
-        with open(manifest_path) as f:
-            manifest = json.load(f)
-            manifest_list[manifest["package"]["name"]] = manifest_path
+            manifest_list_object = json.loads(contents)
+            for manifest_path in manifest_list_object["content"]["manifests"]:
+                with open(manifest_path) as f:
+                    manifest = json.load(f)
+                    manifest_list[manifest["package"]["name"]] = manifest_path
 
     return manifest_list
 
 
 def main():
-    parser = argparse.ArgumentParser()
+    parser = argparse.ArgumentParser(
+        description="Create a single list of packages that are only in the GN metadata-based "
+        "'universe' package set, by stripping all assembly-contributed packages from "
+        "those found by GN metadata walk."
+    )
     parser.add_argument("--depfile", help="If provided, create this depfile")
     parser.add_argument(
         "-o",
         "--output",
         help="If provided, write to this output package manifest list rather than stdout",
     )
-    parser.add_argument("base", help="base package manifest list")
-    parser.add_argument("cache", help="cache package manifest list")
-    parser.add_argument("metadata", help="metadata package manifest list")
+    parser.add_argument(
+        "--assembly-base-manifests-list",
+        help="base package manifest list from assembly",
+    )
+    parser.add_argument(
+        "--assembly-cache-manifests-list",
+        help="cache package manifest list from assembly",
+    )
+    parser.add_argument(
+        "--assembly-ondemand-manifests-list",
+        help="on_demand package manifest list from assembly",
+    )
+    parser.add_argument(
+        "--metadata-walk-manifests-list",
+        required=True,
+        help="universe package manifest list from GN metadata walk",
+    )
     args = parser.parse_args()
 
-    with open(args.base) as f:
-        base_list = read_manifest_list(f)
+    base_list = read_manifest_list(args.assembly_base_manifests_list)
+    cache_list = read_manifest_list(args.assembly_cache_manifests_list)
+    ondemand_list = read_manifest_list(args.assembly_ondemand_manifests_list)
+    metadata_walk_list = read_manifest_list(args.metadata_walk_manifests_list)
 
-    with open(args.cache) as f:
-        cache_list = read_manifest_list(f)
-
-    with open(args.metadata) as f:
-        metadata_list = read_manifest_list(f)
+    # The following checks _shouldn't_ be necessary, as product assembly should
+    # never be creating a situation where the same package is in multiple
+    # sets.  They should probably be removed.
+    failures = []
 
     # make sure the cache package list doesn't have any base packages.
     for name, path in cache_list.items():
         if name in base_list:
-            print(
-                "package",
-                name,
-                "is both a base and cache package",
-                file=sys.stderr,
+            failures.append(f"package {name} is both a base and cache package")
+
+    for name, path in ondemand_list.items():
+        if name in base_list:
+            failures.append(
+                f"package {name} is both a base and on_demand package"
             )
             sys.exit(1)
 
+    for name, path in ondemand_list.items():
+        if name in cache_list:
+            failures.append(
+                f"package {name} is both a cache and on_demand package"
+            )
+
+    if failures:
+        for failure in failures:
+            print(failure, file=sys.stderr)
+        sys.exit(1)
+
     manifest_paths = []
-    for name, path in metadata_list.items():
-        if name in base_list or name in cache_list:
+    for name, path in metadata_walk_list.items():
+        if name in base_list or name in cache_list or name in ondemand_list:
             continue
 
         manifest_paths.append(path)
@@ -78,7 +111,8 @@
         with open(args.depfile, "w") as f:
             deps = list(base_list.values())
             deps.extend(cache_list.values())
-            deps.extend(metadata_list.values())
+            deps.extend(ondemand_list.values())
+            deps.extend(metadata_walk_list.values())
 
             f.write(f"{args.output}: {' '.join(deps)}\n")
 
diff --git a/build/images/updates/tests/BUILD.bazel b/build/images/updates/tests/BUILD.bazel
index ff9c534..513c8f0 100644
--- a/build/images/updates/tests/BUILD.bazel
+++ b/build/images/updates/tests/BUILD.bazel
@@ -34,7 +34,6 @@
             "build_type": BUILD_TYPES.ENG,
             "feature_set_level": "utility",
             "storage": {
-                "configure_fshost": True,
                 "filesystems": {
                     "image_name": "fx_publish",
                     "volume": {
diff --git a/build/images/updates/tests/BUILD.gn b/build/images/updates/tests/BUILD.gn
index 1da3b68..5c0bc50 100644
--- a/build/images/updates/tests/BUILD.gn
+++ b/build/images/updates/tests/BUILD.gn
@@ -16,7 +16,7 @@
 if (is_fuchsia) {
   import("//build/assembly/assembled_system.gni")
   import("//build/assembly/board_configuration.gni")
-  import("//build/assembly/cache_packages_from_product_assembler.gni")
+  import("//build/assembly/packages_from_product_assembler.gni")
   import("//build/assembly/product_assembly_configuration.gni")
   import("//build/bazel/assembly/bazel_product_bundle.gni")
   import("//build/images/paths.gni")
@@ -33,7 +33,6 @@
       build_type = "eng"
       feature_set_level = "utility"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = "fx_publish"
           volume = {
@@ -94,15 +93,16 @@
       outputs = [ bazel_assembly_cache_packages_list ]
     }
   } else {
-    cache_packages_from_product_assembler("gn_assembly_cache_packages.list") {
+    packages_from_product_assembler("gn_assembly_cache_packages.list") {
       assembly_label = ":fx_publish_test.gn_assembly($default_toolchain)"
+      package_set = "cache"
       is_bazel_assembled = false
       outputs = [ gn_assembly_cache_packages_list ]
       testonly = true
     }
-    cache_packages_from_product_assembler(
-        "bazel_assembly_cache_packages.list") {
+    packages_from_product_assembler("bazel_assembly_cache_packages.list") {
       assembly_label = ":bazel_pb($default_toolchain)"
+      package_set = "cache"
       is_bazel_assembled = true
       outputs = [ bazel_assembly_cache_packages_list ]
       testonly = true
diff --git a/build/info/BUILD.gn b/build/info/BUILD.gn
index c396910..59afb87 100644
--- a/build/info/BUILD.gn
+++ b/build/info/BUILD.gn
@@ -22,6 +22,23 @@
     ]
   }
 
+  # Ensure this action is invoked if integration HEAD moves
+  _inputs = [
+    # LINT.IfChange
+    # https://fxbug.dev/335391299. These are generated by a Jiri
+    # hook in //integration/fuchsia/stem. Until the hook is activated
+    # these files have empty values but are still read by the
+    # script before `git` is invoked.
+    "//build/info/jiri_generated/integration_commit_stamp.txt",
+    "//build/info/jiri_generated/integration_commit_hash.txt",
+
+    # LINT.ThenChange(//build/info/create_jiri_hook_files.sh)
+
+    # https://fxbug.dev/335391299. Remove the line below once
+    # the Jiri hook has been added to //integration/fuchsia/stem.
+    "//integration/.git/HEAD",
+  ]
+
   # LINT.IfChange
   action("latest-commit-date-and-hash") {
     visibility = [
@@ -29,8 +46,7 @@
       "bootfs/*",
     ]
 
-    # Ensure this action is invoked if integration HEAD moves
-    inputs = [ "//integration/.git/HEAD" ]
+    inputs = _inputs
     outputs = [
       build_info_files.latest_commit_date,
       build_info_files.minimum_utc_stamp,
@@ -40,6 +56,7 @@
     args = [
       "--repo",
       rebase_path("//integration/", root_build_dir),
+      "--use-jiri-values",
       "--timestamp-file",
       rebase_path(build_info_files.minimum_utc_stamp, root_build_dir),
       "--date-file",
@@ -50,6 +67,8 @@
     if (truncate_build_info_commit_date) {
       args += [ "--truncate" ]
     }
+
+    # LINT.ThenChange(//build/info/info.bzl)
   }
 
   if (build_info_version != "") {
@@ -64,6 +83,4 @@
       deps = [ ":latest-commit-date-and-hash" ]
     }
   }
-
-  # LINT.ThenChange(//build/info/info.bzl)
 }
diff --git a/build/info/create_jiri_hook_files.sh b/build/info/create_jiri_hook_files.sh
new file mode 100755
index 0000000..c590a4a
--- /dev/null
+++ b/build/info/create_jiri_hook_files.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script is expected to be invoked as a Jiri hook from
+# integration/fuchsia/stem.
+
+# Its purpose is to generate a Unix timestamp and a commit hash
+# file under //build/info/jiri_generated/
+#
+# For context, see https://fxbug.dev/335391299
+#
+# This uses the //build/info/gen_latest_commit_date.py script
+# with the --force-git option to generate them. Without this
+# option, the same script, which will be invoked at build time,
+# will read these files as input instead, and process them before
+# writing them to their final destination in the Ninja or Bazel
+# build artifact directories.
+
+_SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
+
+fatal () {
+  echo >&2 "FATAL: $*"
+  exit 1
+}
+
+# Assume this script lives under //build/info/
+FUCHSIA_DIR="$(cd "${_SCRIPT_DIR}/../.." && pwd -P 2>/dev/null)"
+if [[ ! -f "${FUCHSIA_DIR}/.jiri_manifest" ]]; then
+  fatal "Cannot locate proper FUCHSIA_DIR, got: ${FUCHSIA_DIR}"
+fi
+
+# Use the OSTYPE and MACHTYPE Bash builtin variables to determine host
+# machine type.
+case "$OSTYPE" in
+  linux*)
+    readonly HOST_OS="linux"
+    ;;
+  darwin*)
+    readonly HOST_OS="mac"
+    ;;
+  *)
+    echo >&2 "Unknown operating system: $OSTYPE."
+    exit 1
+    ;;
+esac
+
+case "$MACHTYPE" in
+  x86_64*)
+    readonly HOST_CPU="x64"
+    ;;
+  aarch64*|arm64*)
+    readonly HOST_CPU="arm64"
+    ;;
+  *)
+    echo >&2 "Unknown architecture: $MACHTYPE."
+    exit 1
+    ;;
+esac
+
+# Locate prebuilt python interpreter.
+PREBUILT_PYTHON="$FUCHSIA_DIR/prebuilt/third_party/python3/${HOST_OS}-${HOST_CPU}/bin/python3"
+if [[ ! -f "${PREBUILT_PYTHON}" ]]; then
+  fatal "Cannot locate PREBUILT_PYTHON: $PREBUILT_PYTHON"
+fi
+
+# LINT.IfChange
+OUTPUT_DIR="${_SCRIPT_DIR}/jiri_generated"
+mkdir -p "${OUTPUT_DIR}"
+
+"$PREBUILT_PYTHON" -S \
+  "${_SCRIPT_DIR}/gen_latest_commit_date.py" \
+  --repo "${FUCHSIA_DIR}/integration" \
+  --timestamp-file "$OUTPUT_DIR/integration_commit_stamp.txt" \
+  --commit-hash-file "${OUTPUT_DIR}/integration_commit_hash.txt"
+# LINT.ThenChange(//build/info/gen_latest_commit_date.py)
diff --git a/build/info/gen_latest_commit_date.py b/build/info/gen_latest_commit_date.py
index 5b85004..f882cb3 100755
--- a/build/info/gen_latest_commit_date.py
+++ b/build/info/gen_latest_commit_date.py
@@ -25,6 +25,8 @@
 import sys
 import subprocess
 
+_SCRIPT_DIR = os.path.dirname(__file__)
+
 
 def main():
     parser = argparse.ArgumentParser(
@@ -35,6 +37,11 @@
         "--git", default="git", help="path to git binary to use"
     )
     parser.add_argument(
+        "--use-jiri-values",
+        action="store_true",
+        help="Use Jiri-generated values instead of invoking git, if possible.",
+    )
+    parser.add_argument(
         "--timestamp-file", help="path to write the unix-style timestamp to"
     )
     parser.add_argument(
@@ -51,42 +58,74 @@
 
     args = parser.parse_args()
 
-    # This script fails mysteriously when invoked in our CI build environment
-    # (though it does work locally). Since it is very hard to debug, and that
-    # MacOS support is now deprecated and soon will be removed, just fake the
-    # values here instead.
-    if sys.platform == "darwin":
-        latest_commit_hash = "254f018638fdf35e91a72b26c030c453bfd0238e"
-        latest_commit_date_unix = 1712566485
-    else:
-        # Set the following options to make the output as stable as possible:
-        # - GIT_CONFIG_NOSYSTEM=1   - Don't check /etc/gitconfig
-        # - --no-optional-locks     - Do not update the git index during read-only operations
-        #                             (see https://fxbug.dev/42175708).
-        # - --date=unix             - Format date as a unix timestamp
-        # - --format=%H\n%cd        - Print the hash and CommitDate fields only, on separate lines
-        git_cmd = [
-            args.git,
-            "--no-optional-locks",
-            f"--git-dir={args.repo}/.git",
-            "log",
-            "--date=unix",
-            "--format=%H\n%cd",
-            "-n",
-            "1",
-        ]
-        git_env = {}
-        git_env.update(os.environ)
-        git_env["GIT_CONFIG_NOSYSTEM"] = "1"
-        result = subprocess.run(
-            git_cmd, env=git_env, check=True, capture_output=True, text=True
-        )
+    latest_commit_hash = None
+    latest_commit_date_unix = 0
+    # First look at files in the jiri_generated/ directory, and use them
+    # if they exist, unless the --force-git option is used.
 
-        # Take the hash and timestamp lines, split and parse/convert them.
-        output_lines = result.stdout.split()
+    # LINT.IfChange
+    if args.use_jiri_values:
+        generated_dir = os.path.join(_SCRIPT_DIR, "jiri_generated")
+        # These files a normally created by a Jiri hook that invokes
+        # //build/info/create_jiri_hook_files.sh.
+        #
+        # However, before the hook is active, they are created with
+        # explicit values ("" and "0" respecitively). Which will force
+        # the use of git after they are loaded.
+        repo_name = os.path.basename(args.repo)
+        hash_file = os.path.join(generated_dir, f"{repo_name}_commit_hash.txt")
+        date_file = os.path.join(generated_dir, f"{repo_name}_commit_stamp.txt")
+        if os.path.exists(hash_file) and os.path.exists(date_file):
+            with open(hash_file) as f:
+                latest_commit_hash = f.read().strip()
+            with open(date_file) as f:
+                latest_commit_date_unix = int(f.read().strip())
 
-        latest_commit_hash = output_lines[0]
-        latest_commit_date_unix = int(output_lines[1])
+        if not latest_commit_hash:
+            print(
+                "WARNING: Falling back to git values, as Jiri values do not exist or are empty.",
+                file=sys.stderr,
+            )
+    # LINT.ThenChange(//build/info/create_jiri_hook_files.sh)
+
+    if not latest_commit_hash:
+        # This script fails mysteriously when invoked in our CI build environment
+        # (though it does work locally). Since it is very hard to debug, and that
+        # MacOS support is now deprecated and soon will be removed, just fake the
+        # values here instead.
+        if sys.platform == "darwin":
+            latest_commit_hash = "254f018638fdf35e91a72b26c030c453bfd0238e"
+            latest_commit_date_unix = 1712566485
+        else:
+            # Use git to extract the values directly.
+            # Set the following options to make the output as stable as possible:
+            # - GIT_CONFIG_NOSYSTEM=1   - Don't check /etc/gitconfig
+            # - --no-optional-locks     - Do not update the git index during read-only operations
+            #                             (see https://fxbug.dev/42175708).
+            # - --date=unix             - Format date as a unix timestamp
+            # - --format=%H\n%cd        - Print the hash and CommitDate fields only, on separate lines
+            git_cmd = [
+                args.git,
+                "--no-optional-locks",
+                f"--git-dir={args.repo}/.git",
+                "log",
+                "--date=unix",
+                "--format=%H\n%cd",
+                "-n",
+                "1",
+            ]
+            git_env = {}
+            git_env.update(os.environ)
+            git_env["GIT_CONFIG_NOSYSTEM"] = "1"
+            result = subprocess.run(
+                git_cmd, env=git_env, check=True, capture_output=True, text=True
+            )
+
+            # Take the hash and timestamp lines, split and parse/convert them.
+            output_lines = result.stdout.split()
+
+            latest_commit_hash = output_lines[0]
+            latest_commit_date_unix = int(output_lines[1])
 
     latest_commit_date = datetime.fromtimestamp(
         latest_commit_date_unix, timezone.utc
diff --git a/build/info/info.bzl b/build/info/info.bzl
index 2368670..f6ed94a 100644
--- a/build/info/info.bzl
+++ b/build/info/info.bzl
@@ -42,6 +42,7 @@
     # Build command line arguments.
     cmd_args = [
         ctx.file._py_script.path,
+        "--use-jiri-values",
         "--git",
         ctx.file._git.path,
         "--timestamp-file",
@@ -60,7 +61,8 @@
     runfiles = ctx.runfiles(
         files = [
             ctx.file._integration_git_head,
-            ctx.file._py_script,
+            ctx.file._integration_commit_hash,
+            ctx.file._integration_commit_stamp,
         ],
         transitive_files = python3_runfiles.files,
     )
@@ -88,6 +90,8 @@
             allow_single_file = True,
             default = "//build/info:gen_latest_commit_date.py",
         ),
+        # https://fxbug.dev/335391299: Remove this once the Jiri hook
+        # has been enabled.
         "_git": attr.label(
             allow_single_file = True,
             doc = "Git binary to use.",
@@ -95,6 +99,14 @@
             default = "//:fuchsia_build_generated/git",
             # LINT.ThenChange(//build/bazel/scripts/update_workspace.py)
         ),
+        "_integration_commit_hash": attr.label(
+            allow_single_file = True,
+            default = "//build/info:jiri_generated/integration_commit_hash.txt",
+        ),
+        "_integration_commit_stamp": attr.label(
+            allow_single_file = True,
+            default = "//build/info:jiri_generated/integration_commit_stamp.txt",
+        ),
     } | PY_TOOLCHAIN_DEPS,
 )
 
diff --git a/build/info/jiri_generated/.gitignore b/build/info/jiri_generated/.gitignore
new file mode 100644
index 0000000..d1fb716
--- /dev/null
+++ b/build/info/jiri_generated/.gitignore
@@ -0,0 +1,2 @@
+integration_commit_hash.txt
+integration_commit_stamp.txt
diff --git a/build/info/jiri_generated/README.md b/build/info/jiri_generated/README.md
new file mode 100644
index 0000000..522a7b5
--- /dev/null
+++ b/build/info/jiri_generated/README.md
@@ -0,0 +1,14 @@
+This directory contains two files which reflect the commit
+hash and timestamp of //integration/.git/HEAD.
+
+A Jiri hook, in //integration/fuchsia/stem, is used to invoke
+`//build/info/create_jiri_hook_files.sh` which will overwrite
+them, on each `jiri sync` operation, with up-to-date values.
+
+The files are listed in this directory's `.gitignore` to ensure
+that their updates are properly ignored by git commands. Their
+default values in the fuchsia.git checkout are provided to ensure
+that everything works even if the hook is not enabled yet in
+the integration.git repository.
+
+For context, see https://fxbug.dev/335391299
diff --git a/build/info/jiri_generated/integration_commit_hash.txt b/build/info/jiri_generated/integration_commit_hash.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/build/info/jiri_generated/integration_commit_hash.txt
@@ -0,0 +1 @@
+
diff --git a/build/info/jiri_generated/integration_commit_stamp.txt b/build/info/jiri_generated/integration_commit_stamp.txt
new file mode 100644
index 0000000..573541ac
--- /dev/null
+++ b/build/info/jiri_generated/integration_commit_stamp.txt
@@ -0,0 +1 @@
+0
diff --git a/build/licenses/generated_licenses_spdx.gni b/build/licenses/generated_licenses_spdx.gni
index acb0780..821b690 100644
--- a/build/licenses/generated_licenses_spdx.gni
+++ b/build/licenses/generated_licenses_spdx.gni
@@ -154,6 +154,7 @@
     }
 
     generated_file(_targets.generated_metadata) {
+      forward_variables_from(invoker, [ "testonly" ])
       outputs = [ _files.generated_metadata ]
       data_keys = [
         "license",
diff --git a/build/licenses/python/BUILD.gn b/build/licenses/python/BUILD.gn
index fe554c5..174c328 100644
--- a/build/licenses/python/BUILD.gn
+++ b/build/licenses/python/BUILD.gn
@@ -22,6 +22,7 @@
   python_binary("generated_licenses_spdx_tool") {
     main_source = "generated_licenses_spdx_tool.py"
     sources = common_sources
+    enable_mypy = true
   }
 
   # The following tests can be run conveniently also via:
diff --git a/build/licenses/python/collector.py b/build/licenses/python/collector.py
index d1582fa..0a3b4d8 100644
--- a/build/licenses/python/collector.py
+++ b/build/licenses/python/collector.py
@@ -7,7 +7,6 @@
 from collections import defaultdict
 import enum
 import logging
-from pathlib import Path
 from readme_fuchsia import ReadmesDB, Readme
 from gn_license_metadata import (
     GnApplicableLicensesMetadata,
@@ -17,6 +16,7 @@
 from gn_label import GnLabel
 from file_access import FileAccess
 import dataclasses
+import os
 
 
 @dataclasses.dataclass(frozen=True)
@@ -25,8 +25,9 @@
 
     public_name: str
     license_files: tuple[GnLabel]
-    debug_hint: str = dataclasses.field(hash=False, compare=False)
+    debug_hint: str = dataclasses.field(hash=False, compare=False, default="")
 
+    @staticmethod
     def create(
         public_name: str,
         license_files: Tuple[GnLabel],
@@ -43,7 +44,7 @@
     def __str__(self) -> str:
         return (
             """License(name='{name}', files=[{files}], hint='{hint}')""".format(
-                name=self.name,
+                name=self.public_name,
                 files=", ".join([str(f) for f in self.license_files]),
                 hint=self.debug_hint,
             )
@@ -144,7 +145,7 @@
 
     kind: CollectorErrorKind
     target_label: GnLabel
-    debug_hint: str = dataclasses.field(hash=False, compare=False, default=None)
+    debug_hint: str = dataclasses.field(hash=False, compare=False, default="")
 
 
 @dataclasses.dataclass(frozen=False)
@@ -188,7 +189,7 @@
     errors: List[CollectorError] = dataclasses.field(default_factory=list)
     stats: CollectorStats = dataclasses.field(default_factory=CollectorStats)
 
-    def _add_error(self, error: CollectorError):
+    def _add_error(self, error: CollectorError) -> None:
         logging.debug(
             "Collection error %s for %s: %s",
             error.kind.name,
@@ -197,7 +198,7 @@
         )
         self.errors.append(error)
 
-    def _add_license(self, lic: CollectedLicense):
+    def _add_license(self, lic: CollectedLicense) -> None:
         logging.debug(
             "Collected license %s %s: %s",
             lic.public_name,
@@ -210,7 +211,7 @@
 
     def _add_license_from_metadata(
         self, license_metadata_label: GnLabel, used_by_target: GnLabel
-    ):
+    ) -> None:
         if (
             license_metadata_label.without_toolchain()
             in _ignored_license_labels
@@ -301,7 +302,7 @@
         return True
 
     def _add_licenses_for_golib(
-        self, label: GnLabel, original_label=None
+        self, label: GnLabel, original_label: GnLabel | None = None
     ) -> bool:
         assert label.is_3p_golib()
 
@@ -318,8 +319,8 @@
 
         public_package_name = label.name.split("/")[-1]
 
-        def license_file_predicate(path: Path) -> bool:
-            file_name_upper = path.name.upper()
+        def license_file_predicate(path: str) -> bool:
+            file_name_upper = os.path.basename(path).upper()
             return file_name_upper in (
                 "LICENSE",
                 "COPYRIGHT",
@@ -364,7 +365,7 @@
             self._add_license(
                 CollectedLicense.create(
                     public_name="Fuchsia",
-                    license_files=tuple([self.default_license_file]),
+                    license_files=(self.default_license_file,),
                     collection_hint="Default license for non 3p targets",
                 )
             )
@@ -381,8 +382,9 @@
         resource_of: GnLabel = None,
         is_resource_of_target_with_licenses: bool = False,
     ) -> bool:
-        if label in self.scan_result_by_label:
-            return self.scan_result_by_label[label]
+        result = self.scan_result_by_label.get(label, None)
+        if result is not None:
+            return result
         elif not self.include_host_tools and label.is_host_target():
             logging.debug(
                 "Skipping host target %s since include_host_tools=False", label
@@ -393,12 +395,11 @@
         is_group_target = False
         resources = None
 
-        target_metadata: GnApplicableLicensesMetadata = None
-        if label in self.metadata_db.applicable_licenses_by_target:
+        target_metadata: GnApplicableLicensesMetadata = (
+            self.metadata_db.applicable_licenses_by_target.get(label, None)
+        )
+        if target_metadata is not None:
             self.stats.targets_scanned += 1
-            target_metadata = self.metadata_db.applicable_licenses_by_target[
-                label
-            ]
             is_group_target = target_metadata.is_group()
             resources = target_metadata.third_party_resources
 
@@ -482,7 +483,7 @@
                     CollectorError(
                         kind=CollectorErrorKind.THIRD_PARTY_TARGET_WITHOUT_APPLICABLE_LICENSES,
                         target_label=label,
-                        debug_hint=None,
+                        debug_hint="",
                     )
                 )
 
@@ -491,7 +492,7 @@
 
         return license_found
 
-    def collect(self):
+    def collect(self) -> None:
         # Reset
         self.stats = CollectorStats()
         self.errors.clear()
@@ -503,7 +504,7 @@
         ) in self.metadata_db.applicable_licenses_by_target.values():
             self._scan_label(target_metadata.target_label)
 
-    def log_errors(self, log_level: int, is_full_report: bool):
+    def log_errors(self, log_level: int, is_full_report: bool) -> None:
         errors_by_kind: Dict[
             CollectorErrorKind, List[CollectorError]
         ] = defaultdict(list)
diff --git a/build/licenses/python/file_access.py b/build/licenses/python/file_access.py
index 85dba6e..4407038 100644
--- a/build/licenses/python/file_access.py
+++ b/build/licenses/python/file_access.py
@@ -3,7 +3,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from pathlib import Path
 from typing import Callable, List, Set
 from gn_label import GnLabel
 import dataclasses
@@ -14,21 +13,22 @@
 class FileAccess:
     """Manages access to the real file system, while keeping track of depfiles."""
 
-    fuchsia_source_path: Path
-    visited_files: Set[GnLabel] = dataclasses.field(default_factory=set)
+    fuchsia_source_path_str: str
+    visited_files: Set[str] = dataclasses.field(default_factory=set)
 
     def read_text(self, label: GnLabel) -> str:
         """Reads the file into a text string"""
         GnLabel.check_type(label)
-        path = self.fuchsia_source_path / label.path
+        path = os.path.join(self.fuchsia_source_path_str, label.path_str)
         self.visited_files.add(path)
-        return path.read_text()
+        with open(path) as f:
+            return f.read()
 
     def file_exists(self, label: GnLabel) -> bool:
         """Whether the file exists and is not a directory"""
         GnLabel.check_type(label)
-        path = self.fuchsia_source_path / label.path
-        if path.exists() and path.is_file():
+        path = os.path.join(self.fuchsia_source_path_str, label.path_str)
+        if os.path.isfile(path):
             self.visited_files.add(path)
             return True
         return False
@@ -36,39 +36,40 @@
     def directory_exists(self, label: GnLabel) -> bool:
         """Whether the directory exists and is indeed a directory"""
         GnLabel.check_type(label)
-        path = self.fuchsia_source_path / label.path
-        if path.exists() and path.is_dir():
+        path = os.path.join(self.fuchsia_source_path_str, label.path_str)
+        if os.path.isdir(path):
             self.visited_files.add(path)
             return True
         return False
 
     def search_directory(
-        self, label: GnLabel, path_predicate: Callable[[Path], bool]
+        self, label: GnLabel, path_predicate: Callable[[str], bool]
     ) -> List[GnLabel]:
         """Lists the files in a directory corresponding with `label` (including files in subdirs) matching `path_predicate`"""
         GnLabel.check_type(label)
-        path = self.fuchsia_source_path / label.path
+        path = os.path.join(self.fuchsia_source_path_str, label.path_str)
         self.visited_files.add(path)
 
         output = []
 
         for root, _, files in os.walk(path):
-            root_path = Path(root)
             for file in files:
-                file_path = root_path / file
+                file_path = os.path.join(root, file)
                 if path_predicate(file_path):
-                    relative_to_label = file_path.relative_to(
-                        self.fuchsia_source_path
-                    ).relative_to(label.path)
+                    relative_to_label = os.path.relpath(
+                        os.path.relpath(
+                            file_path, self.fuchsia_source_path_str
+                        ),
+                        label.path_str,
+                    )
                     output.append(
-                        label.create_child_from_str(str(relative_to_label))
+                        label.create_child_from_str(relative_to_label)
                     )
 
         return output
 
-    def write_depfile(self, dep_file_path: Path, main_entry: Path):
-        if not dep_file_path.parent.exists():
-            dep_file_path.parent.mkdir(parents=True, exist_ok=True)
+    def write_depfile(self, dep_file_path: str, main_entry: str) -> None:
+        os.makedirs(os.path.dirname(dep_file_path), exist_ok=True)
         with open(dep_file_path, "w") as dep_file:
             dep_file.write(f"{main_entry}:\\\n")
             dep_file.write(
diff --git a/build/licenses/python/file_access_test.py b/build/licenses/python/file_access_test.py
index 9367379..4a52be3 100644
--- a/build/licenses/python/file_access_test.py
+++ b/build/licenses/python/file_access_test.py
@@ -8,6 +8,7 @@
 from file_access import FileAccess
 from gn_label import GnLabel
 from pathlib import Path
+import os
 import tempfile
 import unittest
 
@@ -20,7 +21,9 @@
     def setUp(self) -> None:
         self.temp_dir = tempfile.TemporaryDirectory()
         self.temp_dir_path = Path(self.temp_dir.name)
-        self.file_access = FileAccess(fuchsia_source_path=self.temp_dir_path)
+        self.file_access = FileAccess(
+            fuchsia_source_path_str=self.temp_dir.name
+        )
 
         file_path1 = self.temp_dir_path / "foo"
         file_path1.write_text("FOO")
@@ -70,7 +73,7 @@
     def test_search_directory_with_predicate(self):
         children = self.file_access.search_directory(
             GnLabel.from_str("//"),
-            path_predicate=lambda path: path.name == "bar",
+            path_predicate=lambda path: os.path.basename(path) == "bar",
         )
         children.sort()
         self.assertEqual(children, [GnLabel.from_str("//bar")])
@@ -86,7 +89,7 @@
     def _assert_depfile(self, expected_content):
         depfile_path = self.temp_dir_path / "depfile"
         self.file_access.write_depfile(
-            dep_file_path=depfile_path, main_entry=Path("main")
+            dep_file_path=depfile_path, main_entry="main"
         )
         actual_depfile_contents = depfile_path.read_text()
         self.assertEqual(actual_depfile_contents, expected_content)
@@ -101,13 +104,13 @@
 
     def test_write_depfile_after_directory_exists(self):
         self.file_access.directory_exists(GnLabel.from_str("//"))
-        self._assert_depfile(f"""main:\\\n    {self.temp_dir_path}""")
+        self._assert_depfile(f"""main:\\\n    {self.temp_dir_path}/""")
 
     def test_write_depfile_after_search_directory(self):
         self.file_access.search_directory(
             GnLabel.from_str("//"), path_predicate=lambda _: True
         )
-        self._assert_depfile(f"""main:\\\n    {self.temp_dir_path}""")
+        self._assert_depfile(f"""main:\\\n    {self.temp_dir_path}/""")
 
 
 if __name__ == "__main__":
diff --git a/build/licenses/python/generated_licenses_spdx_tool.py b/build/licenses/python/generated_licenses_spdx_tool.py
index 1692d84..55099c7 100644
--- a/build/licenses/python/generated_licenses_spdx_tool.py
+++ b/build/licenses/python/generated_licenses_spdx_tool.py
@@ -7,6 +7,7 @@
 import argparse
 import sys
 import logging
+import os
 from file_access import FileAccess
 from gn_label import GnLabel
 from spdx_writer import SpdxWriter
@@ -17,7 +18,7 @@
 from spdx_comparator import SpdxComparator
 
 
-def main():
+def main() -> int:
     """
     Generates licenses SPDX json file from GN license metadata.
     """
@@ -96,20 +97,21 @@
     log_level = args.log_level.upper()
 
     logging.basicConfig(
-        level=log_level, force="format='%(levelname)s:%(message)s'"
+        level=log_level, force=True, format="%(levelname)s:%(message)s"
     )
 
     fuchsia_source_path = Path(args.fuchsia_source_path).expanduser()
     assert fuchsia_source_path.exists()
     logging.debug("fuchsia_source_path=%s", fuchsia_source_path)
 
-    file_access = FileAccess(fuchsia_source_path=fuchsia_source_path)
+    fuchsia_source_path_str = str(fuchsia_source_path)
+    file_access = FileAccess(fuchsia_source_path_str=fuchsia_source_path_str)
 
     readmes_db = ReadmesDB(file_access=file_access)
 
     metadata_db = GnLicenseMetadataDB.from_file(
-        file_path=Path(args.generated_license_metadata),
-        fuchsia_source_path=fuchsia_source_path,
+        file_path=args.generated_license_metadata,
+        fuchsia_source_path=fuchsia_source_path_str,
     )
 
     # Collect licenses information
@@ -152,16 +154,15 @@
             else None,
         )
 
-    spdx_output_path = Path(args.spdx_output)
-    spdx_writer.save(spdx_output_path)
+    spdx_writer.save(args.spdx_output)
     logging.info(
-        f"Wrote spdx {spdx_output_path} (licenses={len(collector.unique_licenses)} size={spdx_output_path.stat().st_size})"
+        f"Wrote spdx {args.spdx_output} (licenses={len(collector.unique_licenses)} size={os.stat(args.spdx_output).st_size})"
     )
 
     if args.compare_with_legacy_spdx:
         # Compare with legacy spdx file
         comparator = SpdxComparator(
-            current_file=spdx_output_path,
+            current_file=args.spdx_output,
             legacy_file=Path(args.compare_with_legacy_spdx),
         )
         comparator.compare()
@@ -176,9 +177,8 @@
                 return -1
 
     # Generate a GN depfile
-    dep_file_path = Path(args.dep_file)
-    logging.info(f"writing depfile {dep_file_path}")
-    file_access.write_depfile(dep_file_path, main_entry=spdx_output_path)
+    logging.info(f"writing depfile {args.dep_file}")
+    file_access.write_depfile(args.dep_file, main_entry=args.spdx_output)
 
     return 0
 
diff --git a/build/licenses/python/gn_label.py b/build/licenses/python/gn_label.py
index a1adccff..a868182 100644
--- a/build/licenses/python/gn_label.py
+++ b/build/licenses/python/gn_label.py
@@ -5,8 +5,9 @@
 """Utilities for working with GnLabel strings."""
 
 import dataclasses
+import os
 from pathlib import Path
-from typing import List
+from typing import Any, List
 
 
 @dataclasses.dataclass(frozen=True)
@@ -16,14 +17,16 @@
     """The original GN label string, e.g. `//foo/bar:baz(//toolchain)`"""
     gn_str: str
     """The path part of the label, e.g. `foo/bar` in `//foo/bar:baz`"""
-    path: Path = dataclasses.field(hash=False, compare=False)
+    # path: Path = dataclasses.field(hash=False, compare=False)
+    path_str: str = dataclasses.field(hash=False, compare=False)
     """The name part of the label, e.g. `baz` in `//foo/bar:baz` or `bar` for `//foo/bar`"""
     name: str = dataclasses.field(hash=False, compare=False)
     """Whether the label has a local name, e.g. True for `//foo/bar:baz` but false for `//foo/bar/baz`"""
     is_local_name: bool = dataclasses.field(hash=False, compare=False)
     """The toolchain part of the label, e.g. `//toolchain` in `//foo/bar(//toolchain)`"""
-    toolchain: "GnLabel" = dataclasses.field(hash=False, compare=False)
+    toolchain: "GnLabel|None" = dataclasses.field(hash=False, compare=False)
 
+    @staticmethod
     def from_str(original_str: str) -> "GnLabel":
         """Constructs a GnLabel instance from a GN target label string"""
         assert original_str.startswith(
@@ -44,52 +47,55 @@
                 toolchain = GnLabel.from_str(toolchain_str)
                 label = original_str[0:toolchain_begin]
 
-        path_and_name = label.split(":", maxsplit=1)
+        path, colon, name = label[2:].partition(":")
+        if ".." in path:
+            path = GnLabel._resolve_dot_dot(path)
 
-        path_str = path_and_name[0][2:]  # remove '//'
-        if ".." in path_str:
-            path_str = GnLabel._resolve_dot_dot(path_str)
-        path = Path(path_str)
-
-        if len(path_and_name) == 2:
-            name = path_and_name[1]
+        if colon:
             is_local_name = True
+            gn_str = f"//{path}:{name}"
         else:
-            assert len(path_and_name) == 1
-            name = str(path.name)
+            name = os.path.basename(path)
             is_local_name = False
+            gn_str = f"//{path}"
 
-        gn_str = ["//", path_str]
-        if is_local_name:
-            gn_str.extend([":", name])
         if toolchain:
-            gn_str.extend(["(", toolchain.gn_str, ")"])
-        gn_str = "".join(gn_str)
+            gn_str += f"({toolchain.gn_str})"
 
         return GnLabel(
             gn_str=gn_str,
             name=name,
             is_local_name=is_local_name,
-            path=path,
+            path_str=path,
             toolchain=toolchain,
         )
 
-    def from_path(path: Path):
+    @staticmethod
+    def from_path(path: Path | str) -> "GnLabel":
         """Constructs a GnLabel instance from a Path object."""
-        assert isinstance(
-            path, Path
-        ), f"Expected path of type Path but got {type(path)}"
-        if path.name == "" and path.parent.name == "":
-            return GnLabel.from_str("//")
-        return GnLabel.from_str(f"//{path}")
+        if isinstance(path, Path):
+            if path.name == "" and path.parent.name == "":
+                return GnLabel.from_str("//")
+            return GnLabel.from_str(f"//{path}")
+        elif isinstance(path, str):
+            if (
+                os.path.basename(path) == ""
+                and os.path.basename(os.path.dirname(path)) == ""
+            ):
+                return GnLabel.from_str("//")
+            return GnLabel.from_str(f"//{path}")
+        else:
+            assert False, f"Expected path of type Path but got {type(path)}"
 
-    def check_type(other) -> "GnLabel":
+    @staticmethod
+    def check_type(other: Any) -> "GnLabel":
         """Asserts that `other` is of type GnLabel"""
         assert isinstance(
             other, GnLabel
         ), f"{other} type {type(other)} is not {GnLabel}"
         return other
 
+    @staticmethod
     def check_types_in_list(list: List["GnLabel"]) -> List["GnLabel"]:
         """Asserts that all values in `list` are of type GnLabel"""
         for v in list:
@@ -99,12 +105,14 @@
     def parent_label(self) -> "GnLabel":
         """Returns //foo/bar for //foo/bar/baz and //foo/bar:baz"""
         assert self.has_parent_label(), f"{self} has no parent label"
-        if not self.is_local_name and self.name == self.path.name:
+        if not self.is_local_name and self.name == os.path.basename(
+            self.path_str
+        ):
             # Return //foo for //foo/bar
-            return GnLabel.from_path(self.path.parent)
+            return GnLabel.from_path(os.path.dirname(self.path_str))
         else:
             # Return //foo/bar for //foo/bar:bar and //foo/bar:baz
-            return GnLabel.from_path(self.path)
+            return GnLabel.from_path(self.path_str)
 
     def has_parent_label(self) -> bool:
         return self.gn_str != "//"
@@ -127,15 +135,14 @@
 
     def rebased_path(self, base_dir: Path) -> Path:
         """Returns package_path rebased to a given base_dir."""
-        return base_dir / self.path
+        return base_dir / self.path_str
 
     def code_search_url(self) -> str:
         """Returns package_path rebased to a given base_dir."""
-        path = self.path
-        return f"https://cs.opensource.google/fuchsia/fuchsia/+/main:{path}"
+        return f"https://cs.opensource.google/fuchsia/fuchsia/+/main:{self.path_str}"
 
     def is_host_target(self) -> bool:
-        return self.toolchain and self.toolchain.name.startswith("host_")
+        return bool(self.toolchain and self.toolchain.name.startswith("host_"))
 
     def is_3rd_party(self) -> bool:
         return "third_party" in self.gn_str or "thirdparty" in self.gn_str
@@ -157,14 +164,18 @@
             assert (
                 not self.is_local_name
             ), f"Can't apply {child_path_str} to {self} because both have :"
-            return GnLabel.from_str(f"//{self.path}:{child_path_str[1:]}")
+            return GnLabel.from_str(f"//{self.path_str}:{child_path_str[1:]}")
         elif child_path_str.startswith("../"):
             parent_path = (
-                self.parent_label().path if self.is_local_name else self.path
+                self.parent_label().path_str
+                if self.is_local_name
+                else self.path_str
             )
-            return GnLabel.from_path(parent_path / Path(child_path_str))
+            return GnLabel.from_path(os.path.join(parent_path, child_path_str))
         else:
-            return GnLabel.from_path(self.path / Path(child_path_str))
+            return GnLabel.from_path(
+                os.path.join(self.path_str, child_path_str)
+            )
 
     def __str__(self) -> str:
         return self.gn_str
@@ -175,6 +186,7 @@
     def __gt__(self, other: "GnLabel") -> bool:
         return self.gn_str > other.gn_str
 
+    @staticmethod
     def _resolve_dot_dot(path: str) -> str:
         """Resolves .. elements in a path string"""
         assert "//" not in path
diff --git a/build/licenses/python/gn_label_test.py b/build/licenses/python/gn_label_test.py
index 5d5a751..9744a86 100644
--- a/build/licenses/python/gn_label_test.py
+++ b/build/licenses/python/gn_label_test.py
@@ -14,7 +14,7 @@
     def test_from_str(self):
         label = GnLabel.from_str("//path/to/foo")
         self.assertEqual(label.gn_str, "//path/to/foo")
-        self.assertEqual(label.path, Path("path/to/foo"))
+        self.assertEqual(label.path_str, "path/to/foo")
         self.assertEqual(label.name, "foo")
         self.assertFalse(label.is_local_name)
         self.assertIsNone(label.toolchain)
@@ -23,14 +23,14 @@
         toolchain = GnLabel.from_str("//some/toolchain")
         label = GnLabel.from_str("//path/to/foo(//some/toolchain)")
         self.assertEqual(label.gn_str, "//path/to/foo(//some/toolchain)")
-        self.assertEqual(label.path, Path("path/to/foo"))
+        self.assertEqual(label.path_str, "path/to/foo")
         self.assertEqual(label.name, "foo")
         self.assertEqual(label.toolchain, toolchain)
 
     def test_from_str_with_local_name(self):
         label = GnLabel.from_str("//path/to/foo:bar")
         self.assertEqual(label.gn_str, "//path/to/foo:bar")
-        self.assertEqual(label.path, Path("path/to/foo"))
+        self.assertEqual(label.path_str, "path/to/foo")
         self.assertEqual(label.name, "bar")
         self.assertTrue(label.is_local_name)
         self.assertIsNone(label.toolchain)
@@ -38,7 +38,7 @@
     def test_from_str_with_redundant_local_name(self):
         label = GnLabel.from_str("//path/to/foo:foo")
         self.assertEqual(label.gn_str, "//path/to/foo:foo")
-        self.assertEqual(label.path, Path("path/to/foo"))
+        self.assertEqual(label.path_str, "path/to/foo")
         self.assertEqual(label.name, "foo")
         self.assertTrue(label.is_local_name)
         self.assertIsNone(label.toolchain)
@@ -47,7 +47,7 @@
         toolchain = GnLabel.from_str("//some/toolchain")
         label = GnLabel.from_str("//path/to/foo:bar(//some/toolchain)")
         self.assertEqual(label.gn_str, "//path/to/foo:bar(//some/toolchain)")
-        self.assertEqual(label.path, Path("path/to/foo"))
+        self.assertEqual(label.path_str, "path/to/foo")
         self.assertEqual(label.name, "bar")
         self.assertEqual(label.toolchain, toolchain)
 
@@ -55,28 +55,28 @@
         toolchain = GnLabel.from_str("//some/toolchain")
         label = GnLabel.from_str("//path/to/foo/../bar:baz(//some/toolchain)")
         self.assertEqual(label.gn_str, "//path/to/bar:baz(//some/toolchain)")
-        self.assertEqual(label.path, Path("path/to/bar"))
+        self.assertEqual(label.path_str, "path/to/bar")
         self.assertEqual(label.name, "baz")
         self.assertEqual(label.toolchain, toolchain)
 
     def test_from_str_root_path(self):
         label = GnLabel.from_str("//")
         self.assertEqual(label.gn_str, "//")
-        self.assertEqual(label.path, Path("."))
+        self.assertEqual(label.path_str, "")
         self.assertEqual(label.name, "")
         self.assertIsNone(label.toolchain)
 
     def test_from_root_path(self):
         label = GnLabel.from_path(Path(""))
         self.assertEqual(label.gn_str, "//")
-        self.assertEqual(label.path, Path("."))
+        self.assertEqual(label.path_str, "")
         self.assertEqual(label.name, "")
         self.assertIsNone(label.toolchain)
 
     def test_from_path(self):
         label = GnLabel.from_path(Path("path/to/foo"))
         self.assertEqual(label.gn_str, "//path/to/foo")
-        self.assertEqual(label.path, Path("path/to/foo"))
+        self.assertEqual(label.path_str, "path/to/foo")
         self.assertEqual(label.name, "foo")
         self.assertIsNone(label.toolchain)
 
diff --git a/build/licenses/python/gn_license_metadata.py b/build/licenses/python/gn_license_metadata.py
index d40444a..8a5356c 100644
--- a/build/licenses/python/gn_license_metadata.py
+++ b/build/licenses/python/gn_license_metadata.py
@@ -7,10 +7,14 @@
 import json
 import dataclasses
 import logging
-from pathlib import Path
-from typing import Dict, List, Tuple
+import os
+from typing import Any, Dict, List, Tuple, TypeAlias
 from gn_label import GnLabel
 
+AnyDict: TypeAlias = Dict[Any, Any]
+AnyList: TypeAlias = List[Any]
+OptionalPath: TypeAlias = str | None
+
 
 @dataclasses.dataclass(frozen=True)
 class GnLicenseMetadata:
@@ -20,11 +24,13 @@
     public_package_name: str
     license_files: Tuple[GnLabel]
 
-    def is_license_metadata_dict(dict: Dict) -> bool:
+    @staticmethod
+    def is_license_metadata_dict(dict: AnyDict) -> bool:
         return "license_files" in dict
 
+    @staticmethod
     def from_json_dict(
-        dict: Dict, absolute_fuchsia_source_path: Path = None
+        dict: AnyDict, absolute_fuchsia_source_path: OptionalPath = None
     ) -> "GnLicenseMetadata":
         target_label = GnLabel.from_str(dict["target_label"])
         logging.debug("Loading GnLicenseMetadata for %s", target_label)
@@ -59,14 +65,16 @@
     license_labels: Tuple[GnLabel]
     third_party_resources: Tuple[GnLabel]
 
-    def is_applicable_licenses_metadata_dict(dict: Dict) -> bool:
+    @staticmethod
+    def is_applicable_licenses_metadata_dict(dict: AnyDict) -> bool:
         return "license_labels" in dict
 
-    def is_group(self):
+    def is_group(self) -> bool:
         return self.target_type == "group"
 
+    @staticmethod
     def from_json_dict(
-        data: Dict, absolute_fuchsia_source_path: Path = None
+        data: AnyDict, absolute_fuchsia_source_path: OptionalPath = None
     ) -> "GnApplicableLicensesMetadata":
         assert isinstance(data, dict)
         target_label = GnLabel.from_str(data["target_label"])
@@ -83,16 +91,12 @@
 
         license_labels = [GnLabel.from_str(s) for s in data["license_labels"]]
 
-        third_party_resources = []
-        if "third_party_resources" in data:
-            third_party_resources = [
-                target_label.create_child_from_str(
-                    _rebase_absolute_path(s, absolute_fuchsia_source_path)
-                )
-                for s in data["third_party_resources"]
-            ]
-        else:
-            third_party_resources = []
+        third_party_resources = [
+            target_label.create_child_from_str(
+                _rebase_absolute_path(s, absolute_fuchsia_source_path)
+            )
+            for s in data.get("third_party_resources", [])
+        ]
 
         return GnApplicableLicensesMetadata(
             target_label=target_label,
@@ -115,14 +119,17 @@
         GnLabel, GnApplicableLicensesMetadata
     ] = dataclasses.field(default_factory=dict)
 
+    @staticmethod
     def from_file(
-        file_path: Path, fuchsia_source_path: Path
+        file_path: str, fuchsia_source_path: str
     ) -> "GnLicenseMetadataDB":
         """Loads from a json file generated by the build/licenses/license_collection.gni template"""
         logging.debug("Loading metadata from %s", file_path)
 
         # To resolve absolute paths, turn the source path into an absolute one
-        absolute_fuchsia_source_path = fuchsia_source_path.resolve()
+        absolute_fuchsia_source_path = os.path.abspath(
+            os.path.normpath(fuchsia_source_path)
+        )
 
         with open(file_path, "r") as f:
             output = GnLicenseMetadataDB.from_json_list(
@@ -133,8 +140,9 @@
             )
             return output
 
+    @staticmethod
     def from_json_list(
-        json_list: List, fuchsia_source_path: Path = None
+        json_list: AnyList, fuchsia_source_path: OptionalPath = None
     ) -> "GnLicenseMetadataDB":
         """Loads from a json list generated by the build/licenses/license_collection.gni template"""
 
@@ -160,32 +168,32 @@
         # Remove applicable_licenses for targets that are license targets.
         # Those are meaningless.
         for label in db.licenses_by_label.keys():
-            if label in db.applicable_licenses_by_target:
-                db.applicable_licenses_by_target.pop(label)
+            db.applicable_licenses_by_target.pop(label, None)
 
         return db
 
-    def add_license_metadata(self, license_metadata: GnLicenseMetadata):
-        assert license_metadata.target_label not in self.licenses_by_label
-        self.licenses_by_label[license_metadata.target_label] = license_metadata
+    def add_license_metadata(self, license_metadata: GnLicenseMetadata) -> None:
+        current = self.licenses_by_label.setdefault(
+            license_metadata.target_label, license_metadata
+        )
+        assert current == license_metadata
 
     def add_applicable_licenses_metadata(
         self, application: GnApplicableLicensesMetadata
-    ):
+    ) -> None:
+        current = self.applicable_licenses_by_target.setdefault(
+            application.target_label, application
+        )
         assert (
-            application.target_label not in self.applicable_licenses_by_target
+            current == application
         ), f"Multiple applicable_licenses metadata entries for {application.target_label} ({application.target_type}), probably due to https://fxbug.dev/42083609)."
-        self.applicable_licenses_by_target[
-            application.target_label
-        ] = application
 
 
 def _rebase_absolute_path(
-    path_str: str, absolute_fuchsia_source_path: Path
+    path_str: str, absolute_fuchsia_source_path: OptionalPath
 ) -> str:
-    if absolute_fuchsia_source_path == None:
-        return path_str
-    path = Path(path_str)
-    if path.is_relative_to(absolute_fuchsia_source_path):
-        return "//" + str(path.relative_to(absolute_fuchsia_source_path))
+    if absolute_fuchsia_source_path and os.path.isabs(path_str):
+        rel_path = os.path.relpath(path_str, absolute_fuchsia_source_path)
+        if not rel_path.startswith("../"):
+            return "//" + rel_path
     return path_str
diff --git a/build/licenses/python/readme_fuchsia.py b/build/licenses/python/readme_fuchsia.py
index a4c0bc28..f5b4d0f 100644
--- a/build/licenses/python/readme_fuchsia.py
+++ b/build/licenses/python/readme_fuchsia.py
@@ -13,7 +13,7 @@
 @dataclasses.dataclass
 class Readme:
     readme_label: GnLabel
-    package_name: str
+    package_name: str | None
     license_files: Tuple[GnLabel]
 
     def from_text(
@@ -47,7 +47,9 @@
 @dataclasses.dataclass
 class ReadmesDB:
     file_access: FileAccess
-    cache: Dict[GnLabel, Readme] = dataclasses.field(default_factory=dict)
+    cache: Dict[GnLabel, Readme | None] = dataclasses.field(
+        default_factory=dict
+    )
 
     _barrier_dir_names: ClassVar[Set[str]] = set(
         [
@@ -59,30 +61,31 @@
         ]
     )
 
-    def find_readme_for_label(self, target_label: GnLabel) -> Readme:
+    def find_readme_for_label(self, target_label: GnLabel) -> Readme | None:
         GnLabel.check_type(target_label)
 
         logging.debug("Finding readme for %s", target_label)
-
         if target_label.toolchain:
             target_label = target_label.without_toolchain()
         if target_label.is_local_name:
             target_label = target_label.parent_label()
         assert not target_label.is_local_name
 
-        if target_label in self.cache:
-            value = self.cache[target_label]
+        value = self.cache.get(target_label, False)
+        if value != False:
             logging.debug("Found %s in cache", value)
+            assert not isinstance(value, bool)  # quiet mypy false positive.
             return value
 
+        if target_label.path_str:
+            readme_fuchsia_suffix = f"{target_label.path_str}/README.fuchsia"
+        else:
+            readme_fuchsia_suffix = "README.fuchsia"
+
         potential_readme_files = [
-            "vendor/google/tools/check-licenses/assets/readmes"
-            / target_label.path
-            / "README.fuchsia",
-            "tools/check-licenses/assets/readmes"
-            / target_label.path
-            / "README.fuchsia",
-            target_label.path / "README.fuchsia",
+            f"vendor/google/tools/check-licenses/assets/readmes/{readme_fuchsia_suffix}",
+            f"tools/check-licenses/assets/readmes/{readme_fuchsia_suffix}",
+            readme_fuchsia_suffix,
         ]
         for readme_source_path in potential_readme_files:
             readme_label = GnLabel.from_path(readme_source_path)
@@ -101,14 +104,15 @@
                 )
                 self.cache[target_label] = readme
                 return readme
-            else:
-                logging.debug("%s does not exist", readme_label)
+
+            logging.debug("%s does not exist", readme_label)
 
         if target_label.name in ReadmesDB._barrier_dir_names:
             logging.debug("%s is a barrier path", target_label)
             self.cache[target_label] = None
             return None
-        elif target_label.has_parent_label():
+
+        if target_label.has_parent_label():
             parent = target_label.parent_label()
             logging.debug(
                 "Trying with parent of %s: %s...", target_label, parent
@@ -120,7 +124,7 @@
             )
             self.cache[target_label] = parent_result
             return parent_result
-        else:
-            logging.debug(f"No readme found for %s", target_label)
-            self.cache[target_label] = None
-            return None
+
+        logging.debug(f"No readme found for %s", target_label)
+        self.cache[target_label] = None
+        return None
diff --git a/build/licenses/python/readme_fuchsia_test.py b/build/licenses/python/readme_fuchsia_test.py
index 3cc7af5..992cffe 100644
--- a/build/licenses/python/readme_fuchsia_test.py
+++ b/build/licenses/python/readme_fuchsia_test.py
@@ -62,13 +62,13 @@
 
 @dataclasses.dataclass
 class MockFileAccess(FileAccess):
-    readme_content_by_path: Dict[Path, str] = None
+    readme_content_by_path: Dict[str, str] = None
 
     def read_text(self, label: GnLabel) -> str:
-        return self.readme_content_by_path[label.path]
+        return self.readme_content_by_path[label.path_str]
 
     def file_exists(self, label: GnLabel) -> bool:
-        return label.path in self.readme_content_by_path
+        return label.path_str in self.readme_content_by_path
 
 
 class ReadmesDBTest(unittest.TestCase):
@@ -79,7 +79,7 @@
         self.mock_content_by_path = {}
 
         file_access = MockFileAccess(
-            fuchsia_source_path=None,
+            fuchsia_source_path_str=None,
             readme_content_by_path=self.mock_content_by_path,
         )
         self.db = ReadmesDB(file_access=file_access)
@@ -88,12 +88,12 @@
 
     def _mock_readme_files(self, file_paths: List[str]):
         for path in file_paths:
-            self.mock_content_by_path[Path(path)] = "Name: Foo"
+            self.mock_content_by_path[path] = "Name: Foo"
 
     def _assert_found_readme(self, for_label: str, expected_readme_path: str):
         readme = self.db.find_readme_for_label(GnLabel.from_str(for_label))
         self.assertIsNotNone(readme)
-        self.assertEqual(readme.readme_label.path, Path(expected_readme_path))
+        self.assertEqual(readme.readme_label.path_str, expected_readme_path)
 
     def _assert_readme_not_found(self, for_label: str):
         readme = self.db.find_readme_for_label(GnLabel.from_str(for_label))
diff --git a/build/licenses/python/spdx_comparator.py b/build/licenses/python/spdx_comparator.py
index 9dc67ce..feced2f 100644
--- a/build/licenses/python/spdx_comparator.py
+++ b/build/licenses/python/spdx_comparator.py
@@ -10,6 +10,7 @@
 from pathlib import Path
 import re
 from typing import Any, Dict, List, Set
+from typing.re import Pattern as re_Pattern
 import hashlib
 from gn_label import GnLabel
 
@@ -23,12 +24,12 @@
     text_hash: str
 
     # Debugging fields: Not part of compare or hash
-    spdx_id: str = dataclasses.field(compare=False, hash=False, default=None)
-    url: str = dataclasses.field(compare=False, hash=False, default=None)
-    text_sample: str = dataclasses.field(
+    spdx_id: str = dataclasses.field(compare=False, hash=False, default="")
+    url: str | None = dataclasses.field(compare=False, hash=False, default=None)
+    text_sample: str = dataclasses.field(compare=False, hash=False, default="")
+    debug_hint: str | None = dataclasses.field(
         compare=False, hash=False, default=None
     )
-    debug_hint: str = dataclasses.field(compare=False, hash=False, default=None)
 
     def __gt__(self, other: "_ExtractedLicense") -> bool:
         return (
@@ -36,6 +37,7 @@
             > f"{other.path}-{other.name}-{other.text_hash}"
         )
 
+    @staticmethod
     def from_json_dict(input: Dict[str, Any]) -> "_ExtractedLicense":
         # Example SPDX license dict:
         # {
@@ -119,7 +121,7 @@
 
 
 # License path patterns that are expected to be missing
-_expected_missing: List[re.Pattern] = [
+_expected_missing: List[re_Pattern] = [
     re.compile(s)
     for s in [
         # COPYING and UNLICENSE files are not rust licenses
@@ -157,7 +159,7 @@
         default_factory=set
     )
 
-    def compare(self):
+    def compare(self) -> None:
         """Returns whether the files have the same licenses"""
         current_lics = self._read_spdx_licenses(self.current_file)
         legacy_lics = self._read_spdx_licenses(self.legacy_file)
@@ -189,7 +191,7 @@
                     self.expected_missing.add(lic)
                     self.missing.remove(lic)
 
-    def _read_spdx_licenses(self, path) -> Set[_ExtractedLicense]:
+    def _read_spdx_licenses(self, path: Path | str) -> Set[_ExtractedLicense]:
         with open(path, "r") as spdx_file:
             spdx_doc = json.load(spdx_file)
             output = set()
@@ -199,15 +201,15 @@
             return output
 
     def found_differences(self) -> bool:
-        return self.added or self.missing
+        return len(self.added) != 0 or len(self.missing) != 0
 
-    def log_differences(self, log_level: int, is_full_report: bool):
+    def log_differences(self, log_level: int, is_full_report: bool) -> None:
         message_lines = []
 
-        def report(s: str):
+        def report(s: str) -> None:
             message_lines.append(s)
 
-        def full_report(s: str):
+        def full_report(s: str) -> None:
             if is_full_report:
                 report(s)
 
diff --git a/build/licenses/python/spdx_writer.py b/build/licenses/python/spdx_writer.py
index e6d4e50..21b4dc1 100644
--- a/build/licenses/python/spdx_writer.py
+++ b/build/licenses/python/spdx_writer.py
@@ -7,10 +7,12 @@
 import json
 import hashlib
 import dataclasses
-from pathlib import Path
 from file_access import FileAccess
 from gn_label import GnLabel
-from typing import Callable, Dict, List, Any, Tuple
+from typing import Callable, Dict, List, Any, Tuple, TypeAlias
+import os
+
+AnyDict: TypeAlias = Dict[Any, Any]
 
 
 @dataclasses.dataclass(frozen=False)
@@ -36,14 +38,15 @@
     extracted_licenses: List[Dict[str, Any]] = dataclasses.field(
         default_factory=list
     )
-    license_json_by_ref: Dict[str, Dict] = dataclasses.field(
+    license_json_by_ref: Dict[str, AnyDict] = dataclasses.field(
         default_factory=dict
     )
-    package_json_by_ids: Dict[str, Dict] = dataclasses.field(
+    package_json_by_ids: Dict[str, AnyDict] = dataclasses.field(
         default_factory=dict
     )
 
-    def create(root_package_name: str, file_access: FileAccess):
+    @staticmethod
+    def create(root_package_name: str, file_access: FileAccess) -> "SpdxWriter":
         writer = SpdxWriter(
             file_access=file_access,
             document_id="SPDXRef-DOCUMENT",
@@ -53,7 +56,7 @@
         writer._init_json()
         return writer
 
-    def _init_json(self):
+    def _init_json(self) -> None:
         self.json_document.update(
             {
                 "spdxVersion": "SPDX-2.3",
@@ -61,7 +64,7 @@
                 "name": self.root_package_name,
                 "documentNamespace": "",
                 "creationInfo": {
-                    "creators": [f"Tool: {Path(__file__).name}"],
+                    "creators": [f"Tool: {os.path.basename(__file__)}"],
                 },
                 "dataLicense": "CC0-1.0",
                 "documentDescribes": self.document_describes,
@@ -84,7 +87,7 @@
         public_package_name: str,
         license_labels: Tuple[GnLabel],
         collection_hint: str,
-    ):
+    ) -> None:
         package_id = self._spdx_package_id(public_package_name, license_labels)
 
         if package_id in self.package_json_by_ids:
@@ -136,7 +139,7 @@
             }
         )
 
-    def _sort_elements(self):
+    def _sort_elements(self) -> None:
         """Sorts all output elements alphabetically.
 
         This ensures consistent and developer-friendly output independent on input ordering.
@@ -150,7 +153,7 @@
             key=lambda x: x["spdxElementId"] + x["relatedSpdxElement"]
         )
 
-    def save(self, file_path: Path):
+    def save(self, file_path: str) -> None:
         self._sort_elements()
         with open(file_path, "w") as f:
             json.dump(self.json_document, f, indent=4)
@@ -160,20 +163,20 @@
         return json.dumps(self.json_document, indent=4)
 
     def _spdx_package_id(
-        self, public_package_name, license_labels: Tuple[GnLabel]
+        self, public_package_name: str, license_labels: Tuple[GnLabel]
     ) -> str:
         md5 = hashlib.md5()
         md5.update(public_package_name.strip().encode("utf-8"))
         for ll in license_labels:
-            md5.update(str(ll.path).encode("utf-8"))
+            md5.update(str(ll.path_str).encode("utf-8"))
         digest = md5.hexdigest()
         return f"SPDXRef-Package-{digest}"
 
     def _spdx_license_ref(
-        self, public_package_name, license_label: GnLabel
+        self, public_package_name: str, license_label: GnLabel
     ) -> str:
         md5 = hashlib.md5()
         md5.update(public_package_name.strip().encode("utf-8"))
-        md5.update(str(license_label.path).encode("utf-8"))
+        md5.update(str(license_label.path_str).encode("utf-8"))
         digest = md5.hexdigest()
         return f"LicenseRef-{digest}"
diff --git a/build/licenses/python/spdx_writer_test.py b/build/licenses/python/spdx_writer_test.py
index 1a53feb..722c0a8 100644
--- a/build/licenses/python/spdx_writer_test.py
+++ b/build/licenses/python/spdx_writer_test.py
@@ -13,7 +13,7 @@
 
 class MockFileAccess(FileAccess):
     def read_text(self, label: GnLabel) -> str:
-        return f"TEXT FROM {label.path}"
+        return f"TEXT FROM {label.path_str}"
 
 
 class SpdxWriterTest(unittest.TestCase):
@@ -22,7 +22,7 @@
     def setUp(self) -> None:
         self.writer = SpdxWriter.create(
             root_package_name="root pkg",
-            file_access=MockFileAccess(fuchsia_source_path="unused"),
+            file_access=MockFileAccess(fuchsia_source_path_str="unused"),
         )
 
         return super().setUp()
diff --git a/build/packages/exported_fuchsia_package_archive.gni b/build/packages/exported_fuchsia_package_archive.gni
new file mode 100644
index 0000000..6654280
--- /dev/null
+++ b/build/packages/exported_fuchsia_package_archive.gni
@@ -0,0 +1,92 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/components/fuchsia_package_archive.gni")
+
+# A variant of fuchsia_package_archive also exposes itself in the
+# `exported_package_archives` build api module.
+#
+# Parameters
+#
+#   package (required)
+#     A fuchsia_package() target defined earlier in the same file.
+#     Type: label
+#
+#   api_level (optional)
+#     The minimum required API level for the components in this package.
+#     Defaults to -1, denoting an unspecified API level.
+#     Type: int
+#
+#   testonly
+#   visibility
+template("exported_fuchsia_package_archive") {
+  if (current_toolchain == default_toolchain) {
+    assert(defined(invoker.package), "package is required")
+    _package_label = invoker.package
+
+    _api_level = -1
+    if (defined(invoker.api_level)) {
+      api_level = invoker.api_level
+    }
+
+    _archive_label = ":${target_name}_archive"
+    fuchsia_package_archive("${target_name}_archive") {
+      forward_variables_from(invoker, "*")
+    }
+
+    # LINT.IfChange
+    _input_far = get_label_info(_archive_label, "target_out_dir") + "/" +
+                 get_label_info(_package_label, "name") + ".far"
+
+    # LINT.ThenChange(//src/sys/pkg/bin/package-tool/package-tool.gni)
+
+    # LINT.IfChange
+    _input_package_manifest =
+        get_label_info(_package_label, "target_out_dir") + "/" +
+        get_label_info(_package_label, "name") + "/package_manifest.json"
+
+    # LINT.ThenChange(//build/components/fuchsia_package.gni)
+
+    _output_metadata = "$target_out_dir/${target_name}_metadata.json"
+    action(target_name) {
+      forward_variables_from(invoker, "*", [ "package" ])
+
+      metadata = {
+        exported_package_archives =
+            [ rebase_path(_output_metadata, root_build_dir) ]
+      }
+
+      script = "//build/packages/generate_package_archive_metadata.py"
+
+      inputs = [
+        _input_far,
+        _input_package_manifest,
+      ]
+
+      outputs = [ _output_metadata ]
+
+      args = [
+        "--far",
+        rebase_path(_input_far, root_build_dir),
+        "--package-manifest",
+        rebase_path(_input_package_manifest, root_build_dir),
+        "--cpu",
+        target_cpu,
+        "--api-level",
+        "$_api_level",
+        "--out",
+        rebase_path(_output_metadata, root_build_dir),
+      ]
+
+      deps = [
+        _archive_label,
+        _package_label,
+      ]
+    }
+  } else {
+    group(target_name) {
+      public_deps = [ ":${target_name}($default_toolchain)" ]
+    }
+  }
+}
diff --git a/build/packages/generate_package_archive_metadata.py b/build/packages/generate_package_archive_metadata.py
new file mode 100644
index 0000000..8bd91ca
--- /dev/null
+++ b/build/packages/generate_package_archive_metadata.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env fuchsia-vendored-python
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Collects useful metadata for describing package archives.
+For use in the template //build/packages:exported_fuchsia_package_archive."""
+
+import argparse
+import json
+import sys
+
+from pathlib import Path
+
+
+def parse_args() -> argparse.Namespace:
+    parser = argparse.ArgumentParser()
+
+    def path_arg(validate_type=None):
+        def arg(path):
+            path = Path(path)
+            assert (
+                not validate_type
+                or validate_type == "file"
+                and path.is_file()
+                or validate_type == "directory"
+                and path.is_dir()
+            ), f'Path "{path}" is not a {validate_type}!'
+            return path
+
+        return arg
+
+    parser.add_argument(
+        "--far",
+        help="A path to the package archive.",
+        type=path_arg("file"),
+        required=True,
+    )
+    parser.add_argument(
+        "--package-manifest",
+        help="A path to the underlying package's manifest.",
+        type=path_arg("file"),
+        required=True,
+    )
+    parser.add_argument(
+        "--cpu",
+        help="The underlying package's target cpu architecture.",
+        required=True,
+    )
+    parser.add_argument(
+        "--api-level",
+        help="The underlying package's target api level.",
+        type=int,
+        required=True,
+    )
+    parser.add_argument(
+        "--out",
+        help="The path to write the json metadata for the package archive.",
+        type=path_arg(),
+        required=True,
+    )
+    return parser.parse_args()
+
+
+def main() -> int:
+    args = parse_args()
+
+    package_manifest = json.loads(args.package_manifest.read_text())
+    args.out.write_text(
+        json.dumps(
+            {
+                "name": package_manifest["package"]["name"],
+                "cpu": args.cpu,
+                "api_level": args.api_level,
+                "path": str(args.far),
+            }
+        )
+    )
+
+    return 0
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/build/packages/sdk_fuchsia_package.gni b/build/packages/sdk_fuchsia_package.gni
index 8523be6..6cc36c9 100644
--- a/build/packages/sdk_fuchsia_package.gni
+++ b/build/packages/sdk_fuchsia_package.gni
@@ -87,14 +87,27 @@
   assert(defined(invoker.api_level_added),
          "Must specify the API level at which the package was added")
 
-  # Build the package for supported API levels.
-  package_in_target_api_level =
-      invoker.api_level_added <= override_target_api_level
-
-  if (defined(invoker.api_level_removed)) {
+  # Build packages at `PLATFORM`, for now. See the references to
+  # fxbug.dev/310006516 further down in this file for more context.
+  #
+  # TODO(https://fxbug.dev/310006516): Delete API-level-agnostic packages from the IDK.
+  if (override_target_api_level == "PLATFORM") {
+    package_in_target_api_level = true
+    not_needed(invoker,
+               [
+                 "api_level_added",
+                 "api_level_removed",
+               ])
+  } else {
+    # Build the package for supported API levels.
     package_in_target_api_level =
-        package_in_target_api_level &&
-        override_target_api_level < invoker.api_level_removed
+        invoker.api_level_added <= override_target_api_level
+
+    if (defined(invoker.api_level_removed)) {
+      package_in_target_api_level =
+          package_in_target_api_level &&
+          override_target_api_level < invoker.api_level_removed
+    }
   }
 
   if (package_in_target_api_level && current_toolchain == target_toolchain) {
@@ -247,6 +260,17 @@
       ]
       depfile = _sdk_package_depfile
 
+      # Change "PLATFORM" to -1, which is what it used to be. This is necessary
+      # for backwards compatibility until we actually remove API-level-agnostic
+      # packages from the IDK.
+      #
+      # TODO(https://fxbug.dev/310006516): Delete this once API-level-agnostic
+      # packages are no longer in the IDK.
+      _api_level_arg = override_target_api_level
+      if (override_target_api_level == "PLATFORM") {
+        _api_level_arg = -1
+      }
+
       args = [
         "--manifest",
         rebase_path(package_manifest_file, root_build_dir),
@@ -254,8 +278,27 @@
         rebase_path(computed_content_checklist_file, root_build_dir),
         "--output",
         rebase_path(_sdk_package_dir, root_build_dir),
+
+        # In the API-level-agnostic builds, the value of this flag is a bit
+        # strange, and means we say in `meta.json` that the API level is
+        # "PLATFORM". This is... neither correct nor incorrect.
+        #
+        # It's honestly rather moot, because none of the SDKs actually allow
+        # users to use these packages, yet. Hopefully we'll be able to add
+        # support for API-level-aware package prebuilts right off the bat,
+        # rather than first building support for including an API-level-agnostic
+        # subpackage, and then going back and fixing it.
+        #
+        # Arguably the right thing to do would be to _not_ build the packages in
+        # the API-level-agnostic builds, but then we wouldn't be building them
+        # anywhere, and we'd be in more danger of bitrot on the "packages in the
+        # IDK" work. So for now, we'll continue building them with this strange
+        # metadata quirk.
+        #
+        # TODO(https://fxbug.dev/310006516): Delete this comment once API-level-agnostic
+        # packages are no longer in the IDK.
         "--api-level",
-        "${override_target_api_level}",
+        "${_api_level_arg}",
         "--target-cpu",
         "${target_cpu}",
         "--depfile",
diff --git a/build/rbe/cxx_link_remote_wrapper.py b/build/rbe/cxx_link_remote_wrapper.py
index 6d8cc13..d0d7266 100755
--- a/build/rbe/cxx_link_remote_wrapper.py
+++ b/build/rbe/cxx_link_remote_wrapper.py
@@ -358,15 +358,24 @@
         self.vprintlist("remote inputs", remote_inputs)
         self.vprintlist("remote output files", remote_output_files)
         self.vprintlist("remote output dirs", remote_output_dirs)
-        self.vprintlist("rewrapper options", remote_options)
 
-        downloads = []
-        if self.depfile:  # always fetch the depfile
-            downloads.append(self.depfile)
+        # Interpret --download_outputs=false as a request to avoid
+        # downloading the main linker output, but download everything else.
+        # This will always fetch the depfile, which is needed by ninja.
+        translated_remote_options = []
+        for opt in remote_options:
+            if opt == "--download_outputs=false":
+                translated_remote_options.append(
+                    f"--download_regex=-{self.primary_output}$"
+                )
+            else:
+                translated_remote_options.append(opt)
+
+        self.vprintlist("rewrapper options", translated_remote_options)
 
         self._remote_action = remote_action.remote_action_from_args(
             main_args=self._main_args,
-            remote_options=remote_options,
+            remote_options=translated_remote_options,
             command=remote_command,
             inputs=remote_inputs,
             output_files=remote_output_files,
@@ -374,7 +383,6 @@
             working_dir=self.working_dir,
             exec_root=self.exec_root,
             post_remote_run_success_action=self._post_remote_success_action,
-            downloads=downloads,
         )
 
         self._prepare_status = 0
diff --git a/build/rbe/cxx_link_remote_wrapper_test.py b/build/rbe/cxx_link_remote_wrapper_test.py
index 816a835..98a6311c 100755
--- a/build/rbe/cxx_link_remote_wrapper_test.py
+++ b/build/rbe/cxx_link_remote_wrapper_test.py
@@ -308,7 +308,9 @@
                 fake_builddir / depfile,
             ],
         )
-        self.assertEqual(set(c.remote_action.always_download), set([depfile]))
+        self.assertEqual(
+            set(c.remote_action.expected_downloads), {output, depfile}
+        )
 
         with mock.patch.object(
             remote_action.RemoteAction,
@@ -359,7 +361,7 @@
                 self.assertEqual(c.prepare(), 0)
 
             self.assertEqual(
-                set(c.remote_action.always_download), set([depfile])
+                set(c.remote_action.expected_downloads), {output, depfile}
             )
             self.assertEqual(c.remote_action.remote_working_dir, remote_cwd)
             c._rewrite_remote_depfile()
diff --git a/build/rbe/cxx_remote_wrapper.py b/build/rbe/cxx_remote_wrapper.py
index b19bb5d..0510f48 100755
--- a/build/rbe/cxx_remote_wrapper.py
+++ b/build/rbe/cxx_remote_wrapper.py
@@ -211,7 +211,7 @@
             # return self._verify_remote_depfile()
             self._rewrite_remote_depfile()
 
-        # TODO: if downloads were skipped, need to force-download depfile
+        # we expect the depfile to always be downloaded, via --download_regex
         return 0
 
     def _verify_remote_depfile(self) -> int:
@@ -330,14 +330,10 @@
         self.vprintlist("remote output dirs", remote_output_dirs)
         self.vprintlist("rewrapper options", remote_options)
 
-        # Interpret --download_outputs=false as a request to avoid
-        # downloading only the primary compiler output, usually the .o file.
-        # In other words, always download *all* other outputs,
-        # including the depfile.
-        # The depfile *must* be downloaded because it is consumed by ninja.
-        downloads = [
-            f for f in remote_output_files if f != self.primary_output
-        ] + remote_output_dirs
+        # To skip downloading, pass --download_regex=... to rewrapper.
+        # The argument should start with '-' to indicate that
+        # everything that does not match the pattern should be downloaded.
+        # Depfiles must be downloaded because ninja expects them.
 
         self._remote_action = remote_action.remote_action_from_args(
             main_args=self._main_args,
@@ -349,7 +345,6 @@
             working_dir=self.working_dir,
             exec_root=self.exec_root,
             post_remote_run_success_action=self._post_remote_success_action,
-            downloads=downloads,
         )
 
         self._prepare_status = 0
diff --git a/build/rbe/cxx_remote_wrapper_test.py b/build/rbe/cxx_remote_wrapper_test.py
index 41240a2..b165ea2 100755
--- a/build/rbe/cxx_remote_wrapper_test.py
+++ b/build/rbe/cxx_remote_wrapper_test.py
@@ -398,7 +398,9 @@
             c.remote_action.output_files_relative_to_project_root,
             [fake_builddir / output, fake_builddir / depfile],
         )
-        self.assertEqual(set(c.remote_action.always_download), set([depfile]))
+        self.assertEqual(
+            set(c.remote_action.expected_downloads), {output, depfile}
+        )
 
         with mock.patch.object(
             remote_action.RemoteAction,
@@ -444,7 +446,7 @@
 
             mock_check.assert_called_once()
             self.assertEqual(
-                set(c.remote_action.always_download), set([depfile])
+                set(c.remote_action.expected_downloads), {output, depfile}
             )
             self.assertEqual(c.remote_action.remote_working_dir, remote_cwd)
             c._rewrite_remote_depfile()
diff --git a/build/rbe/remote_action.py b/build/rbe/remote_action.py
index 0781be4..b50505d 100755
--- a/build/rbe/remote_action.py
+++ b/build/rbe/remote_action.py
@@ -920,7 +920,6 @@
         miscomparison_export_dir: Path = None,
         post_remote_run_success_action: Callable[[], int] = None,
         remote_debug_command: Sequence[str] = None,
-        always_download: Sequence[Path] = None,
     ):
         """RemoteAction constructor.
 
@@ -973,8 +972,6 @@
             a cause of error.
           remote_debug_command: if True, run different command remotely instead of
             the original command, for debugging the remote inputs setup.
-          always_download: files/dirs to download, relative to the working dir,
-            even if --download_outputs=false.
         """
         self._rewrapper = rewrapper
         self._config = cfg  # can be None
@@ -1000,7 +997,6 @@
         self._options = options or []
         self._post_remote_run_success_action = post_remote_run_success_action
         self._remote_debug_command = remote_debug_command or []
-        self._always_download = always_download or []
 
         # When comparing local vs. remote, force exec_strategy=remote
         # to eliminate any unintended local execution cases.
@@ -1071,10 +1067,6 @@
         return self._config
 
     @property
-    def always_download(self) -> Sequence[str]:
-        return self._always_download
-
-    @property
     def _default_auxiliary_file_basename(self) -> str:
         # Return a str instead of Path because most callers will want to
         # append a suffix (str + str).
@@ -1192,10 +1184,53 @@
         return self._rewrapper_known_options.canonicalize_working_dir
 
     @property
+    def download_regex(self) -> Optional[str]:
+        return self._rewrapper_known_options.download_regex
+
+    @property
     def download_outputs(self) -> bool:
         return self._rewrapper_known_options.download_outputs
 
     @property
+    def need_download_stub_predicate(self) -> Callable[[Path], bool]:
+        """Return a function that indicates whether an output path will require a download stub."""
+        download_regex = self.download_regex
+        if download_regex is not None:
+            if download_regex.startswith("-"):
+                exclude_regex = re.compile(download_regex.removeprefix("-"))
+
+                def need_download_stub(path: Path) -> bool:
+                    return exclude_regex.match(str(path))
+
+            else:
+                include_regex = re.compile(download_regex)
+
+                def need_download_stub(path: Path) -> bool:
+                    return not include_regex.match(str(path))
+
+        else:
+
+            def need_download_stub(path: Path) -> bool:
+                # --download_outputs applies to all paths
+                return not self.download_outputs
+
+        return need_download_stub
+
+    @property
+    def skipping_some_download(self) -> bool:
+        """Returns true if some download is expected to be skipped."""
+        return self.download_regex is not None or not self.download_outputs
+
+    @property
+    def expected_downloads(self) -> Sequence[Path]:
+        """Returns a collection of output files that are expected to be downloaded."""
+        return [
+            f
+            for f in self.output_files_relative_to_working_dir
+            if not self.need_download_stub_predicate(f)
+        ]
+
+    @property
     def save_temps(self) -> bool:
         return self._save_temps
 
@@ -1321,7 +1356,7 @@
         # diagnostics and troubleshooting.
         # When NOT downloading outputs, we need the .rrpl file for the
         # output digests to be able to retrieve them from the CAS later.
-        if self.diagnose_nonzero or not self.download_outputs:
+        if self.diagnose_nonzero or self.skipping_some_download:
             yield f"--action_log={self._action_log}"
 
         yield from self.options
@@ -1449,7 +1484,7 @@
             return self.local_launch_command
         return self.remote_launch_command
 
-    def _process_download_stubs(self) -> Dict[Path, cl_utils.SubprocessResult]:
+    def _process_download_stubs(self) -> None:
         """Create download stubs so artifacts can be retrieved later."""
         self.vmsg(f"Reading remote action log from {self._action_log}.")
         log_record = ReproxyLogEntry.parse_action_log(self._action_log)
@@ -1460,10 +1495,12 @@
             "STATUS_LOCAL_FALLBACK",
             "STATUS_RACING_LOCAL",
         }:
-            return {}
+            return
 
-        self.vmsg("Creating download stubs for remote outputs.")
-        # Create stubs, even for artifacts that are always_download-ed.
+        if not self.skipping_some_download:
+            return
+
+        self.vmsg("Collecting digests for all remote outputs.")
         unique_log_dir = _reproxy_log_dir()  # unique per build
         build_id = Path(unique_log_dir).name if unique_log_dir else "unknown"
         stub_infos = log_record.make_download_stubs(
@@ -1472,42 +1509,17 @@
             build_id=build_id,
         )
 
-        # Write download stubs out.
+        # rewrapper has already downloaded the outputs that were not excluded
+        # by 'download_regex'.
+        # Write download stubs out for the artifacts that were not downloaded.
+
+        need_download_stub = self.need_download_stub_predicate
         for stub_info in stub_infos.values():
-            self.vmsg(f"  {stub_info.path}: {stub_info.blob_digest}")
-            self._update_stub(stub_info)
-
-        if not self.always_download:
-            return {}
-
-        always_download = set(self.always_download)
-        # Download outputs that were explicitly requested.
-        # Download actions here do not need to be locked because
-        # this remote action (as a step of a full build)
-        # is the sole producer of its outputs.
-
-        # Declared outputs are not required to exist remotely.
-        available_downloads = {
-            path: stub_info
-            for path, stub_info in stub_infos.items()
-            if path in always_download
-        }
-
-        path_strs = [str(path) for path in available_downloads.keys()]
-        outputs = self.output_files_relative_to_working_dir
-        target = outputs[0] if len(outputs) > 0 else "unknown-target"
-        try:
-            self.vmsg(f"Downloading outputs for {target}: {path_strs}")
-            download_statuses = download_output_stub_infos_batch(
-                downloader=self.downloader(),
-                stub_infos=available_downloads.values(),
-                working_dir_abs=self.working_dir,
-                verbose=self.verbose,
-            )
-        finally:
-            self.vmsg(f"  Downloaded outputs for {target} ({len(stub_infos)}).")
-
-        return download_statuses
+            if need_download_stub(stub_info.path):
+                self.vmsg(
+                    f"  download stub: {stub_info.path}: {stub_info.blob_digest}"
+                )
+                self._update_stub(stub_info)
 
     def download_inputs(
         self, keep_filter: Callable[[Path], bool]
@@ -1654,7 +1666,7 @@
             # Nothing do compare.
             return 0
 
-        if not self.download_outputs:
+        if self.skipping_some_download:
             self._process_download_stubs()
 
         # Possibly transform some of the remote outputs.
@@ -1668,12 +1680,12 @@
                 return post_run_status
 
         if self.compare_with_local:  # requesting comparison vs. local
-            if self.download_outputs:
+            if not self.skipping_some_download:
                 # Also run locally, and compare outputs.
                 return self._compare_against_local()
 
             # TODO: in compare-mode, force-download all output files and dirs,
-            # overriding and taking precedence over
+            # overriding and taking precedence over --download_regex and
             # --download_outputs=false, because comparison is intended
             # to be done locally with downloaded artifacts.
             # For now, just advise the user.
@@ -2251,8 +2263,12 @@
         "--download_outputs",
         type=cl_utils.bool_golang_flag,
         default=True,
-        help="Set to false to avoid downloading outputs after remote execution succeeds.  Each toolchain (Rust, C++) may decide how to apply this to its set of outputs yb default.  For example, for Rust, this affects only the main -o output."
-        "",
+        help="Set to false to avoid downloading outputs after remote execution succeeds.  Each toolchain (Rust, C++) may decide how to apply this to its set of outputs by default.  For example, for Rust, this affects only the main -o output.  Prefer using --download_regex over this option.",
+    )
+    parser.add_argument(
+        "--download_regex",
+        type=str,
+        help="Use a regex to specify which outputs to download or not.  Prefix with '-' to exclude files matching the pattern from downloading.  This flag takes precedence over --download_outputs.  This wrapper only supports a single regex value.",
     )
     return parser
 
@@ -2432,12 +2448,6 @@
         default=None,
         help=f"""Alternate command to execute remotely, while doing the setup for the original command.  e.g. --remote-debug-command="ls -l -R {PROJECT_ROOT_REL}" .""",
     )
-    main_group.add_argument(
-        "--download",
-        action="append",
-        default=[],
-        help="Always download these outputs, even when --download_outputs=false.  Arguments are files or directories relative to the working dir, comma-separated, repeatable and cumulative.",
-    )
     # Positional args are the command and arguments to run.
     parser.add_argument(
         "command", nargs="*", help="The command to run remotely"
@@ -2466,7 +2476,6 @@
     input_list_paths: Sequence[Path] = None,
     output_files: Sequence[Path] = None,
     output_dirs: Sequence[Path] = None,
-    downloads: Sequence[Path] = None,
     **kwargs,  # other RemoteAction __init__ params
 ) -> RemoteAction:
     """Construct a remote action based on argparse parameters."""
@@ -2483,9 +2492,6 @@
         Path(p)
         for p in cl_utils.flatten_comma_list(main_args.output_directories)
     ]
-    always_download = (downloads or []) + [
-        Path(p) for p in cl_utils.flatten_comma_list(main_args.download)
-    ]
     return RemoteAction(
         rewrapper=main_args.bindir / "rewrapper",
         options=(remote_options or []),
@@ -2508,7 +2514,6 @@
         fsatrace_path=main_args.fsatrace_path,
         diagnose_nonzero=main_args.diagnose_nonzero,
         remote_debug_command=main_args.remote_debug_command,
-        always_download=always_download,
         **kwargs,
     )
 
diff --git a/build/rbe/remote_action_test.py b/build/rbe/remote_action_test.py
index 2ca0c2ae..9e0a360 100755
--- a/build/rbe/remote_action_test.py
+++ b/build/rbe/remote_action_test.py
@@ -1997,7 +1997,6 @@
         self.assertFalse(action.check_determinism)
         self.assertFalse(action.diagnose_nonzero)
         self.assertTrue(action.download_outputs)
-        self.assertEqual(action.always_download, [])
 
     def test_path_setup_implicit(self):
         command = ["beep", "boop"]
@@ -2754,6 +2753,7 @@
         )
         self.assertEqual(action.local_only_command, command)
         self.assertFalse(action.download_outputs)
+        self.assertEqual(action.expected_downloads, [])
         options = action.options
         self.assertIn(download_option, options)
         logdir = "/fake/tmp/rpl/logz.932874"
@@ -2805,6 +2805,7 @@
         )
         self.assertEqual(action.local_only_command, command)
         self.assertFalse(action.download_outputs)
+        self.assertEqual(action.expected_downloads, [])
         options = action.options
         self.assertIn(download_option, options)
         logdir = "/fake/tmp/rpl/logz.932875"
@@ -2908,6 +2909,7 @@
         )
         self.assertEqual(action.local_only_command, command)
         self.assertFalse(action.download_outputs)
+        self.assertEqual(action.expected_downloads, [])
         options = action.options
         self.assertIn(download_option, options)
         logdir = "/fake/tmp/rpl/logz.888222"
@@ -2959,6 +2961,7 @@
         )
         self.assertEqual(action.local_only_command, command)
         self.assertFalse(action.download_outputs)
+        self.assertEqual(action.expected_downloads, [])
         options = action.options
         self.assertIn(download_option, options)
         logdir = "/fake/tmp/rpl/logz.213123"
@@ -3009,6 +3012,7 @@
         )
         self.assertEqual(action.local_only_command, command)
         self.assertFalse(action.download_outputs)
+        self.assertEqual(action.expected_downloads, [])
         options = action.options
         self.assertIn(download_option, options)
         logdir = "/fake/tmp/rpl/logz.81891"
@@ -3061,6 +3065,7 @@
         )
         self.assertEqual(action.local_only_command, command)
         self.assertFalse(action.download_outputs)
+        self.assertEqual(action.expected_downloads, [])
         self.assertTrue(action.preserve_unchanged_output_mtime)
         options = action.options
         self.assertIn(download_option, options)
@@ -3266,156 +3271,6 @@
             mock_remove.assert_called_with()
             mock_create_stub.assert_called_with(self.working_dir)
 
-    def test_explicit_always_download(self):
-        exec_root = Path("/home/project")
-        build_dir = Path("build-out")
-        working_dir = exec_root / build_dir
-        download_option = "--download_outputs=false"
-        p = remote_action._MAIN_ARG_PARSER
-        command = ["echo"]
-        output = Path("out.out")
-        output_digest = "5a5a57a76a6e4e4/91"
-        main_args, other = p.parse_known_args(
-            [download_option, f"--download={output}", "--"] + command
-        )
-        action = remote_action.remote_action_from_args(
-            main_args,
-            remote_options=other,
-            exec_root=exec_root,
-            working_dir=working_dir,
-            output_files=[output],
-        )
-        self.assertEqual(action.local_only_command, command)
-        self.assertFalse(action.download_outputs)
-        self.assertEqual(action.always_download, [output])
-        options = action.options
-        self.assertIn(download_option, options)
-        logdir = "/fake/tmp/rpl/logz.12387127"
-        action_digest = "9182731aef9ad0"
-        log_record = FakeReproxyLogEntry(
-            execution_id="000-111-22",
-            action_digest=action_digest,
-            output_file_digests={output: output_digest},
-            output_directory_digests={},
-            completion_status="STATUS_REMOTE_EXECUTION",
-        )
-        with mock.patch.object(
-            remote_action, "_reproxy_log_dir", return_value=logdir
-        ) as mock_log_dir:
-            with mock.patch.object(
-                remote_action.ReproxyLogEntry,
-                "parse_action_log",
-                return_value=log_record,
-            ) as mock_parse_log:
-                with mock.patch.object(
-                    remote_action.DownloadStubInfo, "create"
-                ) as mock_write_stub:
-                    with mock.patch.object(
-                        remote_action,
-                        "download_output_stub_infos_batch",
-                        return_value={output: cl_utils.SubprocessResult(0)},
-                    ) as mock_download:
-                        with mock.patch.object(
-                            remote_action.RemoteAction,
-                            "_run_maybe_remotely",
-                            return_value=cl_utils.SubprocessResult(0),
-                        ) as mock_run:
-                            with mock.patch.object(
-                                remote_action.RemoteAction,
-                                "downloader",
-                                return_value=_FAKE_DOWNLOADER,
-                            ) as mock_downloader:
-                                exit_code = action.run()
-        self.assertEqual(exit_code, 0)
-        mock_run.assert_called()
-        mock_log_dir.assert_called_with()
-        mock_write_stub.assert_called_with(working_dir)
-        mock_parse_log.assert_called_with(Path(str(output) + ".rrpl"))
-        mock_download.assert_called_once()
-        mock_downloader.assert_called_once_with()
-
-    def test_explicit_always_download_with_real_proxy_logdir(self):
-        with tempfile.TemporaryDirectory() as td:
-            exec_root = Path(td) / "exec_root"
-            logdir = Path(td) / "tmp/reproxy/logs"
-            build_dir = Path("build-out")
-            working_dir = exec_root / build_dir
-            download_option = "--download_outputs=false"
-            p = remote_action._MAIN_ARG_PARSER
-            command = ["compilezor"]
-            output = Path("objdir/hello-w0rld.obj")
-            output_digest = "3333377777ggggcccccaaaaa/717"
-            main_args, other = p.parse_known_args(
-                [download_option, f"--download={output}", "--"] + command
-            )
-            action = remote_action.remote_action_from_args(
-                main_args,
-                remote_options=other,
-                exec_root=exec_root,
-                working_dir=working_dir,
-                output_files=[output],
-            )
-            self.assertEqual(action.local_only_command, command)
-            self.assertFalse(action.download_outputs)
-            self.assertEqual(action.always_download, [output])
-            options = action.options
-            self.assertIn(download_option, options)
-            action_log = Path(str(output) + ".rrpl")
-            self.assertIn(
-                f"--action_log={action_log}",
-                set(action._generate_remote_command_prefix()),
-            )
-            action_log_contents = f"""
-command:  {{
-        identifiers:  {{
-                command_id:  "2b2b2b2b2-111111"
-                invocation_id:  "26363673-4643-7789-afad-7d2f8531ba98"
-                tool_name:  "re-client"
-                execution_id:  "fedefedefefdedefefe"
-        }}
-}}
-remote_metadata:  {{
-        command_digest:  "f9d024e5dc99433b08f4592309379e611461498d1480e2057c7afc285d30f097/181"
-        action_digest:  "87bacb7fege6ha65a3300/77"
-        output_file_digests: {{
-                key: "{output}"
-                value: "{output_digest}"
-        }}
-}}
-completion_status: STATUS_CACHE_HIT
-"""
-
-            def fake_run_remote(
-                unused_action: remote_action.RemoteAction,
-            ) -> cl_utils.SubprocessResult:
-                output.parent.mkdir(parents=True, exist_ok=True)
-                _write_file_contents(output, "death-to-bash-scripts\n")
-                _write_file_contents(action_log, action_log_contents)
-                return cl_utils.SubprocessResult(0)
-
-            with mock.patch.object(
-                remote_action, "_reproxy_log_dir", return_value=logdir
-            ) as mock_log_dir:
-                with mock.patch.object(
-                    remote_action,
-                    "download_output_stub_infos_batch",
-                    return_value={},
-                ) as mock_download:
-                    with mock.patch(
-                        "remote_action.RemoteAction._run_maybe_remotely",
-                        new=fake_run_remote,
-                    ) as mock_run:
-                        with mock.patch.object(
-                            remote_action.RemoteAction,
-                            "downloader",
-                            return_value=_FAKE_DOWNLOADER,
-                        ) as mock_downloader:
-                            exit_code = action.run()
-            self.assertEqual(exit_code, 0)
-            mock_log_dir.assert_called_once()
-            mock_download.assert_called_once()
-            mock_downloader.assert_called_once_with()
-
 
 class RbeDiagnosticsTests(unittest.TestCase):
     def _make_remote_action(self, **kwargs):
diff --git a/build/rbe/rustc_remote_wrapper.py b/build/rbe/rustc_remote_wrapper.py
index f87b027..89d2429 100755
--- a/build/rbe/rustc_remote_wrapper.py
+++ b/build/rbe/rustc_remote_wrapper.py
@@ -755,11 +755,19 @@
         # artifact).  In other words, always download *all* other outputs,
         # including the depfile and emitted llvm-ir (if applicable).
         # The depfile *must* be downloaded because it is consumed by ninja.
-        downloads = [f for f in remote_output_files if f != self.primary_output]
+
+        translated_remote_options = []
+        for opt in self.remote_options:
+            if opt == "--download_outputs=false":
+                translated_remote_options.append(
+                    f"--download_regex=-{self.primary_output}$"
+                )
+            else:
+                translated_remote_options.append(opt)
 
         self._remote_action = remote_action.remote_action_from_args(
             main_args=self._main_args,
-            remote_options=self.remote_options,
+            remote_options=translated_remote_options,
             command=list(self.remote_compile_command()),
             inputs=remote_inputs,
             output_files=remote_output_files,
@@ -767,7 +775,6 @@
             working_dir=self.working_dir,
             exec_root=self.exec_root,
             post_remote_run_success_action=self._post_remote_success_action,
-            downloads=downloads,
         )
         self._prepare_status = 0  # exit code success
         return self._prepare_status
@@ -920,7 +927,7 @@
             self._rewrite_remote_or_local_depfile()
 
         if (
-            not self.remote_action.download_outputs
+            self.remote_action.skipping_some_download
             and self._rust_action.main_output_is_executable
         ):
             # TODO(b/285030257): This is a workaround to a problem where
diff --git a/build/rbe/rustc_remote_wrapper_test.py b/build/rbe/rustc_remote_wrapper_test.py
index 643bb6c..0264e28 100755
--- a/build/rbe/rustc_remote_wrapper_test.py
+++ b/build/rbe/rustc_remote_wrapper_test.py
@@ -412,8 +412,60 @@
             remote_inputs, set([compiler, shlib_rel, source] + deps)
         )
         self.assertEqual(remote_output_files, {rlib, depfile_path})
+        self.assertFalse(a.skipping_some_download)
         # Even if download_outputs=false, the depfile is required locally.
-        self.assertEqual(set(a.always_download), {depfile_path})
+        self.assertEqual(set(a.expected_downloads), remote_output_files)
+
+    def test_prepare_depfile_download_false(self):
+        exec_root = Path("/home/project")
+        working_dir = exec_root / "build-here"
+        compiler = Path("../tools/bin/rustc")
+        shlib = Path("tools/lib/librusteze.so")
+        shlib_abs = exec_root / shlib
+        shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
+        source = Path("../foo/src/lib.rs")
+        rlib = Path("obj/foo.rlib")
+        deps = [Path("../foo/src/other.rs")]
+        depfile_path = Path("obj/foo.rlib.d")
+        depfile_contents = [str(d) + ":" for d in deps]
+        # skip downloading the main output
+        command = _strs(
+            [
+                compiler,
+                source,
+                "-o",
+                rlib,
+                f"--emit=dep-info={depfile_path}",
+                "--remote-flag=--download_outputs=false",
+            ]
+        )
+        r = rustc_remote_wrapper.RustRemoteAction(
+            ["--"] + command,
+            exec_root=exec_root,
+            working_dir=working_dir,
+            auto_reproxy=False,
+        )
+
+        mocks = self.generate_prepare_mocks(
+            depfile_contents=depfile_contents,
+            compiler_shlibs=[shlib_rel],
+        )
+        with contextlib.ExitStack() as stack:
+            for m in mocks:
+                stack.enter_context(m)
+            prepare_status = r.prepare()
+
+        self.assertEqual(prepare_status, 0)  # success
+        a = r.remote_action
+        remote_inputs = set(a.inputs_relative_to_working_dir)
+        remote_output_files = set(a.output_files_relative_to_working_dir)
+        self.assertEqual(
+            remote_inputs, set([compiler, shlib_rel, source] + deps)
+        )
+        self.assertEqual(remote_output_files, {rlib, depfile_path})
+        self.assertTrue(a.skipping_some_download)
+        # Even if download_outputs=false, the depfile is required locally.
+        self.assertEqual(set(a.expected_downloads), {depfile_path})
 
     def test_prepare_depfile_failure(self):
         exec_root = Path("/home/project")
@@ -480,7 +532,59 @@
         )
         # Even if download_outputs=false, we want the non-primary outputs.
         self.assertEqual(remote_output_files, {rlib, llvm_ir})
-        self.assertEqual(set(a.always_download), {llvm_ir})
+        self.assertFalse(a.skipping_some_download)
+        self.assertEqual(set(a.expected_downloads), remote_output_files)
+
+    def test_prepare_llvm_ir_download_false(self):
+        exec_root = Path("/home/project")
+        working_dir = exec_root / "build-here"
+        compiler = Path("../tools/bin/rustc")
+        shlib = Path("tools/lib/librusteze.so")
+        shlib_abs = exec_root / shlib
+        shlib_rel = cl_utils.relpath(shlib_abs, start=working_dir)
+        source = Path("../foo/src/lib.rs")
+        rlib = Path("obj/foo.rlib")
+        llvm_ir = Path("obj/foo.ll")
+        deps = [Path("../foo/src/other.rs")]
+        depfile_path = Path("obj/foo.rlib.d")
+        depfile_contents = [str(d) + ":" for d in deps]
+        command = _strs(
+            [
+                compiler,
+                source,
+                "-o",
+                rlib,
+                f"--emit=llvm-ir",
+                "--remote-flag=--download_outputs=false",
+            ]
+        )
+        r = rustc_remote_wrapper.RustRemoteAction(
+            ["--"] + command,
+            exec_root=exec_root,
+            working_dir=working_dir,
+            auto_reproxy=False,
+        )
+
+        mocks = self.generate_prepare_mocks(
+            depfile_contents=depfile_contents,
+            compiler_shlibs=[shlib_rel],
+        )
+        with contextlib.ExitStack() as stack:
+            for m in mocks:
+                stack.enter_context(m)
+            prepare_status = r.prepare()
+
+        self.assertEqual(prepare_status, 0)  # success
+        a = r.remote_action
+        remote_inputs = set(a.inputs_relative_to_working_dir)
+        remote_output_files = set(a.output_files_relative_to_working_dir)
+        self.assertEqual(
+            remote_inputs, set([compiler, shlib_rel, source] + deps)
+        )
+        # Even if download_outputs=false, we want the non-primary outputs.
+        self.assertEqual(remote_output_files, {rlib, llvm_ir})
+        self.assertTrue(a.skipping_some_download)
+        self.assertEqual(set(a.expected_downloads), {llvm_ir})
 
     def test_prepare_externs(self):
         exec_root = Path("/home/project")
diff --git a/build/rust/rustc_library.gni b/build/rust/rustc_library.gni
index 5fb6843..4925f7a 100644
--- a/build/rust/rustc_library.gni
+++ b/build/rust/rustc_library.gni
@@ -55,6 +55,12 @@
 #   test_deps (optional)
 #     List of rust_library GN targets on which this crate's tests depend.
 #
+#   non_test_deps (optional)
+#     List of rust_library GN targets on which this crate depends but not its
+#     tests. This can be used to replace a dependency between the test and
+#     library targets. It's an error to provide this when with_unit_tests is
+#     false.
+#
 #   non_rust_deps (optional)
 #     List of non-rust_library GN targets on which this crate depends.
 #     Obsolete. Please use deps instead.
@@ -184,6 +190,7 @@
                                "assert_no_deps",
                                "disable_rustdoc",
                                "test_disable_rbe",
+                               "non_test_deps",
                              ])
       if (defined(invoker.test_disable_rbe)) {
         disable_rbe = invoker.test_disable_rbe
@@ -226,6 +233,12 @@
       deps += invoker.deps
     }
 
+    if (defined(invoker.non_test_deps)) {
+      assert(defined(invoker.with_unit_tests) && invoker.with_unit_tests,
+             "use deps if not generating unit tests")
+      deps += invoker.non_test_deps
+    }
+
     # TODO(https://fxbug.dev/42120123) remove "non_rust_deps"
     if (defined(invoker.non_rust_deps)) {
       deps += invoker.non_rust_deps
diff --git a/build/sdk/BUILD.gn b/build/sdk/BUILD.gn
index 127684e..ef88e82 100644
--- a/build/sdk/BUILD.gn
+++ b/build/sdk/BUILD.gn
@@ -70,6 +70,7 @@
   "//sdk/lib/vfs/cpp",
   "//sdk/lib/virtgralloc:virtgralloc_headers",
   "//sdk/lib/zbi-format",
+  "//src/devices/lib/mmio",
   "//src/lib/fidl/cpp:cpp_base",
   "//src/lib/fidl/cpp:hlcpp_conversion",
   "//src/lib/fidl/cpp:natural_ostream",
@@ -80,6 +81,7 @@
   "//zircon/system/ulib/async:async-cpp",
   "//zircon/system/ulib/async",
   "//zircon/system/ulib/ddk-platform-defs",
+  "//zircon/system/ulib/hwreg:hwreg_sdk",
   "//zircon/system/ulib/inspect",
   "//zircon/system/ulib/mmio-ptr",
   "//zircon/system/ulib/sync:sync-cpp",
diff --git a/build/sdk/config.gni b/build/sdk/config.gni
index 90d72c3..12f1d43 100644
--- a/build/sdk/config.gni
+++ b/build/sdk/config.gni
@@ -11,14 +11,6 @@
   # Can be true for any API level, including the default level.
   sdk_inside_sub_build = false
 
-  # Whether currently building a sub-build for a specific supported API level
-  # rather than a build or sub-build at the default API level.
-  # Note that this can be false in sub-builds - specifically, when building the
-  # default API level for target CPUs other than the host.
-  # `sdk_inside_sub_build` must be true and `override_target_api_level` must be
-  # set to a valid level.
-  sdk_inside_supported_api_sub_build = false
-
   # An upper bound on the maximum number of subbuilds that may be running at the
   # same time. A larger number means these good things:
   # - Better parallelization of the inherently single-threaded parts of GN and
diff --git a/build/sdk/generate_idk/BUILD.gn b/build/sdk/generate_idk/BUILD.gn
index ce4282d..e9211d8 100644
--- a/build/sdk/generate_idk/BUILD.gn
+++ b/build/sdk/generate_idk/BUILD.gn
@@ -10,7 +10,10 @@
   python_binary("generate_idk") {
     visibility = [ "*" ]
     main_source = "cmd.py"
-    deps = [ ":lib" ]
+    deps = [
+      ":lib",
+      "//build/python/modules/depfile",
+    ]
     enable_mypy = true
   }
 
diff --git a/build/sdk/generate_idk/__init__.py b/build/sdk/generate_idk/__init__.py
index c6d02fe..6a642e1 100644
--- a/build/sdk/generate_idk/__init__.py
+++ b/build/sdk/generate_idk/__init__.py
@@ -98,6 +98,100 @@
 )
 
 
+@dataclasses.dataclass
+class PartialAtom:
+    """Metadata and files associated with a single Atom from a single subbuild.
+
+    Attributes:
+        meta (AtomMeta): JSON object from the atom's `meta.json` file.
+        meta_src (pathlib.Path): The path from which `meta` was read.
+        dest_to_src (dict[pathlib.Path, pathlib.Path]): All non-metadata files
+            associated with this atom belong in this dictionary. The key is the
+            file path relative to the final IDK directory. The value is either
+            absolute or relative to the current working directory.
+    """
+
+    meta: AtomMeta
+    meta_src: pathlib.Path
+    dest_to_src: dict[pathlib.Path, pathlib.Path]
+
+
+@dataclasses.dataclass
+class PartialIDK:
+    """A model of the parts of an IDK from a single subbuild.
+
+    Attributes:
+        manifest_src (pathlib.Path): Source path for the overall build manifest.
+            Either absolute or relative to the current working directory.
+        atoms (dict[pathlib.Path, PartialAtom]): Atoms to include in the IDK,
+            indexed by the path to their metadata file, relative to the final
+            IDK directory (e.g., `bind/fuchsia.ethernet/meta.json`).
+    """
+
+    manifest_src: pathlib.Path
+    atoms: dict[pathlib.Path, PartialAtom]
+
+    @staticmethod
+    def load(
+        build_dir: pathlib.Path, relative_manifest_path: pathlib.Path
+    ) -> PartialIDK:
+        """Load relevant information about a piece of the IDK from a subbuild
+        dir."""
+        result = PartialIDK(
+            manifest_src=(build_dir / relative_manifest_path), atoms={}
+        )
+        with (build_dir / relative_manifest_path).open() as f:
+            build_manifest: BuildManifestJson = json.load(f)
+
+        for atom in build_manifest["atoms"]:
+            # sdk_noop_atoms have no metadata specified. Skip them.
+            if not atom["meta"]:
+                continue
+
+            meta_dest = pathlib.Path(atom["meta"])
+            meta_src = None
+            dest_to_src = {}
+            for file in atom["files"]:
+                src_path = build_dir / file["source"]
+                dest_path = pathlib.Path(file["destination"])
+
+                # Determine if this file is the metadata file for this atom.
+                if dest_path == meta_dest:
+                    meta_src = src_path
+                else:
+                    assert dest_path not in dest_to_src, (
+                        "File specified multiple times in atom: %s" % dest_path
+                    )
+                    dest_to_src[dest_path] = src_path
+
+            assert meta_src, (
+                "Atom does not include its metadata file in 'files': %s" % atom
+            )
+
+            with meta_src.open() as f:
+                assert meta_dest not in result.atoms, (
+                    "Atom metadata file specified multiple times: %s"
+                    % meta_dest
+                )
+                result.atoms[meta_dest] = PartialAtom(
+                    meta=json.load(f),
+                    meta_src=meta_src,
+                    dest_to_src=dest_to_src,
+                )
+
+        return result
+
+    def input_files(self) -> set[pathlib.Path]:
+        """Return the set of input files in this PartialIDK for generating a
+        depfile."""
+        result = set()
+        result.add(self.manifest_src)
+        for atom in self.atoms.values():
+            result.add(atom.meta_src)
+            result |= set(atom.dest_to_src.values())
+        return result
+
+
 class AtomMergeError(Exception):
     def __init__(self, atom_path: pathlib.Path):
         super(AtomMergeError, self).__init__(
@@ -106,7 +200,7 @@
 
 
 @dataclasses.dataclass
-class PartialIDK:
+class MergedIDK:
     """A model of a (potentially incomplete) IDK.
 
     Attributes:
@@ -120,56 +214,30 @@
             relative to the current working directory.
     """
 
-    atoms: dict[pathlib.Path, AtomMeta]
-    dest_to_src: dict[pathlib.Path, pathlib.Path]
+    atoms: dict[pathlib.Path, AtomMeta] = dataclasses.field(
+        default_factory=dict
+    )
+    dest_to_src: dict[pathlib.Path, pathlib.Path] = dataclasses.field(
+        default_factory=dict
+    )
 
-    @staticmethod
-    def load(
-        build_dir: pathlib.Path, relative_manifest_path: pathlib.Path
-    ) -> PartialIDK:
-        """Load relevant information about a piece of the IDK from a subbuild
-        dir."""
-        with (build_dir / relative_manifest_path).open() as f:
-            build_manifest: BuildManifestJson = json.load(f)
-
-        result = PartialIDK(atoms={}, dest_to_src={})
-        for atom in build_manifest["atoms"]:
-            for file in atom["files"]:
-                src_path = build_dir / file["source"]
-                dest_path = pathlib.Path(file["destination"])
-
-                # Determine if this file is the metadata file for this atom.
-                if atom["meta"] == file["destination"]:
-                    with src_path.open() as f:
-                        assert dest_path not in result.atoms, (
-                            "Atom metadata file specified multiple times: %s"
-                            % dest_path
-                        )
-                        result.atoms[dest_path] = json.load(f)
-                else:
-                    # Some files may be listed under multiple atoms, for
-                    # example, package blobs. That's fine, but they must always
-                    # have the same source file.
-                    if prev_src := result.dest_to_src.get(dest_path):
-                        assert src_path.samefile(prev_src), (
-                            "IDK file '%s' listed with multiple sources:\n- %s\n- %s"
-                            % (dest_path, prev_src, src_path)
-                        )
-                    else:
-                        result.dest_to_src[dest_path] = src_path
-
-        return result
-
-    def merge_with(self, other: PartialIDK) -> PartialIDK:
-        """Merge the contents of this PartialIDK with another.
+    def merge_with(self, other: PartialIDK) -> MergedIDK:
+        """Merge the contents of this MergedIDK with a PartialIDK and return the
+        result.
 
         Put enough of them together, and you get a full IDK!
         """
-        return PartialIDK(
+        result = MergedIDK(
             atoms=_merge_atoms(self.atoms, other.atoms),
-            dest_to_src=_merge_other_files(self.dest_to_src, other.dest_to_src),
+            dest_to_src=self.dest_to_src,
         )
 
+        for atom in other.atoms.values():
+            result.dest_to_src = _merge_other_files(
+                result.dest_to_src, atom.dest_to_src
+            )
+        return result
+
     def sdk_manifest_json(
         self, host_arch: str, target_arch: list[str], release_version: str
     ) -> Any:
@@ -204,7 +272,7 @@
 
 
 def _merge_atoms(
-    a: dict[pathlib.Path, AtomMeta], b: dict[pathlib.Path, AtomMeta]
+    a: dict[pathlib.Path, AtomMeta], b: dict[pathlib.Path, PartialAtom]
 ) -> dict[pathlib.Path, AtomMeta]:
     """Merge two dictionaries full of atoms."""
     result = {}
@@ -219,25 +287,26 @@
                 # Treat version_history.json specially, since it doesn't have a
                 # 'type' field.
                 assert (
-                    atom_a == atom_b
+                    atom_a == atom_b.meta
                 ), "A and B had different 'version_history' values. Huh?"
                 result[atom_path] = atom_a
             else:
                 # Merge atoms found in both IDKs.
                 try:
-                    result[atom_path] = _merge_atom(atom_a, atom_b)
+                    result[atom_path] = _merge_atom_meta(atom_a, atom_b.meta)
                 except Exception as e:
                     raise AtomMergeError(atom_path) from e
         elif atom_a:
             result[atom_path] = atom_a
         else:
             assert atom_b, "unreachable. Atom '%s' had falsy value?" % atom_path
-            result[atom_path] = atom_b
+            result[atom_path] = atom_b.meta
     return result
 
 
 def _merge_other_files(
-    a: dict[pathlib.Path, pathlib.Path], b: dict[pathlib.Path, pathlib.Path]
+    a: dict[pathlib.Path, pathlib.Path],
+    b: dict[pathlib.Path, pathlib.Path],
 ) -> dict[pathlib.Path, pathlib.Path]:
     """Merge two dictionaries from (destination -> src). Shared keys are only
     allowed if the value files have the same contents."""
@@ -330,7 +399,7 @@
         return a or b or {}
 
 
-def _merge_atom(a: AtomMeta, b: AtomMeta) -> AtomMeta:
+def _merge_atom_meta(a: AtomMeta, b: AtomMeta) -> AtomMeta:
     """Merge two atoms, according to type-specific rules."""
     if a["type"] in (
         "cc_source_library",
diff --git a/build/sdk/generate_idk/cmd.py b/build/sdk/generate_idk/cmd.py
index 50e8e93..51c5b5c 100755
--- a/build/sdk/generate_idk/cmd.py
+++ b/build/sdk/generate_idk/cmd.py
@@ -20,6 +20,7 @@
 import pathlib
 import sys
 
+import depfile
 import generate_idk
 
 
@@ -81,18 +82,22 @@
         type=pathlib.Path,
         required=True,
     )
+    parser.add_argument(
+        "--depfile",
+        help="Path to the stamp file",
+        type=pathlib.Path,
+    )
     args = parser.parse_args()
 
-    first_subbuild, *other_subbuilds = args.subbuild_directory
+    # Collect all possible input files, to make a depfile.
+    input_files: set[pathlib.Path] = set()
 
-    merged = generate_idk.PartialIDK.load(
-        first_subbuild, args.relative_manifest
-    )
-
-    for build_dir in other_subbuilds:
+    merged = generate_idk.MergedIDK()
+    for build_dir in args.subbuild_directory:
         manifest = generate_idk.PartialIDK.load(
             build_dir, args.relative_manifest
         )
+        input_files |= manifest.input_files()
         merged = merged.merge_with(manifest)
 
     output_dir: pathlib.Path = args.output_directory
@@ -134,6 +139,14 @@
 
     args.stamp_file.touch()
 
+    if args.depfile:
+        depfile_path: pathlib.Path = args.depfile
+        depfile_path.parent.mkdir(parents=True, exist_ok=True)
+        with depfile_path.open("w") as depfile_out:
+            depfile.DepFile.from_deps(
+                str(args.stamp_file), set(str(d) for d in input_files)
+            ).write_to(depfile_out)
+
     return 0
 
 
diff --git a/build/sdk/generate_idk/generate_idk_unittest.py b/build/sdk/generate_idk/generate_idk_unittest.py
index 7aa180c..f8a77a2 100755
--- a/build/sdk/generate_idk/generate_idk_unittest.py
+++ b/build/sdk/generate_idk/generate_idk_unittest.py
@@ -26,60 +26,84 @@
     def test_unmergables_error(self) -> None:
         for atom_type in UNMERGABLE_TYPES:
             a: generate_idk.PartialIDK = generate_idk.PartialIDK(
+                manifest_src="thingy.sdk",
                 atoms={
-                    "foo/bar.json": {
-                        "type": atom_type,
-                        "foo": "bar",
-                    }
+                    "foo/bar.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/bar.json"),
+                        meta={
+                            "type": atom_type,
+                            "foo": "bar",
+                        },
+                        dest_to_src={},
+                    )
                 },
-                dest_to_src={},
             )
             b: generate_idk.PartialIDK = generate_idk.PartialIDK(
+                manifest_src="thingy.sdk",
                 atoms={
-                    "foo/bar.json": {
-                        "type": atom_type,
-                        "foo": "baz",
-                    }
+                    "foo/bar.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/bar.json"),
+                        meta={
+                            "type": atom_type,
+                            "foo": "baz",
+                        },
+                        dest_to_src={},
+                    )
                 },
-                dest_to_src={},
             )
 
             with self.assertRaises(generate_idk.AtomMergeError) as e:
-                a.merge_with(b)
+                generate_idk.MergedIDK().merge_with(a).merge_with(b)
             self.assertIn("'foo' does not match", str(e.exception.__cause__))
 
     def test_unmergables_pass(self) -> None:
         for atom_type in UNMERGABLE_TYPES:
             a: generate_idk.PartialIDK = generate_idk.PartialIDK(
+                manifest_src="thingy.sdk",
                 atoms={
-                    "foo/bar.json": {
-                        "type": atom_type,
-                        "foo": "bar",
-                    },
-                    "foo/qux.json": {
-                        "type": "cc_source_library",
-                        "hither": "yon",
-                    },
+                    "foo/bar.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/bar.json"),
+                        meta={
+                            "type": atom_type,
+                            "foo": "bar",
+                        },
+                        dest_to_src={},
+                    ),
+                    "foo/qux.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/qux.json"),
+                        meta={
+                            "type": "cc_source_library",
+                            "hither": "yon",
+                        },
+                        dest_to_src={},
+                    ),
                 },
-                dest_to_src={},
             )
             b: generate_idk.PartialIDK = generate_idk.PartialIDK(
+                manifest_src="thingy.sdk",
                 atoms={
-                    "foo/bar.json": {
-                        "type": atom_type,
-                        "foo": "bar",
-                    },
-                    "foo/baz.json": {
-                        "type": atom_type,
-                        "foo": "baz",
-                    },
+                    "foo/bar.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/bar.json"),
+                        meta={
+                            "type": atom_type,
+                            "foo": "bar",
+                        },
+                        dest_to_src={},
+                    ),
+                    "foo/baz.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/baz.json"),
+                        meta={
+                            "type": atom_type,
+                            "foo": "baz",
+                        },
+                        dest_to_src={},
+                    ),
                 },
-                dest_to_src={},
             )
 
             self.assertEqual(
-                a.merge_with(b),
-                generate_idk.PartialIDK(
+                generate_idk.MergedIDK().merge_with(a).merge_with(b),
+                generate_idk.MergedIDK(
                     atoms={
                         "foo/bar.json": {
                             "type": atom_type,
@@ -100,41 +124,49 @@
 
     def test_merge_cc_prebuilt_library_pass(self) -> None:
         a = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "cc_prebuilt_library",
-                    "binaries": {
-                        "a": "a",
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "cc_prebuilt_library",
+                        "binaries": {
+                            "a": "a",
+                        },
+                        "variants": [
+                            {"constraints": "a"},
+                        ],
+                        "foo": "bar",
                     },
-                    "variants": [
-                        {"constraints": "a"},
-                    ],
-                    "foo": "bar",
-                },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
         b = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "cc_prebuilt_library",
-                    "binaries": {
-                        "b": "b",
-                        "c": "c",
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "cc_prebuilt_library",
+                        "binaries": {
+                            "b": "b",
+                            "c": "c",
+                        },
+                        "variants": [
+                            {"constraints": "b"},
+                            {"constraints": "c"},
+                        ],
+                        "foo": "bar",
                     },
-                    "variants": [
-                        {"constraints": "b"},
-                        {"constraints": "c"},
-                    ],
-                    "foo": "bar",
-                },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
 
         self.assertEqual(
-            a.merge_with(b),
-            generate_idk.PartialIDK(
+            generate_idk.MergedIDK().merge_with(a).merge_with(b),
+            generate_idk.MergedIDK(
                 atoms={
                     "atom0.json": {
                         "type": "cc_prebuilt_library",
@@ -157,35 +189,43 @@
 
     def test_merge_package_pass(self) -> None:
         a = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "package",
-                    "variants": [
-                        {"api_level": 12, "arch": "x64"},
-                        {"api_level": 13, "arch": "x64"},
-                    ],
-                    "foo": "bar",
-                },
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "package",
+                        "variants": [
+                            {"api_level": 12, "arch": "x64"},
+                            {"api_level": 13, "arch": "x64"},
+                        ],
+                        "foo": "bar",
+                    },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
         b = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "package",
-                    "variants": [
-                        {"api_level": 13, "arch": "arm64"},
-                        {"api_level": 14, "arch": "arm64"},
-                    ],
-                    "foo": "bar",
-                },
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "package",
+                        "variants": [
+                            {"api_level": 13, "arch": "arm64"},
+                            {"api_level": 14, "arch": "arm64"},
+                        ],
+                        "foo": "bar",
+                    },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
 
         self.assertEqual(
-            a.merge_with(b),
-            generate_idk.PartialIDK(
+            generate_idk.MergedIDK().merge_with(a).merge_with(b),
+            generate_idk.MergedIDK(
                 atoms={
                     "atom0.json": {
                         "type": "package",
@@ -204,34 +244,42 @@
 
     def test_merge_loadable_module_pass(self) -> None:
         a = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "loadable_module",
-                    "binaries": {
-                        "a": "a",
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "loadable_module",
+                        "binaries": {
+                            "a": "a",
+                        },
+                        "foo": "bar",
                     },
-                    "foo": "bar",
-                },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
         b = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "loadable_module",
-                    "binaries": {
-                        "b": "b",
-                        "c": "c",
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "loadable_module",
+                        "binaries": {
+                            "b": "b",
+                            "c": "c",
+                        },
+                        "foo": "bar",
                     },
-                    "foo": "bar",
-                },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
 
         self.assertEqual(
-            a.merge_with(b),
-            generate_idk.PartialIDK(
+            generate_idk.MergedIDK().merge_with(a).merge_with(b),
+            generate_idk.MergedIDK(
                 atoms={
                     "atom0.json": {
                         "type": "loadable_module",
@@ -249,41 +297,49 @@
 
     def test_merge_sysroot_pass(self) -> None:
         a = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "sysroot",
-                    "versions": {
-                        "a": "a",
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "sysroot",
+                        "versions": {
+                            "a": "a",
+                        },
+                        "variants": [
+                            {"constraints": "a"},
+                        ],
+                        "foo": "bar",
                     },
-                    "variants": [
-                        {"constraints": "a"},
-                    ],
-                    "foo": "bar",
-                },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
         b = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "sysroot",
-                    "versions": {
-                        "b": "b",
-                        "c": "c",
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "sysroot",
+                        "versions": {
+                            "b": "b",
+                            "c": "c",
+                        },
+                        "variants": [
+                            {"constraints": "b"},
+                            {"constraints": "c"},
+                        ],
+                        "foo": "bar",
                     },
-                    "variants": [
-                        {"constraints": "b"},
-                        {"constraints": "c"},
-                    ],
-                    "foo": "bar",
-                },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
 
         self.assertEqual(
-            a.merge_with(b),
-            generate_idk.PartialIDK(
+            generate_idk.MergedIDK().merge_with(a).merge_with(b),
+            generate_idk.MergedIDK(
                 atoms={
                     "atom0.json": {
                         "type": "sysroot",
@@ -306,34 +362,42 @@
 
     def test_merge_variants_cc_prebuilt_library_pass(self) -> None:
         a = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "cc_prebuilt_library",
-                    "variants": [
-                        {"constraints": "a"},
-                    ],
-                    "foo": "bar",
-                },
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "cc_prebuilt_library",
+                        "variants": [
+                            {"constraints": "a"},
+                        ],
+                        "foo": "bar",
+                    },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
         b = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "cc_prebuilt_library",
-                    "variants": [
-                        {"constraints": "b"},
-                        {"constraints": "c"},
-                    ],
-                    "foo": "bar",
-                },
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "cc_prebuilt_library",
+                        "variants": [
+                            {"constraints": "b"},
+                            {"constraints": "c"},
+                        ],
+                        "foo": "bar",
+                    },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
 
         self.assertEqual(
-            a.merge_with(b),
-            generate_idk.PartialIDK(
+            generate_idk.MergedIDK().merge_with(a).merge_with(b),
+            generate_idk.MergedIDK(
                 atoms={
                     "atom0.json": {
                         "type": "cc_prebuilt_library",
@@ -353,148 +417,203 @@
     def test_merge_binaries_fail(self) -> None:
         for atom_type in ["cc_prebuilt_library", "loadable_module"]:
             a = generate_idk.PartialIDK(
+                manifest_src="thingy.sdk",
                 atoms={
-                    "atom0.json": {
-                        "type": atom_type,
-                        "binaries": {
+                    "atom0.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/atom0.json"),
+                        meta={
+                            "type": atom_type,
+                            "binaries": {
+                                "a": "a",
+                            },
+                            "foo": "bar",
+                        },
+                        dest_to_src={},
+                    ),
+                },
+            )
+            b = generate_idk.PartialIDK(
+                manifest_src="thingy.sdk",
+                atoms={
+                    "atom0.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/atom0.json"),
+                        meta={
+                            "type": atom_type,
+                            "binaries": {
+                                "a": "a",
+                                "c": "c",
+                            },
+                            "foo": "bar",
+                        },
+                        dest_to_src={},
+                    ),
+                },
+            )
+
+            with self.assertRaises(generate_idk.AtomMergeError) as e:
+                generate_idk.MergedIDK().merge_with(a).merge_with(b)
+            self.assertIn("overlapping keys", str(e.exception.__cause__))
+
+    def test_merge_versions_fail(self) -> None:
+        a = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
+            atoms={
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "sysroot",
+                        "versions": {
                             "a": "a",
                         },
                         "foo": "bar",
                     },
-                },
-                dest_to_src={},
-            )
-            b = generate_idk.PartialIDK(
-                atoms={
-                    "atom0.json": {
-                        "type": atom_type,
-                        "binaries": {
+                    dest_to_src={},
+                ),
+            },
+        )
+        b = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
+            atoms={
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "sysroot",
+                        "versions": {
                             "a": "a",
                             "c": "c",
                         },
                         "foo": "bar",
                     },
-                },
-                dest_to_src={},
-            )
-
-            with self.assertRaises(generate_idk.AtomMergeError) as e:
-                a.merge_with(b)
-            self.assertIn("overlapping keys", str(e.exception.__cause__))
-
-    def test_merge_versions_fail(self) -> None:
-        a = generate_idk.PartialIDK(
-            atoms={
-                "atom0.json": {
-                    "type": "sysroot",
-                    "versions": {
-                        "a": "a",
-                    },
-                    "foo": "bar",
-                },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
-        )
-        b = generate_idk.PartialIDK(
-            atoms={
-                "atom0.json": {
-                    "type": "sysroot",
-                    "versions": {
-                        "a": "a",
-                        "c": "c",
-                    },
-                    "foo": "bar",
-                },
-            },
-            dest_to_src={},
         )
 
         with self.assertRaises(generate_idk.AtomMergeError) as e:
-            a.merge_with(b)
+            generate_idk.MergedIDK().merge_with(a).merge_with(b)
         self.assertIn("overlapping keys", str(e.exception.__cause__))
 
     def test_merge_variants_fail(self) -> None:
         for atom_type in ["cc_prebuilt_library", "sysroot"]:
             a = generate_idk.PartialIDK(
+                manifest_src="thingy.sdk",
                 atoms={
-                    "atom0.json": {
-                        "type": atom_type,
-                        "variants": [
-                            {"constraints": "a"},
-                        ],
-                        "foo": "bar",
-                    },
+                    "atom0.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/atom0.json"),
+                        meta={
+                            "type": atom_type,
+                            "variants": [
+                                {"constraints": "a"},
+                            ],
+                            "foo": "bar",
+                        },
+                        dest_to_src={},
+                    ),
                 },
-                dest_to_src={},
             )
             b = generate_idk.PartialIDK(
+                manifest_src="thingy.sdk",
                 atoms={
-                    "atom0.json": {
-                        "type": atom_type,
-                        "variants": [
-                            {"constraints": "a"},
-                            {"constraints": "c"},
-                        ],
-                        "foo": "bar",
-                    },
+                    "atom0.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/atom0.json"),
+                        meta={
+                            "type": atom_type,
+                            "variants": [
+                                {"constraints": "a"},
+                                {"constraints": "c"},
+                            ],
+                            "foo": "bar",
+                        },
+                        dest_to_src={},
+                    ),
                 },
-                dest_to_src={},
             )
 
             with self.assertRaises(generate_idk.AtomMergeError) as e:
-                a.merge_with(b)
+                generate_idk.MergedIDK().merge_with(a).merge_with(b)
             self.assertIn("duplicate variants", str(e.exception.__cause__))
 
     def test_merge_variants_package_fail(self) -> None:
         a = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "package",
-                    "variants": [
-                        {"api_level": 12, "arch": "x64"},
-                    ],
-                    "foo": "bar",
-                },
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "package",
+                        "variants": [
+                            {"api_level": 12, "arch": "x64"},
+                        ],
+                        "foo": "bar",
+                    },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
         b = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
             atoms={
-                "atom0.json": {
-                    "type": "package",
-                    "variants": [
-                        {"api_level": 12, "arch": "x64"},
-                        {"api_level": 12, "arch": "arm64"},
-                    ],
-                    "foo": "bar",
-                },
+                "atom0.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/atom0.json"),
+                    meta={
+                        "type": "package",
+                        "variants": [
+                            {"api_level": 12, "arch": "x64"},
+                            {"api_level": 12, "arch": "arm64"},
+                        ],
+                        "foo": "bar",
+                    },
+                    dest_to_src={},
+                ),
             },
-            dest_to_src={},
         )
 
         with self.assertRaises(generate_idk.AtomMergeError) as e:
-            a.merge_with(b)
+            generate_idk.MergedIDK().merge_with(a).merge_with(b)
         self.assertIn("duplicate variants", str(e.exception.__cause__))
 
     def test_merge_files(self) -> None:
-        a = generate_idk.PartialIDK(
-            atoms={},
-            dest_to_src={
-                pathlib.Path("dest/foo"): pathlib.Path("src/foo"),
-                pathlib.Path("dest/bar"): pathlib.Path("src/bar"),
+        a: generate_idk.PartialIDK = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
+            atoms={
+                "foo/bar.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/foo/bar.json"),
+                    meta={
+                        "type": "cc_source_library",
+                    },
+                    dest_to_src={
+                        pathlib.Path("dest/foo"): pathlib.Path("src/foo"),
+                        pathlib.Path("dest/bar"): pathlib.Path("src/bar"),
+                    },
+                )
             },
         )
-        b = generate_idk.PartialIDK(
-            atoms={},
-            dest_to_src={
-                pathlib.Path("dest/foo"): pathlib.Path("src/foo"),
-                pathlib.Path("dest/baz"): pathlib.Path("src/baz"),
+        b: generate_idk.PartialIDK = generate_idk.PartialIDK(
+            manifest_src="thingy.sdk",
+            atoms={
+                "foo/bar.json": generate_idk.PartialAtom(
+                    meta_src=pathlib.Path("src/foo/bar.json"),
+                    meta={
+                        "type": "cc_source_library",
+                    },
+                    dest_to_src={
+                        pathlib.Path("dest/foo"): pathlib.Path("src/foo"),
+                        pathlib.Path("dest/baz"): pathlib.Path("src/baz"),
+                    },
+                )
             },
         )
+        print(generate_idk.MergedIDK().merge_with(a))
+        print(generate_idk.MergedIDK().merge_with(a).merge_with(b))
+
         self.assertEqual(
-            a.merge_with(b),
-            generate_idk.PartialIDK(
-                atoms={},
+            generate_idk.MergedIDK().merge_with(a).merge_with(b),
+            generate_idk.MergedIDK(
+                atoms={
+                    "foo/bar.json": {
+                        "type": "cc_source_library",
+                    },
+                },
                 dest_to_src={
                     pathlib.Path("dest/foo"): pathlib.Path("src/foo"),
                     pathlib.Path("dest/bar"): pathlib.Path("src/bar"),
@@ -514,21 +633,41 @@
             file_b.write_text("foo")
 
             a = generate_idk.PartialIDK(
-                atoms={},
-                dest_to_src={
-                    pathlib.Path("dest/foo"): file_a,
+                manifest_src="thingy.sdk",
+                atoms={
+                    "foo/bar.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/bar.json"),
+                        meta={
+                            "type": "cc_source_library",
+                        },
+                        dest_to_src={
+                            pathlib.Path("dest/foo"): file_a,
+                        },
+                    ),
                 },
             )
             b = generate_idk.PartialIDK(
-                atoms={},
-                dest_to_src={
-                    pathlib.Path("dest/foo"): file_b,
+                manifest_src="thingy.sdk",
+                atoms={
+                    "foo/bar.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/bar.json"),
+                        meta={
+                            "type": "cc_source_library",
+                        },
+                        dest_to_src={
+                            pathlib.Path("dest/foo"): file_b,
+                        },
+                    ),
                 },
             )
             self.assertEqual(
-                a.merge_with(b),
-                generate_idk.PartialIDK(
-                    atoms={},
+                generate_idk.MergedIDK().merge_with(a).merge_with(b),
+                generate_idk.MergedIDK(
+                    atoms={
+                        "foo/bar.json": {
+                            "type": "cc_source_library",
+                        },
+                    },
                     dest_to_src={
                         pathlib.Path("dest/foo"): file_a,
                     },
@@ -546,20 +685,36 @@
             file_b.write_text("bar")
 
             a = generate_idk.PartialIDK(
-                atoms={},
-                dest_to_src={
-                    pathlib.Path("dest/foo"): file_a,
+                manifest_src="thingy.sdk",
+                atoms={
+                    "foo/bar.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/bar.json"),
+                        meta={
+                            "type": "cc_source_library",
+                        },
+                        dest_to_src={
+                            pathlib.Path("dest/foo"): file_a,
+                        },
+                    ),
                 },
             )
             b = generate_idk.PartialIDK(
-                atoms={},
-                dest_to_src={
-                    pathlib.Path("dest/foo"): file_b,
+                manifest_src="thingy.sdk",
+                atoms={
+                    "foo/bar.json": generate_idk.PartialAtom(
+                        meta_src=pathlib.Path("src/foo/bar.json"),
+                        meta={
+                            "type": "cc_source_library",
+                        },
+                        dest_to_src={
+                            pathlib.Path("dest/foo"): file_b,
+                        },
+                    ),
                 },
             )
 
             with self.assertRaises(AssertionError) as e:
-                a.merge_with(b)
+                generate_idk.MergedIDK().merge_with(a).merge_with(b)
             self.assertIn("Multiple non-identical files", str(e.exception))
 
 
diff --git a/build/sdk/idk.gni b/build/sdk/idk.gni
index 9af6e32..e71d1ea 100644
--- a/build/sdk/idk.gni
+++ b/build/sdk/idk.gni
@@ -180,7 +180,7 @@
       _subbuild(_subbuild_name) {
         sdk_collection = invoker.sdk_collection_label
         target_cpu = target_cpu
-        api_level = "0"  # Sentinel for "default"
+        api_level = "PLATFORM"
         extra_deps = []
 
         forward_variables_from(invoker,
@@ -264,6 +264,12 @@
       _exported_dir_stamp,
     ]
 
+    # The exported dir is fully under our control and gets deleted by every
+    # invocation of this build rule.
+    hermetic_action_ignored_prefixes = [ _exported_dir ]
+
+    depfile = "${target_gen_dir}/${target_name}.d"
+
     args = []
 
     foreach(dir, _subbuild_dirs) {
@@ -279,6 +285,8 @@
       rebase_path(_exported_dir, root_build_dir),
       "--stamp-file",
       rebase_path(_exported_dir_stamp, root_build_dir),
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
       "--host-arch",
       host_triple,
       "--release-version",
@@ -292,10 +300,6 @@
       ]
     }
 
-    # TODO(https://fxbug.dev/333054435): Generate a depfile to make this
-    # hermetic.
-    hermetic_deps = false
-
     forward_variables_from(invoker,
                            [
                              "testonly",
diff --git a/build/sdk/meta/src/product_bundle.rs b/build/sdk/meta/src/product_bundle.rs
index 6ddc890..a4e3566 100644
--- a/build/sdk/meta/src/product_bundle.rs
+++ b/build/sdk/meta/src/product_bundle.rs
@@ -253,7 +253,7 @@
 
     let mut repos = Vec::<FileSystemRepository>::new();
     for repo in pb.repositories {
-        let mut repo_builder = FileSystemRepository::builder(
+        let repo_builder = FileSystemRepository::builder(
             repo.metadata_path
                 .canonicalize()
                 .with_context(|| format!("failed to canonicalize {:?}", repo.metadata_path))?
@@ -263,10 +263,8 @@
                 .with_context(|| format!("failed to canonicalize {:?}", repo.blobs_path))?
                 .try_into()?,
         )
-        .alias(repo.name);
-        if let Some(blob_type) = repo.delivery_blob_type {
-            repo_builder = repo_builder.delivery_blob_type(blob_type.try_into()?);
-        }
+        .alias(repo.name)
+        .delivery_blob_type(repo.delivery_blob_type.try_into()?);
         repos.push(repo_builder.build());
     }
     Ok(repos)
diff --git a/build/sdk/meta/src/product_bundle/v2.rs b/build/sdk/meta/src/product_bundle/v2.rs
index 5844ac1..c52c373 100644
--- a/build/sdk/meta/src/product_bundle/v2.rs
+++ b/build/sdk/meta/src/product_bundle/v2.rs
@@ -86,12 +86,11 @@
     /// directory.
     pub blobs_path: Utf8PathBuf,
 
-    /// Specify the delivery blob type of each blob, None means the blobs are
-    /// uncompressed and not delivery blobs.
+    /// Specify the delivery blob type of each blob.
     /// This is used by the repo server, not the product bundle per se.
     /// See //src/storage/blobfs/delivery_blob.h for the list of types.
-    #[serde(default, skip_serializing_if = "Option::is_none")]
-    pub delivery_blob_type: Option<u32>,
+    #[serde(default = "default_delivery_blob_type")]
+    pub delivery_blob_type: u32,
 
     /// The path to the file containing all the root metadata private keys.
     pub root_private_key_path: Option<Utf8PathBuf>,
@@ -106,6 +105,10 @@
     pub timestamp_private_key_path: Option<Utf8PathBuf>,
 }
 
+fn default_delivery_blob_type() -> u32 {
+    1
+}
+
 impl Repository {
     /// Return the path to the targets.json file that contains a list of all the
     /// packages.
@@ -590,7 +593,7 @@
                 name: "fuchsia.com".into(),
                 metadata_path: dir.join("repository"),
                 blobs_path: dir.join("repository").join("blobs"),
-                delivery_blob_type: None,
+                delivery_blob_type: 1,
                 root_private_key_path: None,
                 targets_private_key_path: None,
                 snapshot_private_key_path: None,
@@ -627,7 +630,7 @@
                 name: "fuchsia.com".into(),
                 metadata_path: "repository".into(),
                 blobs_path: "blobs".into(),
-                delivery_blob_type: None,
+                delivery_blob_type: 1,
                 root_private_key_path: None,
                 targets_private_key_path: None,
                 snapshot_private_key_path: None,
diff --git a/build/sdk/sdk_atom.gni b/build/sdk/sdk_atom.gni
index 93005e2..971014a 100644
--- a/build/sdk/sdk_atom.gni
+++ b/build/sdk/sdk_atom.gni
@@ -239,11 +239,10 @@
     rebase_path(meta_file, root_build_dir),
   ]
 
-  # api files are only valid for the HEAD API level. When
-  # override_target_api_level is set, some of them will fail to reflect
-  # the API of the atom being built. Disallow api verification when
-  # this is the case.
-  _verify_api = defined(invoker.api) && override_target_api_level == -1
+  # api files are only valid for the PLATFORM API level. When
+  # override_target_api_level is set, some of them will fail to reflect the API
+  # of the atom being built. Disallow api verification when this is the case.
+  _verify_api = defined(invoker.api) && override_target_api_level == "PLATFORM"
 
   if (_verify_api) {
     if (defined(invoker.api_contents)) {
diff --git a/build/sdk/subbuild.py b/build/sdk/subbuild.py
index 7d526292..b42d802 100755
--- a/build/sdk/subbuild.py
+++ b/build/sdk/subbuild.py
@@ -67,7 +67,7 @@
     return 1
 
 
-def write_file_if_unchanged(path: Path, content: str) -> bool:
+def write_file_if_changed(path: Path, content: str) -> bool:
     """Write |content| into |path| if needed. Return True on write."""
     if path.exists() and path.read_text() == content:
         # Nothing to do
@@ -157,9 +157,9 @@
     )
     parser.add_argument(
         "--api-level",
-        type=int,
+        type=str,
         required=True,
-        help="API level at which to build the sdk_collection, or 0 to use the default.",
+        help="API level at which to build the sdk_collection.",
     )
     parser.add_argument("--stamp-file", help="Optional output stamp file.")
     parser.add_argument(
@@ -285,19 +285,23 @@
 
     args_gn_content += "sdk_inside_sub_build = true\n"
 
-    if api_level == 0:
-        # The host architecture is built at the default level as part of the
+    # PLATFORM should be passed to GN as a string, numeric API levels are passed
+    # as ints.
+    if api_level == "PLATFORM":
+        gn_api_level = '"PLATFORM"'
+
+        # The host architecture is built at the PLATFORM level as part of the
         # main build, so only sub-builds for other target CPU architectures
         # should reach here.
         assert f"{target_cpu}" != f"{get_host_arch()}"
     else:
-        # A non-default API level was specified.
-        args_gn_content += "sdk_inside_supported_api_sub_build = true\n"
-        args_gn_content += f"override_target_api_level = {api_level}\n"
+        gn_api_level = int(api_level)
+
+    args_gn_content += f"override_target_api_level = {gn_api_level}\n"
 
     log(f"{build_dir}: args.gn content:\n{args_gn_content}")
     if (
-        write_file_if_unchanged(build_dir / "args.gn", args_gn_content)
+        write_file_if_changed(build_dir / "args.gn", args_gn_content)
         or not (build_dir / "build.ninja").exists()
     ):
         if run_checked_command(
@@ -311,15 +315,16 @@
         ):
             return 1
 
+    # Touch the sentinel file in the build directory to force any non-hermetic
+    # build rules to rebuild.
+    (build_dir / "force_nonhermetic_rebuild").touch()
+
     # Adjust the NINJA_STATUS environment variable before launching Ninja
     # in order to add a prefix distinguishing its build actions from
     # the top-level ones.
     ninja_status = os.environ.get("NINJA_STATUS", "[%f/%t](%r) ")
 
-    if api_level == 0:
-        status_prefix = f"IDK_SUBBUILD_{target_cpu} "
-    else:
-        status_prefix = f"IDK_SUBBUILD_api{api_level}-{target_cpu} "
+    status_prefix = f"IDK_SUBBUILD_api_{api_level}_{target_cpu} "
     ninja_status = status_prefix + ninja_status
     ninja_env = {"NINJA_STATUS": ninja_status}
 
diff --git a/build/testing/BUILD.gn b/build/testing/BUILD.gn
index 612182d..f42dacd 100644
--- a/build/testing/BUILD.gn
+++ b/build/testing/BUILD.gn
@@ -35,7 +35,6 @@
         config_type = "none"
       }
       storage = {
-        configure_fshost = true
         filesystems = invoker.filesystems
       }
       development_support = {
diff --git a/build/testing/boot_tests/boot_test.gni b/build/testing/boot_tests/boot_test.gni
index 1312cbf..b5dfdde 100644
--- a/build/testing/boot_tests/boot_test.gni
+++ b/build/testing/boot_tests/boot_test.gni
@@ -22,6 +22,10 @@
 boot_test_success_string =
     "***Boot-test-successful!-MDd7/O65SuVZ23yGAaQG4CedYQGH9E1/58r73pSAVK0=***"
 
+# The default timeout for boot tests, which is also the bootup timeout for
+# cuckoo tests.
+default_boot_test_timeout_secs = 600
+
 _all_emu_types = [
   "QEMU",
   "AEMU",
@@ -52,7 +56,7 @@
   toolchain = "//build/toolchain:host_${invoker.cpu_for_host}"
   test_script = "$root_out_dir/$main_target.sh"
 
-  timeout_secs = 600
+  timeout_secs = default_boot_test_timeout_secs
   if (defined(invoker.timeout)) {
     if (invoker.timeout != false) {
       timeout_secs = invoker.timeout
diff --git a/build/testing/boot_tests/kernel_zbi_test.gni b/build/testing/boot_tests/kernel_zbi_test.gni
index 312338c..bbdb971 100644
--- a/build/testing/boot_tests/kernel_zbi_test.gni
+++ b/build/testing/boot_tests/kernel_zbi_test.gni
@@ -26,9 +26,7 @@
   # packages, core realm shards, etc.
   input_groups = [
     "bootstrap",
-    "legacy",
     "network",
-    "debug",
     "test",
   ]
 }
@@ -63,6 +61,11 @@
       environments = target_environments
       isolated = true
       product_bundle = main_target
+
+      bootup_timeout_secs = default_boot_test_timeout_secs
+      if (defined(invoker.timeout)) {
+        bootup_timeout_secs = invoker.timeout
+      }
     }
   }
 
@@ -199,7 +202,11 @@
     cuckoo_target_name = "${target_name}.cuckoo"
     if (default_toolchain == current_toolchain) {
       _cuckoo_product_bundle(cuckoo_target_name) {
-        forward_variables_from(invoker, [ "disabled" ])
+        forward_variables_from(invoker,
+                               [
+                                 "disabled",
+                                 "timeout",
+                               ])
         kernel_zbi = ":$main_target.zbi"
         kernel_image_name = "$main_target"
       }
diff --git a/build/testing/test_spec.gni b/build/testing/test_spec.gni
index 4f59693..fc48f6b 100644
--- a/build/testing/test_spec.gni
+++ b/build/testing/test_spec.gni
@@ -152,7 +152,13 @@
 #     [string] The name of a product bundle describing the system against which
 #     the test should be run (describing the test itself in the case of boot
 #     tests). Associated product bundle artifacts can be looked up with this
-#     name in the product bundle build API module.
+#     name in the product bundle build API module. This value is only respected
+#     when `isolated` is true.
+#
+#   bootup_timeout_secs (optional)
+#     [int] The timeout in seconds the test expects the provided product_bundle
+#     and environment it's run against will take to boot up. This value is only
+#     respected when `isolated` is true.
 #
 #   environments (optional, default: Emu for fuchsia; else a VM)
 #     [list of scopes] Device environments in which the test should run.
@@ -411,7 +417,11 @@
   }
 
   test_spec = {
-    forward_variables_from(invoker, [ "product_bundle" ])
+    forward_variables_from(invoker,
+                           [
+                             "product_bundle",
+                             "bootup_timeout_secs",
+                           ])
     test = {
       forward_variables_from(invoker,
                              [
@@ -429,6 +439,12 @@
                                "build_rule",
                                "has_generated_manifest",
                              ])
+      if (!defined(isolated) || !isolated) {
+        assert(!defined(product_bundle),
+               "product_bundle is only respected if isolated=true.")
+        assert(!defined(bootup_timeout_secs),
+               "bootup_timeout_secs is only respected if isolated=true.")
+      }
       if (defined(_parallel)) {
         parallel = _parallel
       }
diff --git a/build/toolchain/clang_toolchain.gni b/build/toolchain/clang_toolchain.gni
index b6ef94b..c6c4d38 100644
--- a/build/toolchain/clang_toolchain.gni
+++ b/build/toolchain/clang_toolchain.gni
@@ -151,8 +151,9 @@
         _cxx_concurrent_jobs = concurrent_jobs.local
       } else {
         compiler_prefix_list += RBE_EXEC_STRATEGY_MAP[cxx_rbe_exec_strategy]
-        if (!cxx_rbe_download_obj_files) {
-          compiler_prefix_list += [ "--download_outputs=false" ]
+        if (!cxx_rbe_download_obj_files) {  # download everything except the
+                                            # object file
+          compiler_prefix_list += [ "--download_regex='-.*\\.o\$\$'" ]
         }
         _cxx_concurrent_jobs = concurrent_jobs.remote
       }
@@ -857,12 +858,12 @@
           not_needed([ "rmeta" ])
         }
         command += " --crate-type {{crate_type}} --emit=dep-info=$depfile,link$extra_emit_opts -Zdep-info-omit-d-target {{rustflags}}"
-        if (!rust_rbe_download_rlibs) {
+        if (!rust_rbe_download_rlibs) {  # download everything except the rlib
           command += " --remote-flag=--download_outputs=false"
         }
         command += " -o $rlib"
         if (rustc_use_response_files) {
-          rspfile = "{{output}}.rsp"
+          rspfile = "$rlib.rsp"
           rspfile_content = "{{rustdeps}} {{externs}}"
           command += " -Zshell-argfiles @shell:" + rspfile
         } else {
@@ -980,7 +981,7 @@
         command += " --crate-type {{crate_type}} --emit=dep-info=$depfile,link{{EMIT_RMETA}} -Zdep-info-omit-d-target {{rustflags}}"
         command += " -o $_main_output --extern proc_macro"
         if (rustc_use_response_files) {
-          rspfile = "{{output}}.rsp"
+          rspfile = "$_main_output.rsp"
           rspfile_content = "{{rustdeps}} {{externs}}"
           command += " -Zshell-argfiles @shell:" + rspfile
         } else {
diff --git a/build/toolchain/default_concurrent_jobs.gni b/build/toolchain/default_concurrent_jobs.gni
index 8d3414f..9e935d5 100644
--- a/build/toolchain/default_concurrent_jobs.gni
+++ b/build/toolchain/default_concurrent_jobs.gni
@@ -6,8 +6,6 @@
     current_toolchain == default_toolchain,
     "This should only be imported in the default_toolchain, beause the pools it is used with MUST only be defined once for the entire build.")
 
-import("//build/config/lto/config.gni")
-
 _script = "get_concurrent_jobs.py"
 _args = [
   "-S",  # https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=62771
@@ -15,26 +13,10 @@
   "--reserve-memory=1GB",
 ]
 
-if (use_lto) {
-  # As per logic in //build/config/lto/config.gni, only use thinlto
-  # if lto is set
-  if (use_thinlto) {
-    _args += [
-      "--memory-per-job",
-      "local=16GB",
-    ]
-  } else {
-    _args += [
-      "--memory-per-job",
-      "local=32GB",
-    ]
-  }
-} else {
-  # No lto
-  _args += [
-    "--memory-per-job",
-    "local=1GB",
-  ]
-}
+_args += [
+  "--memory-per-job",
+  "local=1GB",
+]
+
 default_concurrent_jobs =
     exec_script(python_exe_src, _args, "json", [ _script ])
diff --git a/build/toolchain/rbe.gni b/build/toolchain/rbe.gni
index 7693da30..fb08614da 100644
--- a/build/toolchain/rbe.gni
+++ b/build/toolchain/rbe.gni
@@ -128,7 +128,8 @@
   # Set to true to emit additional .rmeta files when compiling Rust rlibs.
   # The .rmeta metadata files can be used by downstream build actions
   # to quickly evaluate transitive dependencies (and remote inputs).
-  rust_emit_rmeta = false
+  # This is required to support skipping downloads of rlibs.
+  rust_emit_rmeta = true
 
   # TODO(b/42084033): Controls whether or not to download (intermediate)
   # rlibs from remote Rust build actions.
diff --git a/build/toolchain/toolchain_tags.gni b/build/toolchain/toolchain_tags.gni
index 0c95b34..7b14fb7 100644
--- a/build/toolchain/toolchain_tags.gni
+++ b/build/toolchain/toolchain_tags.gni
@@ -27,6 +27,9 @@
   # This indicates a toolchain does not provide the Fuchsia Compiler ABI.
   "no-compiler-abi",
 
+  # This indicates a toolchain offers no floating point support.
+  "no-floating-point",
+
   # This tag is used by Zircon toolchains that generate static PIE executable
   # binaries.
   "static-pie",
diff --git a/build/toolchain/zircon/BUILD.gn b/build/toolchain/zircon/BUILD.gn
index 5b76666..777656f 100644
--- a/build/toolchain/zircon/BUILD.gn
+++ b/build/toolchain/zircon/BUILD.gn
@@ -26,6 +26,7 @@
 
       tags = [
         "no-compiler-abi",
+        "no-floating-point",
         "standalone",
       ]
       exclude_variant_tags = [ "needs-compiler-abi" ]
diff --git a/build/toolchain/zircon/zircon_toolchain.gni b/build/toolchain/zircon/zircon_toolchain.gni
index 8b90a37..484cef0 100644
--- a/build/toolchain/zircon/zircon_toolchain.gni
+++ b/build/toolchain/zircon/zircon_toolchain.gni
@@ -259,7 +259,8 @@
     } else {
       compiler_prefix_list += RBE_EXEC_STRATEGY_MAP[cxx_rbe_exec_strategy]
       if (!cxx_rbe_download_obj_files) {
-        compiler_prefix_list += [ "--download_outputs=false" ]
+        # download everything except the object file
+        compiler_prefix_list += [ "--download_regex='-.*\\.o\$\$'" ]
       }
       _cxx_concurrent_jobs = concurrent_jobs.remote
     }
@@ -874,7 +875,8 @@
     # are very distinct.
 
     _zircon_optimize = zircon_optimize
-    if (optimize == "sanitizer" || optimize == "profile") {
+    if (optimize == "sanitizer" || optimize == "profile" ||
+        optimize == "size_lto") {
       _zircon_optimize = optimize
     }
 
diff --git a/build/zircon/zx_library.gni b/build/zircon/zx_library.gni
index e0d6dcc..81c2086 100644
--- a/build/zircon/zx_library.gni
+++ b/build/zircon/zx_library.gni
@@ -18,7 +18,7 @@
 #
 # * When building with a Zircon-specific toolchain, it will create a source_set()
 #   if the global `is_kernel` is true (meaning building part of the kernel), or
-#   a static_library() target otherwise. Teh values of `sdk`, `sdk_publishable`
+#   a static_library() target otherwise. The values of `sdk`, `sdk_publishable`
 #   and `sdk_headers` will be ignored entirely.
 #
 #   This will also create a :headers sub-target, a group used to give access
@@ -30,10 +30,12 @@
 #
 # * When not using a Zircon-specific toolchain, which means the library is built
 #   either as a Fuchsia user binary or a host binary, `sdk` must be set to determine
-#   the shape of the library, as well as `sdk_headers to list the library's public
+#   the shape of the library, as must `sdk_headers to list the library's public
 #   headers, relative to its `include` sub-directory.
 #
-#   If `sdk_publishable` is true, the library will be part of the Fuchsia SDK.
+#   If `sdk_publishable` is present, an sdk_*() template will be used, enabling
+#   the library to be part of the Fuchsia SDK. The value of `sdk_publishable`
+#   must be a valid SDK category.
 #
 #   Any :headers sub-targets that appear in public_deps will be rewritten into
 #   a dependency to the library itself, e.g.:
@@ -54,17 +56,15 @@
 #     source set, static library or shared library with the Fuchsia build.
 #     This is required, except when building with Zircon-specific toolchains.
 #     Note that this name is confusing for historical reasons, because using
-#     this parameter does not make this library exported to the Fuchsia SDK
-#     (see `sdk_publishable` below for this).
-#     Type: "static" or "shared" or "source"
+#     this parameter does not alone make this library exported to the Fuchsia
+#     SDK (see `sdk_publishable` below for this).
+#     TODO(https://fxbug.dev/333125197): Rename this parameter.
+#     Values: "static" or "shared" or "source"
 #
 #   sdk_publishable
-#     Optional: Indicates that this library can be added to the Fuchsia SDK.
-#     When false, the library is not added to the SDK. When true, it is added
-#     to the SDK with a "partner" category. Otherwise, a string value may be
-#     used to specify another category (e.g. `sdk_publishable` = "cts"`).
-#     Type: bool, or a string indicating an SDK category.
-#     Default: false
+#     Optional: Indicates that this library can be added to the Fuchsia SDK
+#     and in which SDK category.
+#     Type: string indicating an SDK category.
 #
 #   sdk_area (optional)
 #     [string] The API area responsible for maintaining this library.
@@ -95,6 +95,10 @@
     "sdk_publishable",
   ]
 
+  # TODO(https://fxbug.dev/333125197): Move this such that it is only applied
+  # when needed and does not silently ignore parameters that will never be used
+  # (i.e., for non-sdkable targets). Update the documentation above to indicate
+  # when it is supported.
   not_needed(invoker,
              [
                "sdk_name",
@@ -167,14 +171,12 @@
         "The `sdk` argument is needed to build a zx_library() with a Fuchsia or host toolchain ($current_toolchain)")
     shape = invoker.sdk
 
-    sdkable =
-        defined(invoker.sdk_publishable) && invoker.sdk_publishable != false
+    sdkable = defined(invoker.sdk_publishable)
     if (sdkable) {
-      if (invoker.sdk_publishable == true) {
-        sdk_category = "partner"
-      } else {
-        sdk_category = invoker.sdk_publishable
-      }
+      assert(
+          invoker.sdk_publishable == "${invoker.sdk_publishable}",
+          "Must be an SDK category name if specified - received: ${invoker.sdk_publishable}")
+      sdk_category = invoker.sdk_publishable
     }
 
     extra_target_args = {
diff --git a/bundles/assembly/BUILD.gn b/bundles/assembly/BUILD.gn
index 8649074..591fdc4 100644
--- a/bundles/assembly/BUILD.gn
+++ b/bundles/assembly/BUILD.gn
@@ -105,7 +105,6 @@
   bootfs_packages = [
     "//src/bringup/bin/critical-services:package",
     "//src/bringup/bin/device-name-provider:package",
-    "//src/bringup/bin/paver:package",
     "//src/bringup/bin/sysinfo:package",
     "//src/devices/sysmem/bin/sysmem_connector:pkg",
     "//src/diagnostics/archivist:package",
@@ -392,6 +391,7 @@
     "//src/diagnostics/iquery:bootfs",
     "//src/media/audio/tools/audio-driver-ctl:bootfs",
     "//src/security/bin/syscall-check:bootfs",
+    "//src/sys/tools/package:bootfs",
     "//src/ui/backlight/bin/backlight:bootfs",
     "//src/ui/input/bin/hid:bootfs",
 
@@ -446,6 +446,11 @@
   ]
 }
 
+# Legacy AIB for migration purposes.
+assembly_input_bundle("paver_legacy") {
+  bootfs_packages = [ "//src/bringup/bin/paver:package" ]
+}
+
 # The console AIB is included by all eng and userdebug products.
 #
 assembly_input_bundle("console_userdebug") {
@@ -1009,20 +1014,21 @@
     },
   ]
 
-  # Included with //bundles/tools.
+  # wlancfg's donut tool.
+  on_demand = [ "//src/connectivity/wlan/wlancfg/tool:donut" ]
   shell_commands += [
     {
-      package = "sched"
-      components = [ "sched" ]
+      package = "donut"
+      components = [ "donut" ]
     },
-    {
-      package = "cowsay"
-      components = [ "cowsay" ]
-    },
-    {
-      package = "hwstress-cli"
-      components = [ "hwstress" ]
-    },
+  ]
+
+  # Moved here from //bundles/packages/prod:cmdutils
+  on_demand += [
+    "//src/zircon/bin/time",
+    "//src/zircon/bin/uname",
+  ]
+  shell_commands += [
     {
       package = "time"
       components = [ "time" ]
@@ -1031,6 +1037,14 @@
       package = "uname"
       components = [ "uname" ]
     },
+  ]
+
+  # Included with //bundles/tools.
+  shell_commands += [
+    {
+      package = "sched"
+      components = [ "sched" ]
+    },
     {
       package = "far"
       components = [ "far" ]
@@ -1075,10 +1089,7 @@
       package = "net-cli"
       components = [ "net" ]
     },
-    {
-      package = "donut"
-      components = [ "donut" ]
-    },
+
     {
       package = "dai-info"
       components = [ "dai-info" ]
@@ -1197,18 +1208,46 @@
     },
   ]
 
-  # Document the sbase shell commands in the on-demand package set (these are
-  # not added to the product image).
+  # Other manually-included shell commands
+  shell_commands += [
+    {
+      package = "cowsay"
+      components = [ "cowsay" ]
+    },
+    {
+      package = "hwstress-cli"
+      components = [ "hwstress" ]
+    },
+  ]
+
+  # Add the sbase binaries, some of which are in base, but most are in the
+  # on_demand package set.
+  _sbase_bins_in_base = [
+    # Always include 'ls'
+    "ls",
+
+    # This is used by Chromium test infrastructure, and needs to always be
+    # available.
+    "sha1sum",
+  ]
   on_demand = []
   foreach(bin, sbase_binaries) {
-    # To be enabled soon, but will cause errors in assembly.
-    # on_demand += [ "//third_party/sbase:${bin}_pkg" ]
+    # Always create the shell_commands entry.
     shell_commands += [
       {
         package = bin
         components = [ bin ]
       },
     ]
+
+    # Add to the base package set if it's in the _sbase_bins_in_base list,
+    # otherwise add it to on_demand
+    _sbase_target = "//third_party/sbase:${bin}_pkg"
+    if (_sbase_bins_in_base != _sbase_bins_in_base + [ bin ] - [ bin ]) {
+      base_packages += [ _sbase_target ]
+    } else {
+      on_demand += [ _sbase_target ]
+    }
   }
 
   compiled_packages = [
@@ -1634,10 +1673,6 @@
                     "//src/sys/cache_manager/meta/cache_manager.core_shard.cml",
                     "//src/sys/pkg/bin/system-updater/meta/system_updater.core_shard.cml",
                     "//src/recovery/factory_reset/meta/factory_reset.core_shard.cml",
-
-                    # TODO(https://fxbug.dev/42160712): only include in eng builds
-                    "//src/sys/test_manager/meta/test_manager.core_shard.cml",
-                    "//src/sys/testing/meta/test_realm.core_shard.cml",
                   ],
                   root_build_dir)
         },
@@ -1883,27 +1918,10 @@
 assembly_input_bundle("input_group_one") {
   kernel_cmdline = [ "kernel.oom.behavior=reboot" ]
   base_packages = [ "//src/sys/cache_manager" ]
-  compiled_packages = [
-    {
-      name = "core"
-      component_shards = [
-        {
-          component_name = "core"
-          shards = rebase_path(
-                  [
-                    # TODO(https://fxbug.dev/42160712): only include in eng builds
-                    "//src/sys/fuzzing/meta/fuzzing.core-shard.cml",
-                  ],
-                  root_build_dir)
-        },
-      ]
-    },
-  ]
 }
 
 assembly_input_bundle("input_group_two") {
   kernel_cmdline = [ "kernel.render-dlog-to-crashlog=true" ]
-  base_packages = [ "//src/session/bin/session_manager" ]
   flexible_packages = [
     "//src/connectivity/location/emergency",
     "//src/media/sessions:mediasession",
@@ -2250,14 +2268,9 @@
           shards = rebase_path(
                   [
                     "//src/performance/experimental/profiler/meta/profiler.core_shard.cml",
-                    # These should only be added by this AIB, because their
-                    # packages are only added by this AIB, however due to many
-                    # routing issues, they are included in a wider set of
-                    # assemblies than just those that include "testing_support"
-                    #
-                    # "//src/sys/test_manager/meta/test_manager.core_shard.cml",
-                    # "//src/sys/fuzzing/meta/fuzzing.core-shard.cml",
-                    # "//src/sys/testing/meta/test_realm.core_shard.cml",
+                    "//src/sys/test_manager/meta/test_manager.core_shard.cml",
+                    "//src/sys/fuzzing/meta/fuzzing.core-shard.cml",
+                    "//src/sys/testing/meta/test_realm.core_shard.cml",
                   ],
                   root_build_dir)
         },
@@ -3719,12 +3732,6 @@
   deps = qemu_boot_shim.deps
 }
 
-# Enabling a soft-transition, remove when complete
-# TODO(122864) Remove transitional labels
-group("third_party_sbase_for_transition") {
-  public_deps = [ "//third_party/sbase:sbase-pkgs" ]
-}
-
 # Assembly may select at most one bundle with `intl_services` name prefix.
 icu_assembly_input_bundle("intl_services") {
   icu_base_packages = [ "//src/intl/intl_services:pkg" ]
@@ -3909,6 +3916,12 @@
   kernel_cmdline = [ "kernel.page-scanner.lru-action=compress_only" ]
 }
 
+# Performs eviction continuously while under memory pressure instead of only once when the pressure
+# level changes.
+assembly_input_bundle("kernel_evict_continuous") {
+  kernel_cmdline = [ "kernel.oom.evict-continuous=true" ]
+}
+
 # Assembly selects whether to include this AIB or not.
 assembly_input_bundle("zoneinfo") {
   base_packages = [ "//src/intl/tzdata_provider:zoneinfo_provider_pkg" ]
diff --git a/bundles/assembly/platform_aib_names.bzl b/bundles/assembly/platform_aib_names.bzl
index 057cd3e..0896771 100644
--- a/bundles/assembly/platform_aib_names.bzl
+++ b/bundles/assembly/platform_aib_names.bzl
@@ -26,11 +26,13 @@
     "paravirtualization_support",
     "kernel_anonymous_memory_compression",
     "kernel_anonymous_memory_compression_eager_lru",
+    "kernel_evict_continuous",
     "kernel_contiguous_physical_pages",
     "kernel_args_user",
     "kernel_debug_broker_user",
     "legacy_power_framework",
     "live_usb",
+    "paver_legacy",
     "resources",
     "virtcon",
     "virtcon_disable",
diff --git a/bundles/assembly/platform_aibs.gni b/bundles/assembly/platform_aibs.gni
index 2987705..bef21b9 100644
--- a/bundles/assembly/platform_aibs.gni
+++ b/bundles/assembly/platform_aibs.gni
@@ -57,6 +57,7 @@
   "fshost_fvm_minfs",
   "fshost_fvm_minfs_migration",
   "fshost_storage",
+  "paver_legacy",
 
   # SWD (Software Delivery)
   "no_update_checker",
@@ -233,9 +234,10 @@
       "feedback_user_config",
       "feedback_userdebug_config",
 
-      # Kernel Compression
+      # Kernel Reclamation
       "kernel_anonymous_memory_compression",
       "kernel_anonymous_memory_compression_eager_lru",
+      "kernel_evict_continuous",
 
       # Recovery
       "factory_reset_trigger",
diff --git a/bundles/assembly_input_groups/BUILD.gn b/bundles/assembly_input_groups/BUILD.gn
index 9ba8c1d..ff7a3f3 100644
--- a/bundles/assembly_input_groups/BUILD.gn
+++ b/bundles/assembly_input_groups/BUILD.gn
@@ -20,27 +20,11 @@
   cmdline_deps = [ ":userboot.next-component-manager" ]
 }
 
-assembly_input_groups("legacy") {
-  visibility = [ "*" ]
-  base_packages = []
-}
-
 assembly_input_groups("network") {
   visibility = [ "*" ]
   base_packages = [ "//src/connectivity/network:for_transition" ]
 }
 
-assembly_input_groups("debug") {
-  visibility = [ "*" ]
-  base_packages = [
-    "//bundles/assembly:third_party_sbase_for_transition",
-    "//src/connectivity/wlan/wlancfg/tool:for_transition",
-    "//src/factory/factory_store_providers",
-  ]
-  core_realm_shards =
-      [ "//src/factory/factory_store_providers:factory_store_providers_shard" ]
-}
-
 assembly_input_groups("test") {
   visibility = [ "*" ]
 
diff --git a/bundles/packages/prod/BUILD.gn b/bundles/packages/prod/BUILD.gn
index 49e0b8a..90e0118 100644
--- a/bundles/packages/prod/BUILD.gn
+++ b/bundles/packages/prod/BUILD.gn
@@ -36,7 +36,6 @@
     "//src/fonts",
     "//src/power:battery",
     "//src/zircon/bin/hwstress",
-    "//third_party/sbase:sbase-pkgs",
   ]
 }
 
@@ -91,13 +90,7 @@
 
 group("cmdutils") {
   testonly = true
-  public_deps = [
-    "//examples/cowsay",
-    "//src/zircon/bin/hwstress",
-    "//src/zircon/bin/time",
-    "//src/zircon/bin/uname",
-    "//third_party/sbase:sbase-pkgs",
-  ]
+  public_deps = []
 }
 
 group("cobalt_client") {
diff --git a/docs/contribute/contributing-to-fidl/fidl-project-checklist.md b/docs/contribute/contributing-to-fidl/fidl-project-checklist.md
index c2db44b..f8074a3 100644
--- a/docs/contribute/contributing-to-fidl/fidl-project-checklist.md
+++ b/docs/contribute/contributing-to-fidl/fidl-project-checklist.md
@@ -46,8 +46,8 @@
     making a modification to tables, or create a new test file.
 
 It is expected for changes to FIDL which cascade to backends to update all
-Fuchsia FIDL team owned bindings, i.e. Rust, Go, Dart, HLCPP, New C++ (includes
-natural and wire APIs; the wire APIs were called LLCPP).
+Fuchsia FIDL team owned bindings, i.e. Rust, Go, Dart, HLCPP, New C++ (natural
+and wire).
 
 ## Changes to the JSON IR
 
@@ -75,7 +75,7 @@
 * Update any relevant guides:
   * [FIDL API rubric][api-rubric] for guidance on using this feature.
   * For example, when changing the memory allocation APIs in C++ wire types, the
-    [C++ wire domain object memory ownership guide][llcpp-allocators] should be
+    [C++ wire domain object memory ownership guide][cpp-allocators] should be
     updated.
   * We've also found it good practice to present to API Council in order to
     socialize new features, and explain to council members how to review APIs in
@@ -141,7 +141,7 @@
 [go-example]: /examples/fidl/go/fidl_packages/fidl_test.go
 [ldmsg]: /zircon/system/ulib/ldmsg/ldmsg.c
 [lexicon]: /docs/reference/fidl/language/lexicon.md
-[llcpp-allocators]: /docs/development/languages/fidl/tutorials/cpp/topics/wire-memory-ownership.md
+[cpp-allocators]: /docs/development/languages/fidl/tutorials/cpp/topics/wire-memory-ownership.md
 [measure-tape]: /tools/fidl/measure-tape
 [RELRO]: https://www.redhat.com/en/blog/hardening-elf-binaries-using-relocation-read-only-relro
 [sanitizer-abi]: /zircon/system/ulib/ldmsg/BUILD.gn
diff --git a/docs/contribute/contributing-to-netstack/netstack3.md b/docs/contribute/contributing-to-netstack/netstack3.md
index 1c83707..42818b7 100644
--- a/docs/contribute/contributing-to-netstack/netstack3.md
+++ b/docs/contribute/contributing-to-netstack/netstack3.md
@@ -37,8 +37,8 @@
 * Generate a `Cargo.toml` file to enable development with `cargo` by running `fx
   build build/rust:cargo_toml_gen` followed by `fx gen-cargo
   //src/connectivity/network/netstack3/core:netstack3-core`.
-* Add the following lines to your `~/.cargo/config` file, replacing the absolute
-  path to your Fuchsia directory and replacing the target if your local
+* Add the following lines to your `~/.cargo/config.toml` file, replacing the
+  absolute path to your Fuchsia directory and replacing the target if your local
   development target is different than `x86_64-unknown-linux-gnu`:
 
   ```toml
diff --git a/docs/contribute/governance/areas/_areas.yaml b/docs/contribute/governance/areas/_areas.yaml
index 0c822d3..c1a27fc 100644
--- a/docs/contribute/governance/areas/_areas.yaml
+++ b/docs/contribute/governance/areas/_areas.yaml
@@ -406,6 +406,19 @@
       </li>
     </ul>
 
+- name: 'Testing'
+  api_primary: 'crjohns@google.com'
+  api_secondary: ''
+  description: |
+    The set of APIs responsible for executing, observing, and returning the results
+    of tests executed on a device. These APIs abstract over different
+    test frameworks and tools to provide a FIDL interface for testing use cases
+    on Fuchsia.
+  examples:
+    - fidl: 'fuchsia.test.manager'
+    - fidl: 'fuchsia.test'
+    - fidl: 'fuchsia.debugdata'
+
 - name: 'Toolchain'
   api_primary: 'mcgrathr@google.com'
   api_secondary: ''
diff --git a/docs/contribute/governance/rfcs/0241_explicit_platform_external.md b/docs/contribute/governance/rfcs/0241_explicit_platform_external.md
new file mode 100644
index 0000000..42e18c5
--- /dev/null
+++ b/docs/contribute/governance/rfcs/0241_explicit_platform_external.md
@@ -0,0 +1,405 @@
+<!-- mdformat off(templates not supported) -->
+{% set rfcid = "RFC-0241" %}
+{% include "docs/contribute/governance/rfcs/_common/_rfc_header.md" %}
+# {{ rfc.name }}: {{ rfc.title }}
+{# Fuchsia RFCs use templates to display various fields from _rfcs.yaml. View the #}
+{# fully rendered RFCs at /docs/contribute/governance/rfcs #}
+<!-- SET the `rfcid` VAR ABOVE. DO NOT EDIT ANYTHING ELSE ABOVE THIS LINE. -->
+
+<!-- mdformat on -->
+
+<!-- This should begin with an H2 element (for example, ## Summary).-->
+
+## Summary
+
+The Fuchsia IDK doesn't specify whether external components should implement
+clients or servers for the various FIDL protocols that it defines. This makes it
+difficult to correctly evaluate the backwards compatibility implications of
+changes to Fuchsia APIs. This RFC proposes a way to express that information in
+a both human and machine readable way in FIDL. This unlocks opportunities to
+improve the correctness and stability of Fuchsia-based products.
+
+## Motivation
+
+Much of the [Fuchsia System Interface][fuchsia-system-interface] is expressed in
+[FIDL][fidl-language] as a set of [protocols][fidl-protocols] and the types that
+are exchanged over those protocols. Protocols are asymmetric with a client-end
+and a server-end, but the FIDL declarations that are supplied as part of the
+SDK/IDK don't specify whether the interface presented by the Fuchsia Platform to
+external components provided by products are for the server side, the client
+side or both sides of these protocols.
+
+This lack of preciseness significantly constrains the kinds of changes that can
+be made safely to the Fuchsia System Interface without knowledge of the
+implementation of the Fuchsia Platform, and often external components. In
+practice, most protocols will either have only servers or only clients
+implemented within the Fuchsia Platform, but this information isn't expressed in
+a way that can be checked by tools or discovered by end developers.
+
+For example, if a type that is part of the system interface contains a
+`string:100` (a string that takes at most 100 bytes when encoded in UTF-8) and
+later we realize that we need to support longer strings. If that type is only
+ever sent from external components to platform components (in protocol method
+requests) then the length constraint can be safely increased, because the
+component decoding a message containing that string will always be at least as
+new as the component encoding it. If that type may be sent from platform
+components to external components then the length can't be increased safely
+because a component built against a newer API level in the platform might
+inadvertently send malformed messages to external components.
+
+## Stakeholders
+
+Who has a stake in whether this RFC is accepted?
+
+_Facilitator:_
+
+The person appointed by FEC to shepherd this RFC through the RFC
+process.
+
+_Reviewers:_
+
+- abarth@google.com
+- chaselatta@google.com
+- hjfreyer@google.com
+
+_Consulted:_
+
+- aaronwood@google.com
+- awolter@google.com
+- crjohns@google.com
+- mkember@google.com
+- pesk@google.com
+- surajmalhotra@google.com
+- wittrock@google.com
+
+_Socialization:_
+
+Circulated a 1-pager describing the problem and proposal amongst people working
+on platform versioning.
+
+## Requirements
+
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
+"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
+interpreted as described in
+[IETF RFC 2119](https://tools.ietf.org/html/rfc2119).
+
+We MUST be able to express which system interface protocols MAY have their
+clients or servers or both implemented in platform or external components. This
+information MUST be expressed in a way that is accessible to tools that evaluate
+platform changes for compatibility.
+
+This information SHOULD be available to tools that run at software assembly time
+and MAY be available to the component framework at runtime. This information
+SHOULD be made visible to end-developers through generated API documentation and
+build-time checks.
+
+For this information to be useful in evaluating compatibility between the
+Fuchsia platform and components built upon it, external components MUST be built
+against a stable API level that is supported by the platform.
+
+## Design
+
+### Analysis
+
+Compatibility of the platform ABI surface as a whole can be broken down into
+considering the compatibility of individual types exchanged between external
+components and platform components, both in protocols over channels and
+[serialized][fidl-at-rest] and exchanged out of band.
+
+All exchange of FIDL data between components is rooted in in one of:
+
+ - FIDL protocols that are exchanged through [component
+   framework][component-framework] protocol capabilities. These are marked with
+   the `@discoverable` attribute.
+ - FIDL protocols that are exchanged through non-FIDL means such as [process
+   args][processargs],
+ - FIDL types that are [serialized][fidl-at-rest] and exchanged in files (like
+   component manifests) or bespoke IPC transports.
+
+Given a view of the whole Fuchsia System Interface FIDL we can, for each root,
+collect the set of types that may be sent from clients to servers and from
+servers to clients.
+
+
+#### Protocols
+
+If we know, for each "root" protocol, whether its clients and servers may be
+implemented in external components or platform components, we can collect the
+set of types that may be sent from external components to platform components,
+from platform components to external components, between platform components and
+between external components.
+
+For the protocol:
+
+```fidl
+@discoverable
+protocol {
+    M(Req) -> (Resp);
+}
+```
+
+Given where we allow clients and servers to be implemented we can see where
+types in a request (**Req**) vs response (**Resp**) may flow between external
+components (**E**) and platform components (**P**):
+
+| Client | Server | E to P    | P to E    | P to P    | E to E    |
+| ------ | ------ | --------- | --------- | --------- | --------- |
+| E      | E      |           |           |           | Req, Resp |
+| E      | P      | Req       | Resp      |           |           |
+| E      | P, E   | Req       | Resp      |           | Req, Resp |
+| P      | E      | Resp      | Req       |           |           |
+| P      | P, E   | Resp      | Req       | Req, Resp |           |
+| P, E   | E      | Resp      | Req       |           | Req, Resp |
+| P, E   | P      | Req       | Resp      | Req, Resp |           |
+| P, E   | P, E   | Req, Resp | Req, Resp | Req, Resp | Req, Resp |
+
+Platform code is guaranteed to speak a superset of the protocol versions spoken
+by external code, so we can say the following about whether type constraints can
+be tightened or loosened:
+
+| Sender   | Receiver | Constraints   |
+| -------- | -------- | ------------- |
+| external | platform | can't tighten |
+| platform | external | can't loosen  |
+| external | external | can't change  |
+
+So we need to be able to constrain where we allow clients and servers to be
+implemented.
+
+*Almost* all protocols that are roots are exchanged through component framework
+capabilities. Those that aren't are low-level and esoteric. They include
+`fuchsia.io.Directory` and a few network socket control channel protocols in
+`fuchsia.posix.socket`. Instead of inventing a new way to mark these protocols
+as roots of communication we should extend the meaning of `@discoverable` to
+incorporate these protocols. In fact there are constants in
+`fuchsia.posix.socket` for the names of socket control protocols that will be
+automatically generated once they're marked as `@discoverable`.
+
+#### Types
+
+Currently any component (external or platform) code can serialize or deserialize
+any non-resource type from raw bytes. To allow compatibility tools to know which
+FIDL types _won't_ be serialized or deserialized in some contexts we should
+explicitly mark types that are passed between components outside of normal FIDL
+IPC.
+
+### Syntax
+
+#### Protocols
+
+The discoverable attribute will be extended to express where discoverable
+protocols may be implemented. By default a protocol marked as `@discoverable`
+may have clients and servers implemented by both external components and
+platform components.
+
+The `server` and `client` optional attributes list the kinds of components that
+may implement that kind of endpoint. By default both endpoints can be
+implemented by any component.
+
+For example:
+
+```fidl
+// All servers in the platform, all clients in external components.
+@discoverable(client="external", server="platform")
+protocol P {};
+
+// All servers in external components, all clients in the platform.
+@discoverable(client="platform", server="external")
+protocol Q {};
+
+// Only clients allowed in external components, both clients and servers allowed in the platform.
+@discoverable(client="platform,external", server="platform")
+protocol R {};
+
+// Servers are only allowed in platform components. Clients are allowed anywhere.
+// If both clients and servers are allowed that argument can (and should) be omitted.
+@discoverable(server="platform")
+protocol S {};
+```
+
+#### Types
+
+A new `@serializable` attribute will be added to FIDL to mark which types may be
+serialized and passed between components outside of FIDL protocols.
+
+This attribute is only allowed on non-`resource` `struct`s, `table`s and
+`union`s.
+
+It has two optional arguments, `read` and `write`. Each of these take a comma
+separated list of `platform` and `external` indicating whether platform
+components or external components are expected to read or write that type. The
+default value of each argument is `"platform,external"` indicating that it can
+be read and written from that kind of component.
+
+## Implementation
+
+### FIDL Toolchain
+`fidlc` will be updated to accept these the arguments to `@discoverable` and the
+new attribute `@serializable`. FIDL bindings generators (`fidlgen_*`) will not
+be modified [yet](#fidl-bindings).
+
+### Fuchsia System Interface
+All discoverable FIDL protocols in `partner` and `partner_internal` libraries
+will be updated. Most will be marked `@discoverable(server="platform")`
+indicating that external components should only implement clients but platform
+components may implement clients and servers. Some, such as many in `fuchsia.io`
+will be marked `@discoverable()` indicating that any component may implement
+clients and servers. A few, mostly for drivers will be marked
+`@discoverable(client="platform", server="external")` indicating that external
+components should only implement servers and platform components should only
+implement clients.
+
+After some experimentation and prototyping there doesn't seem to be a
+straight-forward way to calculate which category each protocol falls into.
+Neither runtime inspection of the component graph, nor static evaluation of CML
+shards were clear. Instead we'll look at the manifests of external components
+for which protocol capabilities they use and offer.
+
+For standalone data-types we will look for calls the the various language
+bindings' explicit serialization APIs and annotate the types that are used there
+appropriately.
+
+### Compatibility Tooling
+We're developing a tool to evaluate the compatibility of different versions of
+the FIDL IPC portions of the Fuchsia System Interface. This works against the
+FIDL IR and will incorporate information from discoverable attributes. A
+complete description of the compatibility rules that this tool will implement
+will come in another RFC.
+
+### Future Opportunities
+Compatibility tooling is the motivating priority behind this enhancement to FIDL
+syntax. However, this richer information about the Fuchsia System Interface may
+prove useful elsewhere.
+
+#### FIDL Bindings
+The FIDL bindings generators could become aware of whether they're building
+bindings that target platform components or external components and adjust the
+code they generate to encourage developers to only implement clients and servers
+of protocols in contexts where they have compatibility guarantees.
+
+Preventing any unsupported clients or servers is counter-productive because
+developers need to be able to fake or mock their peers in tests, but perhaps we
+can place guards to discourage their use in non-test contexts.
+
+The standalone serialization code can be updated to only allow types that are
+marked as `@serializable` to be passed in.
+
+#### Component Framework
+Within component framework, protocol capabilities are untyped. They're often
+named after the FIDL protocol they carry, but that is merely a convention, and
+one that is violated. Tools that reason about the protocols that a component
+uses to communicate with its peers have to guess, based on the names of
+capabilities what protocols are being used.
+
+If the component framework added protocol types to its model these tools would
+be simpler, more robust and more correct.
+
+#### Software Assembly
+Software assembly produces Fuchsia system images out of configuration, platform
+components and external components. It could use information about which
+protocols may be served from platform components or external to refuse to
+assemble products that violate those rules. This would ensure that product
+owners aren't inadvertently building products that make compatibility guarantees
+that the Fuchsia isn't offering, and help platform developers to avoid exposing
+capabilities in ways that they don't intend to support.
+
+#### Security
+
+Knowing which end of protocol capabilities are routed across the external /
+platform boundary may be useful for evaluating the security properties of the
+system. This could be done in an ad-hoc fashion, or integrated into existing
+tooling.
+
+## Performance
+
+There will be no change to performance.
+
+## Ergonomics
+
+This requires some of the assumptions in the system to be made explicit which
+involves a little more work up-front, but can make the system much easier to
+understand and work with.
+
+## Backwards Compatibility
+
+Existing FIDL libraries will be unaffected. `@discoverable` without arguments
+remains a valid attribute.
+
+Initially we will not want to version the discoverable and serializable
+attributes, since they're an input to versioning, have no impact on source or
+runtime compatibility, and need to be adopted widely to see benefits. If we
+[update FIDL bindings](#fidl-bindings) to changed based on the discoverable
+arguments we will have to consider versioning them as changing them could break
+existing source code.
+
+## Security considerations
+
+There may be future [opportunities](#security) in this area to improve overall
+system security.
+
+## Privacy considerations
+
+None
+
+## Testing
+
+This will make it easier to ensure that we have complete [compatibility
+tests][compatibility-tests] for the Fuchsia platform by explicitly encoding
+which ends of which protocols we promise compatibility with.
+
+For all of the `fidlc` changes we will add new `fidlc` tests.
+
+Until we are validating at assembly time that all components are following the
+rules expressed in FIDL files we won't know for sure that the external /
+platform split we've expressed in the SDK matches the reality in Fuchsia
+products.
+
+## Documentation
+
+A few pieces of FIDL documentation will need to be updated:
+
+ - the [list of supported attributes][fidl-attributes] will be updated to
+   document the changes to `@discoverable` and the addition of `@serializable`
+ - the [FIDL rubric][fidl-rubric] will be updated to describe how this should be
+   used
+
+## Drawbacks, alternatives, and unknowns
+
+We could keep the status quo, but that would either significantly limit the
+kinds of changes we could support, or limit the confidence our tools could have
+in checking the safety of changes.
+
+We could express the external / platform split outside of the FIDL language in
+the API tooling (like we do for SDK categories), but since this categorization
+happens at the declaration level that would feel less ergonomic and more likely
+to become stale.
+
+Instead of using `@discoverable` to mark protocols like `fuchsia.io.Directory`,
+we could come up with an equivalent attribute that meant the same for
+compatibility but didn't include support for protocol capabilities. That felt
+like more complexity that was necessary.
+
+Instead of adding `@serializable` to mark types that are exchanged out of band,
+we could just write placeholder FIDL `protocol`s that use those typed and are
+marked `@discoverable` with appropriate attributes to imply where those types
+may be read and written. That would mean having protocols that are never meant
+to be spoken and would generally be hard to get right and messy.
+
+Instead of syntax like `@discoverable(server="platform", client="external")`, we
+used `@discoverable(platform="server", external="client")` for a little while
+but the current syntax feels easier to understand.
+
+## Prior art and references
+
+n/a
+
+[compatibility-tests]: /docs/development/testing/ctf/compatibility_testing.md
+[component-framework]: /docs/concepts/components/v2/introduction.md
+[fidl-at-rest]: /docs/contribute/governance/rfcs/0120_standalone_use_of_fidl_wire_format.md
+[fidl-attributes]: /docs/reference/fidl/language/attributes.md
+[fidl-language]: /docs/reference/fidl/language/language.md
+[fidl-protocols]: /docs/reference/fidl/language/language.md#protocols
+[fidl-rubric]: /docs/development/api/fidl.md
+[fuchsia-system-interface]: /docs/concepts/packages/system.md
+[processargs]: /docs/concepts/process/program_loading.md#the_processargs_protocol
diff --git a/docs/contribute/governance/rfcs/0242_configuration_capabilities.md b/docs/contribute/governance/rfcs/0242_configuration_capabilities.md
new file mode 100644
index 0000000..138b4bb
--- /dev/null
+++ b/docs/contribute/governance/rfcs/0242_configuration_capabilities.md
@@ -0,0 +1,434 @@
+<!-- mdformat off(templates not supported) -->
+{% set rfcid = "RFC-0242" %}
+{% include "docs/contribute/governance/rfcs/_common/_rfc_header.md" %}
+# {{ rfc.name }}: {{ rfc.title }}
+{# Fuchsia RFCs use templates to display various fields from _rfcs.yaml. View the #}
+{# fully rendered RFCs at https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs #}
+<!-- SET the `rfcid` VAR ABOVE. DO NOT EDIT ANYTHING ELSE ABOVE THIS LINE. -->
+
+<!-- mdformat on -->
+
+<!-- This should begin with an H2 element (for example, ## Summary).-->
+
+## Summary
+
+Outline the use of configuration [capabilities][capabilities] in the
+component framework and the syntax that will be added to CML files to support
+them.
+
+It should be noted that this document supercedes parts of the earlier Structured
+Configuration RFCs, which are mentioned in the prior arts section.
+
+## Motivation
+
+Components in Fuchsia use [structured configuration][rfc-0127] to get
+configuration values. Today configuration values are mostly loaded out of a
+component's package. It is possible for a parent component to imperatively set
+configuration values when launching a dynamic component, but most components in
+Fuchsia are static.
+
+There are multiple motivations for adding this feature:
+
+- Allowing a static parent to configure a child's config.
+- Routing a single config value to multiple components.
+- Providing configuration values from a CML file.
+
+The first customer for Configuration Capabilities is system assembly, as this
+feature will make it possible to remove technical debt. The technical debt
+exists because there is currently no way to provide configuration to a static
+component besides editing that component's package. System assembly currently
+opens fuchsia packages, edits their configuration value files, and then
+re-packages them. This is technical debt as it changes the hash value of the
+package and the config value file is technically a "private" API of the
+component that is not easily evolvable.
+
+For out of tree packages that cannot be rebuilt, configuration capabilities
+provides a way for those components to be configured. There is currently no way
+to edit those component's configurations within a static topology.
+
+This feature will likely be useful in many future configuration use cases.
+
+## Stakeholders
+
+
+_Facilitator:_ neelsa@google.com
+
+_Reviewers:_
+
+- System Assembly: aaronwood@google.com
+- Component Framework: geb@google.com
+- Security: markdittmer@google.com
+- Driver Framework: surajmalhotra@google.com
+- Component Framework: wittrock@google.com
+
+_Socialization:_ This issue has been discussed with the Component Framework team
+before writing the RFC.
+
+## Requirements
+
+Configuration Capabilities allows CML authors to set the configuration values of
+static components. They allow for the routing of configuration values through
+the topology so that multiple components can use the same value. Routing values
+through the topology allows indirect ancestors to specify values, where the
+existing feature only allows direct parents to specify values.
+
+Configuration Capabilities should follow existing Component Framework features
+when possible to be consistent with the rest of the system.
+
+## Design
+
+The bulk of the design is CML syntax for declaring and routing a configuration
+capability. A configuration capability has both its type and value defined in
+CML. A configuration capability is routed to a component that wishes to use
+it. The component using the configuration capability will be able to see the
+value when the component is started by using the existing structured
+configuration libraries.
+
+Below is an example for defining a configuration capability:
+
+```json5
+// Configuration capabilities can be defined in any component.
+// When a configuration capability is defined, a value must be set for it.
+capabilities: [
+  {
+    // Define the name of the capability.
+    config: "fuchsia.netstack.UseNetstack3",
+    // Define the type of the configuration.
+    type: "bool",
+    // When defining a configuration capability, there *must* be a value.
+    // If the route for the configuration capability ends at this definition, the
+    // value of the capability will always be this value.
+    value: "true"
+  },
+  // The below shows a string config.
+  {
+      config: "fuchsia.config.MyString",
+      type: "string",
+      max_size: 100,
+      value: "test",
+  },
+  // The below shows a vector config.
+  {
+      config: "fuchsia.config.MyUint8Vector",
+      type: "vector",
+      element: { type: "uint8" },
+      max_count: 100,
+      value: [1, 2, 3 ],
+  },
+]
+```
+
+The `type`, `element`, `max_count`, `max_size` fields on the `config` capability
+have identical meanings to their use in the `config` stanza. All values that are
+supported in the `config` stanza are supported in the `capabilities` block.
+
+The `type` field supports the following:
+
+- bool
+- uint8, uint16, uint32, uint64
+- int8, int16, int32, int64
+- string
+- vector
+
+The using block supports the same `type`, `element`, `max_count`, and `max_size`
+fields as the capabilities block.
+
+Below is example syntax for using a configuration capability:
+
+```json5
+// Using a configuration capability means that this configuration will show
+// up in the component's structured config at runtime with the specified `key`
+// name.
+// NOTE: Using a configuration capability will override the value in the Config
+// Value File (CVF) and the value obtained from the "mutability" setting.
+use: [
+  {
+    config: "fuchsia.netstack.LaunchProcess",
+    // This is the name that the component will see in its Structured Config
+    // struct. If the `use` is optional this must match a name in the "config"
+    // block of the component's manifest.
+    key: "can_launch_process",
+    // The using field needs the type information so that the component's
+    // Config Value File format can be created.
+    type: "bool",
+    // From is identical to other capabilities.
+    from: "parent",
+  },
+  // The below shows a vector config.
+  {
+    config: "fuchsia.netstack.MyUint8Vector",
+    key: "my_vector",
+    type: "vector",
+    element: { type: "uint8" },
+    max_count: 100,
+    from: "parent",
+  },
+  // The below shows a string config.
+  {
+    config: "fuchsia.netstack.MyString",
+    key: "my_string",
+    type: "string",
+    max_size: 256,
+    from: "parent",
+  },
+]
+```
+
+Below is example syntax for routing a configuration capability:
+
+```json5
+// Expose and Offer behave the same as any other capability.
+expose: [
+  {
+    config: "fuchsia.netstack.UseNetstack3",
+    as: "fuchsia.mycomponent.UseVersion3",
+    from: "self",
+  },
+]
+offer: [
+  {
+    config: "fuchsia.config.MyString",
+    as: "fuchsia.mycomponent.ProcessName",
+    from: "self",
+    to: "#mychild",
+   },
+]
+```
+
+### Optional Capabilities
+
+If a component is using a configuration capability with the availability set to
+`optional`, and that capability is being routed from `void`, then the component
+will receive the value from the Configuration Value File (CVF). This feature
+exists to support soft migrations for updating configurations.
+
+### Deprecation of the 'config' block
+
+Before configuration capabilities, the config fields were declared in the
+`config` stanza in the CML. This information is now being replaced by the
+information in the `use` stanza. This means that the Structured Configuration
+schema that is generated for a component will be a union of the field
+declarations in the `use` block and the `config` stanza.
+
+Once all structured config clients have been migrated to configuration
+capabilities, support for the config block in CML will be removed.
+
+### Deprecation of the 'mutability: parent' feature
+
+Before configuration capabilities, a config value could be declared as
+`mutability: parent`, which would allow the parent of that component to
+change the value.
+
+Users of this feature will be migrated to `use` a configuration capability
+from their parent. Once all users have been migrated, this feature will be
+removed.
+
+## Implementation
+
+The implementation of these CML features is relatively straight forward and can
+be done in tree in a few CLs. Clients can migrate to using configuration
+capabilities at any time as this does not affect existing structured
+configuration features.
+
+We will need to ensure Scrutiny understands the configuration capabilities and
+can verify that a specific product has a given configuration.
+
+## Performance
+
+Starting a component may become slightly slower due to Component Framework
+needing to perform routing on the configuration capabilities a component uses.
+This could be significant if the capabilities are coming from a component that
+is unresolved and needs to downloaded. This should be negligible for resolved
+components.
+
+## Ergonomics
+
+The ergonomics for this new CML capability are identical to existing
+capabilities. It is a bit verbose to add and route a configuration capability,
+but the syntax was chosen to match existing capability syntax as much as
+possible. Where possible, the syntax was also chosen to match the existing
+`config` block syntax.  When the two syntax's conflicted, the existing
+capability syntax was preferred. Matching existing syntax reduces cognitive
+effort by users familiar with the component framework.
+
+The CF team may decide to keep the `config` block as syntactic sugar for
+declaring a configuration capability, or add additional syntactic sugar if we
+need better ergonomics.
+
+## Backwards Compatibility
+
+This is a new feature. It is backwards compatible with existing structured
+configuration features.
+
+It is worth noting that routing a configuration capability to a component will
+always take precedence over the value in the CVF file. If a component has an
+optional configuration capability route and the route is not present, then the
+value in the CVF file will be used.
+
+## Security considerations
+
+This feature should not impact security. Scrutiny and other tools to
+investigate CML will work on this new capability type.
+
+It could be argued that setting capabilities in this way will be more visible
+than the existing strategy of editing values within a component's package.
+
+If a component is using a required configuration capability and one is not
+routed to it, the component will be unable to start. This should not be a
+security problem because the parent of a component is trusted, and these routes
+can be statically verified to be correct.
+
+## Privacy considerations
+
+This proposal should have no impact on privacy.
+
+## Testing
+
+This feature will need unit and integration tests. The general testing areas
+are:
+
+- Parsing the new CML syntax.
+- Routing the new capability through the topology.
+- Attempting to start a component with missing configuration capabilities.
+- Attempting to start a component with a configuration capability of the wrong
+  type.
+- Starting a dynamic component with a configuration capability.
+
+The feature will need the following tests added to Scrutiny:
+
+- Testing that Scrutiny can resolve values for configuration capabilities.
+- Testing precedence/override logic for different sources of config values.
+- Testing interactions between configuration capabilities, the config block, and
+  mutability.
+
+None of these tests require new test infrastructure.
+
+## Documentation
+
+Fuchsia.dev will need to be updated to have documentation on configuration
+capabilities. The existing capability docs will be used as a template for this
+new documentation.
+
+## Drawbacks, alternatives, and unknowns
+
+### Alternative: Implement a configuration override service
+
+The original
+[Structured Configuration RFC][rfc-0127]
+proposed that structured config is directly sourced from a component's package.
+The RFC specifically calls out that it is not attempting to address
+"configuration data that is set by other components (except parent components
+and admin components)". One alternative is to continue to not support a
+capability based configuration scheme.
+
+One of the drawbacks to Configuration Capabilities instead of the override
+service is that Configuration Capabilities is more verbose and more complicated.
+Implementing something globally is always going to be simpler initially.
+However, Fuchsia has found that capability based systems end up being more
+composable and understandable in the long run. It is very helpful to be able to
+say that a specific configuration is only used by a subset of the component
+topology, or to use two different values within two different components.
+Configuration Capabilities make this easier to express and embodies the
+capability based system used elsewhere in Fuchsia. Using the existing CML
+syntax for configuration allows the feature to be understood more easily by
+fuchsia developers, and it composes well with component framework's existing
+tools.
+
+### Drawback: Many additional use fields
+
+Keeping the type information in the `use` block adds 6 additional fields
+which are only valid for configuration capabilities.
+
+It would be possible to combine these 6 fields into one field with subfields,
+but adding the fields was preferable as it kept the syntax close to the
+existing `config` block syntax.
+
+### Drawback: Conflating type information and routing
+
+One drawback to putting the configuration schema in the `use` declaratio is
+that the `use` block defines the type information and also defines routing.
+Some components may wish to define their configuration without specifying
+routing, and then route their configuration differently in different scenarios.
+This is simpler if the type information is in a different place than the Use
+block.
+
+Component authors that want to change how their types are defined must modify
+their `use` blocks instead of only modifying their `config` blocks.
+
+If the combination of configuration definition and routing becomes a persistent
+pain point for developers, then Component Framework team may revisit this
+decision.
+
+### Alternative: Keep configuration type definition in the `config` block
+
+One alternative is to not have a "type" field in the `use` declaration, and to
+instead rely on the type information in the existing "config" block. This was
+the case in the earlier versions of this RFC. This alternative addresses the
+current drawback of conflating type information and routing. It makes it easier
+for clients to define configuration in one place and to route it in another
+place (possibly including different CML shards to route differently based on
+different configurations).
+
+In the current Structured Configuration-based implementation in which Component
+Manager "pushes" configuration to the component when launching it, Component
+Manager needs to ensure that the routed capability's type matches that of the
+target Structured Configuration field. It was decided that the type information
+would be placed on the `use` declaration because this is symmetric with the
+Capability Declaration. When Component Manager performs routing it needs to
+ensure that the type information lines up, which means that logically the
+information should be contained at both ends (Capability and Use) of the route.
+
+Another reason for keeping the type information on the `use` declaration is that
+it becomes possible to keep all of the information in the `use` declaration and
+not require a matching "config" block entry. This keeps the information in a
+single location in the CML file, which makes it easier to audit.
+
+### Alternative: `as` field in `use` declaration
+
+With the Structured Configuration field name and type information encapsulated
+within the `config` block, `as` could be used to specify the field to which the
+capability is being provided. This would be consistent with how most non-`path`
+"renaming" is done in CML.
+
+The `key` term was used instead because the field operates differently than
+other `as` fields. `as` is normally optional, but `key` is required. `key` must
+also match an existing key in the `config` block if the capability is optional.
+
+### Unknown: Balancing existing Structured Config inconsistencies with Capabilities
+
+There are a number of ways that the existing Structured Configuration is
+inconsistent with how other Capabilities work.
+
+One inconsistency is that the program is deeply dependent on the format of the
+Structured Configuration that is defined in the component manifest. Normally it
+is the manifest that depends on the program, and Structured Configuration makes
+this relationship circular. This is visible in the fact that the Structured
+Configuration build rules require adding an extra layer between the component,
+component manifest, and the program. This circular inconsistency will not be
+addressed by Configuration Capabilities, but it should hopefully be addressed
+in a followup RFC.
+
+Another inconsistency is that Structured Configuration is "pushed" to the
+component when it is started, where other capabilities are "pulled" as the
+component accesses them. This inconsistency is also not addressed in this
+RFC. The purpose of this RFC is to add routing and capability support within
+Component Manifests. This RFC does not change the interface between a program
+and Structured Configuration, so that the number of migrations needed is
+limited.
+
+Fuchsia will be in a better place to address these inconsistencies after
+implementing Configuration Capabilities and seeing how they are used. More
+client data will help us address pain points and implement followup changes.
+
+## Prior art and references
+
+Prior structured configuration rfcs:
+
+- [rfc-0127]
+- [rfc-0146]
+- [rfc-0215]
+
+[capabilities]: /docs/concepts/components/v2/capabilities/README.md
+[rfc-0127]: /docs/contribute/governance/rfcs/0127_structured_configuration.md
+[rfc-0146]: /docs/contribute/governance/rfcs/0146_structured_config_schemas_in_cml.md
+[rfc-0215]: /docs/contribute/governance/rfcs/0215_structured_config_parent_overrides.md
diff --git a/docs/contribute/governance/rfcs/0243_wlan_roaming.md b/docs/contribute/governance/rfcs/0243_wlan_roaming.md
new file mode 100644
index 0000000..c308017
--- /dev/null
+++ b/docs/contribute/governance/rfcs/0243_wlan_roaming.md
@@ -0,0 +1,1061 @@
+<!-- Generated with `fx rfc` -->
+
+<!-- mdformat off(templates not supported) -->
+{% set rfcid = "RFC-0243" %}
+{% include "docs/contribute/governance/rfcs/_common/_rfc_header.md" %}
+# {{ rfc.name }}: {{ rfc.title }}
+{# Fuchsia RFCs use templates to display various fields from _rfcs.yaml. View the #}
+{# fully rendered RFCs at https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs #}
+
+<!-- mdformat on -->
+
+## Summary
+
+A device that is connected to a wireless network where there are multiple access
+points will gain the ability to roam between them. "Roam" means the client
+device moves its connection from one access point (AP) to another AP within the
+same wireless network, without incurring a full disconnection during the
+transition. A device may roam for many reasons: perhaps the device has moved
+farther from its current AP and closer to another AP; or perhaps a device's
+connection to its current AP has degraded in some way (e.g. high error rate). In
+cases like these, a device may attempt to roam to another AP to avoid incurring
+a full disconnection. This document addresses the API changes and logic
+necessary to support Fullmac-initiated and WLAN Policy-initiated roaming.
+
+## Motivation
+
+Maintaining WLAN connectivity sometimes requires that a device uses a different
+AP from the one it is currently using. Most commonly, this is because:
+
+*   the current AP is no longer reachable
+*   the connection to the current AP has degraded in some way
+
+Roaming allows a device to move to a new AP with minimal disruption, using
+802.11 reassociation. Without roaming, a device has to disconnect (or learn that
+it has been disconnected) from the original AP, tear down all its networking
+connections, and begin a new connection to an AP.
+
+Contrast this with the situation when roaming is supported: a device can select
+a new AP while still connected to the original AP, and perform the
+reassociation. Reassociation is observed to take approximately 70 ms, while a
+disconnect followed by a reconnect is observed to take approximately 130 ms.
+While reassociation isn't a panacea, other features that further reduce the
+disruption require reassociation support. Once the plumbing for roaming is
+present (i.e. this design), a slew of further roaming enhancements will become
+possible with future work, such as:
+
+*   **Roam before an interruption happens**: With BSS Transition Management
+    (IEEE 802.11-2020 4.3.19.3), an AP can notify a device that it should roam
+    before an upcoming interruption.
+*   **Reduce duration of roaming disruption, sometimes to zero**: With Fast BSS
+    Transition (IEEE 802.11-2020 4.5.4.8), a device can perform most of the
+    risky and time-consuming steps of the roam before leaving the original AP.
+*   **Take advantage of hardware offloads**: Roaming feature offloads present in
+    some Fullmac chip firmware can implement roaming protocols, reduce power
+    usage by performing roaming logic on-chip rather than in the OS, and reduce
+    delay between roam decision and roam start.
+*   **Give WLAN Policy greater control over the connection**: Significant work
+    is underway in WLAN Policy to decide when and where to roam. The API and
+    logic changes described here are essential to allow WLAN Policy to initiate
+    a roam, and respond when a roam attempt completes.
+
+## Stakeholders
+
+*Facilitator:*
+
+neelsa@google.com
+
+*Reviewers:*
+
+*   silberst@google.com: for WLAN
+*   karthikrish@google.com: for WLAN Drivers
+*   swiggett@google.com: for WLAN Core
+*   haydennix@google.com: for WLAN Policy
+*   sbalana@google.com: for Connectivity Automation testing
+
+*Consulted:*
+
+*   Netstack: brunodalbo@google.com
+*   Network Policy: dhobsd@google.com
+*   WLAN Core: chcl@google.com, kiettran@google.com
+*   WLAN Drivers: rsakthi@google.com
+*   WLAN Policy: mnck@google.com, nmccracken@google.com
+
+*Socialization:*
+
+*   Prototypes were created for multiple variations on the possible
+    implementation of WLAN Core logic, which were discussed in meetings with
+    WLAN Core and separately with the WLAN team lead
+*   Draft RFC was circulated and discussed in detail with Connectivity Drivers,
+    WLAN Core, WLAN Policy, Network Policy, and Netstack teams
+*   Multiple ancillary documents were drafted to explore relevant topics,
+    especially around SME state machine changes, EAPOL behavior, and disconnect
+    behavior
+
+## Requirements
+
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
+"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
+interpreted as described in
+[IETF RFC 2119](https://tools.ietf.org/html/rfc2119). Requirements are included
+below.
+
+## Terms
+
+*   Device: client device in an 802.11 wireless network; in 802.11 terms,
+    "device" means non-AP STA in this document
+*   Station (STA): a device connected to an 802.11 wireless network
+*   Access point (AP): connects one or more client devices to a network via the
+    802.11 wireless networking protocol
+    *   current AP: when a device is connected to a wireless network, it can
+        only be associated with one AP at any given time; the current AP is the
+        AP that the device is associated to at the present moment
+    *   original AP: where the device is associated at the beginning of a roam
+        attempt
+    *   target AP: when a device is attempting a roam to a different AP, the
+        target AP is where the device is attempting to associate; at completion
+        of a successful roam attempt, the target AP becomes the current AP
+*   Roam: when a client device moves its connection from one AP to another AP
+    within the same wireless network, without incurring a full disconnection
+    during the transition; in this document, "roam" is the set of actions taken
+    to move the connection, which includes authentication and reassociation with
+    the target AP, and coordination between layers of Fuchsia WLAN software
+*   Reassociation: 802.11-specified mechanism to move a client device's
+    association from one AP to another AP (see IEEE 802.11-2020 4.5.3.4)
+
+## Design
+
+Coordination of roaming requires FIDL API changes affecting almost all of WLAN:
+Fullmac, MLME, SME, and WLAN Policy. The API specified in this RFC supports two
+major modes of operation:
+
+*   Fullmac-initiated roam
+*   WLAN Policy-initiated roam
+*   *(For a brief discussion of how Softmac roaming might work, see
+    [Appendix C: Looking ahead to Softmac roaming](#appendix-c))*
+
+In a **Fullmac-initiated roam**, the decision of when and where to roam is made
+by the Fullmac firmware. In order for a roam to succeed, the start of the roam
+MUST be communicated upward through MLME and SME, and the result of the roam
+MUST be communicated upward through MLME, SME, and into WLAN Policy. A
+Fullmac-initiated roam attempt begins with Fullmac issuing a `RoamStartInd`, and
+the result of the roam attempt results in WLAN Policy receiving a
+`ConnectTransaction.OnRoamResult`. The messages follow these paths:
+
+*   Fullmac firmware roam start notification to Fullmac driver -> Fullmac
+    `RoamStartInd` -> MLME `RoamStartInd` -> SME
+*   Fullmac firmware roam result notification to Fullmac driver -> Fullmac
+    `RoamResultInd` -> MLME `RoamResultInd` -> SME
+    `ConnectTransaction.OnRoamResult` -> WLAN Policy
+
+In a **WLAN Policy-initiated roam**, the decision of when and where to roam is
+made by WLAN Policy and MUST be communicated downward through SME, MLME, Fullmac
+driver, and finally into device firmware. The device firmware attempts the roam,
+and the result of the roam attempt MUST be reported upward through Fullmac,
+MLME, SME, and into WLAN Policy. A WLAN Policy-initiated roam attempt begins
+with WLAN Policy issuing a `ClientSme.Roam`, and the result of the roam attempt
+eventually results in WLAN Policy receiving a `ConnectTransaction.OnRoamResult`.
+The messages follow these paths:
+
+*   WLAN Policy -> SME `ClientSme.Roam` -> MLME `RoamReq` -> Fullmac `RoamReq`
+    -> Fullmac firmware roam command
+*   Fullmac firmware roam result notification to Fullmac driver -> Fullmac
+    `RoamConf` -> MLME `RoamConf` -> SME `ConnectTransaction.OnRoamResult` ->
+    WLAN Policy
+
+To implement these API changes, there will be logic changes throughout WLAN:
+
+*   Fullmac driver changes to send firmware commands that initiate a roam, and
+    respond to notification from firmware about the progress and eventual result
+    of a roam
+*   MLME changes to open/close the 802.1X controlled port as the roam progresses
+    through authentication, reassociation, and RSNA setup
+*   SME changes to introduce a new internal SME client state (*Roaming*)
+*   SME and WLAN Policy changes to give WLAN Policy the ability to initiate a
+    roam, and to notify WLAN Policy of the result of a roam (WLAN Policy
+    receives the same roam result notification whether the roam was
+    Fullmac-initiated or WLAN Policy-initiated)
+
+This RFC does not specify how roaming decisions are to be made by Fullmac or
+WLAN Policy, other than to advise that roaming decisions:
+
+*   SHOULD incorporate available higher order connectivity signals (such as
+    Internet connectivity of APs) when deciding whether to roam
+*   and SHOULD incorporate similar signals after a successful roam to gauge
+    whether the roam yielded a working connection
+
+### SME will get a new *Roaming* internal client state
+
+SME needs to track specific data about a client when it is roaming, and manage
+transitions between the roaming state and its other internal states. A new
+internal state named *Roaming* will be added to the SME client state machine.
+Like the SME *Connecting* state, *Roaming* state is where SME attempts to
+authenticate and associate with an AP (which we will refer to as the "target
+AP"). There are a few key differences:
+
+*   the only valid transition into *Roaming* state is from *Associated* state;
+    while there are many existing valid transitions into *Connecting* state
+*   *Roaming* has special handling for receipt of certain events; where
+    *Connecting* transitions to *Idle* state on receipt of a 802.11
+    deauthentication, or transitions to *Disconnecting* on receipt of a
+    disassociation, *Roaming* MUST only handle deauthentication and
+    disassociation frames from the target AP
+*   *Roaming* state handles events that would not be handled by *Connecting*
+    (`RoamResultInd` and `RoamConf`)
+*   when SME moves from *Associated* to *Roaming*, the current AP changes
+    because SME is attempting to connect to the target AP; during transitions
+    between *Associated* and *Connecting*, the AP does not change
+
+Here is a high level overview of the SME client state machine (changes in red):
+
+![SME state machine overview diagram showing new Roaming state and transitions
+between SME states](resources/0243_wlan_roaming/sme_state_changes_overview.png)
+
+Here's a more detailed SME client state machine diagram for Fullmac-initiated
+roam, showing the happy path (`RoamStartInd` followed by successful
+`RoamResultInd`) and relevant failure paths:
+
+![SME state machine diagram showing events that cause transitions between
+Roaming and other SME states in Fullmac-initiated
+roam](resources/0243_wlan_roaming/sme_state_changes_fullmac_initiated_roam.png)
+
+Here's a similar SME client state machine diagram for WLAN Policy-initiated
+roam, showing the happy path (`RoamReq` followed by successful `RoamConf`) and
+relevant failure paths:
+
+![SME state machine diagram showing events that cause transitions between
+Roaming and other SME states in WLAN Policy-initiated
+roam](resources/0243_wlan_roaming/sme_state_changes_wlan_policy_initiated_roam.png)
+
+See [Fullmac-initiated roam](#fullmac-initiated-roam) and
+[WLAN Policy-initiated roam](#wlan-policy-initiated-roam) sections below for
+more details on how SME transitions to/from the *Roaming* state.
+
+### Fullmac-initiated roam {#fullmac-initiated-roam}
+
+Some Fullmac device firmware can be configured to decide when and where to roam.
+Here's a high-level overview of how a roam initiated by Fullmac is handled by
+WLAN:
+
+![Stack diagram showing the flow of roam start and roam result messages for a
+Fullmac-initiated roam](resources/0243_wlan_roaming/fullmac_initiated_roam.png)
+
+When a Fullmac-initiated roam attempt begins (**step 1** in the above diagram),
+the Fullmac driver MUST send a `RoamStartInd` up to MLME (**step 2**). The
+`RoamStartInd` MUST be sent before the firmware begins the authentication or
+reassociation to the target AP. Like a `ConnectReq` (which creates an initial
+connection to an AP), `RoamStartInd` contains the BSS Description of the target
+AP. MLME SHOULD provide the full BSS Description to SME (see **step 4 below**).
+
+The `RoamStartInd` also MUST contain:
+
+*   the BSSID of the target AP (stored separately, in case the BSS Description
+    is missing)
+*   a boolean indicating whether the original association was maintained at roam
+    start time (for Fast BSS Transition support, see [Appendix A](#appendix-a)).
+
+As more roaming features are implemented, other fields MAY be added to
+`RoamStartInd`.
+
+Because the roam attempt MUST use the same security configuration that was used
+to connect to the original AP when roaming to a target AP, Fullmac MUST retain
+the original security configuration that was used for the initial connection to
+the AP. Fullmac MUST NOT reassociate to an AP that does not match the original
+security configuration used in the initial connection. See
+[Appendix D: Reassociation request security configuration](#appendix-d) for more
+details.
+
+When a roam attempt is in progress, the Fullmac driver:
+
+*   MAY reject incoming scan requests (this is the case for brcmfmac, the only
+    current Fullmac driver)
+*   MAY cancel a scan that is in progress when the roam attempt starts
+*   MUST return an error for incoming connect requests
+    *   this is similar to existing Fullmac behavior (in brcmfmac), which does
+        not service (and returns an error for) an incoming connect request when
+        there is a connection attempt in progress; we will do the same for
+        connect attempts when a roam attempt is in progress
+*   MUST return an error for incoming roam requests
+    *   again, similar to existing connect behavior in Fullmac, but for roam
+        attempts
+*   MUST service incoming disconnect requests
+
+Because of these constraints, the Fullmac driver MUST set an internal roam
+timeout for completion of 802.11 authentication and reassociation. The timeout
+duration does not include any post-reassociation actions (e.g. EAPOL, DHCP). If
+the reassociation does not complete before the timeout:
+
+*   Fullmac MUST initiate a disconnect if the original association has not been
+    maintained
+*   see [Appendix A](#appendix-a) for changes when Fast BSS Transition is
+    supported
+
+The roam timeout is needed to avoid becoming stuck in a state where important
+functions such as scan and connect cannot be performed. The timeout SHOULD be
+set substantially longer than a typical authentication and reassociation (which
+have been observed to be in the neighborhood of 100 ms). A reasonable default
+roam timeout MAY be somewhere around 1 second.
+
+When MLME receives a `RoamStartInd` from Fullmac (**steps 2 and 3**), it MUST
+close the 802.1X controlled port. At this point, MLME MUST consider the device
+to be:
+
+*   authenticated with the original AP
+*   not associated with the original AP
+*   in pending RSNA state (if security configuration requires RSNA)
+
+MLME informs SME that the roam has started via MLME `RoamStartInd` (**step 4**).
+SME uses the BSS Description in MLME `RoamStartInd` to perform 802.11
+authentication and RSNA setup in concert with Fullmac. If the BSS Description
+provided by MLME `RoamStartInd` is missing or invalid, SME MUST fail the roam.
+
+Upon receipt of MLME `RoamStartInd`, SME updates its internal state to represent
+that the device is roaming. Significant state and logic are already maintained
+in SME to support authentication and RSNA, processes which are performed in
+concert with the Fullmac firmware/driver and MLME. Fuchsia WLAN uses SME as the
+802.11 authenticator (rather than an authenticator that might be provided by
+Fullmac firmware). Also, Fuchsia WLAN uses SME as an external supplicant for
+RSNA (rather than using a firmware supplicant, or a third party supplicant like
+wpa_supplicant).
+
+If SME detects a malformed `RoamStartInd` (e.g. missing fields, or invalid
+data), SME knows that the roam has failed due to an internal error. At the point
+that Fullmac issued the `RoamStartInd`, the device was still associated with the
+original AP, though Fullmac may have since left the channel and/or band of the
+original AP shortly after. SME will take the following actions:
+
+*   SME MUST consider this to be a disconnect, even if the `RoamStartInd`
+    indicates that the original association is maintained, because the invalid
+    roam attempt might otherwise continue
+*   SME MUST send WLAN Policy an `OnRoamResult` indicating that the disconnect
+    was due to a malformed `RoamStartInd`
+*   SME MUST send a deauthenticate to the target AP
+*   SME MAY send a deauthenticate to the original AP
+*   SME MUST transition to *Disconnecting*
+
+If `RoamStartInd` is not malformed, SME MUST transition to *Roaming*.
+
+Note that WLAN Policy is not informed of the start of a roam. Stated
+differently, `RoamStartInd` is propagated up to SME, but the start of a roam is
+not communicated to WLAN Policy through the `ConnectTransaction` protocol. At
+design time, WLAN Policy team did not see a need for such an event, but it can
+be added if need arises. From observations of actual roams, lack of roam start
+notification to WLAN Policy results in a short duration where WLAN Policy is
+unaware that a roam is in progress; sending a roam start event from SME to WLAN
+Policy would reduce that duration by approximately 50 ms.
+
+After sending the `RoamStartInd` to MLME, the Fullmac firmware begins the
+process of 802.11 authentication with the target AP (**step 5**). Authentication
+is coordinated with higher layers in the same fashion as a regular connection.
+When 802.11 authentication is complete, the firmware begins the process of
+802.11 reassociation with the target AP. *(See IEEE 802.11-2020 11.3.5.4 for
+details about how authentication, reassociation, and RSNA are coordinated).*
+Once Fullmac starts the reassociation exchange, the device is no longer
+associated with the original AP (but see
+[Looking ahead to Fast BSS Transition](#appendix-a) for some subtle details).
+
+Upon success, failure, or timeout of a Fullmac-initiated roam attempt (**step
+6**), the Fullmac driver MUST send a `RoamResultInd` up to MLME (**steps 7 and
+8**). The `RoamResultInd` provides information similar to what is provided in a
+`ConnectConf`. Most importantly, it includes the 802.11 status code of the roam
+attempt. Similar to `RoamStartInd`, `RoamResultInd` MUST contain a boolean field
+to indicate whether the original association is maintained (see
+[Looking ahead to Fast BSS Transition](#appendix-a)).
+`original_association_maintained` MUST be false if the roam succeeded, because a
+successful roam always incurs disassociation from the original AP.
+
+`RoamResultInd` also MUST contain a boolean field to indicate whether the device
+is authenticated with the target AP:
+
+*   `target_bss_authenticated` MUST be true if the roam attempt succeeded
+*   if `status_code` is anything other than success, `target_bss_authenticated`
+    specifies whether the device is currently authenticated with the target AP
+*   this field is present to inform SME of authenticated state with the target
+    AP, because SME MAY decide to send a deauthenticate request to the target AP
+    during its cleanup after a failed roam attempt
+
+Upon receipt of `RoamResultInd`, MLME MUST keep the 802.1X controlled port
+closed (but see [Looking ahead to Fast BSS Transition](#appendix-a)). If the
+roam succeeded:
+
+*   device MUST be associated with the indicated AP
+*   device MAY still be authenticated with the original AP
+*   device MUST NOT be associated with the original AP
+
+If the roam failed:
+
+*   device MAY still be authenticated with the original AP
+*   device MAY be authenticated with the target AP, as indicated by
+    `target_bss_authenticated`
+
+MLME sends `RoamResultInd` up to SME (**step 9**).
+
+Upon receipt of the MLME `RoamResultInd`, SME does the following if the roam
+succeeded:
+
+*   SME MUST move its internal state from *Roaming* to *Associated*, using the
+    target AP as the current AP
+*   SME MUST NOT transition out of *Associated* upon receipt of any
+    disassociate/deauthenticate frames from the original AP
+*   if the security configuration requires RSNA: RSNA setup occurs, coordinated
+    between Fullmac firmware, Fullmac driver, MLME, and SME in the same fashion
+    as the RSNA setup that occurs at first connection
+*   upon successful RSNA setup (or if the network does not require RSNA), the
+    802.1X controlled port will be opened in the same fashion as a regular
+    successful connection
+
+If `RoamResultInd` indicates that the roam failed, SME instead does the
+following:
+
+*   if `target_bss_authenticated` is true:
+    *   SME MAY request deauthentication from the original AP (but see
+        [Disconnect behavior](#disconnect-behavior) for some subtleties here)
+    *   SME MAY request deauthentication from the target AP
+    *   if SME decides to request deauthentication from the target AP, SME MUST
+        transition from *Roaming* into *Disconnecting*
+    *   otherwise SME MUST transition from *Roaming* into *Idle*
+    *   in case of SAE timeout with the target AP:
+        *   SME MAY request deauthentication from the original AP
+        *   SME MUST transition from *Roaming* directly to *Idle*
+*   if `target_bss_authenticated` is false:
+    *   SME MAY request deauthentication from the original AP (but see
+        [Disconnect behavior](#disconnect-behavior) for some subtleties here)
+    *   if SME decides to request deauthentication from the original AP, SME
+        MUST transition from *Roaming* into *Disconnecting*
+    *   otherwise SME MUST transition from *Roaming* into *Idle*
+
+SME communicates with WLAN Policy over a per-connection channel using the
+existing `ConnectTransaction` API. SME MUST send an `OnRoamResult` to WLAN
+Policy to inform it that a roam attempt has completed (**step 10**). The
+`RoamResult` is similar to SME `ConnectResult`. `RoamResult`:
+
+*   MUST include BSSID of the target AP
+*   MUST include a status code indicating whether the roam succeeded
+*   MUST include a boolean indicating whether the original association has been
+    maintained
+    *   MUST be false if the roam succeeded
+    *   see [Looking ahead to Fast BSS Transition](#appendix-a) for more details
+*   SHOULD include the BSS description of the target AP, regardless of success/
+    failure (but this field MAY be empty if the roam failed)
+*   MUST include an SME `DisconnectInfo` if a disconnect was incurred; in other
+    words, this is REQUIRED if roam failed and original association was not
+    maintained
+
+Upon receipt of `OnRoamResult`, WLAN Policy will update its internal state. If
+the roam succeeded, WLAN Policy MUST continue to maintain the existing
+`ConnectTransaction` with SME, but with the device now associated to the target
+AP. If the result indicates roam failure:
+
+*   if the original association was not preserved, WLAN Policy MUST close the
+    `ConnectTransaction` and end the connection
+*   after a roam failure, WLAN Policy will begin the process of creating a new
+    connection, similar to how it responds to any lost connection
+
+### WLAN Policy-initiated roam {#wlan-policy-initiated-roam}
+
+WLAN Policy will gain the ability to initiate a roam attempt and learn of its
+outcome. A high-level overview of how a roam initiated by WLAN Policy is handled
+by WLAN:
+
+![Stack diagram showing the flow of roam request and roam confirmation messages
+for a WLAN Policy-initiated
+roam](resources/0243_wlan_roaming/wlan_policy_initiated_roam.png)
+
+When WLAN Policy initiates a roam attempt, it does so by issuing a
+`ClientSme.Roam` to SME (**step 1 in the above diagram**). `Roam` contains a
+`RoamRequest`, which is conceptually similar to SME `ConnectRequest`, though
+with fewer options because SSID and security configuration MUST NOT change
+during the roam (see
+[Appendix D: Reassociation security configuration](#appendix-d) for more
+background on the security configuration used in a roam).
+
+Because the roam attempt MUST use the same security configuration that was used
+to connect to the original AP when roaming to a target AP, WLAN Policy MUST
+retain the original security configuration that was used for the initial
+connection to the AP. WLAN Policy MUST NOT attempt to reassociate to an AP that
+does not match the original security configuration used in the initial
+connection.
+
+In order for WLAN Policy to retain the security configuration used for the
+connection to the original AP, it must first obtain it, so SME
+`ConnectTransaction.ConnectResult` MUST gain a new field that informs WLAN
+Policy of the exact security configuration that was used in the original
+association request.
+
+Upon receipt of a `ClientSme.Roam` from WLAN Policy, SME behaves the same as if
+it had received a `RoamStartInd` from MLME, except that it sends a `RoamReq`
+down to MLME (**step 2**).
+
+Upon receipt of a `RoamReq` from SME, MLME behaves the same as if it had
+received a `RoamStartInd` from Fullmac, except that it sends a `RoamReq` down to
+Fullmac (**steps 3 and 4**).
+
+Upon receipt of a `RoamReq` from MLME, Fullmac sends commands to the firmware to
+begin the authentication and reassociation processes (**step 5**), and then the
+firmware does just as it would for a Fullmac-initiated roam (**step 6**). When
+the firmware notifies the Fullmac driver of the result of the roam attempt
+(**step 7**), Fullmac sends a `RoamConf` up to MLME (**steps 8 and 9**).
+`RoamConf` is similar to `RoamResultInd`.
+
+Upon receipt of `RoamConf`, MLME behaves the same as if it had received a
+`RoamResultInd`, except that it sends a `RoamConf` up to SME (**step 10**).
+
+Upon receipt of `RoamConf`, SME behaves the same as if it had received a
+`RoamResultInd` from MLME. SME sends an `OnRoamResult` to WLAN Policy over the
+`ConnectTransaction` (**step 11**).
+
+Upon receipt of `OnRoamResult`, WLAN Policy takes the same actions as those
+discussed above at the end of a Fullmac-initiated roam.
+
+## Implementation
+
+### Phase 1: API and logic introduced without pushing to production devices
+
+The API changes can be made in two Gerrit changes: one for Fullmac-initiated
+roam, and another for WLAN Policy-initiated roam.
+
+The strategy for roaming changes so far has been to introduce the roaming logic
+changes, without enabling them on production devices. Fullmac-initiated roaming
+is guarded by a driver feature in the brcmfmac driver. There are unit and
+integration tests to ensure that the roaming features are disabled, to prevent
+the feature from being accidentally enabled.
+
+For WLAN Policy-initiated roaming, the API can be introduced without anything
+calling the SME `ClientSme.Roam`/`ConnectTransaction.OnRoamResult` API until
+WLAN Policy is confident that it can be enabled. Once the API is present, WLAN
+Policy can begin using roam success/failure as an input to its connection
+quality tracking, and WLAN Policy logic can decide whether to use the
+`ClientSme.Roam` API for a specific AP, or even whether to use the
+`ClientSme.Roam` API at all.
+
+WLAN Policy MUST have the ability to enable or disable roaming features at
+interface creation time. This allows WLAN Policy to:
+
+*   know that Fullmac-initiated roaming is enabled or disabled on a specific
+    interface
+*   fully disable roaming features on an interface in case of a runtime problem
+
+A simple API change to `fuchsia.wlan.device` is necessary to support this need.
+A minimal implementation requires adding a single field to `CreateIfaceRequest`
+to allow the caller to specify the roaming feature(s) that must be enabled
+during interface creation.
+
+Note that for Fullmac interfaces, existing firmware can only enable features
+like roaming offloads at interface creation time.
+
+### Phase 2: Integration testing
+
+For Fullmac-initiated roaming, the change can be tested on local developer
+builds (e.g. by uncommenting roaming features in the brcmfmac Fullmac driver
+code), and can be integration tested on real device and AP hardware using
+[Antlion](https://fuchsia.googlesource.com/antlion). There is already an Antlion
+integration test suite for Fullmac-initiated roaming
+(`WlanWirelessNetworkManagementTest`), which tests successful and unsuccessful
+roaming attempts. The existing test suite requires a Fuchsia Fullmac-capable
+device that is instrumented to roam between two networks on a single physical AP
+device. Increasing integration coverage via a new Antlion test suite for
+additional Fullmac-initiated roaming scenarios is also expected.
+
+For WLAN Policy-initiated roaming, the changes can be tested on local developer
+builds, and can be integration tested on real device and AP hardware using
+Antlion (by giving WLAN Policy the ability to enable roaming on an interface at
+runtime, see discussion in phase 1 above). Increasing integration coverage via a
+new Antlion test suite for additional WLAN Policy-initiated roaming scenarios is
+also expected.
+
+Antlion test suites that exercise Fullmac-initiated or WLAN Policy-initiated
+roaming MUST know whether those features are in use on the Fuchsia
+device-under-test (DUT). This is necessary because Antlion needs to know whether
+to run or skip roaming tests on that DUT. For the existing Fullmac-initiated
+roaming test suite, Antlion configuration has special directives for WLAN
+features: presence of a roaming feature in the Antlion config tells Antlion to
+run Fullmac-initiated roaming tests, otherwise those tests are skipped. The
+implementation SHOULD give Antlion the explicit ability to query for feature
+support (using WLAN Driver Features), and SHOULD give Antlion the explicit
+ability to enable roaming features on a DUT before running tests on that DUT.
+
+The existing Fullmac-initiated roaming Antlion test suite, as well as any new
+test suites, MUST be runnable on Connectivity Automation testbeds with a WLAN
+Antlion testbed.
+
+A Fullmac-initiated roaming capable WLAN testbed:
+
+*   MUST contain at least one Fullmac-initiated roaming capable physical Fuchsia
+    device
+*   MUST contain Antlion-compatible physical AP device(s) capable of providing
+    two or more simultaneous APs (in 802.11 terms, two or more BSSs within the
+    same ESS)
+*   SHOULD allow for variable signal attenuation
+*   MAY enclose devices in radio shields to decrease interference
+
+When such a testbed is available, developers will be able to these tests against
+run work-in-progress changes using existing Antlion tryjobs infrastructure.
+
+Deeper integration testing (e.g. using a third-party lab for testing roaming
+scenarios) is likely to be used as well.
+
+### Phase 3: Rollout to production devices
+
+Pending the outcome of integration testing, rollout can begin. WLAN Policy MUST
+have the ability to enable and disable roaming features on a per-interface
+basis, as discussed in phase 1 above.
+
+Rollout of Fullmac-initiated and WLAN Policy-initiated roaming will be
+controlled by WLAN Policy, using WLAN Policy's typical feature rollout
+mechanisms (or a new rollout mechanism, at their option). WLAN Policy already
+has logic for connection selection, connection quality, and recovery from
+connection failure. WLAN Policy frequently makes changes to these functions in
+the usual course of operation. It is likely that additional runtime safeguards
+specific to roaming will be introduced by WLAN Policy, but this RFC does not
+endeavor to specify them.
+
+## Performance
+
+Metrics that we will need to evaluate during the rollout phase include:
+
+*   Roam attempt / roam success, as counts and rate
+*   Roam time to complete, as histogram
+*   Roam timeout, as count and rate
+*   Roam success followed by unusable interface, as count
+*   Roam failure reason, broken down by `DisconnectInfo` (roughly, disconnect
+    source and reason)
+*   Periods of excessive roaming
+
+We will need to monitor metrics that are not roaming-specific as well:
+
+*   non-roaming disconnect counts (should not increase significantly)
+*   uptime ratio (should not decrease significantly)
+*   number of idle interface autoconnects (should not increase significantly)
+
+## Ergonomics
+
+This RFC does not specify any end user control of roaming. Other operating
+systems provide end users no control over roaming (e.g. MacOS), or very limited
+control via special configuration (e.g. Windows, Linux). At this time we do not
+expect WLAN Policy to provide an end user control for roaming. Therefore,
+Fuchsia end users do not take on significant cognitive load from the
+introduction of Fullmac-initiated or WLAN Policy-initiated roaming. The only
+expected user visible effect is that some transitions between access points will
+be faster. To the end user, a failed roam will be indistinguishable from any
+other connection interruption, and the recovery from the interruption will be
+just like a connection interruption that did not involve roaming: a regular scan
+and connect.
+
+## Backwards Compatibility
+
+The 802.11 spec has included roaming (reassociation) since long before Fuchsia
+existed.
+
+The primary concern for backwards compatibility is that the introduction of
+roaming does not frequently cause a working network connection to become
+unusable, for the many existing devices that use Fuchsia WLAN. As the rollout
+section above mentions, giving WLAN Policy the ability to explicitly decide when
+to enable and use roaming features will go a long way to ensure that the use of
+roaming features does not leave interfaces in a degraded or unusable state. WLAN
+Policy MAY:
+
+*   throttle roam scans
+*   denylist problematic APs
+*   implement backoff to throttle roam attempts
+*   disable roaming at runtime
+
+## Security considerations
+
+Three security concerns exist:
+
+*   original AP and target AP MUST have the same SSID
+*   the target AP must match the security parameters that were specified in the
+    connection to the original AP
+*   decision of which AP to connect to has always been the purview of WLAN
+    Policy; Fullmac-initiated roaming delegates some of this responsibility to
+    Fullmac firmware
+
+WLAN SME already validates that SSID and security parameters match the original
+security configuration, and the same mechanism will be used to validate them for
+the target AP. Failure of these validation steps results in tearing down the
+connection. See [Appendix D](#appendix-d) for more detail on the security
+configuration used in a roam attempt.
+
+As for responsibility for choosing an AP:
+
+*   For Fullmac-initiated roaming, if the Fullmac firmware has found a suitable
+    AP to roam to, we have explicitly given it the ability to roam to it. And in
+    the course of completing the roam, WLAN SME will validate that the AP is
+    suitable for the original security configuration (as described in
+    [Appendix D](#appendix-d)).
+*   For WLAN Policy-initiated roaming, WLAN Policy is already in charge of
+    deciding which AP to connect to. WLAN Policy-initiated roaming only provides
+    a different mechanism for connecting to a target AP (using 802.11
+    reassociation, rather than 802.11 association).
+
+## Privacy considerations
+
+This design provides the API that allows Fullmac and WLAN Policy to initiate a
+roam and learn of the roam result. These actions incur use of the same
+information already used for existing (non-roaming) connection and disconnection
+logic. This design does not alter the current privacy posture of WLAN software.
+
+## Testing
+
+*   Unit tests already exist for Fullmac driver (using the brcmfmac Sim
+    Framework)
+*   Integration tests on real device and AP hardware already exist for
+    Fullmac-initiated roaming (using the Antlion
+    WlanWirelessNetworkManagementTest suite)
+*   Further integration tests will be created that exercise roaming scenarios
+    for Fullmac-initiated and WLAN Policy-initiated roaming
+*   Connectivity Automation will use these Antlion tests in their lab facilities
+*   Third party roaming tests may also be used
+
+## Documentation
+
+FIDL changes will include significant documentation for new messages, fields,
+and methods. Additional documentation beyond the inline documentation is not
+planned.
+
+## Drawbacks, alternatives, and unknowns
+
+### BSSID Blocklist extension
+
+Fullmac-initiated roaming is likely to require a BSSID blocklist API (similar to
+the one that exists in Android), allowing WLAN Policy to specify certain APs
+that should not be connected to. This would allow WLAN Policy to avoid a
+situation where the Fullmac firmware repeatedly roams to an AP that WLAN Policy
+knows is not functional.
+
+### Whether to share control between Fullmac and WLAN Policy
+
+This RFC specifies that WLAN Policy will have control over whether a Fullmac
+interface has roaming logic enabled. The expectation is that either Fullmac or
+WLAN Policy is in control of roaming logic for an interface, but probably not
+both. A situation where both Fullmac and WLAN Policy are simultaneously
+initiating roam attempts might cause "thrashing" between APs if Fullmac and WLAN
+Policy disagree about which AP is best. A BSSID Blocklist API would give WLAN
+Policy the ability to set a "guardrail" on Fullmac's roaming decisions, without
+having more than one initiator of roaming decisions. If we decide that there is
+a valid reason to have both Fullmac and WLAN Policy initiating roam attempts,
+this will require additional design.
+
+### Disconnect behavior {#disconnect-behavior}
+
+Very careful analysis of disconnect scenarios is ongoing. We need to be
+confident that WLAN is resilient in the face of disconnects that occur during
+periods of ambiguity (e.g. when Fullmac knows that the roam has started, but
+higher layers like SME do not).
+
+The current disconnection logic in SME attempts to deauthenticate from the AP as
+a cleanup measure in most disconnection scenarios. When a roam attempt causes
+the device to leave the channel (or even band) of the original AP:
+
+*   Fullmac may not know whether the device is still authenticated with the
+    original AP
+*   because Fullmac doesn't know, Fullmac cannot inform SME whether the device
+    is conclusively still authenticated with the original AP in some cases
+*   if SME decides during its cleanup to request deauthentication from the
+    original AP (by sending a deauthenticate request to Fullmac), this
+    deauthenticate request may not be serviceable by Fullmac, because Fullmac
+    may be unable to reach the original AP
+
+In this and other cases that involve disconnects, we may discover that we need
+different disconnect behavior at the Fullmac and/or SME layers.
+
+### Interactions with existing "reconnect" logic in WLAN Policy and SME
+
+WLAN Policy and SME have existing "reconnect" behaviors, where re-establishing a
+previously working connection is attempted. For example, when a connection is
+disassociated but not deauthenticated, SME can preserve the `ConnectTransaction`
+protocol between WLAN Policy and SME while SME attempts to associate to the AP.
+If the SME reconnect succeeds, SME was able to skip the authentication overhead
+and reduce the disconnected time. Behaviors like this will likely need to be
+scrutinized for how they interact with roaming. As a hypothetical example, there
+may be cases where we discover that we need to deauthenticate more aggressively
+during or after roam attempts in order to prevent reconnects from encountering
+problems after a failed roam attempt. We may also find that we need to change
+the timing of reconnects, or adjust other parameters.
+
+### Interactions with DHCP and layer 3 management {#layer-3-interactions}
+
+WLAN software manages the data link layer, also known as "layer 2." Above layer
+2 is the network layer, also known as "layer 3," which is managed by DHCP,
+Netstack, Network Policy, and other management software. When a roam attempt
+occurs, disruptions in layer 2 and layer 3 are likely:
+
+*   a brief pause in the flow of layer 2 traffic is likely, for the duration
+    that the device is disconnected from the original AP but not yet fully
+    connected to the target AP
+*   roam attempts cause the 802.1X controlled port to close, which will cause a
+    layer 3 link down, followed by a link up if the attempt succeeds
+
+In Fuchsia, a layer 3 link down currently causes a full DHCP client teardown and
+init. This may go unnoticed by the user, or may result in user-visible loss of
+IP connectivity. This "layer 2 disruption causing layer 3 disruption" scenario
+is not unique to roaming: a disconnect followed by a connect (even to the same
+AP) causes a full DHCP client teardown and init now.
+
+This layer 3 disruption could be reduced with additional design (outside the
+scope of this RFC) to:
+
+*   give layer 3 software the option of optimizing for layer 2 disruptions that
+    are expected to provide the same layer 3 connectivity, by providing enough
+    information about the layer 2 disruption to layer 3 software
+*   decide on the right checks to verify layer 3 connectivity (e.g. DNAv4, ARP
+    probe, DHCP actions, existing or new reachability checks) to use when such a
+    layer 2 disruption occurs
+*   coordinate the logic for performing these layer 3 checks, backed by a
+    fallback to full DHCP client teardown and init when necessary
+
+The exact mechanism(s), post-roam verifications, and logic needed would have to
+be worked out. Android has some prior art here (see
+[Android updateLayer2Information](#prior-art)), and IETF RFCs for DNAv4 and
+DNAv6 also cover this problem space (see [DNAv4 and DNAv6](#prior-art)).
+
+## Prior art and references {#prior-art}
+
+*   [Android Wi-Fi Network Selection](https://source.android.com/docs/core/connect/wifi-network-selection)
+*   [Android SSID and BSSID Blocking](https://source.android.com/docs/core/connect/wifi-network-selection#ssid-bssid-blocking)
+*   [Android updateLayer2Information](https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Wifi/service/java/com/android/server/wifi/ClientModeImpl.java?q=symbol%3A%5Cbcom.android.server.wifi.ClientModeImpl.updateLayer2Information%5Cb%20case%3Ayes)
+*   DNAv4 and DNAv6:
+    *   [Detecting Network Attachment in IPv4 (DNAv4)](https://www.ietf.org/rfc/rfc4436.txt)
+    *   [Simple Procedures for Detecting Network Attachment in IPv6](https://www.ietf.org/rfc/rfc6059.txt)
+*   [Linux cfg80211 subsystem](https://docs.kernel.org/driver-api/80211/cfg80211.html#)
+    (see documentation of functions connect and cfg80211_roamed)
+*   [macOS wireless roaming for enterprise customers](https://support.apple.com/en-us/102002)
+*   [Microsoft WifiCx OID_WDI_TASK_ROAM](https://learn.microsoft.com/en-us/windows-hardware/drivers/netcx/oid-wdi-task-roam)
+*   [wpa_supplicant Developers' documentation](https://w1.fi/wpa_supplicant/devel/#_wpa_supplicant)
+    (though little proper documentation exists)
+
+## Appendix A: Looking ahead to Fast BSS Transition {#appendix-a}
+
+Fast BSS Transition is not currently supported in Fuchsia WLAN. Fast BSS
+Transition allows a device to move its association to the target AP, with RSNA
+intact. When Fast BSS Transition becomes supported by WLAN, a few behaviors will
+change and the current design takes these behavior changes into account.
+
+At initial connection time, WLAN Policy will need to see one (or more)
+additional information elements (abbreviated IE) that are specific to Fast BSS
+Transition support. It is likely these would be communicated to WLAN Policy
+within SME `ConnectTransaction.ConnectResult` (similar to the way this RFC
+specifies that security config is communicated to WLAN Policy). Fast BSS
+Transition APs advertise a "mobility domain" IE that the device can use to
+identify other APs that accept Fast BSS Transitions from the current AP.
+
+At the start of a roam that specifies that Fast BSS Transition is in use, WLAN
+MUST retain associated state and RSNA with the original AP. This is true whether
+the roam is Fullmac-initiated by `RoamStartInd` or WLAN Policy-initiated by
+`RoamReq`. One important ramification is that MLME will not close the controlled
+port at the start of a Fast BSS Transition roam. The original connection will
+continue as usual, while the new connection is being established via Fast BSS
+Transition. If the Fast BSS Transition roam succeeds and
+`original_association_maintained` is true:
+
+*   MLME MUST keep the 802.1X controlled port open
+*   because the controlled port was never closed, the device may only experience
+    a brief pause in layer 2 (observed to take approximately 20 ms) with no IP
+    connectivity disruption
+
+If the roam attempt fails (or reaches a roam attempt timeout):
+
+*   `RoamResultInd`/`RoamConf` `original_association_maintained` specifies
+    whether the association with the original AP has been maintained throughout
+    the unsuccessful roam attempt
+*   Fullmac SHOULD NOT initiate a disconnect if the original association has
+    been maintained (but there may be cases where the driver knows that recovery
+    from the failure/timeout requires a disconnect)
+
+If MLME sends a `RoamResultInd`/`RoamConf` to SME indicating that a Fast BSS
+Transition roam failed:
+
+*   SME MUST transition from *Roaming* to *Associated* with the original AP
+*   if `target_bss_authenticated` is true, SME MAY request deauthentication from
+    the target AP (see [Disconnect behavior](#disconnect-behavior) for some
+    subtle details)
+
+When Fast BSS Transition is supported, WLAN Policy will be able to maintain the
+existing `ConnectTransaction` with the original AP even after WLAN Policy
+receives an `OnRoamResult` that indicates a failed Fast BSS Transition roam
+attempt.
+
+Fast BSS Transition will also add another consideration to
+[Interactions with DHCP and layer 3 management](#layer-3-interactions): some
+successful roam attempts will not close the 802.1X controlled port during the
+attempt, so there will be no layer 3 link down. Without a layer 3 link down
+followed by a layer 3 link up, layer 3 management software will need some other
+signal to know that post-roam verification actions should occur.
+
+Another ramification is that various state machines (MLME, SME, WLAN Policy)
+will need to maintain state for more than one AP. While this can be done by
+adding fields to existing states, it's likely that refactoring these state
+machines to be multiple-BSS aware will become more attractive once Fast BSS
+Transition is on the horizon. A quick look at the SME client state machine
+illustrates the quality of changes that might be necessary:
+
+*   At start of a Fast BSS Transition roam, SME will need to model the fact that
+    the device is still associated with RSNA on the original AP, while also
+    modeling that the device is authenticating with the target AP
+*   When authentication with the target AP is complete, SME needs to model that
+    the device is still associated with RSNA on the original AP, while it is
+    reassociating to the target AP
+*   At completion of a successful Fast BSS Transition roam:
+    *   the device will move to 802.11 *associated with RSNA* state (see IEEE
+        802.11-2020 11.3.1) with the target AP
+    *   the device will drop to *authenticated* state with the original AP
+    *   the device may subsequently lose *authenticated* state with the original
+        AP, e.g. by the original AP sending the device a deauthenticate
+        indication; but this does not affect the connection with the target AP
+*   At a completion of a failed Fast BSS Transition roam attempt, the resulting
+    device state is more complicated:
+    *   if the failure occurred before the device lost its association with the
+        original AP, the device is still *associated with RSNA* on the original
+        AP, and may be *authenticated* with the target AP
+    *   if the failure happened after the device lost its association with the
+        original AP, the device is no longer *associated* to any AP, and may be
+        *authenticated* with the original AP and/or the target AP
+
+## Appendix B: Looking ahead to fallback-capable roaming {#appendix-b}
+
+802.11 specifies that a device can be authenticated with multiple APs, but it
+can only be associated with a single AP at any given time. When a roam attempt
+fails, the device is still authenticated with the original AP, unless a
+deauthentication indication has been received from the original AP. This means
+that the SME could maintain enough state with the original AP to allow it to
+transition from *Roaming* state back into *Connecting* state, skipping the
+authentication process with the original AP. This would shorten the time to get
+back to associated state with the original AP. This was prototyped by adding two
+new states to the SME client state machine:
+
+*   *Roaming*, as described in this RFC
+*   *RoamingWithFallback*, which retains enough state about the original AP to
+    go back into *Connecting* state with the original AP upon roam failure
+
+This prototype of a fallback-capable SME client state machine is not currently
+being pursued. After discussion with WLAN Core team, the general consensus was
+that implementing fallback-capable roaming would be easier if the SME client
+state machine were refactored to explicitly keep state for multiple APs. There
+may also be Fullmac firmware limitations to contend with--some firmware requires
+that the Fullmac driver disconnect and reset the firmware state upon a roam
+failure, which may preclude the ability to fallback.
+
+If we decide to implement fallback-capable roaming, it can coexist with Fast BSS
+Transition. Fallback-capable roaming endeavors to keep authenticated state with
+the original AP; while Fast BSS Transition endeavors to keep associated state
+and RSNA. We could use both Fast BSS Transition and fallback-capable roaming, or
+just one of them, or neither.
+
+## Appendix C: Looking ahead to roaming on Softmac {#appendix-c}
+
+A "Softmac" WLAN device differs from Fullmac in one important way. A Fullmac
+device has most of the 802.11 MLME logic implemented in firmware, while a
+Softmac device has most of the WLAN MLME logic implemented in driver software.
+Because Fullmac handles construction and parsing of reassociation frames,
+orchestrates the roaming process, and can even decide when and where to roam,
+the Fullmac API needs significant changes for roaming (i.e. this RFC). But in
+Softmac, the API and logic changes required for roaming support are likely to be
+different in nature:
+
+*   It is likely that WLAN Policy's roaming control logic (not described in this
+    RFC) will be used to decide when and where to roam, rather than implementing
+    separate logic for this in the Softmac driver or in Fuchsia MLME/SME
+*   Logic for constructing and parsing 802.11 reassociation frames, and
+    orchestrating the roaming process, is likely to be implemented in MLME
+    rather than adding more to the Softmac API surface
+*   Softmac must keep track of the current channel for many reasons, and since a
+    roam attempt may change the channel or band, this logic may need to be
+    adjusted
+*   All of this comes with the caveat that no prototyping of Softmac roaming has
+    been undertaken, so it's possible that we may encounter Softmac firmware
+    that requires a different approach
+
+## Appendix D: Reassociation security configuration {#appendix-d}
+
+When a device roams (via reassociation), the security configuration specified in
+the reassociation request frame MUST be the same security configuration that was
+used for the original connection (see IEEE 802.11-2020 11.3.5.4). This
+requirement merits a deeper discussion of how this affects the API changes
+specified in this RFC.
+
+WLAN Policy stores saved networks, which are specified in `NetworkConfig` which
+aims to represent them in human-understandable terms:
+
+*   SSID
+*   high level protection type for the networks (e.g. WPA2, or WPA3, but not the
+    many possible variations within those broad types)
+*   credentials (e.g. password)
+
+When WLAN Policy decides to connect to a specific AP, WLAN Policy sends SME a
+`ConnectRequest` which contains additional details about the AP:
+
+*   BSS Description for the AP that the device should connect to
+*   802.11 authentication type (e.g. 802.11 open authentication, or WPA3 SAE)
+
+SME then:
+
+*   compares this more detailed specification to the security configuration(s)
+    offered by the AP (contained in the BSS Description)
+*   decides on the security configuration that will be included in the
+    association request
+*   generates the exact bytes that will be sent to the AP in the association
+    request
+    *   for example, for a WPA2 network SME generates an RSNE information
+        element
+    *   that RSNE might have the RSN capabilities `MFPR` bit set to 1, meaning
+        that management frame protection (MFP, see IEEE 802.11-2020 9.4.2.24.4)
+        is required, so the device will not join a network that doesn't support
+        MFP
+    *   or SME might have set `MFPR` to 0 (meaning not required), while setting
+        `MFPC` to 1, meaning that the device can join a network regardless of
+        whether MFP is supported or required on that network
+*   propagates this security configuration down into MLME, and eventually into
+    the Fullmac firmware that will send the association request to the AP
+
+The association will only succeed if the AP security configuration can match
+against the SME-specified security configuration (see IEEE 802.11-2020 12.6.3
+for how this works). IEEE 802.11-2020 11.3.5.4 REQUIRES that the same RSNE that
+was included in the original association request is used in any subsequent
+reassociation (roam) requests.
+
+For Fullmac-initiated roam attempts, this does not impose any need for any
+additional API. SME decides the security configuration that will be used in the
+original association request, Fullmac stores this configuration, and Fullmac
+uses this security configuration for any roam attempts. Because WLAN Policy is
+not choosing the target AP, WLAN Policy never needs to know the security
+configuration for Fullmac-initiated roam attempts in this case.
+
+But for WLAN Policy-initiated roaming, there is a need for WLAN Policy to know
+the SME-specified security configuration that was used to connect to the
+original AP, because:
+
+*   WLAN Policy is going to choose a target AP for the roam attempt
+*   but if WLAN Policy does not know the SME-specified security configuration
+    that was included in the original association request, it cannot know for
+    sure that the AP it picks will match the original security configuration
+*   if WLAN Policy picks an incompatible target AP, the roam will fail
+
+The solution is to add a field to SME `ConnectResult` that will share the
+security IE with WLAN Policy at initial connection time.
+
+If we discover that there are cases where Fullmac firmware uses a different
+security configuration during a roam:
+
+*   SME SHOULD almost certainly fail the roam rather than take a risk that the
+    security configuration is less secure than the original security
+    configuration; and SME should complain loudly
+*   WLAN Policy SHOULD almost certainly disable roaming for that device to
+    prevent this from occurring again; and WLAN Policy should complain loudly
+
+If we discover a need for changing security configuration during a roam, we will
+have to evaluate that need against the security configuration invariant imposed
+by IEEE 802.11-2020 11.3.5.4. Considering that previous revisions of 802.11 did
+not clarify this question, it is possible that we will encounter Fullmac
+firmware which does not uphold the invariant. If we discover a case that we need
+to support, we could add API fields/methods to explicitly allow WLAN Policy to
+get and/or set the security configuration.
+
+We may also discover that we want WLAN to uphold stronger security guarantees
+than just the 802.11 spec-imposed constraints. For WLAN Policy-initiated
+roaming, WLAN Policy will be free to enforce stronger security by choosing only
+APs that match stricter security criteria than what was used in the initial
+connection, still subject to the SME validation that security parameters match
+the original security configuration. For Fullmac-initiated roaming, it is likely
+that a driver API would need to be introduced to allow changing the
+association/reassociation request IEs, and/or firmware would have to be modified
+with additional configuration options to provide this behavior.
diff --git a/docs/contribute/governance/rfcs/_rfcs.yaml b/docs/contribute/governance/rfcs/_rfcs.yaml
index c2b02ba..7d899f6 100644
--- a/docs/contribute/governance/rfcs/_rfcs.yaml
+++ b/docs/contribute/governance/rfcs/_rfcs.yaml
@@ -3140,3 +3140,42 @@
   reviewers: ['abarth@google.com', 'cpu@google.com', 'maniscalco@google.com']
   submitted: '2024-02-06'
   reviewed: '2024-03-11'
+
+- name: 'RFC-0241'
+  title: 'Explicit Platform / External Split in SDK Interfaces'
+  short_description: 'Expressing more precisely which parts of the Fuchsia interface can be implemented outside of the Fuchsia platform.'
+  authors: ['ianloic@google.com']
+  file: '0241_explicit_platform_external.md'
+  area: ['FIDL']
+  issue: ['335446415']
+  gerrit_change_id: ['982353']
+  status: 'Accepted'
+  reviewers: ['abarth@google.com', 'chaselatta@google.com', 'hjfreyer@google.com', 'mkember@google.com']
+  submitted: '2024-01-29'
+  reviewed: '2024-04-09'
+
+- name: 'RFC-0242'
+  title: 'Configuration Capabilities'
+  short_description: "Adding Configuration Capabilities to the Component Framework"
+  authors: ['dgilhooley@google.com']
+  file: '0242_configuration_capabilities.md'
+  area: ['Component Framework']
+  issue: ['']
+  gerrit_change_id: ['986276']
+  status: 'Accepted'
+  reviewers: ['aaronwood@google.com', 'geb@google.com', 'markdittmer@google.com', 'surajmalhotra@google.com', 'wittrock@google.com']
+  submitted: '2024-02-05'
+  reviewed: '2024-04-11'
+
+- name: 'RFC-0243'
+  title: 'WLAN Roaming'
+  short_description: 'A device that is connected to a wireless network where there are multiple access points will gain the ability to roam between them. "Roam" means the device moves its connection from one access point (AP) to another AP within the same wireless network, without incurring a full disconnection during the transition.'
+  authors: ['karlward@google.com']
+  file: '0243_wlan_roaming.md'
+  area: ['WLAN']
+  issue: ['']
+  gerrit_change_id: ['961555']
+  status: 'Accepted'
+  reviewers: ['haydennix@google.com', 'karthikrish@google.com', 'sbalana@google.com', 'silberst@google.com', 'swiggett@google.com']
+  submitted: '2023-12-15'
+  reviewed: '2024-04-11'
diff --git a/docs/contribute/governance/rfcs/_toc.yaml b/docs/contribute/governance/rfcs/_toc.yaml
index 17205896..ee543c3 100644
--- a/docs/contribute/governance/rfcs/_toc.yaml
+++ b/docs/contribute/governance/rfcs/_toc.yaml
@@ -496,3 +496,10 @@
     path: /docs/contribute/governance/rfcs/0239_platform_versioning_in_practice.md
   - title: "RFC-0240: Asynchronous operations are on objects"
     path: /docs/contribute/governance/rfcs/0240_async_ops_are_on_objects.md
+  - title: "RFC-0241: Explicit Platform / External Split in SDK Interfaces"
+    path: /docs/contribute/governance/rfcs/0241_explicit_platform_external.md
+  - title: "RFC-0242: Configuration Capabilities"
+    path: /docs/contribute/governance/rfcs/0242_configuration_capabilities.md
+  - title: "RFC-0243: WLAN Roaming"
+    path: /docs/contribute/governance/rfcs/0243_wlan_roaming.md
+
diff --git a/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/fullmac_initiated_roam.png b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/fullmac_initiated_roam.png
new file mode 100644
index 0000000..6a13f2ac
--- /dev/null
+++ b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/fullmac_initiated_roam.png
Binary files differ
diff --git a/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_fullmac_initiated_roam.png b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_fullmac_initiated_roam.png
new file mode 100644
index 0000000..1791db4
--- /dev/null
+++ b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_fullmac_initiated_roam.png
Binary files differ
diff --git a/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_overview.png b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_overview.png
new file mode 100644
index 0000000..3f5055d
--- /dev/null
+++ b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_overview.png
Binary files differ
diff --git a/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_wlan_policy_initiated_roam.png b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_wlan_policy_initiated_roam.png
new file mode 100644
index 0000000..b4cc1e6
--- /dev/null
+++ b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/sme_state_changes_wlan_policy_initiated_roam.png
Binary files differ
diff --git a/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/wlan_policy_initiated_roam.png b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/wlan_policy_initiated_roam.png
new file mode 100644
index 0000000..bd458bf
--- /dev/null
+++ b/docs/contribute/governance/rfcs/resources/0243_wlan_roaming/wlan_policy_initiated_roam.png
Binary files differ
diff --git a/docs/development/bluetooth/concepts/architecture.md b/docs/development/bluetooth/concepts/architecture.md
index 0906900..9d6cffa 100644
--- a/docs/development/bluetooth/concepts/architecture.md
+++ b/docs/development/bluetooth/concepts/architecture.md
@@ -79,7 +79,7 @@
 a management interface to designate an active adapter when multiple adapters are
 present.
 
-bt-host devices implement the [host.fidl](/src/connectivity/bluetooth/fidl/host.fidl)
+bt-host devices implement the [host.fidl](/sdk/fidl/fuchsia.bluetooth.host/host.fidl)
 protocol to communicate with the Bluetooth system service.
 
 
diff --git a/docs/development/drivers/developer_guide/write-a-minimal-dfv2-driver.md b/docs/development/drivers/developer_guide/write-a-minimal-dfv2-driver.md
index 14f5807..a92f59f 100644
--- a/docs/development/drivers/developer_guide/write-a-minimal-dfv2-driver.md
+++ b/docs/development/drivers/developer_guide/write-a-minimal-dfv2-driver.md
@@ -464,14 +464,11 @@
                      .properties(arena, std::move(properties))
                      .Build();
 
-     zx::result controller_endpoints =
-         fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-     ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                   controller_endpoints.status_string());
-     controller_.Bind(std::move(controller_endpoints->client));
+     auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
+     controller_.Bind(std::move(controller_endpoints.client));
 
      fidl::WireResult result =
-         fidl::WireCall(node())->AddChild(args, std::move(controller_endpoints->server), {});
+         fidl::WireCall(node())->AddChild(args, std::move(controller_endpoints.server), {});
      if (!result.ok()) {
        FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
        return completer(result.status());
diff --git a/docs/development/drivers/migration/migrate-from-banjo-to-fidl/convert-banjo-protocols-to-fidl-protocols.md b/docs/development/drivers/migration/migrate-from-banjo-to-fidl/convert-banjo-protocols-to-fidl-protocols.md
index a7205e7..659cd03 100644
--- a/docs/development/drivers/migration/migrate-from-banjo-to-fidl/convert-banjo-protocols-to-fidl-protocols.md
+++ b/docs/development/drivers/migration/migrate-from-banjo-to-fidl/convert-banjo-protocols-to-fidl-protocols.md
@@ -219,8 +219,8 @@
    #include <lib/fdf/cpp/channel.h>
    #include <lib/fdf/cpp/channel_read.h>
    #include <lib/fdf/cpp/dispatcher.h>
-   #include <lib/fidl/llcpp/connect_service.h>
-   #include <lib/fidl/llcpp/vector_view.h>
+   #include <lib/fidl/cpp/wire/connect_service.h>
+   #include <lib/fidl/cpp/wire/vector_view.h>
    ...
    ```
 
@@ -537,10 +537,10 @@
   above) needs to be implemented on the server end (see
   `MyExampleFunction()` below).
 
-  When the server end device class inherits the
-  `fdf::WireServer<ProtocolName>` object, virtual functions based on
-  your protocol definition are generated, similar to LLCPP. The following
-  is the format of this function:
+  When the server end device class inherits the `fdf::WireServer<ProtocolName>`
+  object, virtual functions based on your protocol definition are generated,
+  similar to `fidl::WireServer<ProtocolName>`. The following is the format of
+  this function:
 
   ```cpp
   void MyExampleFunction(MyExampleFunctionRequestView request, fdf::Arena& arena, MyExampleFunctionCompleter::Sync& completer);
@@ -802,7 +802,7 @@
 - [Banjo][banjo]
 - [FIDL][fidl]
 - [RFC-0126: Driver Runtime][driver-runtime-rfc]
-- [New C++ bindings tutorials][llcpp]
+- [New C++ bindings tutorials][cpp-tutorial]
 - [Driver dispatcher and threads][driver-dispatcher]
 - [FIDL attributes][fidl-attributes]
 - [Implement a C++ FIDL server][implement-fidl-server]
@@ -824,7 +824,7 @@
 [fidl]: /docs/concepts/fidl/overview.md
 [migrate-from-dfv1-to-dfv2]: /docs/development/drivers/migration/migrate-from-dfv1-to-dfv2/overview.md
 [driver-runtime-rfc]: /docs/contribute/governance/rfcs/0126_driver_runtime.md
-[llcpp]: /docs/development/languages/fidl/tutorials/cpp/README.md
+[cpp-tutorial]: /docs/development/languages/fidl/tutorials/cpp/README.md
 [synchronized-dispatchers]: /docs/concepts/drivers/driver-dispatcher-and-threads.md#synchronous-operations
 [wlanofmac-cml]: https://cs.opensource.google/fuchsia/fuchsia/+/main:src/connectivity/wlan/drivers/wlansoftmac/meta/wlansoftmac.cml
 [driver-dispatcher]: /docs/concepts/drivers/driver-dispatcher-and-threads.md
diff --git a/docs/development/drivers/migration/migrate-from-banjo-to-fidl/faq.md b/docs/development/drivers/migration/migrate-from-banjo-to-fidl/faq.md
index f75f24b..587455e 100644
--- a/docs/development/drivers/migration/migrate-from-banjo-to-fidl/faq.md
+++ b/docs/development/drivers/migration/migrate-from-banjo-to-fidl/faq.md
@@ -38,9 +38,9 @@
 communications in the driver take place using FIDL.
 
 The good news is that the syntax of the driver runtime FIDL is similar to
-FIDL [LLCPP][llcpp]. The only difference is that there are some additional
-parameters in the function calls. And the namespace of some classes or
-primitives it uses is `fdf` instead of the original one (for example,
+FIDL [C++ wire bindings][cpp-bindings]. The only difference is that there are
+some additional parameters in the function calls. And the namespace of some
+classes or primitives it uses is `fdf` instead of the original one (for example,
 `fdf::WireServer`), but FIDL wire binding types are still used in data
 transactions (for example, `fidl::VectorView`).
 
@@ -145,7 +145,7 @@
 [fidl]: /docs/concepts/fidl/overview.md
 [migrate-from-dfv1-to-dfv2]: /docs/development/drivers/migration/migrate-from-dfv1-to-dfv2.md
 [driver-runtime-rfc]: /docs/contribute/governance/rfcs/0126_driver_runtime.md
-[llcpp]: /docs/development/languages/fidl/tutorials/cpp/README.md
+[cpp-bindings]: /docs/reference/fidl/bindings/cpp-bindings.md
 [synchronized-dispatchers]: /docs/concepts/drivers/driver-dispatcher-and-threads.md#synchronous-operations
 [wlanofmac-cml]: https://cs.opensource.google/fuchsia/fuchsia/+/main:src/connectivity/wlan/drivers/wlansoftmac/meta/wlansoftmac.cml
 [driver-dispatcher]: /docs/concepts/drivers/driver-dispatcher-and-threads.md
diff --git a/docs/development/drivers/migration/migrate-from-dfv1-to-dfv2/update-driver-interfaces-to-dfv2.md b/docs/development/drivers/migration/migrate-from-dfv1-to-dfv2/update-driver-interfaces-to-dfv2.md
index 9e50be0..a558fa4 100644
--- a/docs/development/drivers/migration/migrate-from-dfv1-to-dfv2/update-driver-interfaces-to-dfv2.md
+++ b/docs/development/drivers/migration/migrate-from-dfv1-to-dfv2/update-driver-interfaces-to-dfv2.md
@@ -95,11 +95,9 @@
                     .name(arena, “example_node”)
                     .Build();
 
-  zx::result controller_endpoints =
-        fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT(controller_endpoints.is_ok());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
-  auto result = node_->AddChild(args, std::move(controller_endpoints->server), {});
+  auto result = node_->AddChild(args, std::move(controller_endpoints.server), {});
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child: %s", result.status_string());
     return zx::error(result.status());
@@ -120,7 +118,7 @@
 void MyExampleDriver::Stop() {
   // controller_endpoints defined in the previous example.
   fidl::WireSyncClient<fuchsia_driver_framework::NodeController>
-       node_controller(controller_endpoints->client);
+       node_controller(controller_endpoints.client);
 
   auto status = node_controller->Remove();
   if (!status.ok()) {
diff --git a/docs/development/languages/fidl/guides/README.md b/docs/development/languages/fidl/guides/README.md
index 7a6ff2c..df82f10 100644
--- a/docs/development/languages/fidl/guides/README.md
+++ b/docs/development/languages/fidl/guides/README.md
@@ -6,8 +6,7 @@
 * [Designing APIs][designing-apis]
 * [Maxing Out Pagination][pagination] &mdash; help on determining how much data
    can fit into a single message
-* [C Family Binding Comparison][c-family] &mdash; how to decide which binding
-  (HLCPP, LLCPP, or C) to use
+* [Comparing new C++ and high-level C++ language bindings][c-family]
 * [Viewing generated code][generated-code] &mdash; how to find the bindings code
   generated by FIDL
 
diff --git a/docs/development/languages/fidl/guides/_toc.yaml b/docs/development/languages/fidl/guides/_toc.yaml
index 10dccf51..eff90a2 100644
--- a/docs/development/languages/fidl/guides/_toc.yaml
+++ b/docs/development/languages/fidl/guides/_toc.yaml
@@ -13,7 +13,7 @@
     path: /docs/development/languages/fidl/guides/api-design.md
   - title: "Maxing out pagination"
     path: /docs/development/languages/fidl/guides/max-out-pagination.md
-  - title: "Picking between LLCPP and HLCPP bindings"
+  - title: "Comparing new C++ and high-level C++ language bindings"
     path: /docs/development/languages/fidl/guides/c-family-comparison.md
   - title: "Viewing generated bindings code"
     path: /docs/development/languages/fidl/guides/generated-code.md
diff --git a/docs/development/languages/fidl/tutorials/cpp/topics/services.md b/docs/development/languages/fidl/tutorials/cpp/topics/services.md
index 09a4005..9f7e972d 100644
--- a/docs/development/languages/fidl/tutorials/cpp/topics/services.md
+++ b/docs/development/languages/fidl/tutorials/cpp/topics/services.md
@@ -1,8 +1,7 @@
 # Using services
 
-Refer to the [example code][code] for how to use services in LLCPP. For
-background and motivation on a FIDL `service`, refer to [RFC-0041][rfc-0041].
+Refer to the [example code][code] for how to use services in the C++ bindings.
+For background and motivation on a FIDL `service, see [RFC-0041].
 
-<!-- xrefs -->
 [code]: /examples/fidl/cpp/services
-[rfc-0041]: /docs/contribute/governance/rfcs/0041_unifying_services_devices.md
+[RFC-0041]: /docs/contribute/governance/rfcs/0041_unifying_services_devices.md
diff --git a/docs/development/tools/fuchsia-controller/getting-started-in-tree.md b/docs/development/tools/fuchsia-controller/getting-started-in-tree.md
index e79bc21..3b966d4 100644
--- a/docs/development/tools/fuchsia-controller/getting-started-in-tree.md
+++ b/docs/development/tools/fuchsia-controller/getting-started-in-tree.md
@@ -125,7 +125,7 @@
 Including the host test data rule will also include the FIDL IR, so no need
 to include both dependencies.
 
-### Add the Python import block {:#add-the-python-imnport-block .numbered}
+### Add the Python import block {:#add-the-python-import-block .numbered}
 
 Once all dependencies are all included, we can add the following libraries
 in the Python main file:
@@ -489,6 +489,87 @@
   the returned object until you're done with it. Otherwise, the task may
   be garbage collected and canceled.
 
+### Experimenting with the Python Interpreter {:.numbered}
+
+If you're unsure of how to construct certain types and you want to skip through
+building and running an executable, it is possible to use the Python interpreter
+to inspect FIDL structures.
+
+To start, you need to make sure you have the prerequisite FIDL libraries built
+and available for use in Python (covered above), as Python will need access to
+the FIDL IR in order to function.
+
+The following commands will change depending on your fuchsia build directory (
+which defaults to `$FUCHSIA_DIR/out/default`):
+
+```sh
+FUCHSIA_BUILD_DIR="$FUCHSIA_DIR/out/default" # Change depending on build dir.
+export FIDL_IR_PATH="$FUCHSIA_BUILD_DIR/fidling/gen/ir_root"
+__PYTHONPATH="$FUCHSIA_BUILD_DIR/host_x64:$FUCHSIA_DIR/src/developer/ffx/lib/fuchsia-controller/python"
+if [ ! -z PYTHONPATH ]; then
+    __PYTHONPATH="$PYTHONPATH:$__PYTHONPATH"
+fi
+export PYTHONPATH="$__PYTHONPATH"
+```
+
+You can then start a python interpreter from anywhere, which will also support
+tab completion so you can inspect various types. For example:
+
+
+```sh {:.devsite-disable-click-to-copy}
+$ python3
+Python 3.11.8 (main, Feb  7 2024, 21:52:08) [GCC 13.2.0] on linux
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import fidl.fuchsia_hwinfo
+>>> fidl.fuchsia_hwinfo.<TAB><TAB>
+fidl.fuchsia_hwinfo.Architecture(
+fidl.fuchsia_hwinfo.Board()
+fidl.fuchsia_hwinfo.BoardGetInfoResponse(
+fidl.fuchsia_hwinfo.BoardInfo(
+fidl.fuchsia_hwinfo.Device()
+fidl.fuchsia_hwinfo.DeviceGetInfoResponse(
+fidl.fuchsia_hwinfo.DeviceInfo(
+fidl.fuchsia_hwinfo.MAX_VALUE_SIZE
+fidl.fuchsia_hwinfo.Product()
+fidl.fuchsia_hwinfo.ProductGetInfoResponse(
+fidl.fuchsia_hwinfo.ProductInfo(
+fidl.fuchsia_hwinfo.fullname
+```
+
+You can then see all values exported by this module. If you would like to
+experiment with async in `IPython`, you can also do the same environment setup
+as above, and execute `IPython`. First, make sure you have it installed:
+
+```sh
+sudo apt install python3-ipython
+```
+
+And then you can run `IPython`. The following example assumes that you run an
+emulator named `fuchsia-emulator` and run from the Fuchsia default build
+directory (otherwise, `"sdk.root"` needs to be changed):
+
+
+```sh {:.devsite-disable-click-to-copy}
+Python 3.11.8 (main, Feb  7 2024, 21:52:08) [GCC 13.2.0]
+Type 'copyright', 'credits' or 'license' for more information
+IPython 8.20.0 -- An enhanced Interactive Python. Type '?' for help.
+
+In [1]: from fuchsia_controller_py import Context
+
+In [2]: import fidl.fuchsia_buildinfo
+
+In [3]: ctx = Context(target="fuchsia-emulator", config={"sdk.root": "./sdk/exported/core"})
+
+In [4]: hdl = ctx.connect_device_proxy("/core/build-info", fidl.fuchsia_buildinfo.Provider.MARKER)
+
+In [5]: provider = fidl.fuchsia_buildinfo.Provider.Client(hdl)
+
+In [6]: await provider.get_build_info()
+Out[6]: ProviderGetBuildInfoResponse(build_info=BuildInfo(product_config='core', board_config='x64', version='2024-04-04T18:15:05+00:00', latest_commit_date='2024-04-04T18:15:05+00:00'))
+
+In [7]:
+```
+
 <!-- Reference links -->
 
 [fuchsia-controller-header-file]: /src/developer/ffx/lib/fuchsia-controller/cpp/abi/fuchsia_controller.h
diff --git a/docs/gen/boot-options.md b/docs/gen/boot-options.md
index 792e0f7..3c70023c 100644
--- a/docs/gen/boot-options.md
+++ b/docs/gen/boot-options.md
@@ -361,6 +361,18 @@
 spent in physboot and it is desirable to exclude this sort of work from
 holistic time measurements.
 
+### kernel.phys.backtrace-max=\<uint32_t>
+
+**Default:** `0x40`
+
+When there is a crash in the kernel's early boot phase, it can print out
+backtraces on the serial console; it prints both a backtrace based on frame
+pointers and, when built to use shadow call stacks also a parallel backtrace
+based on the shadow call stack.  Each backtrace will print no more than this
+many frames.  (Most backtraces will end with the outermost frame before hitting
+the limit.)  Setting the limit to zero prints unlimited frames, which for the
+frame-pointers backtrace can get into an infinite loop with some bugs.
+
 ### kernel.phys.print-stack-max=\<uint32_t>
 
 **Default:** `0x400`
@@ -568,24 +580,6 @@
 presuming that the bootloader provides enough information to know how to disable
 the WDT at all.
 
-### gfxconsole.early=\<bool>
-
-**Default:** `false`
-
-This option requests that the kernel start a graphics console
-during early boot (if possible), to display kernel debug print
-messages while the system is starting.  When userspace starts up, a usermode
-graphics console driver takes over.
-
-The early kernel console can be slow on some platforms, so if it is not
-needed for debugging it may speed up boot to disable it.
-
-### gfxconsole.font=\[9x16 | 18x32\]
-
-**Default:** `9x16`
-
-This option asks the graphics console to use a specific font.
-
 ### kernel.halt-on-panic=\<bool>
 
 **Default:** `false`
@@ -706,6 +700,16 @@
 
 This value should be greater than or equal to `kernel.page-scanner.min-aging-interval`.
 
+### kernel.page-scanner.accessed-scan-interval=\<uint32_t>
+
+**Default:** `0x3`
+
+Sets the time, in seconds, between harvesting page access information. Lower values provide greater
+age fidelity and will improve accuracy of page reclamation choices at the expense of increased CPU
+time spent harvesting.
+
+There is no benefit to setting this to be lower than the `kernel.page-scanner.min-aging-interval`.
+
 ### kernel.page-scanner.active-ratio-multiplier=\<uint32_t>
 
 **Default:** `0x2`
diff --git a/docs/gen/build_arguments.md b/docs/gen/build_arguments.md
index d2b8fec..aced517 100644
--- a/docs/gen/build_arguments.md
+++ b/docs/gen/build_arguments.md
@@ -847,22 +847,6 @@
 
 From //build/info/info.gni:17
 
-### build_libvulkan_img_rgx
-
-Targets that will be built as IMG vulkan ICDS.
-
-**Current value (from the default):** `[]`
-
-From //src/graphics/lib/magma/gnbuild/magma.gni:36
-
-### build_libvulkan_vsi_vip
-
-Targets that will be built as verisilicon vulkan ICDS.
-
-**Current value (from the default):** `[]`
-
-From //src/graphics/lib/magma/gnbuild/magma.gni:33
-
 ### build_only_labels
 
 These labels are added as dependencies of '//:default', but not as a
@@ -1164,7 +1148,7 @@
 
 **Current value (from the default):** `"//out/not-default/comparison-reports"`
 
-From //build/toolchain/rbe.gni:195
+From //build/toolchain/rbe.gni:196
 
 ### compress_debuginfo
 
@@ -1172,7 +1156,7 @@
 
 **Current value (from the default):** `"zstd"`
 
-From //build/config/compiler.gni:90
+From //build/config/compiler.gni:92
 
 ### config_example_cpp_greeting
 
@@ -1329,7 +1313,7 @@
 
 **Current value (from the default):** `"none"`
 
-From //build/toolchain/rbe.gni:190
+From //build/toolchain/rbe.gni:191
 
 ### cxx_rbe_download_obj_files
 
@@ -1341,7 +1325,7 @@
 
 **Current value (from the default):** `true`
 
-From //build/toolchain/rbe.gni:202
+From //build/toolchain/rbe.gni:203
 
 ### cxx_rbe_enable
 
@@ -1354,7 +1338,7 @@
 
 **Overridden from the default:** `false`
 
-From //build/toolchain/rbe.gni:143
+From //build/toolchain/rbe.gni:144
 
 **Current value for `target_cpu = "x64"`:** `false`
 
@@ -1362,7 +1346,7 @@
 
 **Overridden from the default:** `false`
 
-From //build/toolchain/rbe.gni:143
+From //build/toolchain/rbe.gni:144
 
 ### cxx_rbe_exec_strategy
 
@@ -1385,7 +1369,7 @@
 
 **Current value (from the default):** `"remote_local_fallback"`
 
-From //build/toolchain/rbe.gni:166
+From //build/toolchain/rbe.gni:167
 
 ### cxx_rbe_minimalist_wrapper
 
@@ -1395,7 +1379,7 @@
 
 **Current value (from the default):** `true`
 
-From //build/toolchain/rbe.gni:148
+From //build/toolchain/rbe.gni:149
 
 ### data_filesystem_format
 
@@ -1415,7 +1399,7 @@
 
 **Current value (from the default):** `"debug"`
 
-From //build/config/compiler.gni:52
+From //build/config/compiler.gni:54
 
 ### default_configs
 
@@ -1457,7 +1441,7 @@
 
 **Current value (from the default):** `true`
 
-From //build/config/BUILD.gn:35
+From //build/config/BUILD.gn:37
 
 ### dev_bootfs_labels
 
@@ -1528,7 +1512,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:101
+From //BUILD.gn:115
 
 **Current value for `target_cpu = "x64"`:** `[]`
 
@@ -1536,7 +1520,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:101
+From //BUILD.gn:115
 
 ### devicetree_board_driver
 
@@ -1842,593 +1826,599 @@
 
 From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:81
 
+### dir_pw_cpu_exception_risc_v
+
+**Current value (from the default):** `"//third_party/pigweed/src/pw_cpu_exception_risc_v"`
+
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:83
+
 ### dir_pw_crypto
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_crypto"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:82
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:84
 
 ### dir_pw_digital_io
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_digital_io"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:83
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:85
 
 ### dir_pw_digital_io_linux
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_digital_io_linux"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:84
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:86
 
 ### dir_pw_digital_io_mcuxpresso
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_digital_io_mcuxpresso"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:86
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:88
 
 ### dir_pw_digital_io_rp2040
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_digital_io_rp2040"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:87
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:89
 
 ### dir_pw_docgen
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_docgen"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:88
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:90
 
 ### dir_pw_doctor
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_doctor"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:89
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:91
 
 ### dir_pw_emu
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_emu"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:90
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:92
 
 ### dir_pw_env_setup
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_env_setup"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:91
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:93
 
 ### dir_pw_env_setup_zephyr
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_env_setup_zephyr"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:92
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:94
 
 ### dir_pw_file
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_file"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:93
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:95
 
 ### dir_pw_format
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_format"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:94
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:96
 
 ### dir_pw_function
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_function"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:95
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:97
 
 ### dir_pw_fuzzer
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_fuzzer"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:96
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:98
 
 ### dir_pw_grpc
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_grpc"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:97
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:99
 
 ### dir_pw_hdlc
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_hdlc"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:98
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:100
 
 ### dir_pw_hex_dump
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_hex_dump"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:99
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:101
 
 ### dir_pw_i2c
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_i2c"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:100
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:102
 
 ### dir_pw_i2c_linux
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_i2c_linux"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:101
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:103
 
 ### dir_pw_i2c_mcuxpresso
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_i2c_mcuxpresso"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:102
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:104
 
 ### dir_pw_i2c_rp2040
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_i2c_rp2040"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:103
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:105
 
 ### dir_pw_ide
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_ide"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:104
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:106
 
 ### dir_pw_interrupt
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_interrupt"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:105
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:107
 
 ### dir_pw_interrupt_cortex_m
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_interrupt_cortex_m"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:107
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:109
 
 ### dir_pw_interrupt_xtensa
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_interrupt_xtensa"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:108
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:110
 
 ### dir_pw_interrupt_zephyr
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_interrupt_zephyr"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:109
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:111
 
 ### dir_pw_intrusive_ptr
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_intrusive_ptr"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:110
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:112
 
 ### dir_pw_json
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_json"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:111
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:113
 
 ### dir_pw_kvs
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_kvs"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:112
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:114
 
 ### dir_pw_libc
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_libc"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:113
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:115
 
 ### dir_pw_libcxx
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_libcxx"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:114
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:116
 
 ### dir_pw_log
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_log"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:115
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:117
 
 ### dir_pw_log_android
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_log_android"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:116
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:118
 
 ### dir_pw_log_basic
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_log_basic"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:117
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:119
 
 ### dir_pw_log_null
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_log_null"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:118
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:120
 
 ### dir_pw_log_rpc
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_log_rpc"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:119
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:121
 
 ### dir_pw_log_string
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_log_string"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:120
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:122
 
 ### dir_pw_log_tokenized
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_log_tokenized"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:121
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:123
 
 ### dir_pw_log_zephyr
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_log_zephyr"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:122
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:124
 
 ### dir_pw_malloc
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_malloc"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:123
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:125
 
 ### dir_pw_malloc_freelist
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_malloc_freelist"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:124
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:126
 
 ### dir_pw_malloc_freertos
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_malloc_freertos"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:125
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:127
 
 ### dir_pw_metric
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_metric"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:126
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:128
 
 ### dir_pw_minimal_cpp_stdlib
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_minimal_cpp_stdlib"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:128
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:130
 
 ### dir_pw_module
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_module"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:129
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:131
 
 ### dir_pw_multibuf
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_multibuf"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:130
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:132
 
 ### dir_pw_multisink
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_multisink"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:131
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:133
 
 ### dir_pw_package
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_package"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:132
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:134
 
 ### dir_pw_perf_test
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_perf_test"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:133
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:135
 
 ### dir_pw_persistent_ram
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_persistent_ram"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:134
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:136
 
 ### dir_pw_polyfill
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_polyfill"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:135
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:137
 
 ### dir_pw_preprocessor
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_preprocessor"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:136
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:138
 
 ### dir_pw_presubmit
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_presubmit"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:137
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:139
 
 ### dir_pw_protobuf
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_protobuf"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:138
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:140
 
 ### dir_pw_protobuf_compiler
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_protobuf_compiler"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:139
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:141
 
 ### dir_pw_random
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_random"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:140
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:142
 
 ### dir_pw_result
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_result"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:141
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:143
 
 ### dir_pw_ring_buffer
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_ring_buffer"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:142
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:144
 
 ### dir_pw_router
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_router"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:143
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:145
 
 ### dir_pw_rpc
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_rpc"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:144
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:146
 
 ### dir_pw_rpc_transport
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_rpc_transport"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:145
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:147
 
 ### dir_pw_rust
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_rust"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:146
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:148
 
 ### dir_pw_sensor
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sensor"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:147
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:149
 
 ### dir_pw_snapshot
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_snapshot"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:148
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:150
 
 ### dir_pw_software_update
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_software_update"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:149
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:151
 
 ### dir_pw_span
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_span"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:150
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:152
 
 ### dir_pw_spi
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_spi"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:151
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:153
 
 ### dir_pw_spi_linux
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_spi_linux"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:152
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:154
 
 ### dir_pw_spi_mcuxpresso
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_spi_mcuxpresso"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:153
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:155
 
 ### dir_pw_spi_rp2040
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_spi_rp2040"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:154
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:156
 
 ### dir_pw_status
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_status"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:155
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:157
 
 ### dir_pw_stm32cube_build
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_stm32cube_build"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:156
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:158
 
 ### dir_pw_stream
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_stream"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:157
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:159
 
 ### dir_pw_stream_shmem_mcuxpresso
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_stream_shmem_mcuxpresso"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:159
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:161
 
 ### dir_pw_stream_uart_linux
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_stream_uart_linux"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:160
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:162
 
 ### dir_pw_stream_uart_mcuxpresso
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_stream_uart_mcuxpresso"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:162
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:164
 
 ### dir_pw_string
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_string"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:163
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:165
 
 ### dir_pw_symbolizer
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_symbolizer"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:164
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:166
 
 ### dir_pw_sync
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sync"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:165
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:167
 
 ### dir_pw_sync_baremetal
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sync_baremetal"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:166
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:168
 
 ### dir_pw_sync_embos
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sync_embos"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:167
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:169
 
 ### dir_pw_sync_freertos
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sync_freertos"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:168
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:170
 
 ### dir_pw_sync_stl
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sync_stl"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:169
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:171
 
 ### dir_pw_sync_threadx
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sync_threadx"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:170
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:172
 
 ### dir_pw_sync_zephyr
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sync_zephyr"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:171
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:173
 
 ### dir_pw_sys_io
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:172
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:174
 
 ### dir_pw_sys_io_ambiq_sdk
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_ambiq_sdk"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:173
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:175
 
 ### dir_pw_sys_io_arduino
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_arduino"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:174
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:176
 
 ### dir_pw_sys_io_baremetal_lm3s6965evb
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_baremetal_lm3s6965evb"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:176
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:178
 
 ### dir_pw_sys_io_baremetal_stm32f429
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_baremetal_stm32f429"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:178
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:180
 
 ### dir_pw_sys_io_emcraft_sf2
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_emcraft_sf2"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:180
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:182
 
 ### dir_pw_sys_io_mcuxpresso
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_mcuxpresso"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:181
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:183
 
 ### dir_pw_sys_io_rp2040
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_rp2040"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:182
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:184
 
 ### dir_pw_sys_io_stdio
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_stdio"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:183
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:185
 
 ### dir_pw_sys_io_stm32cube
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_stm32cube"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:184
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:186
 
 ### dir_pw_sys_io_zephyr
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_sys_io_zephyr"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:185
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:187
 
 ### dir_pw_system
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_system"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:186
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:188
 
 ### dir_pw_target_runner
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_target_runner"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:187
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:189
 
 ### dir_pw_third_party
 
@@ -2554,133 +2544,133 @@
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_thread"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:188
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:190
 
 ### dir_pw_thread_embos
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_thread_embos"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:189
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:191
 
 ### dir_pw_thread_freertos
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_thread_freertos"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:190
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:192
 
 ### dir_pw_thread_stl
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_thread_stl"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:191
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:193
 
 ### dir_pw_thread_threadx
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_thread_threadx"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:192
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:194
 
 ### dir_pw_thread_zephyr
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_thread_zephyr"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:193
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:195
 
 ### dir_pw_tls_client
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_tls_client"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:194
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:196
 
 ### dir_pw_tls_client_boringssl
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_tls_client_boringssl"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:196
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:198
 
 ### dir_pw_tls_client_mbedtls
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_tls_client_mbedtls"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:198
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:200
 
 ### dir_pw_tokenizer
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_tokenizer"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:199
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:201
 
 ### dir_pw_toolchain
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_toolchain"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:200
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:202
 
 ### dir_pw_toolchain_bazel
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_toolchain_bazel"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:201
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:203
 
 ### dir_pw_trace
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_trace"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:202
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:204
 
 ### dir_pw_trace_tokenized
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_trace_tokenized"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:203
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:205
 
 ### dir_pw_transfer
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_transfer"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:204
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:206
 
 ### dir_pw_uart
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_uart"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:205
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:207
 
 ### dir_pw_unit_test
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_unit_test"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:206
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:208
 
 ### dir_pw_unit_test_zephyr
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_unit_test_zephyr"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:207
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:209
 
 ### dir_pw_varint
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_varint"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:208
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:210
 
 ### dir_pw_watch
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_watch"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:209
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:211
 
 ### dir_pw_web
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_web"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:210
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:212
 
 ### dir_pw_work_queue
 
 **Current value (from the default):** `"//third_party/pigweed/src/pw_work_queue"`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:211
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:213
 
 ### disable_boot_tests
 
@@ -2749,7 +2739,7 @@
 
 **Current value (from the default):** `5`
 
-From //build/config/compiler.gni:66
+From //build/config/compiler.gni:68
 
 ### e2e_test_labels
 
@@ -2762,7 +2752,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:90
+From //BUILD.gn:104
 
 **Current value for `target_cpu = "x64"`:** `[]`
 
@@ -2770,7 +2760,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:90
+From //BUILD.gn:104
 
 ### emu_window_size_height
 
@@ -2825,7 +2815,7 @@
 
 **Current value (from the default):** `false`
 
-From //build/config/BUILD.gn:31
+From //build/config/BUILD.gn:33
 
 ### enable_grpc_ares
 
@@ -3150,12 +3140,6 @@
 
 From //zircon/vdso/vdso.gni:9
 
-### expat_build_root
-
-**Current value (from the default):** `"//third_party/expat"`
-
-From //src/graphics/lib/magma/gnbuild/magma.gni:12
-
 ### experimental_cxx_version
 
 **NOTE:** This is for **experimentation only** and should not normally be
@@ -3175,6 +3159,25 @@
 
 From //zircon/kernel/params.gni:147
 
+### exported_package_labels
+
+If you add labels to this variable the `exported_fuchsia_package_archive()`
+targets captured by these labels will be collected and exposed in the
+'package_archives' build api module. Ordinary `fuchsia_package_archive()`
+targets are not captured.
+
+Note: This variable is only used for metadata collection -- any package
+labels added here will still need to be included in the build graph
+elsewhere.
+
+It's usually advisable to use labels of well-defined, curated `group()`s of
+packages instead of explicitly adding the labels of the
+`exported_fuchsia_package_archive()` targets directly.
+
+**Current value (from the default):** `[]`
+
+From //BUILD.gn:89
+
 ### extra_bazel_assembly_targets
 
 Extra GN targets to include when Bazel assembly is enabled. This list is
@@ -3474,24 +3477,6 @@
 
 From //build/testing/boot_tests/kernel_zbi_test.gni:17
 
-### generate_legacy_ninja_build_outputs_licenses_spdx
-
-Deprecated. No-op.
-TODO(https://fxbug.dev/42082793): Remove once unused downstream.
-
-**Current value (from the default):** `false`
-
-From //build/bazel/licenses/BUILD.gn:19
-
-### generate_legacy_ninja_build_outputs_licenses_spdx_from_metadata
-
-Deprecated. No-op.
-TODO(https://fxbug.dev/42082793): Remove once unused downstream.
-
-**Current value (from the default):** `true`
-
-From //build/bazel/licenses/BUILD.gn:23
-
 ### generate_licenses_spdx_stubs
 
 When true, generated_licenses_spdx template will generate stub SPDX files
@@ -3694,7 +3679,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:82
+From //BUILD.gn:96
 
 **Current value for `target_cpu = "x64"`:** `[]`
 
@@ -3702,7 +3687,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:82
+From //BUILD.gn:96
 
 ### host_byteorder
 
@@ -3728,7 +3713,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:108
+From //BUILD.gn:122
 
 **Current value for `target_cpu = "x64"`:** `[]`
 
@@ -3736,7 +3721,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:108
+From //BUILD.gn:122
 
 ### host_os
 
@@ -3755,7 +3740,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:96
+From //BUILD.gn:110
 
 **Current value for `target_cpu = "x64"`:** `[]`
 
@@ -3763,7 +3748,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:96
+From //BUILD.gn:110
 
 ### host_tools_base_path_override
 
@@ -4436,7 +4421,7 @@
 
 **Current value (from the default):** `"none"`
 
-From //build/toolchain/rbe.gni:249
+From //build/toolchain/rbe.gni:250
 
 ### link_rbe_enable
 
@@ -4450,7 +4435,7 @@
 
 **Overridden from the default:** `false`
 
-From //build/toolchain/rbe.gni:211
+From //build/toolchain/rbe.gni:212
 
 **Current value for `target_cpu = "x64"`:** `false`
 
@@ -4458,7 +4443,7 @@
 
 **Overridden from the default:** `false`
 
-From //build/toolchain/rbe.gni:211
+From //build/toolchain/rbe.gni:212
 
 ### link_rbe_exec_strategy
 
@@ -4481,7 +4466,7 @@
 
 **Current value (from the default):** `"remote"`
 
-From //build/toolchain/rbe.gni:229
+From //build/toolchain/rbe.gni:230
 
 ### llvm_prefix
 
@@ -4535,12 +4520,6 @@
 
 From //build/config/sanitizers/sanitizer_default_options.gni:35
 
-### magma_build_root
-
-**Current value (from the default):** `"//src/graphics/lib/magma"`
-
-From //src/graphics/lib/magma/gnbuild/magma.gni:11
-
 ### magma_debug
 
 **Current value (from the default):** `false`
@@ -4553,7 +4532,7 @@
 
 **Current value (from the default):** `true`
 
-From //src/graphics/lib/magma/gnbuild/magma.gni:19
+From //src/graphics/lib/magma/gnbuild/magma.gni:12
 
 ### magma_openvx_include
 
@@ -4561,7 +4540,7 @@
 
 **Current value (from the default):** `""`
 
-From //src/graphics/lib/magma/gnbuild/magma.gni:25
+From //src/graphics/lib/magma/gnbuild/magma.gni:15
 
 ### magma_openvx_package
 
@@ -4569,13 +4548,7 @@
 
 **Current value (from the default):** `""`
 
-From //src/graphics/lib/magma/gnbuild/magma.gni:28
-
-### magma_python_path
-
-**Current value (from the default):** `"/b/s/w/ir/x/w/fuchsia/third_party/mako"`
-
-From //src/graphics/lib/magma/gnbuild/magma.gni:16
+From //src/graphics/lib/magma/gnbuild/magma.gni:18
 
 ### max_blob_contents_size
 
@@ -4688,18 +4661,6 @@
 
 From //src/graphics/drivers/msd-arm-mali/src/BUILD.gn:23
 
-### msd_build_root
-
-**Current value (from the default):** `"//src/graphics/drivers"`
-
-From //src/graphics/lib/magma/gnbuild/magma.gni:13
-
-### msd_intel_gen_build_root
-
-**Current value (from the default):** `"//src/graphics/drivers/msd-intel-gen"`
-
-From //src/graphics/lib/magma/gnbuild/magma.gni:14
-
 ### msd_intel_gen_enable_hardware_unit_tests
 
 **Current value (from the default):** `false`
@@ -5278,6 +5239,7 @@
 * `debug`: "optimized for debugging", light enough to avoid confusion
 * `default`: default optimization level
 * `size`:  optimized for space rather than purely for speed
+* `size_lto`:  optimize for space and use LTO
 * `speed`: optimized purely for speed
 * `sanitizer`: optimized for sanitizers (ASan, etc.)
 * `profile`: optimized for coverage/profile data collection
@@ -5285,7 +5247,7 @@
 
 **Current value (from the default):** `"size"`
 
-From //build/config/compiler.gni:22
+From //build/config/compiler.gni:23
 
 ### output_breakpad_syms
 
@@ -5306,16 +5268,20 @@
 ### override_target_api_level
 
 Specify a specific target API level for the platform build.
-When set to -1, the platform is built targeting HEAD with runtime support
-for all supported and sunset API levels.
-Must be -1 or a positive integer corresponding to currently supported
-(not sunset) API level. This is primarily used by the SDK.
-Not all targets support the non-default value. In particular, `:default`
-currently fails.
 
-**Current value (from the default):** `-1`
+For the normal platform build, the API level is "PLATFORM", which is greater
+than (that is to say: "newer than") all other API levels.
 
-From //build/config/fuchsia/target_api_level.gni:13
+If this is _not_ set to "PLATFORM", then it must be set to a positive
+integer corresponding to a currently supported (not sunset) API level. In
+that case, the build will target the given API level.
+
+This is primarily used by the IDK. Not all targets support the non-default
+value. In particular, `:default` currently fails.
+
+**Current value (from the default):** `"PLATFORM"`
+
+From //build/config/fuchsia/target_api_level.gni:17
 
 ### package_flavor_selections
 
@@ -5516,14 +5482,6 @@
 
 From //build/go/go_build.gni:28
 
-### prebuilt_libvulkan_img_path
-
-The path to a prebuilt libvulkan.so for an IMG GPU.
-
-**Current value (from the default):** `""`
-
-From //src/graphics/lib/magma/gnbuild/magma.gni:22
-
 ### product_assembly_overrides
 
 This GN arg enables developer overrides for the given assembly targets
@@ -5543,7 +5501,7 @@
 
 **Current value (from the default):** `[]`
 
-From //build/assembly/developer_overrides.gni:117
+From //build/assembly/developer_overrides.gni:121
 
 ### product_bootfs_labels
 
@@ -6214,25 +6172,25 @@
 
 A list with all Pigweed modules docs groups. DO NOT SET THIS BUILD ARGUMENT!
 
-**Current value (from the default):** `["//third_party/pigweed/src/docker:docs", "//third_party/pigweed/src/pw_alignment:docs", "//third_party/pigweed/src/pw_allocator:docs", "//third_party/pigweed/src/pw_analog:docs", "//third_party/pigweed/src/pw_android_toolchain:docs", "//third_party/pigweed/src/pw_arduino_build:docs", "//third_party/pigweed/src/pw_assert:docs", "//third_party/pigweed/src/pw_assert_basic:docs", "//third_party/pigweed/src/pw_assert_log:docs", "//third_party/pigweed/src/pw_assert_tokenized:docs", "//third_party/pigweed/src/pw_assert_zephyr:docs", "//third_party/pigweed/src/pw_async:docs", "//third_party/pigweed/src/pw_async2:docs", "//third_party/pigweed/src/pw_async2_basic:docs", "//third_party/pigweed/src/pw_async2_epoll:docs", "//third_party/pigweed/src/pw_async_basic:docs", "//third_party/pigweed/src/pw_base64:docs", "//third_party/pigweed/src/pw_bloat:docs", "//third_party/pigweed/src/pw_blob_store:docs", "//third_party/pigweed/src/pw_bluetooth:docs", "//third_party/pigweed/src/pw_bluetooth_hci:docs", "//third_party/pigweed/src/pw_bluetooth_profiles:docs", "//third_party/pigweed/src/pw_bluetooth_proxy:docs", "//third_party/pigweed/src/pw_bluetooth_sapphire:docs", "//third_party/pigweed/src/pw_boot:docs", "//third_party/pigweed/src/pw_boot_cortex_m:docs", "//third_party/pigweed/src/pw_build:docs", "//third_party/pigweed/src/pw_build_android:docs", "//third_party/pigweed/src/pw_build_info:docs", "//third_party/pigweed/src/pw_build_mcuxpresso:docs", "//third_party/pigweed/src/pw_bytes:docs", "//third_party/pigweed/src/pw_channel:docs", "//third_party/pigweed/src/pw_checksum:docs", "//third_party/pigweed/src/pw_chre:docs", "//third_party/pigweed/src/pw_chrono:docs", "//third_party/pigweed/src/pw_chrono_embos:docs", "//third_party/pigweed/src/pw_chrono_freertos:docs", "//third_party/pigweed/src/pw_chrono_rp2040:docs", "//third_party/pigweed/src/pw_chrono_stl:docs", "//third_party/pigweed/src/pw_chrono_threadx:docs", "//third_party/pigweed/src/pw_chrono_zephyr:docs", "//third_party/pigweed/src/pw_cli:docs", "//third_party/pigweed/src/pw_compilation_testing:docs", "//third_party/pigweed/src/pw_config_loader:docs", "//third_party/pigweed/src/pw_console:docs", "//third_party/pigweed/src/pw_containers:docs", "//third_party/pigweed/src/pw_cpu_exception:docs", "//third_party/pigweed/src/pw_cpu_exception_cortex_m:docs", "//third_party/pigweed/src/pw_crypto:docs", "//third_party/pigweed/src/pw_digital_io:docs", "//third_party/pigweed/src/pw_digital_io_linux:docs", "//third_party/pigweed/src/pw_digital_io_mcuxpresso:docs", "//third_party/pigweed/src/pw_digital_io_rp2040:docs", "//third_party/pigweed/src/pw_docgen:docs", "//third_party/pigweed/src/pw_doctor:docs", "//third_party/pigweed/src/pw_emu:docs", "//third_party/pigweed/src/pw_env_setup:docs", "//third_party/pigweed/src/pw_env_setup_zephyr:docs", "//third_party/pigweed/src/pw_file:docs", "//third_party/pigweed/src/pw_format:docs", "//third_party/pigweed/src/pw_function:docs", "//third_party/pigweed/src/pw_fuzzer:docs", "//third_party/pigweed/src/pw_grpc:docs", "//third_party/pigweed/src/pw_hdlc:docs", "//third_party/pigweed/src/pw_hex_dump:docs", "//third_party/pigweed/src/pw_i2c:docs", "//third_party/pigweed/src/pw_i2c_linux:docs", "//third_party/pigweed/src/pw_i2c_mcuxpresso:docs", "//third_party/pigweed/src/pw_i2c_rp2040:docs", "//third_party/pigweed/src/pw_ide:docs", "//third_party/pigweed/src/pw_interrupt:docs", "//third_party/pigweed/src/pw_interrupt_cortex_m:docs", "//third_party/pigweed/src/pw_interrupt_xtensa:docs", "//third_party/pigweed/src/pw_interrupt_zephyr:docs", "//third_party/pigweed/src/pw_intrusive_ptr:docs", "//third_party/pigweed/src/pw_json:docs", "//third_party/pigweed/src/pw_kvs:docs", "//third_party/pigweed/src/pw_libc:docs", "//third_party/pigweed/src/pw_libcxx:docs", "//third_party/pigweed/src/pw_log:docs", "//third_party/pigweed/src/pw_log_android:docs", "//third_party/pigweed/src/pw_log_basic:docs", "//third_party/pigweed/src/pw_log_null:docs", "//third_party/pigweed/src/pw_log_rpc:docs", "//third_party/pigweed/src/pw_log_string:docs", "//third_party/pigweed/src/pw_log_tokenized:docs", "//third_party/pigweed/src/pw_log_zephyr:docs", "//third_party/pigweed/src/pw_malloc:docs", "//third_party/pigweed/src/pw_malloc_freelist:docs", "//third_party/pigweed/src/pw_malloc_freertos:docs", "//third_party/pigweed/src/pw_metric:docs", "//third_party/pigweed/src/pw_minimal_cpp_stdlib:docs", "//third_party/pigweed/src/pw_module:docs", "//third_party/pigweed/src/pw_multibuf:docs", "//third_party/pigweed/src/pw_multisink:docs", "//third_party/pigweed/src/pw_package:docs", "//third_party/pigweed/src/pw_perf_test:docs", "//third_party/pigweed/src/pw_persistent_ram:docs", "//third_party/pigweed/src/pw_polyfill:docs", "//third_party/pigweed/src/pw_preprocessor:docs", "//third_party/pigweed/src/pw_presubmit:docs", "//third_party/pigweed/src/pw_protobuf:docs", "//third_party/pigweed/src/pw_protobuf_compiler:docs", "//third_party/pigweed/src/pw_random:docs", "//third_party/pigweed/src/pw_result:docs", "//third_party/pigweed/src/pw_ring_buffer:docs", "//third_party/pigweed/src/pw_router:docs", "//third_party/pigweed/src/pw_rpc:docs", "//third_party/pigweed/src/pw_rpc_transport:docs", "//third_party/pigweed/src/pw_rust:docs", "//third_party/pigweed/src/pw_sensor:docs", "//third_party/pigweed/src/pw_snapshot:docs", "//third_party/pigweed/src/pw_software_update:docs", "//third_party/pigweed/src/pw_span:docs", "//third_party/pigweed/src/pw_spi:docs", "//third_party/pigweed/src/pw_spi_linux:docs", "//third_party/pigweed/src/pw_spi_mcuxpresso:docs", "//third_party/pigweed/src/pw_spi_rp2040:docs", "//third_party/pigweed/src/pw_status:docs", "//third_party/pigweed/src/pw_stm32cube_build:docs", "//third_party/pigweed/src/pw_stream:docs", "//third_party/pigweed/src/pw_stream_shmem_mcuxpresso:docs", "//third_party/pigweed/src/pw_stream_uart_linux:docs", "//third_party/pigweed/src/pw_stream_uart_mcuxpresso:docs", "//third_party/pigweed/src/pw_string:docs", "//third_party/pigweed/src/pw_symbolizer:docs", "//third_party/pigweed/src/pw_sync:docs", "//third_party/pigweed/src/pw_sync_baremetal:docs", "//third_party/pigweed/src/pw_sync_embos:docs", "//third_party/pigweed/src/pw_sync_freertos:docs", "//third_party/pigweed/src/pw_sync_stl:docs", "//third_party/pigweed/src/pw_sync_threadx:docs", "//third_party/pigweed/src/pw_sync_zephyr:docs", "//third_party/pigweed/src/pw_sys_io:docs", "//third_party/pigweed/src/pw_sys_io_ambiq_sdk:docs", "//third_party/pigweed/src/pw_sys_io_arduino:docs", "//third_party/pigweed/src/pw_sys_io_baremetal_lm3s6965evb:docs", "//third_party/pigweed/src/pw_sys_io_baremetal_stm32f429:docs", "//third_party/pigweed/src/pw_sys_io_emcraft_sf2:docs", "//third_party/pigweed/src/pw_sys_io_mcuxpresso:docs", "//third_party/pigweed/src/pw_sys_io_rp2040:docs", "//third_party/pigweed/src/pw_sys_io_stdio:docs", "//third_party/pigweed/src/pw_sys_io_stm32cube:docs", "//third_party/pigweed/src/pw_sys_io_zephyr:docs", "//third_party/pigweed/src/pw_system:docs", "//third_party/pigweed/src/pw_target_runner:docs", "//third_party/pigweed/src/pw_thread:docs", "//third_party/pigweed/src/pw_thread_embos:docs", "//third_party/pigweed/src/pw_thread_freertos:docs", "//third_party/pigweed/src/pw_thread_stl:docs", "//third_party/pigweed/src/pw_thread_threadx:docs", "//third_party/pigweed/src/pw_thread_zephyr:docs", "//third_party/pigweed/src/pw_tls_client:docs", "//third_party/pigweed/src/pw_tls_client_boringssl:docs", "//third_party/pigweed/src/pw_tls_client_mbedtls:docs", "//third_party/pigweed/src/pw_tokenizer:docs", "//third_party/pigweed/src/pw_toolchain:docs", "//third_party/pigweed/src/pw_toolchain_bazel:docs", "//third_party/pigweed/src/pw_trace:docs", "//third_party/pigweed/src/pw_trace_tokenized:docs", "//third_party/pigweed/src/pw_transfer:docs", "//third_party/pigweed/src/pw_uart:docs", "//third_party/pigweed/src/pw_unit_test:docs", "//third_party/pigweed/src/pw_unit_test_zephyr:docs", "//third_party/pigweed/src/pw_varint:docs", "//third_party/pigweed/src/pw_watch:docs", "//third_party/pigweed/src/pw_web:docs", "//third_party/pigweed/src/pw_work_queue:docs"]`
+**Current value (from the default):** `["//third_party/pigweed/src/docker:docs", "//third_party/pigweed/src/pw_alignment:docs", "//third_party/pigweed/src/pw_allocator:docs", "//third_party/pigweed/src/pw_analog:docs", "//third_party/pigweed/src/pw_android_toolchain:docs", "//third_party/pigweed/src/pw_arduino_build:docs", "//third_party/pigweed/src/pw_assert:docs", "//third_party/pigweed/src/pw_assert_basic:docs", "//third_party/pigweed/src/pw_assert_log:docs", "//third_party/pigweed/src/pw_assert_tokenized:docs", "//third_party/pigweed/src/pw_assert_zephyr:docs", "//third_party/pigweed/src/pw_async:docs", "//third_party/pigweed/src/pw_async2:docs", "//third_party/pigweed/src/pw_async2_basic:docs", "//third_party/pigweed/src/pw_async2_epoll:docs", "//third_party/pigweed/src/pw_async_basic:docs", "//third_party/pigweed/src/pw_base64:docs", "//third_party/pigweed/src/pw_bloat:docs", "//third_party/pigweed/src/pw_blob_store:docs", "//third_party/pigweed/src/pw_bluetooth:docs", "//third_party/pigweed/src/pw_bluetooth_hci:docs", "//third_party/pigweed/src/pw_bluetooth_profiles:docs", "//third_party/pigweed/src/pw_bluetooth_proxy:docs", "//third_party/pigweed/src/pw_bluetooth_sapphire:docs", "//third_party/pigweed/src/pw_boot:docs", "//third_party/pigweed/src/pw_boot_cortex_m:docs", "//third_party/pigweed/src/pw_build:docs", "//third_party/pigweed/src/pw_build_android:docs", "//third_party/pigweed/src/pw_build_info:docs", "//third_party/pigweed/src/pw_build_mcuxpresso:docs", "//third_party/pigweed/src/pw_bytes:docs", "//third_party/pigweed/src/pw_channel:docs", "//third_party/pigweed/src/pw_checksum:docs", "//third_party/pigweed/src/pw_chre:docs", "//third_party/pigweed/src/pw_chrono:docs", "//third_party/pigweed/src/pw_chrono_embos:docs", "//third_party/pigweed/src/pw_chrono_freertos:docs", "//third_party/pigweed/src/pw_chrono_rp2040:docs", "//third_party/pigweed/src/pw_chrono_stl:docs", "//third_party/pigweed/src/pw_chrono_threadx:docs", "//third_party/pigweed/src/pw_chrono_zephyr:docs", "//third_party/pigweed/src/pw_cli:docs", "//third_party/pigweed/src/pw_compilation_testing:docs", "//third_party/pigweed/src/pw_config_loader:docs", "//third_party/pigweed/src/pw_console:docs", "//third_party/pigweed/src/pw_containers:docs", "//third_party/pigweed/src/pw_cpu_exception:docs", "//third_party/pigweed/src/pw_cpu_exception_cortex_m:docs", "//third_party/pigweed/src/pw_cpu_exception_risc_v:docs", "//third_party/pigweed/src/pw_crypto:docs", "//third_party/pigweed/src/pw_digital_io:docs", "//third_party/pigweed/src/pw_digital_io_linux:docs", "//third_party/pigweed/src/pw_digital_io_mcuxpresso:docs", "//third_party/pigweed/src/pw_digital_io_rp2040:docs", "//third_party/pigweed/src/pw_docgen:docs", "//third_party/pigweed/src/pw_doctor:docs", "//third_party/pigweed/src/pw_emu:docs", "//third_party/pigweed/src/pw_env_setup:docs", "//third_party/pigweed/src/pw_env_setup_zephyr:docs", "//third_party/pigweed/src/pw_file:docs", "//third_party/pigweed/src/pw_format:docs", "//third_party/pigweed/src/pw_function:docs", "//third_party/pigweed/src/pw_fuzzer:docs", "//third_party/pigweed/src/pw_grpc:docs", "//third_party/pigweed/src/pw_hdlc:docs", "//third_party/pigweed/src/pw_hex_dump:docs", "//third_party/pigweed/src/pw_i2c:docs", "//third_party/pigweed/src/pw_i2c_linux:docs", "//third_party/pigweed/src/pw_i2c_mcuxpresso:docs", "//third_party/pigweed/src/pw_i2c_rp2040:docs", "//third_party/pigweed/src/pw_ide:docs", "//third_party/pigweed/src/pw_interrupt:docs", "//third_party/pigweed/src/pw_interrupt_cortex_m:docs", "//third_party/pigweed/src/pw_interrupt_xtensa:docs", "//third_party/pigweed/src/pw_interrupt_zephyr:docs", "//third_party/pigweed/src/pw_intrusive_ptr:docs", "//third_party/pigweed/src/pw_json:docs", "//third_party/pigweed/src/pw_kvs:docs", "//third_party/pigweed/src/pw_libc:docs", "//third_party/pigweed/src/pw_libcxx:docs", "//third_party/pigweed/src/pw_log:docs", "//third_party/pigweed/src/pw_log_android:docs", "//third_party/pigweed/src/pw_log_basic:docs", "//third_party/pigweed/src/pw_log_null:docs", "//third_party/pigweed/src/pw_log_rpc:docs", "//third_party/pigweed/src/pw_log_string:docs", "//third_party/pigweed/src/pw_log_tokenized:docs", "//third_party/pigweed/src/pw_log_zephyr:docs", "//third_party/pigweed/src/pw_malloc:docs", "//third_party/pigweed/src/pw_malloc_freelist:docs", "//third_party/pigweed/src/pw_malloc_freertos:docs", "//third_party/pigweed/src/pw_metric:docs", "//third_party/pigweed/src/pw_minimal_cpp_stdlib:docs", "//third_party/pigweed/src/pw_module:docs", "//third_party/pigweed/src/pw_multibuf:docs", "//third_party/pigweed/src/pw_multisink:docs", "//third_party/pigweed/src/pw_package:docs", "//third_party/pigweed/src/pw_perf_test:docs", "//third_party/pigweed/src/pw_persistent_ram:docs", "//third_party/pigweed/src/pw_polyfill:docs", "//third_party/pigweed/src/pw_preprocessor:docs", "//third_party/pigweed/src/pw_presubmit:docs", "//third_party/pigweed/src/pw_protobuf:docs", "//third_party/pigweed/src/pw_protobuf_compiler:docs", "//third_party/pigweed/src/pw_random:docs", "//third_party/pigweed/src/pw_result:docs", "//third_party/pigweed/src/pw_ring_buffer:docs", "//third_party/pigweed/src/pw_router:docs", "//third_party/pigweed/src/pw_rpc:docs", "//third_party/pigweed/src/pw_rpc_transport:docs", "//third_party/pigweed/src/pw_rust:docs", "//third_party/pigweed/src/pw_sensor:docs", "//third_party/pigweed/src/pw_snapshot:docs", "//third_party/pigweed/src/pw_software_update:docs", "//third_party/pigweed/src/pw_span:docs", "//third_party/pigweed/src/pw_spi:docs", "//third_party/pigweed/src/pw_spi_linux:docs", "//third_party/pigweed/src/pw_spi_mcuxpresso:docs", "//third_party/pigweed/src/pw_spi_rp2040:docs", "//third_party/pigweed/src/pw_status:docs", "//third_party/pigweed/src/pw_stm32cube_build:docs", "//third_party/pigweed/src/pw_stream:docs", "//third_party/pigweed/src/pw_stream_shmem_mcuxpresso:docs", "//third_party/pigweed/src/pw_stream_uart_linux:docs", "//third_party/pigweed/src/pw_stream_uart_mcuxpresso:docs", "//third_party/pigweed/src/pw_string:docs", "//third_party/pigweed/src/pw_symbolizer:docs", "//third_party/pigweed/src/pw_sync:docs", "//third_party/pigweed/src/pw_sync_baremetal:docs", "//third_party/pigweed/src/pw_sync_embos:docs", "//third_party/pigweed/src/pw_sync_freertos:docs", "//third_party/pigweed/src/pw_sync_stl:docs", "//third_party/pigweed/src/pw_sync_threadx:docs", "//third_party/pigweed/src/pw_sync_zephyr:docs", "//third_party/pigweed/src/pw_sys_io:docs", "//third_party/pigweed/src/pw_sys_io_ambiq_sdk:docs", "//third_party/pigweed/src/pw_sys_io_arduino:docs", "//third_party/pigweed/src/pw_sys_io_baremetal_lm3s6965evb:docs", "//third_party/pigweed/src/pw_sys_io_baremetal_stm32f429:docs", "//third_party/pigweed/src/pw_sys_io_emcraft_sf2:docs", "//third_party/pigweed/src/pw_sys_io_mcuxpresso:docs", "//third_party/pigweed/src/pw_sys_io_rp2040:docs", "//third_party/pigweed/src/pw_sys_io_stdio:docs", "//third_party/pigweed/src/pw_sys_io_stm32cube:docs", "//third_party/pigweed/src/pw_sys_io_zephyr:docs", "//third_party/pigweed/src/pw_system:docs", "//third_party/pigweed/src/pw_target_runner:docs", "//third_party/pigweed/src/pw_thread:docs", "//third_party/pigweed/src/pw_thread_embos:docs", "//third_party/pigweed/src/pw_thread_freertos:docs", "//third_party/pigweed/src/pw_thread_stl:docs", "//third_party/pigweed/src/pw_thread_threadx:docs", "//third_party/pigweed/src/pw_thread_zephyr:docs", "//third_party/pigweed/src/pw_tls_client:docs", "//third_party/pigweed/src/pw_tls_client_boringssl:docs", "//third_party/pigweed/src/pw_tls_client_mbedtls:docs", "//third_party/pigweed/src/pw_tokenizer:docs", "//third_party/pigweed/src/pw_toolchain:docs", "//third_party/pigweed/src/pw_toolchain_bazel:docs", "//third_party/pigweed/src/pw_trace:docs", "//third_party/pigweed/src/pw_trace_tokenized:docs", "//third_party/pigweed/src/pw_transfer:docs", "//third_party/pigweed/src/pw_uart:docs", "//third_party/pigweed/src/pw_unit_test:docs", "//third_party/pigweed/src/pw_unit_test_zephyr:docs", "//third_party/pigweed/src/pw_varint:docs", "//third_party/pigweed/src/pw_watch:docs", "//third_party/pigweed/src/pw_web:docs", "//third_party/pigweed/src/pw_work_queue:docs"]`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:562
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:566
 
 ### pw_module_tests
 
 A list with all Pigweed module test groups. DO NOT SET THIS BUILD ARGUMENT!
 
-**Current value (from the default):** `["//third_party/pigweed/src/docker:tests", "//third_party/pigweed/src/pw_alignment:tests", "//third_party/pigweed/src/pw_allocator:tests", "//third_party/pigweed/src/pw_analog:tests", "//third_party/pigweed/src/pw_android_toolchain:tests", "//third_party/pigweed/src/pw_arduino_build:tests", "//third_party/pigweed/src/pw_assert:tests", "//third_party/pigweed/src/pw_assert_basic:tests", "//third_party/pigweed/src/pw_assert_log:tests", "//third_party/pigweed/src/pw_assert_tokenized:tests", "//third_party/pigweed/src/pw_assert_zephyr:tests", "//third_party/pigweed/src/pw_async:tests", "//third_party/pigweed/src/pw_async2:tests", "//third_party/pigweed/src/pw_async2_basic:tests", "//third_party/pigweed/src/pw_async2_epoll:tests", "//third_party/pigweed/src/pw_async_basic:tests", "//third_party/pigweed/src/pw_base64:tests", "//third_party/pigweed/src/pw_bloat:tests", "//third_party/pigweed/src/pw_blob_store:tests", "//third_party/pigweed/src/pw_bluetooth:tests", "//third_party/pigweed/src/pw_bluetooth_hci:tests", "//third_party/pigweed/src/pw_bluetooth_profiles:tests", "//third_party/pigweed/src/pw_bluetooth_proxy:tests", "//third_party/pigweed/src/pw_bluetooth_sapphire:tests", "//third_party/pigweed/src/pw_boot:tests", "//third_party/pigweed/src/pw_boot_cortex_m:tests", "//third_party/pigweed/src/pw_build:tests", "//third_party/pigweed/src/pw_build_android:tests", "//third_party/pigweed/src/pw_build_info:tests", "//third_party/pigweed/src/pw_build_mcuxpresso:tests", "//third_party/pigweed/src/pw_bytes:tests", "//third_party/pigweed/src/pw_channel:tests", "//third_party/pigweed/src/pw_checksum:tests", "//third_party/pigweed/src/pw_chre:tests", "//third_party/pigweed/src/pw_chrono:tests", "//third_party/pigweed/src/pw_chrono_embos:tests", "//third_party/pigweed/src/pw_chrono_freertos:tests", "//third_party/pigweed/src/pw_chrono_rp2040:tests", "//third_party/pigweed/src/pw_chrono_stl:tests", "//third_party/pigweed/src/pw_chrono_threadx:tests", "//third_party/pigweed/src/pw_chrono_zephyr:tests", "//third_party/pigweed/src/pw_cli:tests", "//third_party/pigweed/src/pw_compilation_testing:tests", "//third_party/pigweed/src/pw_config_loader:tests", "//third_party/pigweed/src/pw_console:tests", "//third_party/pigweed/src/pw_containers:tests", "//third_party/pigweed/src/pw_cpu_exception:tests", "//third_party/pigweed/src/pw_cpu_exception_cortex_m:tests", "//third_party/pigweed/src/pw_crypto:tests", "//third_party/pigweed/src/pw_digital_io:tests", "//third_party/pigweed/src/pw_digital_io_linux:tests", "//third_party/pigweed/src/pw_digital_io_mcuxpresso:tests", "//third_party/pigweed/src/pw_digital_io_rp2040:tests", "//third_party/pigweed/src/pw_docgen:tests", "//third_party/pigweed/src/pw_doctor:tests", "//third_party/pigweed/src/pw_emu:tests", "//third_party/pigweed/src/pw_env_setup:tests", "//third_party/pigweed/src/pw_env_setup_zephyr:tests", "//third_party/pigweed/src/pw_file:tests", "//third_party/pigweed/src/pw_format:tests", "//third_party/pigweed/src/pw_function:tests", "//third_party/pigweed/src/pw_fuzzer:tests", "//third_party/pigweed/src/pw_grpc:tests", "//third_party/pigweed/src/pw_hdlc:tests", "//third_party/pigweed/src/pw_hex_dump:tests", "//third_party/pigweed/src/pw_i2c:tests", "//third_party/pigweed/src/pw_i2c_linux:tests", "//third_party/pigweed/src/pw_i2c_mcuxpresso:tests", "//third_party/pigweed/src/pw_i2c_rp2040:tests", "//third_party/pigweed/src/pw_ide:tests", "//third_party/pigweed/src/pw_interrupt:tests", "//third_party/pigweed/src/pw_interrupt_cortex_m:tests", "//third_party/pigweed/src/pw_interrupt_xtensa:tests", "//third_party/pigweed/src/pw_interrupt_zephyr:tests", "//third_party/pigweed/src/pw_intrusive_ptr:tests", "//third_party/pigweed/src/pw_json:tests", "//third_party/pigweed/src/pw_kvs:tests", "//third_party/pigweed/src/pw_libc:tests", "//third_party/pigweed/src/pw_libcxx:tests", "//third_party/pigweed/src/pw_log:tests", "//third_party/pigweed/src/pw_log_android:tests", "//third_party/pigweed/src/pw_log_basic:tests", "//third_party/pigweed/src/pw_log_null:tests", "//third_party/pigweed/src/pw_log_rpc:tests", "//third_party/pigweed/src/pw_log_string:tests", "//third_party/pigweed/src/pw_log_tokenized:tests", "//third_party/pigweed/src/pw_log_zephyr:tests", "//third_party/pigweed/src/pw_malloc:tests", "//third_party/pigweed/src/pw_malloc_freelist:tests", "//third_party/pigweed/src/pw_malloc_freertos:tests", "//third_party/pigweed/src/pw_metric:tests", "//third_party/pigweed/src/pw_minimal_cpp_stdlib:tests", "//third_party/pigweed/src/pw_module:tests", "//third_party/pigweed/src/pw_multibuf:tests", "//third_party/pigweed/src/pw_multisink:tests", "//third_party/pigweed/src/pw_package:tests", "//third_party/pigweed/src/pw_perf_test:tests", "//third_party/pigweed/src/pw_persistent_ram:tests", "//third_party/pigweed/src/pw_polyfill:tests", "//third_party/pigweed/src/pw_preprocessor:tests", "//third_party/pigweed/src/pw_presubmit:tests", "//third_party/pigweed/src/pw_protobuf:tests", "//third_party/pigweed/src/pw_protobuf_compiler:tests", "//third_party/pigweed/src/pw_random:tests", "//third_party/pigweed/src/pw_result:tests", "//third_party/pigweed/src/pw_ring_buffer:tests", "//third_party/pigweed/src/pw_router:tests", "//third_party/pigweed/src/pw_rpc:tests", "//third_party/pigweed/src/pw_rpc_transport:tests", "//third_party/pigweed/src/pw_rust:tests", "//third_party/pigweed/src/pw_sensor:tests", "//third_party/pigweed/src/pw_snapshot:tests", "//third_party/pigweed/src/pw_software_update:tests", "//third_party/pigweed/src/pw_span:tests", "//third_party/pigweed/src/pw_spi:tests", "//third_party/pigweed/src/pw_spi_linux:tests", "//third_party/pigweed/src/pw_spi_mcuxpresso:tests", "//third_party/pigweed/src/pw_spi_rp2040:tests", "//third_party/pigweed/src/pw_status:tests", "//third_party/pigweed/src/pw_stm32cube_build:tests", "//third_party/pigweed/src/pw_stream:tests", "//third_party/pigweed/src/pw_stream_shmem_mcuxpresso:tests", "//third_party/pigweed/src/pw_stream_uart_linux:tests", "//third_party/pigweed/src/pw_stream_uart_mcuxpresso:tests", "//third_party/pigweed/src/pw_string:tests", "//third_party/pigweed/src/pw_symbolizer:tests", "//third_party/pigweed/src/pw_sync:tests", "//third_party/pigweed/src/pw_sync_baremetal:tests", "//third_party/pigweed/src/pw_sync_embos:tests", "//third_party/pigweed/src/pw_sync_freertos:tests", "//third_party/pigweed/src/pw_sync_stl:tests", "//third_party/pigweed/src/pw_sync_threadx:tests", "//third_party/pigweed/src/pw_sync_zephyr:tests", "//third_party/pigweed/src/pw_sys_io:tests", "//third_party/pigweed/src/pw_sys_io_ambiq_sdk:tests", "//third_party/pigweed/src/pw_sys_io_arduino:tests", "//third_party/pigweed/src/pw_sys_io_baremetal_lm3s6965evb:tests", "//third_party/pigweed/src/pw_sys_io_baremetal_stm32f429:tests", "//third_party/pigweed/src/pw_sys_io_emcraft_sf2:tests", "//third_party/pigweed/src/pw_sys_io_mcuxpresso:tests", "//third_party/pigweed/src/pw_sys_io_rp2040:tests", "//third_party/pigweed/src/pw_sys_io_stdio:tests", "//third_party/pigweed/src/pw_sys_io_stm32cube:tests", "//third_party/pigweed/src/pw_sys_io_zephyr:tests", "//third_party/pigweed/src/pw_system:tests", "//third_party/pigweed/src/pw_target_runner:tests", "//third_party/pigweed/src/pw_thread:tests", "//third_party/pigweed/src/pw_thread_embos:tests", "//third_party/pigweed/src/pw_thread_freertos:tests", "//third_party/pigweed/src/pw_thread_stl:tests", "//third_party/pigweed/src/pw_thread_threadx:tests", "//third_party/pigweed/src/pw_thread_zephyr:tests", "//third_party/pigweed/src/pw_tls_client:tests", "//third_party/pigweed/src/pw_tls_client_boringssl:tests", "//third_party/pigweed/src/pw_tls_client_mbedtls:tests", "//third_party/pigweed/src/pw_tokenizer:tests", "//third_party/pigweed/src/pw_toolchain:tests", "//third_party/pigweed/src/pw_toolchain_bazel:tests", "//third_party/pigweed/src/pw_trace:tests", "//third_party/pigweed/src/pw_trace_tokenized:tests", "//third_party/pigweed/src/pw_transfer:tests", "//third_party/pigweed/src/pw_uart:tests", "//third_party/pigweed/src/pw_unit_test:tests", "//third_party/pigweed/src/pw_unit_test_zephyr:tests", "//third_party/pigweed/src/pw_varint:tests", "//third_party/pigweed/src/pw_watch:tests", "//third_party/pigweed/src/pw_web:tests", "//third_party/pigweed/src/pw_work_queue:tests"]`
+**Current value (from the default):** `["//third_party/pigweed/src/docker:tests", "//third_party/pigweed/src/pw_alignment:tests", "//third_party/pigweed/src/pw_allocator:tests", "//third_party/pigweed/src/pw_analog:tests", "//third_party/pigweed/src/pw_android_toolchain:tests", "//third_party/pigweed/src/pw_arduino_build:tests", "//third_party/pigweed/src/pw_assert:tests", "//third_party/pigweed/src/pw_assert_basic:tests", "//third_party/pigweed/src/pw_assert_log:tests", "//third_party/pigweed/src/pw_assert_tokenized:tests", "//third_party/pigweed/src/pw_assert_zephyr:tests", "//third_party/pigweed/src/pw_async:tests", "//third_party/pigweed/src/pw_async2:tests", "//third_party/pigweed/src/pw_async2_basic:tests", "//third_party/pigweed/src/pw_async2_epoll:tests", "//third_party/pigweed/src/pw_async_basic:tests", "//third_party/pigweed/src/pw_base64:tests", "//third_party/pigweed/src/pw_bloat:tests", "//third_party/pigweed/src/pw_blob_store:tests", "//third_party/pigweed/src/pw_bluetooth:tests", "//third_party/pigweed/src/pw_bluetooth_hci:tests", "//third_party/pigweed/src/pw_bluetooth_profiles:tests", "//third_party/pigweed/src/pw_bluetooth_proxy:tests", "//third_party/pigweed/src/pw_bluetooth_sapphire:tests", "//third_party/pigweed/src/pw_boot:tests", "//third_party/pigweed/src/pw_boot_cortex_m:tests", "//third_party/pigweed/src/pw_build:tests", "//third_party/pigweed/src/pw_build_android:tests", "//third_party/pigweed/src/pw_build_info:tests", "//third_party/pigweed/src/pw_build_mcuxpresso:tests", "//third_party/pigweed/src/pw_bytes:tests", "//third_party/pigweed/src/pw_channel:tests", "//third_party/pigweed/src/pw_checksum:tests", "//third_party/pigweed/src/pw_chre:tests", "//third_party/pigweed/src/pw_chrono:tests", "//third_party/pigweed/src/pw_chrono_embos:tests", "//third_party/pigweed/src/pw_chrono_freertos:tests", "//third_party/pigweed/src/pw_chrono_rp2040:tests", "//third_party/pigweed/src/pw_chrono_stl:tests", "//third_party/pigweed/src/pw_chrono_threadx:tests", "//third_party/pigweed/src/pw_chrono_zephyr:tests", "//third_party/pigweed/src/pw_cli:tests", "//third_party/pigweed/src/pw_compilation_testing:tests", "//third_party/pigweed/src/pw_config_loader:tests", "//third_party/pigweed/src/pw_console:tests", "//third_party/pigweed/src/pw_containers:tests", "//third_party/pigweed/src/pw_cpu_exception:tests", "//third_party/pigweed/src/pw_cpu_exception_cortex_m:tests", "//third_party/pigweed/src/pw_cpu_exception_risc_v:tests", "//third_party/pigweed/src/pw_crypto:tests", "//third_party/pigweed/src/pw_digital_io:tests", "//third_party/pigweed/src/pw_digital_io_linux:tests", "//third_party/pigweed/src/pw_digital_io_mcuxpresso:tests", "//third_party/pigweed/src/pw_digital_io_rp2040:tests", "//third_party/pigweed/src/pw_docgen:tests", "//third_party/pigweed/src/pw_doctor:tests", "//third_party/pigweed/src/pw_emu:tests", "//third_party/pigweed/src/pw_env_setup:tests", "//third_party/pigweed/src/pw_env_setup_zephyr:tests", "//third_party/pigweed/src/pw_file:tests", "//third_party/pigweed/src/pw_format:tests", "//third_party/pigweed/src/pw_function:tests", "//third_party/pigweed/src/pw_fuzzer:tests", "//third_party/pigweed/src/pw_grpc:tests", "//third_party/pigweed/src/pw_hdlc:tests", "//third_party/pigweed/src/pw_hex_dump:tests", "//third_party/pigweed/src/pw_i2c:tests", "//third_party/pigweed/src/pw_i2c_linux:tests", "//third_party/pigweed/src/pw_i2c_mcuxpresso:tests", "//third_party/pigweed/src/pw_i2c_rp2040:tests", "//third_party/pigweed/src/pw_ide:tests", "//third_party/pigweed/src/pw_interrupt:tests", "//third_party/pigweed/src/pw_interrupt_cortex_m:tests", "//third_party/pigweed/src/pw_interrupt_xtensa:tests", "//third_party/pigweed/src/pw_interrupt_zephyr:tests", "//third_party/pigweed/src/pw_intrusive_ptr:tests", "//third_party/pigweed/src/pw_json:tests", "//third_party/pigweed/src/pw_kvs:tests", "//third_party/pigweed/src/pw_libc:tests", "//third_party/pigweed/src/pw_libcxx:tests", "//third_party/pigweed/src/pw_log:tests", "//third_party/pigweed/src/pw_log_android:tests", "//third_party/pigweed/src/pw_log_basic:tests", "//third_party/pigweed/src/pw_log_null:tests", "//third_party/pigweed/src/pw_log_rpc:tests", "//third_party/pigweed/src/pw_log_string:tests", "//third_party/pigweed/src/pw_log_tokenized:tests", "//third_party/pigweed/src/pw_log_zephyr:tests", "//third_party/pigweed/src/pw_malloc:tests", "//third_party/pigweed/src/pw_malloc_freelist:tests", "//third_party/pigweed/src/pw_malloc_freertos:tests", "//third_party/pigweed/src/pw_metric:tests", "//third_party/pigweed/src/pw_minimal_cpp_stdlib:tests", "//third_party/pigweed/src/pw_module:tests", "//third_party/pigweed/src/pw_multibuf:tests", "//third_party/pigweed/src/pw_multisink:tests", "//third_party/pigweed/src/pw_package:tests", "//third_party/pigweed/src/pw_perf_test:tests", "//third_party/pigweed/src/pw_persistent_ram:tests", "//third_party/pigweed/src/pw_polyfill:tests", "//third_party/pigweed/src/pw_preprocessor:tests", "//third_party/pigweed/src/pw_presubmit:tests", "//third_party/pigweed/src/pw_protobuf:tests", "//third_party/pigweed/src/pw_protobuf_compiler:tests", "//third_party/pigweed/src/pw_random:tests", "//third_party/pigweed/src/pw_result:tests", "//third_party/pigweed/src/pw_ring_buffer:tests", "//third_party/pigweed/src/pw_router:tests", "//third_party/pigweed/src/pw_rpc:tests", "//third_party/pigweed/src/pw_rpc_transport:tests", "//third_party/pigweed/src/pw_rust:tests", "//third_party/pigweed/src/pw_sensor:tests", "//third_party/pigweed/src/pw_snapshot:tests", "//third_party/pigweed/src/pw_software_update:tests", "//third_party/pigweed/src/pw_span:tests", "//third_party/pigweed/src/pw_spi:tests", "//third_party/pigweed/src/pw_spi_linux:tests", "//third_party/pigweed/src/pw_spi_mcuxpresso:tests", "//third_party/pigweed/src/pw_spi_rp2040:tests", "//third_party/pigweed/src/pw_status:tests", "//third_party/pigweed/src/pw_stm32cube_build:tests", "//third_party/pigweed/src/pw_stream:tests", "//third_party/pigweed/src/pw_stream_shmem_mcuxpresso:tests", "//third_party/pigweed/src/pw_stream_uart_linux:tests", "//third_party/pigweed/src/pw_stream_uart_mcuxpresso:tests", "//third_party/pigweed/src/pw_string:tests", "//third_party/pigweed/src/pw_symbolizer:tests", "//third_party/pigweed/src/pw_sync:tests", "//third_party/pigweed/src/pw_sync_baremetal:tests", "//third_party/pigweed/src/pw_sync_embos:tests", "//third_party/pigweed/src/pw_sync_freertos:tests", "//third_party/pigweed/src/pw_sync_stl:tests", "//third_party/pigweed/src/pw_sync_threadx:tests", "//third_party/pigweed/src/pw_sync_zephyr:tests", "//third_party/pigweed/src/pw_sys_io:tests", "//third_party/pigweed/src/pw_sys_io_ambiq_sdk:tests", "//third_party/pigweed/src/pw_sys_io_arduino:tests", "//third_party/pigweed/src/pw_sys_io_baremetal_lm3s6965evb:tests", "//third_party/pigweed/src/pw_sys_io_baremetal_stm32f429:tests", "//third_party/pigweed/src/pw_sys_io_emcraft_sf2:tests", "//third_party/pigweed/src/pw_sys_io_mcuxpresso:tests", "//third_party/pigweed/src/pw_sys_io_rp2040:tests", "//third_party/pigweed/src/pw_sys_io_stdio:tests", "//third_party/pigweed/src/pw_sys_io_stm32cube:tests", "//third_party/pigweed/src/pw_sys_io_zephyr:tests", "//third_party/pigweed/src/pw_system:tests", "//third_party/pigweed/src/pw_target_runner:tests", "//third_party/pigweed/src/pw_thread:tests", "//third_party/pigweed/src/pw_thread_embos:tests", "//third_party/pigweed/src/pw_thread_freertos:tests", "//third_party/pigweed/src/pw_thread_stl:tests", "//third_party/pigweed/src/pw_thread_threadx:tests", "//third_party/pigweed/src/pw_thread_zephyr:tests", "//third_party/pigweed/src/pw_tls_client:tests", "//third_party/pigweed/src/pw_tls_client_boringssl:tests", "//third_party/pigweed/src/pw_tls_client_mbedtls:tests", "//third_party/pigweed/src/pw_tokenizer:tests", "//third_party/pigweed/src/pw_toolchain:tests", "//third_party/pigweed/src/pw_toolchain_bazel:tests", "//third_party/pigweed/src/pw_trace:tests", "//third_party/pigweed/src/pw_trace_tokenized:tests", "//third_party/pigweed/src/pw_transfer:tests", "//third_party/pigweed/src/pw_uart:tests", "//third_party/pigweed/src/pw_unit_test:tests", "//third_party/pigweed/src/pw_unit_test_zephyr:tests", "//third_party/pigweed/src/pw_varint:tests", "//third_party/pigweed/src/pw_watch:tests", "//third_party/pigweed/src/pw_web:tests", "//third_party/pigweed/src/pw_work_queue:tests"]`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:390
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:393
 
 ### pw_modules
 
 A list with paths to all Pigweed module. DO NOT SET THIS BUILD ARGUMENT!
 
-**Current value (from the default):** `["//third_party/pigweed/src/docker", "//third_party/pigweed/src/pw_alignment", "//third_party/pigweed/src/pw_allocator", "//third_party/pigweed/src/pw_analog", "//third_party/pigweed/src/pw_android_toolchain", "//third_party/pigweed/src/pw_arduino_build", "//third_party/pigweed/src/pw_assert", "//third_party/pigweed/src/pw_assert_basic", "//third_party/pigweed/src/pw_assert_log", "//third_party/pigweed/src/pw_assert_tokenized", "//third_party/pigweed/src/pw_assert_zephyr", "//third_party/pigweed/src/pw_async", "//third_party/pigweed/src/pw_async2", "//third_party/pigweed/src/pw_async2_basic", "//third_party/pigweed/src/pw_async2_epoll", "//third_party/pigweed/src/pw_async_basic", "//third_party/pigweed/src/pw_base64", "//third_party/pigweed/src/pw_bloat", "//third_party/pigweed/src/pw_blob_store", "//third_party/pigweed/src/pw_bluetooth", "//third_party/pigweed/src/pw_bluetooth_hci", "//third_party/pigweed/src/pw_bluetooth_profiles", "//third_party/pigweed/src/pw_bluetooth_proxy", "//third_party/pigweed/src/pw_bluetooth_sapphire", "//third_party/pigweed/src/pw_boot", "//third_party/pigweed/src/pw_boot_cortex_m", "//third_party/pigweed/src/pw_build", "//third_party/pigweed/src/pw_build_android", "//third_party/pigweed/src/pw_build_info", "//third_party/pigweed/src/pw_build_mcuxpresso", "//third_party/pigweed/src/pw_bytes", "//third_party/pigweed/src/pw_channel", "//third_party/pigweed/src/pw_checksum", "//third_party/pigweed/src/pw_chre", "//third_party/pigweed/src/pw_chrono", "//third_party/pigweed/src/pw_chrono_embos", "//third_party/pigweed/src/pw_chrono_freertos", "//third_party/pigweed/src/pw_chrono_rp2040", "//third_party/pigweed/src/pw_chrono_stl", "//third_party/pigweed/src/pw_chrono_threadx", "//third_party/pigweed/src/pw_chrono_zephyr", "//third_party/pigweed/src/pw_cli", "//third_party/pigweed/src/pw_compilation_testing", "//third_party/pigweed/src/pw_config_loader", "//third_party/pigweed/src/pw_console", "//third_party/pigweed/src/pw_containers", "//third_party/pigweed/src/pw_cpu_exception", "//third_party/pigweed/src/pw_cpu_exception_cortex_m", "//third_party/pigweed/src/pw_crypto", "//third_party/pigweed/src/pw_digital_io", "//third_party/pigweed/src/pw_digital_io_linux", "//third_party/pigweed/src/pw_digital_io_mcuxpresso", "//third_party/pigweed/src/pw_digital_io_rp2040", "//third_party/pigweed/src/pw_docgen", "//third_party/pigweed/src/pw_doctor", "//third_party/pigweed/src/pw_emu", "//third_party/pigweed/src/pw_env_setup", "//third_party/pigweed/src/pw_env_setup_zephyr", "//third_party/pigweed/src/pw_file", "//third_party/pigweed/src/pw_format", "//third_party/pigweed/src/pw_function", "//third_party/pigweed/src/pw_fuzzer", "//third_party/pigweed/src/pw_grpc", "//third_party/pigweed/src/pw_hdlc", "//third_party/pigweed/src/pw_hex_dump", "//third_party/pigweed/src/pw_i2c", "//third_party/pigweed/src/pw_i2c_linux", "//third_party/pigweed/src/pw_i2c_mcuxpresso", "//third_party/pigweed/src/pw_i2c_rp2040", "//third_party/pigweed/src/pw_ide", "//third_party/pigweed/src/pw_interrupt", "//third_party/pigweed/src/pw_interrupt_cortex_m", "//third_party/pigweed/src/pw_interrupt_xtensa", "//third_party/pigweed/src/pw_interrupt_zephyr", "//third_party/pigweed/src/pw_intrusive_ptr", "//third_party/pigweed/src/pw_json", "//third_party/pigweed/src/pw_kvs", "//third_party/pigweed/src/pw_libc", "//third_party/pigweed/src/pw_libcxx", "//third_party/pigweed/src/pw_log", "//third_party/pigweed/src/pw_log_android", "//third_party/pigweed/src/pw_log_basic", "//third_party/pigweed/src/pw_log_null", "//third_party/pigweed/src/pw_log_rpc", "//third_party/pigweed/src/pw_log_string", "//third_party/pigweed/src/pw_log_tokenized", "//third_party/pigweed/src/pw_log_zephyr", "//third_party/pigweed/src/pw_malloc", "//third_party/pigweed/src/pw_malloc_freelist", "//third_party/pigweed/src/pw_malloc_freertos", "//third_party/pigweed/src/pw_metric", "//third_party/pigweed/src/pw_minimal_cpp_stdlib", "//third_party/pigweed/src/pw_module", "//third_party/pigweed/src/pw_multibuf", "//third_party/pigweed/src/pw_multisink", "//third_party/pigweed/src/pw_package", "//third_party/pigweed/src/pw_perf_test", "//third_party/pigweed/src/pw_persistent_ram", "//third_party/pigweed/src/pw_polyfill", "//third_party/pigweed/src/pw_preprocessor", "//third_party/pigweed/src/pw_presubmit", "//third_party/pigweed/src/pw_protobuf", "//third_party/pigweed/src/pw_protobuf_compiler", "//third_party/pigweed/src/pw_random", "//third_party/pigweed/src/pw_result", "//third_party/pigweed/src/pw_ring_buffer", "//third_party/pigweed/src/pw_router", "//third_party/pigweed/src/pw_rpc", "//third_party/pigweed/src/pw_rpc_transport", "//third_party/pigweed/src/pw_rust", "//third_party/pigweed/src/pw_sensor", "//third_party/pigweed/src/pw_snapshot", "//third_party/pigweed/src/pw_software_update", "//third_party/pigweed/src/pw_span", "//third_party/pigweed/src/pw_spi", "//third_party/pigweed/src/pw_spi_linux", "//third_party/pigweed/src/pw_spi_mcuxpresso", "//third_party/pigweed/src/pw_spi_rp2040", "//third_party/pigweed/src/pw_status", "//third_party/pigweed/src/pw_stm32cube_build", "//third_party/pigweed/src/pw_stream", "//third_party/pigweed/src/pw_stream_shmem_mcuxpresso", "//third_party/pigweed/src/pw_stream_uart_linux", "//third_party/pigweed/src/pw_stream_uart_mcuxpresso", "//third_party/pigweed/src/pw_string", "//third_party/pigweed/src/pw_symbolizer", "//third_party/pigweed/src/pw_sync", "//third_party/pigweed/src/pw_sync_baremetal", "//third_party/pigweed/src/pw_sync_embos", "//third_party/pigweed/src/pw_sync_freertos", "//third_party/pigweed/src/pw_sync_stl", "//third_party/pigweed/src/pw_sync_threadx", "//third_party/pigweed/src/pw_sync_zephyr", "//third_party/pigweed/src/pw_sys_io", "//third_party/pigweed/src/pw_sys_io_ambiq_sdk", "//third_party/pigweed/src/pw_sys_io_arduino", "//third_party/pigweed/src/pw_sys_io_baremetal_lm3s6965evb", "//third_party/pigweed/src/pw_sys_io_baremetal_stm32f429", "//third_party/pigweed/src/pw_sys_io_emcraft_sf2", "//third_party/pigweed/src/pw_sys_io_mcuxpresso", "//third_party/pigweed/src/pw_sys_io_rp2040", "//third_party/pigweed/src/pw_sys_io_stdio", "//third_party/pigweed/src/pw_sys_io_stm32cube", "//third_party/pigweed/src/pw_sys_io_zephyr", "//third_party/pigweed/src/pw_system", "//third_party/pigweed/src/pw_target_runner", "//third_party/pigweed/src/pw_thread", "//third_party/pigweed/src/pw_thread_embos", "//third_party/pigweed/src/pw_thread_freertos", "//third_party/pigweed/src/pw_thread_stl", "//third_party/pigweed/src/pw_thread_threadx", "//third_party/pigweed/src/pw_thread_zephyr", "//third_party/pigweed/src/pw_tls_client", "//third_party/pigweed/src/pw_tls_client_boringssl", "//third_party/pigweed/src/pw_tls_client_mbedtls", "//third_party/pigweed/src/pw_tokenizer", "//third_party/pigweed/src/pw_toolchain", "//third_party/pigweed/src/pw_toolchain_bazel", "//third_party/pigweed/src/pw_trace", "//third_party/pigweed/src/pw_trace_tokenized", "//third_party/pigweed/src/pw_transfer", "//third_party/pigweed/src/pw_uart", "//third_party/pigweed/src/pw_unit_test", "//third_party/pigweed/src/pw_unit_test_zephyr", "//third_party/pigweed/src/pw_varint", "//third_party/pigweed/src/pw_watch", "//third_party/pigweed/src/pw_web", "//third_party/pigweed/src/pw_work_queue"]`
+**Current value (from the default):** `["//third_party/pigweed/src/docker", "//third_party/pigweed/src/pw_alignment", "//third_party/pigweed/src/pw_allocator", "//third_party/pigweed/src/pw_analog", "//third_party/pigweed/src/pw_android_toolchain", "//third_party/pigweed/src/pw_arduino_build", "//third_party/pigweed/src/pw_assert", "//third_party/pigweed/src/pw_assert_basic", "//third_party/pigweed/src/pw_assert_log", "//third_party/pigweed/src/pw_assert_tokenized", "//third_party/pigweed/src/pw_assert_zephyr", "//third_party/pigweed/src/pw_async", "//third_party/pigweed/src/pw_async2", "//third_party/pigweed/src/pw_async2_basic", "//third_party/pigweed/src/pw_async2_epoll", "//third_party/pigweed/src/pw_async_basic", "//third_party/pigweed/src/pw_base64", "//third_party/pigweed/src/pw_bloat", "//third_party/pigweed/src/pw_blob_store", "//third_party/pigweed/src/pw_bluetooth", "//third_party/pigweed/src/pw_bluetooth_hci", "//third_party/pigweed/src/pw_bluetooth_profiles", "//third_party/pigweed/src/pw_bluetooth_proxy", "//third_party/pigweed/src/pw_bluetooth_sapphire", "//third_party/pigweed/src/pw_boot", "//third_party/pigweed/src/pw_boot_cortex_m", "//third_party/pigweed/src/pw_build", "//third_party/pigweed/src/pw_build_android", "//third_party/pigweed/src/pw_build_info", "//third_party/pigweed/src/pw_build_mcuxpresso", "//third_party/pigweed/src/pw_bytes", "//third_party/pigweed/src/pw_channel", "//third_party/pigweed/src/pw_checksum", "//third_party/pigweed/src/pw_chre", "//third_party/pigweed/src/pw_chrono", "//third_party/pigweed/src/pw_chrono_embos", "//third_party/pigweed/src/pw_chrono_freertos", "//third_party/pigweed/src/pw_chrono_rp2040", "//third_party/pigweed/src/pw_chrono_stl", "//third_party/pigweed/src/pw_chrono_threadx", "//third_party/pigweed/src/pw_chrono_zephyr", "//third_party/pigweed/src/pw_cli", "//third_party/pigweed/src/pw_compilation_testing", "//third_party/pigweed/src/pw_config_loader", "//third_party/pigweed/src/pw_console", "//third_party/pigweed/src/pw_containers", "//third_party/pigweed/src/pw_cpu_exception", "//third_party/pigweed/src/pw_cpu_exception_cortex_m", "//third_party/pigweed/src/pw_cpu_exception_risc_v", "//third_party/pigweed/src/pw_crypto", "//third_party/pigweed/src/pw_digital_io", "//third_party/pigweed/src/pw_digital_io_linux", "//third_party/pigweed/src/pw_digital_io_mcuxpresso", "//third_party/pigweed/src/pw_digital_io_rp2040", "//third_party/pigweed/src/pw_docgen", "//third_party/pigweed/src/pw_doctor", "//third_party/pigweed/src/pw_emu", "//third_party/pigweed/src/pw_env_setup", "//third_party/pigweed/src/pw_env_setup_zephyr", "//third_party/pigweed/src/pw_file", "//third_party/pigweed/src/pw_format", "//third_party/pigweed/src/pw_function", "//third_party/pigweed/src/pw_fuzzer", "//third_party/pigweed/src/pw_grpc", "//third_party/pigweed/src/pw_hdlc", "//third_party/pigweed/src/pw_hex_dump", "//third_party/pigweed/src/pw_i2c", "//third_party/pigweed/src/pw_i2c_linux", "//third_party/pigweed/src/pw_i2c_mcuxpresso", "//third_party/pigweed/src/pw_i2c_rp2040", "//third_party/pigweed/src/pw_ide", "//third_party/pigweed/src/pw_interrupt", "//third_party/pigweed/src/pw_interrupt_cortex_m", "//third_party/pigweed/src/pw_interrupt_xtensa", "//third_party/pigweed/src/pw_interrupt_zephyr", "//third_party/pigweed/src/pw_intrusive_ptr", "//third_party/pigweed/src/pw_json", "//third_party/pigweed/src/pw_kvs", "//third_party/pigweed/src/pw_libc", "//third_party/pigweed/src/pw_libcxx", "//third_party/pigweed/src/pw_log", "//third_party/pigweed/src/pw_log_android", "//third_party/pigweed/src/pw_log_basic", "//third_party/pigweed/src/pw_log_null", "//third_party/pigweed/src/pw_log_rpc", "//third_party/pigweed/src/pw_log_string", "//third_party/pigweed/src/pw_log_tokenized", "//third_party/pigweed/src/pw_log_zephyr", "//third_party/pigweed/src/pw_malloc", "//third_party/pigweed/src/pw_malloc_freelist", "//third_party/pigweed/src/pw_malloc_freertos", "//third_party/pigweed/src/pw_metric", "//third_party/pigweed/src/pw_minimal_cpp_stdlib", "//third_party/pigweed/src/pw_module", "//third_party/pigweed/src/pw_multibuf", "//third_party/pigweed/src/pw_multisink", "//third_party/pigweed/src/pw_package", "//third_party/pigweed/src/pw_perf_test", "//third_party/pigweed/src/pw_persistent_ram", "//third_party/pigweed/src/pw_polyfill", "//third_party/pigweed/src/pw_preprocessor", "//third_party/pigweed/src/pw_presubmit", "//third_party/pigweed/src/pw_protobuf", "//third_party/pigweed/src/pw_protobuf_compiler", "//third_party/pigweed/src/pw_random", "//third_party/pigweed/src/pw_result", "//third_party/pigweed/src/pw_ring_buffer", "//third_party/pigweed/src/pw_router", "//third_party/pigweed/src/pw_rpc", "//third_party/pigweed/src/pw_rpc_transport", "//third_party/pigweed/src/pw_rust", "//third_party/pigweed/src/pw_sensor", "//third_party/pigweed/src/pw_snapshot", "//third_party/pigweed/src/pw_software_update", "//third_party/pigweed/src/pw_span", "//third_party/pigweed/src/pw_spi", "//third_party/pigweed/src/pw_spi_linux", "//third_party/pigweed/src/pw_spi_mcuxpresso", "//third_party/pigweed/src/pw_spi_rp2040", "//third_party/pigweed/src/pw_status", "//third_party/pigweed/src/pw_stm32cube_build", "//third_party/pigweed/src/pw_stream", "//third_party/pigweed/src/pw_stream_shmem_mcuxpresso", "//third_party/pigweed/src/pw_stream_uart_linux", "//third_party/pigweed/src/pw_stream_uart_mcuxpresso", "//third_party/pigweed/src/pw_string", "//third_party/pigweed/src/pw_symbolizer", "//third_party/pigweed/src/pw_sync", "//third_party/pigweed/src/pw_sync_baremetal", "//third_party/pigweed/src/pw_sync_embos", "//third_party/pigweed/src/pw_sync_freertos", "//third_party/pigweed/src/pw_sync_stl", "//third_party/pigweed/src/pw_sync_threadx", "//third_party/pigweed/src/pw_sync_zephyr", "//third_party/pigweed/src/pw_sys_io", "//third_party/pigweed/src/pw_sys_io_ambiq_sdk", "//third_party/pigweed/src/pw_sys_io_arduino", "//third_party/pigweed/src/pw_sys_io_baremetal_lm3s6965evb", "//third_party/pigweed/src/pw_sys_io_baremetal_stm32f429", "//third_party/pigweed/src/pw_sys_io_emcraft_sf2", "//third_party/pigweed/src/pw_sys_io_mcuxpresso", "//third_party/pigweed/src/pw_sys_io_rp2040", "//third_party/pigweed/src/pw_sys_io_stdio", "//third_party/pigweed/src/pw_sys_io_stm32cube", "//third_party/pigweed/src/pw_sys_io_zephyr", "//third_party/pigweed/src/pw_system", "//third_party/pigweed/src/pw_target_runner", "//third_party/pigweed/src/pw_thread", "//third_party/pigweed/src/pw_thread_embos", "//third_party/pigweed/src/pw_thread_freertos", "//third_party/pigweed/src/pw_thread_stl", "//third_party/pigweed/src/pw_thread_threadx", "//third_party/pigweed/src/pw_thread_zephyr", "//third_party/pigweed/src/pw_tls_client", "//third_party/pigweed/src/pw_tls_client_boringssl", "//third_party/pigweed/src/pw_tls_client_mbedtls", "//third_party/pigweed/src/pw_tokenizer", "//third_party/pigweed/src/pw_toolchain", "//third_party/pigweed/src/pw_toolchain_bazel", "//third_party/pigweed/src/pw_trace", "//third_party/pigweed/src/pw_trace_tokenized", "//third_party/pigweed/src/pw_transfer", "//third_party/pigweed/src/pw_uart", "//third_party/pigweed/src/pw_unit_test", "//third_party/pigweed/src/pw_unit_test_zephyr", "//third_party/pigweed/src/pw_varint", "//third_party/pigweed/src/pw_watch", "//third_party/pigweed/src/pw_web", "//third_party/pigweed/src/pw_work_queue"]`
 
-From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:218
+From //third_party/pigweed/src/pw_build/generated_pigweed_modules_lists.gni:220
 
 ### pw_preprocessor_CONFIG
 
@@ -7123,10 +7081,11 @@
 Set to true to emit additional .rmeta files when compiling Rust rlibs.
 The .rmeta metadata files can be used by downstream build actions
 to quickly evaluate transitive dependencies (and remote inputs).
+This is required to support skipping downloads of rlibs.
 
-**Current value (from the default):** `false`
+**Current value (from the default):** `true`
 
-From //build/toolchain/rbe.gni:131
+From //build/toolchain/rbe.gni:132
 
 ### rust_incremental
 
@@ -7158,6 +7117,14 @@
 
 From //build/rust/build.gni:19
 
+### rust_parallel_frontend_threads
+
+Enable the rust parallel front-end with N threads
+
+**Current value (from the default):** `false`
+
+From //build/config/rust/BUILD.gn:36
+
 ### rust_rbe_check
 
 Run one of the more expensive checks, intended for CI.
@@ -7196,7 +7163,7 @@
 
 **Current value (from the default):** `true`
 
-From //build/toolchain/rbe.gni:135
+From //build/toolchain/rbe.gni:136
 
 ### rust_rbe_download_unstripped_binaries
 
@@ -7416,7 +7383,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:118
+From //BUILD.gn:132
 
 **Current value for `target_cpu = "x64"`:** `[]`
 
@@ -7424,7 +7391,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:118
+From //BUILD.gn:132
 
 ### sdk_cross_compile_host_tools
 
@@ -7454,19 +7421,6 @@
 
 From //build/sdk/config.gni:12
 
-### sdk_inside_supported_api_sub_build
-
-Whether currently building a sub-build for a specific supported API level
-rather than a build or sub-build at the default API level.
-Note that this can be false in sub-builds - specifically, when building the
-default API level for target CPUs other than the host.
-`sdk_inside_sub_build` must be true and `override_target_api_level` must be
-set to a valid level.
-
-**Current value (from the default):** `false`
-
-From //build/sdk/config.gni:20
-
 ### sdk_max_simultaneous_sub_builds
 
 An upper bound on the maximum number of subbuilds that may be running at the
@@ -7487,7 +7441,7 @@
 
 **Current value (from the default):** `5`
 
-From //build/sdk/config.gni:37
+From //build/sdk/config.gni:29
 
 ### sdk_sub_build_max_load_average
 
@@ -7497,7 +7451,7 @@
 
 **Current value (from the default):** `""`
 
-From //build/sdk/config.gni:49
+From //build/sdk/config.gni:41
 
 ### sdk_sub_build_parallelism
 
@@ -7509,7 +7463,7 @@
 
 **Current value (from the default):** `""`
 
-From //build/sdk/config.gni:44
+From //build/sdk/config.gni:36
 
 ### select_variant
 
@@ -7980,7 +7934,7 @@
 
 **Current value (from the default):** `""`
 
-From //BUILD.gn:114
+From //BUILD.gn:128
 
 ### test_package_labels
 
@@ -7993,7 +7947,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:86
+From //BUILD.gn:100
 
 **Current value for `target_cpu = "x64"`:** `[]`
 
@@ -8001,7 +7955,7 @@
 
 **Overridden from the default:** `[]`
 
-From //BUILD.gn:86
+From //BUILD.gn:100
 
 ### testonly_in_containers
 
@@ -8027,7 +7981,7 @@
 
 **Current value (from the default):** `"thinlto-cache"`
 
-From //build/config/lto/config.gni:16
+From //build/config/lto/config.gni:10
 
 ### thinlto_jobs
 
@@ -8035,7 +7989,7 @@
 
 **Current value (from the default):** `8`
 
-From //build/config/lto/config.gni:13
+From //build/config/lto/config.gni:7
 
 ### time_trace
 
@@ -8322,14 +8276,6 @@
 
 From //zircon/system/ulib/c/libc.gni:18
 
-### use_lto
-
-Use link time optimization (LTO).
-
-**Current value (from the default):** `false`
-
-From //build/config/lto/config.gni:7
-
 ### use_null_vulkan_on_host
 
 TODO(liyl): Currently non-x64 platforms don't have Vulkan support,
@@ -8352,7 +8298,7 @@
 
 **Current value (from the default):** `false`
 
-From //build/config/compiler.gni:41
+From //build/config/compiler.gni:43
 
 ### use_prebuilt_codec_runner_intel_gen
 
@@ -8417,14 +8363,6 @@
 
 From //src/lib/vulkan/build/config.gni:42
 
-### use_thinlto
-
-Use ThinLTO variant of LTO if use_lto = true.
-
-**Current value (from the default):** `true`
-
-From //build/config/lto/config.gni:10
-
 ### use_udev
 
 **Current value (from the default):** `false`
@@ -8853,13 +8791,13 @@
 
 **Current value (from the default):** `false`
 
-From //third_party/mesa/src/intel/vulkan/BUILD.gn:26
+From //third_party/mesa/src/intel/vulkan/BUILD.gn:29
 
 ### anv_enable_raytracing
 
 **Current value (from the default):** `false`
 
-From //third_party/mesa/src/intel/vulkan/BUILD.gn:27
+From //third_party/mesa/src/intel/vulkan/BUILD.gn:30
 
 ### anv_use_max_ram
 
@@ -8867,7 +8805,7 @@
 
 **Current value (from the default):** `false`
 
-From //third_party/mesa/src/intel/vulkan/BUILD.gn:30
+From //third_party/mesa/src/intel/vulkan/BUILD.gn:33
 
 ### build_libvulkan_goldfish
 
diff --git a/docs/get-started/sdk/learn/driver/driver-service.md b/docs/get-started/sdk/learn/driver/driver-service.md
index 95bdbbc..9566716 100644
--- a/docs/get-started/sdk/learn/driver/driver-service.md
+++ b/docs/get-started/sdk/learn/driver/driver-service.md
@@ -58,7 +58,7 @@
 *   `fuchsia_fidl_library()`: Declares the `examples.qemuedu` FIDL
     library and describes the FIDL source files it includes.
 *   `fuchsia_fidl_llcpp_library()`: Describes the generated
-    [LLCPP (Low-Level C++) bindings][fidl-cpp-bindings] for components to
+    [C++ wirebindings][fidl-cpp-bindings] for components to
     interact with this FIDL library.
 
 `qemu_edu/fidl/BUILD.bazel`:
@@ -224,4 +224,4 @@
 
 [concepts-capabilities]: /docs/concepts/components/v2/capabilities/README.md
 [concepts-devfs]: /docs/concepts/drivers/driver_communication.md#service_discovery_using_devfs
-[fidl-cpp-bindings]: /docs/development/languages/fidl/guides/c-family-comparison.md
+[fidl-cpp-bindings]: /docs/reference/fidl/bindings/cpp-bindings.md
diff --git a/docs/reference/fidl/bindings/cpp-bindings.md b/docs/reference/fidl/bindings/cpp-bindings.md
index a15bbed..55a6d4e 100644
--- a/docs/reference/fidl/bindings/cpp-bindings.md
+++ b/docs/reference/fidl/bindings/cpp-bindings.md
@@ -1,5 +1,17 @@
 # New C++ bindings
 
+<!-- TODO(https://fxbug.dev/42054534): Document natural bindings here too. -->
+
+The new C++ bindings come in **natural** and **wire** variants. The natural
+bindings are optimized for safety and ergonomics, while the wire bindings are
+optimized for performance. Most code should should use the natural bindings.
+Only turn to the wire bindings when performance requirements demand it or when
+you need precise control over memory allocation.
+
+Note: This page currently only documents the wire bindings. See the [New C++
+bindings tutorials] and [Comparing new C++ and high-level C++ language bindings]
+for examples of the natural bindings.
+
 ## Libraries {#libraries}
 
 Given the library declaration:
@@ -38,15 +50,15 @@
 
 ## Fields
 
-This section describes how the FIDL toolchain converts FIDL types to native
-types in LLCPP. These types can appear as members in an aggregate type or as
-parameters to a protocol method.
+This section describes how the FIDL toolchain converts FIDL types to C++ wire
+types. These types can appear as members in an aggregate type or as parameters
+to a protocol method.
 
 ### Built-in types {#builtins}
 
 The FIDL types are converted to C++ types based on the following table:
 
-|FIDL Type|LLCPP Type|
+|FIDL Type|C++ Wire Type|
 |--- |--- |
 |`bool`|`bool`, *(requires sizeof(bool) == 1)*|
 |`int8`|`int8_t`|
@@ -67,17 +79,16 @@
 |`zx.Handle`|`zx::handle`|
 |`zx.Handle:S`|The corresponding zx type is used whenever possible. For example, `zx::vmo` or `zx::channel`.|
 
-Nullable built-in types do not have different generated types than their
-non-nullable counterparts in LLCPP, and are omitted from the table above.
+Optional vectors, strings, client/server ends, and handles have the same C++
+wire types as their non-optional counterparts.
 
 ### User defined types {#user-defined-types}
 
-In LLCPP, a user defined type (bits, enum, constant, struct, union, or table) is
-referred to using the generated class or variable (see [Type
-Definitions](#type-definitions)). The nullable version of a user defined type
-`T` is referred to using a `fidl::ObjectView` of the generated type *except*
-for unions, which simply use the generated type itself. Refer to the [LLCPP
-memory guide][llcpp-allocation] for information about `ObjectView`.
+The C++ wire bindings define a class for each user defined bits, enum, struct,
+table, and union. For strict enums, they define an `enum class` instead of a
+regular class. For unions, they use the same class to represent optional and
+non-optional values. For boxed structs, they use `fidl::ObjectView`. See [Memory
+ownership of wire domain objects] to learn more about `fidl::ObjectView`.
 
 ## Type definitions {#type-definitions}
 
@@ -199,7 +210,7 @@
 }
 ```
 
-LLCPP does not currently support default values, and instead zero-initializes
+The C++ bindings do not support default values, and instead they zero-initialize
 all fields of the struct.
 
 Example usage:
@@ -277,7 +288,8 @@
 When a FIDL message containing a union with an unknown variant is decoded into
 `JsonValue`, `JsonValue::Which()` will return `JsonValue::Tag::kUnknown`.
 
-The LLCPP bindings do not store the raw bytes and handles of unknown variants.
+The C++ bindings bindings do not store the raw bytes and handles of unknown
+variants.
 
 Encoding a union with an unknown variant is not supported and will cause
 an encoding failure.
@@ -315,8 +327,8 @@
 `fidl::WireTableFrame<User>`.
 
 `fidl::WireTableFrame<User>` is a container for the table's internal storage,
-and is allocated separately from the builder because LLCPP maintains the object
-layout of the underlying wire format. It is only use internally by builders.
+and is allocated separately from the builder to maintain the object layout of
+the underlying wire format. It is only use internally by builders.
 
 `fidl::WireTableFrame<User>` has the following methods:
 
@@ -346,19 +358,19 @@
 {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/cpp/domain_objects/main.cc" region_tag="wire-tables" adjust_indentation="auto" exclude_regexp="^TEST|^}" %}
 ```
 
-In addition to assigning fields with `fidl::ObjectView`, any of the allocation
-strategies described in the [tutorial][llcpp-allocation] can also be used.
+In addition to assigning fields with `fidl::ObjectView`, you can use any of the
+allocation strategies described in [Memory ownership of wire domain objects].
 
 Note: Tables with unknown fields will decode successfully but will fail to
 encode.
 
 ### Inline layouts
 
-The generated C++ code uses the [the name reserved by `fidlc`][anon-names] for
+The generated C++ code uses the [the name chosen by `fidlc`][anon-names] for
 inline layouts.
 
-LLCPP also generates scoped names to refer to any inline layouts that were
-defined directly within a parent layout in FIDL. For example, for the FIDL:
+The C++ bindings also generate scoped names to refer to inline layouts. For
+example, for the FIDL:
 
 ```fidl
 type Outer = struct {
@@ -404,10 +416,10 @@
 
 ### Typed channel endpoints {#typed-channels}
 
-LLCPP sends and receives FIDL protocol messages over the
-[Zircon channel][zircon-channel] transport, which carry arbitrary blobs of bytes
-and handles. Rather than exposing raw endpoints, for instance `zx::channel`, the
-API exposes three templated endpoint classes:
+The C++ bindings send and receive FIDL protocol messages over the [Zircon
+channel][zircon-channel] transport, which carry arbitrary blobs of bytes and
+handles. Rather than exposing raw endpoints, for instance `zx::channel`, the API
+exposes three templated endpoint classes:
 
 * `fidl::ClientEnd<TicTacToe>`: the client endpoint of the `TicTacToe` protocol;
   it owns a `zx::channel`. Client bindings that require exclusive ownership of
@@ -495,8 +507,8 @@
 
 ### Client {#client}
 
-The LLCPP bindings provides multiple ways to interact with a FIDL protocol as a
-client:
+The C++ wire bindings bindings provides multiple ways to interact with a FIDL
+protocol as a client:
 
 * `fidl::WireClient<TicTacToe>`: This class exposes thread-safe APIs for
   outgoing asynchronous and synchronous calls as well as asynchronous event
@@ -511,15 +523,14 @@
   models compared to `WireClient`, but requires a two-phase shutdown pattern to
   prevent use-after-frees. Objects of this class may be destroyed on an
   arbitrary thread. It also supports use with a multi-threaded dispatcher. For
-  more details, see [LLCPP threading guide][llcpp-threading-guide].
+  more details, see the [New C++ bindings threading guide].
 * `fidl::WireSyncClient<TicTacToe>`: This class exposes purely synchronous APIs
   for outgoing calls as well as for event handling. It owns the client end of
   the channel.
 * `fidl::WireCall<TicTacToe>`: This class is identical to `WireSyncClient`
   except that it does not have ownership of the client end of the channel.
-  `WireCall` may be preferable to `WireSyncClient` when migrating code from the
-  C bindings to the LLCPP bindings, or when implementing C APIs that take raw
-  `zx_handle_t`s.
+  `WireCall` may be preferable to `WireSyncClient` when implementing C APIs that
+  take raw `zx_handle_t`s.
 
 #### WireClient {#async-client}
 
@@ -776,10 +787,10 @@
 * `virtual void MakeMove(MakeMoveRequestView request, MakeMoveCompleter::Sync&
   completer)`
 
-Refer to the [example LLCPP server][llcpp-server-example] for how to bind and
+Refer to the [example C++ server][cpp-server-example] for how to bind and
 set up a server implementation.
 
-The LLCPP bindings also provide functions for manually dispatching a message
+The C++ wire bindings also provide functions for manually dispatching a message
 given an implementation, `fidl::WireDispatch<TicTacToe>`:
 
 * `void fidl::WireDispatch<TicTacToe>(fidl::WireServer<TicTacToe>* impl,
@@ -798,7 +809,7 @@
 * `request->start_first`
 * `request->row`
 
-See [LLCPP memory guide][llcpp-allocation] for notes on request lifetime.
+See [Memory ownership of wire domain objects] for notes on request lifetime.
 
 #### Completers {#server-completers}
 
@@ -834,10 +845,10 @@
 
 Finally, sync completers for two way methods can be converted to an async
 completer using the `ToAsync()` method. Async completers can out-live the scope
-of the handler by e.g. moving it into a lambda capture (see [LLCPP
-tutorial][llcpp-async-example] for example usage), allowing the server to
+of the handler by e.g. moving it into a lambda capture, allowing the server to
 respond to requests asynchronously. The async completer has the same methods for
-responding to the client as the sync completer.
+responding to the client as the sync completer. See [Responding to requests
+asynchronously] for example usage
 
 Note: Each `Completer` object must only be accessed by one thread at a time.
 Simultaneous access from multiple threads will result in a crash.
@@ -914,8 +925,8 @@
 
 ### Events {#events}
 
-In LLCPP, events can be handled asynchronously or synchronously, depending
-on the type of [client](#client) being used.
+In the C++ bindings, events can be handled asynchronously or synchronously,
+depending on the type of [client](#client) being used.
 
 #### Async client {#async-event-handlers}
 
@@ -1186,10 +1197,10 @@
 
 ## Test scaffolding {#test-scaffolding}
 
-The FIDL toolchain also generates a file suffixed with `_test_base.h` that
-contains convenience code for testing FIDL client and server implementations. To
-use these headers, depend on the generated test scaffolding library with a
-`_testing` suffix (`my_library_llcpp_testing` instead of `my_library_llcpp`).
+The FIDL toolchain also generates a file named `wire_test_base.h` that contains
+convenience code for testing FIDL client and server implementations. To use
+these headers, depend on the bindings target label with a `_testing` suffix
+(`my_library_cpp_testing` instead of `my_library_cpp`).
 
 ### Server test base
 
@@ -1238,16 +1249,15 @@
 `OnOpponentMove`, which is implemented to just call
 `NotImplemented_("OnOpponentMove")`.
 
-
-<!-- xrefs -->
 [anon-names]: /docs/reference/fidl/language/language.md#inline-layouts
 [cpp-style]: https://google.github.io/styleguide/cppguide.html#Naming
 [generated-name-attr]: /docs/reference/fidl/language/attributes.md#generated-name
-[llcpp-allocation]: /docs/development/languages/fidl/tutorials/cpp/topics/wire-memory-ownership.md
-[llcpp-async-example]: /docs/development/languages/fidl/tutorials/cpp/topics/async-completer.md
-[llcpp-threading-guide]: /docs/development/languages/fidl/tutorials/cpp/topics/threading.md
-[llcpp-tutorial]: /docs/development/languages/fidl/tutorials/cpp
-[llcpp-server-example]: /examples/fidl/cpp/server/wire
+[Memory ownership of wire domain objects]: /docs/development/languages/fidl/tutorials/cpp/topics/wire-memory-ownership.md
+[Responding to requests asynchronously]: /docs/development/languages/fidl/tutorials/cpp/topics/async-completer.md
+[New C++ bindings threading guide]: /docs/development/languages/fidl/tutorials/cpp/topics/threading.md
+[New C++ bindings tutorials]: /docs/development/languages/fidl/tutorials/cpp
+[Comparing new C++ and high-level C++ language bindings]: /docs/development/languages/fidl/guides/c-family-comparison.md
+[cpp-server-example]: /examples/fidl/cpp/server/wire
 [lang-constants]: /docs/reference/fidl/language/language.md#constants
 [lang-bits]: /docs/reference/fidl/language/language.md#bits
 [lang-enums]: /docs/reference/fidl/language/language.md#enums
diff --git a/docs/reference/fidl/language/bindings-spec.md b/docs/reference/fidl/language/bindings-spec.md
index e8803cb..26f3bd3 100644
--- a/docs/reference/fidl/language/bindings-spec.md
+++ b/docs/reference/fidl/language/bindings-spec.md
@@ -517,8 +517,7 @@
 "linearization"). The downside of such an approach is that it makes the bindings
 more rigid: changes to the FIDL wire format become more complex to implement.
 
-The [LLCPP bindings][llcpp] are the only binding that take this
-approach.
+The [C++ wire bindings] are the only binding that take this approach.
 
 ### Equality comparison {#equality-comparison}
 
@@ -661,7 +660,7 @@
 [go-generated-code-comment]: https://github.com/golang/go/issues/13560#issuecomment-288457920
 [attributes]: /docs/reference/fidl/language/attributes.md
 [Life of a handle]: /docs/concepts/fidl/life-of-a-handle.md
-[llcpp]: /docs/reference/fidl/bindings/cpp-bindings.md
+[C++ wire bindings]: /docs/reference/fidl/bindings/cpp-bindings.md
 [source-compatible]: /docs/development/languages/fidl/guides/compatibility/README.md#strict-flexible
 [soft-transitions]: /docs/contribute/governance/rfcs/0002_platform_versioning.md#terminology
 [strict-event]: /docs/contribute/governance/rfcs/0138_handling_unknown_interactions.md#changes-to-bindings
diff --git a/docs/reference/fidl/language/language.md b/docs/reference/fidl/language/language.md
index 68a5de2..16b24c7 100644
--- a/docs/reference/fidl/language/language.md
+++ b/docs/reference/fidl/language/language.md
@@ -1,7 +1,7 @@
 # FIDL language specification
 
 This document is a specification of the Fuchsia Interface Definition Language
-(**FIDL**) syntax.
+(**FIDL**).
 
 For more information about FIDL's overall purpose, goals, and requirements,
 see [Overview][fidl-overview].
@@ -12,73 +12,71 @@
 
 ## Syntax
 
-FIDL provides a syntax for declaring named bits, constants, enums, structs,
-tables, unions, and protocols. These declarations are collected into libraries
-for distribution.
+FIDL provides a syntax for declaring data types and protocols. These
+declarations are collected into libraries for distribution.
 
-FIDL declarations are stored in plain text UTF-8 files. Each file consists of a
+FIDL declarations are stored in UTF-8 text files. Each file consists of a
 sequence of semicolon-delimited declarations. The order of declarations within a
-FIDL file, or among FIDL files within a library, is irrelevant. FIDL does not
-require (or support) forward declarations of any kind.
+FIDL file, or among FIDL files within a library, is irrelevant.
 
 ### Comments
 
-FIDL comments start with two (`//`) or three (`///`) forward slashes, continue
-to the end of the line, and can contain UTF-8 content (which is, of course, ignored).
-The three-forward-slash variant is a "documentation comment", and causes the comment
-text to be emitted into the generated code (as a comment, escaped correctly
-for the target language).
+FIDL comments start with two forward slashes (`//`) and continue to the end of
+the line. Comments that start with three forward slashes (`///`) are called
+documentation comments, and get emitted as comments in the generated bindings.
 
 ```fidl
 {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference.test.fidl" region_tag="comments" %}
 ```
 
-Note that documentation comments can also be provided via the [`@doc`
-attribute][doc-attribute].
-
 ### Keywords
 
-The following are keywords in FIDL.
+The following words have special meaning in FIDL:
 
 ```
-alias, as, bits, compose, const, enum, error, flexible, library, optional,
-protocol, resource, service, strict, struct, table, type, union, using.
+ajar, alias, as, bits, closed, compose, const, enum, error, false, flexible,
+library, open, optional, protocol, resource, service, strict, struct, table,
+true, type, union, using.
+```
+
+However, FIDL has no reserved keywords. For example:
+
+```fidl
+{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference.test.fidl" region_tag="keywords" %}
 ```
 
 ### Identifiers {#identifiers}
 
-FIDL _identifiers_ label declarations and their members. FIDL identifiers must
-match the regex `[a-zA-Z]([a-zA-Z0-9_]*[a-zA-Z0-9])?`. In words: identifiers
-must start with a letter, can contain letters, numbers, and underscores, but
-cannot end with an underscore.
+#### Library names
+
+FIDL _library names_ label [FIDL libraries](#libraries). They consist of one or
+more components separated by dots (`.`). Each component must match the regex
+`[a-z][a-z0-9]*`. In words: library name components must start with a lowercase
+letter, can contain lowercase letters, and numbers.
 
 ```fidl
-// a struct named "Foo"
-type Foo = struct {};
-
-// an enum named "enum", containing a single member
-type enum = enum { WITH_A_MEMBER = 1; };
-```
-
-Note: While using keywords as identifiers is supported, it can lead to
-confusion, and should therefore be considered on a case-by-case basis. See the
-`Names` section of the [Style Rubric][naming-style].
-
-FIDL _library names_ label [FIDL libraries](#libraries). FIDL library names
-consist of one or more elements each matching the regex `[a-z][a-z0-9]*`. In
-words: library name elements must start with a lowercase letter, can contain
-lowercase letters, and numbers (they cannot contain uppercase letters, nor
-underscores). Library names are used in [Qualified
-Identifiers](#qualified-identifiers).
-
-```fidl
-// a library named "foo"
+// A library named "foo".
 library foo;
 ```
 
-Identifiers and library names are case-sensitive.
+#### Identifiers
 
-### Qualified Identifiers {#qualified-identifiers}
+FIDL _identifiers_ label declarations and their members. They must match the
+regex `[a-zA-Z]([a-zA-Z0-9_]*[a-zA-Z0-9])?`. In words: identifiers must start
+with a letter, can contain letters, numbers, and underscores, but cannot end
+with an underscore.
+
+```fidl
+// A struct named "Foo".
+type Foo = struct {};
+```
+
+FIDL identifiers are case sensitive. However, identifiers must have unique
+_canonical forms_, otherwise the FIDL compiler will fail with [fi-0035:
+Canonical name collision](/reference/fidl/language/errcat#fi-0035). The
+canonical form of an identifier is obtained by converting it to `snake_case`.
+
+#### Qualified identifiers {#qualified-identifiers}
 
 FIDL always looks for unqualified symbols within the scope of the current
 library. To reference symbols in other libraries, they must be qualified by
@@ -111,34 +109,78 @@
 };
 ```
 
+#### Resolution algorithm {#resolution-algorithm}
+
+FIDL uses the following algorithm to resolve identifiers. When a "try resolving"
+step fails, it proceeds to the next step. When a "resolve" step fails, the
+compiler produces an error.
+
+* If it is unqualified:
+    1. Try resolving as a declaration in the current library.
+    2. Try resoving as a builtin declaration, e.g. `bool` refers to `fidl.bool`.
+    3. Resolve as a contextual bits/enum member, e.g. the `CHANNEL` in
+       `zx.handle:CHANNEL` refers to `zx.ObjType.Channel`.
+* If it is qualified as `X.Y`:
+    1. Try resolving `X` as a declaration within the current library:
+        1. Resolve `Y` as a member of `X`.
+    2. Resolve `X` as a library name or alias.
+        1. Resolve `Y` as a declaration in `X`.
+* If it is qualified as `x.Y.Z` where `x` represents one or more components:
+    1. Try resolving `x.Y` as a library name or alias:
+        1. Resolve `Z` as a declaration in `x.Y`.
+    2. Resolve `x` as a library name or alias:
+        1. Resolve `Y` as a declaration in `x`:
+            1. Resolve `Z` as a member of `x.Y`.
+
+Note: If you import libraries `X` and `X.Y`, and library `X` defines an enum
+named `Y`, you cannot refer to a member of that enum since `X.Y.Z` would be
+interpreted as the declaration `Z` from library `X.Y`, even if no such
+declaration exists. To refer to the enum member, you would have to remove or
+alias one of the imports. This should not come up in practice when following the
+[FIDL Style Guide][naming-style], which mandates `lowercase` library names and
+`UpperCamel` declaration names.
+
+#### Fully qualified names {#fqn}
+
+FIDL uses fully qualified names (abbreviated "FQN") to refer unambiguously to
+declarations and members. An FQN consts of a library name, a slash `/`, a
+declaration identifier, and optionally a dot `.` and member identifier. For
+example:
+
+* `fuchsia.io/MAX_BUF` refers to the `MAX_BUF` constant in library `fuchsia.io`.
+* `fuchsia.process/Launcher.Launch` refers to the `Launch` method in the
+  `Launcher` protocol of library `fuchsia.process`.
+
+FQNs are used in error messages, in the FIDL JSON intermediate representation,
+and in documentation comment cross references. They are also used as method
+selectors, which method ordinals are derived from.
+
 ### Literals
 
-FIDL supports integer, floating point, boolean, string, and enumeration literals, using
-a simplified syntax familiar to C programmers (see below for examples).
+FIDL supports the following kinds of literals:
+
+* Boolean: `true`, `false`
+* Integer: `0`, `-1`, `123`, `0xABC`, `0b101`, etc.
+* Floating point: `1.23`, `-0.01`, `1e5`, `2.0e-3`, etc.
+* String: `"hello"`, `"\\ \" \n \r \t \u{1f642}"`, etc.
 
 ### Constants {#constants}
 
-FIDL supports the following constant types: bits, booleans, signed and unsigned
-integers, floating point values, strings, and enumerations.
-The syntax is similar to C:
+FIDL allows defining constants for all types that support literals (boolean,
+integer, floating point, and string), and bits and enums. For example:
 
 ```fidl
 {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference.test.fidl" region_tag="consts" %}
 ```
 
-These declarations introduce a name within their scope.
-The constant's type must be either a primitive or an enum.
+Constant expressions are either literals, references to other constants,
+references to bits or enum members, or a combination of bits members separated
+by the pipe character (`|`). FIDL does not support any other arithmetic
+expressions such as `1 + 2`.
 
-Constant expressions are either literals or the names of other
-constant expressions.
+### Declaration separator
 
-> For greater clarity, there is no expression processing in FIDL; that is,
-> you *cannot* declare a constant as having the value `6 + 5`, for
-> example.
-
-### Declaration Separator
-
-FIDL uses the semi-colon **';'** to separate adjacent declarations within the
+FIDL uses the semicolon (`;`) to separate adjacent declarations within the
 file, much like C.
 
 ## Libraries {#libraries}
@@ -149,20 +191,21 @@
 // library identifier separated by dots
 library fuchsia.composition;
 
-// "using" to import library "fuchsia.buffers"
-using fuchsia.buffers;
+// "using" to import library "fuchsia.mem"
+using fuchsia.mem;
 
-// "using" to import library "fuchsia.geometry" and create a shortform called "geo"
+// "using" to import library "fuchsia.geometry" under the alias "geo"
 using fuchsia.geometry as geo;
 ```
 
-Libraries may declare that they use other libraries with a "using" declaration.
-This allows the library to refer to symbols defined in other libraries upon which
-they depend. Symbols imported this way may be accessed by:
+Libraries may declare that they use other libraries with a `using` declaration.
+This allows the library to refer to symbols defined in other libraries upon
+which they depend. Symbols imported this way may be accessed by qualifying them
+with the library name, as in `fuchsia.mem.Range`.
 
-*   qualifying them with the fully qualified library name (as in _"fuchsia.geometry.Rect"_),
-*   specifying just the library name (as in _"geometry.Rect"_), or,
-*   using a library alias (as in _"geo.Rect"_).
+A `using` declaration can also specify an alias with the `as` syntax. In this
+case, symbols in the other library can only be accessed by qualifying them with
+the alias, as in `geo.Rect` (using `fuchsia.geometry.Rect` would not work).
 
 In the source tree, each library consists of a directory with some number of
 **.fidl** files. The name of the directory is irrelevant to the FIDL compiler
@@ -172,17 +215,17 @@
 The scope of `library` and `using` declarations is limited to a single file.
 Each individual file within a FIDL library must restate the `library`
 declaration together with any `using` declarations needed by that file.
+Libraries with multiple files [conventionally have an overview.fidl
+file][library-overview] containing only a `library` declaration along with
+attributes and a documentation comment.
 
 The library's name may be used by certain language bindings to provide scoping
-for symbols emitted by the code generator.
+for symbols emitted by the code generator. For example, the C++ bindings
+generator places declarations for the FIDL library `fuchsia.ui` within the C++
+namespace `fuchsia_ui`. Similarly, for languages such as Dart and Rust, which
+have their own module system, each FIDL library is compiled as a module.
 
-For example, the C++ bindings generator places declarations for the
-FIDL library `fuchsia.ui` within the C++ namespace
-`fuchsia::ui`. Similarly, for languages such as Dart and Rust, which
-have their own module system, each FIDL library is compiled as a
-module for that language.
-
-## Types and Type Declarations
+## Types and type declarations
 
 FIDL supports a number of builtin types as well as declarations of new types
 (e.g. structs, unions, type aliases) and protocols.
@@ -190,7 +233,7 @@
 ### Primitives
 
 *   Simple value types.
-*   Never optional.
+*   Cannot be optional.
 
 The following primitive types are supported:
 
@@ -199,10 +242,7 @@
 *    Unsigned integer        **`uint8 uint16 uint32 uint64`**
 *    IEEE 754 Floating-point **`float32 float64`**
 
-Numbers are suffixed with their size in bits, **`bool`** is 1
-byte.
-
-We also alias **`byte`** to mean **`uint8`** as a [built-in alias](#built-in-aliases).
+Numbers are suffixed with their size in bits, **`int8`** is 1 byte.
 
 #### Use
 
@@ -213,13 +253,11 @@
 ### Bits {#bits}
 
 * Named bit types.
-* Discrete subset of bit values chosen from an underlying integer primitive
-  type.
-* Never optional.
+* Discrete subset of bit values chosen from an underlying integer type.
+* Cannot be optional.
 * Bits can either be [`strict` or `flexible`](#strict-vs-flexible).
 * Bits default to `flexible`.
-* `strict` bits must have at least one member (`flexible` bits can be
-  memberless).
+* `strict` bits must have at least one member (`flexible` bits can be empty).
 
 #### Operators
 
@@ -234,9 +272,8 @@
 ### Enums {#enums}
 
 * Proper enumerated types.
-* Discrete subset of named values chosen from an underlying integer primitive
-  type.
-* Never optional.
+* Discrete subset of named values chosen from an underlying integer type.
+* Cannot be optional.
 * Enums can be [`strict` or `flexible`](#strict-vs-flexible).
 * Enums default to `flexible`.
 * `strict` enums must have at least one member (`flexible` enums can be
@@ -244,9 +281,9 @@
 
 #### Declaration
 
-The ordinal index is **required** for each enum element. The underlying type of
+The ordinal is **required** for each enum element. The underlying type of
 an enum must be one of: **int8, uint8, int16, uint16, int32, uint32, int64,
-uint64**. If omitted, the underlying type is assumed to be **uint32**.
+uint64**. If omitted, the underlying type defaults to **uint32**.
 
 ```fidl
 {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference.test.fidl" region_tag="enums" %}
@@ -265,16 +302,14 @@
 ### Arrays
 
 *   Fixed-length sequences of homogeneous elements.
-*   Elements can be of any type including: primitives, enums, arrays, strings,
-    vectors, handles, structs, tables, unions.
-*   Never optional themselves; may contain optional types.
+*   Elements can be of any type.
+*   Cannot be optional themselves; may contain optional types.
 
 #### Use
 
-Arrays are denoted **`array<T, N>`** where _T_ can
-be any FIDL type (including an array) and _N_ is a positive
-integer constant expression that specifies the number of elements in
-the array.
+Arrays are denoted **`array<T, N>`** where _T_ can be any FIDL type (including
+an array) and _N_ is a positive integer constant expression that specifies the
+number of elements in the array.
 
 ```fidl
 {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference.test.fidl" region_tag="arrays" %}
@@ -288,8 +323,8 @@
 
 *   Variable-length sequence of UTF-8 encoded characters representing text.
 *   Can be optional; absent strings and empty strings are distinct.
-*   Can specify a maximum size, e.g. **`string:40`** for a
-    maximum 40 byte string.
+*   Can specify a maximum size, e.g. **`string:40`** for a maximum 40 byte
+    string. By default, `string` means `string:MAX`, i.e unbounded.
 *   String literals support the escape sequences `\\`, `\"`, `\n`, `\r`, `\t`,
     and `\u{X}` where the `X` is 1 to 6 hex digits for a Unicode code point.
 *   May contain embedded `NUL` bytes, unlike traditional C strings.
@@ -323,8 +358,8 @@
 
 *   Variable-length sequence of homogeneous elements.
 *   Can be optional; absent vectors and empty vectors are distinct.
-*   Can specify a maximum size, e.g. **`vector<T>:40`** for a
-    maximum 40 element vector.
+*   Can specify a maximum size, e.g. **`vector<T>:40`** for a maximum 40 element
+    vector. By default, `vector<T>` means `vector<T>:MAX`, i.e. unbounded.
 *   There is no special case for vectors of bools. Each bool element takes one
     byte as usual.
 
@@ -490,7 +525,7 @@
 {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference.test.fidl" region_tag="unions-use" %}
 ```
 
-### Strict vs. Flexible {#strict-vs-flexible}
+### Strict vs. flexible {#strict-vs-flexible}
 
 FIDL type declarations can either have **strict** or **flexible** behavior:
 
@@ -524,7 +559,7 @@
 Note: A type that is both flexible and a [value type](#value-vs-resource) will
 not allow deserializing unknown data that contains handles.
 
-### Value vs. Resource {#value-vs-resource}
+### Value vs. resource {#value-vs-resource}
 
 Every FIDL type is either a **value type** or a **resource type**. Resource
 types include:
@@ -568,18 +603,15 @@
 ### Protocols {#protocols}
 
 *   Describe methods that can be invoked by sending messages over a channel.
-*   Methods are identified by their ordinal index. The compiler calculates the ordinal by
-    * Taking the SHA-256 hash of the string generated by concatenating:
-        * The UTF-8 encoded library name, with no trailing \0 character
-        * '.' (ASCII 0x2e)
-        * The UTF-8 encoded protocol name, with no trailing \0 character
-        * '/' (ASCII 0x2f)
-        * The UTF-8 encoded method name, with no trailing \0 character
-    * Extracting the upper 32 bits of the hash value, and
-    * Setting the upper bit of that value to 0.
-    * To coerce the compiler into generating a different value, methods can have
-      a `@selector` attribute.  The value of the `@selector` attribute will be
-      used in the place of the method name above.
+*   Methods are identified by their ordinal. The compiler calculates it by:
+    * Taking the SHA-256 hash of the method's [fully qualified name](#fqn).
+    * Extracting the first 8 bytes of the hash digest,
+    * Interpreting those bytes as a little endian integer,
+    * Setting the upper bit (i.e. last bit) of that value to 0.
+    * To override the ordinal, methods can have a `@selector` attribute. If the
+      attribute's argument is a valid FQN, it will be used in place of the FQN
+      above. Otherwise, it must be a valid identifier, and will be used in place
+      of the method name when constructing the FQN.
 *   Each method declaration states its arguments and results.
     *   If no results are declared, then the method is one-way: no response will
         be generated by the server.
@@ -622,7 +654,7 @@
 {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference.test.fidl" region_tag="endpoints" %}
 ```
 
-### Protocol Composition {#protocol-composition}
+### Protocol composition {#protocol-composition}
 
 A protocol can include methods from other protocols.
 This is called composition: you compose one protocol from other protocols.
@@ -746,11 +778,6 @@
 
 ### Unknown interactions {#unknown-interactions}
 
-Note: Unknown interaction handling is an experimental feature. Most libraries
-currently cannot use it. This notice will be updated when it is available for
-general use. Please contact fidl-dev@fuchsia.dev if you have questions about
-using it.
-
 Protocols can define how they react when they receive a method call or event
 which has an ordinal which isn't recognized. Unrecognized ordinals occur
 primarily when a client and server were built using different versions of a
@@ -845,20 +872,6 @@
 *   `ajar`: Can compose `ajar` and `closed` protocols.
 *   `closed`: Can only compose other `closed` protocols.
 
-#### Behavior prior to unknown interactions
-
-Before unknown interactions support was added to FIDL, all protocols behaved as
-if they were `closed` and all methods behaved as if they were `strict`. The
-default values for protocols and methods with the `unknown_interactions`
-experiment enabled are `open` and `flexible`. This means that to avoid changing
-from `closed` and `strict` to `open` and `flexible` when you enable
-`unknown_interactions`, you need to add explicit `closed` and `strict` modifiers
-to any existing protocols and methods.
-
-See the [compatibility
-guide](/docs/development/languages/fidl/guides/compatibility/README.md) for more
-information about migrating unknown interactions modifiers.
-
 ### Aliasing {#aliasing}
 
 Type aliasing is supported. For example:
@@ -882,38 +895,28 @@
 Here, the `Message` struct contains a string of `MAX_SIZE` bytes called `baseline`,
 and a vector of up to `5` strings of `MAX_SIZE` called `chapters`.
 
-Note that **`byte`** is a built-in aliases, [see below](#built-in-aliases).
-
 <<../../../development/languages/fidl/widgets/_alias.md>>
 
-### Built-ins
+### Builtins
 
-FIDL provides several built-ins:
+FIDL provides the following builtins:
 
-* convenience types (**`byte`**)
-* `zx library` [see below](#zx-library)
+* Primitive types: `bool`, `int8`, `int16`, `int32`, `int64`, `uint8`, `uint16`,
+  `uint32`, `uint64`, `float32`, `float64`.
+* Other types: `string`, `client_end`, `server_end`.
+* Type templates: `array`, `vector`, `box`.
+* Aliases: `byte`.
+* Constraints: `optional`, `MAX`.
 
-#### Built-in aliases {#built-in-aliases}
+All builtins below to the `fidl` library. This library is always available and
+does not need to be imported with `using`. For example, if you declare a struct
+named `string`, you can refer to the original string type as `fidl.string`.
 
-The **`byte`** type is built-in, and is conceptually equivalent to:
+#### Library `zx` {#zx-library}
 
-```fidl
-{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference_builtin.test.fidl" region_tag="builtin" %}
-```
-
-When you refer to a name without specific scope, e.g.:
-
-```fidl
-{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/fidl/fuchsia.examples.docs/language_reference.test.fidl" region_tag="builtin-aliases" %}
-```
-
-we treat this as `builtin.byte` automatically (so long as there isn't a
-more-specific name in scope).
-
-#### ZX Library {#zx-library}
-
-The `fidlc` compiler automatically generates an internal [ZX library](library-zx.md)
-for you that contains commonly used Zircon definitions.
+Library `zx` is not built in, but it is treated specially by the compiler. It is
+defined in [//zircon/vdso/zx](/zircon/vdso/zx). Libraries import it with
+`using zx` and most commonly use the `zx.Handle` type.
 
 ### Inline layouts {#inline-layouts}
 
@@ -945,15 +948,15 @@
 };
 ```
 
-When an inline layout is used, `fidlc` will reserve a name for it that is
+When an inline layout is used, FIDL will reserve a name for it that is
 guaranteed to be unique, based on the [naming context][naming-context] that the
 layout is used in. This results in the following reserved names:
 
 * For inline layouts used as the type of an outer layout member, the reserved
   name is simply the name of the corresponding member.
-    * In the example above, the name `Options` is reserved for the inlined
+    * In the example above, the name `Options` is reserved for the inline
       `table`.
-* For top level request/response types, `fidlc` concatenates the protocol name,
+* For top level request/response types, FIDL concatenates the protocol name,
   the method name, and then either `"Request"` or `"Response"` depending on
   where the type is used.
     * In the example above, the name `LauncherGenerateTerrainRequest` is
@@ -973,7 +976,6 @@
 * Override the reserved name using the [`@generated_name`][generated-name-attr]
   attribute.
 
-<!-- xref -->
 [mixin]: https://en.wikipedia.org/wiki/Mixin
 [rfc-0023]: /docs/contribute/governance/rfcs/0023_compositional_model_protocols.md
 [rfc-0031]: /docs/contribute/governance/rfcs/0031_typed_epitaphs.md
@@ -993,3 +995,4 @@
 [naming-context]: /docs/contribute/governance/rfcs/0050_syntax_revamp.md#layout-naming-contexts
 [generated-name-attr]: /docs/reference/fidl/language/attributes.md#generated-name
 [Life of a handle]: /docs/concepts/fidl/life-of-a-handle.md
+[library-overview]: /docs/development/languages/fidl/guides/style.md#library-overview
diff --git a/docs/reference/testing/what-tests-to-write.md b/docs/reference/testing/what-tests-to-write.md
index fc4cbfcb..299b0e2 100644
--- a/docs/reference/testing/what-tests-to-write.md
+++ b/docs/reference/testing/what-tests-to-write.md
@@ -1,20 +1,25 @@
 # What Tests to Write
 
-## Motivation
+**Tests help uncover potential issues in code**, and the various types of tests offer different levels of coverage.
 
-Fuchsia developers seek guidance on what tests are actually necessary
-to validate the software they write. This includes component authors,
-driver authors, and anyone who publishes or maintains aspects of
-the API and ABI surface area of Fuchsia.
+This document guides developers (component authors, driver authors, and API/ABI maintainers) on the essential tests for validating Fuchsia software.
 
-We generally **write tests to detect things that may go wrong**
-with our code, and different types of tests provide coverage for
-different potential problems.
+The table below provides an overview of the types of tests categorized
+by what needs that type of test.
 
-This document describes the kinds of tests that provide different
-types of coverage.
-
-## Guidance
+|                                                            |Source Code|Components|Drivers|Protocols|
+|------------------------------------------------------------|-----------|----------|-------|---------|
+|[Unit](#unit-tests)                                         |All        |-         |-      |-        |
+|[Integration](#integration-tests)                           |-          |All       |Some   |-        |
+|[Compatibility (CTF)](#compatibility-tests)                 |-          |Some      |Some   |All (SDK)|
+|[Spec Conformance](#spec-conformance-tests)                 |-          |Some      |All    |Some     |
+|[Platform Expectation](#platform-expectation-tests)         |-          |Some      |Some   |Some     |
+|[System Interaction (Product)](#system-interaction-tests)   |-          |Some      |Some   |Some     |
+<!-- TODO(b/308191530): Fill out these sections
+|[Microbenchmarks](#microbenchmarks)|All (performance critical)|-|-|-
+|[Mezzobenchmarks](#mezzobenchmarks)|-|Some|Some|-
+|[Macrobenchmarks](#macrobenchmarks)|-|Some|Some|-
+-->
 
 The following sections categorize types of tests in terms of the
 following criteria:
@@ -33,36 +38,17 @@
 * When does Fuchsia run this type of test (when in the release
 pipeline is this kind of test run)
 
-The below table provides an overview of the types of tests categorized
-by what needs that type of test.
+## Unit Tests {#unit-tests}
 
-|                                                            |Source Code|Components|Drivers|Protocols|
-|------------------------------------------------------------|-----------|----------|-------|---------|
-|[Unit](#unit-tests)                                         |All        |-         |-      |-        |
-|[Hermetic integration](#hermetic-integration-tests)         |-          |All       |Some   |-        |
-|[Non-hermetic integration](#non-hermetic-integration-tests) |-          |Few       |Few    |-        |
-|[Compatibility (CTF)](#compatibility-tests)                 |-          |Some      |Some   |All (SDK)|
-|[Spec Conformance](#conformance-tests)                      |-          |Some      |Some   |Some     |
-|[On-device System Validation](#system-validation-tests)     |-          |Some      |Some   |Some     |
-|[Host-driven System Automation (Lacewing)](#lacewing-tests) |-          |Some      |Some   |Some     |
-<!-- TODO(b/308191530): Fill out these sections
-|[Microbenchmarks](#microbenchmarks)|All (performance critical)|-|-|-
-|[Mezzobenchmarks](#mezzobenchmarks)|-|Some|Some|-
-|[Macrobenchmarks](#macrobenchmarks)|-|Some|Some|-
--->
-
-
-### Unit Tests {#unit-tests}
-
-* What needs it: All source code
-* What does it test for: Code contracts for individual units of software
-* What are its key benefits: Permits more effective refactoring,
+* **What needs it:** All source code
+* **What does it test for:** Code contracts for individual units of software
+* **What are its key benefits:** Permits more effective refactoring,
 optimization, and development.
-* Where to view coverage: https://analysis.chromium.org/coverage/p/fuchsia
-* How to implement: Use a test framework for your language of choice
-* Who writes this kind of test: All component/driver owners
-* Where are the sources stored: Adjacent to the code being tested
-* When does Fuchsia run this type of test: Commit-Queue and Continuous
+* **Where to view coverage:** https://analysis.chromium.org/coverage/p/fuchsia
+* **How to implement:** Use a test framework for your language of choice
+* **Who writes this kind of test:** All component/driver owners
+* **Where are the sources stored:**  Adjacent to the code being tested
+* **When does Fuchsia run this type of test:** Commit-Queue and Continuous
 Integration
 
 All code should be covered by the smallest possible test that is
@@ -93,20 +79,37 @@
 Learn how to write driver unit tests in the
 [Driver unit testing quick start](/docs/development/sdk/driver-testing/driver-unit-testing-quick-start.md).
 
-### Hermetic Integration Tests {#hermetic-integration-tests}
+The diagram below shows unit tests running in a Fuchsia system.
+![Unit Tests](images/unit-test.png "Diagram shows unit tests  running in a Fuchsia system.")
 
-* What needs it: All components and many drivers
-* What does it test for: Runtime behavior and contracts
-* What are its key benefits: Ensures that a component or driver can
+### Integration Tests {#integration-tests}
+
+Integration tests check that the interface and behavior of one component works alongside another component that calls it.
+Validate that different components work together as a system and interact as expected.
+
+The following scenarios are validated for the component under test:
+
+* It can actually start up and respond to requests
+* It responds as expected to requests
+* It interacts as expected with its own dependencies
+* If the driver is made up of multiple components, check the components are behaving correctly inside the driver
+
+The recommendation is to to run integration tests hermetically (in isolation) using [Test Realm Factory](/docs/development/testing/components/test_realm_factory.md), but they can be run in non-hermetically if needed.
+
+### Hermetic Integration Tests
+
+* **What needs it:** All components and many drivers
+* **What does it test for:** Runtime behavior and contracts
+* **What are its key benefits:** Ensures that a component or driver can
 start up, initialize itself, and interact with dependencies
-* Where to view coverage: https://analysis.chromium.org/coverage/p/fuchsia.
+* **Where to view coverage:** https://analysis.chromium.org/coverage/p/fuchsia.
 Note that OOT use cases require build option changes to output
 coverage information and process it.
-* How to implement: [Test Realm
+* **How to implement:** [Test Realm
 Factory](/docs/development/testing/components/test_realm_factory.md)
-* Who writes this kind of test: All component authors, many driver developers
-* Where are the sources stored: Adjacent to the code being tested
-* When does Fuchsia run this type of test: Commit-Queue and Continuous
+* **Who writes this kind of test:** All component authors, many driver developers
+* **Where are the sources stored:**  Adjacent to the code being tested
+* **When does Fuchsia run this type of test:** Commit-Queue and Continuous
 Integration
 
 While unit tests are small and focused on specific pieces of business
@@ -131,11 +134,14 @@
 [DriverTestRealm](/docs/development/drivers/testing/driver_test_realm.md) and
 [Test UI Stack](/docs/contribute/governance/rfcs/0180_test_ui_stack.md)).
 
+The diagram below shows hermetic integration tests using the Test Realm pattern.
+![Integration Tests](images/integration-test.png "Diagram shows hermetic integration tests using the Test Realm pattern.")
+
 All tests on Fuchsia are hermetic by default, which means they
 automatically benefit from provable hermeticity and the ability to
 arbitrarily nest dependencies.
 
-**Hermetic Integration Tests** simply build on top of this foundation
+Hermetic Integration Tests simply build on top of this foundation
 to run a component or driver in an isolated test environment and
 interact with it using FIDL protocols. These tests cover the following
 scenarios for a component/driver:
@@ -171,22 +177,22 @@
 those tests should use TRF.**
 
 
-### Non-hermetic Integration Tests {#non-hermetic-integration-tests}
+### Non-hermetic Integration Tests
 
-* What needs it: Some components and drivers. Specifically those
+* **What needs it:** Some components and drivers. Specifically those
 that have dependencies that are difficult to mock or isolate (e.g. Vulkan).
-* What does it test for: System behavior and contracts
-* What are its key benefits: Ensures that a component or driver can
+* **What does it test for:** System behavior and contracts
+* **What are its key benefits:** Ensures that a component or driver can
 start up, initialize itself, and interact with dependencies, even
 when some of those dependencies are system-wide and non-hermetic.
-* Where to view coverage: https://analysis.chromium.org/coverage/p/fuchsia.
+* **Where to view coverage:** https://analysis.chromium.org/coverage/p/fuchsia.
 Note that OOT use cases require build option changes to output
 coverage information and process it.
-* How to implement: [Test Realm
+* **How to implement:** [Test Realm
 Factory](/docs/development/testing/components/test_realm_factory.md)
-* Who writes this kind of test: Some component and driver authors
-* Where are the sources stored: Adjacent to the code being tested
-* When does Fuchsia run this type of test: Commit-Queue and Continuous
+* **Who writes this kind of test:** Some component and driver authors
+* **Where are the sources stored:**  Adjacent to the code being tested
+* **When does Fuchsia run this type of test:** Commit-Queue and Continuous
 Integration
 
 While Hermetic Integration Tests are what we should strive for,
@@ -196,6 +202,9 @@
 we do not yet have a high-fidelity mock for Vulkan, so we allow
 certain tests access to the system-wide Vulkan capabilities.
 
+The diagram below shows non-hermetic integration tests with an outside system, component or driver interaction.
+![Integration Tests](images/integration-test-non-hermetic.png "Diagram shows non-hermetic integration tests with an outside system, component or driver interaction.")
+
 Tests that access system capabilities are called **Non-hermetic
 Integration Tests**. While they are technically not hermetic, they
 should still try to be as isolated as possible:
@@ -224,26 +233,29 @@
 System Interaction Tests](#lacewing-tests)).
 
 
-### Compatibility Tests (CTF) {#compatibility-tests}
+## Compatibility Tests (CTF) {#compatibility-tests}
 
-* What needs it: Protocols exposed in the SDK, but is also applicable
+* **What needs it:** Protocols exposed in the SDK, but is also applicable
 to client libraries and tools.
-* What does it test for: Platform ABI/API behavior consistency and
+* **What does it test for:** Platform ABI/API behavior consistency and
 compatibility
-* What are its key benefits: Ensures that the behavior of platform
+* **What are its key benefits:** Ensures that the behavior of platform
 protocols does not unexpectedly change in incompatible ways.
 Especially important for platform stability.
-* Where to view coverage: CTF coverage dashboard.
-* How to implement: Write a Test Realm Factory (TRF) integration
+* **Where to view coverage:** CTF coverage dashboard.
+* **How to implement:** Write a Test Realm Factory (TRF) integration
 test, [enable CTF
 mode](/docs/development/testing/ctf/contributing_tests.md).
-* Who writes this kind of test: All owners of SDK protocol
+* **Who writes this kind of test:** All owners of SDK protocol
 implementations
-* Where are the sources stored: fuchsia.git
-* When does Fuchsia run this type of test: Commit-Queue and Continuous
+* **Where are the sources stored:**  fuchsia.git
+* **When does Fuchsia run this type of test:** Commit-Queue and Continuous
 Integration
 
-In general, every FIDL protocol's stable API exposed by the SDK
+Compatibility tests provide early warning
+that a downstream breakage is possible due to a platform change,
+and it is especially important to ensure that our platform ABI
+remains stable. In general, every FIDL protocol's stable API exposed by the SDK
 should have a compatibility test for its API levels.
 
 These tests verify that _clients_ of the protocols, targeting a
@@ -277,10 +289,10 @@
 protocols are maintained across future modifications. Failing to
 provide this coverage means that subtle changes to the behavior or
 interface of SDK protocols will cause downstream breakages that are
-especially difficult to root cause. CTF tests provide early warning
-that a downstream breakage is possible due to a platform change,
-and it is especially important to ensure that our platform ABI
-remains stable.
+especially difficult to root cause.
+
+The diagram below shows compatibility tests for using the Test Realm Factory (TRF) pattern and a frozen component fake.
+![Compatibility Tests](images/compatibility-test.png "Diagram shows compatibility tests for using the Test Realm Factory (TRF) pattern and a frozen component fake.")
 
 Enabling CTF mode for a TRF test is a simple configuration option,
 and converting existing integration tests to TRF is straightforward
@@ -293,27 +305,27 @@
 **All components exposing protocols in the partner or public SDK
 should have a CTF test.**
 
-### Spec Conformance Tests {#conformance-tests}
+## Spec Conformance Tests {#spec-conformance-tests}
 
-* What needs it: Out-of-tree (OOT) drivers, components undergoing
+* **What needs it:** Out-of-tree (OOT) drivers, components undergoing
 migration from one implementation to another, (some) framework
 clients.
-* What does it test for: Consistency between different implementations
+* **What does it test for:** Consistency between different implementations
 of a protocol or library, to ensute they conform to the spec.
-* What are its key benefits: Ensures that different implementations
+* **What are its key benefits:** Ensures that different implementations
 of the same interface exhibit compatible behavior. This is especially
 useful for drivers where there may be multiple implementers of the
 same interface.
-* Where to view coverage: TODO
-* How to implement: Use parts of an existing TRF integration test
+* **Where to view coverage:** TODO
+* **How to implement:** Use parts of an existing TRF integration test
 to create a new TRF test. Alternatively write this test in Lacewing
 to interact with a complete system.
-* Who writes this kind of test: Contract/protocol owners define a
+* **Who writes this kind of test:** Contract/protocol owners define a
 test for requirements, and downstream users reuse or compose pieces
 of that test to ensure their code meets the requirements.
-* Where are the sources stored: fuchsia.git or built via the SDK
+* **Where are the sources stored:**  fuchsia.git or built via the SDK
 in stand-alone repos
-* When does Fuchsia run this type of test: Commit-Queue, out-of-tree
+* **When does Fuchsia run this type of test:** Commit-Queue, out-of-tree
 continuous integration.
 
 It is common for the Fuchsia Platform to define a contract that
@@ -338,8 +350,12 @@
 specification, and a Spec Conformance Test is used to validate this is
 the case.
 
+
+### Hermetic approach to spec conformance tests
+We test driver conformance by exercising the driver and checking for expected behaviour - for drivers that control devices this will require running on hardware (recommended approach). This is run by driver developers using the SDK at their desk (on hardware), and in their CI/CQ
+
 Spec Conformance Tests may build on top of TRF tests to have identical
-structure to Compatibility Tests. In this scenario, the primary
+structure to [Compatibility Tests](#compatibility-tests). In this scenario, the primary
 difference is in how the different pieces of the TRF test are used.
 
 The recommended pattern for Spec Conformance testing is to define a
@@ -356,6 +372,16 @@
 behind the FIDL protocol.  This means that the same exact set of
 tests that define the contract are applied to each implementation.
 
+The diagram below shows an approach for running spec conformance tests in a hermetic way.
+![Spec conformance tests (Hermetic)](images/specification-conformance-test.png "Diagram shows an approach for running spec conformance tests in a hermetic way")
+
+### Non-hermetic approach to spec conformance tests
+The non-hermetic approach to test spec conformance is to run the test on a working system using Lacewing for (hardware-dependent implementation). This is run by developers in their CI/CQ against the product implementation.
+
+The diagram below shows an approach for running spec conformance tests in a non-hermetic way.
+![Spec conformance tests (non-hermetic)](images/specification-conformance-test-non-hermetic.png "Diagram shows an approach for running spec conformance tests in a non-hermetic way.")
+
+### Host-driven approach to spec conformance tests
 Alternatively, Spec Conformance tests may be written using Lacewing
 and run as host-driven system interaction tests. This is particularly
 useful when the implementer of the protocol is a driver or otherwise
@@ -363,20 +389,23 @@
 product images including the driver both conform to the spec and
 were appropriately assembled to support interacting with hardware.
 
+The diagram below shows an approach for running spec conformance tests in a host-driven way.
+![Spec conformance tests (Host-driven)](images/specification-conformance-test-host-driven.png "Diagram shows an approach for running spec conformance tests in a host-driven way.")
+
 More concretely, we can solve the above examples as follows:
 
-1. **Drivers**
+1. **Drivers:**
    Define driver FIDL in fuchsia.git. Create a TRF test with
    associated Test Suite and FIDL protocol; ship them in the SDK.
    In an out-of-tree driver repo, implement the driver, create a
    RealmFactory that wraps the driver and implements the test
    FIDL. Run the distributed Test Suite against that RealmFactory.
-1. **Drivers (Lacewing)**
+1. **Drivers (Lacewing):**
    Create a Lacewing test that interacts with the driver's FIDL
    protocols from the host. Ship this test as a binary artifact
    that can be run in out-of-tree driver repos or during product
    assembly.
-1. **Component rewrite**
+1. **Component rewrite:**
    Create a new code base for the rewrite, create a skeleton TRF
    test implementing the test FIDL (following best practices to
    return non-failing
@@ -385,7 +414,7 @@
    Incrementally rewrite the component, and as test cases begin
    pass set failures for those cases to blocking. When all test
    cases pass, the rewrite is done, delete the old implementation.
-1. **Client libraries in multiple languages**
+1. **Client libraries in multiple languages:**
    Define the operations that are possible in your library as a
    test FIDL. Create a TRF test for one implementation of the
    library, then use the Test Suite from that implementation for
@@ -394,27 +423,30 @@
 **Interfaces that are expected to be implemented multiple times should ship
 a spec conformance test for integrators to build on top of.**
 
-### On-device System Validation Tests {#system-validation-tests}
+## Platform Expectation Tests {#platform-expectation-tests}
 
-* What needs it: Many platform components and drivers. For example,
+* **What needs it:** Many platform components and drivers. For example,
 drivers should ensure they interact with actual hardware on an
 assembled system.
-* What does it test for: Behavior of the component/driver on an
+* **What does it test for:** Behavior of the component/driver on an
 assembled product image
-* What are its key benefits: Ensures that a platform component/driver
+* **What are its key benefits:** Ensures that a platform component/driver
 behaves as expected when installed in an actual product. Helps to
 catch issues with capability routing and interactions with real
 hardware.
-* Where to view coverage: TODO
-* How to implement: Write a Test Realm Factory (TRF) integration
-test, create an execution realm, enable system validation mode
-(TODO).
-* Who writes this kind of test: Owners of platform components and drivers
-* Where are the sources stored: fuchsia.git, shipped in the SDK to
+* **Where to view coverage:** TODO
+* **How to implement:** Write a Test Realm Factory (TRF) integration
+test, create an execution realm, enable system validation mode (TODO). Take tests that assert on specifications and run these at every stage of the pipeline (reuse is highly encouraged). Leverage Platform Expectations Test Suit (PETS). <!-- do we want to talk about this? -->
+* **Who writes this kind of test:** Owners of platform components and drivers
+* **Where are the sources stored:**  fuchsia.git, shipped in the SDK to
 out-of-tree repositories
-* When does Fuchsia run this type of test: Commit-Queue, out-of-tree
+* **When does Fuchsia run this type of test:** Commit-Queue, out-of-tree
 continuous integration.
 
+The diagram below shows platform expectation tests where the tests are shipped with the SDK.
+
+![Platform expectation tests](images/platform-expectation-tests.png "Diagram shows platform expectation tests where the tests are shipped with the SDK.")
+
 Hermetic integration tests ensure that a component performs correctly
 in isolation, but it does not validate that an assembled system
 image including that component works properly. System validation
@@ -422,7 +454,7 @@
 ensures the real component behaves as expected, subject to some
 constraints.
 
-On-device system validation tests are typically based on hermetic TRF tests
+Platform Expectation tests are typically based on hermetic TRF tests
 consisting of a RealmFactory and Test Suite. Instead of using the
 RealmFactory (which instantiates isolated components under test),
 system validation tests use a stand-in component that provides
@@ -465,26 +497,27 @@
 cannot happen within the context of a device (e.g. rebooting the
 device as part of testing requires some process external to the
 device to coordinate). Certain host-driven system interaction
-tests (implemented using [Lacewing](#lacewing-tests)) can
-provide the same coverage as on-device system validation tests.
+tests (implemented as [System Interaction Tests](#system-interaction-tests)) can
+provide the same coverage as Platform Expectation tests.
 
-### Host-driven System Interaction Tests (Lacewing) {#lacewing-tests}
+## System Interaction (Product) Tests  {#system-interaction-tests}
+<!-- (Lacewing) -->
 
-* What needs it: Some components and drivers; individual user
+* **What needs it:** Some components and drivers; individual user
 journeys (for instance, validating responses when the user touches
 the screen).
-* What does it test for: Behavioral regressions in system services
+* **What does it test for:** Behavioral regressions in system services
 and individual user journeys.
-* What are its key benefits: Has complete control over one or more
+* **What are its key benefits:** Has complete control over one or more
 Fuchsia devices and non-Fuchsia peripherals. Covers cases requiring
 multiple devices, rebooting devices, or simulating user interaction
 with a device.
-* Where to view coverage: TODO
-* How to implement: Write a Python test using
+* **Where to view coverage:** TODO
+* **How to implement:** Write a Python test using
 [Mobly/Lacewing](https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/src/testing/end_to_end/examples)
-* Who writes this kind of test: Component/driver owners; product owners
-* Where are the sources stored: fuchsia.git or OOT
-* When does Fuchsia run this type of test: Commit-Queue, OOT
+* **Who writes this kind of test:** Component/driver owners; product owners
+* **Where are the sources stored:**  fuchsia.git or OOT
+* **When does Fuchsia run this type of test:** Commit-Queue, OOT
 Continuous Integration as needed
 
 Fuchsia makes hermetic testing possible for a wide range of cases
@@ -497,10 +530,9 @@
 A host-driven system interaction test has the ability to fully
 control a Fuchsia device using SDK tools and direct connection to
 services on the device. They are written using the Lacewing framework
-(build on Mobly), so we will refer to them as **Lacewing tests for
-short**.
+(build on Mobly).
 
-Lacewing tests can arbitrarily connect to services on a target
+Tests that use Lacewing can arbitrarily connect to services on a target
 system. Some tests are written to target specific drivers or
 subsystems (e.g. does the real-time clock save time across reboots?),
 some are written to cover user journeys that require device-wide
@@ -509,11 +541,14 @@
 of Fuchsia and non-Fuchsia devices in concert (e.g. can a Fuchsia
 device pair with a bluetooth accessory?).
 
-Lacewing test's interactions with the device are handled through
+With the Lacewing Framework, interactions with the device are handled through
 "affordances," which provide evolvable interfaces to interact with
 specific device subsystems (e.g. Bluetooth affordance, WLAN affordance,
 etc).
 
+Diagram shows an approach for running system interaction tests using Lacewing.
+![System Interaction Tests](images/system-interaction-test.png "Diagram shows an approach for running system interaction tests using Lacewing")
+
 As with most end-to-end (E2E) tests, this kind of testing can be
 expensive for several reasons:
 
@@ -529,9 +564,9 @@
 the desired outputs.
 
 **Some system components and drivers need this kind of test,** but
-the main benefit of Lacewing tests is to cover real-world device
+the main benefit of using Lacewing is to cover real-world device
 interactions that cannot be covered by isolated on-device tests.
 Choosing between system validation and Lacewing is often a judgement
 call, but there is space for both kinds of testing in a complete
 test strategy. Test authors should seek to get the coverage they
-need for the lowest maintenance cost.
+need for the lowest maintenance cost.
\ No newline at end of file
diff --git a/examples/components/config_from_parent/integration_test/cpp/test.cc b/examples/components/config_from_parent/integration_test/cpp/test.cc
index aba02cc..585e0d6 100644
--- a/examples/components/config_from_parent/integration_test/cpp/test.cc
+++ b/examples/components/config_from_parent/integration_test/cpp/test.cc
@@ -91,11 +91,10 @@
   child_ref.collection(kCollectionName);
   child_ref.name(child_name);
 
-  auto exposed_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ZX_ASSERT(!exposed_endpoints.is_error());
-  auto exposed_client = std::move(exposed_endpoints->client);
+  auto exposed_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+  auto exposed_client = std::move(exposed_endpoints.client);
 
-  realm->OpenExposedDir({child_ref, std::move(exposed_endpoints->server)})
+  realm->OpenExposedDir({child_ref, std::move(exposed_endpoints.server)})
       .ThenExactlyOnce([this](fidl::Result<fuchsia_component::Realm::OpenExposedDir>& result) {
         if (!result.is_ok()) {
           FX_LOGS(ERROR) << "OpenExposedDir failed: " << result.error_value();
@@ -149,11 +148,10 @@
   child_ref.collection(kCollectionName);
   child_ref.name(child_name);
 
-  auto exposed_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ZX_ASSERT(!exposed_endpoints.is_error());
-  auto exposed_client = std::move(exposed_endpoints->client);
+  auto exposed_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+  auto exposed_client = std::move(exposed_endpoints.client);
 
-  realm->OpenExposedDir({child_ref, std::move(exposed_endpoints->server)})
+  realm->OpenExposedDir({child_ref, std::move(exposed_endpoints.server)})
       .ThenExactlyOnce([this](fidl::Result<fuchsia_component::Realm::OpenExposedDir>& result) {
         if (!result.is_ok()) {
           FX_LOGS(ERROR) << "OpenExposedDir failed: " << result.error_value();
diff --git a/examples/components/pw_rpc/runner/component_runner.cc b/examples/components/pw_rpc/runner/component_runner.cc
index d1b4772..b6af88d 100644
--- a/examples/components/pw_rpc/runner/component_runner.cc
+++ b/examples/components/pw_rpc/runner/component_runner.cc
@@ -184,9 +184,8 @@
         if (!entry.directory().has_value()) {
           continue;
         }
-        auto log_sink_endpoints = fidl::CreateEndpoints<fuchsia_logger::LogSink>();
-        FX_CHECK(log_sink_endpoints.is_ok());
-        auto [log_sink_client_end, log_sink_server_end] = *std::move(log_sink_endpoints);
+        auto [log_sink_client_end, log_sink_server_end] =
+            fidl::Endpoints<fuchsia_logger::LogSink>::Create();
         const zx_handle_t svc_handle = entry.directory()->channel().get();
         if (zx_status_t status = fdio_service_connect_at(
                 svc_handle, "fuchsia.logger.LogSink", log_sink_server_end.TakeChannel().release());
diff --git a/examples/components/runner/colocated/BUILD.gn b/examples/components/runner/colocated/BUILD.gn
index d7e9030..de10635 100644
--- a/examples/components/runner/colocated/BUILD.gn
+++ b/examples/components/runner/colocated/BUILD.gn
@@ -22,21 +22,24 @@
   edition = "2021"
 
   deps = [
+    "//examples/components/runner/colocated/fidl:colocated_rust",
     "//sdk/fidl/fuchsia.component:fuchsia.component_rust",
     "//sdk/fidl/fuchsia.component.runner:fuchsia.component.runner_rust",
+    "//sdk/fidl/fuchsia.memory.attribution:fuchsia.memory.attribution_rust",
     "//sdk/fidl/fuchsia.process:fuchsia.process_rust",
+    "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia",
     "//src/lib/fuchsia-async",
     "//src/lib/fuchsia-component",
     "//src/lib/fuchsia-runtime",
-    "//src/lib/mapped-vmo",
+    "//src/lib/fuchsia-sync",
     "//src/lib/zircon/rust:fuchsia-zircon",
+    "//src/performance/memory/attribution",
     "//src/sys/lib/runner",
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:async-lock",
     "//third_party/rust_crates:async-trait",
     "//third_party/rust_crates:futures",
-    "//third_party/rust_crates:rand",
     "//third_party/rust_crates:scopeguard",
     "//third_party/rust_crates:tracing",
   ]
@@ -64,26 +67,14 @@
   manifest = "meta/colocated-runner-example.cml"
 }
 
-fuchsia_component("colocated-component-32mb") {
-  component_name = "colocated-component-32mb"
-  manifest = "meta/colocated-component-32mb.cml"
-}
-
-fuchsia_component("colocated-component-64mb") {
-  component_name = "colocated-component-64mb"
-  manifest = "meta/colocated-component-64mb.cml"
-}
-
-fuchsia_component("colocated-component-128mb") {
-  component_name = "colocated-component-128mb"
-  manifest = "meta/colocated-component-128mb.cml"
+fuchsia_component("colocated-component") {
+  component_name = "colocated-component"
+  manifest = "meta/colocated-component.cml"
 }
 
 fuchsia_package("colocated-runner-example") {
   deps = [
-    ":colocated-component-128mb",
-    ":colocated-component-32mb",
-    ":colocated-component-64mb",
+    ":colocated-component",
     ":colocated-runner",
     ":colocated-runner-example-realm",
   ]
@@ -92,11 +83,14 @@
 fuchsia_unittest_package("colocated-runner-unittests") {
   deps = [
     ":bin_test",
-    ":colocated-component-64mb",
+    ":colocated-component",
   ]
 }
 
 group("hermetic_tests") {
   testonly = true
-  deps = [ ":colocated-runner-unittests" ]
+  deps = [
+    ":colocated-runner-unittests",
+    "integration_tests",
+  ]
 }
diff --git a/examples/components/runner/colocated/README.md b/examples/components/runner/colocated/README.md
index 05977cb..05117e5 100644
--- a/examples/components/runner/colocated/README.md
+++ b/examples/components/runner/colocated/README.md
@@ -7,13 +7,14 @@
 ## What does this runner do
 
 The `colocated` runner demonstrates how to attribute memory to each component
-it runs. A program run by the `colocated` runner will allocate and map a VMO of
-a user-specified size, and then fill it with randomized bytes, to cause the
-pages to be physically allocated.
+it runs. A program run by the `colocated` runner will create and hold a VMO.
+This VMO will be reported by the runner as part of the memory attribution
+protocol.
 
-If the program is started with a `PA_USER0` numbered handle, it will signal the
-`USER_0` signal on the peer handle once it has done filling the VMO, to indicate
-that all the backing pages have been allocated.
+If the program is started with a `PA_USER0` numbered handle, it will serve the
+`fuchsia.examples.colocated.Colocated` protocol over this channel, which can be
+used to retrieve the koid of the VMO created by the colocated component, from
+the component itself.
 
 ## Program schema
 
@@ -50,14 +51,11 @@
 To run a colocated component, provide this URL to `ffx component run`:
 
 ```bash
-$ ffx component run /core/ffx-laboratory:colocated-runner-example/collection:1 'fuchsia-pkg://fuchsia.com/colocated-runner-example#meta/colocated-component-32mb.cm'
+$ ffx component run /core/ffx-laboratory:colocated-runner-example/collection:1 'fuchsia-pkg://fuchsia.com/colocated-runner-example#meta/colocated-component.cm'
 ```
 
-This will start a component that attempts to use 32 MiB of memory, living inside
-the address space of the `colocated` runner.
-
-You may replace `32mb` with `64mb` or `128mb` to test different sizes of memory
-usage.
+This will start a component that lives inside the address space of the
+`colocated` runner.
 
 You may replace `collection:1` with `collection:2` etc. to start multiple
 colocated components in this collection.
diff --git a/examples/components/runner/colocated/fidl/BUILD.gn b/examples/components/runner/colocated/fidl/BUILD.gn
new file mode 100644
index 0000000..0033b96
--- /dev/null
+++ b/examples/components/runner/colocated/fidl/BUILD.gn
@@ -0,0 +1,16 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/fidl/fidl.gni")
+
+fidl("colocated") {
+  # TODO(https://fxbug.dev/42180976) - The structure and location of FIDL libraries along
+  # with their names can be confusing. We should update this once we land on a
+  # decision in the linked bug.
+  name = "fuchsia.examples.colocated"
+
+  sources = [ "colocated.test.fidl" ]
+
+  public_deps = [ "//zircon/vdso/zx" ]
+}
diff --git a/examples/components/runner/colocated/fidl/colocated.test.fidl b/examples/components/runner/colocated/fidl/colocated.test.fidl
new file mode 100644
index 0000000..7486b2a
--- /dev/null
+++ b/examples/components/runner/colocated/fidl/colocated.test.fidl
@@ -0,0 +1,20 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// Library containing a protocol to report VMO usage by the colocated
+/// component.
+library fuchsia.examples.colocated;
+
+using zx;
+
+/// A protocol for reporting one's own VMO usage.
+///
+/// This protocol is used for integration testing.
+@discoverable
+open protocol Colocated {
+    /// Returns a list of VMO Koids used by the component,
+    GetVmos() -> (struct {
+        vmos vector<zx.Koid>:MAX;
+    });
+};
diff --git a/examples/components/runner/colocated/integration_tests/BUILD.gn b/examples/components/runner/colocated/integration_tests/BUILD.gn
new file mode 100644
index 0000000..a5dde7a
--- /dev/null
+++ b/examples/components/runner/colocated/integration_tests/BUILD.gn
@@ -0,0 +1,58 @@
+# Copyright 2023 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_fuchsia, "These targets are only compiled in the fuchsia toolchain.")
+
+import("//build/components.gni")
+import("//build/rust/rustc_test.gni")
+
+rustc_test("bin") {
+  name = "colocated_runner_integration_test_bin"
+  edition = "2021"
+
+  deps = [
+    "//examples/components/runner/colocated/fidl:colocated_rust",
+    "//sdk/fidl/fuchsia.component:fuchsia.component_rust",
+    "//sdk/fidl/fuchsia.component.decl:fuchsia.component.decl_rust",
+    "//sdk/fidl/fuchsia.memory.attribution:fuchsia.memory.attribution_rust",
+    "//sdk/fidl/fuchsia.process:fuchsia.process_rust",
+    "//src/lib/fuchsia",
+    "//src/lib/fuchsia-async",
+    "//src/lib/fuchsia-component-test",
+    "//src/lib/fuchsia-runtime",
+    "//src/lib/zircon/rust:fuchsia-zircon",
+    "//third_party/rust_crates:async-channel",
+    "//third_party/rust_crates:futures-util",
+  ]
+
+  sources = [ "src/lib.rs" ]
+}
+
+fuchsia_test_component("colocated_runner_integration_test") {
+  component_name = "colocated_runner_integration_test"
+  manifest = "meta/colocated_runner_integration_test.cml"
+  deps = [ ":bin" ]
+}
+
+fuchsia_component("test_realm") {
+  component_name = "test_realm"
+  manifest = "meta/test_realm.cml"
+  testonly = true
+}
+
+fuchsia_test_package("colocated-runner-integration-test") {
+  test_components = [ ":colocated_runner_integration_test" ]
+  deps = [
+    ":test_realm",
+    "//examples/components/runner/colocated:colocated-component",
+    "//examples/components/runner/colocated:colocated-runner",
+    "//src/sys/component_manager:component-manager-realm-builder-cmp",
+    "//src/sys/component_manager:elf_runner",
+  ]
+}
+
+group("integration_tests") {
+  testonly = true
+  deps = [ ":colocated-runner-integration-test" ]
+}
diff --git a/examples/components/runner/colocated/integration_tests/meta/colocated_runner_integration_test.cml b/examples/components/runner/colocated/integration_tests/meta/colocated_runner_integration_test.cml
new file mode 100644
index 0000000..903f09f
--- /dev/null
+++ b/examples/components/runner/colocated/integration_tests/meta/colocated_runner_integration_test.cml
@@ -0,0 +1,14 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "//src/lib/fuchsia-component-test/meta/nested_component_manager.shard.cml",
+        "//src/sys/test_runners/rust/default.shard.cml",
+        "sys/component/realm_builder.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/colocated_runner_integration_test_bin",
+    },
+}
diff --git a/examples/components/runner/colocated/integration_tests/meta/test_realm.cml b/examples/components/runner/colocated/integration_tests/meta/test_realm.cml
new file mode 100644
index 0000000..514dcf9
--- /dev/null
+++ b/examples/components/runner/colocated/integration_tests/meta/test_realm.cml
@@ -0,0 +1,53 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "syslog/offer.shard.cml" ],
+    children: [
+        {
+            name: "elf_runner",
+            url: "#meta/elf_runner.cm",
+        },
+        {
+            name: "colocated-runner",
+            url: "#meta/colocated-runner.cm",
+            environment: "#colocated-runner-env",
+        },
+    ],
+    collections: [
+        {
+            name: "collection",
+            environment: "#colocated-env",
+            durability: "single_run",
+        },
+    ],
+    offer: [
+        {
+            protocol: "fuchsia.process.Launcher",
+            from: "parent",
+            to: "#elf_runner",
+        },
+    ],
+    environments: [
+        {
+            name: "colocated-runner-env",
+            extends: "realm",
+            runners: [
+                {
+                    runner: "elf",
+                    from: "#elf_runner",
+                },
+            ],
+        },
+        {
+            name: "colocated-env",
+            extends: "realm",
+            runners: [
+                {
+                    runner: "colocated",
+                    from: "#colocated-runner",
+                },
+            ],
+        },
+    ],
+}
diff --git a/examples/components/runner/colocated/integration_tests/src/lib.rs b/examples/components/runner/colocated/integration_tests/src/lib.rs
new file mode 100644
index 0000000..799f5b5
--- /dev/null
+++ b/examples/components/runner/colocated/integration_tests/src/lib.rs
@@ -0,0 +1,260 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#![cfg(test)]
+
+use fidl_fuchsia_component as fcomponent;
+use fidl_fuchsia_component_decl as fdecl;
+use fidl_fuchsia_examples_colocated as fcolocated;
+use fidl_fuchsia_memory_attribution as fattribution;
+use fidl_fuchsia_process::HandleInfo;
+use fuchsia_async as fasync;
+use fuchsia_component_test::{
+    Capability, ChildOptions, RealmBuilder, RealmBuilderParams, Ref, Route,
+};
+use fuchsia_runtime::HandleType;
+use fuchsia_zircon as zx;
+use futures_util::{future::BoxFuture, FutureExt};
+use std::{collections::HashMap, sync::Arc};
+
+/// Attribute resource given the set of resources at the root of the system,
+/// and a protocol to attribute resources under different principals.
+fn attribute_memory<'a>(
+    name: String,
+    attribution_provider: fattribution::ProviderProxy,
+    introspector: &'a fcomponent::IntrospectorProxy,
+) -> BoxFuture<'a, Node> {
+    async move {
+        // Otherwise, check if there are attribution information.
+        let attributions = attribution_provider
+            .get()
+            .await
+            .unwrap_or_else(|e| panic!("Failed to get AttributionResponse for {name}: {e}"))
+            .unwrap_or_else(|e| panic!("Failed call to AttributionResponse for {name}: {e:?}"))
+            .attributions
+            .unwrap_or_else(|| panic!("Failed memory attribution for {name}"));
+
+        let mut node = Node::new(name);
+
+        // If there are children, resources assigned to this node by its parent
+        // will be re-assigned to children if applicable.
+        let mut children = HashMap::<String, Node>::new();
+        for attribution in attributions {
+            // Recursively attribute memory in this child principal.
+            match attribution {
+                fattribution::AttributionUpdate::Add(new_principal) => {
+                    let identifier =
+                        get_identifier_string(new_principal.identifier, &node.name, introspector)
+                            .await;
+                    let child = if let Some(client) = new_principal.detailed_attribution {
+                        attribute_memory(identifier, client.into_proxy().unwrap(), introspector)
+                            .await
+                    } else {
+                        Node::new(identifier)
+                    };
+                    children.insert(child.name.clone(), child);
+                }
+                fattribution::AttributionUpdate::Update(updated_principal) => {
+                    let identifier = get_identifier_string(
+                        updated_principal.identifier,
+                        &node.name,
+                        introspector,
+                    )
+                    .await;
+
+                    let child = children.get_mut(&identifier).unwrap();
+                    match updated_principal.resources.unwrap() {
+                        fattribution::Resources::Data(d) => {
+                            child.resources = d
+                                .into_iter()
+                                .filter_map(|r| {
+                                    if let fattribution::Resource::KernelObject(koid) = r {
+                                        Some(koid)
+                                    } else {
+                                        None
+                                    }
+                                })
+                                .collect();
+                        }
+                        _ => todo!("unimplemented"),
+                    };
+                }
+                fattribution::AttributionUpdate::Remove(_) => todo!(),
+                _ => panic!("Unimplemented"),
+            };
+        }
+        node.children.extend(children.into_values());
+        node
+    }
+    .boxed()
+}
+
+async fn get_identifier_string(
+    identifier: Option<fattribution::Identifier>,
+    name: &String,
+    introspector: &fcomponent::IntrospectorProxy,
+) -> String {
+    match identifier.unwrap() {
+        fattribution::Identifier::Self_(_) => todo!("self attribution not supported"),
+        fattribution::Identifier::Component(c) => introspector
+            .get_moniker(c)
+            .await
+            .expect("Inspector call failed")
+            .expect("Inspector::GetMoniker call failed"),
+        fattribution::Identifier::Part(sc) => format!("{}/{}", name, sc).to_owned(),
+        _ => todo!(),
+    }
+}
+
+#[derive(Debug)]
+struct Node {
+    name: String,
+    resources: Vec<u64>,
+    children: Vec<Node>,
+}
+
+impl Node {
+    pub fn new(identifier: String) -> Node {
+        Node { name: identifier, resources: vec![], children: vec![] }
+    }
+}
+
+#[fuchsia::test]
+async fn test_attribute_memory() {
+    // Starts a component manager and obtain its root job, so that we can simulate
+    // traversing the root job of the system, the kind done in `memory_monitor`.
+    let builder = RealmBuilder::with_params(
+        RealmBuilderParams::new().from_relative_url("#meta/test_realm.cm"),
+    )
+    .await
+    .expect("Failed to create test realm builder");
+
+    // Add a child to receive these capabilities so that we can use them in this test.
+    // - fuchsia.memory.attribution.Provider
+    // - fuchsia.component.Realm
+    struct Capabilities {
+        attribution_provider: fattribution::ProviderProxy,
+        introspector: fcomponent::IntrospectorProxy,
+        realm: fcomponent::RealmProxy,
+    }
+    let (capabilities_sender, capabilities_receiver) = async_channel::unbounded::<Capabilities>();
+    let capabilities_sender = Arc::new(capabilities_sender);
+    let receiver = builder
+        .add_local_child(
+            "receiver",
+            move |handles| {
+                let capabilities_sender = capabilities_sender.clone();
+                async move {
+                    capabilities_sender
+                        .send(Capabilities {
+                            attribution_provider: handles
+                                .connect_to_protocol::<fattribution::ProviderMarker>()
+                                .unwrap(),
+                            introspector: handles
+                                .connect_to_protocol::<fcomponent::IntrospectorMarker>()
+                                .unwrap(),
+                            realm: handles
+                                .connect_to_protocol::<fcomponent::RealmMarker>()
+                                .unwrap(),
+                        })
+                        .await
+                        .unwrap();
+
+                    Ok(())
+                }
+                .boxed()
+            },
+            ChildOptions::new().eager(),
+        )
+        .await
+        .expect("Failed to add child");
+
+    builder
+        .add_route(
+            Route::new()
+                .capability(Capability::protocol_by_name("fuchsia.memory.attribution.Provider"))
+                .from(Ref::child("elf_runner"))
+                .to(&receiver),
+        )
+        .await
+        .unwrap();
+
+    builder
+        .add_route(
+            Route::new()
+                .capability(Capability::protocol_by_name("fuchsia.component.Realm"))
+                .from(Ref::framework())
+                .to(&receiver),
+        )
+        .await
+        .unwrap();
+
+    builder
+        .add_route(
+            Route::new()
+                .capability(Capability::protocol_by_name("fuchsia.component.Introspector"))
+                .from(Ref::framework())
+                .to(&receiver),
+        )
+        .await
+        .unwrap();
+
+    let _realm =
+        builder.build_in_nested_component_manager("#meta/component_manager.cm").await.unwrap();
+
+    let capabilities = capabilities_receiver.recv().await.unwrap();
+
+    // Start a colocated component.
+    let collection = fdecl::CollectionRef { name: "collection".to_string() };
+    let decl = fdecl::Child {
+        name: Some("colocated-component".to_string()),
+        url: Some("#meta/colocated-component.cm".to_string()),
+        startup: Some(fdecl::StartupMode::Lazy),
+        ..Default::default()
+    };
+    let (user0, user0_peer) = zx::Channel::create();
+    let args = fcomponent::CreateChildArgs {
+        numbered_handles: Some(vec![HandleInfo {
+            handle: user0_peer.into(),
+            id: fuchsia_runtime::HandleInfo::new(HandleType::User0, 0).as_raw(),
+        }]),
+        ..Default::default()
+    };
+    capabilities.realm.create_child(&collection, &decl, args).await.unwrap().unwrap();
+
+    let colocated_component_vmos =
+        fcolocated::ColocatedProxy::new(fasync::Channel::from_channel(user0))
+            .get_vmos()
+            .await
+            .unwrap();
+
+    assert!(!colocated_component_vmos.is_empty());
+
+    // Starting from the ELF runner, ask about the resource usage.
+    let elf_runner = attribute_memory(
+        "elf_runner.cm".to_owned(),
+        capabilities.attribution_provider,
+        &capabilities.introspector,
+    )
+    .await;
+
+    // We should get the following tree:
+    //
+    // - elf_runner.cm
+    //     - colocated_runner.cm
+    //         - colocated_component.cm
+    //             - Some VMO
+    //         - overhead
+    //     - overhead
+    eprintln!("{:?}", elf_runner);
+    assert_eq!(elf_runner.children.len(), 1);
+    assert!(elf_runner.children[0].name.contains("colocated-runner"));
+    assert_eq!(elf_runner.children[0].children.len(), 1usize);
+    // Name of the colocated component
+    assert_eq!(&elf_runner.children[0].children[0].name, "collection:colocated-component");
+    let resource = &elf_runner.children[0].children[0].resources;
+    for vmo_koid in colocated_component_vmos {
+        assert!(resource.contains(&vmo_koid));
+    }
+}
diff --git a/examples/components/runner/colocated/meta/colocated-component-128mb.cml b/examples/components/runner/colocated/meta/colocated-component-128mb.cml
deleted file mode 100644
index cde1166..0000000
--- a/examples/components/runner/colocated/meta/colocated-component-128mb.cml
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    program: {
-        runner: "colocated",
-        vmo_size: "134217728",
-    },
-}
diff --git a/examples/components/runner/colocated/meta/colocated-component-32mb.cml b/examples/components/runner/colocated/meta/colocated-component-32mb.cml
deleted file mode 100644
index e39fc7e..0000000
--- a/examples/components/runner/colocated/meta/colocated-component-32mb.cml
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    program: {
-        runner: "colocated",
-        vmo_size: "33554432",
-    },
-}
diff --git a/examples/components/runner/colocated/meta/colocated-component-64mb.cml b/examples/components/runner/colocated/meta/colocated-component.cml
similarity index 87%
rename from examples/components/runner/colocated/meta/colocated-component-64mb.cml
rename to examples/components/runner/colocated/meta/colocated-component.cml
index 7efaa9b..ce40757 100644
--- a/examples/components/runner/colocated/meta/colocated-component-64mb.cml
+++ b/examples/components/runner/colocated/meta/colocated-component.cml
@@ -4,6 +4,5 @@
 {
     program: {
         runner: "colocated",
-        vmo_size: "67108864",
     },
 }
diff --git a/examples/components/runner/colocated/meta/colocated-runner.cml b/examples/components/runner/colocated/meta/colocated-runner.cml
index 5bc7277..d0a2759 100644
--- a/examples/components/runner/colocated/meta/colocated-runner.cml
+++ b/examples/components/runner/colocated/meta/colocated-runner.cml
@@ -6,6 +6,7 @@
     program: {
         runner: "elf",
         binary: "bin/colocated_runner",
+        memory_attribution: "true",
     },
     capabilities: [
         { protocol: "fuchsia.component.runner.ComponentRunner" },
@@ -13,6 +14,7 @@
             runner: "colocated",
             path: "/svc/fuchsia.component.runner.ComponentRunner",
         },
+        { protocol: "fuchsia.memory.attribution.Provider" },
     ],
     expose: [
         {
@@ -23,5 +25,9 @@
             runner: "colocated",
             from: "self",
         },
+        {
+            protocol: "fuchsia.memory.attribution.Provider",
+            from: "self",
+        },
     ],
 }
diff --git a/examples/components/runner/colocated/src/main.rs b/examples/components/runner/colocated/src/main.rs
index 3feb0c1..bd5e4b3 100644
--- a/examples/components/runner/colocated/src/main.rs
+++ b/examples/components/runner/colocated/src/main.rs
@@ -2,41 +2,71 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use anyhow::{anyhow, Context, Result};
+use anyhow::{Context, Result};
+use attribution::{AttributionServer, AttributionServerHandle, Observer, Publisher};
+use fidl::endpoints::ControlHandle;
+use fidl::endpoints::RequestStream;
 use fidl_fuchsia_component as fcomponent;
 use fidl_fuchsia_component_runner as fcrunner;
+use fidl_fuchsia_memory_attribution as fattribution;
 use fuchsia_async as fasync;
 use fuchsia_component::server::ServiceFs;
+use fuchsia_sync::Mutex;
 use fuchsia_zircon as zx;
 use futures::{StreamExt, TryStreamExt};
 use runner::component::{ChannelEpitaph, Controllable, Controller};
-use std::future::Future;
+use std::{
+    collections::HashMap,
+    future::Future,
+    sync::{
+        atomic::{AtomicU64, Ordering},
+        Arc,
+    },
+};
+
 use tracing::{info, warn};
+use zx::{HandleBased, Koid};
 
 mod program;
 
 use crate::program::ColocatedProgram;
 
-const VMO_SIZE: &str = "vmo_size";
-
 enum IncomingRequest {
     Runner(fcrunner::ComponentRunnerRequestStream),
+    Memory(fattribution::ProviderRequestStream),
 }
 
 #[fuchsia::main]
 async fn main() -> Result<()> {
+    let resource_tracker = Arc::new(ResourceTracker { resources: Mutex::new(Default::default()) });
+
     let mut service_fs = ServiceFs::new_local();
     service_fs.dir("svc").add_fidl_service(IncomingRequest::Runner);
+    service_fs.dir("svc").add_fidl_service(IncomingRequest::Memory);
     service_fs.take_and_serve_directory_handle().context("failed to serve outgoing namespace")?;
 
+    let memory_server_handle = get_memory_server(resource_tracker.clone());
+
     service_fs
-        .for_each_concurrent(None, |request: IncomingRequest| async move {
+        .for_each_concurrent(None, |request: IncomingRequest| async {
             match request {
                 IncomingRequest::Runner(stream) => {
-                    if let Err(err) = handle_runner_request(stream).await {
+                    if let Err(err) = handle_runner_request(
+                        stream,
+                        resource_tracker.clone(),
+                        memory_server_handle.clone(),
+                    )
+                    .await
+                    {
                         warn!("Error while serving ComponentRunner: {err}");
                     }
                 }
+                IncomingRequest::Memory(stream) => {
+                    let observer = memory_server_handle.new_observer(stream.control_handle());
+                    if let Err(err) = handle_memory_request(stream, observer).await {
+                        warn!("Error while serving AttributionProvider: {err}");
+                    }
+                }
             }
         })
         .await;
@@ -44,15 +74,24 @@
     Ok(())
 }
 
+fn get_memory_server(resource_tracker: Arc<ResourceTracker>) -> AttributionServerHandle {
+    let state_fn = Box::new(move || get_attribution(resource_tracker.clone()));
+    AttributionServer::new(state_fn)
+}
+
 /// Handles `fuchsia.component.runner/ComponentRunner` requests over a FIDL connection.
-async fn handle_runner_request(mut stream: fcrunner::ComponentRunnerRequestStream) -> Result<()> {
+async fn handle_runner_request(
+    mut stream: fcrunner::ComponentRunnerRequestStream,
+    resource_tracker: Arc<ResourceTracker>,
+    memory_server_handle: AttributionServerHandle,
+) -> Result<()> {
     while let Some(request) =
         stream.try_next().await.context("failed to serve ComponentRunner protocol")?
     {
         let fcrunner::ComponentRunnerRequest::Start { start_info, controller, .. } = request;
         let url = start_info.resolved_url.clone().unwrap_or_else(|| "unknown url".to_string());
         info!("Colocated runner is going to start component {url}");
-        match start(start_info) {
+        match start(start_info, resource_tracker.clone(), memory_server_handle.new_publisher()) {
             Ok((program, on_exit)) => {
                 let controller = Controller::new(program, controller.into_stream().unwrap());
                 fasync::Task::spawn(controller.serve(on_exit)).detach();
@@ -69,16 +108,115 @@
     Ok(())
 }
 
+async fn handle_memory_request(
+    mut stream: fattribution::ProviderRequestStream,
+    subscriber: Observer,
+) -> Result<()> {
+    while let Some(request) =
+        stream.try_next().await.context("failed to serve AttributionProvider protocol")?
+    {
+        match request {
+            fattribution::ProviderRequest::Get { responder } => {
+                subscriber.next(responder);
+            }
+            fattribution::ProviderRequest::_UnknownMethod { ordinal, control_handle, .. } => {
+                warn!("Invalid request to AttributionProvider: {ordinal}");
+                control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
+            }
+        }
+    }
+
+    Ok(())
+}
+
+fn get_attribution(resource_tracker: Arc<ResourceTracker>) -> Vec<fattribution::AttributionUpdate> {
+    let mut children = vec![];
+    for (_, (token, koid)) in resource_tracker.resources.lock().iter() {
+        children.push(fattribution::AttributionUpdate::Add(fattribution::NewPrincipal {
+            identifier: Some(fattribution::Identifier::Component(
+                token.duplicate_handle(fidl::Rights::SAME_RIGHTS).unwrap(),
+            )),
+            detailed_attribution: None,
+            ..Default::default()
+        }));
+        children.push(fattribution::AttributionUpdate::Update(fattribution::UpdatedPrincipal {
+            identifier: Some(fattribution::Identifier::Component(
+                token.duplicate_handle(fidl::Rights::SAME_RIGHTS).unwrap(),
+            )),
+            resources: Some(fattribution::Resources::Data(vec![
+                fattribution::Resource::KernelObject(koid.raw_koid()),
+            ])),
+            ..Default::default()
+        }));
+    }
+    children
+}
+
+/// Tracks resources used by each [`ColocatedProgram`]. Since each program just allocates
+/// one VMO, we only need to track one KOID here.
+struct ResourceTracker {
+    resources: Mutex<HashMap<ProgramId, (zx::Event, Koid)>>,
+}
+
+type ProgramId = u64;
+
+static NEXT_ID: AtomicU64 = AtomicU64::new(0);
+
 /// Starts a colocated component.
 fn start(
     start_info: fcrunner::ComponentStartInfo,
+    resource_tracker: Arc<ResourceTracker>,
+    publisher: Publisher,
 ) -> Result<(impl Controllable, impl Future<Output = ChannelEpitaph> + Unpin)> {
-    let vmo_size = runner::get_program_string(&start_info, VMO_SIZE)
-        .ok_or(anyhow!("Missing vmo_size argument in program block"))?;
-    let vmo_size: u64 = vmo_size.parse().context("vmo_size is not a valid number")?;
     let numbered_handles = start_info.numbered_handles.unwrap_or(vec![]);
-    let program = ColocatedProgram::new(vmo_size, numbered_handles)?;
+    let program = ColocatedProgram::new(numbered_handles)?;
+    let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
+    let vmo_koid = program.get_vmo_koid().raw_koid();
+    // Register this VMO.
+    let instance_token = start_info.component_instance.as_ref().unwrap();
+
+    let mut resources = resource_tracker.resources.lock();
+    resources.insert(
+        id,
+        (
+            instance_token.duplicate_handle(fidl::Rights::SAME_RIGHTS).unwrap(),
+            program.get_vmo_koid(),
+        ),
+    );
+
+    let mut updates = vec![];
+    updates.push(fattribution::AttributionUpdate::Add(fattribution::NewPrincipal {
+        identifier: Some(fattribution::Identifier::Component(
+            instance_token.duplicate_handle(fidl::Rights::SAME_RIGHTS).unwrap(),
+        )),
+        detailed_attribution: None,
+        ..Default::default()
+    }));
+    updates.push(fattribution::AttributionUpdate::Update(fattribution::UpdatedPrincipal {
+        identifier: Some(fattribution::Identifier::Component(
+            instance_token.duplicate_handle(fidl::Rights::SAME_RIGHTS).unwrap(),
+        )),
+        resources: Some(fattribution::Resources::Data(vec![fattribution::Resource::KernelObject(
+            vmo_koid,
+        )])),
+        ..Default::default()
+    }));
+    publisher.on_update(updates).unwrap();
     let termination = program.wait_for_termination();
+    let termination_clone = program.wait_for_termination();
+    // Remove this VMO when the program has terminated.
+    let tracker = resource_tracker.clone();
+    fasync::Task::spawn(async move {
+        termination_clone.await;
+        if let Some((token, _)) = tracker.resources.lock().remove(&id) {
+            publisher
+                .on_update(vec![fattribution::AttributionUpdate::Remove(
+                    fattribution::Identifier::Component(token),
+                )])
+                .unwrap();
+        }
+    })
+    .detach();
     Ok((program, termination))
 }
 
@@ -88,74 +226,59 @@
     use super::*;
     use fidl::endpoints::Proxy;
     use fidl_fuchsia_component_decl as fdecl;
+    use fidl_fuchsia_examples_colocated as fcolocated;
     use fidl_fuchsia_process::HandleInfo;
     use fuchsia_runtime::HandleType;
 
     #[fuchsia::test]
     async fn test_start_stop_component() {
+        let resource_tracker =
+            Arc::new(ResourceTracker { resources: Mutex::new(Default::default()) });
         let (runner, runner_stream) =
             fidl::endpoints::create_proxy_and_stream::<fcrunner::ComponentRunnerMarker>().unwrap();
-        let server = fasync::Task::spawn(handle_runner_request(runner_stream));
+        let memory_server = get_memory_server(resource_tracker.clone());
+        let server = fasync::Task::spawn(handle_runner_request(
+            runner_stream,
+            resource_tracker,
+            memory_server.clone(),
+        ));
 
-        // Measure how much private RAM our own process is using.
-        let usage_initial = private_ram();
-
-        // Start a component using 64 MiB of RAM.
+        // Start a colocated component.
         let decl = fuchsia_fs::file::read_in_namespace_to_fidl::<fdecl::Component>(
-            "/pkg/meta/colocated-component-64mb.cm",
+            "/pkg/meta/colocated-component.cm",
         )
         .await
         .unwrap();
         let (controller, controller_server_end) = fidl::endpoints::create_endpoints();
-        let (user0, user0_peer) = zx::EventPair::create();
+        let (user0, user0_peer) = zx::Channel::create();
         let start_info = fcrunner::ComponentStartInfo {
             program: decl.program.unwrap().info,
             numbered_handles: Some(vec![HandleInfo {
                 handle: user0_peer.into(),
                 id: fuchsia_runtime::HandleInfo::new(HandleType::User0, 0).as_raw(),
             }]),
+            component_instance: Some(zx::Event::create()),
             ..Default::default()
         };
         runner.start(start_info, controller_server_end).unwrap();
 
         // Wait until the program has allocated 64 MiB worth of pages.
-        _ = fasync::OnSignals::new(&user0, zx::Signals::USER_0).await.unwrap();
+        let colocated_component_vmos =
+            fcolocated::ColocatedProxy::new(fasync::Channel::from_channel(user0))
+                .get_vmos()
+                .await
+                .unwrap();
 
         // Measure our private memory usage again. It should increase by roughly that much more.
-        let usage_started = private_ram();
-        assert!(
-            usage_started > usage_initial,
-            "initial: {usage_initial}, started: {usage_started}"
-        );
-        assert!(
-            usage_started - usage_initial > 60 * 1024 * 1024,
-            "initial: {usage_initial}, started: {usage_started}"
-        );
+        assert!(!colocated_component_vmos.is_empty());
 
         // Stop the component.
         let controller = controller.into_proxy().unwrap();
         controller.stop().unwrap();
         controller.on_closed().await.unwrap();
 
-        // Measure our private memory usage again. It should roughly go back to before.
-        let usage_stopped = private_ram();
-        assert!(
-            usage_stopped < usage_started,
-            "started: {usage_started}, stopped: {usage_stopped}"
-        );
-        assert!(
-            usage_started - usage_stopped > 60 * 1024 * 1024,
-            "started: {usage_started}, stopped: {usage_stopped}"
-        );
-
         // Close the connection and verify the server task ends successfully.
         drop(runner);
         server.await.unwrap();
     }
-
-    #[track_caller]
-    fn private_ram() -> usize {
-        let process = fuchsia_runtime::process_self();
-        process.task_stats().unwrap().mem_private_bytes
-    }
 }
diff --git a/examples/components/runner/colocated/src/program.rs b/examples/components/runner/colocated/src/program.rs
index 72f8ee5..e3fe566 100644
--- a/examples/components/runner/colocated/src/program.rs
+++ b/examples/components/runner/colocated/src/program.rs
@@ -4,37 +4,34 @@
 
 use async_lock::OnceCell;
 use async_trait::async_trait;
+use fidl::endpoints::RequestStream;
+use fidl_fuchsia_examples_colocated as fcolocated;
 use fidl_fuchsia_process::HandleInfo;
 use fuchsia_async as fasync;
 use fuchsia_runtime::HandleType;
 use fuchsia_zircon as zx;
-use futures::{
-    channel::oneshot,
-    future::{BoxFuture, FutureExt},
-};
-use mapped_vmo::Mapping;
+use futures::future::{BoxFuture, FutureExt};
+use futures::TryStreamExt;
 use runner::component::{ChannelEpitaph, Controllable};
-use std::{ops::DerefMut, sync::Arc};
+use std::sync::Arc;
 use tracing::warn;
-use zx::Peered;
+use zx::{AsHandleRef, Koid};
 
 /// [`ColocatedProgram `] represents an instance of a program run by the
 /// colocated runner. Its state is held in this struct and its behavior
 /// is run in the `task`.
 pub struct ColocatedProgram {
     task: Option<fasync::Task<()>>,
-    filled: Option<oneshot::Receiver<Mapping>>,
     terminated: Arc<OnceCell<()>>,
+    vmo_koid: Koid,
 }
 
 impl ColocatedProgram {
-    pub fn new(vmo_size: u64, numbered_handles: Vec<HandleInfo>) -> Result<Self, anyhow::Error> {
-        let vmo = zx::Vmo::create(vmo_size)?;
-        let vmo_size = vmo.get_size()?;
-        let (filled_sender, filled) = oneshot::channel();
+    pub fn new(numbered_handles: Vec<HandleInfo>) -> Result<Self, anyhow::Error> {
+        let vmo = zx::Vmo::create(1024)?;
+        let vmo_koid = vmo.get_koid()?;
+
         let terminated = Arc::new(OnceCell::new());
-        let fill_vmo_task =
-            fasync::unblock(move || ColocatedProgram::fill_vmo(vmo, vmo_size, filled_sender));
         let terminated_clone = terminated.clone();
         let guard = scopeguard::guard((), move |()| {
             _ = terminated_clone.set_blocking(());
@@ -44,22 +41,29 @@
             // which happens when this task is dropped.
             let _guard = guard;
 
-            fill_vmo_task.await;
-
             // Signal to the outside world that the pages have been allocated.
-            for info in numbered_handles.into_iter().filter(|info| {
-                match fuchsia_runtime::HandleInfo::try_from(info.id) {
+            let handle_info = numbered_handles
+                .into_iter()
+                .filter(|info| match fuchsia_runtime::HandleInfo::try_from(info.id) {
                     Ok(handle_info) => {
                         handle_info == fuchsia_runtime::HandleInfo::new(HandleType::User0, 0)
                     }
                     Err(_) => false,
-                }
-            }) {
-                let handle = zx::EventPair::from(info.handle);
-                match handle.signal_peer(zx::Signals::empty(), zx::Signals::USER_0) {
-                    Ok(()) => {}
-                    Err(status) => {
-                        warn!("Failed to signal USER0 handle: {status}");
+                })
+                .next()
+                .unwrap();
+
+            let channel = zx::Channel::from(handle_info.handle);
+            let mut request_stream = fcolocated::ColocatedRequestStream::from_channel(
+                fasync::Channel::from_channel(channel),
+            );
+            while let Some(request) = request_stream.try_next().await.unwrap() {
+                match request {
+                    fcolocated::ColocatedRequest::GetVmos { responder } => {
+                        responder.send(&[vmo_koid.raw_koid()]).unwrap();
+                    }
+                    fcolocated::ColocatedRequest::_UnknownMethod { .. } => {
+                        panic!("Unknown method");
                     }
                 }
             }
@@ -68,41 +72,7 @@
             std::future::pending().await
         };
         let task = fasync::Task::spawn(task);
-        Ok(Self { task: Some(task), filled: Some(filled), terminated })
-    }
-
-    fn fill_vmo(vmo: zx::Vmo, vmo_size: u64, filled: oneshot::Sender<Mapping>) {
-        // Map the VMO into the address space.
-        let vmo_size = vmo_size as usize;
-        let mut mapping = Mapping::create_from_vmo(
-            &vmo,
-            vmo_size,
-            zx::VmarFlags::PERM_READ | zx::VmarFlags::PERM_WRITE,
-        )
-        .unwrap();
-        let buffer = mapping.deref_mut();
-
-        // Fill the VMO with randomized bytes, to cause pages to be physically allocated.
-        // This approach will defeat page deduplication and page compression, for ease of
-        // memory usage analysis. This program should more or less use `vmo_size` bytes.
-        use rand::RngCore;
-        let mut rng = rand::thread_rng();
-        let mut offset: usize = 0;
-        const BLOCK_SIZE: usize = 512;
-        let mut bytes = vec![0u8; BLOCK_SIZE];
-        loop {
-            rng.fill_bytes(&mut bytes);
-            buffer.write_at(offset, &bytes);
-            offset += BLOCK_SIZE;
-            if offset > vmo_size {
-                break;
-            }
-        }
-        buffer.release_writes();
-
-        // Send the mapping to the program to be kept alive. This will keep those pages
-        // committed.
-        _ = filled.send(mapping);
+        Ok(Self { task: Some(task), terminated, vmo_koid })
     }
 
     /// Returns a future that will resolve when the program is terminated.
@@ -114,6 +84,12 @@
         }
         .boxed()
     }
+
+    /// Returns the koid of the program's VMO, so the runner can report its memory as attributed to
+    /// this component.
+    pub fn get_vmo_koid(&self) -> Koid {
+        self.vmo_koid
+    }
 }
 
 #[async_trait]
@@ -125,11 +101,7 @@
 
     fn stop<'a>(&mut self) -> BoxFuture<'a, ()> {
         let task = self.task.take();
-        let filled = self.filled.take();
         async {
-            if let Some(filled) = filled {
-                _ = filled.await;
-            }
             if let Some(task) = task {
                 _ = task.cancel();
             }
diff --git a/examples/diagnostics/logs/rust/BUILD.gn b/examples/diagnostics/logs/rust/BUILD.gn
index 4a09ec3..7af608d 100644
--- a/examples/diagnostics/logs/rust/BUILD.gn
+++ b/examples/diagnostics/logs/rust/BUILD.gn
@@ -45,7 +45,6 @@
     "//src/lib/fuchsia-component",
     "//src/lib/syslog/rust:syslog-listener",
     "//third_party/rust_crates:futures",
-    "//third_party/rust_crates:pin-utils",
   ]
 
   sources = [ "tests/lib.rs" ]
diff --git a/examples/diagnostics/logs/rust/tests/lib.rs b/examples/diagnostics/logs/rust/tests/lib.rs
index f45e82f..1b3dbde 100644
--- a/examples/diagnostics/logs/rust/tests/lib.rs
+++ b/examples/diagnostics/logs/rust/tests/lib.rs
@@ -10,6 +10,7 @@
 use fuchsia_component::client::connect_to_protocol;
 use fuchsia_syslog_listener::run_log_listener_with_proxy;
 use futures::{channel::mpsc, prelude::*};
+use std::pin::pin;
 
 #[fuchsia::test]
 async fn launch_example_and_read_hello_world() {
@@ -17,7 +18,8 @@
     let _: BinderProxy = connect_to_protocol::<BinderMarker>().expect("launched log example");
 
     let (logs, mut new_logs, _tasks) = listen_to_logs();
-    pin_utils::pin_mut!(logs);
+
+    let mut logs = pin!(logs);
 
     let (next, new_next) = (logs.next().await.unwrap(), new_logs.next().await.unwrap());
     assert_eq!(Severity::try_from(next.severity).unwrap(), Severity::Info);
diff --git a/examples/fidl/fuchsia.examples.docs/BUILD.gn b/examples/fidl/fuchsia.examples.docs/BUILD.gn
index 92c8259..cb61b6c 100644
--- a/examples/fidl/fuchsia.examples.docs/BUILD.gn
+++ b/examples/fidl/fuchsia.examples.docs/BUILD.gn
@@ -39,23 +39,13 @@
 
   # TODO(https://fxbug.dev/328118770): Example libraries should be named
   # differently to avoid using fake fuchsia API levels.
-  platform = "fuchsia"
+  versioned = "fuchsia"
   available = [ "fuchsia:HEAD" ]
 }
 
-fidl("builtin") {
-  testonly = true
-  sources = [ "language_reference_builtin.test.fidl" ]
-  excluded_checks = [
-    "invalid-case-for-decl-name",
-    "wrong-prefix-for-platform-source-library",
-  ]
-}
-
 group("all") {
   testonly = true
   deps = [
-    ":builtin($fidl_toolchain)",
     ":fuchsia.examples.docs($fidl_toolchain)",
     ":versioning($fidl_toolchain)",
   ]
diff --git a/examples/fidl/fuchsia.examples.docs/language_reference.test.fidl b/examples/fidl/fuchsia.examples.docs/language_reference.test.fidl
index d3fc7d4..48f4d2f 100644
--- a/examples/fidl/fuchsia.examples.docs/language_reference.test.fidl
+++ b/examples/fidl/fuchsia.examples.docs/language_reference.test.fidl
@@ -36,6 +36,16 @@
 }; // and this is the last one!
 // [END comments]
 
+// [START keywords]
+// Declaring a struct named "struct" is allowed, though confusing.
+type struct = struct {};
+
+// Declaring a table field named "strict" is a more reasonable example.
+type Options = table {
+    1: strict bool;
+};
+// [END keywords]
+
 // [START consts]
 const ENABLED_FLAG bool = true;
 const OFFSET int8 = -33;
@@ -48,6 +58,7 @@
 const MIN_TEMP float32 = -273.15;
 const CONVERSION_FACTOR float64 = 1.41421358;
 const MY_DRINK Beverage = Beverage.WATER;
+const FEATURES InfoFeatures = InfoFeatures.WLAN | InfoFeatures.SYNTH;
 // [END consts]
 
 // [START defaults]
@@ -342,13 +353,6 @@
 };
 // [END aliasing-usage]
 
-// [START builtin-aliases]
-type RawBytes = struct {
-    head byte;
-    rest vector<uint8>;
-};
-// [END builtin-aliases]
-
 // [START calculator]
 type DivisionError = strict enum : uint32 {
     DIVIDE_BY_ZERO = 1;
diff --git a/examples/fidl/fuchsia.examples.docs/language_reference_builtin.test.fidl b/examples/fidl/fuchsia.examples.docs/language_reference_builtin.test.fidl
deleted file mode 100644
index f8ce555..0000000
--- a/examples/fidl/fuchsia.examples.docs/language_reference_builtin.test.fidl
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-// [START builtin]
-library builtin;
-
-alias byte = uint8;
-// [END builtin]
diff --git a/examples/testing/realm_proxy/testing/realm-factory/src/main.rs b/examples/testing/realm_proxy/testing/realm-factory/src/main.rs
index 3ec8900..26667d05 100644
--- a/examples/testing/realm_proxy/testing/realm-factory/src/main.rs
+++ b/examples/testing/realm_proxy/testing/realm-factory/src/main.rs
@@ -52,13 +52,10 @@
                     //
                     // ... code to serve echo here ...
 
-                    let (echo_sender_client, echo_sender_server) =
-                        endpoints::create_endpoints::<fsandbox::SenderMarker>();
                     let (echo_receiver_client, echo_receiver_stream) =
                         endpoints::create_request_stream::<fsandbox::ReceiverMarker>()?;
                     let factory = client::connect_to_protocol::<fsandbox::FactoryMarker>()?;
-                    let () =
-                        factory.create_sender(echo_receiver_client, echo_sender_server).await?;
+                    let echo_sender_client = factory.create_sender(echo_receiver_client).await?;
                     my_dictionary_proxy
                         .insert("reverse-echo", fsandbox::Capability::Sender(echo_sender_client))
                         .await?
diff --git a/products/core/BUILD.gn b/products/core/BUILD.gn
index fc9e589..69bf795 100644
--- a/products/core/BUILD.gn
+++ b/products/core/BUILD.gn
@@ -70,15 +70,8 @@
   }
 }
 
-_storage_default = {
-  storage = {
-    configure_fshost = true
-  }
-}
-
 _storage_f2fs = {
   storage = {
-    configure_fshost = true
     filesystems = {
       volume = {
         fvm = {
@@ -95,7 +88,6 @@
 
 _storage_minfs = {
   storage = {
-    configure_fshost = true
     filesystems = {
       volume = {
         fvm = {
@@ -121,7 +113,6 @@
   testonly = true
   platform = {
     forward_variables_from(_platform_configuration_base, "*")
-    forward_variables_from(_storage_default, "*")
   }
   product = {
     build_info = default_product_build_info
@@ -166,7 +157,6 @@
   testonly = true
   platform = {
     forward_variables_from(_platform_configuration_base, "*")
-    forward_variables_from(_storage_default, "*")
 
     connectivity = {
       network = {
@@ -187,7 +177,6 @@
   testonly = true
   platform = {
     forward_variables_from(_platform_configuration_base, "*")
-    forward_variables_from(_storage_default, "*")
 
     driver_framework = {
       test_fuzzing_config = {
diff --git a/products/minimal/BUILD.bazel b/products/minimal/BUILD.bazel
index cfbd866..5fe02db 100644
--- a/products/minimal/BUILD.bazel
+++ b/products/minimal/BUILD.bazel
@@ -32,9 +32,6 @@
                 INPUT_DEVICE_TYPE.TOUCHSCREEN,
             ],
         },
-        "storage": {
-            "configure_fshost": True,
-        },
     },
     "product": {
         "build_info": DEFAULT_PRODUCT_BUILD_INFO,
diff --git a/products/minimal/BUILD.gn b/products/minimal/BUILD.gn
index b3ba444..8cf4659 100644
--- a/products/minimal/BUILD.gn
+++ b/products/minimal/BUILD.gn
@@ -24,9 +24,6 @@
         "touchscreen",
       ]
     }
-    storage = {
-      configure_fshost = true
-    }
 
     # If the 'authorized_ssh_keys_path' GN arg has been set, then pass that path
     # as part of the platform configuration.
diff --git a/products/terminal/BUILD.gn b/products/terminal/BUILD.gn
index 800c3a4..10cc640 100644
--- a/products/terminal/BUILD.gn
+++ b/products/terminal/BUILD.gn
@@ -29,7 +29,6 @@
     }
 
     storage = {
-      configure_fshost = true
       filesystems = {
         volume = {
           fvm = {
diff --git a/products/tests/BUILD.gn b/products/tests/BUILD.gn
index 643bf76..26524c7 100644
--- a/products/tests/BUILD.gn
+++ b/products/tests/BUILD.gn
@@ -18,7 +18,6 @@
       ]
     }
     storage = {
-      configure_fshost = true
       live_usb_enabled = false
       filesystems = {
         volume = {
diff --git a/products/workbench/platform_config.bzl b/products/workbench/platform_config.bzl
index 2770f03..3b33722 100644
--- a/products/workbench/platform_config.bzl
+++ b/products/workbench/platform_config.bzl
@@ -50,9 +50,6 @@
             ],
         },
     },
-    "storage": {
-        "configure_fshost": True,
-    },
     "session": {
         "enabled": True,
     },
diff --git a/products/zedboot/BUILD.bazel b/products/zedboot/BUILD.bazel
index c42939c..3b57f69 100644
--- a/products/zedboot/BUILD.bazel
+++ b/products/zedboot/BUILD.bazel
@@ -23,7 +23,6 @@
             "build_type": BUILD_TYPES.ENG,
             "feature_set_level": "bootstrap",
             "storage": {
-                "configure_fshost": True,
                 "filesystems": {
                     "image_name": "zedboot",
                     "image_mode": "no_image",
@@ -48,7 +47,6 @@
             "build_type": BUILD_TYPES.ENG,
             "feature_set_level": "bootstrap",
             "storage": {
-                "configure_fshost": True,
                 "filesystems": {
                     "image_name": "zedboot",
                     "image_mode": "no_image",
@@ -64,8 +62,6 @@
     legacy_bundle = ZEDBOOT_IMAGE_ARGS["legacy_bundle"],
     package_mode = ZEDBOOT_IMAGE_ARGS["package_mode"],
     platform_artifacts = ZEDBOOT_IMAGE_ARGS["platform_artifacts"],
-    # TODO(awolter): Use ZEDBOOT_IMAGE_ARGS from zedboot_images_args.bzl when
-    # `configure_fshost: True` is enabled in v/g.
     product_config = "//products/zedboot:zedboot",
 ) for board in [
     "x64",
@@ -82,8 +78,6 @@
     legacy_bundle = ZEDBOOT_IMAGE_ARGS["legacy_bundle"],
     package_mode = ZEDBOOT_IMAGE_ARGS["package_mode"],
     platform_artifacts = ZEDBOOT_IMAGE_ARGS["platform_artifacts"],
-    # TODO(awolter): Use ZEDBOOT_IMAGE_ARGS from zedboot_images_args.bzl when
-    # `configure_fshost: True` is enabled in v/g.
     product_config = "//products/zedboot:zedboot",
 ) for board in [
     "x64",
@@ -99,8 +93,6 @@
     legacy_bundle = ZEDBOOT_IMAGE_ARGS["legacy_bundle"],
     package_mode = ZEDBOOT_IMAGE_ARGS["package_mode"],
     platform_artifacts = ZEDBOOT_IMAGE_ARGS["platform_artifacts"],
-    # TODO(awolter): Use ZEDBOOT_IMAGE_ARGS from zedboot_images_args.bzl when
-    # `configure_fshost: True` is enabled in v/g.
     product_config = "//products/zedboot:zedboot_with_fvm",
 ) for board in [
     "x64",
diff --git a/products/zedboot/BUILD.gn b/products/zedboot/BUILD.gn
index b5140b6..b2ef4c3c 100644
--- a/products/zedboot/BUILD.gn
+++ b/products/zedboot/BUILD.gn
@@ -9,7 +9,6 @@
     build_type = "eng"
     feature_set_level = "bootstrap"
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "zedboot"
         image_mode = "no_image"
@@ -25,7 +24,6 @@
     build_type = "eng"
     feature_set_level = "bootstrap"
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "zedboot"
         image_mode = "no_image"
@@ -49,7 +47,6 @@
     build_type = "eng"
     feature_set_level = "bootstrap"
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "zedboot"
         image_mode = "no_image"
diff --git a/scripts/fxtest/rewrite/args.py b/scripts/fxtest/rewrite/args.py
index 99a4c8e..52bf9fc 100644
--- a/scripts/fxtest/rewrite/args.py
+++ b/scripts/fxtest/rewrite/args.py
@@ -12,6 +12,8 @@
 import termout
 import util.arg_option as arg_option
 
+LOG_TO_STDOUT_OPTION = "-"
+
 
 @dataclass
 class Flags:
diff --git a/scripts/fxtest/rewrite/environment.py b/scripts/fxtest/rewrite/environment.py
index b137e3c..b989d9c 100644
--- a/scripts/fxtest/rewrite/environment.py
+++ b/scripts/fxtest/rewrite/environment.py
@@ -174,6 +174,9 @@
             raise EnvironmentError(f"No log files found in {self.out_dir}")
         return os.path.join(self.out_dir, matching[-1])
 
+    def log_to_stdout(self) -> bool:
+        return self.log_file == args.LOG_TO_STDOUT_OPTION
+
     def __hash__(self) -> int:
         return hash(self.fuchsia_dir)
 
diff --git a/scripts/fxtest/rewrite/main.py b/scripts/fxtest/rewrite/main.py
index 40bd37f..84f913d 100644
--- a/scripts/fxtest/rewrite/main.py
+++ b/scripts/fxtest/rewrite/main.py
@@ -149,11 +149,16 @@
     """
     do_status_output_signal: asyncio.Event = asyncio.Event()
 
-    tasks.append(
-        asyncio.create_task(
-            console.console_printer(recorder, flags, do_status_output_signal)
+    do_output_to_stdout = flags.logpath == args.LOG_TO_STDOUT_OPTION
+
+    if not do_output_to_stdout:
+        tasks.append(
+            asyncio.create_task(
+                console.console_printer(
+                    recorder, flags, do_status_output_signal
+                )
+            )
         )
-    )
 
     # Initialize event recording.
     recorder.emit_init()
@@ -183,7 +188,7 @@
         return 1
 
     # Initialize status printing at this point, if desired.
-    if flags.status:
+    if flags.status and not do_output_to_stdout:
         do_status_output_signal.set()
         termout.init()
 
@@ -200,11 +205,12 @@
 
     # Configure file logging based on flags.
     if flags.log and exec_env.log_file:
-        tasks.append(
-            asyncio.create_task(
-                log.writer(recorder, gzip.open(exec_env.log_file, "wt"))
-            )
-        )
+        output_file: typing.TextIO
+        if exec_env.log_to_stdout():
+            output_file = sys.stdout
+        else:
+            output_file = gzip.open(exec_env.log_file, "wt")
+        tasks.append(asyncio.create_task(log.writer(recorder, output_file)))
         recorder.emit_instruction_message(
             f"Logging all output to: {exec_env.log_file}"
         )
@@ -215,13 +221,14 @@
         # For convenience, display the log output path when the program exits.
         # Since the async loop may already be exited at that point, directly
         # print to the console.
-        atexit.register(
-            print,
-            statusinfo.dim(
-                f"Output was logged to: {os.path.relpath(exec_env.log_file, os.getcwd())}",
-                style=flags.style,
-            ),
-        )
+        if not exec_env.log_to_stdout():
+            atexit.register(
+                print,
+                statusinfo.dim(
+                    f"Output was logged to: {os.path.relpath(exec_env.log_file, os.getcwd())}",
+                    style=flags.style,
+                ),
+            )
 
     if flags.has_debugger():
         recorder.emit_warning_message(
@@ -307,7 +314,8 @@
             "Use --no-updateifinbase to skip updating base packages."
         )
         build_return_code = await run_build_with_suspended_output(
-            ["build/images/updates"]
+            ["build/images/updates"],
+            show_output=not exec_env.log_to_stdout(),
         )
         if build_return_code != 0:
             recorder.emit_end(
@@ -557,7 +565,9 @@
     status_suffix = " Status output suspended." if termout.is_init() else ""
     recorder.emit_info_message(f"\nExecuting build.{status_suffix}")
 
-    return_code = await run_build_with_suspended_output(build_command_line)
+    return_code = await run_build_with_suspended_output(
+        build_command_line, show_output=not exec_env.log_to_stdout()
+    )
 
     error = None
     if return_code != 0:
@@ -705,6 +715,7 @@
 
 async def run_build_with_suspended_output(
     build_command_line: list[str],
+    show_output: bool = True,
 ) -> int:
     # Allow display to update.
     await asyncio.sleep(0.1)
@@ -713,8 +724,11 @@
         # Clear the status output while we are doing the build.
         termout.write_lines([])
 
+    stdout = None if show_output else subprocess.DEVNULL
+    stderr = None if show_output else subprocess.DEVNULL
+
     return_code = subprocess.call(
-        ["fx", "build"] + build_command_line,
+        ["fx", "build"] + build_command_line, stdout=stdout, stderr=stderr
     )
     return return_code
 
diff --git a/scripts/fxtest/rewrite/termout/tests/termout_test.py b/scripts/fxtest/rewrite/termout/tests/termout_test.py
index 09d16f2..858e4bd 100644
--- a/scripts/fxtest/rewrite/termout/tests/termout_test.py
+++ b/scripts/fxtest/rewrite/termout/tests/termout_test.py
@@ -15,6 +15,7 @@
 import termsim
 
 import termout
+from typing import cast, IO
 
 
 class TestTermout(unittest.TestCase):
@@ -23,7 +24,7 @@
         size = termout.Size(25, 25)
         termout.reset()
         terminal = termsim.Terminal(size.columns)
-        with contextlib.redirect_stdout(terminal):
+        with contextlib.redirect_stdout(cast(IO[str], terminal)):
             termout.write_lines(["Hello"], size=size)
             self.assertListEqual(terminal.lines, ["Hello"])
             termout.write_lines(["World"], size=size)
@@ -34,7 +35,7 @@
         size = termout.Size(3, 25)
         termout.reset()
         terminal = termsim.Terminal(size.columns)
-        with contextlib.redirect_stdout(terminal):
+        with contextlib.redirect_stdout(cast(IO[str], terminal)):
             termout.write_lines(["Hello"], size=size)
             self.assertListEqual(terminal.lines, ["Hel"])
             termout.write_lines(["World"], size=size)
@@ -45,7 +46,7 @@
         size = termout.Size(25, 25)
         termout.reset()
         terminal = termsim.Terminal(size.columns)
-        with contextlib.redirect_stdout(terminal):
+        with contextlib.redirect_stdout(cast(IO[str], terminal)):
             termout.write_lines(["Hello", "World"], size=size)
             self.assertListEqual(terminal.lines, ["Hello", "World"])
             termout.write_lines(["Hello 2", "Different"], size=size)
@@ -56,7 +57,7 @@
         size = termout.Size(25, 25)
         termout.reset()
         terminal = termsim.Terminal(size.columns)
-        with contextlib.redirect_stdout(terminal):
+        with contextlib.redirect_stdout(cast(IO[str], terminal)):
             termout.write_lines(["Hello"], size=size)
             self.assertListEqual(terminal.lines, ["Hello"])
             termout.write_lines(["Hello", "World"], size=size)
@@ -70,7 +71,7 @@
         size = termout.Size(25, 25)
         termout.reset()
         terminal = termsim.Terminal(size.columns)
-        with contextlib.redirect_stdout(terminal):
+        with contextlib.redirect_stdout(cast(IO[str], terminal)):
             termout.write_lines(["Hello"], size=size)
             self.assertListEqual(terminal.lines, ["Hello"])
             termout.write_lines(
diff --git a/scripts/fxtest/rewrite/termout/tests/termsim/termsim.py b/scripts/fxtest/rewrite/termout/tests/termsim/termsim.py
index 362fe5c..30b661b 100644
--- a/scripts/fxtest/rewrite/termout/tests/termsim/termsim.py
+++ b/scripts/fxtest/rewrite/termout/tests/termsim/termsim.py
@@ -22,7 +22,7 @@
         lines (List[str]): The list of lines that would show on a terminal.
     """
 
-    def __init__(self, width: int):
+    def __init__(self, width: int) -> None:
         self._width = width
         self.lines: list[str] = [""]
         self._line_position: int = 0
diff --git a/scripts/fxtest/rewrite/tests/main_test.py b/scripts/fxtest/rewrite/tests/main_test.py
index 3ac2761..086a060 100644
--- a/scripts/fxtest/rewrite/tests/main_test.py
+++ b/scripts/fxtest/rewrite/tests/main_test.py
@@ -775,3 +775,28 @@
                     ),
                     f"Did not find substring, output was:\n{output.getvalue()}",
                 )
+
+    @mock.patch("main.termout.is_valid", return_value=False)
+    async def test_log_to_stdout(self, _termout_mock: mock.Mock) -> None:
+        """Test that we can log everything to stdout, and it parses as JSON lines"""
+
+        _command_mock = self._mock_run_command(0)
+        _subprocess_mock = self._mock_subprocess_call(0)
+        self._mock_has_device_connected(True)
+        self._mock_has_tests_in_base([])
+
+        output = io.StringIO()
+        with contextlib.redirect_stdout(output):
+            ret = await main.async_main_wrapper(
+                args.parse_args(["--logpath", "-"])
+            )
+            self.assertEqual(ret, 0)
+        for line in output.getvalue().splitlines():
+            if not line:
+                continue
+            try:
+                json.loads(line)
+            except json.JSONDecodeError as e:
+                self.fail(
+                    f"Failed to parse line as JSON.\nLine: {line}\nError: {e}"
+                )
diff --git a/scripts/fxtest/scripts/BUILD.gn b/scripts/fxtest/scripts/BUILD.gn
index ebb8c2a..1375355 100644
--- a/scripts/fxtest/scripts/BUILD.gn
+++ b/scripts/fxtest/scripts/BUILD.gn
@@ -47,7 +47,11 @@
 
     configs -= [ "//build/config/rust/lints:allow_unused_results" ]
     configs += [ "//build/config:optimize_speed" ]
-    configs += [ "//build/config/rust:lto_thin" ]
+
+    # Add thinlto config if lto variants are not used.
+    if (!is_lto_variant) {
+      configs += [ "//build/config/lto:thinlto" ]
+    }
   }
 
   # Rename the resulting .pyz for the host tool
diff --git a/scripts/fxtest/test/parsing_test.dart b/scripts/fxtest/test/parsing_test.dart
index 3b32e44..68fa596 100644
--- a/scripts/fxtest/test/parsing_test.dart
+++ b/scripts/fxtest/test/parsing_test.dart
@@ -42,7 +42,6 @@
           'environments': [],
           'test': {
             'cpu': 'arm64',
-            'path': '/pkgfs/packages/component_test/0/test/component_test',
             'name': '//src/sys/component/test:component_test',
             'os': 'fuchsia',
             'package_url':
@@ -60,7 +59,6 @@
       expect(tds, hasLength(1));
       expect(tds[0].packageUrl.toString(), testJson[0]['test']['package_url']);
       expect(tds[0].runtimeDeps, '');
-      expect(tds[0].path, testJson[0]['test']['path']);
       expect(tds[0].name, testJson[0]['test']['name']);
       expect(tds[0].cpu, testJson[0]['test']['cpu']);
       expect(tds[0].os, testJson[0]['test']['os']);
@@ -76,7 +74,6 @@
           'environments': [],
           'test': {
             'cpu': 'arm64',
-            'path': '/pkgfs/packages/component_test/0/test/component_test',
             'name': '//src/sys/component/test:component_test',
             'os': 'fuchsia',
             'package_url':
@@ -94,7 +91,6 @@
       expect(tds, hasLength(1));
       expect(tds[0].packageUrl.toString(), testJson[0]['test']['package_url']);
       expect(tds[0].runtimeDeps, '');
-      expect(tds[0].path, testJson[0]['test']['path']);
       expect(tds[0].name, testJson[0]['test']['name']);
       expect(tds[0].cpu, testJson[0]['test']['cpu']);
       expect(tds[0].os, testJson[0]['test']['os']);
@@ -109,7 +105,6 @@
           'environments': [],
           'test': {
             'cpu': 'arm64',
-            'path': '/pkgfs/packages/component_test/0/test/component_test',
             'name': '//src/sys/component/test:component_test',
             'os': 'fuchsia',
             'package_url':
@@ -126,7 +121,6 @@
       expect(tds, hasLength(1));
       expect(tds[0].packageUrl.toString(), testJson[0]['test']['package_url']);
       expect(tds[0].runtimeDeps, '');
-      expect(tds[0].path, testJson[0]['test']['path']);
       expect(tds[0].name, testJson[0]['test']['name']);
       expect(tds[0].cpu, testJson[0]['test']['cpu']);
       expect(tds[0].os, testJson[0]['test']['os']);
@@ -838,7 +832,6 @@
           'environments': [],
           'test': {
             'cpu': 'arm64',
-            'path': '/pkgfs/packages/component_test/0/test/component_test',
             'name': '//src/sys/component/test:component_test',
             'os': 'fuchsia',
             'component_label': '//src/sys/component/test:test_component',
@@ -875,7 +868,6 @@
           'environments': [],
           'test': {
             'cpu': 'arm64',
-            'path': '/pkgfs/packages/component_test/0/test/component_test',
             'name': '//src/sys/component/test:component_test',
             'os': 'fuchsia',
             'component_label': '//src/sys/component/test:test_component',
@@ -911,7 +903,6 @@
           'environments': [],
           'test': {
             'cpu': 'arm64',
-            'path': '/pkgfs/packages/component_test/0/test/component_test',
             'name': '//src/sys/component/test:component_test',
             'os': 'fuchsia',
             'component_label': '//src/sys/component/test:test_component',
@@ -924,8 +915,6 @@
           'environments': [],
           'test': {
             'cpu': 'arm64',
-            'path':
-                '/pkgfs/packages/second_component_test/0/test/component_test',
             'name': '//src/sys/component/test:component_test',
             'os': 'fuchsia',
             'component_label': '//src/sys/second_component/test:test_component',
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index db4cb4f..9d716d1 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -21,11 +21,8 @@
 
 visibility = [ ":*" ]
 
-assert(sdk_inside_supported_api_sub_build ==
-       (sdk_inside_sub_build && override_target_api_level != -1))
-
 # Verify that `override_target_api_level` is actually supported.
-if (override_target_api_level != -1) {
+if (override_target_api_level != "PLATFORM") {
   _override_is_supported = false
   foreach(supported_level, platform_version.build_time_supported_api_levels) {
     if (supported_level == override_target_api_level) {
@@ -195,11 +192,9 @@
 sdk_molecule("fuchsia_idk_atoms") {
   visibility += [ "//vendor/*" ]
 
-  deps = [ ":fuchsia_idk_atoms_for_each_api_level_and_legacy" ]
+  deps = [ ":fuchsia_idk_atoms_for_each_api_level_and_platform" ]
 
-  if (sdk_inside_supported_api_sub_build) {
-    deps += [ ":fuchsia_idk_atoms_for_each_api_level" ]
-  } else {
+  if (override_target_api_level == "PLATFORM") {
     deps += [
       # Do not add to this list. Instead, add new items to
       # fuchsia_idk_atoms_independent_of_api_level, which verifies there are no
@@ -207,9 +202,11 @@
       ":fuchsia_idk_atoms_independent_of_api_level",
 
       # There are very limited exceptions that do depend on API level but are
-      # only built in an API-level agnostic build.
-      ":fuchsia_idk_atoms_for_legacy_only",
+      # only built at "PLATFORM".
+      ":fuchsia_idk_atoms_for_platform_only",
     ]
+  } else {
+    deps += [ ":fuchsia_idk_atoms_for_each_api_level" ]
   }
 
   host_tools_deps = [
@@ -224,7 +221,7 @@
 }
 
 # Prebuilt libraries (including the sysroot) must be built and included for all
-# API levels they support. They are also built at `LEGACY` (a.k.a., the
+# API levels they support. They are also built at `PLATFORM` (a.k.a., the
 # API-level-agnostic build, a.k.a., the default platform build), for backwards
 # compatibility with IDK users that don't yet know about per-API-level
 # prebuilts.
@@ -232,25 +229,26 @@
 # TODO(https://fxbug.dev/310006516): Move all these into
 # `fuchsia_idk_atoms_for_each_api_level` once all IDK users are using the
 # per-API-level artifacts.
-sdk_molecule("fuchsia_idk_atoms_for_each_api_level_and_legacy") {
+sdk_molecule("fuchsia_idk_atoms_for_each_api_level_and_platform") {
   deps = [
     ":core_cc_prebuilt_libraries",
+    ":core_packages_for_each_api_level_and_platform",
     ":core_sysroot",
   ]
 }
 
 # Prebuilt libraries and packages that are built exclusively for the API levels
-# SDK users can target (not `LEGACY`).
+# SDK users can target (not `PLATFORM`).
 sdk_molecule("fuchsia_idk_atoms_for_each_api_level") {
   deps = [ ":core_packages" ]
 }
 
-if (!sdk_inside_supported_api_sub_build) {
+if (override_target_api_level == "PLATFORM") {
   # Do not add dependencies to this target without a really good reason.
   # Most dependencies should be built at every API level (add to
   # :fuchsia_idk_atoms_for_each_api_level) or be verifiably independent of the
   # API level (add to :fuchsia_idk_atoms_independent_of_api_level).
-  sdk_molecule("fuchsia_idk_atoms_for_legacy_only") {
+  sdk_molecule("fuchsia_idk_atoms_for_platform_only") {
     deps = [
       # The C++ source libraries must be buildable at each supported API level
       # but are only built once.
@@ -265,7 +263,7 @@
       # of the subbuilds currently puts the build files at the same path, so all
       # but one of them gets clobbered. Give `loadable_modules` the proper
       # per-API-level treatment and move this to
-      # :fuchsia_idk_atoms_for_each_api_level_and_legacy.
+      # :fuchsia_idk_atoms_for_each_api_level_and_platform.
       ":core_loadable_modules",
     ]
   }
@@ -541,10 +539,7 @@
 
 sdk_molecule("core_packages") {
   deps = [
-    "//src/graphics/magma/tests/integration:magma_conformance_tests_sdk",
-    "//src/graphics/tests/vkreadback:vkreadback_test_sdk",
     "//src/performance/memory/heapdump/collector:collector_sdk",
-
     # TODO(https://fxbug.dev/326231777): Uncomment this once
     # realm_builder_server can build targeting API levels.
     #
@@ -552,9 +547,20 @@
   ]
 }
 
+# TODO(https://fxbug.dev/310006516): Move the contents of this target to
+# ":core_packages" once downstream customers no longer need them in "API level
+# agnostic" form.
+sdk_molecule("core_packages_for_each_api_level_and_platform") {
+  deps = [
+    "//src/graphics/magma/tests/integration:magma_conformance_tests_sdk",
+    "//src/graphics/tests/vkreadback:vkreadback_test_sdk",
+  ]
+}
+
 sdk_molecule("core_data") {
   deps = [
     # TODO(ddorwin): Rename these to make it clear that they are data (e.g., _shards).
+    "//sdk/lib/driver_component:driver_component",
     "//sdk/lib/heapdump_instrumentation:heapdump_instrumentation_shard",
     "//sdk/lib/inspect",
     "//sdk/lib/sys/component:realm_builder_shard_sdk",
@@ -634,6 +640,8 @@
     "//sdk/lib/ui/scenic/cpp:cpp_sdk",
     "//sdk/lib/ui/scenic/cpp/testing:testing_sdk",
     "//sdk/lib/vfs/cpp:cpp_sdk",
+    "//sdk/lib/zbi-format:zbi-format_sdk",
+    "//src/devices/lib/mmio:mmio_sdk",
     "//src/lib/fidl/cpp:cpp_sdk",
     "//src/lib/fidl/cpp:hlcpp_conversion_sdk",
     "//src/lib/fidl/cpp:natural_ostream_sdk",
@@ -642,6 +650,7 @@
     "//zircon/system/ulib/async-loop:async-loop-cpp_sdk",
     "//zircon/system/ulib/async-loop:async-loop_sdk",
     "//zircon/system/ulib/async-testing:async-testing_sdk",
+    "//zircon/system/ulib/hwreg:hwreg_sdk_sdk",
     "//zircon/system/ulib/inspect:inspect_sdk",
     "//zircon/system/ulib/trace:trace_sdk",
     "//zircon/system/ulib/trace-vthread:trace-vthread_sdk",
@@ -738,7 +747,7 @@
     "//src/devices/testing/fake-bti:fake-bti_sdk",
     "//src/devices/testing/fake-mmio-reg:fake-mmio-reg_sdk",
     "//src/devices/testing/mock-mmio-reg:mock-mmio-reg_sdk",
-    "//zircon/system/ulib/ddk-platform-defs:ddk-platform-defs_sdk",
+    "//src/lib/memory_barriers:memory_barriers_sdk",
     "//zircon/system/ulib/fzl:fzl_sdk",
   ]
 }
@@ -868,67 +877,11 @@
   ]
 }
 
-# Tools Fuchsia driver developers used on the host platform; where host is often
-# Linux or Mac OS.
-# WARNING (https://fxbug.dev/287395493): the driver SDK will soon be removed.
-# DO NOT ADD anything here!
-sdk_molecule("driver_host_tools") {
-  _driver_host_tools = [
-    "//src/devices/tools/fidlgen_banjo:fidlgen_banjo_bin_sdk",
-    "//tools/bindc:bindc_sdk",
-    "//tools/fidl/fidlgen_cpp:fidlgen_cpp_sdk",
-
-    # TODO(https://fxbug.dev/42160879): Change to "fidlgen_cpp" once Bazel SDK uses the non-experimental name.
-    "//tools/fidl/fidlgen_cpp:fidlgen_cpp_experimental_driver_only_toolchain_sdk",
-  ]
-
-  if (host_os == "linux" && sdk_cross_compile_host_tools) {
-    _toolchains = [
-      host_x64_toolchain,
-      host_arm64_toolchain,
-    ]
-  } else {
-    _toolchains = [ host_toolchain ]
-  }
-  deps = []
-  foreach(toolchain, _toolchains) {
-    foreach(dep, _driver_host_tools) {
-      deps += [ "$dep($toolchain)" ]
-    }
-  }
-}
-
-# WARNING (https://fxbug.dev/287395493): the driver SDK will soon be removed.
-# DO NOT ADD anything here!
-sdk_molecule("bind") {
-  deps = [
-    "//src/devices/bind/fuchsia.acpi:fuchsia.acpi_sdk",
-    "//src/devices/bind/fuchsia.test:fuchsia.test_sdk",
-    "//src/devices/bind/fuchsia.usb:fuchsia.usb_sdk",
-  ]
-}
-
 # Controls the maximum number of simultaneous subbuilds.
 pool("subbuild_pool") {
   depth = sdk_max_simultaneous_sub_builds
 }
 
-# WARNING (https://fxbug.dev/287395493): the driver SDK will soon be removed.
-# DO NOT ADD anything here!
-sdk_molecule("driver_fidl") {
-  deps = [
-    "//sdk/fidl/fuchsia.device.fs:fuchsia.device.fs_sdk($fidl_toolchain)",
-    "//sdk/fidl/fuchsia.driver.framework:fuchsia.driver.framework_sdk($fidl_toolchain)",
-    "//sdk/fidl/fuchsia.hardware.i2c:fuchsia.hardware.i2c_sdk($fidl_toolchain)",
-    "//sdk/fidl/fuchsia.hardware.pci:fuchsia.hardware.pci_sdk($fidl_toolchain)",
-    "//sdk/fidl/fuchsia.wlan.common:fuchsia.wlan.common_sdk($fidl_toolchain)",
-    "//sdk/fidl/fuchsia.wlan.ieee80211:fuchsia.wlan.ieee80211_sdk($fidl_toolchain)",
-    "//sdk/fidl/fuchsia.wlan.internal:fuchsia.wlan.internal_sdk($fidl_toolchain)",
-    "//sdk/fidl/fuchsia.wlan.phyimpl:fuchsia.wlan.phyimpl_sdk($fidl_toolchain)",
-    "//sdk/fidl/fuchsia.wlan.softmac:fuchsia.wlan.softmac_sdk($fidl_toolchain)",
-  ]
-}
-
 # An SDK collection providing SDK atoms used for driver development.
 # Their API/ABI is not stable at all. Note: this cannot contain
 # testonly atoms.
@@ -950,31 +903,7 @@
 sdk_molecule("driver_atoms") {
   category = "experimental"
 
-  deps = [
-    ":bind",
-    ":driver_fidl",
-    ":fuchsia_idk_atoms",
-    "//sdk/lib/component/incoming/cpp:cpp_sdk",
-    "//sdk/lib/component/outgoing/cpp:cpp_sdk",
-    "//sdk/lib/driver/component/cpp:cpp_sdk",
-    "//sdk/lib/driver/devfs/cpp:cpp_sdk",
-    "//sdk/lib/driver/runtime:driver_runtime_cpp_sdk",
-    "//sdk/lib/driver/runtime:driver_runtime_sdk",
-    "//sdk/lib/driver_component:driver_component",
-    "//sdk/lib/fidl/cpp/wire:wire_sdk",
-    "//sdk/lib/fidl_driver:fidl_driver_natural_sdk",
-    "//sdk/lib/fidl_driver:fidl_driver_sdk",
-    "//sdk/lib/input_report_reader:input_report_reader_sdk",
-    "//sdk/lib/inspect/component/cpp:cpp_sdk",
-    "//src/devices/bin/driver_runtime:driver_runtime_sdk",
-    "//src/devices/lib/mmio:mmio_sdk",
-    "//src/lib/ddk:ddk_metadata_sdk",
-    "//src/lib/fidl/cpp:cpp_sdk",
-    "//zircon/system/ulib/hwreg:hwreg_sdk_sdk",
-    "//zircon/system/ulib/hwreg-i2c:hwreg-i2c_sdk_sdk",
-  ]
-
-  host_tools_deps = [ ":driver_host_tools" ]
+  deps = [ ":fuchsia_idk_atoms" ]
 }
 
 # These markers are used to define dependencies on FIDL bindings
diff --git a/sdk/banjo/fuchsia.hardware.display.controller/display-controller.fidl b/sdk/banjo/fuchsia.hardware.display.controller/display-controller.fidl
index 078cc0f..bdfde50 100644
--- a/sdk/banjo/fuchsia.hardware.display.controller/display-controller.fidl
+++ b/sdk/banjo/fuchsia.hardware.display.controller/display-controller.fidl
@@ -189,7 +189,11 @@
 };
 
 type PrimaryLayer = struct {
-    image Image;
+    /// The result of a successful ImportImage() call.
+    image_handle uint64;
+
+    /// Must match the ImportImage() argument for `image_handle`.
+    image_metadata ImageMetadata;
 
     /// An ALPHA_* constant.
     ///
diff --git a/sdk/banjo/fuchsia.hardware.goldfish.control/BUILD.gn b/sdk/banjo/fuchsia.hardware.goldfish.control/BUILD.gn
deleted file mode 100644
index f6d08d3..0000000
--- a/sdk/banjo/fuchsia.hardware.goldfish.control/BUILD.gn
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2019 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/fidl/fidl.gni")
-
-fidl("fuchsia.hardware.goldfish.control") {
-  sources = [ "goldfish-control.fidl" ]
-  public_deps = [ "//zircon/vdso/zx" ]
-  enable_banjo = true
-}
diff --git a/sdk/banjo/fuchsia.hardware.goldfish.control/goldfish-control.fidl b/sdk/banjo/fuchsia.hardware.goldfish.control/goldfish-control.fidl
deleted file mode 100644
index 6de2079..0000000
--- a/sdk/banjo/fuchsia.hardware.goldfish.control/goldfish-control.fidl
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-library fuchsia.hardware.goldfish.control;
-
-using zx;
-
-@transport("Banjo")
-@banjo_layout("ddk-protocol")
-closed protocol GoldfishControl {
-    /// Get color buffer for VMO. Fails if VMO is not associated with a color
-    /// buffer.
-    strict GetColorBuffer(resource struct {
-        vmo zx.Handle:VMO;
-    }) -> (struct {
-        ret zx.Status;
-        cb uint32;
-    });
-
-    /// Create a sync fence on goldfish control device. The fence `event`
-    /// argument will signal its peer once all the graphics work already queued
-    /// on the EGL display context associated with the device when it is created
-    /// has finished.
-    /// Returns ZX_ERR_INTERNAL if the device cannot create a fence or cannot
-    /// trigger the wait.
-    strict CreateSyncFence(resource struct {
-        event zx.Handle:EVENTPAIR;
-    }) -> (struct {
-        ret zx.Status;
-    });
-
-    /// Connect a channel to a goldfish-pipe FIDL server.
-    strict ConnectToPipeDevice(resource struct {
-        channel zx.Handle:CHANNEL;
-    }) -> (struct {
-        ret zx.Status;
-    });
-};
diff --git a/sdk/bundles/BUILD.gn b/sdk/bundles/BUILD.gn
index 034e30b..2335c5e 100644
--- a/sdk/bundles/BUILD.gn
+++ b/sdk/bundles/BUILD.gn
@@ -29,7 +29,6 @@
     "//third_party/openssh-portable:scp-shell-pkg",
     "//third_party/openssh-portable:ssh-keygen-shell-pkg",
     "//third_party/openssh-portable:ssh-shell-pkg",
-    "//third_party/sbase:sbase-pkgs",
     "//tools/check-licenses:host($host_toolchain)",
     "//tools/fidl/fidlmerge:host",
     "//tools/fidl/gidl:host",
diff --git a/sdk/ctf/build/internal/create_ctf_releases_gni.sh b/sdk/ctf/build/internal/create_ctf_releases_gni.sh
index 0efb4e8..c6afbd7 100755
--- a/sdk/ctf/build/internal/create_ctf_releases_gni.sh
+++ b/sdk/ctf/build/internal/create_ctf_releases_gni.sh
@@ -31,8 +31,15 @@
 ctf_releases = [" \
 > "${DESTINATION}"
 
+echo "Finding CTF releases..."
 for release in $(ls ${PREBUILT_DIR}); do
-  echo "  \"${release}\"," >> "${DESTINATION}"
+  if [ -d "${PREBUILT_DIR}/${release}/linux-x64" ]; then
+    echo "  Have release for ${release}... adding"
+    echo "  \"${release}\"," >> "${DESTINATION}"
+  else
+    echo "  No release for ${release}... skipping"
+  fi
+
 done
 
 echo "]" >> "${DESTINATION}"
diff --git a/sdk/fidl/BUILD.gn b/sdk/fidl/BUILD.gn
index cc48981..2877fb27 100644
--- a/sdk/fidl/BUILD.gn
+++ b/sdk/fidl/BUILD.gn
@@ -67,6 +67,7 @@
   "//sdk/fidl/fuchsia.hardware.i2c:fuchsia.hardware.i2c",
   "//sdk/fidl/fuchsia.hardware.light:fuchsia.hardware.light",
   "//sdk/fidl/fuchsia.hardware.network:fuchsia.hardware.network",
+  "//sdk/fidl/fuchsia.hardware.pci:fuchsia.hardware.pci",
   "//sdk/fidl/fuchsia.hardware.platform.device:fuchsia.hardware.platform.device",
   "//sdk/fidl/fuchsia.hardware.power:fuchsia.hardware.power",
   "//sdk/fidl/fuchsia.hardware.power.sensor:fuchsia.hardware.power.sensor",
diff --git a/sdk/fidl/fuchsia.accessibility.gesture/BUILD.gn b/sdk/fidl/fuchsia.accessibility.gesture/BUILD.gn
index 2220e78..1856905 100644
--- a/sdk/fidl/fuchsia.accessibility.gesture/BUILD.gn
+++ b/sdk/fidl/fuchsia.accessibility.gesture/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.accessibility.gesture") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [ "gesture_listener.fidl" ]
 
diff --git a/sdk/fidl/fuchsia.accessibility.semantics/BUILD.gn b/sdk/fidl/fuchsia.accessibility.semantics/BUILD.gn
index 99c9ea6..6c2b53e 100644
--- a/sdk/fidl/fuchsia.accessibility.semantics/BUILD.gn
+++ b/sdk/fidl/fuchsia.accessibility.semantics/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.accessibility.semantics") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "node.fidl",
diff --git a/sdk/fidl/fuchsia.accessibility.tts/BUILD.gn b/sdk/fidl/fuchsia.accessibility.tts/BUILD.gn
index 51e5c73..5ad5c48 100644
--- a/sdk/fidl/fuchsia.accessibility.tts/BUILD.gn
+++ b/sdk/fidl/fuchsia.accessibility.tts/BUILD.gn
@@ -9,7 +9,7 @@
   excluded_checks = [ "string-bounds-not-specified" ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "tts.fidl",
diff --git a/sdk/fidl/fuchsia.audio.controller/BUILD.gn b/sdk/fidl/fuchsia.audio.controller/BUILD.gn
index 6cf733e2..72875dc 100644
--- a/sdk/fidl/fuchsia.audio.controller/BUILD.gn
+++ b/sdk/fidl/fuchsia.audio.controller/BUILD.gn
@@ -20,6 +20,7 @@
   public_deps = [
     "//sdk/fidl/fuchsia.audio.device",
     "//sdk/fidl/fuchsia.hardware.audio",
+    "//sdk/fidl/fuchsia.hardware.audio.signalprocessing",
     "//sdk/fidl/fuchsia.io",
     "//sdk/fidl/fuchsia.media",
     "//zircon/vdso/zx",
diff --git a/sdk/fidl/fuchsia.audio.controller/device.fidl b/sdk/fidl/fuchsia.audio.controller/device.fidl
index 0c1fbca..9cc006f 100644
--- a/sdk/fidl/fuchsia.audio.controller/device.fidl
+++ b/sdk/fidl/fuchsia.audio.controller/device.fidl
@@ -5,63 +5,12 @@
 library fuchsia.audio.controller;
 
 using fuchsia.audio.device;
+using fuchsia.hardware.audio.signalprocessing;
 using fuchsia.hardware.audio;
 using fuchsia.io;
 using zx;
 
-/// Maximum number of audio devices in the system at any time.
-const MAX_COUNT_DEVICES uint32 = 256;
-
-/// Information about a device.
-type DeviceInfo = flexible union {
-    /// Device supports the fuchsia.hardware.audio/StreamConfig protocol.
-    1: stream_config StreamConfigDeviceInfo;
-
-    /// Device supports the fuchsia.hardware.audio/Composite protocol.
-    2: composite CompositeDeviceInfo;
-};
-
-/// Information about a device that supports the fuchsia.hardware.audio/StreamConfig protocol.
-type StreamConfigDeviceInfo = table {
-    /// Top level static properties of the stream.
-    ///
-    /// Required.
-    1: stream_properties fuchsia.hardware.audio.StreamProperties;
-
-    /// Supported formats.
-    ///
-    /// Required.
-    2: supported_formats
-            vector<fuchsia.hardware.audio.SupportedFormats>:fuchsia.hardware.audio.MAX_COUNT_FORMATS;
-
-    /// Gain state.
-    ///
-    /// Required.
-    3: gain_state fuchsia.hardware.audio.GainState;
-
-    /// Plug state.
-    ///
-    /// Required.
-    4: plug_state fuchsia.hardware.audio.PlugState;
-};
-
-/// Information about a device that supports the fuchsia.hardware.audio/Composite protocol.
-type CompositeDeviceInfo = table {
-    /// Top level static properties of the stream.
-    ///
-    /// Required.
-    1: composite_properties fuchsia.hardware.audio.CompositeProperties;
-
-    /// Supported DAI Formats
-    2: supported_dai_formats
-            vector<fuchsia.hardware.audio.DaiSupportedFormats>:fuchsia.hardware.audio.MAX_COUNT_FORMATS;
-
-    /// Supported ring buffer formats.
-    3: supported_ring_buffer_formats
-            vector<fuchsia.hardware.audio.SupportedFormats>:fuchsia.hardware.audio.MAX_COUNT_FORMATS;
-};
-
-/// Identifies which device to retrieve information about.
+/// Identifies an audio device.
 type DeviceSelector = flexible union {
     /// Driver node in devfs, e.g. `/dev/class/audio-input/3d99d780`.
     1: devfs struct {
@@ -71,27 +20,27 @@
         /// Device type.
         device_type fuchsia.audio.device.DeviceType;
     };
+
     /// A device available through the `fuchsia.audio.device/Registry` protocol.
     2: registry fuchsia.audio.device.TokenId;
 };
 
+/// Identifies a device ring buffer for playing/recording.
+type DeviceRingBuffer = struct {
+    /// The device that has a ring buffer.
+    selector DeviceSelector;
+
+    /// The ID of an ENDPOINT (with type RING_BUFFER) signal processing element
+    /// of the desired ring buffer.
+    ///
+    /// For Dai and StreamConfig devices, this should be
+    /// `fuchsia.audio.device.DEFAULT_RING_BUFFER_ELEMENT_ID`.
+    ring_buffer_element_id fuchsia.hardware.audio.signalprocessing.ElementId;
+};
+
 /// Enumerate, query, and control audio devices from clients.
 @discoverable
 open protocol DeviceControl {
-    /// Returns details about a specific audio device.
-    flexible GetDeviceInfo(resource table {
-        /// Id of device to retrieve information about, and
-        /// whether it is an input or output device.
-        ///
-        /// Required.
-        1: device DeviceSelector;
-    }) -> (resource table {
-        /// Information about the device.
-        ///
-        /// Required.
-        1: device_info DeviceInfo;
-    }) error zx.Status;
-
     /// Sets the gain of the stream in decibels.
     flexible DeviceSetGainState(resource table {
         /// Id of the device to set the gain state.
diff --git a/sdk/fidl/fuchsia.audio.controller/play.fidl b/sdk/fidl/fuchsia.audio.controller/play.fidl
index 1d71791..7c1b56d 100644
--- a/sdk/fidl/fuchsia.audio.controller/play.fidl
+++ b/sdk/fidl/fuchsia.audio.controller/play.fidl
@@ -55,7 +55,7 @@
             };
 
             /// A device ring buffer.
-            2: device_ring_buffer DeviceSelector;
+            2: device_ring_buffer DeviceRingBuffer;
         };
 
         /// Play settings.
diff --git a/sdk/fidl/fuchsia.audio.controller/record.fidl b/sdk/fidl/fuchsia.audio.controller/record.fidl
index 1fa55ef..3cf2e05 100644
--- a/sdk/fidl/fuchsia.audio.controller/record.fidl
+++ b/sdk/fidl/fuchsia.audio.controller/record.fidl
@@ -45,7 +45,7 @@
             2: loopback struct {};
 
             /// A device ring buffer.
-            3: device_ring_buffer DeviceSelector;
+            3: device_ring_buffer DeviceRingBuffer;
         };
 
         /// The stream format in which to record the audio.
diff --git a/sdk/fidl/fuchsia.bluetooth.bredr/profile.fidl b/sdk/fidl/fuchsia.bluetooth.bredr/profile.fidl
index 23ad00d..b0925f4b 100644
--- a/sdk/fidl/fuchsia.bluetooth.bredr/profile.fidl
+++ b/sdk/fidl/fuchsia.bluetooth.bredr/profile.fidl
@@ -228,6 +228,11 @@
         channel Channel;
         protocol ProtocolDescriptorList;
     });
+
+    /// An event produced by a FIDL server to signal that the registered service should be revoked
+    /// and removed from the Service Discovery Protocol database.
+    /// It is expected that this protocol will be subsequently closed after issuing this event.
+    flexible -> OnRevoke();
 };
 
 /// Maximum number of attributes returned or allowed in a search request.
diff --git a/sdk/fidl/fuchsia.bluetooth.host/BUILD.gn b/sdk/fidl/fuchsia.bluetooth.host/BUILD.gn
new file mode 100644
index 0000000..1f4cc52
--- /dev/null
+++ b/sdk/fidl/fuchsia.bluetooth.host/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/fidl/fidl.gni")
+
+fidl("fuchsia.bluetooth.host") {
+  sdk_category = "internal"
+  name = "fuchsia.bluetooth.host"
+
+  sources = [ "host.fidl" ]
+
+  public_deps = [
+    "//sdk/fidl/fuchsia.bluetooth",
+    "//sdk/fidl/fuchsia.bluetooth.bredr",
+    "//sdk/fidl/fuchsia.bluetooth.gatt",
+    "//sdk/fidl/fuchsia.bluetooth.gatt2",
+    "//sdk/fidl/fuchsia.bluetooth.le",
+    "//sdk/fidl/fuchsia.bluetooth.sys",
+  ]
+  enable_hlcpp = true
+}
diff --git a/sdk/fidl/fuchsia.bluetooth.host/OWNERS b/sdk/fidl/fuchsia.bluetooth.host/OWNERS
new file mode 100644
index 0000000..564a55d7
--- /dev/null
+++ b/sdk/fidl/fuchsia.bluetooth.host/OWNERS
@@ -0,0 +1 @@
+include /src/connectivity/bluetooth/OWNERS
diff --git a/src/connectivity/bluetooth/fidl/host.fidl b/sdk/fidl/fuchsia.bluetooth.host/host.fidl
similarity index 86%
rename from src/connectivity/bluetooth/fidl/host.fidl
rename to sdk/fidl/fuchsia.bluetooth.host/host.fidl
index 526e85f..c4e9fc1 100644
--- a/src/connectivity/bluetooth/fidl/host.fidl
+++ b/sdk/fidl/fuchsia.bluetooth.host/host.fidl
@@ -20,26 +20,19 @@
     });
 };
 
+type ProtocolRequest = flexible resource union {
+    1: central server_end:fuchsia.bluetooth.le.Central;
+    2: peripheral server_end:fuchsia.bluetooth.le.Peripheral;
+    3: gatt_server server_end:fuchsia.bluetooth.gatt.Server;
+    4: gatt2_server server_end:fuchsia.bluetooth.gatt2.Server;
+    5: profile server_end:fuchsia.bluetooth.bredr.Profile;
+};
+
 /// Interface for interacting with a Bluetooth host device (bt-host)
-closed protocol Host {
-    /// The following methods fulfill a given interface request. bt-host device
-    /// will start processing FIDL messages. If the request cannot be fulfilled,
-    /// the bt-host device will close its end of the given channel.
-    strict RequestLowEnergyCentral(resource struct {
-        central server_end:fuchsia.bluetooth.le.Central;
-    });
-    strict RequestLowEnergyPeripheral(resource struct {
-        peripheral server_end:fuchsia.bluetooth.le.Peripheral;
-    });
-    strict RequestGattServer(resource struct {
-        server server_end:fuchsia.bluetooth.gatt.Server;
-    });
-    strict RequestGatt2Server(resource struct {
-        server server_end:fuchsia.bluetooth.gatt2.Server;
-    });
-    strict RequestProfile(resource struct {
-        profile server_end:fuchsia.bluetooth.bredr.Profile;
-    });
+open protocol Host {
+    /// Fulfills a given protocol request. bt-host will start processing FIDL messages. If the
+    /// request cannot be fulfilled, the bt-host device will close its end of the given channel.
+    flexible RequestProtocol(ProtocolRequest);
 
     /// Shuts down the host, ending all active Bluetooth procedures:
     ///
@@ -54,7 +47,9 @@
     ///
     /// The Host will continue to send OnDeviceUpdated events as procedures get
     /// terminated.
-    strict Close();
+    ///
+    /// The Host protocol will close when shutdown is complete.
+    strict Shutdown();
 
     /// Returns information about the Bluetooth host subsystem and controller managed by this Host
     /// instance. If there has been no change to the state since the last call to this method, the
@@ -63,14 +58,12 @@
     /// The returned `info` structure will be populated with the current state of the bt-host
     /// device. However the `active` parameter will never be populated. This field is managed
     /// by a higher layer.
-    strict WatchState() -> (struct {
+    flexible WatchState() -> (struct {
         info sys.HostInfo;
     });
 
     /// Assigns local data to this host.
-    strict SetLocalData(struct {
-        host_data sys.HostData;
-    });
+    strict SetLocalData(sys.HostData);
 
     /// Monitors updates for connectable peers known to the system. Replies only when
     /// peers have been added, modified, or removed since the most recent call to WatchPeers().
@@ -85,18 +78,18 @@
     ///
     /// - response `updated` Peers that were added or updated since the last call to WatchPeers().
     /// - response `removed` Ids of peers that were removed since the last call to WatchPeers().
-    strict WatchPeers() -> (struct {
+    flexible WatchPeers() -> (struct {
         updated vector<sys.Peer>:MAX;
         removed vector<bt.PeerId>:MAX;
     });
 
     /// Sets the local name for this host device.
-    strict SetLocalName(struct {
+    flexible SetLocalName(struct {
         local_name bt.DeviceName;
     }) -> () error sys.Error;
 
     /// Sets the device class for this host device.
-    strict SetDeviceClass(struct {
+    flexible SetDeviceClass(struct {
         device_class bt.DeviceClass;
     }) -> () error sys.Error;
 
@@ -108,22 +101,22 @@
     /// Discovery will continue until it is terminated via StopDiscovery() or if the Host protocol
     /// channel gets closed. If the device does not support BR/EDR, only LE discovery will be
     /// performed.
-    strict StartDiscovery() -> () error sys.Error;
+    flexible StartDiscovery() -> () error sys.Error;
 
     /// Terminates discovery if one was started via StartDiscovery().
     ///
     /// NOTE: If another client is performing discovery (e.g. via its own le.Central interface
     /// handle), then the system will continue performing device discovery even if this method
     /// results in success.
-    strict StopDiscovery();
+    flexible StopDiscovery();
 
     /// Sets whether this host should be connectable.
-    strict SetConnectable(struct {
+    flexible SetConnectable(struct {
         enabled bool;
     }) -> () error sys.Error;
 
     /// Sets whether this host should be discoverable.
-    strict SetDiscoverable(struct {
+    flexible SetDiscoverable(struct {
         enabled bool;
     }) -> () error sys.Error;
 
@@ -145,7 +138,7 @@
     /// The result of the procedure will be communicated via `status`. If the remote device
     /// supports both BR/EDR and LE transports and a link cannot be established over both, then an
     /// error Status will be returned and neither transport will be connected.
-    strict Connect(struct {
+    flexible Connect(struct {
         id bt.PeerId;
     }) -> () error sys.Error;
 
@@ -155,7 +148,7 @@
     /// - response `status` Contains an error if either LE or BR/EDR transport fails to disconnect.
     ///                     Contains success when both transports are successfully disconnected or
     ///                     if the peer is already disconnected.
-    strict Disconnect(struct {
+    flexible Disconnect(struct {
         id bt.PeerId;
     }) -> () error sys.Error;
 
@@ -169,7 +162,7 @@
     /// NOTE: This is intended to satisfy test scenarios that require pairing procedures to be
     /// initiated without relying on service access. In normal operation, Bluetooth security is
     /// enforced during service access.
-    strict Pair(struct {
+    flexible Pair(struct {
         id bt.PeerId;
         options sys.PairingOptions;
     }) -> () error sys.Error;
@@ -181,7 +174,7 @@
     /// Returns success after no peer exists that's identified by `device_id` (even if it didn't
     /// exist before Forget), failure if the peer specified by `device_id` could not be
     /// disconnected or deleted and still exists.
-    strict Forget(struct {
+    flexible Forget(struct {
         id bt.PeerId;
     }) -> () error sys.Error;
 
@@ -189,7 +182,7 @@
     /// device will continuously perform a passive LE scan in the background when
     /// no device discovery sessions are active and accept connection requests from
     /// bonded peripherals.
-    strict EnableBackgroundScan(struct {
+    flexible EnableBackgroundScan(struct {
         enabled bool;
     });
 
@@ -220,7 +213,7 @@
     /// I/O capabilities. Calling this method cancels any on-going pairing procedure started
     /// using a previous delegate. Pairing requests will be rejected if no PairingDelegate has been
     /// assigned.
-    strict SetPairingDelegate(resource struct {
+    flexible SetPairingDelegate(resource struct {
         input sys.InputCapability;
         output sys.OutputCapability;
         delegate client_end:sys.PairingDelegate;
@@ -236,7 +229,7 @@
     /// `errors`. This can happen for entries that are malformed and for peers that are already
     /// known to the bt-host. An empty `errors` list indicates that all bonds were successfully
     /// restored.
-    strict RestoreBonds(struct {
+    flexible RestoreBonds(struct {
         bonds vector<sys.BondingData>:MAX;
     }) -> (struct {
         errors vector<sys.BondingData>:MAX;
@@ -245,7 +238,7 @@
     // ===== Events =====
 
     /// Notifies when bonding data for a peer has been updated.
-    strict -> OnNewBondingData(struct {
+    flexible -> OnNewBondingData(struct {
         data sys.BondingData;
     });
 
diff --git a/sdk/fidl/fuchsia.camera/BUILD.gn b/sdk/fidl/fuchsia.camera/BUILD.gn
index 125c177..3d59aaa 100644
--- a/sdk/fidl/fuchsia.camera/BUILD.gn
+++ b/sdk/fidl/fuchsia.camera/BUILD.gn
@@ -12,7 +12,7 @@
   ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "camera.fidl",
diff --git a/sdk/fidl/fuchsia.camera2.hal/BUILD.gn b/sdk/fidl/fuchsia.camera2.hal/BUILD.gn
index ed9bf92..857e60b 100644
--- a/sdk/fidl/fuchsia.camera2.hal/BUILD.gn
+++ b/sdk/fidl/fuchsia.camera2.hal/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.camera2.hal") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [ "hal.fidl" ]
 
diff --git a/sdk/fidl/fuchsia.camera2/BUILD.gn b/sdk/fidl/fuchsia.camera2/BUILD.gn
index 5409066..f2094df 100644
--- a/sdk/fidl/fuchsia.camera2/BUILD.gn
+++ b/sdk/fidl/fuchsia.camera2/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.camera2") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "manager.fidl",
diff --git a/sdk/fidl/fuchsia.camera3/BUILD.gn b/sdk/fidl/fuchsia.camera3/BUILD.gn
index 6ceb9fe..2426497 100644
--- a/sdk/fidl/fuchsia.camera3/BUILD.gn
+++ b/sdk/fidl/fuchsia.camera3/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.camera3") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "device.fidl",
diff --git a/sdk/fidl/fuchsia.component.sandbox/fuchsia.component.sandbox.api b/sdk/fidl/fuchsia.component.sandbox/fuchsia.component.sandbox.api
index 265c9e8..cd8eb0e 100644
--- a/sdk/fidl/fuchsia.component.sandbox/fuchsia.component.sandbox.api
+++ b/sdk/fidl/fuchsia.component.sandbox/fuchsia.component.sandbox.api
@@ -1,3 +1,3 @@
 {
-  "fidl/fuchsia.component.sandbox": "c2ee4c23f6c97943d45c18093b0d13df"
+  "fidl/fuchsia.component.sandbox": "d831dbf0cced4445c1faf15371d5f58c"
 }
\ No newline at end of file
diff --git a/sdk/fidl/fuchsia.component.sandbox/overview.fidl b/sdk/fidl/fuchsia.component.sandbox/overview.fidl
index 983c0cf..d1e81a63 100644
--- a/sdk/fidl/fuchsia.component.sandbox/overview.fidl
+++ b/sdk/fidl/fuchsia.component.sandbox/overview.fidl
@@ -1,5 +1,5 @@
 // Copyright 2023 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-@available(added=HEAD)
+@available(added=20)
 library fuchsia.component.sandbox;
diff --git a/sdk/fidl/fuchsia.component.sandbox/sandbox.fidl b/sdk/fidl/fuchsia.component.sandbox/sandbox.fidl
index 431877c..0b5c387 100644
--- a/sdk/fidl/fuchsia.component.sandbox/sandbox.fidl
+++ b/sdk/fidl/fuchsia.component.sandbox/sandbox.fidl
@@ -13,6 +13,7 @@
 /// Maximum number of items returned by [DictionaryIterator].
 const MAX_DICTIONARY_ITEMS_CHUNK uint32 = 128;
 
+@available(added=HEAD)
 closed protocol HandleCapability {
     compose fuchsia.unknown.Cloneable;
     strict GetHandle() -> (resource struct {
@@ -22,6 +23,7 @@
     };
 };
 
+@available(added=HEAD)
 type DataCapability = flexible union {
     1: bytes vector<byte>:MAX_DATA_LENGTH;
     2: string string:MAX_DATA_LENGTH;
@@ -29,6 +31,7 @@
     4: uint64 uint64;
 };
 
+@available(added=HEAD)
 type Capability = flexible resource union {
     1: unit @generated_name("UnitCapability") struct {};
     2: handle client_end:HandleCapability;
@@ -36,25 +39,28 @@
     4: cloneable client_end:fuchsia.unknown.Cloneable;
     5: dictionary client_end:Dictionary;
     6: sender client_end:Sender;
-    7: open client_end:fuchsia.io.Openable;
-    8: directory client_end:fuchsia.io.Directory;
+    7: directory client_end:fuchsia.io.Directory;
 };
 
 /// The maximum length of a dictionary key. This should coincide with
 /// fuchsia.component.MAX_NAME_LENGTH.
+@available(added=HEAD)
 const MAX_NAME_LENGTH uint64 = fuchsia.io.MAX_NAME_LENGTH;
 
 /// The key of a [`DictionaryItem`]. The constraints for valid keys are documented at
 /// https://fuchsia.dev/reference/cml#names.
+@available(added=HEAD)
 alias DictionaryKey = string:MAX_NAME_LENGTH;
 
 /// A key-value pair in a [`Dictionary`].
+@available(added=HEAD)
 type DictionaryItem = resource struct {
     key DictionaryKey;
     value Capability;
 };
 
 /// Error returned from methods in [`Dictionary`].
+@available(added=HEAD)
 type DictionaryError = flexible enum {
     /// The Dictionary does not contain an item with the given key.
     NOT_FOUND = 1;
@@ -75,6 +81,7 @@
 };
 
 @discoverable
+@available(added=20)
 open protocol Dictionary {
     /// Creates a new connection to the same underlying dictionary.
     ///
@@ -85,11 +92,13 @@
     ///
     /// * error `DictionaryError.ALREADY_EXISTS` if the dictionary already contains an
     /// item with the same key.
+    @available(added=HEAD)
     flexible Insert(DictionaryItem) -> () error DictionaryError;
 
     /// Get a clone of a capability from this dictionary.
     ///
     /// * error `DictionaryError.NOT_FOUND` if the dictionary does not contain the key.
+    @available(added=HEAD)
     flexible Get(struct {
         key DictionaryKey;
     }) -> (resource struct {
@@ -99,6 +108,7 @@
     /// Removes a key from the dictionary, returning the [`Capability`] value.
     ///
     /// * error `DictionaryError.NOT_FOUND` if the dictionary does not contain the key.
+    @available(added=HEAD)
     flexible Remove(struct {
         key DictionaryKey;
     }) -> (resource struct {
@@ -109,6 +119,7 @@
     ///
     /// This operation creates shallow clones of values.
     // TODO(b/314361448): Remove once callers use Dictionary.Enumerate instead
+    @available(added=HEAD)
     flexible Read() -> (resource struct {
         items vector<DictionaryItem>:MAX;
     });
@@ -119,6 +130,7 @@
     /// For example, if this dictionary contains nested dictionaries, the newly
     /// created dictionary will contain references to those same nested
     /// dictionaries because the entries are cloned rather than copied.
+    @available(added=HEAD)
     flexible Copy(resource struct {
         request server_end:Dictionary;
     });
@@ -126,6 +138,7 @@
     /// Enumerates the entries in this dictionary.
     ///
     /// Creates a clone of each item during enumeration.
+    @available(added=HEAD)
     flexible Enumerate(resource struct {
         contents server_end:DictionaryIterator;
     });
@@ -134,11 +147,13 @@
     ///
     /// If `contents` is not provided, all the items are discarded without
     /// enumerating them.
+    @available(added=HEAD)
     flexible Drain(resource struct {
         contents server_end:<DictionaryIterator, optional>;
     });
 };
 
+@available(added=HEAD)
 open protocol DictionaryIterator {
     flexible GetNext() -> (resource struct {
         items vector<DictionaryItem>:MAX_DICTIONARY_ITEMS_CHUNK;
@@ -148,6 +163,7 @@
 /// A sender allows a client to send a channel to the framework
 /// so that it can be connected.
 @discoverable
+@available(added=HEAD)
 open protocol Sender {
     compose fuchsia.unknown.Cloneable;
 
@@ -158,39 +174,33 @@
 /// A receiver is served by clients and allows them to receive channels
 /// from the framework.
 @discoverable
+@available(added=HEAD)
 open protocol Receiver {
     /// Sends a channel to this receiver.
     flexible Receive(ProtocolPayload);
 };
 
 /// Contains a protocol open request.
+@available(added=HEAD)
 type ProtocolPayload = resource struct {
     channel zx.Handle:CHANNEL;
 };
 
 /// Entrypoint for instantiation of sandbox types.
 @discoverable
+@available(added=HEAD)
 open protocol Factory {
     /// Creates a `Sender` from a client served `Receiver`.
     flexible CreateSender(resource struct {
         receiver client_end:Receiver;
-        sender server_end:Sender;
-    }) -> ();
+    }) -> (resource struct {
+        sender client_end:Sender;
+    });
 
     /// Creates a new empty [`Dictionary`].
-    flexible CreateDictionary(resource struct {
-        server_end server_end:Dictionary;
-    }) -> ();
-
-    /// Creates an [`Open`] capability that issues Open calls on
-    /// an another [`Openable`].
-    ///
-    /// This registers the `Openable` as a sandbox capability,
-    /// represented by the client end peer of `server_end`.
-    flexible CreateOpen(resource struct {
-        client_end client_end:fuchsia.io.Openable;
-        server_end server_end:fuchsia.io.Openable;
-    }) -> ();
+    flexible CreateDictionary() -> (resource struct {
+        dictionary client_end:Dictionary;
+    });
 
     /// Creates a [`Directory`] capability from a [`client_end:fuchsia.io.Directory`], and
     /// registers it as a sandbox capability.
diff --git a/sdk/fidl/fuchsia.component.test/fuchsia.component.test.api b/sdk/fidl/fuchsia.component.test/fuchsia.component.test.api
index 4a632c3..cee4f51 100644
--- a/sdk/fidl/fuchsia.component.test/fuchsia.component.test.api
+++ b/sdk/fidl/fuchsia.component.test/fuchsia.component.test.api
@@ -1,3 +1,3 @@
 {
-  "fidl/fuchsia.component.test": "8ece960545fae20e844332036bf0936e"
+  "fidl/fuchsia.component.test": "7f6b21be56639d5c99f779e05d1e1487"
 }
\ No newline at end of file
diff --git a/sdk/fidl/fuchsia.component.test/realm_builder.fidl b/sdk/fidl/fuchsia.component.test/realm_builder.fidl
index a4b4d30..a840fd0 100644
--- a/sdk/fidl/fuchsia.component.test/realm_builder.fidl
+++ b/sdk/fidl/fuchsia.component.test/realm_builder.fidl
@@ -137,6 +137,10 @@
     /// policy.
     @available(added=9)
     CONFIG_OVERRIDE_UNSUPPORTED = 21;
+
+    /// A child declaration failed validation.
+    @available(added=20)
+    INVALID_CHILD_DECL = 22;
 };
 
 closed protocol Builder {
diff --git a/sdk/fidl/fuchsia.component/namespace.fidl b/sdk/fidl/fuchsia.component/namespace.fidl
index a255ee5..c7ec655d 100644
--- a/sdk/fidl/fuchsia.component/namespace.fidl
+++ b/sdk/fidl/fuchsia.component/namespace.fidl
@@ -4,14 +4,14 @@
 library fuchsia.component;
 using fuchsia.component.sandbox;
 
-@available(added=HEAD)
+@available(added=20)
 type NamespaceInputEntry = resource struct {
     path string:MAX_PATH_LENGTH;
     dictionary client_end:fuchsia.component.sandbox.Dictionary;
 };
 
 /// Error returned from methods in [`Namespace`].
-@available(added=HEAD)
+@available(added=20)
 type NamespaceError = flexible enum {
     /// The parent of a parent shares a prefix with another namespace entry
     SHADOW = 1;
@@ -30,7 +30,7 @@
 };
 
 /// Protocol for performing namespace operations.
-@available(added=HEAD)
+@available(added=20)
 @discoverable
 open protocol Namespace {
     flexible Create(resource struct {
diff --git a/sdk/fidl/fuchsia.device.manager/BUILD.gn b/sdk/fidl/fuchsia.device.manager/BUILD.gn
index 3a0dc29..e536e5e 100644
--- a/sdk/fidl/fuchsia.device.manager/BUILD.gn
+++ b/sdk/fidl/fuchsia.device.manager/BUILD.gn
@@ -8,15 +8,8 @@
   sdk_category = "internal"
   sources = [
     "administrator.fidl",
-    "coordinator.fidl",
     "system-state-transition.fidl",
   ]
-  public_deps = [
-    "//sdk/fidl/fuchsia.device",
-    "//sdk/fidl/fuchsia.driver.framework",
-    "//sdk/fidl/fuchsia.driver.legacy",
-    "//sdk/fidl/fuchsia.io",
-    "//zircon/vdso/zx",
-  ]
+  public_deps = [ "//zircon/vdso/zx" ]
   enable_hlcpp = true
 }
diff --git a/sdk/fidl/fuchsia.device.manager/coordinator.fidl b/sdk/fidl/fuchsia.device.manager/coordinator.fidl
deleted file mode 100644
index 6fb7c9f..0000000
--- a/sdk/fidl/fuchsia.device.manager/coordinator.fidl
+++ /dev/null
@@ -1,376 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-library fuchsia.device.manager;
-
-// TODO(teisenbe): Move these interfaces to be internal to the devmgr codebase
-
-using fuchsia.driver.framework as fdf;
-using fuchsia.driver.legacy;
-using fuchsia.io;
-using fuchsia.device;
-using zx;
-
-// Identifier used to let the devcoordinator describe specific devices during
-// composite construction
-alias LocalDeviceId = uint64;
-
-/// This definition must match `ZX_DEVICE_NAME_MAX` and is checked by a static assert.
-const DEVICE_NAME_MAX uint32 = 31;
-
-/// Maximum number of bytes in a device arguments string.
-const DEVICE_ARGS_MAX uint32 = 1024;
-
-/// Maximum number of bytes in a metadata payload
-const METADATA_BYTES_MAX uint32 = 8192;
-
-/// Maximum number of metadata that can be added to a device
-const METADATA_MAX uint32 = 32;
-
-/// Maximum number of fragments that a composite device can have
-const FRAGMENTS_MAX uint32 = 16;
-
-/// Maximum number of parts that a composite device fragment can have
-const DEVICE_FRAGMENT_PARTS_MAX uint32 = 16;
-
-/// Maximum number of instructions in the match program of a device fragment part
-const DEVICE_FRAGMENT_PART_INSTRUCTIONS_MAX uint32 = 32;
-
-/// Maximum length of a dispatcher scheduler role.
-const MAX_SCHEDULER_ROLE_LENGTH uint32 = 2048;
-
-/// Bit flags for device add configuration
-type AddDeviceConfig = strict bits : uint32 {
-    /// Device can be a fragment in multiple composite devices
-    ALLOW_MULTI_COMPOSITE = 0x00000001;
-    /// Device should not trigger the auto-bind mechanism
-    SKIP_AUTOBIND = 0x00000004;
-    /// Device should run in an isolated driver host from its children.
-    MUST_ISOLATE = 0x00000008;
-};
-
-/// A part of a description of a DeviceFragment
-type DeviceFragmentPart = struct {
-    match_program
-            vector<fuchsia.driver.legacy.BindInstruction>:DEVICE_FRAGMENT_PART_INSTRUCTIONS_MAX;
-};
-
-/// A piece of a composite device
-type DeviceFragment = struct {
-    name string:32;
-    parts vector<DeviceFragmentPart>:DEVICE_FRAGMENT_PARTS_MAX;
-};
-
-/// Metadata that can be added to a device
-type DeviceMetadata = struct {
-    key uint32;
-    data vector<uint8>:METADATA_BYTES_MAX;
-};
-
-/// Composite device parts and properties
-type CompositeDeviceDescriptor = struct {
-    props vector<fuchsia.driver.legacy.DeviceProperty>:fuchsia.driver.legacy.PROPERTIES_MAX;
-    str_props
-            vector<fuchsia.driver.legacy.DeviceStrProperty>:fuchsia.driver.legacy.STR_PROPERTIES_MAX;
-    fragments vector<DeviceFragment>:FRAGMENTS_MAX;
-    primary_fragment_index uint32;
-    spawn_colocated bool;
-    metadata vector<DeviceMetadata>:<METADATA_MAX, optional>;
-};
-
-/// Composite node specification parts and properties.
-type CompositeNodeSpecDescriptor = struct {
-    parents vector<fdf.ParentSpec>:MAX;
-    metadata vector<DeviceMetadata>:<METADATA_MAX, optional>;
-};
-
-/// Protocol for controlling devices in a devhost process from the devcoordinator
-closed protocol DeviceController {
-    /// Connect to the device's FIDL, but also include other FIDLs multiplexed on the same channel.
-    ///
-    /// + request `include_node` if this is true then include fuchsia.io/Node on the channel.
-    /// + request `include_controller` if this is true then include fuchsia.device/Controller on the channel.
-    strict ConnectMultiplexed(resource struct {
-        server zx.Handle:CHANNEL;
-        include_node bool;
-        include_controller bool;
-    });
-
-    /// Connect to the device's fuchsia.device/Controller API.
-    strict ConnectToController(resource struct {
-        controller server_end:fuchsia.device.Controller;
-    });
-
-    /// Connect to the device's API.
-    ///
-    /// NOTE: This is not multiplexed with fuchsia.io/Node or fuchsia.device/Controller.
-    strict ConnectToDeviceProtocol(resource struct {
-        server zx.Handle:CHANNEL;
-    });
-
-    /// Bind the requested driver to this device.  `driver_path` is informational,
-    /// but all calls to BindDriver/CreateDevice should use the same `driver_path`
-    /// each time they use a `driver` VMO with the same contents. Returns a `status`
-    /// and optionally a channel to the driver's test output. `test_output` will be
-    /// not present unless the driver is configured to run its run_unit_tests hook, in
-    /// which case the other end of the channel will have been passed to the driver.
-    ///
-    /// + request `default_dispatcher_scheduler_role` the scheduler role to set for
-    /// the default dispatcher created for the driver. The scheduler role determines
-    /// the thread pool that the dispatcher will be serviced by. This may be an empty
-    /// string if the driver does not require the dispatcher to run in a specific
-    /// thread pool. Setting a scheduler role is on a best-effort basis. If an invalid
-    /// scheduler role is specified, the dispatcher will be serviced by the default
-    /// thread pool, and this will not cause an error to be returned.
-    strict BindDriver(resource struct {
-        driver_path string:fuchsia.driver.legacy.DEVICE_PATH_MAX;
-        driver zx.Handle:VMO;
-        default_dispatcher_scheduler_role string:MAX_SCHEDULER_ROLE_LENGTH;
-    }) -> (resource struct {
-        status zx.Status;
-        test_output zx.Handle:<CHANNEL, optional>;
-    });
-
-    /// Give this device a channel to its shadow in another process.
-    strict ConnectProxy(resource struct {
-        shadow zx.Handle:CHANNEL;
-    });
-
-    /// Ask devhost to call the device init hook.
-    strict Init() -> (struct {
-        status zx.Status;
-    });
-
-    /// Ask devhost to unbind this device. On success, the remote end of this
-    /// interface channel will close instead of returning a result.
-    strict Unbind() -> () error zx.Status;
-
-    /// Ask the devhost to complete the removal of this device, which previously had
-    /// invoked `ScheduleRemove`. This is a special case that can be removed
-    /// once `device_remove` invokes `unbind`.
-    strict CompleteRemoval() -> () error zx.Status;
-
-    /// Ask devhost to suspend this device, using the target state indicated by `flags`.
-    strict Suspend(struct {
-        flags uint32;
-    }) -> (struct {
-        status zx.Status;
-    });
-
-    /// Ask devhost to resume this device, using the target system state indicated by
-    /// 'target_system_state'.
-    strict Resume(struct {
-        target_system_state uint32;
-    }) -> (struct {
-        status zx.Status;
-    });
-
-    /// Informs the driver that it has been made visible in devfs.
-    strict SignalMadeVisible();
-};
-
-const FRAGMENT_NAME_MAX uint32 = 32;
-
-type Fragment = struct {
-    name string:FRAGMENT_NAME_MAX;
-    id LocalDeviceId;
-};
-
-type StubDevice = struct {
-    protocol_id uint32;
-};
-
-type ProxyDevice = resource struct {
-    driver_path string:fuchsia.driver.legacy.DEVICE_PATH_MAX;
-    driver zx.Handle:VMO;
-    parent_proxy zx.Handle:CHANNEL;
-};
-
-type FidlProxyDevice = resource struct {
-    /// If this is present this represents an incoming namespace directory that the
-    /// device can use to access FIDL protocols from its parent.
-    incoming_dir client_end:<fuchsia.io.Directory, optional>;
-};
-
-type CompositeDevice = struct {
-    fragments vector<Fragment>:FRAGMENTS_MAX;
-    name string:DEVICE_NAME_MAX;
-};
-
-type DeviceType = strict resource union {
-    /// The device has no parent to communicate with and no driver to load.
-    1: stub StubDevice;
-
-    /// The device acts as a proxy for its parent and talks to it via its
-    /// proxy channel.
-    2: proxy ProxyDevice;
-
-    /// This device is a proxy for its parent which lives in another driver host.
-    /// The parent exposes FIDL protocols in its outgoing directory, which have
-    /// been routed to this device.
-    3: fidl_proxy FidlProxyDevice;
-
-    /// The device is a composite device with several parents, referred to as
-    /// fragments. The device aggregates all parent devices together. The order of the
-    /// fragments will match the original composite creation request.
-    4: composite CompositeDevice;
-};
-
-/// Protocol for controlling a driver host process from the driver manager
-closed protocol DriverHostController {
-    /// Create a device in the driver host. |type| describes what type of device
-    /// is set up, how it communicates with its parent (if it has one).
-    ///
-    /// `local_device_id` will be a unique value within the device's devhost
-    strict CreateDevice(resource struct {
-        coordinator client_end:Coordinator;
-        device_controller server_end:DeviceController;
-        type DeviceType;
-        local_device_id LocalDeviceId;
-    }) -> (struct {
-        status zx.Status;
-    });
-
-    // TODO(https://fxbug.dev/42147318): Currently unimplemented.
-    /// Request to restart the driver host. Also restarts all children devices and drivers and
-    /// rebinds them once the Driver Host has restarted.
-    strict Restart() -> (struct {
-        status zx.Status;
-    });
-};
-
-/// This struct holds non-resource arguments for creating a new device with the
-/// Coordinator.
-type AddDeviceArgs = struct {
-    /// The device name, used for debugging.
-    name string:DEVICE_NAME_MAX;
-    /// The protocol id, used for binding.
-    protocol_id uint32;
-    /// The property list of the device, used for binding.
-    property_list fuchsia.driver.legacy.DevicePropertyList;
-    /// The driver path, used for debugging.
-    driver_path string:<fuchsia.driver.legacy.DEVICE_PATH_MAX, optional>;
-    /// This should be used only for shadowed device. This will be forwarded to
-    /// the shadowed device.
-    args string:<DEVICE_ARGS_MAX, optional>;
-    device_add_config AddDeviceConfig;
-    has_init bool;
-    /// An address pointing to the DFv2 device symbol, which contains its banjo
-    /// ops. This exists on every DFv1 device, but it is only used by a DFv2
-    /// child.
-    dfv2_device_symbol uint64;
-};
-
-/// Interface for drivers in driver host to coordinate with the driver
-/// manager.
-closed protocol Coordinator {
-    /// Record the addition of a new device that can be communicated with via `device_controller`.
-    /// On success, the returned `local_device_id` is the identifier assigned by devmgr.
-    // TODO(https://fxbug.dev/42154360): String properties are unimplemented.
-    strict AddDevice(resource struct {
-        args AddDeviceArgs;
-        coordinator server_end:Coordinator;
-        device_controller client_end:DeviceController;
-        inspect zx.Handle:<VMO, optional>;
-        outgoing_dir client_end:<fuchsia.io.Directory, optional>;
-    }) -> (struct {
-        local_device_id LocalDeviceId;
-    }) error zx.Status;
-
-    /// Requests the devcoordinator schedule the removal of this device,
-    /// and the unbinding of its children.
-    /// If `unbind_self` is true, the unbind hook for this device will also be called.
-    strict ScheduleRemove(struct {
-        unbind_self bool;
-    });
-
-    /// Requests the devcoordinator schedule the unbinding of this device's children.
-    /// If the device has no children, no request will be sent, and `has_children` will be false.
-    strict ScheduleUnbindChildren() -> (struct {
-        has_children bool;
-    }) error zx.Status;
-
-    /// Attempt to bind a driver against this device.
-    /// + request `driver_url_suffix` only driver's that match this URL suffix will try to bind to
-    ///           the device (e.g: "fvm.cm").
-    ///           If this is null, the API will autobind.
-    /// * error `ZX_ERR_ALREADY_BOUND` if the device is already bound.
-    /// * error `ZX_ERR_NOT_FOUND` no drivers were found.
-    strict BindDevice(struct {
-        driver_url_suffix string:<fuchsia.driver.legacy.DEVICE_PATH_MAX, optional>;
-    }) -> () error zx.Status;
-
-    /// Returns the topological path of this device.
-    strict GetTopologicalPath() -> (struct {
-        path string:fuchsia.driver.legacy.DEVICE_PATH_MAX;
-    }) error zx.Status;
-
-    /// Requests that the firmware at the given path be loaded and returned.
-    strict LoadFirmware(struct {
-        driver_path string:fuchsia.driver.legacy.DEVICE_PATH_MAX;
-        fw_path string:fuchsia.driver.legacy.DEVICE_PATH_MAX;
-    }) -> (resource struct {
-        vmo zx.Handle:VMO;
-        size uint64;
-    }) error zx.Status;
-
-    /// Retrieve the metadata blob associated with this device and the given key.
-    strict GetMetadata(struct {
-        key uint32;
-    }) -> (struct {
-        data vector<uint8>:METADATA_BYTES_MAX;
-    }) error zx.Status;
-
-    /// Retrieve the metadata size associated with this device and the given key.
-    strict GetMetadataSize(struct {
-        key uint32;
-    }) -> (struct {
-        size uint64;
-    }) error zx.Status;
-
-    /// Add metadata blob associated with this device and the given key.
-    /// If the same key is specified multiple times, the new data will be
-    /// ignored in favor of the data from first call with the specified key.
-    // TODO(https://fxbug.dev/42063857): Return ZX_ERR_ALREADY_EXISTS on duplicate key
-    // instead.
-    strict AddMetadata(struct {
-        key uint32;
-        data vector<uint8>:<METADATA_BYTES_MAX, optional>;
-    }) -> () error zx.Status;
-
-    /// Adds the given composite device.  This causes the driver manager to try to match the
-    /// fragments against the existing device tree, and to monitor all new device additions
-    /// in order to find the fragments as they are created.
-    strict AddCompositeDevice(struct {
-        name string:DEVICE_NAME_MAX;
-        comp_desc CompositeDeviceDescriptor;
-    }) -> () error zx.Status;
-
-    /// Adds the given composite node spec. This causes the driver manager to add the spec to
-    /// the driver index, and then try to match the parents against the node topology.
-    /// All device additions will be monitored to see if they matched to the remaining
-    /// unbound nodes.
-    strict AddCompositeNodeSpec(struct {
-        name string:DEVICE_NAME_MAX;
-        spec CompositeNodeSpecDescriptor;
-    }) -> () error zx.Status;
-
-    /// Connects the given FIDL protocol inside of a FIDL service. Connection is completed
-    /// asynchronously due to pipelining. Returning `ZX_OK` does not imply the service exists. A
-    /// two way call to the service via the retained client end of the channel pair must be issued
-    /// in order to ascertain whether the connection has been successfully established.
-    /// + |fragment_name| should be specified if the parent is a composite node.
-    /// + |service_name| should be specified if attempting to connect to a service. This will be
-    ///   mandatory in the future: https://fxbug.dev/42058509.
-    /// * error Reports `ZX_ERR_UNAVAILABLE` if the parent (or fragment) does not have an outgoing
-    ///   directory.
-    /// * error Reports `ZX_ERR_NOT_FOUND` if |fragment_name| is not the name of a parent.
-    /// * error Reports `ZX_ERR_NOT_SUPPORTED` if |fragment_name| is specified by the device is not
-    ///   a composite node
-    strict ConnectFidlProtocol(resource struct {
-        fragment_name string:<DEVICE_NAME_MAX, optional>;
-        service_name string:<fuchsia.driver.legacy.STR_LENGTH_MAX, optional>;
-        protocol_name string:fuchsia.driver.legacy.STR_LENGTH_MAX;
-        server zx.Handle:CHANNEL;
-    }) -> () error zx.Status;
-};
diff --git a/sdk/fidl/fuchsia.device/controller.fidl b/sdk/fidl/fuchsia.device/controller.fidl
index 3bb534d..bf3e4ee 100644
--- a/sdk/fidl/fuchsia.device/controller.fidl
+++ b/sdk/fidl/fuchsia.device/controller.fidl
@@ -13,10 +13,6 @@
 const MAX_DRIVER_NAME_LEN uint64 = 32;
 /// Maximum length for a driver path
 const MAX_DRIVER_PATH_LEN uint64 = 1024;
-/// Maximum device power states. In future this should account
-/// for performance states.
-const MAX_DEVICE_POWER_STATES uint32 = 5;
-const MIN_DEVICE_POWER_STATES uint32 = 2; // D0 & D3COLD
 
 @deprecated("devices will be services in the future")
 type DeviceSignal = strict bits : uint32 {
@@ -32,95 +28,6 @@
     HANGUP = 0x10000000; // ZX_USER_SIGNAL_4
 };
 
-type DevicePowerState = strict enum : uint8 {
-    /// Mandatory Working state. Device is fully functional, can take I/O,
-    /// issue interrupts. This state is mandatory for all devices
-    /// The device enters into this state by default, when powered on.
-    DEVICE_POWER_STATE_D0 = 0;
-    /// [OPTIONAL] Device is not working when in this state. It cannot process
-    /// I/O nor issue interrupts, unless it is armed for some special interrupts
-    /// that can wake up the system/device. When in this state, the restore time
-    /// of getting back to working state is less than other low-power states
-    /// Power savings in this state are lesser than other low power states.
-    /// Device may retain some hardware context and full initialization
-    /// may not be needed when resuming from this state.
-    DEVICE_POWER_STATE_D1 = 1;
-    /// [OPTIONAL] Device is not working when in this state. It cannot process
-    /// I/O nor issue interrupts, unless it is armed for some special interrupts
-    /// that can wake up the system/device. When in this state, the restore time
-    /// of getting back to working state is more than DEVICE_POWER_STATE_D1 and
-    /// less than restore time of getting back from DEVICE_POWER_STATE_D3HOT,
-    /// DEVICE_POWER_STATE_D3COLD. Power savings in this state are lesser
-    /// than DEVICE_POWER_STATE_D3COLD, DEVICE_POWER_STATE_D3HOT.
-    /// Device may retain some hardware context and full initialization
-    /// may not be needed when resuming from this state.
-    DEVICE_POWER_STATE_D2 = 2;
-    /// [OPTIONAL] Device is not working when in this state. It cannot process
-    /// I/O nor issue interrupts, unless it is armed for some special interrupts
-    /// that can wake up the system/device. When in this state, the restore time
-    /// of getting back to working state is more than DEVICE_POWER_STATE_D1,
-    /// DEVICE_POWER_STATE_D3HOT and less than restore time of getting back from
-    /// DEVICE_POWER_STATE_D3COLD. Power savings in this state are lesser
-    /// than DEVICE_POWER_STATE_D3COLD. Device has no context and full initialization
-    /// by the device driver when resuming from this state.
-    /// Although the device is completely off, it is still powered on and is enumerable.
-    DEVICE_POWER_STATE_D3HOT = 3;
-    /// [MANDATORY] Device is not working when in this state. It cannot process
-    /// I/O nor issue interrupts, unless it is armed for some special interrupts
-    /// that can wake up the system/device. When in this state, the restore time
-    /// of getting back to working state is more than all other low power states.
-    /// Power savings are more compared to all other low-power states.
-    /// Device has no context and full initialization by the device driver when
-    /// resuming from this state. In this state, the power to this device is turned off.
-    /// Device may be powered by other auxiliary supplies to support wake capability.
-    DEVICE_POWER_STATE_D3COLD = 4;
-};
-
-/// [MANDATORY] Default performance state when the device is in DEVICE_POWER_STATE_D0
-const DEVICE_PERFORMANCE_STATE_P0 uint32 = 0;
-
-// TODO(ravoorir): This should be table when the Controller protocol moves off of simple layout.
-type DevicePowerStateInfo = struct {
-    state_id DevicePowerState;
-
-    /// Is this state supported?
-    is_supported bool;
-
-    /// Restore time for coming out of this state to working D0 state.
-    restore_latency int64;
-
-    /// Is this device wakeup_capable?
-    wakeup_capable bool;
-
-    /// Deepest system system sleep state that the device can wake the system from.
-    system_wake_state int32;
-};
-
-/// Performance state info for a device. A performance state is relevant only
-/// when the device is in non-sleeping working device power state.
-type DevicePerformanceStateInfo = struct {
-    state_id int32;
-    /// Restore time for coming out of this state to fully working performance state.
-    restore_latency int64;
-    /// Is this state supported?
-    is_supported bool;
-    // TODO(ravoorir): Explore how more device specific metadata can be saved here.
-    // Maybe a union of metadata coming from different devices.
-};
-
-type SystemPowerStateInfo = struct {
-    // TODO(ravoorir): This can be removed when all clients move away from the suspend_flag.
-    suspend_flag uint32;
-    /// Should wakeup be enabled from this system state?
-    wakeup_enable bool;
-
-    /// Device power state that the device should be in, for this system power state.
-    dev_state DevicePowerState;
-    /// Performance state that the device should be in, for this system power state.
-    /// Only applicable, if the dev_state is a working state (DEVICE_POWER_STATE_D0).
-    performance_state uint32;
-};
-
 /// Interface for manipulating a device in a devhost
 closed protocol Controller {
     /// Connect to the underlying device's FIDL protocol.
diff --git a/sdk/fidl/fuchsia.diagnostics/BUILD.gn b/sdk/fidl/fuchsia.diagnostics/BUILD.gn
index 42990d9..02513a4 100644
--- a/sdk/fidl/fuchsia.diagnostics/BUILD.gn
+++ b/sdk/fidl/fuchsia.diagnostics/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.diagnostics") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Diagnostics"
   api = "fuchsia.diagnostics.api"
   sources = [
     "format.fidl",
diff --git a/sdk/fidl/fuchsia.gpu.agis/BUILD.gn b/sdk/fidl/fuchsia.gpu.agis/BUILD.gn
index a22d4d9..57c8a0c 100644
--- a/sdk/fidl/fuchsia.gpu.agis/BUILD.gn
+++ b/sdk/fidl/fuchsia.gpu.agis/BUILD.gn
@@ -7,7 +7,7 @@
 fidl("fuchsia.gpu.agis") {
   sources = [ "agis.fidl" ]
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Graphics"
   public_deps = [ "//zircon/vdso/zx" ]
   enable_hlcpp = true
 }
diff --git a/sdk/fidl/fuchsia.gpu.magma/BUILD.gn b/sdk/fidl/fuchsia.gpu.magma/BUILD.gn
index 4811c1b..05d809f 100644
--- a/sdk/fidl/fuchsia.gpu.magma/BUILD.gn
+++ b/sdk/fidl/fuchsia.gpu.magma/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.gpu.magma") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Graphics"
   sources = [ "magma.fidl" ]
   public_deps = [
     "//sdk/fidl/fuchsia.memorypressure",
diff --git a/sdk/fidl/fuchsia.hardware.adc/BUILD.gn b/sdk/fidl/fuchsia.hardware.adc/BUILD.gn
index 00b0574..637e00f 100644
--- a/sdk/fidl/fuchsia.hardware.adc/BUILD.gn
+++ b/sdk/fidl/fuchsia.hardware.adc/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.hardware.adc") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
   sources = [ "adc.fidl" ]
   public_deps = [ "//zircon/vdso/zx" ]
 }
diff --git a/sdk/fidl/fuchsia.hardware.audio.signalprocessing/BUILD.gn b/sdk/fidl/fuchsia.hardware.audio.signalprocessing/BUILD.gn
index 10437df..93f9f61 100644
--- a/sdk/fidl/fuchsia.hardware.audio.signalprocessing/BUILD.gn
+++ b/sdk/fidl/fuchsia.hardware.audio.signalprocessing/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.hardware.audio.signalprocessing") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "connector.fidl",
diff --git a/sdk/fidl/fuchsia.hardware.audio.signalprocessing/endpoint.fidl b/sdk/fidl/fuchsia.hardware.audio.signalprocessing/endpoint.fidl
index d36971d..0e04dca 100644
--- a/sdk/fidl/fuchsia.hardware.audio.signalprocessing/endpoint.fidl
+++ b/sdk/fidl/fuchsia.hardware.audio.signalprocessing/endpoint.fidl
@@ -15,7 +15,7 @@
     /// Required
     1: plugged bool;
 
-    /// Timestamps (using `CLOCK_DOMAIN_MONOTONIC`) the information provided in the other fields
+    /// Timestamps (using `ZX_CLOCK_MONOTONIC`) the information provided in the other fields
     /// of this table. Indicates when the transition described by this table occurred.
     ///
     /// Required.
@@ -62,8 +62,12 @@
 /// State for an `Element` with `type` equal to `ENDPOINT`.
 @available(added=12)
 type EndpointElementState = table {
-    /// The plug detect state for this endpoint.
+    /// If included the plug detect state for this endpoint.
     ///
-    /// Required.
+    /// This field should not be present in a `SetElementState` `state` since the plug state
+    /// can't be set by a client. It must be provided by the server in a `WatchElementState`
+    /// reply.
+    ///
+    /// Required for servers.
     1: plug_state PlugState;
 };
diff --git a/sdk/fidl/fuchsia.hardware.audio/BUILD.gn b/sdk/fidl/fuchsia.hardware.audio/BUILD.gn
index e306ce49..e376085 100644
--- a/sdk/fidl/fuchsia.hardware.audio/BUILD.gn
+++ b/sdk/fidl/fuchsia.hardware.audio/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.hardware.audio") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "clock.fidl",
diff --git a/sdk/fidl/fuchsia.hardware.bluetooth/BUILD.gn b/sdk/fidl/fuchsia.hardware.bluetooth/BUILD.gn
index 75daeda..2455a80 100644
--- a/sdk/fidl/fuchsia.hardware.bluetooth/BUILD.gn
+++ b/sdk/fidl/fuchsia.hardware.bluetooth/BUILD.gn
@@ -14,8 +14,8 @@
   ]
 
   public_deps = [
+    "//sdk/fidl/fuchsia.bluetooth.host",
     "//sdk/fidl/fuchsia.bluetooth.test",
-    "//src/connectivity/bluetooth/fidl:host",
     "//zircon/vdso/zx",
   ]
 
diff --git a/sdk/fidl/fuchsia.hardware.cpu.ctrl/OWNERS b/sdk/fidl/fuchsia.hardware.cpu.ctrl/OWNERS
new file mode 100644
index 0000000..79fd310
--- /dev/null
+++ b/sdk/fidl/fuchsia.hardware.cpu.ctrl/OWNERS
@@ -0,0 +1,2 @@
+include /src/devices/platform/OWNERS
+include /src/power/OWNERS
diff --git a/sdk/fidl/fuchsia.hardware.cpu.ctrl/ctrl.fidl b/sdk/fidl/fuchsia.hardware.cpu.ctrl/ctrl.fidl
index 7edc9b1..09fe81d 100644
--- a/sdk/fidl/fuchsia.hardware.cpu.ctrl/ctrl.fidl
+++ b/sdk/fidl/fuchsia.hardware.cpu.ctrl/ctrl.fidl
@@ -68,3 +68,7 @@
         id uint64;
     });
 };
+
+service Service {
+    device client_end:Device;
+};
diff --git a/sdk/fidl/fuchsia.hardware.display.engine/BUILD.gn b/sdk/fidl/fuchsia.hardware.display.engine/BUILD.gn
index 44a8980..8ebe980 100644
--- a/sdk/fidl/fuchsia.hardware.display.engine/BUILD.gn
+++ b/sdk/fidl/fuchsia.hardware.display.engine/BUILD.gn
@@ -14,6 +14,7 @@
     "//sdk/fidl/fuchsia.hardware.display.types",
     "//sdk/fidl/fuchsia.hardware.i2cimpl",
     "//sdk/fidl/fuchsia.images2",
+    "//sdk/fidl/fuchsia.sysmem",
     "//zircon/vdso/zx",
   ]
   contains_drivers = true
diff --git a/sdk/fidl/fuchsia.hardware.display.engine/engine.fidl b/sdk/fidl/fuchsia.hardware.display.engine/engine.fidl
index 905626c..1b03cef 100644
--- a/sdk/fidl/fuchsia.hardware.display.engine/engine.fidl
+++ b/sdk/fidl/fuchsia.hardware.display.engine/engine.fidl
@@ -6,6 +6,7 @@
 using fuchsia.hardware.display.types;
 using fuchsia.hardware.i2cimpl;
 using fuchsia.images2;
+using fuchsia.sysmem;
 using zx;
 
 type ColorConversion = strict bits : uint32 {
@@ -97,10 +98,7 @@
     flexible ImportBufferCollection(resource struct {
         buffer_collection_id BufferCollectionId;
 
-        // TODO(https://fxbug.dev/42171012): This is a client end channel of FIDL protocol
-        // fuchsia.sysmem.BufferCollectionToken. The raw channel needs to be
-        // replaced with FIDL client end once banjo to FIDL migration finishes.
-        collection_token zx.Handle:CHANNEL;
+        collection_token client_end:fuchsia.sysmem.BufferCollectionToken;
     }) -> () error zx.Status;
 
     /// Release an imported buffer collection.
diff --git a/sdk/fidl/fuchsia.hardware.goldfish.pipe/goldfish-pipe.fidl b/sdk/fidl/fuchsia.hardware.goldfish.pipe/goldfish-pipe.fidl
index e44e51b..d22271f 100644
--- a/sdk/fidl/fuchsia.hardware.goldfish.pipe/goldfish-pipe.fidl
+++ b/sdk/fidl/fuchsia.hardware.goldfish.pipe/goldfish-pipe.fidl
@@ -82,17 +82,6 @@
     strict GetBti() -> (resource struct {
         bti zx.Handle:BTI;
     }) error zx.Status;
-
-    /// Create a sysmem connection - used to implement fuchsia.hardware.sysmem.
-    strict ConnectSysmem(resource struct {
-        connection zx.Handle:CHANNEL;
-    }) -> () error zx.Status;
-
-    /// Register a sysmem heap.
-    strict RegisterSysmemHeap(resource struct {
-        heap uint64;
-        connection zx.Handle:CHANNEL;
-    }) -> () error zx.Status;
 };
 
 service Service {
diff --git a/sdk/fidl/fuchsia.hardware.goldfish/goldfish_control.fidl b/sdk/fidl/fuchsia.hardware.goldfish/goldfish_control.fidl
index 9b5a9e8..78dafe0 100644
--- a/sdk/fidl/fuchsia.hardware.goldfish/goldfish_control.fidl
+++ b/sdk/fidl/fuchsia.hardware.goldfish/goldfish_control.fidl
@@ -226,3 +226,7 @@
         event zx.Handle:EVENTPAIR;
     }) -> () error zx.Status;
 };
+
+service ControlService {
+    device client_end:ControlDevice;
+};
diff --git a/sdk/fidl/fuchsia.hardware.pci/BUILD.gn b/sdk/fidl/fuchsia.hardware.pci/BUILD.gn
index 23348c4..84bebe0a 100644
--- a/sdk/fidl/fuchsia.hardware.pci/BUILD.gn
+++ b/sdk/fidl/fuchsia.hardware.pci/BUILD.gn
@@ -5,7 +5,8 @@
 import("//build/fidl/fidl.gni")
 
 fidl("fuchsia.hardware.pci") {
-  sdk_category = "experimental"
+  sdk_category = "partner"
+  sdk_area = "Drivers"
   sources = [ "pci.fidl" ]
   public_deps = [ "//zircon/vdso/zx" ]
 }
diff --git a/sdk/fidl/fuchsia.hardware.pci/fuchsia.hardware.pci.api b/sdk/fidl/fuchsia.hardware.pci/fuchsia.hardware.pci.api
new file mode 100644
index 0000000..076cffa
--- /dev/null
+++ b/sdk/fidl/fuchsia.hardware.pci/fuchsia.hardware.pci.api
@@ -0,0 +1,3 @@
+{
+  "fidl/fuchsia.hardware.pci": "614b00b79e8597af837893784a0a7a7c"
+}
\ No newline at end of file
diff --git a/sdk/fidl/fuchsia.hardware.pci/pci.fidl b/sdk/fidl/fuchsia.hardware.pci/pci.fidl
index 851f872..d8dc73f 100644
--- a/sdk/fidl/fuchsia.hardware.pci/pci.fidl
+++ b/sdk/fidl/fuchsia.hardware.pci/pci.fidl
@@ -1,6 +1,7 @@
 // Copyright 2020 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+@available(added=15)
 library fuchsia.hardware.pci;
 using zx;
 
diff --git a/sdk/fidl/fuchsia.hardware.powersource/powersource.fidl b/sdk/fidl/fuchsia.hardware.powersource/powersource.fidl
index 68904c7..c2297cd 100644
--- a/sdk/fidl/fuchsia.hardware.powersource/powersource.fidl
+++ b/sdk/fidl/fuchsia.hardware.powersource/powersource.fidl
@@ -26,6 +26,18 @@
     MA = 1;
 };
 
+/// Type of data that are determined by manufacturer
+type BatterySpec = table {
+    /// Represent the battery's charging current spec in micro amps
+    1: max_charging_current_ua int32;
+
+    /// Represent the battery's charging voltage spec in micro volt
+    2: max_charnging_voltage_uv int32;
+
+    /// Battery Full Charge Design Capacity in micro amp hour
+    3: design_capacity_uah int32;
+};
+
 type BatteryInfo = struct {
     /// capacity unit. all voltage fields are in millivolts
     unit BatteryUnit;
@@ -52,6 +64,9 @@
     present_rate int32;
     remaining_capacity uint32;
     present_voltage uint32;
+
+    /// specifications set by the manufacturer.
+    battery_spec BatterySpec;
 };
 
 closed protocol Source {
diff --git a/sdk/fidl/fuchsia.hardware.serialimpl/serial-impl.fidl b/sdk/fidl/fuchsia.hardware.serialimpl/serial-impl.fidl
index dea632e..79b020f 100644
--- a/sdk/fidl/fuchsia.hardware.serialimpl/serial-impl.fidl
+++ b/sdk/fidl/fuchsia.hardware.serialimpl/serial-impl.fidl
@@ -36,7 +36,7 @@
 
 // End of `flags` that can be passed to Config.
 
-type SerialState = strict enum : uint32 {
+type SerialState = strict bits : uint32 {
     READABLE = 0x1;
     WRITABLE = 0x2;
 };
diff --git a/sdk/fidl/fuchsia.hardware.vreg/metadata.fidl b/sdk/fidl/fuchsia.hardware.vreg/metadata.fidl
index 973e3d0..efbb5e1 100644
--- a/sdk/fidl/fuchsia.hardware.vreg/metadata.fidl
+++ b/sdk/fidl/fuchsia.hardware.vreg/metadata.fidl
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 library fuchsia.hardware.vreg;
 
-type PwmVregMetadataEntry = table {
+type PwmVregMetadata = table {
     /// PWM index corresponding to the voltage regulator. Should correspond to id in pwm_id_t
     /// defined in //src/lib/ddk/include/ddk/metadata/pwm.h
     1: pwm_index uint32;
@@ -22,8 +22,3 @@
     /// steps.
     5: num_steps uint32;
 };
-
-type Metadata = table {
-    /// Vector of PWM Vreg metadata. One for each PWM voltage regulator.
-    1: pwm_vreg vector<PwmVregMetadataEntry>:MAX;
-};
diff --git a/sdk/fidl/fuchsia.images/BUILD.gn b/sdk/fidl/fuchsia.images/BUILD.gn
index 1f951a7..4237957 100644
--- a/sdk/fidl/fuchsia.images/BUILD.gn
+++ b/sdk/fidl/fuchsia.images/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.images") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "encoded_image.fidl",
diff --git a/sdk/fidl/fuchsia.input.report/BUILD.gn b/sdk/fidl/fuchsia.input.report/BUILD.gn
index 5d38aee..0dfa9f3 100644
--- a/sdk/fidl/fuchsia.input.report/BUILD.gn
+++ b/sdk/fidl/fuchsia.input.report/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.input.report") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "consumer_control.fidl",
diff --git a/sdk/fidl/fuchsia.input.virtualkeyboard/BUILD.gn b/sdk/fidl/fuchsia.input.virtualkeyboard/BUILD.gn
index ceb3c416..e70d108 100644
--- a/sdk/fidl/fuchsia.input.virtualkeyboard/BUILD.gn
+++ b/sdk/fidl/fuchsia.input.virtualkeyboard/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.input.virtualkeyboard") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [ "virtual_keyboard.fidl" ]
 
diff --git a/sdk/fidl/fuchsia.input/BUILD.gn b/sdk/fidl/fuchsia.input/BUILD.gn
index 5d9d364..2623306 100644
--- a/sdk/fidl/fuchsia.input/BUILD.gn
+++ b/sdk/fidl/fuchsia.input/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.input") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "keymap.fidl",
diff --git a/sdk/fidl/fuchsia.inspect/BUILD.gn b/sdk/fidl/fuchsia.inspect/BUILD.gn
index e87079d..e3a393e 100644
--- a/sdk/fidl/fuchsia.inspect/BUILD.gn
+++ b/sdk/fidl/fuchsia.inspect/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.inspect") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Diagnostics"
   api = "fuchsia.inspect.api"
   sources = [
     "inspect_sink.fidl",
diff --git a/sdk/fidl/fuchsia.io.test/io.test.fidl b/sdk/fidl/fuchsia.io.test/io.test.fidl
index 7d6ec81..d2cb472 100644
--- a/sdk/fidl/fuchsia.io.test/io.test.fidl
+++ b/sdk/fidl/fuchsia.io.test/io.test.fidl
@@ -42,8 +42,8 @@
     /// ExecutableFile objects are supported.
     3: supports_executable_file bool;
 
-    /// VmoFile objects are supported. Must support fuchsia.io/File.GetBackingMemory.
-    4: supports_vmo_file bool;
+    /// GetBackingMemory is supported.
+    4: supports_get_backing_memory bool;
 
     /// Remote directories are supported.
     5: supports_remote_dir bool;
@@ -111,18 +111,6 @@
     2: contents vector<uint8>:MAX;
 };
 
-/// Vmo-backed file object which supports opening as readable + writable.
-///
-/// Enabled via the `supports_vmo_file` configuration option. `VmoFile` objects should support
-/// fuchsia.io/File.GetBackingMemory.
-///
-/// As the conformance tests verify W^X enforcement, attempting to open a VmoFile as executable
-/// should fail with ACCESS_DENIED. If executable files are required, use ExecutableFile.
-type VmoFile = resource table {
-    1: name string;
-    2: vmo zx.Handle:VMO;
-};
-
 /// Adds an executable file that supports opening as readable + executable. The file has a non-zero
 /// size, but the contents are otherwise unspecified.
 ///
@@ -130,7 +118,7 @@
 /// support fuchsia.io/File.GetBackingMemory.
 ///
 /// As the conformance tests verify W^X enforcement, opening an ExecutableFile with RIGHT_WRITABLE
-/// should fail with ACCESS_DENIED. If writable files are required, use File/VmoFile instead.
+/// should fail with ACCESS_DENIED. If writable files are required, use File instead.
 type ExecutableFile = table {
     1: name string;
 };
@@ -139,7 +127,6 @@
     1: directory Directory;
     2: remote_directory RemoteDirectory;
     3: file File;
-    4: vmo_file VmoFile;
     5: executable_file ExecutableFile;
 };
 
diff --git a/sdk/fidl/fuchsia.logger/BUILD.gn b/sdk/fidl/fuchsia.logger/BUILD.gn
index 9478c5e..5789c9e 100644
--- a/sdk/fidl/fuchsia.logger/BUILD.gn
+++ b/sdk/fidl/fuchsia.logger/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.logger") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Diagnostics"
   api = "fuchsia.logger.api"
   sources = [ "logger.fidl" ]
   public_deps = [
diff --git a/sdk/fidl/fuchsia.media.audio/BUILD.gn b/sdk/fidl/fuchsia.media.audio/BUILD.gn
index 36f8e8a..3cf368c 100644
--- a/sdk/fidl/fuchsia.media.audio/BUILD.gn
+++ b/sdk/fidl/fuchsia.media.audio/BUILD.gn
@@ -9,7 +9,7 @@
   excluded_checks = [ "invalid-case-for-decl-member" ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "effects_controller.fidl",
diff --git a/sdk/fidl/fuchsia.media.drm/BUILD.gn b/sdk/fidl/fuchsia.media.drm/BUILD.gn
index 78cca65..f5a2ce9 100644
--- a/sdk/fidl/fuchsia.media.drm/BUILD.gn
+++ b/sdk/fidl/fuchsia.media.drm/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.media.drm") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "content_decryption.fidl",
diff --git a/sdk/fidl/fuchsia.media.playback/BUILD.gn b/sdk/fidl/fuchsia.media.playback/BUILD.gn
index d41c9db..21dbd4c 100644
--- a/sdk/fidl/fuchsia.media.playback/BUILD.gn
+++ b/sdk/fidl/fuchsia.media.playback/BUILD.gn
@@ -9,7 +9,7 @@
   excluded_checks = [ "string-bounds-not-specified" ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "overview.fidl",
diff --git a/sdk/fidl/fuchsia.media.sessions2/BUILD.gn b/sdk/fidl/fuchsia.media.sessions2/BUILD.gn
index 611194d..93b7fc3 100644
--- a/sdk/fidl/fuchsia.media.sessions2/BUILD.gn
+++ b/sdk/fidl/fuchsia.media.sessions2/BUILD.gn
@@ -9,7 +9,7 @@
   excluded_checks = [ "vector-bounds-not-specified" ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "discovery.fidl",
diff --git a/sdk/fidl/fuchsia.media.sounds/BUILD.gn b/sdk/fidl/fuchsia.media.sounds/BUILD.gn
index fab6f64..a44ff3e 100644
--- a/sdk/fidl/fuchsia.media.sounds/BUILD.gn
+++ b/sdk/fidl/fuchsia.media.sounds/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.media.sounds") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [ "sound_player.fidl" ]
 
diff --git a/sdk/fidl/fuchsia.media.target/BUILD.gn b/sdk/fidl/fuchsia.media.target/BUILD.gn
index f1d2a93..a8afd11 100644
--- a/sdk/fidl/fuchsia.media.target/BUILD.gn
+++ b/sdk/fidl/fuchsia.media.target/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.media.target") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [ "target_discovery.fidl" ]
 
diff --git a/sdk/fidl/fuchsia.media/BUILD.gn b/sdk/fidl/fuchsia.media/BUILD.gn
index 8726f78..08e0ca1 100644
--- a/sdk/fidl/fuchsia.media/BUILD.gn
+++ b/sdk/fidl/fuchsia.media/BUILD.gn
@@ -14,7 +14,7 @@
   ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [
     "activity_reporter.fidl",
diff --git a/sdk/fidl/fuchsia.mediacodec/BUILD.gn b/sdk/fidl/fuchsia.mediacodec/BUILD.gn
index ea28a49..896214a 100644
--- a/sdk/fidl/fuchsia.mediacodec/BUILD.gn
+++ b/sdk/fidl/fuchsia.mediacodec/BUILD.gn
@@ -9,7 +9,7 @@
   excluded_checks = [ "invalid-case-for-decl-name" ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   sources = [ "codec_factory.fidl" ]
 
diff --git a/sdk/fidl/fuchsia.mediastreams/BUILD.gn b/sdk/fidl/fuchsia.mediastreams/BUILD.gn
index fdb3575..d29e379 100644
--- a/sdk/fidl/fuchsia.mediastreams/BUILD.gn
+++ b/sdk/fidl/fuchsia.mediastreams/BUILD.gn
@@ -15,7 +15,7 @@
   ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Media"
 
   public_deps = [ "//sdk/fidl/fuchsia.math" ]
 
diff --git a/sdk/fidl/fuchsia.memory.attribution/BUILD.gn b/sdk/fidl/fuchsia.memory.attribution/BUILD.gn
index 1eb18e2..1a192f9 100644
--- a/sdk/fidl/fuchsia.memory.attribution/BUILD.gn
+++ b/sdk/fidl/fuchsia.memory.attribution/BUILD.gn
@@ -7,6 +7,7 @@
 fidl("fuchsia.memory.attribution") {
   sdk_category = "internal"
   sources = [ "attribution.fidl" ]
+  sdk_area = "Diagnostics"
 
   public_deps = [ "//zircon/vdso/zx" ]
 
diff --git a/sdk/fidl/fuchsia.memory.debug/BUILD.gn b/sdk/fidl/fuchsia.memory.debug/BUILD.gn
index 781df16..faca139 100644
--- a/sdk/fidl/fuchsia.memory.debug/BUILD.gn
+++ b/sdk/fidl/fuchsia.memory.debug/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.memory.debug") {
   sdk_category = "partner_internal"
-  sdk_area = "Unknown"
+  sdk_area = "Diagnostics"
   sources = [ "debug.fidl" ]
   public_deps = [ "//sdk/fidl/fuchsia.memorypressure" ]
   enable_hlcpp = true
diff --git a/sdk/fidl/fuchsia.memory.heapdump.client/BUILD.gn b/sdk/fidl/fuchsia.memory.heapdump.client/BUILD.gn
index 5213eba..10e6123 100644
--- a/sdk/fidl/fuchsia.memory.heapdump.client/BUILD.gn
+++ b/sdk/fidl/fuchsia.memory.heapdump.client/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.memory.heapdump.client") {
   sdk_category = "partner_internal"
-  sdk_area = "Unknown"
+  sdk_area = "Diagnostics"
   sources = [ "client.fidl" ]
   public_deps = [ "//zircon/vdso/zx" ]
 }
diff --git a/sdk/fidl/fuchsia.memory.heapdump.process/BUILD.gn b/sdk/fidl/fuchsia.memory.heapdump.process/BUILD.gn
index 6b432fd..59bf5f3 100644
--- a/sdk/fidl/fuchsia.memory.heapdump.process/BUILD.gn
+++ b/sdk/fidl/fuchsia.memory.heapdump.process/BUILD.gn
@@ -6,6 +6,7 @@
 
 fidl("fuchsia.memory.heapdump.process") {
   sdk_category = "internal"
+  sdk_area = "Diagnostics"
   sources = [ "process.fidl" ]
   public_deps = [ "//zircon/vdso/zx" ]
 }
diff --git a/sdk/fidl/fuchsia.memory.inspection/BUILD.gn b/sdk/fidl/fuchsia.memory.inspection/BUILD.gn
index 6a0a7a2..2f13635 100644
--- a/sdk/fidl/fuchsia.memory.inspection/BUILD.gn
+++ b/sdk/fidl/fuchsia.memory.inspection/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.memory.inspection") {
   sdk_category = "partner_internal"
-  sdk_area = "Unknown"
+  sdk_area = "Diagnostics"
   sources = [ "inspection.fidl" ]
   public_deps = [ "//zircon/vdso/zx" ]
   enable_hlcpp = true
diff --git a/sdk/fidl/fuchsia.memory.report/BUILD.gn b/sdk/fidl/fuchsia.memory.report/BUILD.gn
index a99ac24..c650ea2 100644
--- a/sdk/fidl/fuchsia.memory.report/BUILD.gn
+++ b/sdk/fidl/fuchsia.memory.report/BUILD.gn
@@ -7,6 +7,7 @@
 fidl("fuchsia.memory.report") {
   sdk_category = "internal"
   sources = [ "report.fidl" ]
+  sdk_area = "Diagnostics"
 
   public_deps = [
     "//sdk/fidl/fuchsia.mem",
diff --git a/sdk/fidl/fuchsia.memory.sampler/BUILD.gn b/sdk/fidl/fuchsia.memory.sampler/BUILD.gn
index 0e40091..e67b186e 100644
--- a/sdk/fidl/fuchsia.memory.sampler/BUILD.gn
+++ b/sdk/fidl/fuchsia.memory.sampler/BUILD.gn
@@ -7,5 +7,6 @@
 fidl("fuchsia.memory.sampler") {
   sdk_category = "internal"
   sources = [ "sampler.fidl" ]
+  sdk_area = "Diagnostics"
   public_deps = [ "//zircon/vdso/zx" ]
 }
diff --git a/sdk/fidl/fuchsia.power.battery.test/simulator.fidl b/sdk/fidl/fuchsia.power.battery.test/simulator.fidl
index 4decc89..0a056a8 100644
--- a/sdk/fidl/fuchsia.power.battery.test/simulator.fidl
+++ b/sdk/fidl/fuchsia.power.battery.test/simulator.fidl
@@ -75,6 +75,11 @@
     strict SetRemainingCapacityUah(struct {
         capacity uint32;
     });
+
+    /// Sets the BatterySpec
+    strict SetBatterySpec(struct {
+        spec fuchsia.power.battery.BatterySpec;
+    });
 };
 
 /// Simulator interface for battery simulation
diff --git a/sdk/fidl/fuchsia.power.battery/battery.fidl b/sdk/fidl/fuchsia.power.battery/battery.fidl
index 5429311..4b7c074 100644
--- a/sdk/fidl/fuchsia.power.battery/battery.fidl
+++ b/sdk/fidl/fuchsia.power.battery/battery.fidl
@@ -68,6 +68,18 @@
     3: full_charge zx.Duration;
 };
 
+/// Type of data that are determined by manufacturer
+type BatterySpec = table {
+    /// Represent the battery's charging current spec in micro amps
+    1: max_charging_current_ua int32;
+
+    /// Represent the battery's charging voltage spec in micro volt
+    2: max_charnging_voltage_uv int32;
+
+    /// Battery Full Charge Design Capacity in micro amp hour
+    3: design_capacity_uah int32;
+};
+
 /// Current battery state information
 type BatteryInfo = table {
     /// General battery status with respect to presence & availability
@@ -102,6 +114,9 @@
 
     /// Forward the battery capqacity in uAh
     10: remaining_capacity_uah uint32;
+
+    /// Battery spec
+    11: battery_spec BatterySpec;
 };
 
 /// Provider interface used to obtain battery status details
diff --git a/sdk/fidl/fuchsia.power.broker/BUILD.gn b/sdk/fidl/fuchsia.power.broker/BUILD.gn
index f61eca6..d494446 100644
--- a/sdk/fidl/fuchsia.power.broker/BUILD.gn
+++ b/sdk/fidl/fuchsia.power.broker/BUILD.gn
@@ -22,6 +22,7 @@
     "//src/power/system-activity-governor/*:*",
     "//src/power/testing/fake-broker/*:*",
     "//src/session/bin/*",
+    "//src/session/tests/session_manager:*",
     "//src/starnix/kernel/*:*",
     "//src/sys/time/timekeeper/*:*",
     "//vendor/*",
diff --git a/sdk/fidl/fuchsia.ui.activity.control/BUILD.gn b/sdk/fidl/fuchsia.ui.activity.control/BUILD.gn
index 7131b85..225986c 100644
--- a/sdk/fidl/fuchsia.ui.activity.control/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.activity.control/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.ui.activity.control") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [ "control.fidl" ]
 
diff --git a/sdk/fidl/fuchsia.ui.activity/BUILD.gn b/sdk/fidl/fuchsia.ui.activity/BUILD.gn
index cfece82..a49bada 100644
--- a/sdk/fidl/fuchsia.ui.activity/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.activity/BUILD.gn
@@ -9,7 +9,7 @@
   excluded_checks = [ "string-bounds-not-specified" ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "activity.fidl",
diff --git a/sdk/fidl/fuchsia.ui.brightness/BUILD.gn b/sdk/fidl/fuchsia.ui.brightness/BUILD.gn
index d703891..54efbb5e 100644
--- a/sdk/fidl/fuchsia.ui.brightness/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.brightness/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.ui.brightness") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
   sources = [
     "brightness.fidl",
     "color_adjustment.fidl",
diff --git a/sdk/fidl/fuchsia.ui.gfx/BUILD.gn b/sdk/fidl/fuchsia.ui.gfx/BUILD.gn
index 2ef4e57..daccaf0 100644
--- a/sdk/fidl/fuchsia.ui.gfx/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.gfx/BUILD.gn
@@ -14,7 +14,7 @@
   ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "Graphics"
 
   sources = [
     "commands.fidl",
diff --git a/sdk/fidl/fuchsia.ui.input/BUILD.gn b/sdk/fidl/fuchsia.ui.input/BUILD.gn
index f64ab73..4eb96e2 100644
--- a/sdk/fidl/fuchsia.ui.input/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.input/BUILD.gn
@@ -14,7 +14,7 @@
   ]
 
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "commands.fidl",
diff --git a/sdk/fidl/fuchsia.ui.input3/BUILD.gn b/sdk/fidl/fuchsia.ui.input3/BUILD.gn
index f14cba72..16469dc 100644
--- a/sdk/fidl/fuchsia.ui.input3/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.input3/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.ui.input3") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "events.fidl",
diff --git a/sdk/fidl/fuchsia.ui.pointer/BUILD.gn b/sdk/fidl/fuchsia.ui.pointer/BUILD.gn
index 7eb16d46..e618194 100644
--- a/sdk/fidl/fuchsia.ui.pointer/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.pointer/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.ui.pointer") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "mouse.fidl",
diff --git a/sdk/fidl/fuchsia.ui.pointerinjector/BUILD.gn b/sdk/fidl/fuchsia.ui.pointerinjector/BUILD.gn
index a46252d..5b54a8f 100644
--- a/sdk/fidl/fuchsia.ui.pointerinjector/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.pointerinjector/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.ui.pointerinjector") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "config.fidl",
diff --git a/sdk/fidl/fuchsia.ui.test.input/BUILD.gn b/sdk/fidl/fuchsia.ui.test.input/BUILD.gn
index f58b483..6a49bd6 100644
--- a/sdk/fidl/fuchsia.ui.test.input/BUILD.gn
+++ b/sdk/fidl/fuchsia.ui.test.input/BUILD.gn
@@ -6,7 +6,7 @@
 
 fidl("fuchsia.ui.test.input") {
   sdk_category = "partner"
-  sdk_area = "Unknown"
+  sdk_area = "HCI"
 
   sources = [
     "media_buttons.fidl",
diff --git a/sdk/history/15/fuchsia.hardware.pci.api_summary.json b/sdk/history/15/fuchsia.hardware.pci.api_summary.json
new file mode 100644
index 0000000..e8354f9
--- /dev/null
+++ b/sdk/history/15/fuchsia.hardware.pci.api_summary.json
@@ -0,0 +1,1544 @@
+[
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.bus",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.device",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.function",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_ADDRESS_COUNT",
+        "type": "uint32",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.result",
+        "ordinal": "3",
+        "type": "fuchsia.hardware.pci/BarResult"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.io",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/IoBar"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.vmo",
+        "ordinal": "2",
+        "type": "zx/Handle:VMO"
+    },
+    {
+        "kind": "union",
+        "name": "fuchsia.hardware.pci/BarResult",
+        "strictness": "flexible",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_64bit",
+        "ordinal": "5",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_memory",
+        "ordinal": "3",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_prefetchable",
+        "ordinal": "4",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BaseAddress"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetDevices",
+        "strictness": "strict",
+        "ordinal": "3114700014429961362",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetHostBridgeInfo",
+        "strictness": "strict",
+        "ordinal": "4175032687054816861",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.ReadBar",
+        "strictness": "strict",
+        "ordinal": "8759283232091687008",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/BusReadBarRequest",
+        "response": "fuchsia.hardware.pci/Bus_ReadBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Bus",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse.devices",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/PciDevice>:64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.bar_id",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.device",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.offset",
+        "ordinal": "3",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.size",
+        "ordinal": "4",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response.buffer",
+        "ordinal": "1",
+        "type": "vector<uint8>"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.id",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.offset",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Capability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ADVANCED_FEATURES",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP8X",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_CRC",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_HOTSWAP",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.DEBUG_PORT",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.FLATTENING_PORTAL_BRIDGE",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.HYPERTRANSPORT",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSI",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSIX",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCIX",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_BRIDGE_SUBSYSTEM_VID",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_EXPRESS",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_HOT_PLUG",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_PWR_MGMT",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SATA_DATA_NDX_CFG",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SECURE_DEVICE",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SLOT_IDENTIFICATION",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VENDOR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VITAL_PRODUCT_DATA",
+        "value": "3"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/CapabilityId",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.AD_STEP_EN",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.BUS_MASTER_EN",
+        "value": "4"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.FAST_B2B_EN",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.IO_EN",
+        "value": "1"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_EN",
+        "value": "2"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_WR_INV_EN",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PAL_SNOOP_EN",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PERR_RESP_EN",
+        "value": "64"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SERR_EN",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SPECIAL_EN",
+        "value": "8"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Command",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BASE_ADDRESSES",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BIST",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CACHE_LINE_SIZE",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CAPABILITIES_PTR",
+        "value": "52"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CARDBUS_CIS_PTR",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_BASE",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_INTR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_SUB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.COMMAND",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.DEVICE_ID",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.EXP_ROM_ADDRESS",
+        "value": "48"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.HEADER_TYPE",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_LINE",
+        "value": "60"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_PIN",
+        "value": "61"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.LATENCY_TIMER",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MAX_LATENCY",
+        "value": "63"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MIN_GRANT",
+        "value": "62"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.REVISION_ID",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.STATUS",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_ID",
+        "value": "46"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_VENDOR_ID",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.VENDOR_ID",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/Config",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.AckInterrupt",
+        "strictness": "strict",
+        "ordinal": "8103153737854179947",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_AckInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBar",
+        "strictness": "strict",
+        "ordinal": "7721003707982149241",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBarRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBti",
+        "strictness": "strict",
+        "ordinal": "6795907578404380387",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBtiRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetCapabilities",
+        "strictness": "strict",
+        "ordinal": "4180765276430907919",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetDeviceInfo",
+        "strictness": "strict",
+        "ordinal": "6168191258208672022",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetExtendedCapabilities",
+        "strictness": "strict",
+        "ordinal": "830197180054506553",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetInterruptModes",
+        "strictness": "strict",
+        "ordinal": "666335764625137482",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.MapInterrupt",
+        "strictness": "strict",
+        "ordinal": "2733403074518448659",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceMapInterruptRequest",
+        "response": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig16",
+        "strictness": "strict",
+        "ordinal": "4309283036617404603",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig32",
+        "strictness": "strict",
+        "ordinal": "6139942538560107783",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig8",
+        "strictness": "strict",
+        "ordinal": "2952650096395541020",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ResetDevice",
+        "strictness": "strict",
+        "ordinal": "4349199030852488095",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_ResetDevice_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetBusMastering",
+        "strictness": "strict",
+        "ordinal": "3756540713293123587",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest",
+        "response": "fuchsia.hardware.pci/Device_SetBusMastering_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetInterruptMode",
+        "strictness": "strict",
+        "ordinal": "602334104497834086",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest",
+        "response": "fuchsia.hardware.pci/Device_SetInterruptMode_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig16",
+        "strictness": "strict",
+        "ordinal": "4481291721614851839",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig32",
+        "strictness": "strict",
+        "ordinal": "99457760178582408",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig8",
+        "strictness": "strict",
+        "ordinal": "331585330300009727",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Device",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest.index",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/CapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint8>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/ExtendedCapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint16>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse.modes",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.base_class",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.bus_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.dev_id",
+        "ordinal": "8",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.device_id",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.func_id",
+        "ordinal": "9",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.padding",
+        "ordinal": "10",
+        "type": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.program_interface",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.revision_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.sub_class",
+        "ordinal": "4",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.vendor_id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest.which_irq",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest.enabled",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.mode",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptMode"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.requested_irq_count",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.value",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.value",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.value",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response.result",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Bar"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response.bti",
+        "ordinal": "1",
+        "type": "zx/Handle:BTI"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response.interrupt",
+        "ordinal": "1",
+        "type": "zx/Handle:INTERRUPT"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response.value",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response.value",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response.value",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/EXTENDED_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "4096"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.offset",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/ExtendedCapability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ACS",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ADVANCED_ERROR_REPORTING",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ALTERNATE_PROTOCOL",
+        "value": "43"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ARI",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ATS",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.CAC",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DATA_LINK_FEATURE",
+        "value": "37"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DESIGNATED_VENDOR",
+        "value": "35"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DEVICE_SERIAL_NUMBER",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DPC",
+        "value": "29"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DYNAMIC_POWER_ALLOCATION",
+        "value": "22"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.FRS_QUEUEING",
+        "value": "33"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.HIERARCHY_ID",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.L1PM_SUBSTATES",
+        "value": "30"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LANE_MARGINING_AT_RECEIVER",
+        "value": "39"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LATENCY_TOLERANCE_REPORTING",
+        "value": "24"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LNR",
+        "value": "28"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MPCIE",
+        "value": "32"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MR_IOV",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTICAST",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTI_FUNCTION_VIRTUAL_CHANNEL",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NATIVE_PCIE_ENCLOSURE",
+        "value": "41"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PASID",
+        "value": "27"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_16",
+        "value": "38"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_32",
+        "value": "42"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PMUX",
+        "value": "26"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.POWER_BUDGETING",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRECISION_TIME_MEASUREMENT",
+        "value": "31"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRI",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RCRB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.READINESS_TIME_REPORTING",
+        "value": "34"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RESIZABLE_BAR",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_INTERNAL_LINK_CONTROL",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_LINK_DECLARATION",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SECONDARY_PCI_EXPRESS",
+        "value": "25"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SR_IOV",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SYSTEM_FIRMWARE_INTERMEDIARY",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.TPH",
+        "value": "23"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VENDOR",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VF_RESIZABLE_BAR",
+        "value": "36"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL_NO_MFVC",
+        "value": "2"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.BRIDGE",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.CARD_BUS",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MASK",
+        "value": "127"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MULTI_FN",
+        "value": "128"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.STANDARD",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/HeaderType",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.end_bus_number",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.name",
+        "ordinal": "1",
+        "type": "string:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.segment_group",
+        "ordinal": "4",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.start_bus_number",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.DISABLED",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY_NOACK",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI_X",
+        "value": "4"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/InterruptMode",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.has_legacy",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msi_count",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msix_count",
+        "ordinal": "3",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.resource",
+        "ordinal": "2",
+        "type": "zx/Handle:RESOURCE"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/IoBar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_BAR_COUNT",
+        "type": "uint8",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_DEVICES",
+        "type": "uint32",
+        "value": "64"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_EXT_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_NAME_LEN",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.base_addresses",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/BaseAddress>:6"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.bus_id",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.capabilities",
+        "ordinal": "2",
+        "type": "vector<fuchsia.hardware.pci/Capability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.config",
+        "ordinal": "4",
+        "type": "vector<uint8>:256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.device_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.ext_capabilities",
+        "ordinal": "3",
+        "type": "vector<fuchsia.hardware.pci/ExtendedCapability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.function_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/PciDevice"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/READBAR_MAX_SIZE",
+        "type": "uint32",
+        "value": "1024"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/STATUS_DEVSEL_MASK",
+        "type": "fuchsia.hardware.pci/Status",
+        "value": "1536"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_HIGH",
+        "value": "1024"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_LOW",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.FAST_B2B",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.INTERRUPT",
+        "value": "8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_ABORT_RCV",
+        "value": "8192"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_PERR",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.NEW_CAPS",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.PERR",
+        "value": "32768"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SERR_SIG",
+        "value": "16384"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SIXTYSIX_MHZ",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_RCV",
+        "value": "4096"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_SIG",
+        "value": "2048"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Status",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "library",
+        "name": "fuchsia.hardware.pci"
+    }
+]
diff --git a/sdk/history/16/fuchsia.hardware.pci.api_summary.json b/sdk/history/16/fuchsia.hardware.pci.api_summary.json
new file mode 100644
index 0000000..e8354f9
--- /dev/null
+++ b/sdk/history/16/fuchsia.hardware.pci.api_summary.json
@@ -0,0 +1,1544 @@
+[
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.bus",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.device",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.function",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_ADDRESS_COUNT",
+        "type": "uint32",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.result",
+        "ordinal": "3",
+        "type": "fuchsia.hardware.pci/BarResult"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.io",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/IoBar"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.vmo",
+        "ordinal": "2",
+        "type": "zx/Handle:VMO"
+    },
+    {
+        "kind": "union",
+        "name": "fuchsia.hardware.pci/BarResult",
+        "strictness": "flexible",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_64bit",
+        "ordinal": "5",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_memory",
+        "ordinal": "3",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_prefetchable",
+        "ordinal": "4",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BaseAddress"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetDevices",
+        "strictness": "strict",
+        "ordinal": "3114700014429961362",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetHostBridgeInfo",
+        "strictness": "strict",
+        "ordinal": "4175032687054816861",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.ReadBar",
+        "strictness": "strict",
+        "ordinal": "8759283232091687008",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/BusReadBarRequest",
+        "response": "fuchsia.hardware.pci/Bus_ReadBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Bus",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse.devices",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/PciDevice>:64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.bar_id",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.device",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.offset",
+        "ordinal": "3",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.size",
+        "ordinal": "4",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response.buffer",
+        "ordinal": "1",
+        "type": "vector<uint8>"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.id",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.offset",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Capability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ADVANCED_FEATURES",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP8X",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_CRC",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_HOTSWAP",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.DEBUG_PORT",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.FLATTENING_PORTAL_BRIDGE",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.HYPERTRANSPORT",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSI",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSIX",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCIX",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_BRIDGE_SUBSYSTEM_VID",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_EXPRESS",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_HOT_PLUG",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_PWR_MGMT",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SATA_DATA_NDX_CFG",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SECURE_DEVICE",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SLOT_IDENTIFICATION",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VENDOR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VITAL_PRODUCT_DATA",
+        "value": "3"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/CapabilityId",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.AD_STEP_EN",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.BUS_MASTER_EN",
+        "value": "4"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.FAST_B2B_EN",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.IO_EN",
+        "value": "1"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_EN",
+        "value": "2"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_WR_INV_EN",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PAL_SNOOP_EN",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PERR_RESP_EN",
+        "value": "64"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SERR_EN",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SPECIAL_EN",
+        "value": "8"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Command",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BASE_ADDRESSES",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BIST",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CACHE_LINE_SIZE",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CAPABILITIES_PTR",
+        "value": "52"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CARDBUS_CIS_PTR",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_BASE",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_INTR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_SUB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.COMMAND",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.DEVICE_ID",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.EXP_ROM_ADDRESS",
+        "value": "48"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.HEADER_TYPE",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_LINE",
+        "value": "60"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_PIN",
+        "value": "61"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.LATENCY_TIMER",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MAX_LATENCY",
+        "value": "63"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MIN_GRANT",
+        "value": "62"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.REVISION_ID",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.STATUS",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_ID",
+        "value": "46"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_VENDOR_ID",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.VENDOR_ID",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/Config",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.AckInterrupt",
+        "strictness": "strict",
+        "ordinal": "8103153737854179947",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_AckInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBar",
+        "strictness": "strict",
+        "ordinal": "7721003707982149241",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBarRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBti",
+        "strictness": "strict",
+        "ordinal": "6795907578404380387",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBtiRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetCapabilities",
+        "strictness": "strict",
+        "ordinal": "4180765276430907919",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetDeviceInfo",
+        "strictness": "strict",
+        "ordinal": "6168191258208672022",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetExtendedCapabilities",
+        "strictness": "strict",
+        "ordinal": "830197180054506553",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetInterruptModes",
+        "strictness": "strict",
+        "ordinal": "666335764625137482",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.MapInterrupt",
+        "strictness": "strict",
+        "ordinal": "2733403074518448659",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceMapInterruptRequest",
+        "response": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig16",
+        "strictness": "strict",
+        "ordinal": "4309283036617404603",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig32",
+        "strictness": "strict",
+        "ordinal": "6139942538560107783",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig8",
+        "strictness": "strict",
+        "ordinal": "2952650096395541020",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ResetDevice",
+        "strictness": "strict",
+        "ordinal": "4349199030852488095",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_ResetDevice_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetBusMastering",
+        "strictness": "strict",
+        "ordinal": "3756540713293123587",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest",
+        "response": "fuchsia.hardware.pci/Device_SetBusMastering_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetInterruptMode",
+        "strictness": "strict",
+        "ordinal": "602334104497834086",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest",
+        "response": "fuchsia.hardware.pci/Device_SetInterruptMode_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig16",
+        "strictness": "strict",
+        "ordinal": "4481291721614851839",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig32",
+        "strictness": "strict",
+        "ordinal": "99457760178582408",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig8",
+        "strictness": "strict",
+        "ordinal": "331585330300009727",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Device",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest.index",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/CapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint8>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/ExtendedCapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint16>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse.modes",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.base_class",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.bus_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.dev_id",
+        "ordinal": "8",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.device_id",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.func_id",
+        "ordinal": "9",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.padding",
+        "ordinal": "10",
+        "type": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.program_interface",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.revision_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.sub_class",
+        "ordinal": "4",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.vendor_id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest.which_irq",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest.enabled",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.mode",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptMode"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.requested_irq_count",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.value",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.value",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.value",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response.result",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Bar"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response.bti",
+        "ordinal": "1",
+        "type": "zx/Handle:BTI"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response.interrupt",
+        "ordinal": "1",
+        "type": "zx/Handle:INTERRUPT"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response.value",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response.value",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response.value",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/EXTENDED_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "4096"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.offset",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/ExtendedCapability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ACS",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ADVANCED_ERROR_REPORTING",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ALTERNATE_PROTOCOL",
+        "value": "43"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ARI",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ATS",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.CAC",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DATA_LINK_FEATURE",
+        "value": "37"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DESIGNATED_VENDOR",
+        "value": "35"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DEVICE_SERIAL_NUMBER",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DPC",
+        "value": "29"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DYNAMIC_POWER_ALLOCATION",
+        "value": "22"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.FRS_QUEUEING",
+        "value": "33"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.HIERARCHY_ID",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.L1PM_SUBSTATES",
+        "value": "30"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LANE_MARGINING_AT_RECEIVER",
+        "value": "39"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LATENCY_TOLERANCE_REPORTING",
+        "value": "24"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LNR",
+        "value": "28"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MPCIE",
+        "value": "32"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MR_IOV",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTICAST",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTI_FUNCTION_VIRTUAL_CHANNEL",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NATIVE_PCIE_ENCLOSURE",
+        "value": "41"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PASID",
+        "value": "27"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_16",
+        "value": "38"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_32",
+        "value": "42"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PMUX",
+        "value": "26"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.POWER_BUDGETING",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRECISION_TIME_MEASUREMENT",
+        "value": "31"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRI",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RCRB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.READINESS_TIME_REPORTING",
+        "value": "34"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RESIZABLE_BAR",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_INTERNAL_LINK_CONTROL",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_LINK_DECLARATION",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SECONDARY_PCI_EXPRESS",
+        "value": "25"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SR_IOV",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SYSTEM_FIRMWARE_INTERMEDIARY",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.TPH",
+        "value": "23"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VENDOR",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VF_RESIZABLE_BAR",
+        "value": "36"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL_NO_MFVC",
+        "value": "2"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.BRIDGE",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.CARD_BUS",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MASK",
+        "value": "127"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MULTI_FN",
+        "value": "128"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.STANDARD",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/HeaderType",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.end_bus_number",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.name",
+        "ordinal": "1",
+        "type": "string:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.segment_group",
+        "ordinal": "4",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.start_bus_number",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.DISABLED",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY_NOACK",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI_X",
+        "value": "4"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/InterruptMode",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.has_legacy",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msi_count",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msix_count",
+        "ordinal": "3",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.resource",
+        "ordinal": "2",
+        "type": "zx/Handle:RESOURCE"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/IoBar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_BAR_COUNT",
+        "type": "uint8",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_DEVICES",
+        "type": "uint32",
+        "value": "64"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_EXT_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_NAME_LEN",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.base_addresses",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/BaseAddress>:6"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.bus_id",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.capabilities",
+        "ordinal": "2",
+        "type": "vector<fuchsia.hardware.pci/Capability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.config",
+        "ordinal": "4",
+        "type": "vector<uint8>:256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.device_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.ext_capabilities",
+        "ordinal": "3",
+        "type": "vector<fuchsia.hardware.pci/ExtendedCapability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.function_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/PciDevice"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/READBAR_MAX_SIZE",
+        "type": "uint32",
+        "value": "1024"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/STATUS_DEVSEL_MASK",
+        "type": "fuchsia.hardware.pci/Status",
+        "value": "1536"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_HIGH",
+        "value": "1024"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_LOW",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.FAST_B2B",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.INTERRUPT",
+        "value": "8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_ABORT_RCV",
+        "value": "8192"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_PERR",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.NEW_CAPS",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.PERR",
+        "value": "32768"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SERR_SIG",
+        "value": "16384"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SIXTYSIX_MHZ",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_RCV",
+        "value": "4096"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_SIG",
+        "value": "2048"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Status",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "library",
+        "name": "fuchsia.hardware.pci"
+    }
+]
diff --git a/sdk/history/17/fuchsia.hardware.pci.api_summary.json b/sdk/history/17/fuchsia.hardware.pci.api_summary.json
new file mode 100644
index 0000000..e8354f9
--- /dev/null
+++ b/sdk/history/17/fuchsia.hardware.pci.api_summary.json
@@ -0,0 +1,1544 @@
+[
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.bus",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.device",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.function",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_ADDRESS_COUNT",
+        "type": "uint32",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.result",
+        "ordinal": "3",
+        "type": "fuchsia.hardware.pci/BarResult"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.io",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/IoBar"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.vmo",
+        "ordinal": "2",
+        "type": "zx/Handle:VMO"
+    },
+    {
+        "kind": "union",
+        "name": "fuchsia.hardware.pci/BarResult",
+        "strictness": "flexible",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_64bit",
+        "ordinal": "5",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_memory",
+        "ordinal": "3",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_prefetchable",
+        "ordinal": "4",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BaseAddress"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetDevices",
+        "strictness": "strict",
+        "ordinal": "3114700014429961362",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetHostBridgeInfo",
+        "strictness": "strict",
+        "ordinal": "4175032687054816861",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.ReadBar",
+        "strictness": "strict",
+        "ordinal": "8759283232091687008",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/BusReadBarRequest",
+        "response": "fuchsia.hardware.pci/Bus_ReadBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Bus",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse.devices",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/PciDevice>:64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.bar_id",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.device",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.offset",
+        "ordinal": "3",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.size",
+        "ordinal": "4",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response.buffer",
+        "ordinal": "1",
+        "type": "vector<uint8>"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.id",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.offset",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Capability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ADVANCED_FEATURES",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP8X",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_CRC",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_HOTSWAP",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.DEBUG_PORT",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.FLATTENING_PORTAL_BRIDGE",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.HYPERTRANSPORT",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSI",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSIX",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCIX",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_BRIDGE_SUBSYSTEM_VID",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_EXPRESS",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_HOT_PLUG",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_PWR_MGMT",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SATA_DATA_NDX_CFG",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SECURE_DEVICE",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SLOT_IDENTIFICATION",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VENDOR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VITAL_PRODUCT_DATA",
+        "value": "3"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/CapabilityId",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.AD_STEP_EN",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.BUS_MASTER_EN",
+        "value": "4"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.FAST_B2B_EN",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.IO_EN",
+        "value": "1"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_EN",
+        "value": "2"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_WR_INV_EN",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PAL_SNOOP_EN",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PERR_RESP_EN",
+        "value": "64"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SERR_EN",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SPECIAL_EN",
+        "value": "8"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Command",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BASE_ADDRESSES",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BIST",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CACHE_LINE_SIZE",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CAPABILITIES_PTR",
+        "value": "52"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CARDBUS_CIS_PTR",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_BASE",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_INTR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_SUB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.COMMAND",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.DEVICE_ID",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.EXP_ROM_ADDRESS",
+        "value": "48"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.HEADER_TYPE",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_LINE",
+        "value": "60"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_PIN",
+        "value": "61"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.LATENCY_TIMER",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MAX_LATENCY",
+        "value": "63"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MIN_GRANT",
+        "value": "62"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.REVISION_ID",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.STATUS",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_ID",
+        "value": "46"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_VENDOR_ID",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.VENDOR_ID",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/Config",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.AckInterrupt",
+        "strictness": "strict",
+        "ordinal": "8103153737854179947",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_AckInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBar",
+        "strictness": "strict",
+        "ordinal": "7721003707982149241",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBarRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBti",
+        "strictness": "strict",
+        "ordinal": "6795907578404380387",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBtiRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetCapabilities",
+        "strictness": "strict",
+        "ordinal": "4180765276430907919",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetDeviceInfo",
+        "strictness": "strict",
+        "ordinal": "6168191258208672022",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetExtendedCapabilities",
+        "strictness": "strict",
+        "ordinal": "830197180054506553",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetInterruptModes",
+        "strictness": "strict",
+        "ordinal": "666335764625137482",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.MapInterrupt",
+        "strictness": "strict",
+        "ordinal": "2733403074518448659",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceMapInterruptRequest",
+        "response": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig16",
+        "strictness": "strict",
+        "ordinal": "4309283036617404603",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig32",
+        "strictness": "strict",
+        "ordinal": "6139942538560107783",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig8",
+        "strictness": "strict",
+        "ordinal": "2952650096395541020",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ResetDevice",
+        "strictness": "strict",
+        "ordinal": "4349199030852488095",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_ResetDevice_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetBusMastering",
+        "strictness": "strict",
+        "ordinal": "3756540713293123587",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest",
+        "response": "fuchsia.hardware.pci/Device_SetBusMastering_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetInterruptMode",
+        "strictness": "strict",
+        "ordinal": "602334104497834086",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest",
+        "response": "fuchsia.hardware.pci/Device_SetInterruptMode_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig16",
+        "strictness": "strict",
+        "ordinal": "4481291721614851839",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig32",
+        "strictness": "strict",
+        "ordinal": "99457760178582408",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig8",
+        "strictness": "strict",
+        "ordinal": "331585330300009727",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Device",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest.index",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/CapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint8>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/ExtendedCapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint16>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse.modes",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.base_class",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.bus_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.dev_id",
+        "ordinal": "8",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.device_id",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.func_id",
+        "ordinal": "9",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.padding",
+        "ordinal": "10",
+        "type": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.program_interface",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.revision_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.sub_class",
+        "ordinal": "4",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.vendor_id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest.which_irq",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest.enabled",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.mode",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptMode"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.requested_irq_count",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.value",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.value",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.value",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response.result",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Bar"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response.bti",
+        "ordinal": "1",
+        "type": "zx/Handle:BTI"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response.interrupt",
+        "ordinal": "1",
+        "type": "zx/Handle:INTERRUPT"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response.value",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response.value",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response.value",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/EXTENDED_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "4096"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.offset",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/ExtendedCapability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ACS",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ADVANCED_ERROR_REPORTING",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ALTERNATE_PROTOCOL",
+        "value": "43"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ARI",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ATS",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.CAC",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DATA_LINK_FEATURE",
+        "value": "37"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DESIGNATED_VENDOR",
+        "value": "35"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DEVICE_SERIAL_NUMBER",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DPC",
+        "value": "29"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DYNAMIC_POWER_ALLOCATION",
+        "value": "22"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.FRS_QUEUEING",
+        "value": "33"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.HIERARCHY_ID",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.L1PM_SUBSTATES",
+        "value": "30"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LANE_MARGINING_AT_RECEIVER",
+        "value": "39"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LATENCY_TOLERANCE_REPORTING",
+        "value": "24"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LNR",
+        "value": "28"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MPCIE",
+        "value": "32"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MR_IOV",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTICAST",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTI_FUNCTION_VIRTUAL_CHANNEL",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NATIVE_PCIE_ENCLOSURE",
+        "value": "41"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PASID",
+        "value": "27"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_16",
+        "value": "38"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_32",
+        "value": "42"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PMUX",
+        "value": "26"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.POWER_BUDGETING",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRECISION_TIME_MEASUREMENT",
+        "value": "31"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRI",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RCRB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.READINESS_TIME_REPORTING",
+        "value": "34"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RESIZABLE_BAR",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_INTERNAL_LINK_CONTROL",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_LINK_DECLARATION",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SECONDARY_PCI_EXPRESS",
+        "value": "25"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SR_IOV",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SYSTEM_FIRMWARE_INTERMEDIARY",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.TPH",
+        "value": "23"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VENDOR",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VF_RESIZABLE_BAR",
+        "value": "36"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL_NO_MFVC",
+        "value": "2"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.BRIDGE",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.CARD_BUS",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MASK",
+        "value": "127"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MULTI_FN",
+        "value": "128"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.STANDARD",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/HeaderType",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.end_bus_number",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.name",
+        "ordinal": "1",
+        "type": "string:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.segment_group",
+        "ordinal": "4",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.start_bus_number",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.DISABLED",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY_NOACK",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI_X",
+        "value": "4"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/InterruptMode",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.has_legacy",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msi_count",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msix_count",
+        "ordinal": "3",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.resource",
+        "ordinal": "2",
+        "type": "zx/Handle:RESOURCE"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/IoBar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_BAR_COUNT",
+        "type": "uint8",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_DEVICES",
+        "type": "uint32",
+        "value": "64"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_EXT_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_NAME_LEN",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.base_addresses",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/BaseAddress>:6"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.bus_id",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.capabilities",
+        "ordinal": "2",
+        "type": "vector<fuchsia.hardware.pci/Capability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.config",
+        "ordinal": "4",
+        "type": "vector<uint8>:256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.device_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.ext_capabilities",
+        "ordinal": "3",
+        "type": "vector<fuchsia.hardware.pci/ExtendedCapability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.function_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/PciDevice"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/READBAR_MAX_SIZE",
+        "type": "uint32",
+        "value": "1024"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/STATUS_DEVSEL_MASK",
+        "type": "fuchsia.hardware.pci/Status",
+        "value": "1536"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_HIGH",
+        "value": "1024"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_LOW",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.FAST_B2B",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.INTERRUPT",
+        "value": "8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_ABORT_RCV",
+        "value": "8192"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_PERR",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.NEW_CAPS",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.PERR",
+        "value": "32768"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SERR_SIG",
+        "value": "16384"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SIXTYSIX_MHZ",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_RCV",
+        "value": "4096"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_SIG",
+        "value": "2048"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Status",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "library",
+        "name": "fuchsia.hardware.pci"
+    }
+]
diff --git a/sdk/history/18/fuchsia.hardware.pci.api_summary.json b/sdk/history/18/fuchsia.hardware.pci.api_summary.json
new file mode 100644
index 0000000..e8354f9
--- /dev/null
+++ b/sdk/history/18/fuchsia.hardware.pci.api_summary.json
@@ -0,0 +1,1544 @@
+[
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.bus",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.device",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.function",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_ADDRESS_COUNT",
+        "type": "uint32",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.result",
+        "ordinal": "3",
+        "type": "fuchsia.hardware.pci/BarResult"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.io",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/IoBar"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.vmo",
+        "ordinal": "2",
+        "type": "zx/Handle:VMO"
+    },
+    {
+        "kind": "union",
+        "name": "fuchsia.hardware.pci/BarResult",
+        "strictness": "flexible",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_64bit",
+        "ordinal": "5",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_memory",
+        "ordinal": "3",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_prefetchable",
+        "ordinal": "4",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BaseAddress"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetDevices",
+        "strictness": "strict",
+        "ordinal": "3114700014429961362",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetHostBridgeInfo",
+        "strictness": "strict",
+        "ordinal": "4175032687054816861",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.ReadBar",
+        "strictness": "strict",
+        "ordinal": "8759283232091687008",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/BusReadBarRequest",
+        "response": "fuchsia.hardware.pci/Bus_ReadBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Bus",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse.devices",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/PciDevice>:64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.bar_id",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.device",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.offset",
+        "ordinal": "3",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.size",
+        "ordinal": "4",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response.buffer",
+        "ordinal": "1",
+        "type": "vector<uint8>"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.id",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.offset",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Capability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ADVANCED_FEATURES",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP8X",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_CRC",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_HOTSWAP",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.DEBUG_PORT",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.FLATTENING_PORTAL_BRIDGE",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.HYPERTRANSPORT",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSI",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSIX",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCIX",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_BRIDGE_SUBSYSTEM_VID",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_EXPRESS",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_HOT_PLUG",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_PWR_MGMT",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SATA_DATA_NDX_CFG",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SECURE_DEVICE",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SLOT_IDENTIFICATION",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VENDOR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VITAL_PRODUCT_DATA",
+        "value": "3"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/CapabilityId",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.AD_STEP_EN",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.BUS_MASTER_EN",
+        "value": "4"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.FAST_B2B_EN",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.IO_EN",
+        "value": "1"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_EN",
+        "value": "2"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_WR_INV_EN",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PAL_SNOOP_EN",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PERR_RESP_EN",
+        "value": "64"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SERR_EN",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SPECIAL_EN",
+        "value": "8"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Command",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BASE_ADDRESSES",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BIST",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CACHE_LINE_SIZE",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CAPABILITIES_PTR",
+        "value": "52"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CARDBUS_CIS_PTR",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_BASE",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_INTR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_SUB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.COMMAND",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.DEVICE_ID",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.EXP_ROM_ADDRESS",
+        "value": "48"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.HEADER_TYPE",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_LINE",
+        "value": "60"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_PIN",
+        "value": "61"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.LATENCY_TIMER",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MAX_LATENCY",
+        "value": "63"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MIN_GRANT",
+        "value": "62"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.REVISION_ID",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.STATUS",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_ID",
+        "value": "46"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_VENDOR_ID",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.VENDOR_ID",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/Config",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.AckInterrupt",
+        "strictness": "strict",
+        "ordinal": "8103153737854179947",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_AckInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBar",
+        "strictness": "strict",
+        "ordinal": "7721003707982149241",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBarRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBti",
+        "strictness": "strict",
+        "ordinal": "6795907578404380387",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBtiRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetCapabilities",
+        "strictness": "strict",
+        "ordinal": "4180765276430907919",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetDeviceInfo",
+        "strictness": "strict",
+        "ordinal": "6168191258208672022",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetExtendedCapabilities",
+        "strictness": "strict",
+        "ordinal": "830197180054506553",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetInterruptModes",
+        "strictness": "strict",
+        "ordinal": "666335764625137482",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.MapInterrupt",
+        "strictness": "strict",
+        "ordinal": "2733403074518448659",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceMapInterruptRequest",
+        "response": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig16",
+        "strictness": "strict",
+        "ordinal": "4309283036617404603",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig32",
+        "strictness": "strict",
+        "ordinal": "6139942538560107783",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig8",
+        "strictness": "strict",
+        "ordinal": "2952650096395541020",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ResetDevice",
+        "strictness": "strict",
+        "ordinal": "4349199030852488095",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_ResetDevice_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetBusMastering",
+        "strictness": "strict",
+        "ordinal": "3756540713293123587",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest",
+        "response": "fuchsia.hardware.pci/Device_SetBusMastering_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetInterruptMode",
+        "strictness": "strict",
+        "ordinal": "602334104497834086",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest",
+        "response": "fuchsia.hardware.pci/Device_SetInterruptMode_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig16",
+        "strictness": "strict",
+        "ordinal": "4481291721614851839",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig32",
+        "strictness": "strict",
+        "ordinal": "99457760178582408",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig8",
+        "strictness": "strict",
+        "ordinal": "331585330300009727",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Device",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest.index",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/CapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint8>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/ExtendedCapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint16>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse.modes",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.base_class",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.bus_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.dev_id",
+        "ordinal": "8",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.device_id",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.func_id",
+        "ordinal": "9",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.padding",
+        "ordinal": "10",
+        "type": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.program_interface",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.revision_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.sub_class",
+        "ordinal": "4",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.vendor_id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest.which_irq",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest.enabled",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.mode",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptMode"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.requested_irq_count",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.value",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.value",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.value",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response.result",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Bar"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response.bti",
+        "ordinal": "1",
+        "type": "zx/Handle:BTI"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response.interrupt",
+        "ordinal": "1",
+        "type": "zx/Handle:INTERRUPT"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response.value",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response.value",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response.value",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/EXTENDED_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "4096"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.offset",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/ExtendedCapability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ACS",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ADVANCED_ERROR_REPORTING",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ALTERNATE_PROTOCOL",
+        "value": "43"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ARI",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ATS",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.CAC",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DATA_LINK_FEATURE",
+        "value": "37"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DESIGNATED_VENDOR",
+        "value": "35"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DEVICE_SERIAL_NUMBER",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DPC",
+        "value": "29"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DYNAMIC_POWER_ALLOCATION",
+        "value": "22"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.FRS_QUEUEING",
+        "value": "33"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.HIERARCHY_ID",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.L1PM_SUBSTATES",
+        "value": "30"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LANE_MARGINING_AT_RECEIVER",
+        "value": "39"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LATENCY_TOLERANCE_REPORTING",
+        "value": "24"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LNR",
+        "value": "28"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MPCIE",
+        "value": "32"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MR_IOV",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTICAST",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTI_FUNCTION_VIRTUAL_CHANNEL",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NATIVE_PCIE_ENCLOSURE",
+        "value": "41"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PASID",
+        "value": "27"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_16",
+        "value": "38"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_32",
+        "value": "42"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PMUX",
+        "value": "26"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.POWER_BUDGETING",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRECISION_TIME_MEASUREMENT",
+        "value": "31"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRI",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RCRB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.READINESS_TIME_REPORTING",
+        "value": "34"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RESIZABLE_BAR",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_INTERNAL_LINK_CONTROL",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_LINK_DECLARATION",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SECONDARY_PCI_EXPRESS",
+        "value": "25"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SR_IOV",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SYSTEM_FIRMWARE_INTERMEDIARY",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.TPH",
+        "value": "23"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VENDOR",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VF_RESIZABLE_BAR",
+        "value": "36"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL_NO_MFVC",
+        "value": "2"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.BRIDGE",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.CARD_BUS",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MASK",
+        "value": "127"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MULTI_FN",
+        "value": "128"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.STANDARD",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/HeaderType",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.end_bus_number",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.name",
+        "ordinal": "1",
+        "type": "string:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.segment_group",
+        "ordinal": "4",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.start_bus_number",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.DISABLED",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY_NOACK",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI_X",
+        "value": "4"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/InterruptMode",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.has_legacy",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msi_count",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msix_count",
+        "ordinal": "3",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.resource",
+        "ordinal": "2",
+        "type": "zx/Handle:RESOURCE"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/IoBar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_BAR_COUNT",
+        "type": "uint8",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_DEVICES",
+        "type": "uint32",
+        "value": "64"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_EXT_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_NAME_LEN",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.base_addresses",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/BaseAddress>:6"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.bus_id",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.capabilities",
+        "ordinal": "2",
+        "type": "vector<fuchsia.hardware.pci/Capability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.config",
+        "ordinal": "4",
+        "type": "vector<uint8>:256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.device_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.ext_capabilities",
+        "ordinal": "3",
+        "type": "vector<fuchsia.hardware.pci/ExtendedCapability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.function_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/PciDevice"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/READBAR_MAX_SIZE",
+        "type": "uint32",
+        "value": "1024"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/STATUS_DEVSEL_MASK",
+        "type": "fuchsia.hardware.pci/Status",
+        "value": "1536"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_HIGH",
+        "value": "1024"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_LOW",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.FAST_B2B",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.INTERRUPT",
+        "value": "8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_ABORT_RCV",
+        "value": "8192"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_PERR",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.NEW_CAPS",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.PERR",
+        "value": "32768"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SERR_SIG",
+        "value": "16384"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SIXTYSIX_MHZ",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_RCV",
+        "value": "4096"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_SIG",
+        "value": "2048"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Status",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "library",
+        "name": "fuchsia.hardware.pci"
+    }
+]
diff --git a/sdk/history/19/fuchsia.hardware.pci.api_summary.json b/sdk/history/19/fuchsia.hardware.pci.api_summary.json
new file mode 100644
index 0000000..e8354f9
--- /dev/null
+++ b/sdk/history/19/fuchsia.hardware.pci.api_summary.json
@@ -0,0 +1,1544 @@
+[
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.bus",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.device",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.function",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_ADDRESS_COUNT",
+        "type": "uint32",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.result",
+        "ordinal": "3",
+        "type": "fuchsia.hardware.pci/BarResult"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.io",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/IoBar"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.vmo",
+        "ordinal": "2",
+        "type": "zx/Handle:VMO"
+    },
+    {
+        "kind": "union",
+        "name": "fuchsia.hardware.pci/BarResult",
+        "strictness": "flexible",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_64bit",
+        "ordinal": "5",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_memory",
+        "ordinal": "3",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_prefetchable",
+        "ordinal": "4",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BaseAddress"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetDevices",
+        "strictness": "strict",
+        "ordinal": "3114700014429961362",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetHostBridgeInfo",
+        "strictness": "strict",
+        "ordinal": "4175032687054816861",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.ReadBar",
+        "strictness": "strict",
+        "ordinal": "8759283232091687008",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/BusReadBarRequest",
+        "response": "fuchsia.hardware.pci/Bus_ReadBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Bus",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse.devices",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/PciDevice>:64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.bar_id",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.device",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.offset",
+        "ordinal": "3",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.size",
+        "ordinal": "4",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response.buffer",
+        "ordinal": "1",
+        "type": "vector<uint8>"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.id",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.offset",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Capability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ADVANCED_FEATURES",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP8X",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_CRC",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_HOTSWAP",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.DEBUG_PORT",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.FLATTENING_PORTAL_BRIDGE",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.HYPERTRANSPORT",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSI",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSIX",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCIX",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_BRIDGE_SUBSYSTEM_VID",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_EXPRESS",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_HOT_PLUG",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_PWR_MGMT",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SATA_DATA_NDX_CFG",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SECURE_DEVICE",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SLOT_IDENTIFICATION",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VENDOR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VITAL_PRODUCT_DATA",
+        "value": "3"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/CapabilityId",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.AD_STEP_EN",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.BUS_MASTER_EN",
+        "value": "4"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.FAST_B2B_EN",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.IO_EN",
+        "value": "1"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_EN",
+        "value": "2"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_WR_INV_EN",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PAL_SNOOP_EN",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PERR_RESP_EN",
+        "value": "64"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SERR_EN",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SPECIAL_EN",
+        "value": "8"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Command",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BASE_ADDRESSES",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BIST",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CACHE_LINE_SIZE",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CAPABILITIES_PTR",
+        "value": "52"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CARDBUS_CIS_PTR",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_BASE",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_INTR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_SUB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.COMMAND",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.DEVICE_ID",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.EXP_ROM_ADDRESS",
+        "value": "48"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.HEADER_TYPE",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_LINE",
+        "value": "60"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_PIN",
+        "value": "61"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.LATENCY_TIMER",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MAX_LATENCY",
+        "value": "63"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MIN_GRANT",
+        "value": "62"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.REVISION_ID",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.STATUS",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_ID",
+        "value": "46"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_VENDOR_ID",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.VENDOR_ID",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/Config",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.AckInterrupt",
+        "strictness": "strict",
+        "ordinal": "8103153737854179947",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_AckInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBar",
+        "strictness": "strict",
+        "ordinal": "7721003707982149241",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBarRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBti",
+        "strictness": "strict",
+        "ordinal": "6795907578404380387",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBtiRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetCapabilities",
+        "strictness": "strict",
+        "ordinal": "4180765276430907919",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetDeviceInfo",
+        "strictness": "strict",
+        "ordinal": "6168191258208672022",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetExtendedCapabilities",
+        "strictness": "strict",
+        "ordinal": "830197180054506553",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetInterruptModes",
+        "strictness": "strict",
+        "ordinal": "666335764625137482",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.MapInterrupt",
+        "strictness": "strict",
+        "ordinal": "2733403074518448659",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceMapInterruptRequest",
+        "response": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig16",
+        "strictness": "strict",
+        "ordinal": "4309283036617404603",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig32",
+        "strictness": "strict",
+        "ordinal": "6139942538560107783",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig8",
+        "strictness": "strict",
+        "ordinal": "2952650096395541020",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ResetDevice",
+        "strictness": "strict",
+        "ordinal": "4349199030852488095",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_ResetDevice_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetBusMastering",
+        "strictness": "strict",
+        "ordinal": "3756540713293123587",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest",
+        "response": "fuchsia.hardware.pci/Device_SetBusMastering_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetInterruptMode",
+        "strictness": "strict",
+        "ordinal": "602334104497834086",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest",
+        "response": "fuchsia.hardware.pci/Device_SetInterruptMode_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig16",
+        "strictness": "strict",
+        "ordinal": "4481291721614851839",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig32",
+        "strictness": "strict",
+        "ordinal": "99457760178582408",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig8",
+        "strictness": "strict",
+        "ordinal": "331585330300009727",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Device",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest.index",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/CapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint8>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/ExtendedCapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint16>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse.modes",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.base_class",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.bus_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.dev_id",
+        "ordinal": "8",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.device_id",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.func_id",
+        "ordinal": "9",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.padding",
+        "ordinal": "10",
+        "type": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.program_interface",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.revision_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.sub_class",
+        "ordinal": "4",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.vendor_id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest.which_irq",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest.enabled",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.mode",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptMode"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.requested_irq_count",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.value",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.value",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.value",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response.result",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Bar"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response.bti",
+        "ordinal": "1",
+        "type": "zx/Handle:BTI"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response.interrupt",
+        "ordinal": "1",
+        "type": "zx/Handle:INTERRUPT"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response.value",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response.value",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response.value",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/EXTENDED_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "4096"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.offset",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/ExtendedCapability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ACS",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ADVANCED_ERROR_REPORTING",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ALTERNATE_PROTOCOL",
+        "value": "43"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ARI",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ATS",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.CAC",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DATA_LINK_FEATURE",
+        "value": "37"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DESIGNATED_VENDOR",
+        "value": "35"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DEVICE_SERIAL_NUMBER",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DPC",
+        "value": "29"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DYNAMIC_POWER_ALLOCATION",
+        "value": "22"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.FRS_QUEUEING",
+        "value": "33"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.HIERARCHY_ID",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.L1PM_SUBSTATES",
+        "value": "30"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LANE_MARGINING_AT_RECEIVER",
+        "value": "39"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LATENCY_TOLERANCE_REPORTING",
+        "value": "24"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LNR",
+        "value": "28"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MPCIE",
+        "value": "32"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MR_IOV",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTICAST",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTI_FUNCTION_VIRTUAL_CHANNEL",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NATIVE_PCIE_ENCLOSURE",
+        "value": "41"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PASID",
+        "value": "27"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_16",
+        "value": "38"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_32",
+        "value": "42"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PMUX",
+        "value": "26"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.POWER_BUDGETING",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRECISION_TIME_MEASUREMENT",
+        "value": "31"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRI",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RCRB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.READINESS_TIME_REPORTING",
+        "value": "34"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RESIZABLE_BAR",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_INTERNAL_LINK_CONTROL",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_LINK_DECLARATION",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SECONDARY_PCI_EXPRESS",
+        "value": "25"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SR_IOV",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SYSTEM_FIRMWARE_INTERMEDIARY",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.TPH",
+        "value": "23"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VENDOR",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VF_RESIZABLE_BAR",
+        "value": "36"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL_NO_MFVC",
+        "value": "2"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.BRIDGE",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.CARD_BUS",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MASK",
+        "value": "127"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MULTI_FN",
+        "value": "128"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.STANDARD",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/HeaderType",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.end_bus_number",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.name",
+        "ordinal": "1",
+        "type": "string:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.segment_group",
+        "ordinal": "4",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.start_bus_number",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.DISABLED",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY_NOACK",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI_X",
+        "value": "4"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/InterruptMode",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.has_legacy",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msi_count",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msix_count",
+        "ordinal": "3",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.resource",
+        "ordinal": "2",
+        "type": "zx/Handle:RESOURCE"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/IoBar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_BAR_COUNT",
+        "type": "uint8",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_DEVICES",
+        "type": "uint32",
+        "value": "64"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_EXT_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_NAME_LEN",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.base_addresses",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/BaseAddress>:6"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.bus_id",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.capabilities",
+        "ordinal": "2",
+        "type": "vector<fuchsia.hardware.pci/Capability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.config",
+        "ordinal": "4",
+        "type": "vector<uint8>:256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.device_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.ext_capabilities",
+        "ordinal": "3",
+        "type": "vector<fuchsia.hardware.pci/ExtendedCapability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.function_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/PciDevice"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/READBAR_MAX_SIZE",
+        "type": "uint32",
+        "value": "1024"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/STATUS_DEVSEL_MASK",
+        "type": "fuchsia.hardware.pci/Status",
+        "value": "1536"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_HIGH",
+        "value": "1024"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_LOW",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.FAST_B2B",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.INTERRUPT",
+        "value": "8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_ABORT_RCV",
+        "value": "8192"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_PERR",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.NEW_CAPS",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.PERR",
+        "value": "32768"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SERR_SIG",
+        "value": "16384"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SIXTYSIX_MHZ",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_RCV",
+        "value": "4096"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_SIG",
+        "value": "2048"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Status",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "library",
+        "name": "fuchsia.hardware.pci"
+    }
+]
diff --git a/sdk/history/20/fuchsia.component.api_summary.json b/sdk/history/20/fuchsia.component.api_summary.json
index d507538..d109263 100644
--- a/sdk/history/20/fuchsia.component.api_summary.json
+++ b/sdk/history/20/fuchsia.component.api_summary.json
@@ -516,6 +516,33 @@
         "value": "255"
     },
     {
+        "kind": "protocol/member",
+        "name": "fuchsia.component/Namespace.Create",
+        "strictness": "flexible",
+        "ordinal": "4839678630846501113",
+        "direction": "two_way",
+        "request": "fuchsia.component/NamespaceCreateRequest",
+        "response": "fuchsia.component/Namespace_Create_Response",
+        "error": "fuchsia.component/NamespaceError"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.component/Namespace",
+        "openness": "open",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.component/NamespaceCreateRequest.entries",
+        "ordinal": "1",
+        "type": "vector<fuchsia.component/NamespaceInputEntry>"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.component/NamespaceCreateRequest",
+        "resourceness": "resource"
+    },
+    {
         "kind": "table/member",
         "name": "fuchsia.component/NamespaceEntry.directory",
         "ordinal": "2",
@@ -533,6 +560,65 @@
         "resourceness": "resource"
     },
     {
+        "kind": "enum/member",
+        "name": "fuchsia.component/NamespaceError.BAD_ENTRY",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.component/NamespaceError.CONVERSION",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.component/NamespaceError.DICTIONARY_READ",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.component/NamespaceError.DUPLICATE",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.component/NamespaceError.SHADOW",
+        "value": "1"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.component/NamespaceError",
+        "strictness": "flexible",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.component/NamespaceInputEntry.dictionary",
+        "ordinal": "2",
+        "type": "fuchsia.component.sandbox/Dictionary"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.component/NamespaceInputEntry.path",
+        "ordinal": "1",
+        "type": "string:4095"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.component/NamespaceInputEntry",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.component/Namespace_Create_Response.entries",
+        "ordinal": "1",
+        "type": "vector<fuchsia.component/NamespaceEntry>"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.component/Namespace_Create_Response",
+        "resourceness": "resource"
+    },
+    {
         "kind": "table",
         "name": "fuchsia.component/PurgedPayload"
     },
diff --git a/sdk/history/20/fuchsia.component.sandbox.api_summary.json b/sdk/history/20/fuchsia.component.sandbox.api_summary.json
index e69de29..7f2b19c 100644
--- a/sdk/history/20/fuchsia.component.sandbox.api_summary.json
+++ b/sdk/history/20/fuchsia.component.sandbox.api_summary.json
@@ -0,0 +1,32 @@
+[
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.component.sandbox/Dictionary.Clone2",
+        "strictness": "strict",
+        "ordinal": "2366825959783828089",
+        "direction": "one_way",
+        "request": "fuchsia.unknown/CloneableClone2Request"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.component.sandbox/Dictionary",
+        "openness": "open",
+        "transport": "channel"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.component.sandbox/MAX_DATA_LENGTH",
+        "type": "uint32",
+        "value": "8192"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.component.sandbox/MAX_DICTIONARY_ITEMS_CHUNK",
+        "type": "uint32",
+        "value": "128"
+    },
+    {
+        "kind": "library",
+        "name": "fuchsia.component.sandbox"
+    }
+]
diff --git a/sdk/history/20/fuchsia.component.test.api_summary.json b/sdk/history/20/fuchsia.component.test.api_summary.json
index 393982c..8ef4631 100644
--- a/sdk/history/20/fuchsia.component.test.api_summary.json
+++ b/sdk/history/20/fuchsia.component.test.api_summary.json
@@ -573,6 +573,11 @@
     },
     {
         "kind": "enum/member",
+        "name": "fuchsia.component.test/RealmBuilderError.INVALID_CHILD_DECL",
+        "value": "22"
+    },
+    {
+        "kind": "enum/member",
         "name": "fuchsia.component.test/RealmBuilderError.INVALID_CHILD_REALM_HANDLE",
         "value": "14"
     },
diff --git a/sdk/history/20/fuchsia.hardware.pci.api_summary.json b/sdk/history/20/fuchsia.hardware.pci.api_summary.json
new file mode 100644
index 0000000..e8354f9
--- /dev/null
+++ b/sdk/history/20/fuchsia.hardware.pci.api_summary.json
@@ -0,0 +1,1544 @@
+[
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.bus",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.device",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Address.function",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_ADDRESS_COUNT",
+        "type": "uint32",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/BASE_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.result",
+        "ordinal": "3",
+        "type": "fuchsia.hardware.pci/BarResult"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bar.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.io",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/IoBar"
+    },
+    {
+        "kind": "union/member",
+        "name": "fuchsia.hardware.pci/BarResult.vmo",
+        "ordinal": "2",
+        "type": "zx/Handle:VMO"
+    },
+    {
+        "kind": "union",
+        "name": "fuchsia.hardware.pci/BarResult",
+        "strictness": "flexible",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_64bit",
+        "ordinal": "5",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_memory",
+        "ordinal": "3",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.is_prefetchable",
+        "ordinal": "4",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BaseAddress.size",
+        "ordinal": "2",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BaseAddress"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetDevices",
+        "strictness": "strict",
+        "ordinal": "3114700014429961362",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.GetHostBridgeInfo",
+        "strictness": "strict",
+        "ordinal": "4175032687054816861",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Bus.ReadBar",
+        "strictness": "strict",
+        "ordinal": "8759283232091687008",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/BusReadBarRequest",
+        "response": "fuchsia.hardware.pci/Bus_ReadBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Bus",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse.devices",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/PciDevice>:64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetDevicesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusGetHostBridgeInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.bar_id",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.device",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Address"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.offset",
+        "ordinal": "3",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest.size",
+        "ordinal": "4",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/BusReadBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response.buffer",
+        "ordinal": "1",
+        "type": "vector<uint8>"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Bus_ReadBar_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.id",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Capability.offset",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Capability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ADVANCED_FEATURES",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.AGP8X",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_CRC",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.COMPACT_PCI_HOTSWAP",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.DEBUG_PORT",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.FLATTENING_PORTAL_BRIDGE",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.HYPERTRANSPORT",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSI",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.MSIX",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCIX",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_BRIDGE_SUBSYSTEM_VID",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_EXPRESS",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_HOT_PLUG",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.PCI_PWR_MGMT",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SATA_DATA_NDX_CFG",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SECURE_DEVICE",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.SLOT_IDENTIFICATION",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VENDOR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/CapabilityId.VITAL_PRODUCT_DATA",
+        "value": "3"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/CapabilityId",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.AD_STEP_EN",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.BUS_MASTER_EN",
+        "value": "4"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.FAST_B2B_EN",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.IO_EN",
+        "value": "1"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_EN",
+        "value": "2"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.MEM_WR_INV_EN",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PAL_SNOOP_EN",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.PERR_RESP_EN",
+        "value": "64"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SERR_EN",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Command.SPECIAL_EN",
+        "value": "8"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Command",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BASE_ADDRESSES",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.BIST",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CACHE_LINE_SIZE",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CAPABILITIES_PTR",
+        "value": "52"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CARDBUS_CIS_PTR",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_BASE",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_INTR",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.CLASS_CODE_SUB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.COMMAND",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.DEVICE_ID",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.EXP_ROM_ADDRESS",
+        "value": "48"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.HEADER_TYPE",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_LINE",
+        "value": "60"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.INTERRUPT_PIN",
+        "value": "61"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.LATENCY_TIMER",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MAX_LATENCY",
+        "value": "63"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.MIN_GRANT",
+        "value": "62"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.REVISION_ID",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.STATUS",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_ID",
+        "value": "46"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.SUBSYSTEM_VENDOR_ID",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/Config.VENDOR_ID",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/Config",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.AckInterrupt",
+        "strictness": "strict",
+        "ordinal": "8103153737854179947",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_AckInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBar",
+        "strictness": "strict",
+        "ordinal": "7721003707982149241",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBarRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetBti",
+        "strictness": "strict",
+        "ordinal": "6795907578404380387",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetBtiRequest",
+        "response": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetCapabilities",
+        "strictness": "strict",
+        "ordinal": "4180765276430907919",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetDeviceInfo",
+        "strictness": "strict",
+        "ordinal": "6168191258208672022",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetExtendedCapabilities",
+        "strictness": "strict",
+        "ordinal": "830197180054506553",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest",
+        "response": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.GetInterruptModes",
+        "strictness": "strict",
+        "ordinal": "666335764625137482",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.MapInterrupt",
+        "strictness": "strict",
+        "ordinal": "2733403074518448659",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceMapInterruptRequest",
+        "response": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig16",
+        "strictness": "strict",
+        "ordinal": "4309283036617404603",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig32",
+        "strictness": "strict",
+        "ordinal": "6139942538560107783",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ReadConfig8",
+        "strictness": "strict",
+        "ordinal": "2952650096395541020",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceReadConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_ReadConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.ResetDevice",
+        "strictness": "strict",
+        "ordinal": "4349199030852488095",
+        "direction": "two_way",
+        "response": "fuchsia.hardware.pci/Device_ResetDevice_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetBusMastering",
+        "strictness": "strict",
+        "ordinal": "3756540713293123587",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest",
+        "response": "fuchsia.hardware.pci/Device_SetBusMastering_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.SetInterruptMode",
+        "strictness": "strict",
+        "ordinal": "602334104497834086",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest",
+        "response": "fuchsia.hardware.pci/Device_SetInterruptMode_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig16",
+        "strictness": "strict",
+        "ordinal": "4481291721614851839",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig16Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig16_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig32",
+        "strictness": "strict",
+        "ordinal": "99457760178582408",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig32Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig32_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol/member",
+        "name": "fuchsia.hardware.pci/Device.WriteConfig8",
+        "strictness": "strict",
+        "ordinal": "331585330300009727",
+        "direction": "two_way",
+        "request": "fuchsia.hardware.pci/DeviceWriteConfig8Request",
+        "response": "fuchsia.hardware.pci/Device_WriteConfig8_Response",
+        "error": "int32"
+    },
+    {
+        "kind": "protocol",
+        "name": "fuchsia.hardware.pci/Device",
+        "openness": "closed",
+        "transport": "channel"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest.bar_id",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBarRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest.index",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetBtiRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/CapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint8>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse.info",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetDeviceInfoResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest.id",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/ExtendedCapabilityId"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse.offsets",
+        "ordinal": "1",
+        "type": "vector<uint16>:32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetExtendedCapabilitiesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse.modes",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceGetInterruptModesResponse"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.base_class",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.bus_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.dev_id",
+        "ordinal": "8",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.device_id",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.func_id",
+        "ordinal": "9",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.padding",
+        "ordinal": "10",
+        "type": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.program_interface",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.revision_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.sub_class",
+        "ordinal": "4",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceInfo.vendor_id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceInfo"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest.which_irq",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceMapInterruptRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceReadConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest.enabled",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetBusMasteringRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.mode",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/InterruptMode"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest.requested_irq_count",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceSetInterruptModeRequest"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request.value",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig16Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request.value",
+        "ordinal": "2",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig32Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.offset",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request.value",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/DeviceWriteConfig8Request"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response.result",
+        "ordinal": "1",
+        "type": "fuchsia.hardware.pci/Bar"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBar_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response.bti",
+        "ordinal": "1",
+        "type": "zx/Handle:BTI"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_GetBti_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response.interrupt",
+        "ordinal": "1",
+        "type": "zx/Handle:INTERRUPT"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_MapInterrupt_Response",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response.value",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig16_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response.value",
+        "ordinal": "1",
+        "type": "uint32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig32_Response"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response.value",
+        "ordinal": "1",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Device_ReadConfig8_Response"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/EXTENDED_CONFIG_SIZE",
+        "type": "uint32",
+        "value": "4096"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.id",
+        "ordinal": "1",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapability.offset",
+        "ordinal": "2",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/ExtendedCapability"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ACS",
+        "value": "13"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ADVANCED_ERROR_REPORTING",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ALTERNATE_PROTOCOL",
+        "value": "43"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ARI",
+        "value": "14"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ATS",
+        "value": "15"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.CAC",
+        "value": "12"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DATA_LINK_FEATURE",
+        "value": "37"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DESIGNATED_VENDOR",
+        "value": "35"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DEVICE_SERIAL_NUMBER",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DPC",
+        "value": "29"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.DYNAMIC_POWER_ALLOCATION",
+        "value": "22"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ENHANCED_ALLOCATION",
+        "value": "20"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.FRS_QUEUEING",
+        "value": "33"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.HIERARCHY_ID",
+        "value": "40"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.L1PM_SUBSTATES",
+        "value": "30"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LANE_MARGINING_AT_RECEIVER",
+        "value": "39"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LATENCY_TOLERANCE_REPORTING",
+        "value": "24"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.LNR",
+        "value": "28"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MPCIE",
+        "value": "32"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MR_IOV",
+        "value": "17"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTICAST",
+        "value": "18"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.MULTI_FUNCTION_VIRTUAL_CHANNEL",
+        "value": "8"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NATIVE_PCIE_ENCLOSURE",
+        "value": "41"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.NULL",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PASID",
+        "value": "27"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_16",
+        "value": "38"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PHYSICAL_LAYER_32",
+        "value": "42"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PMUX",
+        "value": "26"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.POWER_BUDGETING",
+        "value": "4"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRECISION_TIME_MEASUREMENT",
+        "value": "31"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.PRI",
+        "value": "19"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RCRB",
+        "value": "10"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.READINESS_TIME_REPORTING",
+        "value": "34"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.RESIZABLE_BAR",
+        "value": "21"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_EVENT_COLLECTOR_ENDPOINT_ASSOCIATION",
+        "value": "7"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_INTERNAL_LINK_CONTROL",
+        "value": "6"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.ROOT_COMPLEX_LINK_DECLARATION",
+        "value": "5"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SECONDARY_PCI_EXPRESS",
+        "value": "25"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SR_IOV",
+        "value": "16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.SYSTEM_FIRMWARE_INTERMEDIARY",
+        "value": "44"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.TPH",
+        "value": "23"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VENDOR",
+        "value": "11"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VF_RESIZABLE_BAR",
+        "value": "36"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL",
+        "value": "9"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId.VIRTUAL_CHANNEL_NO_MFVC",
+        "value": "2"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/ExtendedCapabilityId",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.BRIDGE",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.CARD_BUS",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MASK",
+        "value": "127"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.MULTI_FN",
+        "value": "128"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/HeaderType.STANDARD",
+        "value": "0"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/HeaderType",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.end_bus_number",
+        "ordinal": "3",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.name",
+        "ordinal": "1",
+        "type": "string:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.segment_group",
+        "ordinal": "4",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo.start_bus_number",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/HostBridgeInfo"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.DISABLED",
+        "value": "0"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY",
+        "value": "1"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.LEGACY_NOACK",
+        "value": "2"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI",
+        "value": "3"
+    },
+    {
+        "kind": "enum/member",
+        "name": "fuchsia.hardware.pci/InterruptMode.MSI_X",
+        "value": "4"
+    },
+    {
+        "kind": "enum",
+        "name": "fuchsia.hardware.pci/InterruptMode",
+        "strictness": "flexible",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.has_legacy",
+        "ordinal": "1",
+        "type": "bool"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msi_count",
+        "ordinal": "2",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/InterruptModes.msix_count",
+        "ordinal": "3",
+        "type": "uint16"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/InterruptModes"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.address",
+        "ordinal": "1",
+        "type": "uint64"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/IoBar.resource",
+        "ordinal": "2",
+        "type": "zx/Handle:RESOURCE"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/IoBar",
+        "resourceness": "resource"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_BAR_COUNT",
+        "type": "uint8",
+        "value": "6"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_DEVICES",
+        "type": "uint32",
+        "value": "64"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_EXT_CAPABILITIES",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/MAX_NAME_LEN",
+        "type": "uint32",
+        "value": "32"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/Padding"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.base_addresses",
+        "ordinal": "1",
+        "type": "vector<fuchsia.hardware.pci/BaseAddress>:6"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.bus_id",
+        "ordinal": "5",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.capabilities",
+        "ordinal": "2",
+        "type": "vector<fuchsia.hardware.pci/Capability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.config",
+        "ordinal": "4",
+        "type": "vector<uint8>:256"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.device_id",
+        "ordinal": "6",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.ext_capabilities",
+        "ordinal": "3",
+        "type": "vector<fuchsia.hardware.pci/ExtendedCapability>:32"
+    },
+    {
+        "kind": "struct/member",
+        "name": "fuchsia.hardware.pci/PciDevice.function_id",
+        "ordinal": "7",
+        "type": "uint8"
+    },
+    {
+        "kind": "struct",
+        "name": "fuchsia.hardware.pci/PciDevice"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/READBAR_MAX_SIZE",
+        "type": "uint32",
+        "value": "1024"
+    },
+    {
+        "kind": "const",
+        "name": "fuchsia.hardware.pci/STATUS_DEVSEL_MASK",
+        "type": "fuchsia.hardware.pci/Status",
+        "value": "1536"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_HIGH",
+        "value": "1024"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.DEVSEL_LOW",
+        "value": "512"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.FAST_B2B",
+        "value": "128"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.INTERRUPT",
+        "value": "8"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_ABORT_RCV",
+        "value": "8192"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.MSTR_PERR",
+        "value": "256"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.NEW_CAPS",
+        "value": "16"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.PERR",
+        "value": "32768"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SERR_SIG",
+        "value": "16384"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.SIXTYSIX_MHZ",
+        "value": "32"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_RCV",
+        "value": "4096"
+    },
+    {
+        "kind": "bits/member",
+        "name": "fuchsia.hardware.pci/Status.TARG_ABORT_SIG",
+        "value": "2048"
+    },
+    {
+        "kind": "bits",
+        "name": "fuchsia.hardware.pci/Status",
+        "strictness": "flexible",
+        "type": "uint16"
+    },
+    {
+        "kind": "library",
+        "name": "fuchsia.hardware.pci"
+    }
+]
diff --git a/sdk/lib/component/incoming/cpp/internal.cc b/sdk/lib/component/incoming/cpp/internal.cc
index a030732..a77fe59 100644
--- a/sdk/lib/component/incoming/cpp/internal.cc
+++ b/sdk/lib/component/incoming/cpp/internal.cc
@@ -112,11 +112,7 @@
 }
 
 zx::result<fidl::ClientEnd<fuchsia_io::Directory>> GetGlobalServiceDirectory() {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  if (endpoints.is_error()) {
-    return endpoints.take_error();
-  }
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
   if (zx_status_t status = fdio_service_connect(kServiceDirectory, server.TakeChannel().release());
       status != ZX_OK) {
     return zx::error(status);
diff --git a/sdk/lib/component/incoming/cpp/protocol.cc b/sdk/lib/component/incoming/cpp/protocol.cc
index f4dca74..f1515cf 100644
--- a/sdk/lib/component/incoming/cpp/protocol.cc
+++ b/sdk/lib/component/incoming/cpp/protocol.cc
@@ -10,11 +10,7 @@
 zx::result<fidl::ClientEnd<fuchsia_io::Directory>> OpenServiceRoot(std::string_view path) {
   // NB: This can't be `return Connect<fuchsia_io::Directory>(path);` because some paths may be both
   // services and directories.
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  if (endpoints.is_error()) {
-    return endpoints.take_error();
-  }
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
   return zx::make_result(
       fdio_open(std::string(path).c_str(), static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
                 server.TakeChannel().release()),
diff --git a/sdk/lib/component/tests/incoming_test.cc b/sdk/lib/component/tests/incoming_test.cc
index ebaa0fd..cc556ef 100644
--- a/sdk/lib/component/tests/incoming_test.cc
+++ b/sdk/lib/component/tests/incoming_test.cc
@@ -36,10 +36,7 @@
 
   fidl::ClientEnd<fuchsia_io::Directory> TakeSvcDirectoryRoot() {
     return PerformBlockingWork([&]() {
-      zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Node>();
-      ZX_ASSERT_MSG(endpoints.is_ok(), "Failed to create fuchsia.io/Node endpoints: %s",
-                    endpoints.status_string());
-      auto& [client, server] = endpoints.value();
+      auto [client, server] = fidl::Endpoints<fuchsia_io::Node>::Create();
       fidl::Request<fuchsia_io::Directory::Open> request(
           /*flags=*/fuchsia_io::OpenFlags{},
           /*mode=*/fuchsia_io::ModeType{},
diff --git a/sdk/lib/component/tests/outgoing_directory_test.cc b/sdk/lib/component/tests/outgoing_directory_test.cc
index f5637bb..d516d67 100644
--- a/sdk/lib/component/tests/outgoing_directory_test.cc
+++ b/sdk/lib/component/tests/outgoing_directory_test.cc
@@ -106,9 +106,7 @@
   static fidl::ClientEnd<fuchsia_io::Directory> GetSvcClientEnd(
       const fidl::ClientEnd<fuchsia_io::Directory>& root,
       fidl::StringView path = kSvcDirectoryPath) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_TRUE(endpoints.is_ok()) << endpoints.status_string();
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_io::Directory>::Create();
     fidl::OneWayStatus status =
         fidl::WireCall(root)->Open(fuchsia_io::wire::OpenFlags::kDirectory, {}, path,
                                    fidl::ServerEnd<fuchsia_io::Node>{server_end.TakeChannel()});
@@ -500,8 +498,7 @@
   static constexpr char kTestContent[] = "Hello World!";
 
   fs::ManagedVfs vfs(dispatcher());
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   auto text_file = fbl::MakeRefCounted<fs::BufferedPseudoFile>(
       /*read_handler=*/[](fbl::String* output) -> zx_status_t {
         *output = kTestContent;
@@ -509,9 +506,9 @@
       });
   auto diagnostics = fbl::MakeRefCounted<fs::PseudoDir>();
   diagnostics->AddEntry(kTestFile, text_file);
-  vfs.ServeDirectory(diagnostics, std::move(endpoints->server));
+  vfs.ServeDirectory(diagnostics, std::move(endpoints.server));
   ASSERT_EQ(GetOutgoingDirectory()
-                ->AddDirectoryAt(std::move(endpoints->client), kTestPath, kTestDirectory)
+                ->AddDirectoryAt(std::move(endpoints.client), kTestPath, kTestDirectory)
                 .status_value(),
             ZX_OK);
 
@@ -557,17 +554,16 @@
       ZX_OK);
 
   // Setup fuchsia.examples.Echo client
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   // First |Serve| is invoked as part of test setup, so we'll assert that a
   // subsequent invocation is allowed.
-  ASSERT_EQ(GetOutgoingDirectory()->Serve(std::move(endpoints->server)).status_value(), ZX_OK);
+  ASSERT_EQ(GetOutgoingDirectory()->Serve(std::move(endpoints.server)).status_value(), ZX_OK);
 
   std::vector<fidl::ClientEnd<fuchsia_io::Directory>> root_client_ends;
   // Take client end for channel used during invocation of |Serve| during setup.
   root_client_ends.emplace_back(TakeRootClientEnd());
   // Take client end for channel used during invocation of |Serve| in this function.
-  root_client_ends.emplace_back(std::move(endpoints->client));
+  root_client_ends.emplace_back(std::move(endpoints.client));
 
   while (!root_client_ends.empty()) {
     fidl::ClientEnd root = std::move(root_client_ends.back());
@@ -698,11 +694,10 @@
 
 TEST_F(OutgoingDirectoryTest, ServeFailsIfHandleInvalid) {
   component::OutgoingDirectory outgoing_directory(dispatcher());
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   // Close server end in order to  invalidate channel.
-  endpoints->server.reset();
-  EXPECT_EQ(outgoing_directory.Serve(std::move(endpoints->server)).status_value(),
+  endpoints.server.reset();
+  EXPECT_EQ(outgoing_directory.Serve(std::move(endpoints.server)).status_value(),
             ZX_ERR_BAD_HANDLE);
 }
 
@@ -831,11 +826,10 @@
 }
 
 TEST_F(OutgoingDirectoryTest, AddDirectoryFailsIfDirectoryNameIsEmpty) {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   EXPECT_EQ(GetOutgoingDirectory()
-                ->AddDirectory(std::move(endpoints->client), /*directory_name=*/"")
+                ->AddDirectory(std::move(endpoints.client), /*directory_name=*/"")
                 .status_value(),
             ZX_ERR_INVALID_ARGS);
 }
@@ -862,10 +856,9 @@
                 .status_value(),
             ZX_OK);
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   EXPECT_EQ(GetOutgoingDirectory()
-                ->AddDirectory(std::move(endpoints->client), kDirectoryName)
+                ->AddDirectory(std::move(endpoints.client), kDirectoryName)
                 .status_value(),
             ZX_ERR_ALREADY_EXISTS);
 }
diff --git a/sdk/lib/device-watcher/cpp/device-watcher.cc b/sdk/lib/device-watcher/cpp/device-watcher.cc
index 59d5cbf..09047eb7 100644
--- a/sdk/lib/device-watcher/cpp/device-watcher.cc
+++ b/sdk/lib/device-watcher/cpp/device-watcher.cc
@@ -21,11 +21,7 @@
 namespace {
 zx::result<fidl::ClientEnd<fuchsia_io::DirectoryWatcher>> Watch(
     fidl::UnownedClientEnd<fuchsia_io::Directory> dir) {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::DirectoryWatcher>();
-  if (endpoints.is_error()) {
-    return endpoints.take_error();
-  }
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::DirectoryWatcher>::Create();
   const fidl::WireResult result =
       fidl::WireCall(dir)->Watch(fuchsia_io::wire::WatchMask::kRemoved, 0, std::move(server));
   if (!result.ok()) {
@@ -240,11 +236,7 @@
 
 zx::result<> WatchDirectoryForItems(const fidl::ClientEnd<fuchsia_io::Directory>& dir,
                                     ItemCallback callback) {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::DirectoryWatcher>();
-  if (endpoints.is_error()) {
-    return endpoints.take_error();
-  }
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::DirectoryWatcher>::Create();
 
   auto watch_mask = fuchsia_io::wire::WatchMask::kAdded | fuchsia_io::wire::WatchMask::kExisting;
   const fidl::WireResult result = fidl::WireCall(dir)->Watch(watch_mask, 0, std::move(server));
diff --git a/sdk/lib/device-watcher/cpp/test.cc b/sdk/lib/device-watcher/cpp/test.cc
index 99cd4c1..b60a76c 100644
--- a/sdk/lib/device-watcher/cpp/test.cc
+++ b/sdk/lib/device-watcher/cpp/test.cc
@@ -40,9 +40,7 @@
   ASSERT_OK(first->AddEntry("second", std::move(second)));
   ASSERT_OK(first->AddEntry("file", file));
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   fs::ManagedVfs vfs(loop.dispatcher());
   ASSERT_OK(vfs.ServeDirectory(first, std::move(server)));
@@ -79,9 +77,7 @@
   ASSERT_OK(first->AddEntry(file1_name, file));
   ASSERT_OK(first->AddEntry(file2_name, file));
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   fs::ManagedVfs vfs(loop.dispatcher());
   ASSERT_OK(vfs.ServeDirectory(first, std::move(server)));
@@ -121,9 +117,7 @@
   ASSERT_OK(first->AddEntry(file1_name, file));
   ASSERT_OK(first->AddEntry(file2_name, file));
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   fs::ManagedVfs vfs(loop.dispatcher());
   ASSERT_OK(vfs.ServeDirectory(first, std::move(server)));
@@ -170,9 +164,7 @@
   ASSERT_OK(first->AddEntry("second", second));
   ASSERT_OK(first->AddEntry("file", file));
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   fs::ManagedVfs vfs(loop.dispatcher());
   ASSERT_OK(vfs.ServeDirectory(first, std::move(server)));
@@ -216,9 +208,7 @@
   auto first = fbl::MakeRefCounted<fs::PseudoDir>();
   ASSERT_OK(first->AddEntry("file", file));
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   fs::ManagedVfs vfs(loop.dispatcher());
   ASSERT_OK(vfs.ServeDirectory(first, std::move(server)));
diff --git a/sdk/lib/dl/diagnostics.h b/sdk/lib/dl/diagnostics.h
index ed8abe7..a58e0b4 100644
--- a/sdk/lib/dl/diagnostics.h
+++ b/sdk/lib/dl/diagnostics.h
@@ -100,9 +100,12 @@
     return {};
   }
 
-  // Reports an out of memory error and makes it safe to destroy this object,
-  // as in DiagnosticsReport.
-  auto OutOfMemory() { return report().OutOfMemory(); }
+  // Sets an OutOfMemory error on the diagnostics object and returns the
+  // reported error back to the caller.
+  auto OutOfMemory(std::string_view error, size_t bytes) {
+    Base::OutOfMemory(error, bytes);
+    return take_error();
+  }
 };
 
 }  // namespace dl
diff --git a/sdk/lib/dl/module.h b/sdk/lib/dl/module.h
index 0cf54d5..d1a602d 100644
--- a/sdk/lib/dl/module.h
+++ b/sdk/lib/dl/module.h
@@ -5,6 +5,7 @@
 #ifndef LIB_DL_MODULE_H_
 #define LIB_DL_MODULE_H_
 
+#include <lib/elfldltl/alloc-checker-container.h>
 #include <lib/elfldltl/dynamic.h>
 #include <lib/elfldltl/load.h>
 #include <lib/elfldltl/memory.h>
@@ -18,12 +19,14 @@
 
 #include <fbl/alloc_checker.h>
 #include <fbl/intrusive_double_list.h>
+#include <fbl/vector.h>
 
 #include "diagnostics.h"
 
 namespace dl {
 
 using Elf = elfldltl::Elf<>;
+using Soname = elfldltl::Soname<>;
 
 // TODO(https://fxbug.dev/324136435): These KMax* variables are copied from
 // //sdk/lib/ld/startup-load.h, we should share these symbols instead.
@@ -46,19 +49,18 @@
 // ld::abi::Abi<...>::Module data structure that describes the module in the
 // passive ABI (see //sdk/lib/ld/module.h).
 
-// A ModuleHandle is created for the ELF file in `dlopen` and is passed to the
-// LoadModule::Load function to decode and load the file into memory. Whereas a
-// LoadModule is ephemeral and lives only as long as it takes to load a module
-// and its dependencies in `dlopen`, the ModuleHandle is a "permanent" data
-// structure that is kept alive in the RuntimeDynamicLinker's `loaded_modules`
-// list until the module is unloaded.
+// A ModuleHandle is created by its corresponding LoadModule (see below) when
+// an ELF file is first loaded by `dlopen`. Whereas a LoadModule is ephemeral
+// and lives only as long as it takes to load a module and its dependencies in
+// `dlopen`, the ModuleHandle is a "permanent" data structure that is kept alive
+// in the RuntimeDynamicLinker's `loaded_modules` list until the module is
+// unloaded.
 
 // While this is an internal API, a ModuleHandle* is the void* handle returned
 // by the public <dlfcn.h> API.
 class ModuleHandle : public fbl::DoublyLinkedListable<std::unique_ptr<ModuleHandle>> {
  public:
   using Addr = Elf::Addr;
-  using Soname = elfldltl::Soname<>;
   using SymbolInfo = elfldltl::SymbolInfo<Elf>;
   using AbiModule = ld::AbiModule<>;
 
@@ -78,8 +80,9 @@
 
   constexpr const Soname& name() const { return name_; }
 
-  static std::unique_ptr<ModuleHandle> Create(Soname name, fbl::AllocChecker& ac) {
-    auto module = std::unique_ptr<ModuleHandle>{new (ac) ModuleHandle};
+  // TODO(https://fxbug.dev/333920495): pass in the symbolizer_modid.
+  [[nodiscard]] static std::unique_ptr<ModuleHandle> Create(Soname name, fbl::AllocChecker& ac) {
+    std::unique_ptr<ModuleHandle> module{new (ac) ModuleHandle};
     if (module) [[likely]] {
       module->name_ = name;
     }
@@ -95,6 +98,7 @@
   const SymbolInfo& symbol_info() const { return abi_module_.symbols; }
 
  private:
+  // A ModuleHandle can only be created with Module::Create...).
   ModuleHandle() = default;
 
   static void Unmap(uintptr_t vaddr, size_t len);
@@ -102,31 +106,64 @@
   AbiModule abi_module_;
 };
 
-using LoadModuleBase = ld::LoadModule<ld::DecodedModuleInMemory<>>;
+// Use a AllocCheckerContainer that supports fallible allocations; methods return
+// a boolean value to signify allocation success or failure.
+template <typename T>
+using Vector = elfldltl::AllocCheckerContainer<fbl::Vector>::Container<T>;
 
-// TODO(https://fxbug.dev/324136435): Replace the code and functions copied from
-// ld::LoadModule to use them directly; then continue to use methods directly
-// from the //sdk/lib/ld public API, refactoring them into shared code as needed.
+// LoadModule is the temporary data structure created to load a file; a
+// LoadModule is created when a file needs to be loaded, and is destroyed after
+// the file module and all its dependencies have been loaded, decoded, symbols
+// resolved, and relro protected.
 template <class OSImpl>
-class LoadModule : public LoadModuleBase {
+class LoadModule : public ld::LoadModule<ld::DecodedModuleInMemory<>>,
+                   public fbl::DoublyLinkedListable<std::unique_ptr<LoadModule<OSImpl>>> {
  public:
   using Loader = typename OSImpl::Loader;
   using File = typename OSImpl::File;
   using Relro = typename Loader::Relro;
   using Phdr = Elf::Phdr;
   using Dyn = Elf::Dyn;
-  using Soname = elfldltl::Soname<>;
   using LoadInfo = elfldltl::LoadInfo<Elf, elfldltl::StaticVector<kMaxSegments>::Container>;
 
-  // A LoadModule takes temporary ownership of the ModuleHandle as it sets
-  // requisite information on its AbiModule during the loading process. If an error
-  // occurs during this process, LoadModule will clean up the module handle in
-  // its own destruction.
-  explicit LoadModule(std::unique_ptr<ModuleHandle> module)
-      : LoadModuleBase{module->name()}, module_(std::move(module)) {
-    // The DecodeModule will use the module's AbiModule to attach information to
-    // as it performs decoding operations.
-    decoded().set_module(module_->module());
+  // This is the observer used to collect DT_NEEDED offsets from the dynamic phdr.
+  static const constexpr std::string_view kNeededError{"DT_NEEDED offsets"};
+  using NeededObserver = elfldltl::DynamicValueCollectionObserver<  //
+      Elf, elfldltl::ElfDynTag::kNeeded, Vector<size_type>, kNeededError>;
+
+  // The LoadModule::Create(...) creates and takes temporary ownership of the
+  // ModuleHandle for the file in order to set information on the data structure
+  // during the loading process. When the loading process has completed,
+  // `take_module()` should  be called on the load module before it's destroyed
+  // to transfer ownership of the module handle to the caller. Otherwise, if an
+  // error occurs during loading, the load module will clean up the module
+  // handle in its own destruction.
+  // A fbl::AllocChecker& caller_ac is passed in to require the caller to check
+  // for allocation success/failure. This function will arm the caller_ac with
+  // the allocation results of its local calls.
+  [[nodiscard]] static std::unique_ptr<LoadModule> Create(Soname name,
+                                                          fbl::AllocChecker& caller_ac) {
+    fbl::AllocChecker ac;
+    auto module = ModuleHandle::Create(name, ac);
+    if (!ac.check()) [[unlikely]] {
+      caller_ac.arm(sizeof(ModuleHandle), false);
+      return nullptr;
+    }
+    std::unique_ptr<LoadModule> load_module{new (ac) LoadModule};
+    if (!ac.check()) [[unlikely]] {
+      caller_ac.arm(sizeof(LoadModule), false);
+      return nullptr;
+    }
+    load_module->set_name(name);
+    // Have the underlying DecodedModule (see <lib/ld/decoded-module.h>) point to
+    // the ABIModule embedded in the ModuleHandle, so that its information will
+    // be filled out during decoding operations.
+    load_module->decoded().set_module(module->module());
+    load_module->module_ = std::move(module);
+
+    // Signal to the caller all allocations have succeeded.
+    caller_ac.arm(sizeof(LoadModule), true);
+    return std::move(load_module);
   }
 
   // This must be the last method called on LoadModule and can only be called
@@ -138,11 +175,12 @@
 
   // Retrieve the file and load it into the system image, then decode the phdrs
   // to metadata to attach to the ABI module and store the information needed
-  // for dependency parsing.
-  bool Load(Diagnostics& diag) {
+  // for dependency parsing. Decode the module's dependencies (if any), and
+  // return a vector their so names.
+  std::optional<Vector<Soname>> Load(Diagnostics& diag) {
     auto file = OSImpl::RetrieveFile(diag, module_->name().str());
     if (!file) [[unlikely]] {
-      return false;
+      return std::nullopt;
     }
 
     // Read the file header and program headers into stack buffers and map in
@@ -151,51 +189,51 @@
     Loader loader;
     auto headers = decoded().LoadFromFile(diag, loader, *std::move(file));
     if (!headers) [[unlikely]] {
-      return false;
+      return std::nullopt;
     }
-    auto& [ehdr_owner, phdrs_owner] = *headers;
-    cpp20::span<const Phdr> phdrs = phdrs_owner;
+
+    Vector<size_type> needed_offsets;
+    // TODO(https://fxbug.dev/331421403): TLS is not supported yet.
+    size_type max_tls_modid = 0;
+    if (!decoded().DecodeFromMemory(  //
+            diag, loader.memory(), loader.page_size(), *headers, max_tls_modid,
+            elfldltl::DynamicRelocationInfoObserver(decoded().reloc_info()),
+            NeededObserver(needed_offsets))) [[unlikely]] {
+      return std::nullopt;
+    }
 
     // After successfully loading the file, finalize the module's mapping by
     // calling `Commit` on the loader. Save the returned relro capability
     // that will be used to apply relro protections later.
-    // TODO(https://fxbug.dev/323418587): For now, pass an empty relro_bounds.
-    // This will eventually take the decoded relro_phdr.
-    loader_relro_ = std::move(loader).Commit(LoadInfo::Region{});
+    loader_relro_ = std::move(loader).Commit(decoded().relro_bounds());
 
-    // Now that the file is in memory, we can decode the phdrs.
-    std::optional<Phdr> dyn_phdr;
-    if (!elfldltl::DecodePhdrs(diag, phdrs, elfldltl::PhdrDynamicObserver<Elf>(dyn_phdr))) {
-      return false;
+    // TODO(https://fxbug.dev/324136435): The code that parses the names from
+    // the symbol table be shared with <lib/ld/remote-decoded-module.h>.
+    if (Vector<Soname> needed_names;
+        needed_names.reserve(diag, kNeededError, needed_offsets.size())) [[likely]] {
+      for (size_type offset : needed_offsets) {
+        std::string_view name = this->symbol_info().string(offset);
+        if (name.empty()) [[unlikely]] {
+          diag.FormatError("DT_NEEDED has DT_STRTAB offset ", offset, " with DT_STRSZ ",
+                           this->symbol_info().strtab().size());
+          return std::nullopt;
+        }
+        if (!needed_names.push_back(diag, kNeededError, Soname{name})) [[unlikely]] {
+          return std::nullopt;
+        }
+      }
+      return std::move(needed_names);
     }
 
-    // TODO(caslyn): Use ld::DecodeFromMemory with a
-    // elfldltl::DynamicValueCollectionObserver so that we collect the needed
-    // entries into an fbl::Vector<size_type> in one pass. Have this Load
-    // function return the std::optional result of that to pass to EnqueueDeps.
-    // From the dynamic phdr, decode the metadata and dependency information.
-    auto memory = ld::ModuleMemory{decoded().module()};
-    auto dyn = DecodeModuleDynamic(
-        decoded().module(), diag, memory, dyn_phdr,
-        elfldltl::DynamicRelocationInfoObserver(decoded().reloc_info()),
-        elfldltl::DynamicTagCountObserver<Elf, elfldltl::ElfDynTag::kNeeded>(needed_count_));
-    if (dyn.is_error()) [[unlikely]] {
-      return {};
-    }
-
-    dynamic_ = dyn.value();
-
-    return true;
+    return std::nullopt;
   }
 
  private:
+  // A LoadModule can only be created with LoadModule::Create...).
+  LoadModule() = default;
+
   std::unique_ptr<ModuleHandle> module_;
   Relro loader_relro_;
-  // TODO(caslyn): These are stored here for now, for convenience. After
-  // dependency enqueueing and sharing code with //sdk/lib/ld, we will be able
-  // to see more clearly how best to pass these values around.
-  cpp20::span<const Dyn> dynamic_;
-  size_t needed_count_ = 0;
 };
 
 }  // namespace dl
diff --git a/sdk/lib/dl/runtime-dynamic-linker.h b/sdk/lib/dl/runtime-dynamic-linker.h
index 07ca7a0..76e8fac 100644
--- a/sdk/lib/dl/runtime-dynamic-linker.h
+++ b/sdk/lib/dl/runtime-dynamic-linker.h
@@ -41,6 +41,9 @@
 inline constexpr int kOpenBindingModeMask = OpenBindingMode::kLazy | OpenBindingMode::kNow;
 inline constexpr int kOpenFlagsMask = OpenFlags::kNoload | OpenFlags::kNodelete;
 
+template <class ModuleType>
+using ModuleList = fbl::DoublyLinkedList<std::unique_ptr<ModuleType>>;
+
 class RuntimeDynamicLinker {
  public:
   using Soname = elfldltl::Soname<>;
@@ -54,6 +57,10 @@
   // if the module was not found.
   ModuleHandle* FindModule(Soname name);
 
+  // Lookup a symbol from the given module, returning a pointer to it in memory,
+  // or an error if not found (ie undefined symbol).
+  fit::result<Error, void*> LookupSymbol(ModuleHandle* module, const char* ref);
+
   template <class OSImpl>
   fit::result<Error, void*> Open(const char* file, int mode) {
     auto already_loaded = CheckOpen(file, mode);
@@ -65,36 +72,33 @@
       return fit::ok(already_loaded.value());
     }
 
-    // TODO(caslyn): Roll up ModuleHandle allocation with LoadModule allocation,
-    // and add comment on the allocation/relationship.
-    fbl::AllocChecker ac;
-    auto module = ModuleHandle::Create(Soname{file}, ac);
-    if (!ac.check()) [[unlikely]] {
-      return Error::OutOfMemory();
-    }
+    // A ModuleHandle for `file` does not yet exist; proceed to loading the
+    // file and all it's dependencies.
 
-    // TODO(https://fxbug.dev/324650368): implement file retrieval interfaces.
     // Use a non-scoped diagnostics object for the main module. Because errors
-    // are generated on this module directly, its name does not need to be
+    // are generated on this module directly, it's name does not need to be
     // prefixed to the error, as is the case using ld::ScopedModuleDiagnostics.
     dl::Diagnostics diag;
-    LoadModule<OSImpl> load_module{std::move(module)};
-    if (!load_module.Load(diag)) [[unlikely]] {
+    auto load_modules = Load<OSImpl>(diag, Soname{file});
+    if (load_modules.is_empty()) [[unlikely]] {
       return diag.take_error();
     }
 
-    // TODO(caslyn): these are actions needed to finish loading the module and
-    // return its reference back to the caller, but are not meant to be invoked
-    // directly by this function. These will be abstracted away eventually.
-    auto loaded_module = std::move(load_module).take_module();
-    ModuleHandle* module_ref = loaded_module.get();
-    loaded_modules_.push_back(std::move(loaded_module));
+    // TODO(caslyn): These are actions needed to return a reference to the main
+    // module back to the caller and add the loaded modules to the dynamic
+    // linker's bookkeeping. This will be abstracted away into another function
+    // eventually.
+    while (!load_modules.is_empty()) {
+      auto load_module = load_modules.pop_front();
+      auto module = std::move(*load_module).take_module();
+      loaded_modules_.push_back(std::move(module));
+    }
 
-    return diag.ok(module_ref);
+    // TODO(caslyn): This assumes the dlopen-ed module is the first module in
+    // loaded_modules_.
+    return diag.ok(&loaded_modules_.front());
   }
 
-  fit::result<Error, void*> LookupSymbol(ModuleHandle* module, const char* ref);
-
  private:
   // Perform basic argument checking and check whether a module for `file` was
   // already loaded. An error is returned if bad input was given. Otherwise,
@@ -102,10 +106,64 @@
   // a module for `file` was not found.
   fit::result<Error, ModuleHandle*> CheckOpen(const char* file, int mode);
 
+  // Load the main module and all its dependencies, returning the list of all
+  // loaded modules. Starting with the main file that was `dlopen`-ed, a
+  // LoadModule is created for each file that is to be loaded, decoded, and its
+  // dependencies parsed and enqueued to be processed in the same manner.
+  template <class OSImpl>
+  static fbl::DoublyLinkedList<std::unique_ptr<LoadModule<OSImpl>>> Load(Diagnostics& diag,
+                                                                         Soname soname) {
+    // This is the list of modules to load and process. The first module of this
+    // list will always be the main file that was `dlopen`-ed.
+    ModuleList<LoadModule<OSImpl>> pending_modules;
+
+    fbl::AllocChecker ac;
+    auto main_module = LoadModule<OSImpl>::Create(soname, ac);
+    if (!ac.check()) [[unlikely]] {
+      diag.OutOfMemory("LoadModule", sizeof(LoadModule<OSImpl>));
+      return {};
+    }
+
+    pending_modules.push_back(std::move(main_module));
+
+    // TODO(https://fxrev.dev/333573264): This needs to handle if a dep is
+    // already loaded.
+    // Iterate over the pending modules that need to be loaded and dependencies
+    // enqueued, appending each new dependency to the pending_modules list so
+    // it can eventually be loaded and processed.
+    for (auto it = pending_modules.begin(); it != pending_modules.end(); it++) {
+      // TODO(caslyn): support scoped module diagnostics.
+      // ld::ScopedModuleDiagnostics module_diag{diag, module_->name().str()};
+
+      auto result = it->Load(diag);
+      if (!result) {
+        return {};
+      }
+
+      for (const auto& needed_entry : *result) {
+        // Skip if this dependency was already added to the pending_modules list.
+        if (std::find(pending_modules.begin(), pending_modules.end(), needed_entry) !=
+            pending_modules.end()) {
+          continue;
+        }
+
+        fbl::AllocChecker ac;
+        auto load_module = LoadModule<OSImpl>::Create(needed_entry, ac);
+        if (!ac.check()) [[unlikely]] {
+          diag.OutOfMemory("LoadModule", sizeof(LoadModule<OSImpl>));
+          return {};
+        }
+        pending_modules.push_back(std::move(load_module));
+      }
+    }
+
+    return std::move(pending_modules);
+  }
+
   // The RuntimeDynamicLinker owns the list of all 'live' modules that have been
   // loaded into the system image.
   // TODO(https://fxbug.dev/324136831): support startup modules
-  fbl::DoublyLinkedList<std::unique_ptr<ModuleHandle>> loaded_modules_;
+  ModuleList<ModuleHandle> loaded_modules_;
 };
 
 }  // namespace dl
diff --git a/sdk/lib/dl/test/BUILD.gn b/sdk/lib/dl/test/BUILD.gn
index e79116b..852f88b 100644
--- a/sdk/lib/dl/test/BUILD.gn
+++ b/sdk/lib/dl/test/BUILD.gn
@@ -30,6 +30,7 @@
     sources += [
       "dl-impl-tests.cc",
       "dl-impl-tests.h",
+      "dl-load-posix-tests-base.h",
       "dl-load-tests.cc",
       "dl-system-tests.cc",
       "dl-system-tests.h",
@@ -37,9 +38,14 @@
     ]
     deps += [
       "..:runtime",
+      "//sdk/lib/ld/testing",
       "//src/lib/elfldltl/testing",
     ]
 
+    if (is_fuchsia) {
+      sources += [ "dl-load-zircon-tests-base.h" ]
+    }
+
     # Plumb in the switch to set cflags, such as the libprefix for test files.
     deps += [ "//sdk/lib/ld/test:load-test-modules-info" ]
   }
diff --git a/sdk/lib/dl/test/dl-impl-tests.cc b/sdk/lib/dl/test/dl-impl-tests.cc
index 447ef9c..583ddd9 100644
--- a/sdk/lib/dl/test/dl-impl-tests.cc
+++ b/sdk/lib/dl/test/dl-impl-tests.cc
@@ -6,18 +6,46 @@
 
 #include <fcntl.h>
 #include <lib/elfldltl/testing/get-test-data.h>
+#ifdef __Fuchsia__
+#include <lib/ld/testing/test-vmo.h>
+#endif
 
 #include <filesystem>
 
+#include <gtest/gtest.h>
+
 namespace dl::testing {
 
+namespace {
+
+// These startup modules should not be retrieved from the filesystem.
+void FileCheck(std::string_view filename) {
+  EXPECT_NE(filename, ld::abi::Abi<>::kSoname.str());
+#ifdef __Fuchsia__
+  EXPECT_NE(filename, ld::testing::GetVdsoSoname().str());
+#endif
+}
+
+}  // namespace
+
 #ifdef __Fuchsia__
 
 std::optional<TestFuchsia::File> TestFuchsia::RetrieveFile(Diagnostics& diag,
                                                            std::string_view filename) {
-  // Use the lib prefix for library paths to the same prefix used in libld,
-  // which generates the testing modules used by libdl.
-  std::filesystem::path path = std::filesystem::path("test") / "lib" / LD_TEST_LIBPREFIX / filename;
+  FileCheck(filename);
+  auto prefix = "";
+  // TODO(https://fxbug.dev/323419430): dlopen shouldn't know if it's loading a
+  // loadable_module or shared library. Shared libraries reside in a
+  // lib/$libprefix directory on instrumented builds; this is a temporary hack
+  // to amend the filepath of a shared library (but not a loadable module) for
+  // an instrumented build so dlopen can locate the file.
+  // Eventually, the mock loader will be primed with the module/shlib files
+  // and this function will only pass `filename` to `TryGetTestLibVmo()` to
+  // retrieve the file from the mock loader.
+  if (std::string{filename}.find("module") == std::string::npos) {
+    prefix = LD_TEST_LIBPREFIX;
+  }
+  std::filesystem::path path = std::filesystem::path("test") / "lib" / prefix / filename;
   if (auto vmo = elfldltl::testing::TryGetTestLibVmo(path.c_str())) {
     return File{std::move(vmo), diag};
   }
@@ -29,6 +57,7 @@
 
 std::optional<TestPosix::File> TestPosix::RetrieveFile(Diagnostics& diag,
                                                        std::string_view filename) {
+  FileCheck(filename);
   std::filesystem::path path = elfldltl::testing::GetTestDataPath(filename);
   if (fbl::unique_fd fd{open(path.c_str(), O_RDONLY)}) {
     return File{std::move(fd), diag};
diff --git a/sdk/lib/dl/test/dl-impl-tests.h b/sdk/lib/dl/test/dl-impl-tests.h
index afd7f0e..010361c 100644
--- a/sdk/lib/dl/test/dl-impl-tests.h
+++ b/sdk/lib/dl/test/dl-impl-tests.h
@@ -12,13 +12,14 @@
 
 #include "../diagnostics.h"
 #include "../runtime-dynamic-linker.h"
-#include "dl-tests-base.h"
 
 #ifdef __Fuchsia__
 #include <lib/elfldltl/vmar-loader.h>
 #include <lib/elfldltl/vmo.h>
 #endif
 
+#include "dl-load-posix-tests-base.h"
+
 namespace dl::testing {
 
 #ifdef __Fuchsia__
@@ -39,8 +40,14 @@
   static std::optional<File> RetrieveFile(Diagnostics& diag, std::string_view filename);
 };
 
+// TODO(https://fxbug.dev/323419430): For now, both versions of dl-impl-tests
+// will use DlLoadPosixTestsBase, which is just a class of empty hooks so that
+// dl-load-tests.cc can compile. Eventually, DlImplTests may use another base
+// class to verify that module/dep files were loaded as expected.
+using DlImplLoadTestsBase = DlLoadPosixTestsBase;
+
 template <class TestOS>
-class DlImplTests : public DlTestsBase {
+class DlImplTests : public DlImplLoadTestsBase {
  public:
   // Error messages in tests can be matched exactly with this test fixture,
   // since the error message returned from the libdl implementation will be the
diff --git a/sdk/lib/dl/test/dl-load-posix-tests-base.h b/sdk/lib/dl/test/dl-load-posix-tests-base.h
new file mode 100644
index 0000000..60676c9
--- /dev/null
+++ b/sdk/lib/dl/test/dl-load-posix-tests-base.h
@@ -0,0 +1,37 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_DL_TEST_DL_LOAD_POSIX_TESTS_BASE_H_
+#define LIB_DL_TEST_DL_LOAD_POSIX_TESTS_BASE_H_
+
+#include <string_view>
+
+#include "dl-tests-base.h"
+
+namespace dl::testing {
+
+// TODO(https://fxbug.dev/323419430): For now DlLoadPosixTestsBase contains
+// empty hooks so that dl-load-tests.cc can call them and compile. Eventually,
+// we will refactor the DlLoadPosixTestsBase and DlLoadFuchsiaTestsBase in
+// such a way where there will be a common base class where these hooks will
+// open the files by name to verify they exist in the test data. The POSIX
+// test fixture will only use this base class, whereas the Zircon test fixture
+// will use a subclass of that which statically overrides those methods.
+class DlLoadPosixTestsBase : public DlTestsBase {
+ public:
+  constexpr void ExpectRootModule(std::string_view name) {}
+
+  constexpr void ExpectMissing(std::string_view name) {}
+
+  constexpr void Needed(std::initializer_list<std::string_view> names) {}
+
+  // TODO(https://fxbug.dev/323419430): This can use TryGetTestLib to assert
+  // that the file does not exist.
+  constexpr void Needed(std::initializer_list<std::pair<std::string_view, bool>> name_found_pairs) {
+  }
+};
+
+}  // namespace dl::testing
+
+#endif  // LIB_DL_TEST_DL_LOAD_POSIX_TESTS_BASE_H_
diff --git a/sdk/lib/dl/test/dl-load-tests.cc b/sdk/lib/dl/test/dl-load-tests.cc
index 56bd6610..df9b018 100644
--- a/sdk/lib/dl/test/dl-load-tests.cc
+++ b/sdk/lib/dl/test/dl-load-tests.cc
@@ -19,6 +19,12 @@
 
 namespace {
 
+// This is a convenience function to specify that a specific dependency should
+// not be found in a Needed set.
+constexpr std::pair<std::string_view, bool> NotFound(std::string_view name) {
+  return {name, false};
+}
+
 using ::testing::MatchesRegex;
 
 template <class Fixture>
@@ -47,17 +53,24 @@
 TYPED_TEST_SUITE(DlTests, TestTypes);
 
 TYPED_TEST(DlTests, NotFound) {
-  auto result = this->DlOpen("does_not_exist.so", RTLD_NOW | RTLD_LOCAL);
+  constexpr const char* kNotFoundFile = "does-not-exist.so";
+
+  this->ExpectMissing(kNotFoundFile);
+
+  auto result = this->DlOpen(kNotFoundFile, RTLD_NOW | RTLD_LOCAL);
   ASSERT_TRUE(result.is_error());
   if constexpr (TestFixture::kCanMatchExactError) {
-    EXPECT_EQ(result.error_value().take_str(), "cannot open does_not_exist.so");
+    EXPECT_EQ(result.error_value().take_str(), "cannot open " + std::string{kNotFoundFile});
   } else {
     EXPECT_THAT(result.error_value().take_str(),
-                MatchesRegex(".*does_not_exist.so:.*(No such file or directory|ZX_ERR_NOT_FOUND)"));
+                MatchesRegex(".*" + std::string{kNotFoundFile} +
+                             ":.*(No such file or directory|ZX_ERR_NOT_FOUND)"));
   }
 }
 
 TYPED_TEST(DlTests, InvalidMode) {
+  constexpr const char* kBasicFile = "ret17.module.so";
+
   if constexpr (!TestFixture::kCanValidateMode) {
     GTEST_SKIP() << "test requires dlopen to validate mode argment";
   }
@@ -71,23 +84,87 @@
   bad_mode &= ~RTLD_DEEPBIND;
 #endif
 
-  auto result = this->DlOpen("libld-dep-a.so", bad_mode);
+  auto result = this->DlOpen(kBasicFile, bad_mode);
   ASSERT_TRUE(result.is_error());
   EXPECT_EQ(result.error_value().take_str(), "invalid mode parameter")
       << "for mode argument " << bad_mode;
 }
 
+// Load a basic file with no dependencies.
 TYPED_TEST(DlTests, Basic) {
-  auto result = this->DlOpen("libld-dep-c.so", RTLD_NOW | RTLD_LOCAL);
+  constexpr const char* kBasicFile = "ret17.module.so";
+
+  this->ExpectRootModule(kBasicFile);
+
+  auto result = this->DlOpen(kBasicFile, RTLD_NOW | RTLD_LOCAL);
   ASSERT_TRUE(result.is_ok()) << result.error_value();
   EXPECT_TRUE(result.value());
-  // Look up the "c" function and call it, expecting its return value of 2.
-  auto sym_result = this->DlSym(result.value(), "c");
+  // Look up the "TestStart" function and call it, expecting it to return 17.
+  auto sym_result = this->DlSym(result.value(), "TestStart");
   ASSERT_TRUE(sym_result.is_ok()) << result.error_value();
   ASSERT_TRUE(sym_result.value());
   int64_t (*func_ptr)();
   func_ptr = reinterpret_cast<int64_t (*)()>(reinterpret_cast<uintptr_t>(sym_result.value()));
-  EXPECT_EQ(func_ptr(), 2);
+  EXPECT_EQ(func_ptr(), 17);
+}
+
+// TODO(https://fxrev.dev/323419430): expect that libld-dep-a.so was needed.
+TYPED_TEST(DlTests, BasicDep) {
+  if constexpr (!TestFixture::kCanLookUpDeps) {
+    GTEST_SKIP()
+        << "TODO(https://fxbug.dev/324650368): test requires dlopen to locate dependencies.";
+  }
+
+  constexpr const char* kBasicDepFile = "basic-dep.module.so";
+
+  this->ExpectRootModule(kBasicDepFile);
+  this->Needed({"libld-dep-a.so"});
+
+  auto result = this->DlOpen(kBasicDepFile, RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(result.is_ok()) << result.error_value();
+  EXPECT_TRUE(result.value());
+}
+
+// TODO(https://fxrev.dev/323419430): expect that libld-dep-[a,b,c].so was needed.
+TYPED_TEST(DlTests, IndirectDeps) {
+  if constexpr (!TestFixture::kCanLookUpDeps) {
+    GTEST_SKIP()
+        << "TODO(https://fxbug.dev/324650368): test requires dlopen to locate dependencies.";
+  }
+
+  constexpr const char* kIndirectDepsFile = "indirect-deps.module.so";
+
+  this->ExpectRootModule(kIndirectDepsFile);
+  this->Needed({"libindirect-deps-a.so", "libindirect-deps-b.so", "libindirect-deps-c.so"});
+
+  auto result = this->DlOpen(kIndirectDepsFile, RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(result.is_ok()) << result.error_value();
+  EXPECT_TRUE(result.value());
+}
+
+TYPED_TEST(DlTests, MissingDependency) {
+  // To clarify this condition, the test needs to be accurate in that its
+  // searching the correct path for the dependency, but can't find it.
+  if constexpr (!TestFixture::kCanLookUpDeps) {
+    GTEST_SKIP()
+        << "TODO(https://fxbug.dev/324650368): test requires dlopen to locate dependencies.";
+  }
+
+  constexpr const char* kMissingDepFile = "missing-dep.module.so";
+
+  this->ExpectRootModule(kMissingDepFile);
+  this->Needed({NotFound("libmissing-dep-dep.so")});
+
+  auto result = this->DlOpen(kMissingDepFile, RTLD_NOW | RTLD_LOCAL);
+  ASSERT_TRUE(result.is_error());
+  // Expect that the dependency lib to missing-dep.module.so cannot be found.
+  if constexpr (TestFixture::kCanMatchExactError) {
+    EXPECT_EQ(result.error_value().take_str(), "cannot open libmissing-dep-dep.so");
+  } else {
+    EXPECT_THAT(
+        result.error_value().take_str(),
+        MatchesRegex(".*libmissing-dep-dep.so:.*(No such file or directory|ZX_ERR_NOT_FOUND)"));
+  }
 }
 
 }  // namespace
diff --git a/sdk/lib/dl/test/dl-load-zircon-tests-base.h b/sdk/lib/dl/test/dl-load-zircon-tests-base.h
new file mode 100644
index 0000000..7f54c2f
--- /dev/null
+++ b/sdk/lib/dl/test/dl-load-zircon-tests-base.h
@@ -0,0 +1,38 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIB_DL_TEST_DL_LOAD_ZIRCON_TESTS_BASE_H_
+#define LIB_DL_TEST_DL_LOAD_ZIRCON_TESTS_BASE_H_
+
+#include <lib/ld/testing/mock-loader-service.h>
+
+#include "dl-tests-base.h"
+
+namespace dl::testing {
+
+// DlLoadZirconTestsBase contains testing hooks to verify that modules and/or
+// dependencies were loaded by the fuchsia.ldsvc.Loader as expected. This class
+// uses the MockLoaderForTest to set a mock loader as the system loader that
+// `dlopen` will invoke to load VMOs.
+// Tests call `Needed` to register the ordered set of dependencies the mock
+// loader is expected to load.
+// TODO(caslyn): comment on how the root module is loaded.
+class DlLoadZirconTestsBase : public DlTestsBase {
+ public:
+  constexpr void ExpectRootModule(std::string_view name) {}
+
+  constexpr void ExpectMissing(std::string_view name) {}
+
+  constexpr void Needed(std::initializer_list<std::string_view> names) {}
+
+  constexpr void Needed(std::initializer_list<std::pair<std::string_view, bool>> name_found_pairs) {
+  }
+
+ private:
+  ld::testing::MockLoaderServiceForTest mock_;
+};
+
+}  // namespace dl::testing
+
+#endif  // LIB_DL_TEST_DL_LOAD_ZIRCON_TESTS_BASE_H_
diff --git a/sdk/lib/dl/test/dl-system-tests.cc b/sdk/lib/dl/test/dl-system-tests.cc
index fcfcf6c..0d48507 100644
--- a/sdk/lib/dl/test/dl-system-tests.cc
+++ b/sdk/lib/dl/test/dl-system-tests.cc
@@ -30,9 +30,19 @@
   } else {
     std::filesystem::path path;
 #ifdef __Fuchsia__
-    // Use the lib prefix for library paths to the same prefix used in libld,
-    // which generates the testing modules used by libdl.
-    path = std::filesystem::path("test") / "lib" / LD_TEST_LIBPREFIX / file;
+    auto prefix = "";
+    // TODO(https://fxbug.dev/323419430): dlopen shouldn't know if it's loading a
+    // loadable_module or shared library. Shared libraries reside in a
+    // lib/$libprefix directory on instrumented builds; this is a temporary hack
+    // to amend the filepath of a shared library (but not a loadable module) for
+    // an instrumented build so dlopen can locate the file.
+    // Eventually, the mock loader will be primed with the module/shlib files
+    // and this function will only pass `filename` to `TryGetTestLibVmo()` to
+    // retrieve the file from the mock loader.
+    if (std::string{file}.find("module") == std::string::npos) {
+      prefix = LD_TEST_LIBPREFIX;
+    }
+    path = std::filesystem::path("test") / "lib" / prefix / file;
 #else
     path = elfldltl::testing::GetTestDataPath(file);
 #endif
diff --git a/sdk/lib/dl/test/dl-system-tests.h b/sdk/lib/dl/test/dl-system-tests.h
index 97807302..8e53ec9 100644
--- a/sdk/lib/dl/test/dl-system-tests.h
+++ b/sdk/lib/dl/test/dl-system-tests.h
@@ -5,16 +5,31 @@
 #ifndef LIB_DL_TEST_DL_SYSTEM_TESTS_H_
 #define LIB_DL_TEST_DL_SYSTEM_TESTS_H_
 
-#include "dl-tests-base.h"
+#ifdef __Fuchsia__
+#include "dl-load-zircon-tests-base.h"
+#else
+#include "dl-load-posix-tests-base.h"
+#endif
 
 namespace dl::testing {
 
-class DlSystemTests : public DlTestsBase {
+#ifdef __Fuchsia__
+using DlSystemLoadTestsBase = DlLoadZirconTestsBase;
+#else
+using DlSystemLoadTestsBase = DlLoadPosixTestsBase;
+#endif
+
+class DlSystemTests : public DlSystemLoadTestsBase {
  public:
   // This test fixture does not need to match on exact error text, since the
   // error message can vary between different system implementations.
   static constexpr bool kCanMatchExactError = false;
+
 #ifdef __Fuchsia__
+  // TODO(https://fxbug.dev/324650368): Disable dep tests until Fuchsia's
+  // loader service can load from test paths.
+  static constexpr bool kCanLookUpDeps = false;
+
   // Fuchsia's musl implementation of dlopen does not validate flag values for
   // the mode argument.
   static constexpr bool kCanValidateMode = false;
diff --git a/sdk/lib/dl/test/dl-tests-base.h b/sdk/lib/dl/test/dl-tests-base.h
index 4a3795d..6f0b535 100644
--- a/sdk/lib/dl/test/dl-tests-base.h
+++ b/sdk/lib/dl/test/dl-tests-base.h
@@ -29,6 +29,8 @@
   static constexpr bool kCanMatchExactError = true;
   // Whether the dlopen implementation validates the mode argument.
   static constexpr bool kCanValidateMode = true;
+  // Whether the implementation can look up a dependency file.
+  static constexpr bool kCanLookUpDeps = true;
 
   // Test fixtures are expected to provide definitions for the following API:
   fit::result<Error, void*> DlOpen(const char* file, int mode);
diff --git a/sdk/lib/driver/component/cpp/tests/fixture_based_tests.cc b/sdk/lib/driver/component/cpp/tests/fixture_based_tests.cc
index e90851d..c3e5b20 100644
--- a/sdk/lib/driver/component/cpp/tests/fixture_based_tests.cc
+++ b/sdk/lib/driver/component/cpp/tests/fixture_based_tests.cc
@@ -229,3 +229,45 @@
       });
   ASSERT_EQ(ZX_OK, run_result.status_value());
 }
+
+class ManualStopFixtureConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = false;
+
+  using DriverType = TestDriver;
+  using EnvironmentType = FixtureBasedTestEnvironment;
+};
+
+// Demonstrates a test fixture that tests out the manual stop and shutdown feature. Validates by
+// checking the a global that gets set in the driver header.
+class FixtureBasedTestManualStop : public fdf_testing::DriverTestFixture<ManualStopFixtureConfig> {
+};
+
+TEST_F(FixtureBasedTestManualStop, ShutdownAndCheckLogger) {
+  ASSERT_EQ(false, g_driver_stopped);
+  ASSERT_EQ(ZX_OK, StopDriver().status_value());
+  ASSERT_EQ(false, g_driver_stopped);
+  ShutdownDispatchersAndDestroyDriver();
+  ASSERT_EQ(true, g_driver_stopped);
+}
+
+class AddChildFixtureConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestDriver;
+  using EnvironmentType = fdf_testing::MinimalEnvironment;
+};
+
+// Checks that adding a child and then managing it by the driver works.
+class FixtureBasedTestAddChild : public fdf_testing::DriverTestFixture<AddChildFixtureConfig> {};
+
+TEST_F(FixtureBasedTestAddChild, AddChild) {
+  EXPECT_EQ(ZX_OK, driver()->InitSyncCompat().status_value());
+  driver()->CreateChildNodeSync();
+  EXPECT_TRUE(driver()->sync_added_child());
+}
diff --git a/sdk/lib/driver/component/cpp/tests/logger_test.cc b/sdk/lib/driver/component/cpp/tests/logger_test.cc
index f61c3fb..34c4050 100644
--- a/sdk/lib/driver/component/cpp/tests/logger_test.cc
+++ b/sdk/lib/driver/component/cpp/tests/logger_test.cc
@@ -104,9 +104,8 @@
   async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread};
 
   // Setup namespace.
-  auto svc = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  EXPECT_EQ(ZX_OK, svc.status_value());
-  auto ns = fdf::testing::CreateNamespace(std::move(svc->client));
+  auto svc = fidl::Endpoints<fuchsia_io::Directory>::Create();
+  auto ns = fdf::testing::CreateNamespace(std::move(svc.client));
   ASSERT_TRUE(ns.is_ok());
 
   // Setup logger.
@@ -129,7 +128,7 @@
   });
   fidl::Binding<fio::Directory> svc_binding2(&svc_directory2);
 
-  svc_binding2.Bind(svc->server.TakeChannel(), loop.dispatcher());
+  svc_binding2.Bind(svc.server.TakeChannel(), loop.dispatcher());
 
   auto logger = fdf::Logger::Create(*ns, loop.dispatcher(), kName, FUCHSIA_LOG_INFO, false);
   ASSERT_TRUE(logger.is_ok());
@@ -160,18 +159,17 @@
   // Setup namespace.
   auto pkg = fidl::CreateEndpoints<fuchsia_io::Directory>();
   EXPECT_EQ(ZX_OK, pkg.status_value());
-  auto svc = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  EXPECT_EQ(ZX_OK, svc.status_value());
+  auto svc = fidl::Endpoints<fuchsia_io::Directory>::Create();
   fidl::Arena arena;
   fidl::VectorView<frunner::wire::ComponentNamespaceEntry> ns_entries(arena, 2);
   ns_entries[0].Allocate(arena);
   ns_entries[0].set_path(arena, "/pkg").set_directory(std::move(pkg->client));
   ns_entries[1].Allocate(arena);
-  ns_entries[1].set_path(arena, "/svc").set_directory(std::move(svc->client));
+  ns_entries[1].set_path(arena, "/svc").set_directory(std::move(svc.client));
   auto ns = fdf::Namespace::Create(ns_entries);
   ASSERT_TRUE(ns.is_ok());
 
-  svc->server.TakeChannel().reset();
+  svc.server.TakeChannel().reset();
 
   // Setup logger.
   auto logger = fdf::Logger::Create(*ns, loop.dispatcher(), kName, FUCHSIA_LOG_INFO, true);
@@ -182,9 +180,8 @@
   async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread};
 
   // Setup namespace.
-  auto svc = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  EXPECT_EQ(ZX_OK, svc.status_value());
-  auto ns = fdf::testing::CreateNamespace(std::move(svc->client));
+  auto svc = fidl::Endpoints<fuchsia_io::Directory>::Create();
+  auto ns = fdf::testing::CreateNamespace(std::move(svc.client));
   ASSERT_TRUE(ns.is_ok());
 
   // Setup logger.
@@ -207,7 +204,7 @@
   });
   fidl::Binding<fio::Directory> svc_binding2(&svc_directory2);
 
-  svc_binding2.Bind(svc->server.TakeChannel(), loop.dispatcher());
+  svc_binding2.Bind(svc.server.TakeChannel(), loop.dispatcher());
 
   auto logger = fdf::Logger::Create(*ns, loop.dispatcher(), kName, FUCHSIA_LOG_INFO, false);
   ASSERT_TRUE(logger.is_ok());
diff --git a/sdk/lib/driver/component/cpp/tests/test_driver.cc b/sdk/lib/driver/component/cpp/tests/test_driver.cc
index 8a1489d..41bdc2e 100644
--- a/sdk/lib/driver/component/cpp/tests/test_driver.cc
+++ b/sdk/lib/driver/component/cpp/tests/test_driver.cc
@@ -6,6 +6,8 @@
 #include <lib/driver/component/cpp/tests/test_driver.h>
 #include <lib/driver/logging/cpp/structured_logger.h>
 
+bool g_driver_stopped = false;
+
 void TestDriver::Start(fdf::StartCompleter completer) {
   node_client_.Bind(std::move(node()), dispatcher());
   // Delay the completion to simulate an async workload.
@@ -158,6 +160,8 @@
   }
 }
 
+void TestDriver::Stop() { g_driver_stopped = true; }
+
 zx::result<> TestDriver::InitSyncCompat() {
   auto result = sync_device_server_.Initialize(incoming(), outgoing(), node_name(), "child",
                                                compat::ForwardMetadata::All());
diff --git a/sdk/lib/driver/component/cpp/tests/test_driver.h b/sdk/lib/driver/component/cpp/tests/test_driver.h
index e45fe45..5771adf 100644
--- a/sdk/lib/driver/component/cpp/tests/test_driver.h
+++ b/sdk/lib/driver/component/cpp/tests/test_driver.h
@@ -11,6 +11,8 @@
 #include <lib/driver/component/cpp/driver_base.h>
 #include <lib/driver/devfs/cpp/connector.h>
 
+extern bool g_driver_stopped;
+
 class TestDriver : public fdf::DriverBase,
                    public fidl::WireServer<fuchsia_driver_component_test::ZirconProtocol>,
                    public fdf::WireServer<fuchsia_driver_component_test::DriverProtocol>,
@@ -24,6 +26,8 @@
 
   void PrepareStop(fdf::PrepareStopCompleter completer) override;
 
+  void Stop() override;
+
   zx::result<> InitSyncCompat();
   void BeginInitAsyncCompat(fit::callback<void(zx::result<>)> completed);
 
diff --git a/sdk/lib/driver/devicetree/examples/example-board/BUILD.bazel b/sdk/lib/driver/devicetree/examples/example-board/BUILD.bazel
index b145360..d417494 100644
--- a/sdk/lib/driver/devicetree/examples/example-board/BUILD.bazel
+++ b/sdk/lib/driver/devicetree/examples/example-board/BUILD.bazel
@@ -87,12 +87,12 @@
         "-Wno-vla-cxx-extension",
     ],
     deps = [
+        "//zircon/system/ulib/ddk-platform-defs",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
         "@fuchsia_sdk//pkg/async-loop-cpp",
         "@fuchsia_sdk//pkg/async-loop-default",
         "@internal_sdk//pkg/board-test-helper",
-        "@internal_sdk//pkg/ddk-platform-defs",
     ],
 )
 
diff --git a/sdk/lib/driver/testing/cpp/fixtures/base_fixture.h b/sdk/lib/driver/testing/cpp/fixtures/base_fixture.h
index 6ef0b16..b994e4d 100644
--- a/sdk/lib/driver/testing/cpp/fixtures/base_fixture.h
+++ b/sdk/lib/driver/testing/cpp/fixtures/base_fixture.h
@@ -69,9 +69,8 @@
 
  public:
   BaseDriverTestFixture()
-      : env_dispatcher_(runtime_.StartBackgroundDispatcher()),
-        env_wrapper_(env_dispatcher_->async_dispatcher(), std::in_place),
-        dut_(&runtime_) {
+      : env_wrapper_(runtime_.StartBackgroundDispatcher()->async_dispatcher(), std::in_place) {
+    dut_.emplace(&runtime_);
     start_args_ = env_wrapper_.SyncCall(&internal::EnvWrapper<EnvironmentType>::Init);
 
     outgoing_directory_client_ =
@@ -89,8 +88,7 @@
       ZX_ASSERT_MSG(result.is_ok(), "Failed to StopDriver: %s.", result.status_string());
     }
 
-    env_wrapper_.reset();
-    runtime_.ShutdownAllDispatchers(dut_.GetDispatcher()->get());
+    ShutdownDispatchersAndDestroyDriverImpl();
   }
 
   // Access the driver runtime object. This can be used to create new background dispatchers
@@ -135,7 +133,7 @@
     return StartDriverImpl(std::move(args_modifier));
   }
 
-  // Stops the driver.
+  // Stops the driver by calling the driver's PrepareStop hook and waiting for it to complete
   //
   // Enabled only when kAutoStopDriver is false.
   template <bool A = kAutoStopDriver, typename = std::enable_if_t<!A>>
@@ -144,6 +142,17 @@
     return StopDriverImpl();
   }
 
+  // Shuts down all of the driver dispatchers, then destroys the driver. This must be called after
+  // having called StopDriver(). This is an optional call, if the user doesn't call this, then it
+  // will happen in the destructor. This calls the DriverBase's Stop hook
+  //
+  // Enabled only when kAutoStopDriver is false.
+  template <bool A = kAutoStopDriver, typename = std::enable_if_t<!A>>
+  void ShutdownDispatchersAndDestroyDriver() {
+    static_assert(A == kAutoStopDriver, "Do not override the A template parameter.");
+    ShutdownDispatchersAndDestroyDriverImpl();
+  }
+
   // Runs a task on the dispatcher context of the driver under test. This will be a different
   // thread than the main test thread, so be careful when capturing and returning pointers to
   // objects that live on different dispatchers like test fixture properties, or the environment.
@@ -154,7 +163,9 @@
   template <typename T, bool F = kDriverOnForeground, typename = std::enable_if_t<!F>>
   T RunInDriverContext(fit::callback<T(DriverType&)> task) {
     static_assert(F == kDriverOnForeground, "Do not override the F template parameter.");
-    return dut_.RunInDriverContext(std::move(task));
+    ZX_ASSERT_MSG(dut_.has_value(),
+                  "Cannot call RunInDriverContext after ShutdownDispatchersAndDestroyDriverImpl.");
+    return dut_->RunInDriverContext(std::move(task));
   }
 
   // Runs a task on the dispatcher context of the driver under test. This will be a different
@@ -167,7 +178,9 @@
   template <bool F = kDriverOnForeground, typename = std::enable_if_t<!F>>
   void RunInDriverContext(fit::callback<void(DriverType&)> task) {
     static_assert(F == kDriverOnForeground, "Do not override the F template parameter.");
-    dut_.RunInDriverContext(std::move(task));
+    ZX_ASSERT_MSG(dut_.has_value(),
+                  "Cannot call RunInDriverContext after ShutdownDispatchersAndDestroyDriverImpl.");
+    dut_->RunInDriverContext(std::move(task));
   }
 
   // Get a pointer to the driver under test.
@@ -176,7 +189,9 @@
   template <bool F = kDriverOnForeground, typename = std::enable_if_t<F>>
   DriverType* driver() {
     static_assert(F == kDriverOnForeground, "Do not override the F template parameter.");
-    return dut_.driver();
+    ZX_ASSERT_MSG(dut_.has_value(),
+                  "Cannot call driver after ShutdownDispatchersAndDestroyDriverImpl.");
+    return dut_->driver();
   }
 
   // Runs a task in a background context while running the foreground driver. This must be used
@@ -351,7 +366,9 @@
     fdf::DriverStartArgs start_args = std::move(start_args_.value());
     start_args_.reset();
 
-    return dut_.Start(std::move(start_args));
+    ZX_ASSERT_MSG(dut_.has_value(),
+                  "Cannot call StartDriver after ShutdownDispatchersAndDestroyDriverImpl.");
+    return dut_->Start(std::move(start_args));
   }
 
   zx::result<> StopDriverImpl() {
@@ -359,15 +376,30 @@
       return zx::error(ZX_ERR_BAD_STATE);
     }
 
-    zx::result prepare_stop_result = dut_.PrepareStop();
+    ZX_ASSERT_MSG(dut_.has_value(),
+                  "Cannot call StopDriver after ShutdownDispatchersAndDestroyDriverImpl.");
+    zx::result prepare_stop_result = dut_->PrepareStop();
     prepare_stop_result_.emplace(prepare_stop_result);
     return prepare_stop_result;
   }
 
+  void ShutdownDispatchersAndDestroyDriverImpl() {
+    ZX_ASSERT_MSG(prepare_stop_result_.has_value(),
+                  "Ensure that StopDriver is called when kAutoStopDriver is false.");
+    if (dut_.has_value()) {
+      env_wrapper_.reset();
+      runtime_.ShutdownAllDispatchers(dut_->GetDispatcher()->get());
+      dut_.reset();
+    }
+  }
+
   fdf_testing::DriverRuntime runtime_;
-  fdf::UnownedSynchronizedDispatcher env_dispatcher_;
   async_patterns::TestDispatcherBound<internal::EnvWrapper<EnvironmentType>> env_wrapper_;
-  internal::DriverWrapper<DriverType, kDriverOnForeground> dut_;
+
+  // The dut_ is created through the constructor, and becomes a nullopt through
+  // |ShutdownDispatchersAndDestroyDriverImpl|.
+  std::optional<internal::DriverWrapper<DriverType, kDriverOnForeground>> dut_;
+
   fidl::ClientEnd<fuchsia_io::Directory> outgoing_directory_client_;
 
   std::optional<fdf::UnownedSynchronizedDispatcher> bg_task_dispatcher_;
diff --git a/sdk/lib/driver_component/BUILD.gn b/sdk/lib/driver_component/BUILD.gn
index 635ccd1..0befce6 100644
--- a/sdk/lib/driver_component/BUILD.gn
+++ b/sdk/lib/driver_component/BUILD.gn
@@ -7,5 +7,5 @@
 sdk_component_manifests("driver_component") {
   name = "driver_component"
   manifests = [ "driver.shard.cml" ]
-  category = "experimental"
+  category = "partner"
 }
diff --git a/sdk/lib/fdio/BUILD.gn b/sdk/lib/fdio/BUILD.gn
index 616a200..5bbe525 100644
--- a/sdk/lib/fdio/BUILD.gn
+++ b/sdk/lib/fdio/BUILD.gn
@@ -18,7 +18,7 @@
   zx_library("fdio-spawn-actions") {
     configs += [ "//build/config:all_source" ]
     sdk = "source"
-    sdk_publishable = true
+    sdk_publishable = "partner"
     sdk_headers = [ "lib/fdio/spawn-actions.h" ]
 
     deps = [
@@ -77,7 +77,7 @@
   zx_library("fdio") {
     configs += [ "//build/config:all_source" ]
     sdk = "shared"
-    sdk_publishable = true
+    sdk_publishable = "partner"
 
     # This list is relative to the include/ directory.
     sdk_headers = rebase_path(fdio_public_headers, "include")
diff --git a/sdk/lib/fdio/tests/fdio_atexit.cc b/sdk/lib/fdio/tests/fdio_atexit.cc
index 3d3ba55..32a66f4 100644
--- a/sdk/lib/fdio/tests/fdio_atexit.cc
+++ b/sdk/lib/fdio/tests/fdio_atexit.cc
@@ -61,18 +61,17 @@
 };
 
 TEST(AtExit, ExitInAccept) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_posix_socket::StreamSocket>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_posix_socket::StreamSocket>::Create();
 
   zx::socket client_socket, server_socket;
   ASSERT_OK(zx::socket::create(ZX_SOCKET_STREAM, &client_socket, &server_socket));
 
   // We're going to need the raw handle so we can signal on it and close it.
-  zx_handle_t server_handle = endpoints->server.channel().get();
+  zx_handle_t server_handle = endpoints.server.channel().get();
 
   Server server(server_handle, std::move(server_socket));
   async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &server);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &server);
   ASSERT_OK(loop.StartThread("fake-socket-server"));
 
   const char* argv[] = {"/pkg/bin/accept-child", nullptr};
@@ -82,7 +81,7 @@
           .h =
               {
                   .id = PA_HND(PA_USER0, 0),
-                  .handle = endpoints->client.channel().release(),
+                  .handle = endpoints.client.channel().release(),
               },
       },
   };
diff --git a/sdk/lib/fdio/tests/fdio_get_vmo.cc b/sdk/lib/fdio/tests/fdio_get_vmo.cc
index ab903ee..6d9bf8f 100644
--- a/sdk/lib/fdio/tests/fdio_get_vmo.cc
+++ b/sdk/lib/fdio/tests/fdio_get_vmo.cc
@@ -175,8 +175,7 @@
   ASSERT_OK(loop.StartThread("fake-filesystem"));
   async_dispatcher_t* dispatcher = loop.dispatcher();
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::File>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::File>::Create();
 
   Context context = {
       .supports_get_backing_memory = true,
@@ -185,11 +184,10 @@
   create_context_vmo(zx_system_get_page_size(), &context.vmo);
   ASSERT_OK(context.vmo.write("abcd", 0, 4));
 
-  fidl::BindServer(dispatcher, std::move(endpoints->server),
-                   std::make_unique<TestServer>(&context));
+  fidl::BindServer(dispatcher, std::move(endpoints.server), std::make_unique<TestServer>(&context));
 
   int raw_fd = -1;
-  ASSERT_OK(fdio_fd_create(endpoints->client.channel().release(), &raw_fd));
+  ASSERT_OK(fdio_fd_create(endpoints.client.channel().release(), &raw_fd));
   fbl::unique_fd fd(raw_fd);
 
   zx_rights_t expected_rights =
@@ -250,8 +248,7 @@
   ASSERT_OK(loop.StartThread("fake-filesystem"));
   async_dispatcher_t* dispatcher = loop.dispatcher();
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::File>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::File>::Create();
 
   Context context = {
       .supports_get_backing_memory = true,
@@ -260,11 +257,10 @@
   create_context_vmo(zx_system_get_page_size(), &context.vmo);
   ASSERT_OK(context.vmo.write("abcd", 0, 4));
 
-  fidl::BindServer(dispatcher, std::move(endpoints->server),
-                   std::make_unique<TestServer>(&context));
+  fidl::BindServer(dispatcher, std::move(endpoints.server), std::make_unique<TestServer>(&context));
 
   int raw_fd = -1;
-  ASSERT_OK(fdio_fd_create(endpoints->client.channel().release(), &raw_fd));
+  ASSERT_OK(fdio_fd_create(endpoints.client.channel().release(), &raw_fd));
   fbl::unique_fd fd(raw_fd);
 
   // Make sure we can obtain an executable VMO from the underlying fd otherwise the test is invalid.
diff --git a/sdk/lib/fdio/tests/fdio_pty.cc b/sdk/lib/fdio/tests/fdio_pty.cc
index a64248c..b288659 100644
--- a/sdk/lib/fdio/tests/fdio_pty.cc
+++ b/sdk/lib/fdio/tests/fdio_pty.cc
@@ -13,33 +13,30 @@
 namespace fpty = fuchsia_hardware_pty;
 
 TEST(PtyTest, WindowSize) {
-  auto endpoints = fidl::CreateEndpoints<fpty::Device>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fpty::Device>::Create();
 
-  fidl::WireSyncClient client{std::move(endpoints->client)};
+  fidl::WireSyncClient client{std::move(endpoints.client)};
 
   ASSERT_OK(fdio_service_connect(fidl::DiscoverableProtocolDefaultPath<fpty::Device>,
-                                 endpoints->server.channel().release()));
+                                 endpoints.server.channel().release()));
 
-  auto endpoints0 = fidl::CreateEndpoints<fpty::Device>();
-  ASSERT_OK(endpoints0.status_value());
-  auto result0 = client->OpenClient(0, std::move(endpoints0->server));
+  auto endpoints0 = fidl::Endpoints<fpty::Device>::Create();
+  auto result0 = client->OpenClient(0, std::move(endpoints0.server));
   ASSERT_OK(result0.status());
   ASSERT_OK(result0->s);
 
   fbl::unique_fd controlling_client;
-  ASSERT_OK(fdio_fd_create(endpoints0->client.channel().release(),
+  ASSERT_OK(fdio_fd_create(endpoints0.client.channel().release(),
                            controlling_client.reset_and_get_address()));
 
-  auto endpoints1 = fidl::CreateEndpoints<fpty::Device>();
-  ASSERT_OK(endpoints1.status_value());
+  auto endpoints1 = fidl::Endpoints<fpty::Device>::Create();
 
-  auto result1 = client->OpenClient(1, std::move(endpoints1->server));
+  auto result1 = client->OpenClient(1, std::move(endpoints1.server));
   ASSERT_OK(result1.status());
   ASSERT_OK(result1->s);
 
   fbl::unique_fd fd;
-  ASSERT_OK(fdio_fd_create(endpoints1->client.channel().release(), fd.reset_and_get_address()));
+  ASSERT_OK(fdio_fd_create(endpoints1.client.channel().release(), fd.reset_and_get_address()));
 
   struct winsize set_size = {
       .ws_row = 7,
diff --git a/sdk/lib/fdio/tests/fdio_socket.cc b/sdk/lib/fdio/tests/fdio_socket.cc
index 87a2875..499860b 100644
--- a/sdk/lib/fdio/tests/fdio_socket.cc
+++ b/sdk/lib/fdio/tests/fdio_socket.cc
@@ -121,13 +121,12 @@
     ASSERT_OK(zx::socket::create(sock_type, &client_socket, &server_socket_));
     server_.emplace(std::move(client_socket));
 
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_posix_socket::StreamSocket>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_posix_socket::StreamSocket>::Create();
 
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &server_.value());
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &server_.value());
     ASSERT_OK(loop_.StartThread("fake-socket-server"));
     ASSERT_OK(
-        fdio_fd_create(endpoints->client.channel().release(), client_fd_.reset_and_get_address()));
+        fdio_fd_create(endpoints.client.channel().release(), client_fd_.reset_and_get_address()));
   }
 
   const zx::socket& server_socket() { return server_socket_; }
@@ -271,15 +270,15 @@
   const size_t memlength = 65536;
   std::unique_ptr<uint8_t[]> memchunk(new uint8_t[memlength]);
 
-  struct iovec iov[] {
-    {
-        .iov_base = memchunk.get(),
-        .iov_len = memlength,
-    },
-        {
-            .iov_base = memchunk.get(),
-            .iov_len = memlength,
-        },
+  struct iovec iov[]{
+      {
+          .iov_base = memchunk.get(),
+          .iov_len = memlength,
+      },
+      {
+          .iov_base = memchunk.get(),
+          .iov_len = memlength,
+      },
   };
 
   const struct msghdr msg = {
@@ -596,8 +595,8 @@
     const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed);
     const auto timeout_ms = std::chrono::duration_cast<std::chrono::milliseconds>(timeout);
 
-    // TODO(https://fxbug.dev/42116074): Only the lower bound of the elapsed time is checked. The upper bound
-    // check is ignored as the syscall could far miss the defined deadline to return.
+    // TODO(https://fxbug.dev/42116074): Only the lower bound of the elapsed time is checked. The
+    // upper bound check is ignored as the syscall could far miss the defined deadline to return.
     EXPECT_GT(elapsed, timeout - margin, "elapsed=%lld ms (which is not within %lld ms of %lld ms)",
               elapsed_ms.count(), margin.count(), timeout_ms.count());
 
diff --git a/sdk/lib/fdio/tests/fdio_watcher.cc b/sdk/lib/fdio/tests/fdio_watcher.cc
index 38018fe..a37e68c5 100644
--- a/sdk/lib/fdio/tests/fdio_watcher.cc
+++ b/sdk/lib/fdio/tests/fdio_watcher.cc
@@ -50,20 +50,19 @@
 };
 
 TEST(WatcherTest, WatchInvalidCallback) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   Server server([](fuchsia_io::wire::WatchMask mask, uint32_t options,
                    fidl::ServerEnd<fuchsia_io::DirectoryWatcher> watcher,
                    fidl::WireServer<fuchsia_io::Directory>::WatchCompleter::Sync& completer) {});
 
   async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &server);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &server);
   ASSERT_OK(loop.StartThread("fake-directory-server"));
 
   fbl::unique_fd directory;
   ASSERT_OK(
-      fdio_fd_create(endpoints->client.channel().release(), directory.reset_and_get_address()));
+      fdio_fd_create(endpoints.client.channel().release(), directory.reset_and_get_address()));
 
   ASSERT_STATUS(fdio_watch_directory(directory.get(), nullptr, ZX_TIME_INFINITE, nullptr),
                 ZX_ERR_INVALID_ARGS);
@@ -72,8 +71,7 @@
 }
 
 TEST(WatcherTest, Smoke) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   Server server([](fuchsia_io::wire::WatchMask mask, uint32_t options,
                    fidl::ServerEnd<fuchsia_io::DirectoryWatcher> watcher,
@@ -103,12 +101,12 @@
         0, bytes, static_cast<uint32_t>(std::distance(std::begin(bytes), it)), nullptr, 0));
   });
   async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &server);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &server);
   ASSERT_OK(loop.StartThread("fake-directory-server"));
 
   fbl::unique_fd directory;
   ASSERT_OK(
-      fdio_fd_create(endpoints->client.channel().release(), directory.reset_and_get_address()));
+      fdio_fd_create(endpoints.client.channel().release(), directory.reset_and_get_address()));
 
   std::vector<std::pair<int, std::string>> events;
   ASSERT_STATUS(fdio_watch_directory(
diff --git a/sdk/lib/fidl/cpp/coding_traits.h b/sdk/lib/fidl/cpp/coding_traits.h
index 3b4bd62..be4e692 100644
--- a/sdk/lib/fidl/cpp/coding_traits.h
+++ b/sdk/lib/fidl/cpp/coding_traits.h
@@ -29,17 +29,17 @@
 
 template <typename T, class EncoderImpl = Encoder>
 size_t EncodingInlineSize(EncoderImpl* encoder) {
-  return CodingTraits<T>::inline_size_v2;
+  return CodingTraits<T>::kInlineSize;
 }
 
 template <typename T, class DecoderImpl = Decoder>
 size_t DecodingInlineSize(DecoderImpl* decoder) {
-  return CodingTraits<T>::inline_size_v2;
+  return CodingTraits<T>::kInlineSize;
 }
 
 template <typename T>
 struct CodingTraits<T, typename std::enable_if<IsPrimitive<T>::value>::type> {
-  static constexpr size_t inline_size_v2 = sizeof(T);
+  static constexpr size_t kInlineSize = sizeof(T);
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, T* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -54,7 +54,7 @@
 
 template <>
 struct CodingTraits<bool> {
-  static constexpr size_t inline_size_v2 = sizeof(bool);
+  static constexpr size_t kInlineSize = sizeof(bool);
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, bool* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -78,7 +78,7 @@
 #ifdef __Fuchsia__
 template <typename T>
 struct CodingTraits<T, typename std::enable_if<std::is_base_of<zx::object_base, T>::value>::type> {
-  static constexpr size_t inline_size_v2 = sizeof(zx_handle_t);
+  static constexpr size_t kInlineSize = sizeof(zx_handle_t);
   static void Encode(Encoder* encoder, zx::object_base* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
     ZX_ASSERT(maybe_handle_info);
@@ -92,7 +92,7 @@
 
 template <typename T>
 struct CodingTraits<std::unique_ptr<T>, typename std::enable_if<!IsFidlXUnion<T>::value>::type> {
-  static constexpr size_t inline_size_v2 = sizeof(uintptr_t);
+  static constexpr size_t kInlineSize = sizeof(uintptr_t);
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, std::unique_ptr<T>* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -131,7 +131,7 @@
 
 template <typename T>
 struct CodingTraits<VectorPtr<T>> {
-  static constexpr size_t inline_size_v2 = sizeof(fidl_vector_t);
+  static constexpr size_t kInlineSize = sizeof(fidl_vector_t);
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, VectorPtr<T>* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -163,7 +163,7 @@
                       typename std::vector<T>::iterator in_begin,
                       typename std::vector<T>::iterator in_end, size_t out_offset,
                       cpp17::optional<HandleInformation> maybe_handle_info) {
-  static_assert(CodingTraits<T>::inline_size_v2 == sizeof(T), "stride doesn't match object size");
+  static_assert(CodingTraits<T>::kInlineSize == sizeof(T), "stride doesn't match object size");
   std::copy(in_begin, in_end, encoder->template GetPtr<T>(out_offset));
 }
 
@@ -182,7 +182,7 @@
 template <typename T, typename DecoderImpl>
 void DecodeVectorBody(UseStdCopy<true>, DecoderImpl* decoder, size_t in_begin_offset,
                       size_t in_end_offset, std::vector<T>* out, size_t count) {
-  static_assert(CodingTraits<T>::inline_size_v2 == sizeof(T), "stride doesn't match object size");
+  static_assert(CodingTraits<T>::kInlineSize == sizeof(T), "stride doesn't match object size");
   *out = std::vector<T>(decoder->template GetPtr<T>(in_begin_offset),
                         decoder->template GetPtr<T>(in_end_offset));
 }
@@ -203,7 +203,7 @@
 
 template <typename T>
 struct CodingTraits<::std::vector<T>> {
-  static constexpr size_t inline_size_v2 = sizeof(fidl_vector_t);
+  static constexpr size_t kInlineSize = sizeof(fidl_vector_t);
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, ::std::vector<T>* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -227,7 +227,7 @@
 
 template <typename T, size_t N>
 struct CodingTraits<::std::array<T, N>> {
-  static constexpr size_t inline_size_v2 = CodingTraits<T>::inline_size_v2 * N;
+  static constexpr size_t kInlineSize = CodingTraits<T>::kInlineSize * N;
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, std::array<T, N>* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -320,7 +320,7 @@
 
 template <typename T, size_t InlineSizeV2>
 struct EncodableCodingTraits {
-  static constexpr size_t inline_size_v2 = InlineSizeV2;
+  static constexpr size_t kInlineSize = InlineSizeV2;
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, T* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/sdk/lib/fidl/cpp/fidl_cpp.api b/sdk/lib/fidl/cpp/fidl_cpp.api
index 4d463e5..b92505a 100644
--- a/sdk/lib/fidl/cpp/fidl_cpp.api
+++ b/sdk/lib/fidl/cpp/fidl_cpp.api
@@ -19,5 +19,5 @@
   "pkg/fidl_cpp/include/lib/fidl/cpp/service_connector.h": "921dc36b03d9c1854b05ebed40c00644",
   "pkg/fidl_cpp/include/lib/fidl/cpp/service_handler_base.h": "4a422b98568937fae5340575ac8d4303",
   "pkg/fidl_cpp/include/lib/fidl/cpp/type_converter.h": "81ea87e9526f104ff4bbebd502c6a7ec",
-  "pkg/fidl_cpp/include/lib/fidl/cpp/unknown_interactions_hlcpp.h": "1d17b2fa8a4a8dea25af7018c356fb86"
+  "pkg/fidl_cpp/include/lib/fidl/cpp/unknown_interactions_hlcpp.h": "1ae305ebbb47d7b39599e0cc28ff19b5"
 }
\ No newline at end of file
diff --git a/sdk/lib/fidl/cpp/fidl_cpp_base.api b/sdk/lib/fidl/cpp/fidl_cpp_base.api
index de36678b..7b4169e 100644
--- a/sdk/lib/fidl/cpp/fidl_cpp_base.api
+++ b/sdk/lib/fidl/cpp/fidl_cpp_base.api
@@ -1,6 +1,6 @@
 {
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/clone.h": "31478b37b9f6261a75b7f1af13085315",
-  "pkg/fidl_cpp_base/include/lib/fidl/cpp/coding_traits.h": "4314e85a37f21b7844ac6cd488752d68",
+  "pkg/fidl_cpp_base/include/lib/fidl/cpp/coding_traits.h": "2f7d43657d3b2f859f30f8a684f8453c",
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/comparison.h": "83af4784b1593fac21e25504f4309614",
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/decoder.h": "71e01a273e0d4271fabff948a1fc826e",
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/encoder.h": "e54b7c777bf999f36b84c16c36160c7f",
@@ -13,7 +13,7 @@
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/message.h": "2c7c6e6659b61f80b0f8cb556169a01f",
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/message_buffer.h": "cb3870d95b861f5d6b5918bf10354e22",
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/message_part.h": "7e16db0daeeaec2565506d21c32c855a",
-  "pkg/fidl_cpp_base/include/lib/fidl/cpp/string.h": "3cfb8cc0cfd48900f747456ad0e96b69",
+  "pkg/fidl_cpp_base/include/lib/fidl/cpp/string.h": "8cdf4990da1c7c4e800026e67737ab6d",
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/traits.h": "9a662d0b356f8ca126441598fbb7d169",
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/types.h": "56e709911f72250dfe5755dfcc2d1445",
   "pkg/fidl_cpp_base/include/lib/fidl/cpp/vector.h": "4527ff9c4f238110d48fc8c4821b36de"
diff --git a/sdk/lib/fidl/cpp/string.h b/sdk/lib/fidl/cpp/string.h
index 3df89dd..556db5c 100644
--- a/sdk/lib/fidl/cpp/string.h
+++ b/sdk/lib/fidl/cpp/string.h
@@ -184,7 +184,7 @@
 
 template <>
 struct CodingTraits<::std::string> {
-  static constexpr size_t inline_size_v2 = sizeof(fidl_string_t);
+  static constexpr size_t kInlineSize = sizeof(fidl_string_t);
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, std::string* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -207,7 +207,7 @@
 
 template <>
 struct CodingTraits<StringPtr> {
-  static constexpr size_t inline_size_v2 = sizeof(fidl_string_t);
+  static constexpr size_t kInlineSize = sizeof(fidl_string_t);
   template <class EncoderImpl>
   static void Encode(EncoderImpl* encoder, StringPtr* value, size_t offset,
                      cpp17::optional<HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/sdk/lib/fidl/cpp/unknown_interactions_hlcpp.h b/sdk/lib/fidl/cpp/unknown_interactions_hlcpp.h
index 29304d5..d6c2f8d 100644
--- a/sdk/lib/fidl/cpp/unknown_interactions_hlcpp.h
+++ b/sdk/lib/fidl/cpp/unknown_interactions_hlcpp.h
@@ -16,7 +16,7 @@
 
 template <>
 struct CodingTraits<::fidl::internal::FrameworkErr> {
-  static constexpr size_t inline_size_v2 = sizeof(::fidl::internal::FrameworkErr);
+  static constexpr size_t kInlineSize = sizeof(::fidl::internal::FrameworkErr);
   static void Encode(Encoder* encoder, ::fidl::internal::FrameworkErr* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
diff --git a/sdk/lib/fidl/cpp/wire/fidl_cpp_wire.api b/sdk/lib/fidl/cpp/wire/fidl_cpp_wire.api
index 17bd8314..66b301a 100644
--- a/sdk/lib/fidl/cpp/wire/fidl_cpp_wire.api
+++ b/sdk/lib/fidl/cpp/wire/fidl_cpp_wire.api
@@ -19,7 +19,7 @@
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/internal/coding_config.h": "4529b25a9ce027afbe1dd126017dd7c4",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/internal/display_error.h": "80038e1de16a7656aa07dfb771c0faa3",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/internal/endpoints.h": "25c8348ce0383fe56de7f6616dc58910",
-  "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/internal/framework_err.h": "8be26ff0a7f390092c7779f44dd512c7",
+  "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/internal/framework_err.h": "cc1cc6498fca6252fa0a308808be154b",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/internal/intrusive_container/container_utils.h": "8fad0ee8c59bdb15b11dfdb4b3a6d8f6",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/internal/intrusive_container/helper_macros.h": "3ffa5bb490ca497ed5c03588eea23cad",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/internal/intrusive_container/node_utils.h": "27c883068f5ce4f5e24f4c1fc3c483db",
@@ -42,16 +42,16 @@
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/status.h": "40fe0fb1df0033a461f085a47da29b44",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/string_view.h": "df5f64ddd9b92fd49c4291c8d78c5049",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/sync_call.h": "411153007795dc8052c5336fc50d28f7",
-  "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/traits.h": "b5eb525b93dcf52e2619c859bdb88bb8",
+  "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/traits.h": "c3cca16ebfb912748e6acb5773a49c1e",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/transaction.h": "384a258e569f5bc022bd41a32a0782f9",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/unknown_interaction_handler.h": "898a0bccf419a2b6ac51434e95221dea",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/unknown_interactions.h": "84512500e07d5a1e29b4fbd4b2388c03",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/vector_view.h": "9a2124c3259039303565c90351244886",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_coding_common.h": "c2222b134eb065c14f7568695ab345a6",
-  "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_coding_traits.h": "ed7b384316b49cce883abb705c3260dd",
+  "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_coding_traits.h": "ea0840ccae37ae816c92cb0667085906",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_decoder.h": "df97148cc05ecad3e208ee754a45a837",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_encoder.h": "1fa6397c5a1dc207d805a7c6d18a616f",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_messaging.h": "46008354c21f3d47e311213ac75313e7",
   "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_messaging_declarations.h": "766890d0cc9576afe671928d119ac004",
-  "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_types.h": "0584a3608fc05f5163599f21d822495d"
+  "pkg/fidl_cpp_wire/include/lib/fidl/cpp/wire/wire_types.h": "c941ff0368d8875a7aed241fd9572b1b"
 }
\ No newline at end of file
diff --git a/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/internal/framework_err.h b/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/internal/framework_err.h
index 2660ae2..166a9dd 100644
--- a/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/internal/framework_err.h
+++ b/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/internal/framework_err.h
@@ -20,8 +20,8 @@
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::fidl::internal::FrameworkErr,
                                   ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(int32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(int32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::FrameworkErr* value,
                      ::fidl::internal::WirePosition position,
diff --git a/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/traits.h b/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/traits.h
index a78b48a..84c8fd6 100644
--- a/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/traits.h
+++ b/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/traits.h
@@ -350,8 +350,8 @@
       return ZX_CHANNEL_MAX_MSG_BYTES;
     }
   }
-  uint64_t primary = FidlAlign(TypeTraits<FidlType>::kPrimarySize);
-  uint64_t out_of_line = FidlAlign(TypeTraits<FidlType>::kMaxOutOfLine);
+  uint64_t primary = FIDL_ALIGN(TypeTraits<FidlType>::kPrimarySize);
+  uint64_t out_of_line = FIDL_ALIGN(TypeTraits<FidlType>::kMaxOutOfLine);
   uint64_t sum = primary + out_of_line;
   if (sum > ZX_CHANNEL_MAX_MSG_BYTES) {
     return ZX_CHANNEL_MAX_MSG_BYTES;
diff --git a/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/wire_coding_traits.h b/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/wire_coding_traits.h
index 43b0e19..161087e 100644
--- a/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/wire_coding_traits.h
+++ b/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/wire_coding_traits.h
@@ -63,7 +63,7 @@
 
 template <typename T, typename Constraint, bool IsRecursive>
 constexpr bool WireIsMemcpyCompatible() {
-  return WireCodingTraits<T, Constraint, IsRecursive>::is_memcpy_compatible;
+  return WireCodingTraits<T, Constraint, IsRecursive>::kIsMemcpyCompatible;
 }
 
 template <typename MaskType>
@@ -81,8 +81,8 @@
 template <typename T, bool IsRecursive>
 struct WireCodingTraits<T, WireCodingConstraintEmpty, IsRecursive,
                         std::enable_if_t<IsPrimitive<T>::value>> {
-  static constexpr size_t inline_size = sizeof(T);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(T);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(WireEncoder* encoder, T* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -94,8 +94,8 @@
 
 template <bool IsRecursive>
 struct WireCodingTraits<bool, WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(bool);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(bool);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(WireEncoder* encoder, const bool* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -131,7 +131,7 @@
     }
     using InnerConstraint = typename Constraint::Inner;
     if constexpr (WireIsMemcpyCompatible<T, InnerConstraint, IsRecursive>()) {
-      constexpr size_t stride = WireCodingTraits<T, InnerConstraint, IsRecursive>::inline_size;
+      constexpr size_t stride = WireCodingTraits<T, InnerConstraint, IsRecursive>::kInlineSize;
       static_assert(stride <= std::numeric_limits<uint32_t>::max(),
                     "assume 32-bit stride to reduce checks");
       encoder->EncodeMemcpyableVector(data, count, stride);
@@ -143,7 +143,7 @@
   template <typename T, typename InnerConstraint>
   static void EncodeEachElement(WireEncoder* encoder, T* data, size_t count, WirePosition position,
                                 RecursionDepth<IsRecursive> recursion_depth) {
-    constexpr size_t stride = WireCodingTraits<T, InnerConstraint, IsRecursive>::inline_size;
+    constexpr size_t stride = WireCodingTraits<T, InnerConstraint, IsRecursive>::kInlineSize;
     static_assert(stride <= std::numeric_limits<uint32_t>::max(),
                   "assume 32-bit stride to reduce checks");
 
@@ -204,7 +204,7 @@
     if (!inner_depth.IsValid()) {
       return;
     }
-    constexpr size_t stride = WireCodingTraits<T, InnerConstraint, IsRecursive>::inline_size;
+    constexpr size_t stride = WireCodingTraits<T, InnerConstraint, IsRecursive>::kInlineSize;
     static_assert(stride <= std::numeric_limits<uint32_t>::max(),
                   "assume 32-bit stride to reduce checks");
     fidl_vector_t* encoded = position.As<fidl_vector_t>();
@@ -257,8 +257,8 @@
 
 template <typename T, typename Constraint, bool IsRecursive>
 struct WireCodingTraits<fidl::VectorView<T>, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(fidl_vector_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fidl_vector_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(WireEncoder* encoder, fidl::VectorView<T>* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -274,8 +274,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct WireCodingTraits<fidl::StringView, Constraint, IsRecursive> final {
-  static constexpr size_t inline_size = sizeof(fidl_string_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fidl_string_t);
+  static constexpr bool kIsMemcpyCompatible = false;
   using StringVectorConstraint =
       WireCodingConstraintVector<WireCodingConstraintEmpty, Constraint::is_optional,
                                  Constraint::limit>;
@@ -309,15 +309,15 @@
 
 template <typename T, size_t N, typename Constraint, bool IsRecursive>
 struct WireCodingTraits<fidl::Array<T, N>, Constraint, IsRecursive> {
-  static constexpr size_t inline_size =
-      WireCodingTraits<T, Constraint, IsRecursive>::inline_size * N;
-  static constexpr bool is_memcpy_compatible =
-      WireCodingTraits<T, Constraint, IsRecursive>::is_memcpy_compatible;
+  static constexpr size_t kInlineSize =
+      WireCodingTraits<T, Constraint, IsRecursive>::kInlineSize * N;
+  static constexpr bool kIsMemcpyCompatible =
+      WireCodingTraits<T, Constraint, IsRecursive>::kIsMemcpyCompatible;
 
   static void Encode(WireEncoder* encoder, fidl::Array<T, N>* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
-    constexpr size_t stride = WireCodingTraits<T, Constraint, IsRecursive>::inline_size;
-    if constexpr (is_memcpy_compatible) {
+    constexpr size_t stride = WireCodingTraits<T, Constraint, IsRecursive>::kInlineSize;
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), &value[0], N * stride);
     } else {
       for (size_t i = 0; i < N; ++i) {
@@ -328,8 +328,8 @@
   }
   static void Decode(WireDecoder* decoder, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
-    constexpr size_t stride = WireCodingTraits<T, Constraint, IsRecursive>::inline_size;
-    if constexpr (!is_memcpy_compatible) {
+    constexpr size_t stride = WireCodingTraits<T, Constraint, IsRecursive>::kInlineSize;
+    if constexpr (!kIsMemcpyCompatible) {
       for (size_t i = 0; i < N; ++i) {
         WireCodingTraits<T, Constraint, IsRecursive>::Decode(decoder, position + i * stride,
                                                              recursion_depth);
@@ -342,8 +342,8 @@
 template <typename T, typename Constraint, bool IsRecursive>
 struct WireCodingTraits<T, Constraint, IsRecursive,
                         std::enable_if_t<std::is_base_of_v<zx::object_base, T>>> {
-  static constexpr size_t inline_size = sizeof(zx_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(zx_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(WireEncoder* encoder, zx::object_base* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -368,8 +368,8 @@
 
 template <typename T, typename Constraint, bool IsRecursive>
 struct WireCodingTraits<fidl::ObjectView<T>, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uintptr_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uintptr_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(WireEncoder* encoder, fidl::ObjectView<T>* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -385,7 +385,7 @@
 
     *position.As<uintptr_t>() = FIDL_ALLOC_PRESENT;
 
-    constexpr size_t alloc_size = WireCodingTraits<T, Constraint, IsRecursive>::inline_size;
+    constexpr size_t alloc_size = WireCodingTraits<T, Constraint, IsRecursive>::kInlineSize;
     WirePosition body;
     if (unlikely(!encoder->Alloc(alloc_size, &body))) {
       return;
@@ -409,7 +409,7 @@
     if (!inner_depth.IsValid()) {
       return;
     }
-    constexpr size_t alloc_size = WireCodingTraits<T, Constraint, IsRecursive>::inline_size;
+    constexpr size_t alloc_size = WireCodingTraits<T, Constraint, IsRecursive>::kInlineSize;
     WirePosition body;
     if (unlikely(!decoder->Alloc(alloc_size, &body))) {
       return;
@@ -425,8 +425,8 @@
   using MemberTrait = WireCodingTraits<T, Constraint, IsRecursive>;
 
  public:
-  static constexpr size_t inline_size = MemberTrait::inline_size;
-  static constexpr bool is_memcpy_compatible = MemberTrait::is_memcpy_compatible;
+  static constexpr size_t kInlineSize = MemberTrait::kInlineSize;
+  static constexpr bool kIsMemcpyCompatible = MemberTrait::kIsMemcpyCompatible;
 
   static void Encode(internal::WireEncoder* encoder, fidl::WireOptional<T>* value,
                      fidl::internal::WirePosition position,
@@ -443,8 +443,8 @@
 #ifdef __Fuchsia__
 template <typename T, typename Constraint, bool IsRecursive>
 struct WireCodingTraits<ClientEnd<T>, Constraint, IsRecursive> {
-  static constexpr bool is_memcpy_compatible = false;
-  static constexpr size_t inline_size = sizeof(zx_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
+  static constexpr size_t kInlineSize = sizeof(zx_handle_t);
 
   static void Encode(WireEncoder* encoder, ClientEnd<T>* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -469,8 +469,8 @@
 
 template <typename T, typename Constraint, bool IsRecursive>
 struct WireCodingTraits<ServerEnd<T>, Constraint, IsRecursive> {
-  static constexpr bool is_memcpy_compatible = false;
-  static constexpr size_t inline_size = sizeof(zx_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
+  static constexpr size_t kInlineSize = sizeof(zx_handle_t);
 
   static void Encode(WireEncoder* encoder, ServerEnd<T>* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -517,7 +517,7 @@
   static constexpr bool kIsRecursive = IsRecursive;
 };
 
-// In order to prevent cyclic dependency issues computing is_memcpy_compatible, perform the
+// In order to prevent cyclic dependency issues computing kIsMemcpyCompatible, perform the
 // computation in a base class.
 template <typename T, typename Constraint, bool IsRecursive>
 struct WireStructCodingTraitsBase {
@@ -525,9 +525,9 @@
       WireCodingTraits<T, Constraint, IsRecursive>::kMembers, [](auto coding_info) {
         return WireCodingTraits<typename decltype(coding_info)::Field,
                                 typename decltype(coding_info)::Constraint,
-                                decltype(coding_info)::kIsRecursive>::is_memcpy_compatible;
+                                decltype(coding_info)::kIsRecursive>::kIsMemcpyCompatible;
       });
-  static constexpr bool is_memcpy_compatible =
+  static constexpr bool kIsMemcpyCompatible =
       are_members_memcpy_compatible && !WireCodingTraits<T, Constraint, IsRecursive>::kHasPadding;
 };
 
diff --git a/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/wire_types.h b/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/wire_types.h
index 0fc47c2..04c8d49 100644
--- a/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/wire_types.h
+++ b/sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/wire_types.h
@@ -79,7 +79,7 @@
 // declaration only for wire types.
 template <typename FidlType>
 using EnableIfWireType =
-    std::enable_if_t<static_cast<bool>(internal::TopLevelCodingTraits<FidlType>::inline_size)>*;
+    std::enable_if_t<static_cast<bool>(internal::TopLevelCodingTraits<FidlType>::kInlineSize)>*;
 
 // The wire format version used when encoding.
 constexpr WireFormatVersion kLLCPPWireFormatVersion = WireFormatVersion::kV2;
@@ -212,7 +212,7 @@
                 UnownedEncodedMessageHandleContainer::handle_metadata_storage_.data()),
             UnownedEncodedMessageHandleContainer::kNumHandles,
             fidl::IsFidlTransactionalMessage<FidlType>::value, value,
-            internal::TopLevelCodingTraits<FidlType>::inline_size,
+            internal::TopLevelCodingTraits<FidlType>::kInlineSize,
             internal::MakeTopLevelEncodeFn<FidlType>()) {}
 
   UnownedEncodedMessage(const UnownedEncodedMessage&) = delete;
@@ -365,7 +365,7 @@
     EncodedMessage message, WireFormatMetadata metadata) {
   static_assert(IsFidlType<FidlType>::value, "Only FIDL types are supported");
 
-  size_t inline_size = internal::TopLevelCodingTraits<FidlType>::inline_size;
+  size_t inline_size = internal::TopLevelCodingTraits<FidlType>::kInlineSize;
   const internal::TopLevelDecodeFn decode_fn = internal::MakeTopLevelDecodeFn<FidlType>();
   const Status status = internal::WireDecode(metadata, inline_size, decode_fn, message);
 
diff --git a/sdk/lib/fidl_base/fidl_base.api b/sdk/lib/fidl_base/fidl_base.api
index b87a64e..1dda5638 100644
--- a/sdk/lib/fidl_base/fidl_base.api
+++ b/sdk/lib/fidl_base/fidl_base.api
@@ -3,9 +3,9 @@
   "pkg/fidl_base/include/lib/fidl/cpp/framework_err.h": "ee007523d29da60714f88fa86db4050c",
   "pkg/fidl_base/include/lib/fidl/cpp/transaction_header.h": "5e248521f37cc00b1a316b1d040c5a64",
   "pkg/fidl_base/include/lib/fidl/cpp/wire_format_metadata.h": "8883ce53a48eb97e3b1d03ff96dfde14",
-  "pkg/fidl_base/include/lib/fidl/internal.h": "70fe5504048cba205e42b6bde31768b0",
+  "pkg/fidl_base/include/lib/fidl/internal.h": "94bb4175709f7dd88facb7ea8bc3c98d",
   "pkg/fidl_base/include/lib/fidl/internal_callable_traits.h": "a18e97bafa2f7e388422a7e721d6421d",
   "pkg/fidl_base/include/lib/fidl/txn_header.h": "93ee43628aa6d571620a3615ed5b109a",
   "pkg/fidl_base/include/lib/fidl/visitor.h": "78056e9e6f4ae10b22480e8bf2c5304d",
-  "pkg/fidl_base/include/lib/fidl/walker.h": "b33646e6cca77412dbf70dddc1284a50"
+  "pkg/fidl_base/include/lib/fidl/walker.h": "54f5ccdce97e4db6360673586eb6381f"
 }
\ No newline at end of file
diff --git a/sdk/lib/fidl_base/include/lib/fidl/internal.h b/sdk/lib/fidl_base/include/lib/fidl/internal.h
index 8256f76..ebb7989 100644
--- a/sdk/lib/fidl_base/include/lib/fidl/internal.h
+++ b/sdk/lib/fidl_base/include/lib/fidl/internal.h
@@ -95,18 +95,6 @@
 static const FidlEmpty kFidlEmpty_IsNotEmpty = false;
 static const FidlEmpty kFidlEmpty_IsEmpty = true;
 
-// TODO(https://fxbug.dev/42119024): Remove either this FidlAlign function or the FIDL_ALIGN macro in
-// zircon/fidl.h.
-// clang-format off
-#ifdef __cplusplus
-constexpr
-#endif  // __cplusplus
-static inline uint64_t FidlAlign(uint32_t offset) {
-  const uint64_t alignment_mask = FIDL_ALIGNMENT - 1;
-  return (offset + alignment_mask) & ~alignment_mask;
-}
-// clang-format on
-
 // Determine if the pointer is aligned to |FIDL_ALIGNMENT|.
 static inline bool FidlIsAligned(const uint8_t* ptr) {
   uintptr_t uintptr = (uintptr_t)(ptr);
@@ -297,7 +285,8 @@
 static const uint8_t kFidlTypeXUnion = 10;
 static const uint8_t kFidlTypeUnion = 10;
 
-// TODO(https://fxbug.dev/42119025): Consider starting enum values for FidlCodedPrimitive from 1, not 0.
+// TODO(https://fxbug.dev/42119025): Consider starting enum values for FidlCodedPrimitive from 1,
+// not 0.
 typedef uint8_t FidlCodedPrimitiveSubtype;
 static const uint8_t kFidlCodedPrimitiveSubtype_Bool = 0;
 static const uint8_t kFidlCodedPrimitiveSubtype_Int8 = 1;
@@ -366,9 +355,7 @@
 #endif
 };
 
-#define FIDL_INTERNAL_INHERIT_TYPE_T \
-  final:                             \
-  fidl_type
+#define FIDL_INTERNAL_INHERIT_TYPE_T final : fidl_type
 
 #else  // __cplusplus
 
diff --git a/sdk/lib/fidl_base/include/lib/fidl/walker.h b/sdk/lib/fidl_base/include/lib/fidl/walker.h
index d5385ec..03f20f8 100644
--- a/sdk/lib/fidl_base/include/lib/fidl/walker.h
+++ b/sdk/lib/fidl_base/include/lib/fidl/walker.h
@@ -785,7 +785,7 @@
   }
   *out_primary_size = static_cast<uint32_t>(primary_size);
 
-  uint64_t first_out_of_line = FidlAlign(static_cast<uint32_t>(primary_size));
+  uint64_t first_out_of_line = FIDL_ALIGN(static_cast<uint32_t>(primary_size));
   if (unlikely(first_out_of_line > buffer_size)) {
     set_error("Buffer is too small for first inline object");
     return ZX_ERR_BUFFER_TOO_SMALL;
diff --git a/sdk/lib/fidl_driver/fidl_driver.api b/sdk/lib/fidl_driver/fidl_driver.api
index f54fd3b..f586d10 100644
--- a/sdk/lib/fidl_driver/fidl_driver.api
+++ b/sdk/lib/fidl_driver/fidl_driver.api
@@ -7,5 +7,5 @@
   "pkg/fidl_driver/include/lib/fidl_driver/cpp/wire_client.h": "ef3b1e2f622719c4f36fcfd358bba41c",
   "pkg/fidl_driver/include/lib/fidl_driver/cpp/wire_messaging.h": "aa776fcb98e4dd12f5cfaf0d4f133f51",
   "pkg/fidl_driver/include/lib/fidl_driver/cpp/wire_messaging_declarations.h": "130dc732f4ef530a1eac5f653d79f479",
-  "pkg/fidl_driver/include/lib/fidl_driver/cpp/wire_types.h": "6b411d84e35356fc26d5b4cbcb7a42ee"
+  "pkg/fidl_driver/include/lib/fidl_driver/cpp/wire_types.h": "2772a7fb779790836e42426238478b4e"
 }
\ No newline at end of file
diff --git a/sdk/lib/fidl_driver/fidl_driver_natural.api b/sdk/lib/fidl_driver/fidl_driver_natural.api
index cedec28..3b6b529 100644
--- a/sdk/lib/fidl_driver/fidl_driver_natural.api
+++ b/sdk/lib/fidl_driver/fidl_driver_natural.api
@@ -4,6 +4,6 @@
   "pkg/fidl_driver_natural/include/lib/fidl_driver/cpp/natural_client.h": "2164c047b98feb599aea3644f910e2aa",
   "pkg/fidl_driver_natural/include/lib/fidl_driver/cpp/natural_messaging.h": "999631bf78bac0241a45ba0c7188a6c3",
   "pkg/fidl_driver_natural/include/lib/fidl_driver/cpp/natural_ostream.h": "e8635be977fc904842459517166da5db",
-  "pkg/fidl_driver_natural/include/lib/fidl_driver/cpp/natural_types.h": "cae0a38844add89d42a127207809ee8d",
+  "pkg/fidl_driver_natural/include/lib/fidl_driver/cpp/natural_types.h": "abee67582cca393cac62d94ec961f7f3",
   "pkg/fidl_driver_natural/include/lib/fidl_driver/cpp/unified_messaging_declarations.h": "54d9cfb48a9628b511ae61c1107132d6"
 }
\ No newline at end of file
diff --git a/sdk/lib/fidl_driver/include/lib/fidl_driver/cpp/natural_types.h b/sdk/lib/fidl_driver/include/lib/fidl_driver/cpp/natural_types.h
index cef91e7..d932513 100644
--- a/sdk/lib/fidl_driver/include/lib/fidl_driver/cpp/natural_types.h
+++ b/sdk/lib/fidl_driver/include/lib/fidl_driver/cpp/natural_types.h
@@ -14,9 +14,8 @@
 
 template <typename Constraint>
 struct NaturalCodingTraits<::fdf::Channel, Constraint> {
-  static constexpr size_t inline_size_v1_no_ee = sizeof(fdf_handle_t);
-  static constexpr size_t inline_size_v2 = sizeof(fdf_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fdf_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, ::fdf::Channel* value, size_t offset,
                      size_t recursion_depth) {
@@ -33,9 +32,8 @@
 
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<::fdf::ServerEnd<T>, Constraint> {
-  static constexpr size_t inline_size_v1_no_ee = sizeof(fdf_handle_t);
-  static constexpr size_t inline_size_v2 = sizeof(fdf_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fdf_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, ::fdf::ServerEnd<T>* value, size_t offset,
                      size_t recursion_depth) {
@@ -52,9 +50,8 @@
 
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<::fdf::ClientEnd<T>, Constraint> {
-  static constexpr size_t inline_size_v1_no_ee = sizeof(fdf_handle_t);
-  static constexpr size_t inline_size_v2 = sizeof(fdf_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fdf_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, ::fdf::ClientEnd<T>* value, size_t offset,
                      size_t recursion_depth) {
diff --git a/sdk/lib/fidl_driver/include/lib/fidl_driver/cpp/wire_types.h b/sdk/lib/fidl_driver/include/lib/fidl_driver/cpp/wire_types.h
index 1799d71..4a6d991 100644
--- a/sdk/lib/fidl_driver/include/lib/fidl_driver/cpp/wire_types.h
+++ b/sdk/lib/fidl_driver/include/lib/fidl_driver/cpp/wire_types.h
@@ -13,8 +13,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct WireCodingTraits<::fdf::Channel, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(fdf_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fdf_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(WireEncoder* encoder, ::fdf::Channel* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -29,8 +29,8 @@
 
 template <typename T, typename Constraint, bool IsRecursive>
 struct WireCodingTraits<::fdf::ServerEnd<T>, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(fdf_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fdf_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(WireEncoder* encoder, ::fdf::ServerEnd<T>* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
@@ -45,8 +45,8 @@
 
 template <typename T, typename Constraint, bool IsRecursive>
 struct WireCodingTraits<::fdf::ClientEnd<T>, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(fdf_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fdf_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(WireEncoder* encoder, ::fdf::ClientEnd<T>* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
diff --git a/sdk/lib/fidl_driver/tests/coding/coding_test.cc b/sdk/lib/fidl_driver/tests/coding/coding_test.cc
index 6cdba01..16c9ed4 100644
--- a/sdk/lib/fidl_driver/tests/coding/coding_test.cc
+++ b/sdk/lib/fidl_driver/tests/coding/coding_test.cc
@@ -32,23 +32,22 @@
   ASSERT_OK(zx::channel::create(0, &zircon_handle_1, &zircon_handle_2));
   zx::result driver_handles = fdf::ChannelPair::Create(0);
   ASSERT_OK(driver_handles.status_value());
-  zx::result zircon_endpoints = fidl::CreateEndpoints<test_driver_coding::ZirconChannelProtocol>();
-  ASSERT_OK(zircon_endpoints.status_value());
+  auto zircon_endpoints = fidl::Endpoints<test_driver_coding::ZirconChannelProtocol>::Create();
   zx::result driver_endpoints = fdf::CreateEndpoints<test_driver_coding::DriverChannelProtocol>();
   ASSERT_OK(driver_endpoints.status_value());
 
   zx_handle_t expected_zircon_handle = zircon_handle_1.get();
   fdf_handle_t expected_driver_handle = driver_handles->end0.get();
-  zx_handle_t expected_zircon_client_end = zircon_endpoints->client.handle()->get();
-  zx_handle_t expected_zircon_server_end = zircon_endpoints->server.handle()->get();
+  zx_handle_t expected_zircon_client_end = zircon_endpoints.client.handle()->get();
+  zx_handle_t expected_zircon_server_end = zircon_endpoints.server.handle()->get();
   fdf_handle_t expected_driver_client_end = driver_endpoints->client.handle()->get();
   fdf_handle_t expected_driver_server_end = driver_endpoints->server.handle()->get();
 
   test_driver_coding::MixedResources obj{{
       .zircon_handle = std::move(zircon_handle_1),
       .driver_handle = std::move(driver_handles->end0),
-      .zircon_client_end = std::move(zircon_endpoints->client),
-      .zircon_server_end = std::move(zircon_endpoints->server),
+      .zircon_client_end = std::move(zircon_endpoints.client),
+      .zircon_server_end = std::move(zircon_endpoints.server),
       .driver_client_end = std::move(driver_endpoints->client),
       .driver_server_end = std::move(driver_endpoints->server),
   }};
@@ -82,15 +81,14 @@
   ASSERT_OK(zx::channel::create(0, &zircon_handle_1, &zircon_handle_2));
   zx::result driver_handles = fdf::ChannelPair::Create(0);
   ASSERT_OK(driver_handles.status_value());
-  zx::result zircon_endpoints = fidl::CreateEndpoints<test_driver_coding::ZirconChannelProtocol>();
-  ASSERT_OK(zircon_endpoints.status_value());
+  auto zircon_endpoints = fidl::Endpoints<test_driver_coding::ZirconChannelProtocol>::Create();
   zx::result driver_endpoints = fdf::CreateEndpoints<test_driver_coding::DriverChannelProtocol>();
   ASSERT_OK(driver_endpoints.status_value());
 
   zx_handle_t expected_zircon_handle = zircon_handle_1.release();
   fdf_handle_t expected_driver_handle = driver_handles->end0.release();
-  zx_handle_t expected_zircon_client_end = zircon_endpoints->client.TakeHandle().release();
-  zx_handle_t expected_zircon_server_end = zircon_endpoints->server.TakeHandle().release();
+  zx_handle_t expected_zircon_client_end = zircon_endpoints.client.TakeHandle().release();
+  zx_handle_t expected_zircon_server_end = zircon_endpoints.server.TakeHandle().release();
   fdf_handle_t expected_driver_client_end = driver_endpoints->client.TakeHandle().release();
   fdf_handle_t expected_driver_server_end = driver_endpoints->server.TakeHandle().release();
 
diff --git a/sdk/lib/fit-promise/BUILD.gn b/sdk/lib/fit-promise/BUILD.gn
index 10c0405..7ce1ebc 100644
--- a/sdk/lib/fit-promise/BUILD.gn
+++ b/sdk/lib/fit-promise/BUILD.gn
@@ -6,7 +6,7 @@
 
 zx_library("fit-promise") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
 
   sdk_headers = [
     "lib/fpromise/barrier.h",
diff --git a/sdk/lib/fit/BUILD.gn b/sdk/lib/fit/BUILD.gn
index 6908070..1fa1cd3 100644
--- a/sdk/lib/fit/BUILD.gn
+++ b/sdk/lib/fit/BUILD.gn
@@ -6,7 +6,7 @@
 
 zx_library("fit") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [
     "lib/fit/defer.h",
     "lib/fit/function.h",
diff --git a/sdk/lib/input_report_reader/reader_unittest.cc b/sdk/lib/input_report_reader/reader_unittest.cc
index 2ad1d76..3f4574d 100644
--- a/sdk/lib/input_report_reader/reader_unittest.cc
+++ b/sdk/lib/input_report_reader/reader_unittest.cc
@@ -114,9 +114,7 @@
 class InputReportReaderTests : public zxtest::Test {
   void SetUp() override {
     ASSERT_EQ(mouse_.Start(), ZX_OK);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputDevice>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputDevice>::Create();
     auto result = fidl::BindServer(loop_.dispatcher(), std::move(server), &mouse_);
     input_device_ = fidl::WireSyncClient<fuchsia_input_report::InputDevice>(std::move(client));
     ASSERT_EQ(loop_.StartThread("MouseDeviceThread"), ZX_OK);
@@ -134,9 +132,7 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
     (void)input_device_->GetInputReportsReader(std::move(server));
     reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(client));
@@ -148,9 +144,7 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
     (void)input_device_->GetInputReportsReader(std::move(server));
     reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(client));
@@ -188,9 +182,7 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
     (void)input_device_->GetInputReportsReader(std::move(server));
     reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(client));
@@ -219,9 +211,7 @@
   // Get the first reader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader_one;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
     (void)input_device_->GetInputReportsReader(std::move(server));
     reader_one = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(client));
@@ -231,9 +221,7 @@
   // Get the second reader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader_two;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
     (void)input_device_->GetInputReportsReader(std::move(server));
     reader_two = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(client));
@@ -297,9 +285,7 @@
   // Get an async InputReportsReader.
   fidl::WireClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
     (void)input_device_->GetInputReportsReader(std::move(server));
     reader.Bind(std::move(client), loop.dispatcher());
@@ -344,9 +330,7 @@
   // Get an async InputReportsReader.
   fidl::WireClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
     (void)input_device_->GetInputReportsReader(std::move(server));
     reader.Bind(std::move(client), loop.dispatcher());
@@ -367,9 +351,7 @@
 TEST_F(InputReportReaderTests, MaxUnreadReports) {
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     ASSERT_TRUE(input_device_->GetInputReportsReader(std::move(server)).ok());
     reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(client));
     mouse_.WaitForNextReader(zx::duration::infinite());
@@ -411,9 +393,7 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
     // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
     (void)input_device_->GetInputReportsReader(std::move(server));
     reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(client));
diff --git a/sdk/lib/ld/test/BUILD.gn b/sdk/lib/ld/test/BUILD.gn
index ee17f26..47479d0 100644
--- a/sdk/lib/ld/test/BUILD.gn
+++ b/sdk/lib/ld/test/BUILD.gn
@@ -103,7 +103,6 @@
   ]
   if (is_fuchsia) {
     sources += [
-      "ld-load-zircon-ldsvc-tests-base.cc",
       "ld-load-zircon-ldsvc-tests-base.h",
       "ld-load-zircon-process-tests-base.cc",
       "ld-load-zircon-process-tests-base.h",
@@ -260,6 +259,7 @@
     "./*",
     "//sdk/lib/dl/test/*",
     "//sdk/lib/ld/test/*",
+    "//sdk/lib/ld/testing/*",
   ]
   testonly = true
 
diff --git a/sdk/lib/ld/test/ld-load-tests-base.cc b/sdk/lib/ld/test/ld-load-tests-base.cc
index f104d7c..ff9ee7b 100644
--- a/sdk/lib/ld/test/ld-load-tests-base.cc
+++ b/sdk/lib/ld/test/ld-load-tests-base.cc
@@ -56,6 +56,8 @@
     if (found) {
       ASSERT_TRUE(elfldltl::testing::GetTestLib(name)) << name;
     }
+    // TODO(https://fxbug.dev/323419430): This can use TryGetTestLib to assert
+    // that the file does not exist.
   }
 }
 
diff --git a/sdk/lib/ld/test/ld-load-zircon-ldsvc-tests-base.cc b/sdk/lib/ld/test/ld-load-zircon-ldsvc-tests-base.cc
deleted file mode 100644
index 44dffad..0000000
--- a/sdk/lib/ld/test/ld-load-zircon-ldsvc-tests-base.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ld-load-zircon-ldsvc-tests-base.h"
-
-#include <lib/elfldltl/testing/get-test-data.h>
-
-namespace ld::testing {
-
-constexpr std::string_view kLibprefix = LD_TEST_LIBPREFIX;
-
-LdLoadZirconLdsvcTestsBase::~LdLoadZirconLdsvcTestsBase() = default;
-
-void LdLoadZirconLdsvcTestsBase::LdsvcExpectConfig(std::string_view config) {
-  ASSERT_NO_FATAL_FAILURE(ReadyMock());
-  mock_.ExpectConfig(config, zx::ok());
-}
-
-void LdLoadZirconLdsvcTestsBase::LdsvcExpectLoadObject(std::string_view name,
-                                                       zx::result<zx::vmo> result) {
-  ASSERT_NO_FATAL_FAILURE(ReadyMock());
-  mock_.ExpectLoadObject(name, std::move(result));
-}
-
-void LdLoadZirconLdsvcTestsBase::LdsvcExpectLoadObject(std::string_view name) {
-  // TODO(https://fxbug.dev/42084623): We should add a LdsvcExpectConfig when the dynamic linker starts doing
-  // so.
-  const std::string path = std::filesystem::path("test") / "lib" / kLibprefix / name;
-  zx::vmo vmo;
-  ASSERT_NO_FATAL_FAILURE(vmo = elfldltl::testing::GetTestLibVmo(path));
-  LdsvcExpectLoadObject(name, zx::ok(std::move(vmo)));
-}
-
-void LdLoadZirconLdsvcTestsBase::ReadyMock() {
-  if (!mock_.Ready()) {
-    ASSERT_NO_FATAL_FAILURE(mock_.Init());
-  }
-}
-
-}  // namespace ld::testing
diff --git a/sdk/lib/ld/test/ld-load-zircon-ldsvc-tests-base.h b/sdk/lib/ld/test/ld-load-zircon-ldsvc-tests-base.h
index 6ff6a24..fb010bd 100644
--- a/sdk/lib/ld/test/ld-load-zircon-ldsvc-tests-base.h
+++ b/sdk/lib/ld/test/ld-load-zircon-ldsvc-tests-base.h
@@ -5,6 +5,7 @@
 #ifndef LIB_LD_TEST_LD_LOAD_ZIRCON_LDSVC_TESTS_BASE_H_
 #define LIB_LD_TEST_LD_LOAD_ZIRCON_LDSVC_TESTS_BASE_H_
 
+#include <lib/elfldltl/testing/get-test-data.h>
 #include <lib/ld/testing/mock-loader-service.h>
 #include <lib/zx/result.h>
 #include <lib/zx/vmo.h>
@@ -17,57 +18,42 @@
 namespace ld::testing {
 
 // This is the common base class for test fixtures that use a
-// fuchsia.ldsvc.Loader service.
+// fuchsia.ldsvc.Loader service and set expectations for the dependencies
+// loaded by it. This class proxies calls to the MockLoaderServiceForTest and
+// passes the function it should use to retrieve test VMO files.
 //
 // It takes calls giving ordered expectations for Loader service requests from
 // the process under test.  These must be used after Load() and before Run()
 // in test cases.
 class LdLoadZirconLdsvcTestsBase : public LdLoadTestsBase {
  public:
-  ~LdLoadZirconLdsvcTestsBase();
+  ~LdLoadZirconLdsvcTestsBase() = default;
 
   // Expect the dynamic linker to send a Config(config) message.
-  void LdsvcExpectConfig(std::string_view config);
+  void LdsvcExpectConfig(std::string_view config) { mock_.ExpectConfig(config); }
 
   // Expect the dynamic linker to send a LoadObject(name) request, and return
   // the given VMO (or error).
-  void LdsvcExpectLoadObject(std::string_view name, zx::result<zx::vmo> result);
-
-  // This is shorthand for LdsvcExpectLoadObject with the VMO acquired from
-  // elfldltl::testing::GetTestLibVmo.
-  void LdsvcExpectLoadObject(std::string_view name);
-
-  // This just is a shorthand for multiple LdsvcExpectLoadObject calls.
-  void Needed(std::initializer_list<std::string_view> names) {
-    for (std::string_view name : names) {
-      LdsvcExpectLoadObject(name);
-    }
+  void LdsvcExpectLoadObject(std::string_view name, zx::result<zx::vmo> result) {
+    mock_.ExpectLoadObject(name, std::move(result));
   }
 
-  // This just is a shorthand for multiple LdsvcExpectLoadObject calls.
+  // Prime the MockLoaderService with the VMO for a dependency by name,
+  // and expect the MockLoader to load that dependency for the test.
+  void LdsvcExpectDependency(std::string_view name) { mock_.ExpectDependency(name); }
+
+  // This just is a shorthand for multiple LdsvcExpectDependency  calls.
+  void Needed(std::initializer_list<std::string_view> names) { mock_.Needed(names); }
+
+  // This just is a shorthand for multiple LdsvcExpectDependency  calls.
   void Needed(std::initializer_list<std::pair<std::string_view, bool>> name_found_pairs) {
-    for (auto [name, found] : name_found_pairs) {
-      if (found) {
-        LdsvcExpectLoadObject(name);
-      } else {
-        LdsvcExpectLoadObject(name, zx::error{ZX_ERR_NOT_FOUND});
-      }
-    }
+    mock_.Needed(name_found_pairs);
   }
 
- protected:
-  zx::channel GetLdsvc() {
-    zx::channel ldsvc;
-    if (mock_.Ready()) {
-      ldsvc = mock_.client().TakeChannel();
-    }
-    return ldsvc;
-  }
+  zx::channel TakeLdsvc() { return mock_.TakeLdsvc(); }
 
  private:
-  void ReadyMock();
-
-  MockLoaderService mock_;
+  MockLoaderServiceForTest mock_;
 };
 
 }  // namespace ld::testing
diff --git a/sdk/lib/ld/test/ld-remote-process-tests.h b/sdk/lib/ld/test/ld-remote-process-tests.h
index 58df1e6..994b6ea 100644
--- a/sdk/lib/ld/test/ld-remote-process-tests.h
+++ b/sdk/lib/ld/test/ld-remote-process-tests.h
@@ -71,8 +71,6 @@
   using Linker = RemoteDynamicLinker<>;
   using RemoteModule = RemoteLoadModule<>;
 
-  static zx::vmo GetTestVmo(std::string_view path);
-
   zx::vmo GetDepVmo(const RemoteModule::Soname& soname);
 
   template <class Diagnostics>
diff --git a/sdk/lib/ld/test/ld-startup-create-process-tests.cc b/sdk/lib/ld/test/ld-startup-create-process-tests.cc
index d6f3a55..03f9f83 100644
--- a/sdk/lib/ld/test/ld-startup-create-process-tests.cc
+++ b/sdk/lib/ld/test/ld-startup-create-process-tests.cc
@@ -41,7 +41,7 @@
 
   // If a mock loader service has been set up by calls to Needed() et al,
   // send the client end over.
-  if (zx::channel ldsvc = GetLdsvc()) {
+  if (zx::channel ldsvc = TakeLdsvc()) {
     ASSERT_NO_FATAL_FAILURE(bootstrap().AddLdsvc(std::move(ldsvc)));
   }
 }
diff --git a/sdk/lib/ld/test/ld-startup-in-process-tests-zircon.cc b/sdk/lib/ld/test/ld-startup-in-process-tests-zircon.cc
index 0e9f6cf..846f3d8 100644
--- a/sdk/lib/ld/test/ld-startup-in-process-tests-zircon.cc
+++ b/sdk/lib/ld/test/ld-startup-in-process-tests-zircon.cc
@@ -83,7 +83,7 @@
 
   // If a mock loader service has been set up by calls to Needed() et al, send
   // the client end over.
-  if (zx::channel ldsvc = GetLdsvc()) {
+  if (zx::channel ldsvc = TakeLdsvc()) {
     ASSERT_NO_FATAL_FAILURE(bootstrap().AddLdsvc(std::move(ldsvc)));
   }
 }
diff --git a/sdk/lib/ld/test/ld-startup-spawn-process-tests-zircon.cc b/sdk/lib/ld/test/ld-startup-spawn-process-tests-zircon.cc
index ed2fff7..61fb182 100644
--- a/sdk/lib/ld/test/ld-startup-spawn-process-tests-zircon.cc
+++ b/sdk/lib/ld/test/ld-startup-spawn-process-tests-zircon.cc
@@ -147,7 +147,7 @@
   std::string interp;
   ASSERT_NO_FATAL_FAILURE(interp = FindInterp(executable_.borrow()));
   if (!interp.empty()) {
-    ASSERT_NO_FATAL_FAILURE(LdsvcExpectLoadObject(interp));
+    ASSERT_NO_FATAL_FAILURE(LdsvcExpectDependency(interp));
   }
 }
 
@@ -157,7 +157,7 @@
   spawn.Name(process_name());
 
   // Pass in the mock loader service channel.
-  spawn.AddLdsvc(GetLdsvc());
+  spawn.AddLdsvc(TakeLdsvc());
 
   // Put the log pipe on stderr to collect any diagnostics.
   fbl::unique_fd log_fd;
diff --git a/sdk/lib/ld/test/modules/BUILD.gn b/sdk/lib/ld/test/modules/BUILD.gn
index 86085df..7ac79be 100644
--- a/sdk/lib/ld/test/modules/BUILD.gn
+++ b/sdk/lib/ld/test/modules/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/lto/config.gni")
 import("//build/dist/resource.gni")
 import("//build/testing/host_test_data.gni")
 import("//build/toolchain/ifs_shared_library.gni")
@@ -158,6 +159,8 @@
 
       deps = [ ":$shlib_target_name" ]
       sources = [ "$root_out_dir/lib$shlib_target_name.so" ]
+
+      # TODO(https://fxbug.dev/333947906): copy targets to a variant dedicated dir.
       outputs = [ "$host_out_dir/test_data/elfldltl/{{source_file_part}}" ]
       metadata = {
         test_runtime_deps = process_file_template(sources, outputs)
@@ -644,6 +647,7 @@
   # TODO(https://fxbug.dev/42085421): LTO insists on using IE accesses here. Remove this
   # when the LLVM bug gets fixed and the fixed toolchain rolled into Fuchsia.
   remove_configs = [ "//build/config/lto" ]
+  configs += [ "//build/config/lto:no-lto" ]
 }
 
 # This is the same as tls-dep but using TLSDESC, with no __tls_get_addr.
@@ -656,6 +660,7 @@
   # TODO(https://fxbug.dev/42085421): LTO insists on using IE accesses here. Remove this
   # when the LLVM bug gets fixed and the fixed toolchain rolled into Fuchsia.
   remove_configs = [ "//build/config/lto" ]
+  configs += [ "//build/config/lto:no-lto" ]
 }
 
 test_executable("tls-exec-shlib") {
@@ -695,6 +700,7 @@
   # TODO(https://fxbug.dev/42085421): LTO insists on using LE accesses. Remove this when
   # the LLVM bug gets fixed and the fixed toolchain rolled into Fuchsia.
   remove_configs = [ "//build/config/lto" ]
+  configs = [ "//build/config/lto:no-lto" ]
 }
 
 test_executable("tls-gd") {
diff --git a/sdk/lib/ld/testing/BUILD.gn b/sdk/lib/ld/testing/BUILD.gn
index ce1d268..036dd4b 100644
--- a/sdk/lib/ld/testing/BUILD.gn
+++ b/sdk/lib/ld/testing/BUILD.gn
@@ -45,6 +45,11 @@
       "test-vmo.cc",
     ]
     deps += [
+      # TODO(https://fxbug.dev/335737373): this is included for `LD_TEST_LIBPREFIX`.
+      # Instead `load-test-modules-info` should extract the exact path for each
+      # artifact to make it possible for the caller to more simply map a
+      # string -> filename.
+      "../test:load-test-modules-info",
       "//sdk/lib/fdio",
       "//sdk/lib/stdcompat",
       "//src/lib/elfldltl/testing",
diff --git a/sdk/lib/ld/testing/include/lib/ld/testing/mock-loader-service.h b/sdk/lib/ld/testing/include/lib/ld/testing/mock-loader-service.h
index 12cd42c..650c636 100644
--- a/sdk/lib/ld/testing/include/lib/ld/testing/mock-loader-service.h
+++ b/sdk/lib/ld/testing/include/lib/ld/testing/mock-loader-service.h
@@ -15,7 +15,8 @@
 namespace ld::testing {
 
 // MockLoaderService is a mock interface for testing that specific requests
-// are made over the fuchsia.ldsvc.Loader protocol.
+// are made over the fuchsia.ldsvc.Loader protocol.  It is controlled by the
+// MockLoaderServiceForTest class (see below).
 //
 // This class initializes a mock server that serves the fuchsia.ldsvc.Loader
 // protocol and provides a reference to a FIDL client to make requests with.
@@ -50,10 +51,14 @@
   void Init();
 
   // Returns true if Init() has been called and succeeded.
-  bool Ready() const { return bool(mock_server_); }
+  bool Ready() const { return static_cast<bool>(mock_server_); }
 
+  // Tell the mock server to expect a LoadObject request for a VMO with `name`
+  // and to return the `expected_result`.
   void ExpectLoadObject(std::string_view name, zx::result<zx::vmo> expected_result);
 
+  // Tell the mock server to expect a Config request with `name` and to return
+  // `expected_result`.
   void ExpectConfig(std::string_view name, zx::result<> expected_result);
 
   fidl::ClientEnd<fuchsia_ldsvc::Loader>& client() { return mock_client_; }
@@ -68,6 +73,83 @@
   ::testing::InSequence sequence_guard_;
 };
 
+// MockLoaderForTest is used by tests to manage an instance of the
+// MockLoaderService. This class provides the public test API to prime the mock
+// loader with FIDL request expectations and the responses the mock loader
+// should return when receiving the request.
+//
+// MockLoaderForTest lazily initializes its mock_loader_ member, so tests must
+// call Init() before interacting with the mock loader service:
+//
+// ```
+// MockLoaderServiceForTest mock_;
+// ASSERT_NO_FATAL_FAILURE(mock_.Init());
+// mock_.ExpectLoadObject("foo.so", zx::ok(zx::vmo()));
+// ...
+// ```
+class MockLoaderServiceForTest {
+ public:
+  MockLoaderServiceForTest() = default;
+  MockLoaderServiceForTest(const MockLoaderServiceForTest&) = delete;
+  MockLoaderServiceForTest(MockLoaderServiceForTest&&) = delete;
+
+  // Prime the mock loader with the VMOs for the list of dependency names, and
+  // add the expectation on the mock loader that it will receive a LoadObject
+  // request for each of these dependencies in the order that they are listed.
+  void Needed(std::initializer_list<std::string_view> names);
+
+  // Similar to above, except that a boolean `found` is paired with the
+  // dependency name to potentially prime the mock loader to return a 'not found'
+  // error when it receives the LoadObject request for that dependency.
+  void Needed(std::initializer_list<std::pair<std::string_view, bool>> name_found_pairs);
+
+  // A generic interface to prime the mock loader with the `expected_result` for
+  // when it receives a LoadObject request for the given `name`.
+  void ExpectLoadObject(std::string_view name, zx::result<zx::vmo> expected_result);
+
+  // This is an overload that will check the validity of the VMO before priming
+  // the mock loader with a zx::ok result.
+  void ExpectLoadObject(std::string_view name, zx::vmo vmo);
+
+  // Prime the mock loader with a dependency VMO and add the expectation on the
+  // mock loader that it will receive a LoadObject request for that dependency.
+  void ExpectDependency(std::string_view name);
+
+  // Prime the mock loader with a root module VMO and add the expectation on the
+  // mock loader that it will receive a LoadObject request for that root module.
+  void ExpectRootModule(std::string_view name);
+
+  // Prime the mock loader with a 'not found' error for `name` and add the
+  // expectation that it will receive a LoadObject request for a VMO with the
+  // given `name`.
+  void ExpectMissing(std::string_view name);
+
+  // Prime the mock loader with config and add the expectation on the mock loader
+  // that it will receive a Config request.
+  void ExpectConfig(std::string_view config);
+
+  // Take ownership of the client end to the MockLoader's FIDL server.
+  zx::channel TakeLdsvc();
+
+  // Borrow the client end to the MockLoader's FIDL server.
+  zx::unowned_channel BorrowLdsvc();
+
+  // Call `func` with the mock loader installed as the system loader so it will
+  // handle fuchsia.ldsvc.Loader requests made during the duration of `func()`.
+  void CallWithLoaderInstalled(fit::function<void()> func);
+
+ private:
+  // Fetch a dependency VMO from a specific path in the test package.
+  static zx::vmo GetDepVmo(std::string_view name);
+
+  // Fetch a the root module VMO from a specific path in the test package.
+  static zx::vmo GetRootModuleVmo(std::string_view name);
+
+  void ReadyMock();
+
+  std::unique_ptr<MockLoaderService> mock_loader_;
+};
+
 }  // namespace ld::testing
 
 #endif  // LIB_LD_TESTING_MOCK_LOADER_SERVICE_H_
diff --git a/sdk/lib/ld/testing/mock-loader-service.cc b/sdk/lib/ld/testing/mock-loader-service.cc
index 7289954..d968285 100644
--- a/sdk/lib/ld/testing/mock-loader-service.cc
+++ b/sdk/lib/ld/testing/mock-loader-service.cc
@@ -7,6 +7,11 @@
 #include <lib/async-loop/cpp/loop.h>
 #include <lib/async-loop/default.h>
 #include <lib/async/dispatcher.h>
+#include <lib/elfldltl/testing/get-test-data.h>
+#include <lib/fit/defer.h>
+#include <zircon/dlfcn.h>
+
+#include <filesystem>
 
 #include <gmock/gmock.h>
 
@@ -78,10 +83,9 @@
 
 void MockLoaderService::Init() {
   mock_server_ = std::make_unique<::testing::StrictMock<MockServer>>();
-  auto endpoints = fidl::CreateEndpoints<fuchsia_ldsvc::Loader>();
-  ASSERT_EQ(endpoints.status_value(), ZX_OK);
-  ASSERT_NO_FATAL_FAILURE(mock_server_->Init(std::move(endpoints->server)));
-  mock_client_ = std::move(endpoints->client);
+  auto endpoints = fidl::Endpoints<fuchsia_ldsvc::Loader>::Create();
+  ASSERT_NO_FATAL_FAILURE(mock_server_->Init(std::move(endpoints.server)));
+  mock_client_ = std::move(endpoints.client);
 }
 
 void MockLoaderService::ExpectLoadObject(std::string_view name,
@@ -94,4 +98,98 @@
   EXPECT_CALL(*mock_server_, MockConfig(std::string{name})).WillOnce(Return(expected_result));
 }
 
+void MockLoaderServiceForTest::Needed(std::initializer_list<std::string_view> names) {
+  for (std::string_view name : names) {
+    ExpectDependency(name);
+  }
+}
+
+void MockLoaderServiceForTest::Needed(
+    std::initializer_list<std::pair<std::string_view, bool>> name_found_pairs) {
+  for (auto [name, found] : name_found_pairs) {
+    if (found) {
+      ExpectDependency(name);
+    } else {
+      ExpectMissing(name);
+    }
+  }
+}
+
+void MockLoaderServiceForTest::ExpectLoadObject(std::string_view name,
+                                                zx::result<zx::vmo> expected_result) {
+  ASSERT_NO_FATAL_FAILURE(ReadyMock());
+  mock_loader_->ExpectLoadObject(name, std::move(expected_result));
+}
+
+void MockLoaderServiceForTest::ExpectLoadObject(std::string_view name, zx::vmo vmo) {
+  ASSERT_TRUE(vmo);
+  ExpectLoadObject(name, zx::ok(std::move(vmo)));
+}
+
+void MockLoaderServiceForTest::ExpectDependency(std::string_view name) {
+  ExpectLoadObject(name, GetDepVmo(name));
+}
+
+void MockLoaderServiceForTest::ExpectRootModule(std::string_view name) {
+  ExpectLoadObject(name, GetRootModuleVmo(name));
+}
+
+void MockLoaderServiceForTest::ExpectMissing(std::string_view name) {
+  ExpectLoadObject(name, zx::error{ZX_ERR_NOT_FOUND});
+}
+
+void MockLoaderServiceForTest::ExpectConfig(std::string_view config) {
+  ASSERT_NO_FATAL_FAILURE(ReadyMock());
+  mock_loader_->ExpectConfig(config, zx::ok());
+}
+
+zx::channel MockLoaderServiceForTest::TakeLdsvc() {
+  zx::channel ldsvc;
+  if (mock_loader_) {
+    ldsvc = mock_loader_->client().TakeChannel();
+  }
+  return ldsvc;
+}
+
+zx::unowned_channel MockLoaderServiceForTest::BorrowLdsvc() {
+  zx::unowned_channel ldsvc;
+  if (mock_loader_) {
+    ldsvc = mock_loader_->client().channel().borrow();
+  }
+  return ldsvc;
+}
+
+void MockLoaderServiceForTest::CallWithLoaderInstalled(fit::function<void()> func) {
+  // Install the mock loader as the system loader.
+  auto mock_ldsvc = BorrowLdsvc();
+  ASSERT_TRUE(mock_ldsvc->is_valid());
+
+  // Restore the loader to the previous system loader at the close of function scope.
+  auto restore_system_ldsvc =
+      fit::defer([system_ldsvc = zx::channel{dl_set_loader_service(mock_ldsvc->get())}]() mutable {
+        dl_set_loader_service(system_ldsvc.release());
+      });
+
+  // Now that the mock loader service is installed, call the function.
+  func();
+}
+
+zx::vmo MockLoaderServiceForTest::GetDepVmo(std::string_view name) {
+  // TODO(https://fxbug.dev/335737373): use a more direct means to look up the file.
+  const std::string path = std::filesystem::path("test") / "lib" / LD_TEST_LIBPREFIX / name;
+  return elfldltl::testing::GetTestLibVmo(path);
+}
+
+zx::vmo MockLoaderServiceForTest::GetRootModuleVmo(std::string_view name) {
+  const std::string path = std::filesystem::path("test") / "lib" / name;
+  return elfldltl::testing::GetTestLibVmo(path);
+}
+
+void MockLoaderServiceForTest::ReadyMock() {
+  if (!mock_loader_) {
+    mock_loader_ = std::make_unique<MockLoaderService>();
+    ASSERT_NO_FATAL_FAILURE(mock_loader_->Init());
+  }
+}
+
 }  // namespace ld::testing
diff --git a/sdk/lib/mmio/mmio.api b/sdk/lib/mmio/mmio.api
new file mode 100644
index 0000000..608e84b
--- /dev/null
+++ b/sdk/lib/mmio/mmio.api
@@ -0,0 +1,8 @@
+{
+  "pkg/mmio/include/lib/mmio/mmio-buffer.h": "62e50447d3433a251c9633c3ad1ee632",
+  "pkg/mmio/include/lib/mmio/mmio-internal.h": "c1fa30e64896cc3759e71b06aa936ca2",
+  "pkg/mmio/include/lib/mmio/mmio-ops.h": "0ab662f1672d1f08ce329a43ae27785a",
+  "pkg/mmio/include/lib/mmio/mmio-pinned-buffer.h": "003d09f3e49f39f8edb6f25bb26bb17a",
+  "pkg/mmio/include/lib/mmio/mmio-view.h": "ebd785e164dde8f523836c043f7383d4",
+  "pkg/mmio/include/lib/mmio/mmio.h": "a673fd08c005ff716ccb4f0aa9407e26"
+}
\ No newline at end of file
diff --git a/sdk/lib/stdcompat/BUILD.gn b/sdk/lib/stdcompat/BUILD.gn
index 8ef5975..6f69e25 100644
--- a/sdk/lib/stdcompat/BUILD.gn
+++ b/sdk/lib/stdcompat/BUILD.gn
@@ -11,7 +11,7 @@
 
 zx_library("stdcompat") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
 
   sdk_headers = [
     "lib/stdcompat/algorithm.h",
diff --git a/sdk/lib/vfs/internal/libvfs.cc b/sdk/lib/vfs/internal/libvfs.cc
index fb602cc..a2cf769 100644
--- a/sdk/lib/vfs/internal/libvfs.cc
+++ b/sdk/lib/vfs/internal/libvfs.cc
@@ -190,7 +190,7 @@
     return ZX_ERR_INVALID_ARGS;
   }
   return vnode->vfs->Serve(vnode->AsNode(), std::move(chan),
-                           intree_vfs::VnodeConnectionOptions::FromIoV1Flags(*fidl_rights));
+                           intree_vfs::VnodeConnectionOptions::FromOpen1Flags(*fidl_rights));
 }
 
 __EXPORT zx_status_t vfs_internal_node_shutdown(vfs_internal_node_t* vnode) {
diff --git a/sdk/lib/zxio/remote.cc b/sdk/lib/zxio/remote.cc
index 0327f264..8952619 100644
--- a/sdk/lib/zxio/remote.cc
+++ b/sdk/lib/zxio/remote.cc
@@ -381,11 +381,7 @@
   }
 
   zx_status_t Clone(zx_handle_t* out_handle) {
-    zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-    if (endpoints.is_error()) {
-      return endpoints.status_value();
-    }
-    auto [client_end, server_end] = std::move(endpoints.value());
+    auto [client_end, server_end] = fidl::Endpoints<fio::Node>::Create();
     const fidl::Status result =
         client()->Clone(fio::wire::OpenFlags::kCloneSameRights, std::move(server_end));
     if (!result.ok()) {
@@ -488,11 +484,7 @@
   }
 
   zx_status_t Clone(zx_handle_t* out_handle) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_unknown::Cloneable>();
-    if (endpoints.is_error()) {
-      return endpoints.status_value();
-    }
-    auto [client_end, server_end] = std::move(endpoints.value());
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_unknown::Cloneable>::Create();
     const fidl::Status result = client()->Clone2(std::move(server_end));
     if (!result.ok()) {
       return result.status();
@@ -1046,11 +1038,7 @@
 template <typename Protocol>
 zx_status_t Remote<Protocol>::Open(uint32_t flags, const char* path, size_t path_len,
                                    zxio_storage_t* storage) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  if (endpoints.is_error()) {
-    return endpoints.status_value();
-  }
-  auto [client_end, server_end] = std::move(endpoints.value());
+  auto [client_end, server_end] = fidl::Endpoints<fio::Node>::Create();
   const fidl::Status result =
       client()->Open(static_cast<fio::wire::OpenFlags>(flags) | fio::wire::OpenFlags::kDescribe, {},
                      fidl::StringView::FromExternal(path, path_len), std::move(server_end));
@@ -1432,11 +1420,7 @@
     return ZX_ERR_BAD_STATE;
   }
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::ExtendedAttributeIterator>();
-  if (endpoints.is_error()) {
-    return endpoints.error_value();
-  }
-  auto [client_end, server_end] = std::move(endpoints.value());
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_io::ExtendedAttributeIterator>::Create();
   const fidl::OneWayStatus result = client()->ListExtendedAttributes(std::move(server_end));
   if (!result.ok()) {
     return result.status();
diff --git a/sdk/lib/zxio/tests/create-test.cc b/sdk/lib/zxio/tests/create-test.cc
index bd36378..406a3bf 100644
--- a/sdk/lib/zxio/tests/create-test.cc
+++ b/sdk/lib/zxio/tests/create-test.cc
@@ -363,10 +363,9 @@
   using ProtocolType = typename NodeServer::_EnclosingProtocol;
 
   void SetUp() final {
-    zx::result node_ends = fidl::CreateEndpoints<ProtocolType>();
-    ASSERT_OK(node_ends.status_value());
-    node_client_end_ = std::move(node_ends->client);
-    node_server_end_ = std::move(node_ends->server);
+    auto node_ends = fidl::Endpoints<ProtocolType>::Create();
+    node_client_end_ = std::move(node_ends.client);
+    node_server_end_ = std::move(node_ends.server);
   }
 
   void TearDown() final { control_loop_.Shutdown(); }
diff --git a/sdk/lib/zxio/tests/directory-test.cc b/sdk/lib/zxio/tests/directory-test.cc
index d932248..8c7928a 100644
--- a/sdk/lib/zxio/tests/directory-test.cc
+++ b/sdk/lib/zxio/tests/directory-test.cc
@@ -125,13 +125,10 @@
         directory_server_(server_loop_.dispatcher()) {}
 
   void SetUp() override {
-    zx::result directory_ends = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(directory_ends.status_value());
-    auto [directory_client_end, directory_server_end] = std::move(directory_ends.value());
+    auto [directory_client_end, directory_server_end] =
+        fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-    zx::result node_ends = fidl::CreateEndpoints<fuchsia_io::Node>();
-    ASSERT_OK(node_ends.status_value());
-    auto [node_client_end, node_server_end] = std::move(node_ends.value());
+    auto [node_client_end, node_server_end] = fidl::Endpoints<fuchsia_io::Node>::Create();
 
     zx::event token;
     ASSERT_OK(zx::event::create(0, &token));
diff --git a/sdk/lib/zxio/tests/dirent-test.cc b/sdk/lib/zxio/tests/dirent-test.cc
index 76e6498..6650248 100644
--- a/sdk/lib/zxio/tests/dirent-test.cc
+++ b/sdk/lib/zxio/tests/dirent-test.cc
@@ -87,9 +87,7 @@
 class DirentTest : public zxtest::Test {
  protected:
   void SetUp() final {
-    zx::result endpoints = fidl::CreateEndpoints<fio::Directory>();
-    ASSERT_OK(endpoints.status_value());
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<fio::Directory>::Create();
     ASSERT_OK(zxio_dir_init(&dir_, std::move(client_end)));
     server_ = std::make_unique<TestServer>();
     loop_ = std::make_unique<async::Loop>(&kAsyncLoopConfigNoAttachToCurrentThread);
diff --git a/sdk/lib/zxio/tests/inception-test.cc b/sdk/lib/zxio/tests/inception-test.cc
index 8ab0cca..eaf2df2 100644
--- a/sdk/lib/zxio/tests/inception-test.cc
+++ b/sdk/lib/zxio/tests/inception-test.cc
@@ -113,9 +113,7 @@
 }  // namespace
 
 TEST(CreateWithAllocator, Directory) {
-  zx::result dir_ends = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(dir_ends.status_value());
-  auto [dir_client, dir_server] = std::move(dir_ends.value());
+  auto [dir_client, dir_server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   auto node_info = fuchsia_io::wire::NodeInfoDeprecated::WithDirectory({});
 
@@ -150,9 +148,7 @@
 }
 
 TEST(CreateWithAllocator, File) {
-  zx::result file_ends = fidl::CreateEndpoints<fuchsia_io::File>();
-  ASSERT_OK(file_ends.status_value());
-  auto [file_client, file_server] = std::move(file_ends.value());
+  auto [file_client, file_server] = fidl::Endpoints<fuchsia_io::File>::Create();
 
   zx::event file_event;
   ASSERT_OK(zx::event::create(0u, &file_event));
@@ -216,9 +212,7 @@
 };
 
 TEST(CreateWithAllocator, Service) {
-  zx::result node_ends = fidl::CreateEndpoints<fuchsia_io::Node>();
-  ASSERT_OK(node_ends.status_value());
-  auto [node_client, node_server] = std::move(node_ends.value());
+  auto [node_client, node_server] = fidl::Endpoints<fuchsia_io::Node>::Create();
 
   auto node_info = fuchsia_io::wire::NodeInfoDeprecated::WithService({});
 
@@ -282,9 +276,7 @@
 };
 
 TEST(CreateWithAllocator, Tty) {
-  zx::result node_ends = fidl::CreateEndpoints<fuchsia_io::Node>();
-  ASSERT_OK(node_ends.status_value());
-  auto [node_client, node_server] = std::move(node_ends.value());
+  auto [node_client, node_server] = fidl::Endpoints<fuchsia_io::Node>::Create();
 
   zx::eventpair event0, event1;
   ASSERT_OK(zx::eventpair::create(0, &event0, &event1));
@@ -327,9 +319,8 @@
 }
 
 TEST(CreateWithAllocator, PacketSocket) {
-  zx::result socket_ends = fidl::CreateEndpoints<fuchsia_posix_socket_packet::Socket>();
-  ASSERT_OK(socket_ends.status_value());
-  auto [socket_client, socket_server] = std::move(socket_ends.value());
+  auto [socket_client, socket_server] =
+      fidl::Endpoints<fuchsia_posix_socket_packet::Socket>::Create();
 
   zx::eventpair event0, event1;
   ASSERT_OK(zx::eventpair::create(0, &event0, &event1));
@@ -371,9 +362,7 @@
 }
 
 TEST(CreateWithAllocator, RawSocket) {
-  zx::result socket_ends = fidl::CreateEndpoints<fuchsia_posix_socket_raw::Socket>();
-  ASSERT_OK(socket_ends.status_value());
-  auto [socket_client, socket_server] = std::move(socket_ends.value());
+  auto [socket_client, socket_server] = fidl::Endpoints<fuchsia_posix_socket_raw::Socket>::Create();
 
   zx::eventpair event0, event1;
   ASSERT_OK(zx::eventpair::create(0, &event0, &event1));
@@ -415,9 +404,8 @@
 }
 
 TEST(CreateWithAllocator, SynchronousDatagramSocket) {
-  zx::result socket_ends = fidl::CreateEndpoints<fuchsia_posix_socket::SynchronousDatagramSocket>();
-  ASSERT_OK(socket_ends.status_value());
-  auto [socket_client, socket_server] = std::move(socket_ends.value());
+  auto [socket_client, socket_server] =
+      fidl::Endpoints<fuchsia_posix_socket::SynchronousDatagramSocket>::Create();
 
   zx::eventpair event0, event1;
   ASSERT_OK(zx::eventpair::create(0, &event0, &event1));
@@ -459,9 +447,8 @@
 }
 
 TEST(CreateWithAllocator, DatagramSocket) {
-  zx::result socket_ends = fidl::CreateEndpoints<fuchsia_posix_socket::DatagramSocket>();
-  ASSERT_OK(socket_ends.status_value());
-  auto [socket_client, socket_server] = std::move(socket_ends.value());
+  auto [socket_client, socket_server] =
+      fidl::Endpoints<fuchsia_posix_socket::DatagramSocket>::Create();
 
   zx::socket socket, peer;
   ASSERT_OK(zx::socket::create(ZX_SOCKET_DATAGRAM, &socket, &peer));
@@ -492,9 +479,8 @@
 }
 
 TEST(CreateWithAllocator, StreamSocket) {
-  zx::result socket_ends = fidl::CreateEndpoints<fuchsia_posix_socket::StreamSocket>();
-  ASSERT_OK(socket_ends.status_value());
-  auto [socket_client, socket_server] = std::move(socket_ends.value());
+  auto [socket_client, socket_server] =
+      fidl::Endpoints<fuchsia_posix_socket::StreamSocket>::Create();
 
   zx::socket socket, peer;
   ASSERT_OK(zx::socket::create(ZX_SOCKET_STREAM, &socket, &peer));
diff --git a/sdk/lib/zxio/tests/socket-test.cc b/sdk/lib/zxio/tests/socket-test.cc
index 2c2f264..1cb263a 100644
--- a/sdk/lib/zxio/tests/socket-test.cc
+++ b/sdk/lib/zxio/tests/socket-test.cc
@@ -370,11 +370,10 @@
     ASSERT_OK(zx::eventpair::create(0u, &error_local_, &error_peer_));
     ASSERT_NO_FATAL_FAILURE(server_.InvalidateClientCache());
 
-    zx::result endpoints = fidl::CreateEndpoints<fsocket::DatagramSocket>();
-    ASSERT_OK(endpoints.status_value());
-    client_ = fidl::WireSyncClient<fsocket::DatagramSocket>{std::move(endpoints->client)};
+    auto endpoints = fidl::Endpoints<fsocket::DatagramSocket>::Create();
+    client_ = fidl::WireSyncClient<fsocket::DatagramSocket>{std::move(endpoints.client)};
 
-    fidl::BindServer(control_loop_.dispatcher(), std::move(endpoints->server), &server_);
+    fidl::BindServer(control_loop_.dispatcher(), std::move(endpoints.server), &server_);
     control_loop_.StartThread("control");
   }
 
diff --git a/sdk/lib/zxio/tests/tty-test.cc b/sdk/lib/zxio/tests/tty-test.cc
index 7b3d35e9..6bcc4b5 100644
--- a/sdk/lib/zxio/tests/tty-test.cc
+++ b/sdk/lib/zxio/tests/tty-test.cc
@@ -80,9 +80,7 @@
 };
 
 TEST(Tty, Basic) {
-  zx::result device_ends = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
-  ASSERT_OK(device_ends.status_value());
-  auto [device_client, device_server] = std::move(device_ends.value());
+  auto [device_client, device_server] = fidl::Endpoints<fuchsia_hardware_pty::Device>::Create();
 
   async::Loop device_control_loop(&kAsyncLoopConfigNoAttachToCurrentThread);
   WindowSizeTtyServer server;
diff --git a/sdk/lib/zxio/tests/watcher-test.cc b/sdk/lib/zxio/tests/watcher-test.cc
index f45d152..a7e8dbe 100644
--- a/sdk/lib/zxio/tests/watcher-test.cc
+++ b/sdk/lib/zxio/tests/watcher-test.cc
@@ -50,19 +50,18 @@
 };
 
 TEST(WatcherTest, WatchInvalidCallback) {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   Server server([](fuchsia_io::wire::WatchMask mask, uint32_t options,
                    fidl::ServerEnd<fuchsia_io::DirectoryWatcher> watcher,
                    fidl::WireServer<fuchsia_io::Directory>::WatchCompleter::Sync& completer) {});
 
   async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &server);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &server);
   ASSERT_OK(loop.StartThread("fake-directory-server"));
 
   zxio_storage_t storage;
-  ASSERT_OK(zxio_create(endpoints->client.channel().release(), &storage));
+  ASSERT_OK(zxio_create(endpoints.client.channel().release(), &storage));
   zxio_t* io = &storage.io;
 
   ASSERT_STATUS(zxio_watch_directory(io, nullptr, ZX_TIME_INFINITE, nullptr), ZX_ERR_INVALID_ARGS);
@@ -71,8 +70,7 @@
 }
 
 TEST(WatcherTest, Smoke) {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   Server server([](fuchsia_io::wire::WatchMask mask, uint32_t options,
                    fidl::ServerEnd<fuchsia_io::DirectoryWatcher> watcher,
@@ -102,11 +100,11 @@
         0, bytes, static_cast<uint32_t>(std::distance(std::begin(bytes), it)), nullptr, 0));
   });
   async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &server);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &server);
   ASSERT_OK(loop.StartThread("fake-directory-server"));
 
   zxio_storage_t storage;
-  ASSERT_OK(zxio_create(endpoints->client.channel().release(), &storage));
+  ASSERT_OK(zxio_create(endpoints.client.channel().release(), &storage));
   zxio_t* io = &storage.io;
 
   std::vector<std::pair<zxio_watch_directory_event_t, std::string>> events;
diff --git a/sdk/manifests/fuchsia_idk.manifest b/sdk/manifests/fuchsia_idk.manifest
index d11aa50..2447afe 100644
--- a/sdk/manifests/fuchsia_idk.manifest
+++ b/sdk/manifests/fuchsia_idk.manifest
@@ -86,6 +86,7 @@
 cc_source_library://pkg/fidl_driver_transport
 cc_source_library://pkg/fit
 cc_source_library://pkg/fit-promise
+cc_source_library://pkg/hwreg
 cc_source_library://pkg/images_cpp
 cc_source_library://pkg/input_report_reader
 cc_source_library://pkg/inspect
@@ -93,6 +94,8 @@
 cc_source_library://pkg/magma_common
 cc_source_library://pkg/media_cpp
 cc_source_library://pkg/media_cpp_no_converters
+cc_source_library://pkg/mmio
+cc_source_library://pkg/mmio-ptr
 cc_source_library://pkg/scenic_cpp
 cc_source_library://pkg/scenic_cpp_testing
 cc_source_library://pkg/stdcompat
@@ -109,12 +112,14 @@
 cc_source_library://pkg/utf-utils
 cc_source_library://pkg/vfs_cpp
 cc_source_library://pkg/virtgralloc_headers
+cc_source_library://pkg/zbi-format
 cc_source_library://pkg/zx
 companion_host_tool://tools/x64/aemu_internal
 companion_host_tool://tools/x64/qemu_internal
 companion_host_tool://tools/x64/qemu_uefi_internal
 dart_library://dart/sl4f
 data://data/config/symbol_index
+data://pkg/driver_component/driver_component.json
 data://pkg/heapdump_instrumentation/heapdump_instrumentation_shard.json
 data://pkg/inspect/inspect.json
 data://pkg/sys/component/realm_builder_shard_sdk.json
@@ -227,6 +232,7 @@
 fidl_library://fidl/fuchsia.hardware.i2c
 fidl_library://fidl/fuchsia.hardware.light
 fidl_library://fidl/fuchsia.hardware.network
+fidl_library://fidl/fuchsia.hardware.pci
 fidl_library://fidl/fuchsia.hardware.platform.device
 fidl_library://fidl/fuchsia.hardware.power
 fidl_library://fidl/fuchsia.hardware.power.sensor
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 4efed34..841c3f3 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -57,6 +57,7 @@
     "recovery:e2e_tests",
     "testing:e2e_tests",
     "tests",
+    "//src/connectivity/network:e2e_tests",
     "//src/storage/lib/paver/e2e_tests",
     "//src/sys/pkg:e2e_tests",
   ]
diff --git a/src/bringup/bin/console-launcher/main.cc b/src/bringup/bin/console-launcher/main.cc
index 6f07b2a..5ab0f8d 100644
--- a/src/bringup/bin/console-launcher/main.cc
+++ b/src/bringup/bin/console-launcher/main.cc
@@ -121,11 +121,7 @@
 
 zx::result<fidl::ClientEnd<fuchsia_hardware_pty::Device>> CreateVirtualConsole(
     const fidl::WireSyncClient<fuchsia_virtualconsole::SessionManager>& session_manager) {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
-  if (endpoints.is_error()) {
-    return endpoints.take_error();
-  }
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_hardware_pty::Device>::Create();
 
   const fidl::Status result = session_manager->CreateSession(std::move(server));
   if (!result.ok()) {
@@ -249,11 +245,7 @@
                                    fidl::ClientEnd<fuchsia_hardware_pty::Device> stdio,
                                    const std::string& term, const std::optional<std::string>& cmd) {
   while (true) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
-    if (endpoints.is_error()) {
-      FX_PLOGS(FATAL, endpoints.status_value()) << "failed to create endpoints";
-    }
-    auto& [client, server] = endpoints.value();
+    auto [client, server] = fidl::Endpoints<fuchsia_hardware_pty::Device>::Create();
 
     const fidl::Status result = fidl::WireCall(stdio)->Clone2(
         fidl::ServerEnd<fuchsia_unknown::Cloneable>(server.TakeChannel()));
@@ -517,7 +509,7 @@
   for (auto& thread : workers) {
     thread.join();
   }
-  // TODO(https://fxbug.dev/42179909): Hang around. If we exit before archivist has started, our logs
-  // will be lost, and this log is load bearing in shell_disabled_test.
+  // TODO(https://fxbug.dev/42179909): Hang around. If we exit before archivist has started, our
+  // logs will be lost, and this log is load bearing in shell_disabled_test.
   std::promise<void>().get_future().wait();
 }
diff --git a/src/bringup/bin/console/console-test.cc b/src/bringup/bin/console/console-test.cc
index 7839e9b..83bf6da 100644
--- a/src/bringup/bin/console/console-test.cc
+++ b/src/bringup/bin/console/console-test.cc
@@ -31,9 +31,7 @@
   };
   Console::TxSink tx_sink = [](const uint8_t* buffer, size_t length) { return ZX_OK; };
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client_end, server_end] = endpoints.value();
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_pty::Device>::Create();
 
   async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
   zx::eventpair event1, event2;
@@ -73,9 +71,7 @@
     return ZX_OK;
   };
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pty::Device>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client_end, server_end] = endpoints.value();
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_pty::Device>::Create();
 
   async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
   zx::eventpair event1, event2;
diff --git a/src/bringup/bin/critical-services/crashsvc/crashsvc-test.cc b/src/bringup/bin/critical-services/crashsvc/crashsvc-test.cc
index 296989e..b5da58c 100644
--- a/src/bringup/bin/critical-services/crashsvc/crashsvc-test.cc
+++ b/src/bringup/bin/critical-services/crashsvc/crashsvc-test.cc
@@ -113,9 +113,7 @@
 class FakeService {
  public:
   explicit FakeService(async_dispatcher_t* dispatcher) : outgoing_(dispatcher) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
-    auto& [client, server] = endpoints.value();
+    auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
     ASSERT_OK(outgoing_.AddUnmanagedProtocol<fuchsia_exception::Handler>(
         [this, dispatcher](fidl::ServerEnd<fuchsia_exception::Handler> request) {
diff --git a/src/bringup/bin/critical-services/main.cc b/src/bringup/bin/critical-services/main.cc
index f4c117a..8edd1d9 100644
--- a/src/bringup/bin/critical-services/main.cc
+++ b/src/bringup/bin/critical-services/main.cc
@@ -116,11 +116,7 @@
   if (controller.is_error()) {
     return controller.error_value();
   }
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::Device>();
-  if (endpoints.is_error()) {
-    return endpoints.error_value();
-  }
-  auto& [device, server] = endpoints.value();
+  auto [device, server] = fidl::Endpoints<fuchsia_hardware_input::Device>::Create();
   const fidl::Status status = fidl::WireCall(controller.value())->OpenSession(std::move(server));
   if (!status.ok()) {
     return status.status();
diff --git a/src/bringup/bin/critical-services/monitor-test.cc b/src/bringup/bin/critical-services/monitor-test.cc
index 3fa2dfb7..d81d204 100644
--- a/src/bringup/bin/critical-services/monitor-test.cc
+++ b/src/bringup/bin/critical-services/monitor-test.cc
@@ -28,11 +28,10 @@
  public:
   MonitorTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) {}
   void SetUp() override {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_power_button::Monitor>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_power_button::Monitor>::Create();
 
-    client_.Bind(std::move(endpoints->client), loop_.dispatcher(), &event_handler_);
-    monitor_.Publish()(std::move(endpoints->server));
+    client_.Bind(std::move(endpoints.client), loop_.dispatcher(), &event_handler_);
+    monitor_.Publish()(std::move(endpoints.server));
   }
 
  protected:
diff --git a/src/bringup/bin/critical-services/oom_watcher-test.cc b/src/bringup/bin/critical-services/oom_watcher-test.cc
index f57a896..fd98b57 100644
--- a/src/bringup/bin/critical-services/oom_watcher-test.cc
+++ b/src/bringup/bin/critical-services/oom_watcher-test.cc
@@ -76,11 +76,10 @@
     // Give the fake a reference to the loop so it can quit the loop once it
     // receives the shutdown signal from the code under test.
     fake_power_manager_.SetLoop(&loop_);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_power_statecontrol::Admin>();
-    ASSERT_OK(endpoints.status_value());
-    power_manager_client_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_power_statecontrol::Admin>::Create();
+    power_manager_client_ = std::move(endpoints.client);
     binding_ = fidl::ServerBindingRef<fuchsia_hardware_power_statecontrol::Admin>(
-        fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &fake_power_manager_));
+        fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &fake_power_manager_));
 
     zx::eventpair::create(0, &kernel_oom_event_, &watcher_oom_event_);
     oom_watcher_.WatchForOom(this->loop_.dispatcher(), zx::event(watcher_oom_event_.get()),
diff --git a/src/bringup/bin/netsvc/debuglog.cc b/src/bringup/bin/netsvc/debuglog.cc
index 8321c43..a9b3a62 100644
--- a/src/bringup/bin/netsvc/debuglog.cc
+++ b/src/bringup/bin/netsvc/debuglog.cc
@@ -210,11 +210,7 @@
   }
   fidl::WireSyncClient client{std::move(log_client_end.value())};
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_logger::LogListenerSafe>();
-  if (endpoints.is_error()) {
-    return endpoints.status_value();
-  }
-  auto [client_end, server_end] = std::move(endpoints.value());
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_logger::LogListenerSafe>::Create();
   {
     fidl::Status result = client->ListenSafe(
         std::move(client_end), fidl::ObjectView<fuchsia_logger::wire::LogFilterOptions>(nullptr));
diff --git a/src/bringup/bin/netsvc/netifc-discover.cc b/src/bringup/bin/netsvc/netifc-discover.cc
index 4e25324..9a00315 100644
--- a/src/bringup/bin/netsvc/netifc-discover.cc
+++ b/src/bringup/bin/netsvc/netifc-discover.cc
@@ -38,13 +38,7 @@
   static std::optional<Info> get_interface_if_matching(
       fidl::ClientEnd<fuchsia_hardware_network::DeviceInstance> instance,
       const std::string& filename) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_network::Device>();
-    if (endpoints.is_error()) {
-      printf("netifc: failed to create netdevice endpoints %s: %s\n", filename.c_str(),
-             endpoints.status_string());
-      return std::nullopt;
-    }
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_network::Device>::Create();
 
     {
       fidl::Status result = fidl::WireCall(instance)->GetDevice(std::move(server_end));
@@ -55,13 +49,8 @@
       }
     }
 
-    zx::result watcher_endpoints = fidl::CreateEndpoints<fuchsia_hardware_network::PortWatcher>();
-    if (watcher_endpoints.is_error()) {
-      printf("netifc: failed to create netdevice port watcher endpoints %s: %s\n", filename.c_str(),
-             watcher_endpoints.status_string());
-      return std::nullopt;
-    }
-    auto& [watcher_client_end, watcher_server_end] = watcher_endpoints.value();
+    auto [watcher_client_end, watcher_server_end] =
+        fidl::Endpoints<fuchsia_hardware_network::PortWatcher>::Create();
 
     {
       fidl::Status result =
@@ -121,12 +110,8 @@
               return;
           }
 
-          zx::result port_endpoints = fidl::CreateEndpoints<fuchsia_hardware_network::Port>();
-          if (port_endpoints.is_error()) {
-            printf("netifc: failed to create port endpoints: %s\n", port_endpoints.status_string());
-            return;
-          }
-          auto [port_client_end, port_server_end] = std::move(port_endpoints.value());
+          auto [port_client_end, port_server_end] =
+              fidl::Endpoints<fuchsia_hardware_network::Port>::Create();
           {
             fidl::Status result = fidl::WireCall(dev)->GetPort(port_id, std::move(port_server_end));
             if (!result.ok()) {
@@ -168,14 +153,8 @@
 
           // This is a good candidate port, but we need to retrieve the MAC
           // address.
-          zx::result mac_endpoints =
-              fidl::CreateEndpoints<fuchsia_hardware_network::MacAddressing>();
-          if (mac_endpoints.is_error()) {
-            printf("netifc: failed to create MacAddressing endpoints: %s\n",
-                   mac_endpoints.status_string());
-            return;
-          }
-          auto [mac_client_end, mac_server_end] = std::move(mac_endpoints.value());
+          auto [mac_client_end, mac_server_end] =
+              fidl::Endpoints<fuchsia_hardware_network::MacAddressing>::Create();
           {
             fidl::Status result =
                 fidl::WireCall(port_client_end)->GetMac(std::move(mac_server_end));
diff --git a/src/bringup/bin/netsvc/netifc.cc b/src/bringup/bin/netsvc/netifc.cc
index 8e189b3..918b295 100644
--- a/src/bringup/bin/netsvc/netifc.cc
+++ b/src/bringup/bin/netsvc/netifc.cc
@@ -91,17 +91,10 @@
                             fidl::ClientEnd<fuchsia_hardware_network::Device> device,
                             fuchsia_hardware_network::wire::PortId port_id,
                             fit::callback<void(zx_status_t)> on_error) {
-  zx::result mac_endpoints = fidl::CreateEndpoints<fuchsia_hardware_network::MacAddressing>();
-  if (mac_endpoints.is_error()) {
-    return mac_endpoints.take_error();
-  }
-  auto& [mac_client, mac_server] = mac_endpoints.value();
+  auto [mac_client, mac_server] =
+      fidl::Endpoints<fuchsia_hardware_network::MacAddressing>::Create();
 
-  zx::result port_endpoints = fidl::CreateEndpoints<fuchsia_hardware_network::Port>();
-  if (port_endpoints.is_error()) {
-    return port_endpoints.take_error();
-  }
-  auto& [port_client, port_server] = port_endpoints.value();
+  auto [port_client, port_server] = fidl::Endpoints<fuchsia_hardware_network::Port>::Create();
 
   {
     fidl::OneWayStatus result = fidl::WireCall(device)->GetPort(port_id, std::move(port_server));
diff --git a/src/bringup/bin/netsvc/test/debuglog-test.cc b/src/bringup/bin/netsvc/test/debuglog-test.cc
index 2d9e9b6..ea672b1 100644
--- a/src/bringup/bin/netsvc/test/debuglog-test.cc
+++ b/src/bringup/bin/netsvc/test/debuglog-test.cc
@@ -57,9 +57,7 @@
                   /* retransmit */ false, kMaxLogData) {}
 
   void SetUp() override {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_logger::LogListenerSafe>();
-    ASSERT_OK(endpoints.status_value());
-    auto [client, server] = std::move(endpoints.value());
+    auto [client, server] = fidl::Endpoints<fuchsia_logger::LogListenerSafe>::Create();
     listener_.Bind(std::move(server));
     client_.Bind(std::move(client), loop_.dispatcher());
 
diff --git a/src/bringup/bin/netsvc/test/payload-streamer-test.cc b/src/bringup/bin/netsvc/test/payload-streamer-test.cc
index 2adcd21..0e4da74 100644
--- a/src/bringup/bin/netsvc/test/payload-streamer-test.cc
+++ b/src/bringup/bin/netsvc/test/payload-streamer-test.cc
@@ -22,11 +22,10 @@
   }
 
   void StartStreamer(netsvc::ReadCallback callback = DefaultCallback) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_paver::PayloadStream>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_paver::PayloadStream>::Create();
 
-    client_ = fidl::WireSyncClient(std::move(endpoints->client));
-    payload_streamer_.emplace(std::move(endpoints->server), std::move(callback));
+    client_ = fidl::WireSyncClient(std::move(endpoints.client));
+    payload_streamer_.emplace(std::move(endpoints.server), std::move(callback));
     loop_.StartThread("payload-streamer-test-loop");
   }
 
diff --git a/src/bringup/bin/paver/BUILD.gn b/src/bringup/bin/paver/BUILD.gn
index 26ae26c..54d6097 100644
--- a/src/bringup/bin/paver/BUILD.gn
+++ b/src/bringup/bin/paver/BUILD.gn
@@ -4,7 +4,55 @@
 
 import("//build/components.gni")
 
+template("paver_template") {
+  not_needed(invoker, [ "*" ])
+  _target_name = target_name
+
+  executable("paver-${target_name}") {
+    defines = [ "${_target_name}" ]
+    sources = [ "paver.cc" ]
+    deps = [
+      "//sdk/fidl/fuchsia.paver:fuchsia.paver_cpp",
+      "//sdk/fidl/fuchsia.process.lifecycle:fuchsia.process.lifecycle_cpp",
+      "//sdk/lib/component/outgoing/cpp",
+      "//sdk/lib/fdio",
+      "//src/storage/lib/paver:${_target_name}",
+      "//src/sys/lib/stdout-to-debuglog/cpp",
+      "//zircon/system/ulib/async-loop:async-loop-cpp",
+      "//zircon/system/ulib/async-loop:async-loop-default",
+    ]
+  }
+
+  fuchsia_component("component-${target_name}") {
+    component_name = "paver"
+    manifest = "meta/paver-${_target_name}.cml"
+    deps = [ ":paver-${_target_name}" ]
+  }
+
+  fuchsia_package("package-${target_name}") {
+    package_name = "paver"
+    deps = [ ":component-${_target_name}" ]
+  }
+}
+
+paver_template("astro") {
+}
+paver_template("luis") {
+}
+paver_template("nelson") {
+}
+paver_template("sherlock") {
+}
+paver_template("vim3") {
+}
+paver_template("violet") {
+}
+paver_template("x64") {
+}
+
+# Legacy targets to be deleted.
 executable("paver") {
+  defines = [ "LEGACY_PAVER" ]
   sources = [ "paver.cc" ]
   deps = [
     "//sdk/fidl/fuchsia.process.lifecycle:fuchsia.process.lifecycle_cpp",
@@ -19,7 +67,7 @@
 
 fuchsia_component("component") {
   component_name = "paver"
-  manifest = "meta/paver.cml"
+  manifest = "meta/paver-legacy.cml"
   deps = [ ":paver" ]
 }
 
diff --git a/src/bringup/bin/paver/meta/paver-astro.cml b/src/bringup/bin/paver/meta/paver-astro.cml
new file mode 100644
index 0000000..50e09e3
--- /dev/null
+++ b/src/bringup/bin/paver/meta/paver-astro.cml
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "//src/bringup/bin/paver/meta/paver.cml" ],
+    program: {
+        binary: "bin/paver-astro",
+    },
+}
diff --git a/src/bringup/bin/paver/meta/paver-legacy.cml b/src/bringup/bin/paver/meta/paver-legacy.cml
new file mode 100644
index 0000000..d35c8bf
--- /dev/null
+++ b/src/bringup/bin/paver/meta/paver-legacy.cml
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "//src/bringup/bin/paver/meta/paver.cml" ],
+    program: {
+        binary: "bin/paver",
+    },
+}
diff --git a/src/bringup/bin/paver/meta/paver-luis.cml b/src/bringup/bin/paver/meta/paver-luis.cml
new file mode 100644
index 0000000..9a956fc
--- /dev/null
+++ b/src/bringup/bin/paver/meta/paver-luis.cml
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "//src/bringup/bin/paver/meta/paver.cml" ],
+    program: {
+        binary: "bin/paver-luis",
+    },
+}
diff --git a/src/bringup/bin/paver/meta/paver-nelson.cml b/src/bringup/bin/paver/meta/paver-nelson.cml
new file mode 100644
index 0000000..972fc0f
--- /dev/null
+++ b/src/bringup/bin/paver/meta/paver-nelson.cml
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "//src/bringup/bin/paver/meta/paver.cml" ],
+    program: {
+        binary: "bin/paver-nelson",
+    },
+}
diff --git a/src/bringup/bin/paver/meta/paver-sherlock.cml b/src/bringup/bin/paver/meta/paver-sherlock.cml
new file mode 100644
index 0000000..2d9abb2
--- /dev/null
+++ b/src/bringup/bin/paver/meta/paver-sherlock.cml
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "//src/bringup/bin/paver/meta/paver.cml" ],
+    program: {
+        binary: "bin/paver-sherlock",
+    },
+}
diff --git a/src/bringup/bin/paver/meta/paver-vim3.cml b/src/bringup/bin/paver/meta/paver-vim3.cml
new file mode 100644
index 0000000..1c89edb
--- /dev/null
+++ b/src/bringup/bin/paver/meta/paver-vim3.cml
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "//src/bringup/bin/paver/meta/paver.cml" ],
+    program: {
+        binary: "bin/paver-vim3",
+    },
+}
diff --git a/src/bringup/bin/paver/meta/paver-violet.cml b/src/bringup/bin/paver/meta/paver-violet.cml
new file mode 100644
index 0000000..f50808a
--- /dev/null
+++ b/src/bringup/bin/paver/meta/paver-violet.cml
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "//src/bringup/bin/paver/meta/paver.cml" ],
+    program: {
+        binary: "bin/paver-violet",
+    },
+}
diff --git a/src/bringup/bin/paver/meta/paver-x64.cml b/src/bringup/bin/paver/meta/paver-x64.cml
new file mode 100644
index 0000000..afbd9c0
--- /dev/null
+++ b/src/bringup/bin/paver/meta/paver-x64.cml
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [ "//src/bringup/bin/paver/meta/paver.cml" ],
+    program: {
+        binary: "bin/paver-x64",
+    },
+}
diff --git a/src/bringup/bin/paver/meta/paver.cml b/src/bringup/bin/paver/meta/paver.cml
index 6074bf8..ff3d633 100644
--- a/src/bringup/bin/paver/meta/paver.cml
+++ b/src/bringup/bin/paver/meta/paver.cml
@@ -5,7 +5,6 @@
     include: [ "syslog/client.shard.cml" ],
     program: {
         runner: "elf",
-        binary: "bin/paver",
         forward_stdout_to: "none",
         forward_stderr_to: "none",
         lifecycle: { stop_event: "notify" },
diff --git a/src/bringup/bin/paver/paver.cc b/src/bringup/bin/paver/paver.cc
index 98a707b..b309ab5 100644
--- a/src/bringup/bin/paver/paver.cc
+++ b/src/bringup/bin/paver/paver.cc
@@ -9,20 +9,38 @@
 #include <lib/async-loop/default.h>
 #include <lib/component/outgoing/cpp/outgoing_directory.h>
 #include <lib/fidl/cpp/wire/server.h>
+#include <zircon/process.h>
 #include <zircon/processargs.h>
 #include <zircon/status.h>
 
 #include "src/storage/lib/paver/abr-client.h"
-#include "src/storage/lib/paver/astro.h"
 #include "src/storage/lib/paver/device-partitioner.h"
+#include "src/storage/lib/paver/pave-logging.h"
+#include "src/sys/lib/stdout-to-debuglog/cpp/stdout-to-debuglog.h"
+
+#if defined(LEGACY_PAVER)
+#include "src/storage/lib/paver/astro.h"
 #include "src/storage/lib/paver/luis.h"
 #include "src/storage/lib/paver/nelson.h"
-#include "src/storage/lib/paver/pave-logging.h"
 #include "src/storage/lib/paver/sherlock.h"
 #include "src/storage/lib/paver/vim3.h"
 #include "src/storage/lib/paver/violet.h"
 #include "src/storage/lib/paver/x64.h"
-#include "src/sys/lib/stdout-to-debuglog/cpp/stdout-to-debuglog.h"
+#elif defined(astro)
+#include "src/storage/lib/paver/astro.h"
+#elif defined(luis)
+#include "src/storage/lib/paver/luis.h"
+#elif defined(nelson)
+#include "src/storage/lib/paver/nelson.h"
+#elif defined(sherlock)
+#include "src/storage/lib/paver/sherlock.h"
+#elif defined(vim3)
+#include "src/storage/lib/paver/vim3.h"
+#elif defined(violet)
+#include "src/storage/lib/paver/violet.h"
+#elif defined(x64)
+#include "src/storage/lib/paver/x64.h"
+#endif
 
 class LifecycleServer final : public fidl::WireServer<fuchsia_process_lifecycle::Lifecycle> {
  public:
@@ -61,22 +79,47 @@
   paver::Paver paver;
   paver.set_dispatcher(dispatcher);
 
+#if defined(LEGACY_PAVER)
   // NOTE: Ordering matters!
   paver::DevicePartitionerFactory::Register(std::make_unique<paver::AstroPartitionerFactory>());
-  paver::DevicePartitionerFactory::Register(std::make_unique<paver::NelsonPartitionerFactory>());
-  paver::DevicePartitionerFactory::Register(std::make_unique<paver::SherlockPartitionerFactory>());
-  paver::DevicePartitionerFactory::Register(std::make_unique<paver::LuisPartitionerFactory>());
-  paver::DevicePartitionerFactory::Register(std::make_unique<paver::Vim3PartitionerFactory>());
-  paver::DevicePartitionerFactory::Register(std::make_unique<paver::VioletPartitionerFactory>());
-  paver::DevicePartitionerFactory::Register(std::make_unique<paver::X64PartitionerFactory>());
-  paver::DevicePartitionerFactory::Register(std::make_unique<paver::DefaultPartitionerFactory>());
   abr::ClientFactory::Register(std::make_unique<paver::AstroAbrClientFactory>());
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::NelsonPartitionerFactory>());
   abr::ClientFactory::Register(std::make_unique<paver::NelsonAbrClientFactory>());
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::SherlockPartitionerFactory>());
   abr::ClientFactory::Register(std::make_unique<paver::SherlockAbrClientFactory>());
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::LuisPartitionerFactory>());
   abr::ClientFactory::Register(std::make_unique<paver::LuisAbrClientFactory>());
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::Vim3PartitionerFactory>());
   abr::ClientFactory::Register(std::make_unique<paver::Vim3AbrClientFactory>());
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::VioletPartitionerFactory>());
   abr::ClientFactory::Register(std::make_unique<paver::VioletAbrClientFactory>());
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::X64PartitionerFactory>());
   abr::ClientFactory::Register(std::make_unique<paver::X64AbrClientFactory>());
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::DefaultPartitionerFactory>());
+#elif defined(astro)
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::AstroPartitionerFactory>());
+  abr::ClientFactory::Register(std::make_unique<paver::AstroAbrClientFactory>());
+#elif defined(nelson)
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::NelsonPartitionerFactory>());
+  abr::ClientFactory::Register(std::make_unique<paver::NelsonAbrClientFactory>());
+#elif defined(sherlock)
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::SherlockPartitionerFactory>());
+  abr::ClientFactory::Register(std::make_unique<paver::SherlockAbrClientFactory>());
+#elif defined(luis)
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::LuisPartitionerFactory>());
+  abr::ClientFactory::Register(std::make_unique<paver::LuisAbrClientFactory>());
+#elif defined(vim3)
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::Vim3PartitionerFactory>());
+  abr::ClientFactory::Register(std::make_unique<paver::Vim3AbrClientFactory>());
+#elif defined(violet)
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::VioletPartitionerFactory>());
+  abr::ClientFactory::Register(std::make_unique<paver::VioletAbrClientFactory>());
+#elif defined(x64)
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::X64PartitionerFactory>());
+  abr::ClientFactory::Register(std::make_unique<paver::X64AbrClientFactory>());
+#else
+  paver::DevicePartitionerFactory::Register(std::make_unique<paver::DefaultPartitionerFactory>());
+#endif
 
   fidl::ServerBindingGroup<fuchsia_paver::Paver> bindings;
   zx::result result = outgoing.AddUnmanagedProtocol<fuchsia_paver::Paver>(
diff --git a/src/bringup/bin/ptysvc/pty-tests.cc b/src/bringup/bin/ptysvc/pty-tests.cc
index d8cd838..76ac1a1 100644
--- a/src/bringup/bin/ptysvc/pty-tests.cc
+++ b/src/bringup/bin/ptysvc/pty-tests.cc
@@ -30,9 +30,7 @@
     zx::result args = PtyServer::Args::Create();
     ASSERT_OK(args.status_value());
     std::shared_ptr server = std::make_shared<PtyServer>(std::move(args.value()), dispatcher());
-    zx::result endpoints = fidl::CreateEndpoints<Device>();
-    ASSERT_OK(endpoints.status_value());
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<Device>::Create();
 
     async::PostTask(dispatcher(),
                     [server = std::move(server), server_end = std::move(server_end)]() mutable {
diff --git a/src/camera/bin/camera-gym/screen_util.h b/src/camera/bin/camera-gym/screen_util.h
index cb16883..7fced40 100644
--- a/src/camera/bin/camera-gym/screen_util.h
+++ b/src/camera/bin/camera-gym/screen_util.h
@@ -4,6 +4,7 @@
 #ifndef SRC_CAMERA_BIN_CAMERA_GYM_SCREEN_UTIL_H_
 #define SRC_CAMERA_BIN_CAMERA_GYM_SCREEN_UTIL_H_
 
+#include <cstdint>
 #include <tuple>
 
 namespace screen_util {
diff --git a/src/camera/drivers/controller/test/device_test.cc b/src/camera/drivers/controller/test/device_test.cc
index 20db73ba..98adb64 100644
--- a/src/camera/drivers/controller/test/device_test.cc
+++ b/src/camera/drivers/controller/test/device_test.cc
@@ -26,12 +26,11 @@
 
     // Create sysmem fragment
     auto sysmem_handler = sysmem_.SyncCall(&FakeSysmem::CreateInstanceHandler);
-    auto sysmem_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(sysmem_endpoints.is_ok());
+    auto sysmem_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     root_->AddFidlService(fuchsia_hardware_sysmem::Service::Name,
-                          std::move(sysmem_endpoints->client), "sysmem");
+                          std::move(sysmem_endpoints.client), "sysmem");
 
-    outgoing_.SyncCall([sysmem_server = std::move(sysmem_endpoints->server),
+    outgoing_.SyncCall([sysmem_server = std::move(sysmem_endpoints.server),
                         sysmem_handler = std::move(sysmem_handler)](
                            component::OutgoingDirectory* outgoing) mutable {
       ZX_ASSERT(outgoing->Serve(std::move(sysmem_server)).is_ok());
@@ -89,11 +88,10 @@
   }
 
   void BindControllerProtocol() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_camera::Device>();
-    ASSERT_EQ(endpoints.status_value(), ZX_OK);
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), controller_device_);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_camera::Device>::Create();
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), controller_device_);
 
-    ASSERT_EQ(camera_protocol_.Bind(endpoints->client.TakeChannel()), ZX_OK);
+    ASSERT_EQ(camera_protocol_.Bind(endpoints.client.TakeChannel()), ZX_OK);
     camera_protocol_.set_error_handler(FailErrorHandler);
     camera_protocol_->GetChannel2(controller_protocol_.NewRequest());
     controller_protocol_.set_error_handler(FailErrorHandler);
@@ -124,11 +122,10 @@
 
 // Verifies GetChannel is not supported.
 TEST_F(ControllerDeviceTest, GetChannel) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_camera::Device>();
-  ASSERT_EQ(endpoints.status_value(), ZX_OK);
-  fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), controller_device_);
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_camera::Device>::Create();
+  fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), controller_device_);
 
-  ASSERT_EQ(camera_protocol_.Bind(endpoints->client.TakeChannel()), ZX_OK);
+  ASSERT_EQ(camera_protocol_.Bind(endpoints.client.TakeChannel()), ZX_OK);
   camera_protocol_->GetChannel(controller_protocol_.NewRequest().TakeChannel());
   RunLoopUntilIdle();
   WaitForChannelClosure(controller_protocol_.channel());
@@ -137,11 +134,10 @@
 
 // Verifies that GetChannel2 works correctly.
 TEST_F(ControllerDeviceTest, GetChannel2) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_camera::Device>();
-  ASSERT_EQ(endpoints.status_value(), ZX_OK);
-  fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), controller_device_);
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_camera::Device>::Create();
+  fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), controller_device_);
 
-  ASSERT_EQ(camera_protocol_.Bind(endpoints->client.TakeChannel()), ZX_OK);
+  ASSERT_EQ(camera_protocol_.Bind(endpoints.client.TakeChannel()), ZX_OK);
   camera_protocol_->GetChannel2(controller_protocol_.NewRequest());
   camera_protocol_.set_error_handler(FailErrorHandler);
   RunLoopUntilIdle();
@@ -149,11 +145,10 @@
 
 // Verifies that GetChannel2 can only have one binding.
 TEST_F(ControllerDeviceTest, GetChannel2InvokeTwice) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_camera::Device>();
-  ASSERT_EQ(endpoints.status_value(), ZX_OK);
-  fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), controller_device_);
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_camera::Device>::Create();
+  fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), controller_device_);
 
-  ASSERT_EQ(camera_protocol_.Bind(endpoints->client.TakeChannel()), ZX_OK);
+  ASSERT_EQ(camera_protocol_.Bind(endpoints.client.TakeChannel()), ZX_OK);
   camera_protocol_->GetChannel2(controller_protocol_.NewRequest());
   RunLoopUntilIdle();
   fuchsia::camera2::hal::ControllerPtr other_controller_protocol;
diff --git a/src/camera/drivers/controller/test/fake_sysmem.h b/src/camera/drivers/controller/test/fake_sysmem.h
index 8843a0a..4739d10 100644
--- a/src/camera/drivers/controller/test/fake_sysmem.h
+++ b/src/camera/drivers/controller/test/fake_sysmem.h
@@ -28,11 +28,10 @@
   }
 
   fidl::ClientEnd<fuchsia_hardware_sysmem::Sysmem> Connect() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_sysmem::Sysmem>();
-    ZX_ASSERT(endpoints.is_ok());
-    sysmem_bindings_.AddBinding(async_get_default_dispatcher(), std::move(endpoints->server), this,
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_sysmem::Sysmem>::Create();
+    sysmem_bindings_.AddBinding(async_get_default_dispatcher(), std::move(endpoints.server), this,
                                 fidl::kIgnoreBindingClosure);
-    return std::move(endpoints->client);
+    return std::move(endpoints.client);
   }
 
  private:
diff --git a/src/camera/drivers/hw_accel/gdc/BUILD.gn b/src/camera/drivers/hw_accel/gdc/BUILD.gn
index 7dff6c4..e9057fa 100644
--- a/src/camera/drivers/hw_accel/gdc/BUILD.gn
+++ b/src/camera/drivers/hw_accel/gdc/BUILD.gn
@@ -87,7 +87,7 @@
     "//src/devices/lib/driver",
     "//src/devices/lib/mmio",
     "//src/devices/testing/fake-bti",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//src/devices/testing/no_ddk",
     "//src/lib/fsl",
     "//zircon/system/ulib/zx",
diff --git a/src/camera/drivers/hw_accel/gdc/gdc_task_unittest.cc b/src/camera/drivers/hw_accel/gdc/gdc_task_unittest.cc
index b63c95f..294571b 100644
--- a/src/camera/drivers/hw_accel/gdc/gdc_task_unittest.cc
+++ b/src/camera/drivers/hw_accel/gdc/gdc_task_unittest.cc
@@ -14,7 +14,7 @@
 #include <utility>
 #include <vector>
 
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 #include <zxtest/zxtest.h>
 
 #include "src/camera/drivers/hw_accel/gdc/gdc.h"
diff --git a/src/camera/drivers/hw_accel/ge2d/BUILD.gn b/src/camera/drivers/hw_accel/ge2d/BUILD.gn
index 74d8bbb..01525e1 100644
--- a/src/camera/drivers/hw_accel/ge2d/BUILD.gn
+++ b/src/camera/drivers/hw_accel/ge2d/BUILD.gn
@@ -107,7 +107,7 @@
     "//src/devices/lib/mmio",
     "//src/devices/lib/sysmem",
     "//src/devices/testing/fake-bti",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//src/devices/testing/no_ddk",
     "//src/lib/ddk",
     "//src/lib/fsl",
diff --git a/src/camera/drivers/hw_accel/ge2d/ge2d_task_unittest.cc b/src/camera/drivers/hw_accel/ge2d/ge2d_task_unittest.cc
index cedb96e..f6bc6f9 100644
--- a/src/camera/drivers/hw_accel/ge2d/ge2d_task_unittest.cc
+++ b/src/camera/drivers/hw_accel/ge2d/ge2d_task_unittest.cc
@@ -24,7 +24,7 @@
 #include <utility>
 #include <vector>
 
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 #include <zxtest/zxtest.h>
 
 #include "src/camera/drivers/hw_accel/ge2d/ge2d.h"
diff --git a/src/camera/drivers/sensors/imx227/imx227_unittest.cc b/src/camera/drivers/sensors/imx227/imx227_unittest.cc
index b31d830..e4c1254 100644
--- a/src/camera/drivers/sensors/imx227/imx227_unittest.cc
+++ b/src/camera/drivers/sensors/imx227/imx227_unittest.cc
@@ -172,12 +172,11 @@
   }
 
   void SetProtocols() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
 
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &mock_i2c_);
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &mock_i2c_);
 
-    i2c_ = ddk::I2cChannel(std::move(endpoints->client));
+    i2c_ = ddk::I2cChannel(std::move(endpoints.client));
     mipi_ = ddk::MipiCsiProtocolClient(mock_mipi_.GetProto());
 
     EXPECT_OK(loop_.StartThread());
diff --git a/src/connectivity/bluetooth/core/bt-gap/BUILD.gn b/src/connectivity/bluetooth/core/bt-gap/BUILD.gn
index 8c6e9b51..fc50acc 100644
--- a/src/connectivity/bluetooth/core/bt-gap/BUILD.gn
+++ b/src/connectivity/bluetooth/core/bt-gap/BUILD.gn
@@ -15,11 +15,11 @@
     "//sdk/fidl/fuchsia.bluetooth.bredr:fuchsia.bluetooth.bredr_rust",
     "//sdk/fidl/fuchsia.bluetooth.gatt:fuchsia.bluetooth.gatt_rust",
     "//sdk/fidl/fuchsia.bluetooth.gatt2:fuchsia.bluetooth.gatt2_rust",
+    "//sdk/fidl/fuchsia.bluetooth.host:fuchsia.bluetooth.host_rust",
     "//sdk/fidl/fuchsia.bluetooth.le:fuchsia.bluetooth.le_rust",
     "//sdk/fidl/fuchsia.bluetooth.sys:fuchsia.bluetooth.sys_rust",
     "//sdk/fidl/fuchsia.device:fuchsia.device_rust",
     "//sdk/fidl/fuchsia.stash:fuchsia.stash_rust",
-    "//src/connectivity/bluetooth/fidl:host_rust",
     "//src/connectivity/bluetooth/lib/async-helpers",
     "//src/connectivity/bluetooth/lib/fuchsia-bluetooth",
     "//src/lib/async-utils",
@@ -34,7 +34,6 @@
     "//src/lib/zircon/rust:fuchsia-zircon",
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:futures",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:serde",
     "//third_party/rust_crates:serde_json",
     "//third_party/rust_crates:slab",
diff --git a/src/connectivity/bluetooth/core/bt-gap/src/host_device.rs b/src/connectivity/bluetooth/core/bt-gap/src/host_device.rs
index 8b6f362..eb1e388 100644
--- a/src/connectivity/bluetooth/core/bt-gap/src/host_device.rs
+++ b/src/connectivity/bluetooth/core/bt-gap/src/host_device.rs
@@ -171,8 +171,8 @@
         self.0.proxy.forget(&id).map(from_fidl_result)
     }
 
-    pub fn close(&self) -> types::Result<()> {
-        self.0.proxy.close().map_err(|e| e.into())
+    pub fn shutdown(&self) -> types::Result<()> {
+        self.0.proxy.shutdown().map_err(|e| e.into())
     }
 
     pub fn restore_bonds(
@@ -332,6 +332,9 @@
                             error!("Failed to persist bonding data: {:#?}", e);
                         }
                     }
+                    HostEvent::_UnknownEvent { ordinal, .. } => {
+                        warn!("Received unknown event with ordinal {ordinal}");
+                    }
                 };
             }
             Err(types::Error::InternalError(format_err!("Host FIDL event stream terminated")))
diff --git a/src/connectivity/bluetooth/core/bt-gap/src/host_dispatcher.rs b/src/connectivity/bluetooth/core/bt-gap/src/host_dispatcher.rs
index b3c7ca9..2e3661f 100644
--- a/src/connectivity/bluetooth/core/bt-gap/src/host_dispatcher.rs
+++ b/src/connectivity/bluetooth/core/bt-gap/src/host_dispatcher.rs
@@ -11,7 +11,7 @@
 use fidl_fuchsia_bluetooth_gatt2::{
     LocalServiceRequest, Server_Marker as Server_Marker2, Server_Proxy,
 };
-use fidl_fuchsia_bluetooth_host::HostProxy;
+use fidl_fuchsia_bluetooth_host::{HostProxy, ProtocolRequest};
 use fidl_fuchsia_bluetooth_le::{CentralMarker, PeripheralMarker};
 use fidl_fuchsia_bluetooth_sys::{
     self as sys, InputCapability, OutputCapability, PairingDelegateProxy,
@@ -224,7 +224,7 @@
             }
 
             // Shut down the previously active host.
-            let _ = self.host_devices[&id].close();
+            let _ = self.host_devices[&id].shutdown();
         }
 
         if self.host_devices.contains_key(&adapter_id) {
@@ -636,23 +636,23 @@
                 match service {
                     HostService::LeCentral => {
                         let remote = ServerEnd::<CentralMarker>::new(chan.into());
-                        let _ = host.request_low_energy_central(remote);
+                        let _ = host.request_protocol(ProtocolRequest::Central(remote));
                     }
                     HostService::LePeripheral => {
                         let remote = ServerEnd::<PeripheralMarker>::new(chan.into());
-                        let _ = host.request_low_energy_peripheral(remote);
+                        let _ = host.request_protocol(ProtocolRequest::Peripheral(remote));
                     }
                     HostService::LeGatt => {
                         let remote = ServerEnd::<Server_Marker>::new(chan.into());
-                        let _ = host.request_gatt_server_(remote);
+                        let _ = host.request_protocol(ProtocolRequest::GattServer(remote));
                     }
                     HostService::LeGatt2 => {
                         let remote = ServerEnd::<Server_Marker2>::new(chan.into());
-                        let _ = host.request_gatt2_server_(remote);
+                        let _ = host.request_protocol(ProtocolRequest::Gatt2Server(remote));
                     }
                     HostService::Profile => {
                         let remote = ServerEnd::<ProfileMarker>::new(chan.into());
-                        let _ = host.request_profile(remote);
+                        let _ = host.request_protocol(ProtocolRequest::Profile(remote));
                     }
                 }
             }
@@ -801,7 +801,7 @@
         let (gatt_server_proxy, remote_gatt_server) = fidl::endpoints::create_proxy()?;
         host_device
             .proxy()
-            .request_gatt2_server_(remote_gatt_server)
+            .request_protocol(ProtocolRequest::Gatt2Server(remote_gatt_server))
             .context(format!("{:?}: failed to open gatt server for bt-host", dbg_ids))?;
         self.spawn_gas_proxy(gatt_server_proxy)
             .await
@@ -1139,7 +1139,10 @@
                     info!("Setting Device Class");
                     let _ = responder.send(Ok(()));
                 }
-                Some(Ok(HostRequest::RequestGatt2Server_ { server, .. })) => {
+                Some(Ok(HostRequest::RequestProtocol {
+                    payload: ProtocolRequest::Gatt2Server(server),
+                    ..
+                })) => {
                     // don't respond at all on the server side.
                     info!("Storing Gatt Server");
                     let mut gatt_server = server.into_stream().unwrap();
diff --git a/src/connectivity/bluetooth/core/bt-gap/src/services/pairing/pairing_requests.rs b/src/connectivity/bluetooth/core/bt-gap/src/services/pairing/pairing_requests.rs
index ff63615..0e7633f 100644
--- a/src/connectivity/bluetooth/core/bt-gap/src/services/pairing/pairing_requests.rs
+++ b/src/connectivity/bluetooth/core/bt-gap/src/services/pairing/pairing_requests.rs
@@ -8,8 +8,8 @@
     futures::{
         future::BoxFuture,
         stream::{FusedStream, FuturesUnordered, Stream},
+        StreamExt,
     },
-    pin_utils::unsafe_pinned,
     std::{
         collections::HashMap,
         pin::Pin,
@@ -24,8 +24,6 @@
     inner: StreamMap<HostId, FuturesUnordered<Tagged<PeerId, BoxFuture<'static, T>>>>,
 }
 
-impl<T: Unpin> Unpin for PairingRequests<T> {}
-
 impl<T> PairingRequests<T> {
     /// Create a new empty PairingRequests<T>
     pub fn empty() -> PairingRequests<T> {
@@ -51,15 +49,6 @@
             .map(|(host, mut futs)| (host, futs.iter_mut().map(|f| f.tag()).collect()))
             .collect()
     }
-
-    // It is safe to take a pinned projection to `inner` as:
-    // * PairingRequests does not implement `Drop`
-    // * PairingRequests only implements Unpin if `inner` is Unpin.
-    // * PairingRequests is not #[repr(packed)].
-    // see: pin_utils::unsafe_pinned docs for details
-    unsafe_pinned!(
-        inner: StreamMap<HostId, FuturesUnordered<Tagged<PeerId, BoxFuture<'static, T>>>>
-    );
 }
 
 impl<T> FusedStream for PairingRequests<T> {
@@ -72,7 +61,7 @@
 impl<T> Stream for PairingRequests<T> {
     type Item = (PeerId, T);
 
-    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
-        self.inner().poll_next(cx)
+    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        self.inner.poll_next_unpin(cx)
     }
 }
diff --git a/src/connectivity/bluetooth/core/bt-gap/src/test/receiver.rs b/src/connectivity/bluetooth/core/bt-gap/src/test/receiver.rs
index cc4c50a..aa7d6e0 100644
--- a/src/connectivity/bluetooth/core/bt-gap/src/test/receiver.rs
+++ b/src/connectivity/bluetooth/core/bt-gap/src/test/receiver.rs
@@ -8,7 +8,9 @@
 use async_helpers::hanging_get::asynchronous as hanging_get;
 use fidl::endpoints::{self, Responder};
 use fidl_fuchsia_bluetooth_gatt2::Server_Request;
-use fidl_fuchsia_bluetooth_host::{HostMarker, HostRequest, HostRequestStream, ReceiverMarker};
+use fidl_fuchsia_bluetooth_host::{
+    HostMarker, HostRequest, HostRequestStream, ProtocolRequest, ReceiverMarker,
+};
 use fidl_fuchsia_bluetooth_sys::{HostInfo as FidlHostInfo, TechnologyType};
 use fuchsia_async as fasync;
 use fuchsia_bluetooth::types::{Address, HostId, HostInfo};
@@ -68,7 +70,9 @@
                 info!("SetLocalName request");
                 assert_matches::assert_matches!(responder.send(Ok(())), Ok(()));
             }
-            HostRequest::RequestGatt2Server_ { server, .. } => {
+            HostRequest::RequestProtocol {
+                payload: ProtocolRequest::Gatt2Server(server), ..
+            } => {
                 info!("RequestGatt2Server request");
                 let mut gatt_server = server.into_stream().unwrap();
                 match gatt_server.next().await {
diff --git a/src/connectivity/bluetooth/core/bt-host/BUILD.gn b/src/connectivity/bluetooth/core/bt-host/BUILD.gn
index 43b038f..51ee080 100644
--- a/src/connectivity/bluetooth/core/bt-host/BUILD.gn
+++ b/src/connectivity/bluetooth/core/bt-host/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/bind/bind.gni")
 import("//build/components.gni")
 import("//build/fuzz.gni")
+import("//build/packages/prebuilt_package.gni")
 import("//src/connectivity/bluetooth/core/bt-host/build/bt_gtest_package.gni")
 
 source_set("sources") {
@@ -31,15 +32,14 @@
     ":stack",
     "fidl",
     "//sdk/banjo/fuchsia.hardware.bt.vendor:fuchsia.hardware.bt.vendor_banjo_cpp",
+    "//sdk/fidl/fuchsia.bluetooth.host:fuchsia.bluetooth.host_hlcpp",
     "//sdk/fidl/fuchsia.hardware.bluetooth:fuchsia.hardware.bluetooth_cpp",
     "//sdk/fidl/fuchsia.process.lifecycle:fuchsia.process.lifecycle_hlcpp",
     "//sdk/lib/fit",
     "//sdk/lib/sys/cpp",
-    "//src/connectivity/bluetooth/fidl:host_hlcpp",
     "//src/connectivity/bluetooth/lib/fidl",
     "//zircon/system/ulib/async-loop:async-loop-cpp",
     "//zircon/system/ulib/async-loop:async-loop-default",
-    "//zircon/system/ulib/fbl",
     "//zircon/system/ulib/trace",
     "//zircon/system/ulib/zx",
   ]
@@ -90,6 +90,16 @@
   deps = [ ":bin" ]
 }
 
+# This is the OOT built bt-host component.
+# See https://pigweed.dev/pw_bluetooth_sapphire/.
+# TODO(https://fxbug.dev/324107025): Rename this target to "bt-host" and update
+#   `//build:non_hermetic_deps` once it's fully migrated OOT.
+prebuilt_package("bt-host-oot") {
+  # component-url: fuchsia-pkg://fuchsia.com/bt-host#meta/bt-host.cm
+  package_name = "bt-host"
+  archive = "//prebuilt/connectivity/bluetooth/bt-host/$target_cpu/bt-host"
+}
+
 fuchsia_package("bt-host") {
   deps = [
     # component-url: fuchsia-pkg://fuchsia.com/bt-host#meta/bt-host.cm
diff --git a/src/connectivity/bluetooth/core/bt-host/controllers/BUILD.gn b/src/connectivity/bluetooth/core/bt-host/controllers/BUILD.gn
index dd9a593..8708ac5 100644
--- a/src/connectivity/bluetooth/core/bt-host/controllers/BUILD.gn
+++ b/src/connectivity/bluetooth/core/bt-host/controllers/BUILD.gn
@@ -6,10 +6,7 @@
 import("//src/connectivity/bluetooth/core/bt-host/build/bt_gtest_package.gni")
 
 group("controllers") {
-  public_deps = [
-    ":banjo_controller",
-    ":fidl_controller",
-  ]
+  public_deps = [ ":fidl_controller" ]
 }
 
 source_set("helpers") {
@@ -26,31 +23,6 @@
   ]
 }
 
-source_set("banjo_controller") {
-  sources = [
-    "banjo_controller.cc",
-    "banjo_controller.h",
-  ]
-
-  deps = [
-    ":helpers",
-    "//src/connectivity/bluetooth/core/bt-host/common",
-    "//src/connectivity/bluetooth/core/bt-host/iso",
-    "//src/connectivity/bluetooth/core/bt-host/transport",
-    "//src/lib/ddk",
-    "//zircon/system/ulib/async:async-cpp",
-    "//zircon/system/ulib/fbl",
-    "//zircon/system/ulib/zx",
-  ]
-
-  public_deps = [
-    "$dir_pw_bluetooth",
-    "//sdk/banjo/fuchsia.hardware.bt.hci:fuchsia.hardware.bt.hci_banjo_cpp",
-    "//sdk/banjo/fuchsia.hardware.bt.vendor:fuchsia.hardware.bt.vendor_banjo_cpp",
-    "//zircon/system/ulib/async",
-  ]
-}
-
 source_set("fidl_controller") {
   sources = [
     "fidl_controller.cc",
@@ -62,7 +34,6 @@
     "//src/connectivity/bluetooth/core/bt-host/common",
     "//src/connectivity/bluetooth/core/bt-host/iso",
     "//src/connectivity/bluetooth/core/bt-host/transport",
-    "//src/lib/ddk",
     "//zircon/system/ulib/async:async-cpp",
     "//zircon/system/ulib/zx",
   ]
@@ -78,19 +49,14 @@
 source_set("tests") {
   testonly = true
 
-  sources = [
-    "banjo_controller_test.cc",
-    "fidl_controller_test.cc",
-  ]
+  sources = [ "fidl_controller_test.cc" ]
 
   deps = [
     ":controllers",
     "//src/connectivity/bluetooth/core/bt-host/fidl:fake_hci_test_fixture",
     "//src/connectivity/bluetooth/core/bt-host/testing",
+    "//src/connectivity/bluetooth/core/bt-host/testing:loop_fixture",
     "//src/connectivity/bluetooth/core/bt-host/testing:test_helpers",
-    "//src/devices/testing/mock-ddk",
-    "//src/lib/ddktl",
-    "//src/lib/testing/loop_fixture",
     "//third_party/googletest:gmock",
     "//third_party/googletest:gtest",
   ]
diff --git a/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller.cc b/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller.cc
deleted file mode 100644
index 63875ead..0000000
--- a/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller.cc
+++ /dev/null
@@ -1,487 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "banjo_controller.h"
-
-#include <lib/async/cpp/task.h>
-#include <lib/fit/defer.h>
-
-#include <variant>
-
-#include "helpers.h"
-#include "pw_result/result.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/assert.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/log.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/trace.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/iso/iso_common.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/slab_allocators.h"
-
-namespace bt::controllers {
-
-namespace {
-
-sco_coding_format_t ScoCodingFormatToBanjo(
-    pw::bluetooth::Controller::ScoCodingFormat coding_format) {
-  switch (coding_format) {
-    case pw::bluetooth::Controller::ScoCodingFormat::kCvsd:
-      return SCO_CODING_FORMAT_CVSD;
-    case pw::bluetooth::Controller::ScoCodingFormat::kMsbc:
-      return SCO_CODING_FORMAT_MSBC;
-    default:
-      BT_PANIC("invalid SCO coding format");
-  }
-}
-
-sco_encoding_t ScoEncodingToBanjo(pw::bluetooth::Controller::ScoEncoding encoding) {
-  switch (encoding) {
-    case pw::bluetooth::Controller::ScoEncoding::k8Bits:
-      return SCO_ENCODING_BITS_8;
-    case pw::bluetooth::Controller::ScoEncoding::k16Bits:
-      return SCO_ENCODING_BITS_16;
-    default:
-      BT_PANIC("invalid SCO encoding");
-  }
-}
-
-sco_sample_rate_t ScoSampleRateToBanjo(pw::bluetooth::Controller::ScoSampleRate sample_rate) {
-  switch (sample_rate) {
-    case pw::bluetooth::Controller::ScoSampleRate::k8Khz:
-      return SCO_SAMPLE_RATE_KHZ_8;
-    case pw::bluetooth::Controller::ScoSampleRate::k16Khz:
-      return SCO_SAMPLE_RATE_KHZ_16;
-    default:
-      BT_PANIC("invalid SCO sample rate");
-  }
-}
-
-bt_vendor_acl_priority_t AclPriorityToBanjo(pw::bluetooth::AclPriority priority) {
-  switch (priority) {
-    case pw::bluetooth::AclPriority::kNormal:
-      return BT_VENDOR_ACL_PRIORITY_NORMAL;
-    case pw::bluetooth::AclPriority::kSink:
-    case pw::bluetooth::AclPriority::kSource:
-      return BT_VENDOR_ACL_PRIORITY_HIGH;
-  }
-}
-
-bt_vendor_acl_direction_t AclPriorityToBanjoAclDirection(pw::bluetooth::AclPriority priority) {
-  switch (priority) {
-    // The direction for kNormal is arbitrary.
-    case pw::bluetooth::AclPriority::kNormal:
-    case pw::bluetooth::AclPriority::kSink:
-      return BT_VENDOR_ACL_DIRECTION_SINK;
-    case pw::bluetooth::AclPriority::kSource:
-      return BT_VENDOR_ACL_DIRECTION_SOURCE;
-  }
-}
-
-}  // namespace
-
-BanjoController::BanjoController(ddk::BtHciProtocolClient hci_proto,
-                                 std::optional<ddk::BtVendorProtocolClient> vendor_proto,
-                                 async_dispatcher_t* dispatcher)
-    : hci_proto_(hci_proto),
-      vendor_proto_(vendor_proto),
-      dispatcher_(dispatcher),
-      callback_data_(fbl::AdoptRef(new CallbackData{.dispatcher = dispatcher})) {}
-
-BanjoController::~BanjoController() { CleanUp(); }
-
-void BanjoController::Initialize(PwStatusCallback complete_callback,
-                                 PwStatusCallback error_callback) {
-  error_cb_ = std::move(error_callback);
-
-  zx::channel their_command_chan;
-  zx_status_t status = zx::channel::create(0, &command_channel_, &their_command_chan);
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "Failed to create command channel");
-    complete_callback(pw::Status::Internal());
-    return;
-  }
-
-  status = hci_proto_.OpenCommandChannel(std::move(their_command_chan));
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "Failed to open command channel");
-    complete_callback(pw::Status::Internal());
-    return;
-  }
-  InitializeWait(command_wait_, command_channel_);
-
-  zx::channel their_acl_chan;
-  status = zx::channel::create(0, &acl_channel_, &their_acl_chan);
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "Failed to create ACL channel");
-    complete_callback(pw::Status::Internal());
-    return;
-  }
-
-  status = hci_proto_.OpenAclDataChannel(std::move(their_acl_chan));
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "Failed to open ACL channel");
-    complete_callback(pw::Status::Internal());
-    return;
-  }
-  InitializeWait(acl_wait_, acl_channel_);
-
-  zx::channel their_sco_chan;
-  status = zx::channel::create(0, &sco_channel_, &their_sco_chan);
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "Failed to create SCO channel");
-    complete_callback(pw::Status::Internal());
-    return;
-  }
-
-  status = hci_proto_.OpenScoChannel(std::move(their_sco_chan));
-  if (status == ZX_OK) {
-    InitializeWait(sco_wait_, sco_channel_);
-  } else {
-    // Failing to open a SCO channel is not fatal, it just indicates lack of SCO support.
-    bt_log(INFO, "controllers", "Failed to open SCO channel: %s", zx_status_get_string(status));
-    sco_channel_.reset();
-  }
-
-  zx::channel their_iso_chan;
-  status = zx::channel::create(0, &iso_channel_, &their_iso_chan);
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "Failed to create ISO channel");
-    complete_callback(pw::Status::Internal());
-    return;
-  }
-
-  status = hci_proto_.OpenIsoDataChannel(std::move(their_iso_chan));
-  if (status == ZX_OK) {
-    InitializeWait(iso_wait_, iso_channel_);
-  } else {
-    // Failing to open an ISO channel is not fatal, it just indicates lack of ISO support.
-    bt_log(INFO, "controllers", "Failed to open ISO channel: %s", zx_status_get_string(status));
-    iso_channel_.reset();
-  }
-
-  complete_callback(PW_STATUS_OK);
-}
-
-void BanjoController::Close(PwStatusCallback callback) {
-  CleanUp();
-  callback(PW_STATUS_OK);
-}
-
-void BanjoController::SendCommand(pw::span<const std::byte> command) {
-  zx_status_t status =
-      command_channel_.write(/*flags=*/0, command.data(), static_cast<uint32_t>(command.size()),
-                             /*handles=*/nullptr, /*num_handles=*/0);
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "failed to write command channel: %s",
-           zx_status_get_string(status));
-    OnError(status);
-  }
-}
-
-void BanjoController::SendAclData(pw::span<const std::byte> data) {
-  zx_status_t status =
-      acl_channel_.write(/*flags=*/0, data.data(), static_cast<uint32_t>(data.size()),
-                         /*handles=*/nullptr, /*num_handles=*/0);
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "failed to write ACL channel: %s", zx_status_get_string(status));
-    OnError(status);
-  }
-}
-
-void BanjoController::SendScoData(pw::span<const std::byte> data) {
-  zx_status_t status =
-      sco_channel_.write(/*flags=*/0, data.data(), static_cast<uint32_t>(data.size()),
-                         /*handles=*/nullptr, /*num_handles=*/0);
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "failed to write SCO channel: %s", zx_status_get_string(status));
-    OnError(status);
-  }
-}
-
-void BanjoController::SendIsoData(pw::span<const std::byte> data) {
-  zx_status_t status =
-      iso_channel_.write(/*flags=*/0, data.data(), static_cast<uint32_t>(data.size()),
-                         /*handles=*/nullptr, /*num_handles=*/0);
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "failed to write ISO channel: %s", zx_status_get_string(status));
-    OnError(status);
-  }
-}
-
-void BanjoController::ConfigureSco(ScoCodingFormat coding_format, ScoEncoding encoding,
-                                   ScoSampleRate sample_rate, PwStatusCallback callback) {
-  hci_proto_.ConfigureSco(
-      ScoCodingFormatToBanjo(coding_format), ScoEncodingToBanjo(encoding),
-      ScoSampleRateToBanjo(sample_rate),
-      [](void* ctx, zx_status_t status) {
-        std::unique_ptr<PwStatusCallback> callback(static_cast<PwStatusCallback*>(ctx));
-        (*callback)(ZxStatusToPwStatus(status));
-      },
-      new PwStatusCallback(ThreadSafeCallbackWrapper(std::move(callback))));
-}
-
-void BanjoController::ResetSco(pw::Callback<void(pw::Status)> callback) {
-  hci_proto_.ResetSco(
-      [](void* ctx, zx_status_t status) {
-        std::unique_ptr<PwStatusCallback> callback(static_cast<PwStatusCallback*>(ctx));
-        (*callback)(ZxStatusToPwStatus(status));
-      },
-      new PwStatusCallback(ThreadSafeCallbackWrapper(std::move(callback))));
-}
-
-void BanjoController::GetFeatures(pw::Callback<void(FeaturesBits)> callback) {
-  if (!vendor_proto_) {
-    callback(FeaturesBits{0});
-    return;
-  }
-  FeaturesBits features_bits = BanjoVendorFeaturesToFeaturesBits(vendor_proto_->GetFeatures());
-  if (sco_channel_.is_valid()) {
-    features_bits |= FeaturesBits::kHciSco;
-  }
-  if (iso_channel_.is_valid()) {
-    features_bits |= FeaturesBits::kHciIso;
-  }
-  callback(features_bits);
-}
-
-void BanjoController::EncodeVendorCommand(
-    pw::bluetooth::VendorCommandParameters parameters,
-    pw::Callback<void(pw::Result<pw::span<const std::byte>>)> callback) {
-  BT_ASSERT(vendor_proto_.has_value());
-
-  if (!std::holds_alternative<pw::bluetooth::SetAclPriorityCommandParameters>(parameters)) {
-    callback(pw::Status::Unimplemented());
-    return;
-  }
-
-  pw::bluetooth::SetAclPriorityCommandParameters params =
-      std::get<pw::bluetooth::SetAclPriorityCommandParameters>(parameters);
-
-  bt_vendor_set_acl_priority_params_t priority_params = {
-      .connection_handle = params.connection_handle,
-      .priority = AclPriorityToBanjo(params.priority),
-      .direction = AclPriorityToBanjoAclDirection(params.priority)};
-  bt_vendor_params_t cmd_params = {.set_acl_priority = priority_params};
-
-  StaticByteBuffer<pw::bluetooth::kMaxVendorCommandBufferSize> encoded_command;
-  size_t actual_size = 0;
-  zx_status_t encode_result = vendor_proto_->EncodeCommand(
-      BT_VENDOR_COMMAND_SET_ACL_PRIORITY, &cmd_params, encoded_command.mutable_data(),
-      encoded_command.size(), &actual_size);
-
-  if (encode_result != ZX_OK) {
-    bt_log(WARN, "controllers", "Failed to encode vendor command");
-    callback(ZxStatusToPwStatus(encode_result));
-    return;
-  }
-  callback(encoded_command.subspan(/*pos=*/0, actual_size));
-}
-
-void BanjoController::OnError(zx_status_t status) {
-  CleanUp();
-
-  if (error_cb_) {
-    error_cb_(ZxStatusToPwStatus(status));
-  }
-}
-
-void BanjoController::CleanUp() {
-  {
-    std::lock_guard<std::mutex> guard(callback_data_->lock);
-    callback_data_->dispatcher = nullptr;
-  }
-
-  // Waits need to be canceled before the underlying channels are destroyed.
-  acl_wait_.Cancel();
-  command_wait_.Cancel();
-  sco_wait_.Cancel();
-  iso_wait_.Cancel();
-
-  acl_channel_.reset();
-  sco_channel_.reset();
-  iso_channel_.reset();
-  command_channel_.reset();
-}
-
-// Wraps a callback in one that posts on the bt-host thread.
-BanjoController::PwStatusCallback BanjoController::ThreadSafeCallbackWrapper(
-    PwStatusCallback callback) {
-  return [cb = std::move(callback), data = callback_data_](pw::Status status) mutable {
-    std::lock_guard<std::mutex> guard(data->lock);
-    // Don't run the callback if BanjoController has been destroyed.
-    if (data->dispatcher) {
-      // This callback may be run on a different thread, so post the result callback to the
-      // bt-host thread.
-      async::PostTask(data->dispatcher, [cb = std::move(cb), status]() mutable { cb(status); });
-    }
-  };
-}
-
-void BanjoController::InitializeWait(async::WaitBase& wait, zx::channel& channel) {
-  BT_ASSERT(channel.is_valid());
-  wait.Cancel();
-  wait.set_object(channel.get());
-  wait.set_trigger(ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED);
-  BT_ASSERT(wait.Begin(dispatcher_) == ZX_OK);
-}
-
-void BanjoController::OnChannelSignal(const char* chan_name, async::WaitBase* wait,
-                                      pw::span<std::byte> buffer, zx::channel& channel,
-                                      DataFunction& data_cb) {
-  uint32_t actual_size;
-  zx_status_t read_status =
-      channel.read(/*flags=*/0u, /*bytes=*/buffer.data(), /*handles=*/nullptr,
-                   /*num_bytes=*/static_cast<uint32_t>(buffer.size()), /*num_handles=*/0,
-                   /*actual_bytes=*/&actual_size, /*actual_handles=*/nullptr);
-
-  if (read_status != ZX_OK) {
-    bt_log(ERROR, "controllers", "%s channel: failed to read RX bytes: %s", chan_name,
-           zx_status_get_string(read_status));
-    OnError(read_status);
-    return;
-  }
-
-  if (data_cb) {
-    data_cb(buffer.subspan(0, actual_size));
-  } else {
-    bt_log(WARN, "controllers", "Dropping packet received on %s channel (no rx callback set)",
-           chan_name);
-  }
-
-  // The wait needs to be restarted after every signal.
-  zx_status_t wait_status = wait->Begin(dispatcher_);
-  if (wait_status != ZX_OK) {
-    bt_log(ERROR, "controllers", "%s wait error: %s", chan_name, zx_status_get_string(wait_status));
-    OnError(wait_status);
-    return;
-  }
-}
-
-void BanjoController::OnAclSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait,
-                                  zx_status_t status, const zx_packet_signal_t* signal) {
-  const char* kChannelName = "ACL";
-  TRACE_DURATION("bluetooth", "BanjoController::OnAclSignal");
-
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "%s channel error: %s", kChannelName,
-           zx_status_get_string(status));
-    OnError(status);
-    return;
-  }
-  if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
-    bt_log(ERROR, "controllers", "%s channel closed", kChannelName);
-    OnError(ZX_ERR_PEER_CLOSED);
-    return;
-  }
-  BT_ASSERT(signal->observed & ZX_CHANNEL_READABLE);
-
-  // Allocate a buffer for the packet. Since we don't know the size beforehand we allocate the
-  // largest possible buffer.
-  std::byte packet[hci::allocators::kLargeACLDataPacketSize];
-  OnChannelSignal(kChannelName, wait, packet, acl_channel_, acl_cb_);
-}
-
-void BanjoController::OnCommandSignal(async_dispatcher_t* /*dispatcher*/, async::WaitBase* wait,
-                                      zx_status_t status, const zx_packet_signal_t* signal) {
-  const char* kChannelName = "command";
-  TRACE_DURATION("bluetooth", "BanjoController::OnCommandSignal");
-
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "%s channel error: %s", kChannelName,
-           zx_status_get_string(status));
-    OnError(status);
-    return;
-  }
-  if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
-    bt_log(ERROR, "controllers", "%s channel closed", kChannelName);
-    OnError(ZX_ERR_PEER_CLOSED);
-    return;
-  }
-  BT_ASSERT(signal->observed & ZX_CHANNEL_READABLE);
-
-  // Allocate a buffer for the packet. Since we don't know the size beforehand we allocate the
-  // largest possible buffer.
-  std::byte packet[hci_spec::kMaxEventPacketPayloadSize + sizeof(hci_spec::EventHeader)];
-  OnChannelSignal(kChannelName, wait, packet, command_channel_, event_cb_);
-}
-
-void BanjoController::OnScoSignal(async_dispatcher_t* /*dispatcher*/, async::WaitBase* wait,
-                                  zx_status_t status, const zx_packet_signal_t* signal) {
-  const char* kChannelName = "SCO";
-  TRACE_DURATION("bluetooth", "BanjoController::OnScoSignal");
-
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "%s channel error: %s", kChannelName,
-           zx_status_get_string(status));
-    OnError(status);
-    return;
-  }
-  if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
-    bt_log(ERROR, "controllers", "%s channel closed", kChannelName);
-    OnError(ZX_ERR_PEER_CLOSED);
-    return;
-  }
-  BT_ASSERT(signal->observed & ZX_CHANNEL_READABLE);
-
-  // Allocate a buffer for the packet. Since we don't know the size beforehand we allocate the
-  // largest possible buffer.
-  std::byte packet[hci::allocators::kMaxScoDataPacketSize];
-  OnChannelSignal(kChannelName, wait, packet, sco_channel_, sco_cb_);
-}
-
-void BanjoController::OnIsoSignal(async_dispatcher_t* /*dispatcher*/, async::WaitBase* wait,
-                                  zx_status_t status, const zx_packet_signal_t* signal) {
-  const char* kChannelName = "ISO";
-  TRACE_DURATION("bluetooth", "BanjoController::OnIsoSignal");
-
-  if (status != ZX_OK) {
-    bt_log(ERROR, "controllers", "%s channel error: %s", kChannelName,
-           zx_status_get_string(status));
-    OnError(status);
-    return;
-  }
-  if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
-    bt_log(ERROR, "controllers", "%s channel closed", kChannelName);
-    OnError(ZX_ERR_PEER_CLOSED);
-    return;
-  }
-  BT_ASSERT(signal->observed & ZX_CHANNEL_READABLE);
-
-  // Isochronous data frames can be quite large (16KB), so dynamically allocate only what is needed.
-  uint32_t read_size = 0;
-  status = iso_channel_.read(/*flags=*/0u, /*bytes=*/nullptr, /*handles=*/nullptr, /*num_bytes=*/0u,
-                             /*num_handles=*/0, &read_size, /*actual_handles=*/nullptr);
-  if (status == ZX_OK) {
-    bt_log(WARN, "controllers", "%s channel: read 0-length packet", kChannelName);
-    return;
-  }
-  if (status != ZX_ERR_BUFFER_TOO_SMALL) {
-    bt_log(ERROR, "controllers", "%s channel: failed to read packet size: %s", kChannelName,
-           zx_status_get_string(status));
-    OnError(status);
-    return;
-  }
-  if (read_size > iso::kMaxIsochronousDataPacketSize) {
-    bt_log(ERROR, "controllers", "%s channel: packet size (%d) exceeds maximum (%zu)", kChannelName,
-           read_size, iso::kMaxIsochronousDataPacketSize);
-    OnError(status);
-    return;
-  }
-
-  std::unique_ptr<std::byte[]> buffer_ptr = std::make_unique<std::byte[]>(read_size);
-  pw::span<std::byte> packet{buffer_ptr.get(), read_size};
-  OnChannelSignal(kChannelName, wait, packet, iso_channel_, iso_cb_);
-}
-
-pw::bluetooth::Controller::FeaturesBits BanjoController::BanjoVendorFeaturesToFeaturesBits(
-    bt_vendor_features_t features) {
-  FeaturesBits out{0};
-  if (features & BT_VENDOR_FEATURES_SET_ACL_PRIORITY_COMMAND) {
-    out |= FeaturesBits::kSetAclPriorityCommand;
-  }
-  if (features & BT_VENDOR_FEATURES_ANDROID_VENDOR_EXTENSIONS) {
-    out |= FeaturesBits::kAndroidVendorExtensions;
-  }
-  return out;
-}
-
-}  // namespace bt::controllers
diff --git a/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller.h b/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller.h
deleted file mode 100644
index 5305a54..0000000
--- a/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller.h
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_CONTROLLERS_BANJO_CONTROLLER_H_
-#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_CONTROLLERS_BANJO_CONTROLLER_H_
-
-#include <fuchsia/hardware/bt/hci/cpp/banjo.h>
-#include <fuchsia/hardware/bt/vendor/cpp/banjo.h>
-#include <lib/async/cpp/wait.h>
-#include <lib/async/dispatcher.h>
-#include <lib/zx/channel.h>
-
-#include <mutex>
-
-#include <fbl/ref_counted.h>
-#include <fbl/ref_ptr.h>
-
-#include "pw_bluetooth/controller.h"
-#include "pw_bluetooth/vendor.h"
-
-namespace bt::controllers {
-
-// BanjoController is an implementation of Controller that uses the fuchsia.hardware.bt.hci/BtHci
-// and fuchsia.hardware.bt.vendor/BtVendor Banjo protocols to communicate with transport drivers.
-class BanjoController final : public pw::bluetooth::Controller {
- public:
-  using PwStatusCallback = pw::Callback<void(pw::Status)>;
-
-  // |vendor_proto| is optional. If the transport driver does not support the BtVendor protocol,
-  // this may be nullopt.
-  // |dispatcher| must outlive this object.
-  BanjoController(ddk::BtHciProtocolClient hci_proto,
-                  std::optional<ddk::BtVendorProtocolClient> vendor_proto,
-                  async_dispatcher_t* dispatcher);
-
-  ~BanjoController() override;
-
-  // Controller overrides:
-  void SetEventFunction(DataFunction func) override { event_cb_ = std::move(func); }
-
-  void SetReceiveAclFunction(DataFunction func) override { acl_cb_ = std::move(func); }
-
-  void SetReceiveScoFunction(DataFunction func) override { sco_cb_ = std::move(func); }
-
-  void SetReceiveIsoFunction(DataFunction func) override { iso_cb_ = std::move(func); }
-
-  void Initialize(PwStatusCallback complete_callback, PwStatusCallback error_callback) override;
-
-  void Close(PwStatusCallback callback) override;
-
-  void SendCommand(pw::span<const std::byte> command) override;
-
-  void SendAclData(pw::span<const std::byte> data) override;
-
-  void SendScoData(pw::span<const std::byte> data) override;
-
-  void SendIsoData(pw::span<const std::byte> data) override;
-
-  void ConfigureSco(ScoCodingFormat coding_format, ScoEncoding encoding, ScoSampleRate sample_rate,
-                    pw::Callback<void(pw::Status)> callback) override;
-
-  void ResetSco(pw::Callback<void(pw::Status)> callback) override;
-
-  void GetFeatures(pw::Callback<void(FeaturesBits)> callback) override;
-
-  void EncodeVendorCommand(
-      pw::bluetooth::VendorCommandParameters parameters,
-      pw::Callback<void(pw::Result<pw::span<const std::byte>>)> callback) override;
-
- private:
-  using ZxStatusCallback = fit::callback<void(zx_status_t)>;
-
-  // Used by Banjo callbacks to detect stack destruction & to dispatch callbacks onto the bt-host
-  // thread.
-  struct CallbackData : public fbl::RefCounted<CallbackData> {
-    // Lock to guard reads/writes to the |dispatcher| pointer variable below (not the underlying
-    // dispatcher). Calls to async::PostTask and async::WaitBase::Begin should be considered reads,
-    // and require the lock to be held.
-    std::mutex lock;
-    // Set to nullptr on BanjoController destruction to indicate to Banjo callbacks, which may run
-    // on an HCI driver thread, that they should do nothing. It is safe to access |dispatcher| on a
-    // different thread than |BanjoController::dispatcher_| because operations on the underying
-    // dispatcher, including waiting for signals and posting tasks, are thread-safe. The only
-    // concern is that the callbacks would use the dispatcher after it is destroyed and this pointer
-    // is invalid, but that is impossible because the dispatcher outlives BanjoController, and
-    // BanjoController sets |dispatcher| to null upon destruction.
-    async_dispatcher_t* dispatcher __TA_GUARDED(lock);
-  };
-
-  // Call to report an error to the client.
-  void OnError(zx_status_t status);
-
-  void CleanUp();
-
-  // Wraps a callback in a callback that posts the callback to the bt-host thread.
-  PwStatusCallback ThreadSafeCallbackWrapper(PwStatusCallback callback);
-
-  void InitializeWait(async::WaitBase& wait, zx::channel& channel);
-
-  void OnChannelSignal(const char* chan_name, async::WaitBase* wait, pw::span<std::byte> buffer,
-                       zx::channel& channel, DataFunction& data_cb);
-
-  void OnAclSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                   const zx_packet_signal_t* signal);
-
-  void OnCommandSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                       const zx_packet_signal_t* signal);
-
-  void OnScoSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                   const zx_packet_signal_t* signal);
-
-  void OnIsoSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                   const zx_packet_signal_t* signal);
-
-  pw::bluetooth::Controller::FeaturesBits BanjoVendorFeaturesToFeaturesBits(
-      bt_vendor_features_t features);
-
-  ddk::BtHciProtocolClient hci_proto_;
-  std::optional<ddk::BtVendorProtocolClient> vendor_proto_;
-
-  zx::channel acl_channel_;
-  zx::channel command_channel_;
-  zx::channel sco_channel_;
-  zx::channel iso_channel_;
-
-  DataFunction event_cb_;
-  DataFunction acl_cb_;
-  DataFunction sco_cb_;
-  DataFunction iso_cb_;
-  PwStatusCallback error_cb_;
-
-  async::WaitMethod<BanjoController, &BanjoController::OnAclSignal> acl_wait_{this};
-  async::WaitMethod<BanjoController, &BanjoController::OnCommandSignal> command_wait_{this};
-  async::WaitMethod<BanjoController, &BanjoController::OnScoSignal> sco_wait_{this};
-  async::WaitMethod<BanjoController, &BanjoController::OnIsoSignal> iso_wait_{this};
-
-  async_dispatcher_t* dispatcher_;
-
-  fbl::RefPtr<CallbackData> callback_data_;
-};
-
-}  // namespace bt::controllers
-
-#endif  // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_CONTROLLERS_BANJO_CONTROLLER_H_
diff --git a/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller_test.cc b/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller_test.cc
deleted file mode 100644
index 11b3dc2..0000000
--- a/src/connectivity/bluetooth/core/bt-host/controllers/banjo_controller_test.cc
+++ /dev/null
@@ -1,744 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "banjo_controller.h"
-
-#include <ddktl/device.h>
-
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/iso/iso_common.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/slab_allocators.h"
-#include "src/devices/testing/mock-ddk/mock-device.h"
-#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
-
-namespace bt::controllers {
-
-using FeaturesBits = pw::bluetooth::Controller::FeaturesBits;
-using ScoCodingFormat = pw::bluetooth::Controller::ScoCodingFormat;
-using ScoSampleRate = pw::bluetooth::Controller::ScoSampleRate;
-using ScoEncoding = pw::bluetooth::Controller::ScoEncoding;
-using pw::bluetooth::AclPriority;
-
-constexpr hci_spec::ConnectionHandle kConnectionHandle = 0x0001;
-
-const StaticByteBuffer kSetAclPriorityNormalCommand(0x01);
-const StaticByteBuffer kSetAclPrioritySourceCommand(0x02);
-const StaticByteBuffer kSetAclPrioritySinkCommand(0x03);
-
-class FakeDevice : public ddk::BtHciProtocol<FakeDevice>, public ddk::BtVendorProtocol<FakeDevice> {
- public:
-  using ConfigureScoCallback =
-      fit::function<void(sco_coding_format_t, sco_encoding_t, sco_sample_rate_t,
-                         bt_hci_configure_sco_callback, void*)>;
-  using ResetScoCallback = fit::function<void(bt_hci_reset_sco_callback, void*)>;
-
-  FakeDevice(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher) {}
-
-  zx_status_t SendEvent(BufferView event) {
-    return command_channel_.write(/*flags=*/0, event.data(), static_cast<uint32_t>(event.size()),
-                                  /*handles=*/nullptr, /*num_handles=*/0);
-  }
-  zx_status_t SendAcl(BufferView buffer) {
-    return acl_channel_.write(/*flags=*/0, buffer.data(), static_cast<uint32_t>(buffer.size()),
-                              /*handles=*/nullptr, /*num_handles=*/0);
-  }
-
-  zx_status_t SendSco(BufferView buffer) {
-    return sco_channel_.write(/*flags=*/0, buffer.data(), static_cast<uint32_t>(buffer.size()),
-                              /*handles=*/nullptr, /*num_handles=*/0);
-  }
-
-  zx_status_t SendIso(BufferView buffer) {
-    return iso_channel_.write(/*flags=*/0, buffer.data(), static_cast<uint32_t>(buffer.size()),
-                              /*handles=*/nullptr, /*num_handles=*/0);
-  }
-
-  void ResetCommandChannel() { command_channel_.reset(); }
-
-  const std::vector<bt::DynamicByteBuffer>& commands_received() const { return commands_received_; }
-  const std::vector<bt::DynamicByteBuffer>& acl_packets_received() const {
-    return acl_packets_received_;
-  }
-  const std::vector<bt::DynamicByteBuffer>& sco_packets_received() const {
-    return sco_packets_received_;
-  }
-  const std::vector<bt::DynamicByteBuffer>& iso_packets_received() const {
-    return iso_packets_received_;
-  }
-
-  bt_hci_protocol_t hci_proto() const {
-    bt_hci_protocol_t proto;
-    proto.ctx = const_cast<FakeDevice*>(this);
-    proto.ops = const_cast<bt_hci_protocol_ops_t*>(&bt_hci_protocol_ops_);
-    return proto;
-  }
-
-  bt_vendor_protocol_t vendor_proto() const {
-    bt_vendor_protocol_t proto;
-    proto.ctx = const_cast<FakeDevice*>(this);
-    proto.ops = const_cast<bt_vendor_protocol_ops_t*>(&bt_vendor_protocol_ops_);
-    return proto;
-  }
-
-  void set_sco_supported(bool supported) { sco_supported_ = supported; }
-
-  void set_command_channel_supported(bool supported) { command_channel_supported_ = supported; }
-
-  void set_acl_channel_supported(bool supported) { acl_channel_supported_ = supported; }
-
-  void set_iso_supported(bool supported) { iso_supported_ = supported; }
-
-  void set_features(bt_vendor_features_t features) { features_ = features; }
-
-  void set_encode_command_status(zx_status_t status) { encode_command_status_ = status; }
-
-  void set_configure_sco_callback(ConfigureScoCallback callback) {
-    configure_sco_cb_ = std::move(callback);
-  }
-
-  void set_reset_sco_callback(ResetScoCallback callback) { reset_sco_cb_ = std::move(callback); }
-
-  bool command_channel_is_valid() const { return command_channel_.is_valid(); }
-  bool acl_channel_is_valid() const { return acl_channel_.is_valid(); }
-  bool sco_channel_is_valid() const { return sco_channel_.is_valid(); }
-  bool iso_channel_is_valid() const { return iso_channel_.is_valid(); }
-
-  // ddk::BtHciProtocol mixins:
-
-  zx_status_t BtHciOpenCommandChannel(zx::channel in) {
-    if (!command_channel_supported_) {
-      return ZX_ERR_NOT_SUPPORTED;
-    }
-    command_channel_ = std::move(in);
-    InitializeWait(command_wait_, &command_channel_);
-    return ZX_OK;
-  }
-
-  zx_status_t BtHciOpenAclDataChannel(zx::channel in) {
-    if (!acl_channel_supported_) {
-      return ZX_ERR_NOT_SUPPORTED;
-    }
-    acl_channel_ = std::move(in);
-    InitializeWait(acl_wait_, &acl_channel_);
-    return ZX_OK;
-  }
-
-  zx_status_t BtHciOpenScoChannel(zx::channel in) {
-    if (!sco_supported_) {
-      return ZX_ERR_NOT_SUPPORTED;
-    }
-    sco_channel_ = std::move(in);
-    InitializeWait(sco_wait_, &sco_channel_);
-    return ZX_OK;
-  }
-
-  zx_status_t BtHciOpenIsoDataChannel(zx::channel in) {
-    if (!iso_supported_) {
-      return ZX_ERR_NOT_SUPPORTED;
-    }
-    iso_channel_ = std::move(in);
-    InitializeWait(iso_wait_, &iso_channel_);
-    return ZX_OK;
-  }
-
-  void BtHciConfigureSco(sco_coding_format_t coding_format, sco_encoding_t encoding,
-                         sco_sample_rate_t sample_rate, bt_hci_configure_sco_callback callback,
-                         void* cookie) {
-    if (configure_sco_cb_) {
-      configure_sco_cb_(coding_format, encoding, sample_rate, callback, cookie);
-    }
-  }
-
-  void BtHciResetSco(bt_hci_reset_sco_callback callback, void* cookie) {
-    if (reset_sco_cb_) {
-      reset_sco_cb_(callback, cookie);
-    }
-  }
-
-  zx_status_t BtHciOpenSnoopChannel(zx::channel in) { return ZX_ERR_NOT_SUPPORTED; }
-
-  // ddk::BtVendorProtocol mixins:
-
-  bt_vendor_features_t BtVendorGetFeatures() { return features_; }
-
-  zx_status_t BtVendorEncodeCommand(bt_vendor_command_t command, const bt_vendor_params_t* params,
-                                    uint8_t* out_encoded_buffer, size_t encoded_size,
-                                    size_t* out_encoded_actual) {
-    if (command != BT_VENDOR_COMMAND_SET_ACL_PRIORITY) {
-      return ZX_ERR_NOT_SUPPORTED;
-    }
-    bt_vendor_set_acl_priority_params_t acl_params = params->set_acl_priority;
-    EXPECT_EQ(acl_params.connection_handle, kConnectionHandle);
-    MutableBufferView out_buffer_view(out_encoded_buffer, encoded_size);
-    *out_encoded_actual = kSetAclPriorityNormalCommand.size();
-    if (acl_params.priority == BT_VENDOR_ACL_PRIORITY_NORMAL) {
-      kSetAclPriorityNormalCommand.Copy(&out_buffer_view);
-    } else if (acl_params.direction == BT_VENDOR_ACL_DIRECTION_SOURCE) {
-      kSetAclPrioritySourceCommand.Copy(&out_buffer_view);
-    } else {
-      kSetAclPrioritySinkCommand.Copy(&out_buffer_view);
-    }
-    return encode_command_status_;
-  }
-
- private:
-  void InitializeWait(async::WaitBase& wait, zx::channel* channel) {
-    BT_ASSERT(channel->is_valid());
-    wait.Cancel();
-    wait.set_object(channel->get());
-    wait.set_trigger(ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED);
-    BT_ASSERT(wait.Begin(dispatcher_) == ZX_OK);
-  }
-
-  void OnChannelSignal(zx::channel* channel, async::WaitBase* wait,
-                       const zx_packet_signal_t* signal,
-                       std::vector<DynamicByteBuffer>* out_vector) {
-    if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
-      channel->reset();
-      return;
-    }
-    ASSERT_TRUE(signal->observed & ZX_CHANNEL_READABLE);
-
-    // ISO packets are larger than all other packets.
-    bt::StaticByteBuffer<iso::kMaxIsochronousDataPacketSize> buffer;
-    uint32_t read_size = 0;
-    zx_status_t read_status = channel->read(0u, buffer.mutable_data(), /*handles=*/nullptr,
-                                            static_cast<uint32_t>(buffer.size()), 0, &read_size,
-                                            /*actual_handles=*/nullptr);
-    ASSERT_TRUE(read_status == ZX_OK);
-    out_vector->emplace_back(bt::BufferView(buffer, read_size));
-    wait->Begin(dispatcher_);
-  }
-
-  void OnAclSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                   const zx_packet_signal_t* signal) {
-    ASSERT_TRUE(status == ZX_OK);
-    OnChannelSignal(&acl_channel_, wait, signal, &acl_packets_received_);
-  }
-
-  void OnCommandSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                       const zx_packet_signal_t* signal) {
-    ASSERT_TRUE(status == ZX_OK);
-    OnChannelSignal(&command_channel_, wait, signal, &commands_received_);
-  }
-
-  void OnScoSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                   const zx_packet_signal_t* signal) {
-    ASSERT_TRUE(status == ZX_OK);
-    OnChannelSignal(&sco_channel_, wait, signal, &sco_packets_received_);
-  }
-
-  void OnIsoSignal(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
-                   const zx_packet_signal_t* signal) {
-    ASSERT_TRUE(status == ZX_OK);
-    OnChannelSignal(&iso_channel_, wait, signal, &iso_packets_received_);
-  }
-
-  bt_vendor_features_t features_{0};
-  bool sco_supported_ = true;
-  bool iso_supported_ = true;
-  bool command_channel_supported_ = true;
-  bool acl_channel_supported_ = true;
-  zx_status_t encode_command_status_ = ZX_OK;
-  ConfigureScoCallback configure_sco_cb_;
-  ResetScoCallback reset_sco_cb_;
-
-  zx::channel command_channel_;
-  async::WaitMethod<FakeDevice, &FakeDevice::OnCommandSignal> command_wait_{this};
-  std::vector<bt::DynamicByteBuffer> commands_received_;
-
-  zx::channel acl_channel_;
-  async::WaitMethod<FakeDevice, &FakeDevice::OnAclSignal> acl_wait_{this};
-  std::vector<bt::DynamicByteBuffer> acl_packets_received_;
-
-  zx::channel sco_channel_;
-  async::WaitMethod<FakeDevice, &FakeDevice::OnScoSignal> sco_wait_{this};
-  std::vector<bt::DynamicByteBuffer> sco_packets_received_;
-
-  zx::channel iso_channel_;
-  async::WaitMethod<FakeDevice, &FakeDevice::OnIsoSignal> iso_wait_{this};
-  std::vector<bt::DynamicByteBuffer> iso_packets_received_;
-
-  async_dispatcher_t* dispatcher_;
-};
-
-class BanjoControllerTest : public ::gtest::TestLoopFixture {
- public:
-  void SetUp() { fake_device_.emplace(dispatcher()); }
-
-  void InitializeController(bool vendor_supported = true) {
-    auto hci_proto = fake_device_->hci_proto();
-    auto vendor_proto = fake_device_->vendor_proto();
-    std::optional<ddk::BtVendorProtocolClient> vendor_client =
-        vendor_supported ? std::optional(ddk::BtVendorProtocolClient(&vendor_proto)) : std::nullopt;
-    controller_.emplace(ddk::BtHciProtocolClient(&hci_proto), std::move(vendor_client),
-                        dispatcher());
-
-    std::optional<pw::Status> complete_status;
-    controller_->Initialize(
-        [&](pw::Status cb_complete_status) { complete_status = cb_complete_status; },
-        [&](pw::Status cb_error) { controller_error_ = cb_error; });
-    ASSERT_TRUE(complete_status.has_value());
-    ASSERT_TRUE(complete_status.value().ok());
-    ASSERT_FALSE(controller_error_.has_value());
-  }
-
-  void DestroyController() { controller_.reset(); }
-
-  BanjoController* controller() { return &controller_.value(); }
-
-  FakeDevice* fake_device() { return &fake_device_.value(); }
-
-  std::optional<pw::Status> controller_error() const { return controller_error_; }
-
- private:
-  std::optional<pw::Status> controller_error_;
-  std::optional<FakeDevice> fake_device_;
-  std::optional<BanjoController> controller_;
-};
-
-TEST_F(BanjoControllerTest, InitializeFailsDueToCommandChannelError) {
-  FakeDevice fake_device(dispatcher());
-  fake_device.set_command_channel_supported(false);
-  auto hci_proto = fake_device.hci_proto();
-  BanjoController controller(ddk::BtHciProtocolClient(&hci_proto), std::nullopt, dispatcher());
-
-  std::optional<pw::Status> complete_status;
-  std::optional<pw::Status> error;
-  controller.Initialize(
-      [&](pw::Status cb_complete_status) { complete_status = cb_complete_status; },
-      [&](pw::Status cb_error) { error = cb_error; });
-  ASSERT_TRUE(complete_status.has_value());
-  ASSERT_TRUE(complete_status->IsInternal());
-  ASSERT_FALSE(error.has_value());
-}
-
-TEST_F(BanjoControllerTest, InitializeFailsDueToAclChannelError) {
-  FakeDevice fake_device(dispatcher());
-  fake_device.set_acl_channel_supported(false);
-  auto hci_proto = fake_device.hci_proto();
-  BanjoController controller(ddk::BtHciProtocolClient(&hci_proto), std::nullopt, dispatcher());
-
-  std::optional<pw::Status> complete_status;
-  std::optional<pw::Status> error;
-  controller.Initialize(
-      [&](pw::Status cb_complete_status) { complete_status = cb_complete_status; },
-      [&](pw::Status cb_error) { error = cb_error; });
-  ASSERT_TRUE(complete_status.has_value());
-  ASSERT_TRUE(complete_status->IsInternal());
-  ASSERT_FALSE(error.has_value());
-}
-
-TEST_F(BanjoControllerTest, SendAndReceiveAcl) {
-  RETURN_IF_FATAL(InitializeController());
-
-  const StaticByteBuffer acl_packet_0(0x00, 0x01, 0x02, 0x03);
-  controller()->SendAclData(acl_packet_0.subspan());
-  RunLoopUntilIdle();
-  ASSERT_EQ(fake_device()->acl_packets_received().size(), 1u);
-  EXPECT_THAT(fake_device()->acl_packets_received()[0], BufferEq(acl_packet_0));
-
-  const StaticByteBuffer acl_packet_1(0x04, 0x05, 0x06, 0x07);
-  controller()->SendAclData(acl_packet_1.subspan());
-  RunLoopUntilIdle();
-  ASSERT_EQ(fake_device()->acl_packets_received().size(), 2u);
-  EXPECT_THAT(fake_device()->acl_packets_received()[1], BufferEq(acl_packet_1));
-
-  std::vector<DynamicByteBuffer> received_acl;
-  controller()->SetReceiveAclFunction([&](pw::span<const std::byte> buffer) {
-    received_acl.emplace_back(BufferView(buffer.data(), buffer.size()));
-  });
-
-  fake_device()->SendAcl(acl_packet_0.view());
-  RunLoopUntilIdle();
-  ASSERT_EQ(received_acl.size(), 1u);
-  EXPECT_THAT(received_acl[0], BufferEq(acl_packet_0));
-
-  fake_device()->SendAcl(acl_packet_1.view());
-  RunLoopUntilIdle();
-  ASSERT_EQ(received_acl.size(), 2u);
-  EXPECT_THAT(received_acl[1], BufferEq(acl_packet_1));
-
-  std::optional<pw::Status> close_status;
-  controller()->Close([&](pw::Status status) { close_status = status; });
-  ASSERT_TRUE(close_status.has_value());
-  EXPECT_EQ(close_status.value(), PW_STATUS_OK);
-}
-
-TEST_F(BanjoControllerTest, SendCommandsAndReceiveEvents) {
-  RETURN_IF_FATAL(InitializeController());
-
-  const StaticByteBuffer packet_0(0x00, 0x01, 0x02, 0x03);
-  controller()->SendCommand(packet_0.subspan());
-  RunLoopUntilIdle();
-  ASSERT_EQ(fake_device()->commands_received().size(), 1u);
-  EXPECT_THAT(fake_device()->commands_received()[0], BufferEq(packet_0));
-
-  const StaticByteBuffer packet_1(0x04, 0x05, 0x06, 0x07);
-  controller()->SendCommand(packet_1.subspan());
-  RunLoopUntilIdle();
-  ASSERT_EQ(fake_device()->commands_received().size(), 2u);
-  EXPECT_THAT(fake_device()->commands_received()[1], BufferEq(packet_1));
-
-  std::vector<DynamicByteBuffer> events;
-  controller()->SetEventFunction([&](pw::span<const std::byte> buffer) {
-    events.emplace_back(BufferView(buffer.data(), buffer.size()));
-  });
-
-  fake_device()->SendEvent(packet_1.view());
-  RunLoopUntilIdle();
-  ASSERT_EQ(events.size(), 1u);
-  EXPECT_THAT(events[0], BufferEq(packet_1));
-
-  fake_device()->SendEvent(packet_1.view());
-  RunLoopUntilIdle();
-  ASSERT_EQ(events.size(), 2u);
-  EXPECT_THAT(events[1], BufferEq(packet_1));
-
-  std::optional<pw::Status> close_status;
-  controller()->Close([&](pw::Status status) { close_status = status; });
-  ASSERT_TRUE(close_status.has_value());
-  EXPECT_EQ(close_status.value(), PW_STATUS_OK);
-}
-
-TEST_F(BanjoControllerTest, SendAndReceiveSco) {
-  RETURN_IF_FATAL(InitializeController());
-
-  const StaticByteBuffer sco_packet_0(0x00, 0x01, 0x02, 0x03);
-  controller()->SendScoData(sco_packet_0.subspan());
-  RunLoopUntilIdle();
-  ASSERT_EQ(fake_device()->sco_packets_received().size(), 1u);
-  EXPECT_THAT(fake_device()->sco_packets_received()[0], BufferEq(sco_packet_0));
-
-  const StaticByteBuffer sco_packet_1(0x04, 0x05, 0x06, 0x07);
-  controller()->SendScoData(sco_packet_1.subspan());
-  RunLoopUntilIdle();
-  ASSERT_EQ(fake_device()->sco_packets_received().size(), 2u);
-  EXPECT_THAT(fake_device()->sco_packets_received()[1], BufferEq(sco_packet_1));
-
-  std::vector<DynamicByteBuffer> received_sco;
-  controller()->SetReceiveScoFunction([&](pw::span<const std::byte> buffer) {
-    received_sco.emplace_back(BufferView(buffer.data(), buffer.size()));
-  });
-
-  fake_device()->SendSco(sco_packet_0.view());
-  RunLoopUntilIdle();
-  ASSERT_EQ(received_sco.size(), 1u);
-  EXPECT_THAT(received_sco[0], BufferEq(sco_packet_0));
-
-  fake_device()->SendSco(sco_packet_1.view());
-  RunLoopUntilIdle();
-  ASSERT_EQ(received_sco.size(), 2u);
-  EXPECT_THAT(received_sco[1], BufferEq(sco_packet_1));
-
-  std::optional<pw::Status> close_status;
-  controller()->Close([&](pw::Status status) { close_status = status; });
-  ASSERT_TRUE(close_status.has_value());
-  EXPECT_EQ(close_status.value(), PW_STATUS_OK);
-}
-
-TEST_F(BanjoControllerTest, SendAndReceiveIso) {
-  RETURN_IF_FATAL(InitializeController());
-
-  const StaticByteBuffer iso_packet_0(0x00, 0x01, 0x02, 0x03);
-  controller()->SendIsoData(iso_packet_0.subspan());
-  RunLoopUntilIdle();
-  ASSERT_EQ(fake_device()->iso_packets_received().size(), 1u);
-  EXPECT_THAT(fake_device()->iso_packets_received()[0], BufferEq(iso_packet_0));
-
-  const StaticByteBuffer iso_packet_1(0x04, 0x05, 0x06, 0x07);
-  controller()->SendIsoData(iso_packet_1.subspan());
-  RunLoopUntilIdle();
-  ASSERT_EQ(fake_device()->iso_packets_received().size(), 2u);
-  EXPECT_THAT(fake_device()->iso_packets_received()[1], BufferEq(iso_packet_1));
-
-  std::vector<DynamicByteBuffer> received_iso;
-  controller()->SetReceiveIsoFunction([&](pw::span<const std::byte> buffer) {
-    received_iso.emplace_back(BufferView(buffer.data(), buffer.size()));
-  });
-
-  fake_device()->SendIso(iso_packet_0.view());
-  RunLoopUntilIdle();
-  ASSERT_EQ(received_iso.size(), 1u);
-  EXPECT_THAT(received_iso[0], BufferEq(iso_packet_0));
-
-  fake_device()->SendIso(iso_packet_1.view());
-  RunLoopUntilIdle();
-  ASSERT_EQ(received_iso.size(), 2u);
-  EXPECT_THAT(received_iso[1], BufferEq(iso_packet_1));
-
-  std::optional<pw::Status> close_status;
-  controller()->Close([&](pw::Status status) { close_status = status; });
-  ASSERT_TRUE(close_status.has_value());
-  EXPECT_EQ(close_status.value(), PW_STATUS_OK);
-}
-
-TEST_F(BanjoControllerTest, GetFeatures) {
-  fake_device()->set_sco_supported(true);
-  fake_device()->set_iso_supported(true);
-  fake_device()->set_features(BT_VENDOR_FEATURES_SET_ACL_PRIORITY_COMMAND |
-                              BT_VENDOR_FEATURES_ANDROID_VENDOR_EXTENSIONS);
-  InitializeController(/*vendor_supported=*/true);
-
-  std::optional<FeaturesBits> features;
-  controller()->GetFeatures([&](FeaturesBits f) { features = f; });
-  ASSERT_TRUE(features.has_value());
-  EXPECT_EQ(features.value(), FeaturesBits::kSetAclPriorityCommand |
-                                  FeaturesBits::kAndroidVendorExtensions | FeaturesBits::kHciSco |
-                                  FeaturesBits::kHciIso);
-}
-
-TEST_F(BanjoControllerTest, NoFeaturesSupported) {
-  fake_device()->set_sco_supported(false);
-  fake_device()->set_iso_supported(false);
-  fake_device()->set_features(0);
-  RETURN_IF_FATAL(InitializeController());
-  std::optional<FeaturesBits> features;
-  controller()->GetFeatures([&](FeaturesBits f) { features = f; });
-  ASSERT_TRUE(features.has_value());
-  EXPECT_EQ(features.value(), FeaturesBits{0});
-}
-
-TEST_F(BanjoControllerTest, EncodeSetAclPriorityCommandNormal) {
-  RETURN_IF_FATAL(InitializeController());
-  pw::bluetooth::VendorCommandParameters params = pw::bluetooth::SetAclPriorityCommandParameters{
-      .connection_handle = kConnectionHandle, .priority = AclPriority::kNormal};
-  std::optional<DynamicByteBuffer> buffer;
-  controller()->EncodeVendorCommand(params, [&](pw::Result<pw::span<const std::byte>> result) {
-    ASSERT_TRUE(result.ok());
-    buffer.emplace(BufferView(result.value().data(), result.value().size()));
-  });
-  ASSERT_TRUE(buffer);
-  EXPECT_THAT(*buffer, BufferEq(kSetAclPriorityNormalCommand));
-}
-
-TEST_F(BanjoControllerTest, EncodeSetAclPriorityCommandSink) {
-  RETURN_IF_FATAL(InitializeController());
-  pw::bluetooth::VendorCommandParameters params = pw::bluetooth::SetAclPriorityCommandParameters{
-      .connection_handle = kConnectionHandle, .priority = AclPriority::kSink};
-  std::optional<DynamicByteBuffer> buffer;
-  controller()->EncodeVendorCommand(params, [&](pw::Result<pw::span<const std::byte>> result) {
-    ASSERT_TRUE(result.ok());
-    buffer.emplace(BufferView(result.value().data(), result.value().size()));
-  });
-  ASSERT_TRUE(buffer);
-  EXPECT_THAT(*buffer, BufferEq(kSetAclPrioritySinkCommand));
-}
-
-TEST_F(BanjoControllerTest, EncodeSetAclPriorityCommandSource) {
-  RETURN_IF_FATAL(InitializeController());
-  pw::bluetooth::VendorCommandParameters params = pw::bluetooth::SetAclPriorityCommandParameters{
-      .connection_handle = kConnectionHandle, .priority = AclPriority::kSource};
-  std::optional<DynamicByteBuffer> buffer;
-  controller()->EncodeVendorCommand(params, [&](pw::Result<pw::span<const std::byte>> result) {
-    ASSERT_TRUE(result.ok());
-    buffer.emplace(BufferView(result.value().data(), result.value().size()));
-  });
-  ASSERT_TRUE(buffer);
-  EXPECT_THAT(*buffer, BufferEq(kSetAclPrioritySourceCommand));
-}
-
-TEST_F(BanjoControllerTest, EncodeSetAclPriorityCommandNotSupported) {
-  fake_device()->set_encode_command_status(ZX_ERR_NOT_SUPPORTED);
-  RETURN_IF_FATAL(InitializeController());
-
-  pw::bluetooth::VendorCommandParameters params = pw::bluetooth::SetAclPriorityCommandParameters{
-      .connection_handle = kConnectionHandle, .priority = AclPriority::kSource};
-  std::optional<pw::Result<pw::span<const std::byte>>> result;
-  controller()->EncodeVendorCommand(
-      params, [&](pw::Result<pw::span<const std::byte>> cb_result) { result = cb_result; });
-  ASSERT_TRUE(result.has_value());
-  EXPECT_EQ(result->status(), pw::Status::Unimplemented());
-}
-
-TEST_F(BanjoControllerTest, ConfigureScoWithFormatCvsdEncoding8BitsSampleRate8Khz) {
-  RETURN_IF_FATAL(InitializeController());
-  int device_cb_count = 0;
-  fake_device()->set_configure_sco_callback(
-      [&](sco_coding_format_t format, sco_encoding_t encoding, sco_sample_rate_t rate,
-          bt_hci_configure_sco_callback callback, void* cookie) {
-        device_cb_count++;
-        EXPECT_EQ(format, SCO_CODING_FORMAT_CVSD);
-        EXPECT_EQ(encoding, SCO_ENCODING_BITS_8);
-        EXPECT_EQ(rate, SCO_SAMPLE_RATE_KHZ_8);
-        callback(cookie, ZX_OK);
-      });
-
-  int controller_cb_count = 0;
-  controller()->ConfigureSco(ScoCodingFormat::kCvsd, ScoEncoding::k8Bits, ScoSampleRate::k8Khz,
-                             [&](pw::Status status) {
-                               controller_cb_count++;
-                               EXPECT_EQ(status, PW_STATUS_OK);
-                             });
-  EXPECT_EQ(device_cb_count, 1);
-  // ConfigureSco() callback should be posted.
-  EXPECT_EQ(controller_cb_count, 0);
-  RunLoopUntilIdle();
-  EXPECT_EQ(controller_cb_count, 1);
-  EXPECT_EQ(device_cb_count, 1);
-}
-
-TEST_F(BanjoControllerTest, ConfigureScoWithFormatCvsdEncoding16BitsSampleRate8Khz) {
-  RETURN_IF_FATAL(InitializeController());
-  fake_device()->set_configure_sco_callback(
-      [](sco_coding_format_t format, sco_encoding_t encoding, sco_sample_rate_t rate,
-         bt_hci_configure_sco_callback callback, void* cookie) {
-        EXPECT_EQ(format, SCO_CODING_FORMAT_CVSD);
-        EXPECT_EQ(encoding, SCO_ENCODING_BITS_16);
-        EXPECT_EQ(rate, SCO_SAMPLE_RATE_KHZ_8);
-        callback(cookie, ZX_OK);
-      });
-
-  int config_cb_count = 0;
-  controller()->ConfigureSco(ScoCodingFormat::kCvsd, ScoEncoding::k16Bits, ScoSampleRate::k8Khz,
-                             [&](pw::Status status) {
-                               config_cb_count++;
-                               EXPECT_EQ(status, PW_STATUS_OK);
-                             });
-  RunLoopUntilIdle();
-  EXPECT_EQ(config_cb_count, 1);
-}
-
-TEST_F(BanjoControllerTest, ConfigureScoWithFormatCvsdEncoding16BitsSampleRate16Khz) {
-  RETURN_IF_FATAL(InitializeController());
-  fake_device()->set_configure_sco_callback(
-      [](sco_coding_format_t format, sco_encoding_t encoding, sco_sample_rate_t rate,
-         bt_hci_configure_sco_callback callback, void* cookie) {
-        EXPECT_EQ(format, SCO_CODING_FORMAT_CVSD);
-        EXPECT_EQ(encoding, SCO_ENCODING_BITS_16);
-        EXPECT_EQ(rate, SCO_SAMPLE_RATE_KHZ_16);
-        callback(cookie, ZX_OK);
-      });
-
-  int config_cb_count = 0;
-  controller()->ConfigureSco(ScoCodingFormat::kCvsd, ScoEncoding::k16Bits, ScoSampleRate::k16Khz,
-                             [&](pw::Status status) {
-                               config_cb_count++;
-                               EXPECT_EQ(status, PW_STATUS_OK);
-                             });
-  RunLoopUntilIdle();
-  EXPECT_EQ(config_cb_count, 1);
-}
-
-TEST_F(BanjoControllerTest, ConfigureScoWithFormatMsbcEncoding16BitsSampleRate16Khz) {
-  RETURN_IF_FATAL(InitializeController());
-  fake_device()->set_configure_sco_callback(
-      [](sco_coding_format_t format, sco_encoding_t encoding, sco_sample_rate_t rate,
-         bt_hci_configure_sco_callback callback, void* cookie) {
-        EXPECT_EQ(format, SCO_CODING_FORMAT_MSBC);
-        EXPECT_EQ(encoding, SCO_ENCODING_BITS_16);
-        EXPECT_EQ(rate, SCO_SAMPLE_RATE_KHZ_16);
-        callback(cookie, ZX_OK);
-      });
-
-  int config_cb_count = 0;
-  controller()->ConfigureSco(ScoCodingFormat::kMsbc, ScoEncoding::k16Bits, ScoSampleRate::k16Khz,
-                             [&](pw::Status status) {
-                               config_cb_count++;
-                               EXPECT_EQ(status, PW_STATUS_OK);
-                             });
-  RunLoopUntilIdle();
-  EXPECT_EQ(config_cb_count, 1);
-}
-
-TEST_F(BanjoControllerTest, ResetSco) {
-  RETURN_IF_FATAL(InitializeController());
-  int device_cb_count = 0;
-  fake_device()->set_reset_sco_callback([&](bt_hci_reset_sco_callback callback, void* ctx) {
-    device_cb_count++;
-    callback(ctx, ZX_OK);
-  });
-  int controller_cb_count = 0;
-  controller()->ResetSco([&](pw::Status status) {
-    controller_cb_count++;
-    EXPECT_EQ(status, PW_STATUS_OK);
-  });
-  EXPECT_EQ(device_cb_count, 1);
-  // The ResetSco() callback should be posted.
-  EXPECT_EQ(controller_cb_count, 0);
-  RunLoopUntilIdle();
-  EXPECT_EQ(device_cb_count, 1);
-  EXPECT_EQ(controller_cb_count, 1);
-}
-
-TEST_F(BanjoControllerTest, ConfigureScoCallbackCalledAfterHciWrapperDestroyed) {
-  RETURN_IF_FATAL(InitializeController());
-  int device_cb_count = 0;
-  bt_hci_configure_sco_callback config_callback = nullptr;
-  void* config_callback_ctx = nullptr;
-  fake_device()->set_configure_sco_callback(
-      [&](sco_coding_format_t format, sco_encoding_t encoding, sco_sample_rate_t rate,
-          bt_hci_configure_sco_callback callback, void* cookie) {
-        device_cb_count++;
-        config_callback = callback;
-        config_callback_ctx = cookie;
-      });
-
-  int controller_cb_count = 0;
-  controller()->ConfigureSco(ScoCodingFormat::kCvsd, ScoEncoding::k8Bits, ScoSampleRate::k8Khz,
-                             [&](pw::Status /*status*/) { controller_cb_count++; });
-  ASSERT_EQ(device_cb_count, 1);
-  EXPECT_EQ(controller_cb_count, 0);
-
-  DestroyController();
-  config_callback(config_callback_ctx, ZX_OK);
-
-  // The ConfigureSco() callback should never be called.
-  EXPECT_EQ(controller_cb_count, 0);
-  RunLoopUntilIdle();
-  EXPECT_EQ(controller_cb_count, 0);
-}
-
-TEST_F(BanjoControllerTest, ResetScoCallbackCalledAfterHciWrapperDestroyed) {
-  RETURN_IF_FATAL(InitializeController());
-  int device_cb_count = 0;
-  bt_hci_reset_sco_callback reset_callback = nullptr;
-  void* reset_callback_ctx = nullptr;
-  fake_device()->set_reset_sco_callback([&](bt_hci_reset_sco_callback callback, void* ctx) {
-    device_cb_count++;
-    reset_callback = callback;
-    reset_callback_ctx = ctx;
-  });
-
-  int controller_cb_count = 0;
-  controller()->ResetSco([&](pw::Status /*status*/) { controller_cb_count++; });
-  ASSERT_EQ(device_cb_count, 1);
-  EXPECT_EQ(controller_cb_count, 0);
-
-  DestroyController();
-  reset_callback(reset_callback_ctx, ZX_OK);
-
-  // The ResetSco() callback should never be called.
-  EXPECT_EQ(controller_cb_count, 0);
-  RunLoopUntilIdle();
-  EXPECT_EQ(controller_cb_count, 0);
-}
-
-TEST_F(BanjoControllerTest, CloseClosesChannels) {
-  RETURN_IF_FATAL(InitializeController());
-  EXPECT_TRUE(fake_device()->acl_channel_is_valid());
-  EXPECT_TRUE(fake_device()->sco_channel_is_valid());
-  EXPECT_TRUE(fake_device()->iso_channel_is_valid());
-  EXPECT_TRUE(fake_device()->command_channel_is_valid());
-
-  std::optional<pw::Status> close_status;
-  controller()->Close([&](pw::Status status) { close_status = status; });
-  ASSERT_TRUE(close_status.has_value());
-  EXPECT_EQ(close_status.value(), PW_STATUS_OK);
-  RunLoopUntilIdle();
-  EXPECT_FALSE(fake_device()->acl_channel_is_valid());
-  EXPECT_FALSE(fake_device()->sco_channel_is_valid());
-  EXPECT_FALSE(fake_device()->iso_channel_is_valid());
-  EXPECT_FALSE(fake_device()->command_channel_is_valid());
-}
-
-TEST_F(BanjoControllerTest, DeviceClosesCommandChannel) {
-  RETURN_IF_FATAL(InitializeController());
-  fake_device()->ResetCommandChannel();
-  RunLoopUntilIdle();
-  EXPECT_THAT(controller_error(), ::testing::Optional(pw::Status::Unavailable()));
-}
-
-}  // namespace bt::controllers
diff --git a/src/connectivity/bluetooth/core/bt-host/controllers/fidl_controller_test.cc b/src/connectivity/bluetooth/core/bt-host/controllers/fidl_controller_test.cc
index c1a1ff7..f240491 100644
--- a/src/connectivity/bluetooth/core/bt-host/controllers/fidl_controller_test.cc
+++ b/src/connectivity/bluetooth/core/bt-host/controllers/fidl_controller_test.cc
@@ -11,8 +11,8 @@
 #include "gmock/gmock.h"
 #include "src/connectivity/bluetooth/core/bt-host/fidl/fake_vendor_server.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
+#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
-#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
 
 namespace bt::controllers {
 
@@ -23,9 +23,9 @@
 const StaticByteBuffer kSetAclPrioritySourceCommand(0x01);
 const StaticByteBuffer kSetAclPrioritySinkCommand(0x02);
 
-class FidlControllerTest : public ::gtest::TestLoopFixture {
+class FidlControllerTest : public bt::testing::TestLoopFixture {
  public:
-  void SetUp() {
+  void SetUp() override {
     fhbt::VendorHandle vendor;
 
     fake_vendor_server_.emplace(vendor.NewRequest(), dispatcher());
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/BUILD.gn b/src/connectivity/bluetooth/core/bt-host/fidl/BUILD.gn
index bcfc57c..9b026d3 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/BUILD.gn
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/BUILD.gn
@@ -41,15 +41,15 @@
 
   public_deps = [
     ":helpers",
+    "$dir_pw_intrusive_ptr",
     "//sdk/fidl/fuchsia.bluetooth:fuchsia.bluetooth_hlcpp",
     "//sdk/fidl/fuchsia.bluetooth.gatt:fuchsia.bluetooth.gatt_hlcpp",
     "//sdk/fidl/fuchsia.bluetooth.gatt2:fuchsia.bluetooth.gatt2_hlcpp",
+    "//sdk/fidl/fuchsia.bluetooth.host:fuchsia.bluetooth.host_hlcpp",
     "//sdk/fidl/fuchsia.bluetooth.le:fuchsia.bluetooth.le_hlcpp",
     "//sdk/lib/fit-promise",
     "//src/connectivity/bluetooth/core/bt-host:stack",
-    "//src/connectivity/bluetooth/fidl:host_hlcpp",
     "//src/connectivity/bluetooth/lib/fidl",
-    "//zircon/system/ulib/fbl",
     "//zircon/system/ulib/zx",
   ]
 }
@@ -62,13 +62,14 @@
   ]
   public_deps = [
     "//sdk/fidl/fuchsia.bluetooth:fuchsia.bluetooth_hlcpp",
+    "//sdk/fidl/fuchsia.bluetooth.bredr:fuchsia.bluetooth.bredr_cpp",
     "//sdk/fidl/fuchsia.bluetooth.gatt:fuchsia.bluetooth.gatt_hlcpp",
     "//sdk/fidl/fuchsia.bluetooth.gatt2:fuchsia.bluetooth.gatt2_hlcpp",
+    "//sdk/fidl/fuchsia.bluetooth.host:fuchsia.bluetooth.host_hlcpp",
     "//src/connectivity/bluetooth/core/bt-host/common",
     "//src/connectivity/bluetooth/core/bt-host/gap",
     "//src/connectivity/bluetooth/core/bt-host/gatt",
     "//src/connectivity/bluetooth/core/bt-host/sdp",
-    "//src/connectivity/bluetooth/fidl:host_hlcpp",
   ]
 }
 
@@ -87,9 +88,8 @@
     "//src/connectivity/bluetooth/core/bt-host/l2cap:testing",
     "//src/connectivity/bluetooth/core/bt-host/testing",
     "//src/connectivity/bluetooth/core/bt-host/testing:fake_controller",
-    "//src/lib/testing/loop_fixture:gtest",
+    "//src/connectivity/bluetooth/core/bt-host/testing:loop_fixture",
     "//third_party/pigweed/backends/pw_async_fuchsia:dispatcher",
-    "//zircon/system/ulib/fbl",
   ]
 }
 
@@ -101,8 +101,9 @@
   public_deps = [
     "//src/connectivity/bluetooth/core/bt-host/gap",
     "//src/connectivity/bluetooth/core/bt-host/gap:testing",
-    "//src/lib/testing/loop_fixture",
+    "//src/connectivity/bluetooth/core/bt-host/testing:loop_fixture",
     "//third_party/googletest:gtest",
+    "//third_party/pigweed/backends/pw_async_fuchsia:dispatcher",
   ]
 }
 
@@ -118,7 +119,7 @@
     "//src/connectivity/bluetooth/core/bt-host/common",
     "//src/connectivity/bluetooth/core/bt-host/gatt",
     "//src/connectivity/bluetooth/core/bt-host/gatt:testing",
-    "//src/lib/testing/loop_fixture",
+    "//src/connectivity/bluetooth/core/bt-host/testing:loop_fixture",
     "//third_party/pigweed/backends/pw_async_fuchsia:dispatcher",
   ]
 }
@@ -161,6 +162,7 @@
     "//src/connectivity/bluetooth/core/bt-host/gatt:testing",
     "//src/connectivity/bluetooth/core/bt-host/testing",
     "//src/connectivity/bluetooth/core/bt-host/testing:fake_controller",
+    "//src/connectivity/bluetooth/core/bt-host/testing:loop_fixture",
     "//third_party/googletest:gmock",
     "//third_party/googletest:gtest",
   ]
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/adapter_test_fixture.h b/src/connectivity/bluetooth/core/bt-host/fidl/adapter_test_fixture.h
index 6b04d79..831e492 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/adapter_test_fixture.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/adapter_test_fixture.h
@@ -13,14 +13,14 @@
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/fake_l2cap.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
-#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
+#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h"
 
 namespace bthost::testing {
 
 // This test fixture provides an instance of the Bluetooth stack with mock data plane (L2CAP) and
 // GATT test doubles. The fixture is backed by a FakeController and an event loop which can be used
 // to test interactions with the Bluetooth controller.
-class AdapterTestFixture : public ::gtest::TestLoopFixture,
+class AdapterTestFixture : public bt::testing::TestLoopFixture,
                            public bt::testing::ControllerTest<bt::testing::FakeController> {
  public:
   AdapterTestFixture()
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/fake_adapter_test_fixture.h b/src/connectivity/bluetooth/core/bt-host/fidl/fake_adapter_test_fixture.h
index c9fd80c..c4871f2 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/fake_adapter_test_fixture.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/fake_adapter_test_fixture.h
@@ -7,13 +7,14 @@
 
 #include <gtest/gtest.h>
 
+#include "pw_async_fuchsia/dispatcher.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/macros.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/fake_adapter.h"
-#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
+#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h"
 
 namespace bt::fidl::testing {
 
-class FakeAdapterTestFixture : public ::gtest::TestLoopFixture {
+class FakeAdapterTestFixture : public bt::testing::TestLoopFixture {
  public:
   FakeAdapterTestFixture() = default;
   ~FakeAdapterTestFixture() override = default;
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/fake_gatt_fixture.h b/src/connectivity/bluetooth/core/bt-host/fidl/fake_gatt_fixture.h
index 3d01a9e..f0b3a4a 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/fake_gatt_fixture.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/fake_gatt_fixture.h
@@ -9,13 +9,13 @@
 
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/macros.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gatt/fake_layer.h"
-#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
+#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h"
 
 namespace bt::fidl::testing {
 
 // Provides a common GTest harness base class for clients of the GATT layer and emulation of
 // ATT behavior.
-class FakeGattFixture : public ::gtest::TestLoopFixture {
+class FakeGattFixture : public bt::testing::TestLoopFixture {
  public:
   FakeGattFixture();
   ~FakeGattFixture() override = default;
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/gatt2_client_server_test.cc b/src/connectivity/bluetooth/core/bt-host/fidl/gatt2_client_server_test.cc
index 46fcf5b..b03ff7d 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/gatt2_client_server_test.cc
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/gatt2_client_server_test.cc
@@ -6,7 +6,6 @@
 
 #include "fuchsia/bluetooth/gatt2/cpp/fidl.h"
 #include "src/connectivity/bluetooth/core/bt-host/fidl/fake_gatt_fixture.h"
-#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
 
 namespace bthost {
 
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/gatt2_server_server.h b/src/connectivity/bluetooth/core/bt-host/fidl/gatt2_server_server.h
index 6495594..c6b7f9d 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/gatt2_server_server.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/gatt2_server_server.h
@@ -7,8 +7,6 @@
 
 #include <fuchsia/bluetooth/gatt2/cpp/fidl.h>
 
-#include <fbl/macros.h>
-
 #include "lib/zx/eventpair.h"
 #include "src/connectivity/bluetooth/core/bt-host/fidl/gatt2_server_ids.h"
 #include "src/connectivity/bluetooth/core/bt-host/fidl/server_base.h"
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/gatt_server_server.h b/src/connectivity/bluetooth/core/bt-host/fidl/gatt_server_server.h
index aee7e12..e126c5e 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/gatt_server_server.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/gatt_server_server.h
@@ -54,7 +54,6 @@
                               bt::gatt::PeerId peer_id, bool notify, bool indicate);
 
   // The mapping between service identifiers and FIDL Service implementations.
-  // TODO(armansito): Consider using fbl::HashTable.
   std::unordered_map<uint64_t, std::unique_ptr<LocalServiceImpl>> services_;
 
   // Keep this as the last member to make sure that all weak pointers are
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/helpers.cc b/src/connectivity/bluetooth/core/bt-host/fidl/helpers.cc
index fba54b9..23fc2d4 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/helpers.cc
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/helpers.cc
@@ -5,23 +5,19 @@
 #include "helpers.h"
 
 #include <endian.h>
+#include <fidl/fuchsia.bluetooth.bredr/cpp/natural_types.h>
+#include <fuchsia/bluetooth/sys/cpp/fidl.h>
+#include <fuchsia/media/cpp/fidl.h>
 
-#include <algorithm>
 #include <charconv>
-#include <functional>
-#include <iterator>
 #include <optional>
 #include <unordered_set>
 
-#include "fuchsia/bluetooth/sys/cpp/fidl.h"
-#include "fuchsia/media/cpp/fidl.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/att/att.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/log.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/discovery_filter.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/gap.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gatt/gatt.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sco/sco.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/types.h"
 
@@ -251,6 +247,71 @@
   return out;
 }
 
+std::optional<bt::sdp::DataElement> NewFidlToDataElement(
+    const fuchsia_bluetooth_bredr::DataElement& fidl) {
+  bt::sdp::DataElement out;
+  switch (fidl.Which()) {
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kInt8:
+      return bt::sdp::DataElement(fidl.int8().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kInt16:
+      return bt::sdp::DataElement(fidl.int16().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kInt32:
+      return bt::sdp::DataElement(fidl.int32().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kInt64:
+      return bt::sdp::DataElement(fidl.int64().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kUint8:
+      return bt::sdp::DataElement(fidl.uint8().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kUint16:
+      return bt::sdp::DataElement(fidl.uint16().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kUint32:
+      return bt::sdp::DataElement(fidl.uint32().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kUint64:
+      return bt::sdp::DataElement(fidl.uint64().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kStr: {
+      bt::DynamicByteBuffer bytes((bt::BufferView(fidl.str().value())));
+      return bt::sdp::DataElement(bytes);
+    }
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kUrl: {
+      out.SetUrl(fidl.url().value());
+      break;
+    }
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kB:
+      return bt::sdp::DataElement(fidl.b().value());
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kUuid:
+      out.Set(NewUuidFromFidl(fidl.uuid()->value()));
+      break;
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kSequence: {
+      std::vector<bt::sdp::DataElement> seq;
+      for (const auto& fidl_elem : fidl.sequence().value()) {
+        std::optional<bt::sdp::DataElement> elem = NewFidlToDataElement(*fidl_elem);
+        if (!elem) {
+          return std::nullopt;
+        }
+        seq.emplace_back(std::move(elem.value()));
+      }
+      out.Set(std::move(seq));
+      break;
+    }
+    case fuchsia_bluetooth_bredr::DataElement::Tag::kAlternatives: {
+      std::vector<bt::sdp::DataElement> alts;
+      for (const auto& fidl_elem : fidl.alternatives().value()) {
+        auto elem = NewFidlToDataElement(*fidl_elem);
+        if (!elem) {
+          return std::nullopt;
+        }
+        alts.emplace_back(std::move(elem.value()));
+      }
+      out.SetAlternative(std::move(alts));
+      break;
+    }
+    default:
+      // Types not handled: Null datatype (never used)
+      bt_log(WARN, "fidl", "Encountered NewFidlToDataElement type not handled.");
+      return std::nullopt;
+  }
+  return out;
+}
+
 namespace {
 
 fbt::AddressType AddressTypeToFidl(bt::DeviceAddress::Type type) {
@@ -336,6 +397,41 @@
   return output;
 }
 
+bool NewAddProtocolDescriptorList(
+    bt::sdp::ServiceRecord* rec, bt::sdp::ServiceRecord::ProtocolListId id,
+    const std::vector<fuchsia_bluetooth_bredr::ProtocolDescriptor>& descriptor_list) {
+  bt_log(TRACE, "fidl", "ProtocolDescriptorList %d", id);
+  for (auto& descriptor : descriptor_list) {
+    bt::sdp::DataElement protocol_params;
+    if (descriptor.params().size() > 1) {
+      std::vector<bt::sdp::DataElement> params;
+      for (auto& fidl_param : descriptor.params()) {
+        auto bt_param = NewFidlToDataElement(fidl_param);
+        if (bt_param) {
+          params.emplace_back(std::move(bt_param.value()));
+        } else {
+          return false;
+        }
+      }
+      protocol_params.Set(std::move(params));
+    } else if (descriptor.params().size() == 1) {
+      auto param = NewFidlToDataElement(descriptor.params().front());
+      if (param) {
+        protocol_params = std::move(param).value();
+      } else {
+        return false;
+      }
+      protocol_params = NewFidlToDataElement(descriptor.params().front()).value();
+    }
+
+    bt_log(TRACE, "fidl", "Adding protocol descriptor: {%d : %s}",
+           fidl::ToUnderlying(descriptor.protocol()), protocol_params.ToString().c_str());
+    rec->AddProtocolDescriptor(id, bt::UUID(static_cast<uint16_t>(descriptor.protocol())),
+                               std::move(protocol_params));
+  }
+  return true;
+}
+
 bool AddProtocolDescriptorList(bt::sdp::ServiceRecord* rec,
                                bt::sdp::ServiceRecord::ProtocolListId id,
                                const ::std::vector<fbredr::ProtocolDescriptor>& descriptor_list) {
@@ -639,6 +735,12 @@
   return output;
 }
 
+bt::UUID NewUuidFromFidl(const fuchsia_bluetooth::Uuid& input) {
+  // Conversion must always succeed given the defined size of |input|.
+  static_assert(sizeof(input.value()) == 16, "FIDL UUID definition malformed!");
+  return bt::UUID(bt::BufferView(input.value().data(), input.value().size()));
+}
+
 bt::sm::IOCapability IoCapabilityFromFidl(fsys::InputCapability input,
                                           fsys::OutputCapability output) {
   if (input == fsys::InputCapability::NONE && output == fsys::OutputCapability::NONE) {
@@ -1300,6 +1402,94 @@
 }
 
 fpromise::result<bt::sdp::ServiceRecord, fuchsia::bluetooth::ErrorCode>
+ServiceDefinitionToServiceRecord(const fuchsia_bluetooth_bredr::ServiceDefinition& definition) {
+  bt::sdp::ServiceRecord rec;
+  std::vector<bt::UUID> classes;
+
+  if (!definition.service_class_uuids().has_value()) {
+    bt_log(WARN, "fidl", "Advertised service contains no Service UUIDs");
+    return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
+  }
+
+  for (auto& uuid : definition.service_class_uuids().value()) {
+    bt::UUID btuuid = fidl_helpers::NewUuidFromFidl(uuid);
+    bt_log(TRACE, "fidl", "Setting Service Class UUID %s", bt_str(btuuid));
+    classes.emplace_back(btuuid);
+  }
+
+  rec.SetServiceClassUUIDs(classes);
+
+  if (definition.protocol_descriptor_list().has_value()) {
+    if (!NewAddProtocolDescriptorList(&rec, bt::sdp::ServiceRecord::kPrimaryProtocolList,
+                                      definition.protocol_descriptor_list().value())) {
+      bt_log(ERROR, "fidl", "Failed to add protocol descriptor list");
+      return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
+    }
+  }
+
+  if (definition.additional_protocol_descriptor_lists().has_value()) {
+    // It's safe to iterate through this list with a ProtocolListId as ProtocolListId = uint8_t,
+    // and std::numeric_limits<uint8_t>::max() == 255 == the MAX_SEQUENCE_LENGTH vector limit from
+    // fuchsia.bluetooth.bredr/ServiceDefinition.additional_protocol_descriptor_lists.
+    BT_ASSERT(definition.additional_protocol_descriptor_lists()->size() <=
+              std::numeric_limits<bt::sdp::ServiceRecord::ProtocolListId>::max());
+    bt::sdp::ServiceRecord::ProtocolListId protocol_list_id = 1;
+    for (const auto& descriptor_list : definition.additional_protocol_descriptor_lists().value()) {
+      if (!NewAddProtocolDescriptorList(&rec, protocol_list_id, descriptor_list)) {
+        bt_log(ERROR, "fidl", "Failed to add additional protocol descriptor list");
+        return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
+      }
+      protocol_list_id++;
+    }
+  }
+
+  if (definition.profile_descriptors().has_value()) {
+    for (const auto& profile : definition.profile_descriptors().value()) {
+      bt_log(TRACE, "fidl", "Adding Profile %#hx v%d.%d",
+             static_cast<unsigned short>(profile.profile_id()), profile.major_version(),
+             profile.minor_version());
+      rec.AddProfile(bt::UUID(static_cast<uint16_t>(profile.profile_id())), profile.major_version(),
+                     profile.minor_version());
+    }
+  }
+
+  if (definition.information().has_value()) {
+    for (const auto& info : definition.information().value()) {
+      if (!info.language().has_value()) {
+        return fpromise::error(fuchsia::bluetooth::ErrorCode::INVALID_ARGUMENTS);
+      }
+
+      const std::string& language = info.language().value();
+      std::string name, description, provider;
+      if (info.name().has_value()) {
+        name = info.name().value();
+      }
+      if (info.description().has_value()) {
+        description = info.description().value();
+      }
+      if (info.provider().has_value()) {
+        provider = info.provider().value();
+      }
+      bt_log(TRACE, "fidl", "Adding Info (%s): (%s, %s, %s)", language.c_str(), name.c_str(),
+             description.c_str(), provider.c_str());
+      rec.AddInfo(language, name, description, provider);
+    }
+  }
+
+  if (definition.additional_attributes().has_value()) {
+    for (const auto& attribute : definition.additional_attributes().value()) {
+      auto elem = NewFidlToDataElement(attribute.element());
+      if (elem) {
+        bt_log(TRACE, "fidl", "Adding attribute %#x : %s", attribute.id(),
+               elem.value().ToString().c_str());
+        rec.SetAttribute(attribute.id(), std::move(elem.value()));
+      }
+    }
+  }
+  return fpromise::ok(std::move(rec));
+}
+
+fpromise::result<bt::sdp::ServiceRecord, fuchsia::bluetooth::ErrorCode>
 ServiceDefinitionToServiceRecord(const fuchsia::bluetooth::bredr::ServiceDefinition& definition) {
   bt::sdp::ServiceRecord rec;
   std::vector<bt::UUID> classes;
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/helpers.h b/src/connectivity/bluetooth/core/bt-host/fidl/helpers.h
index 2e37ade..ffb0515 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/helpers.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/helpers.h
@@ -5,19 +5,17 @@
 #ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_FIDL_HELPERS_H_
 #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_FIDL_HELPERS_H_
 
-#include <fuchsia/bluetooth/bredr/cpp/fidl.h>
-#include <fuchsia/bluetooth/cpp/fidl.h>
+#include <fidl/fuchsia.bluetooth.bredr/cpp/fidl.h>
 #include <fuchsia/bluetooth/gatt/cpp/fidl.h>
 #include <fuchsia/bluetooth/gatt2/cpp/fidl.h>
 #include <fuchsia/bluetooth/host/cpp/fidl.h>
 #include <fuchsia/bluetooth/le/cpp/fidl.h>
+#include <fuchsia/bluetooth/sys/cpp/fidl.h>
+#include <lib/fidl/cpp/type_converter.h>
+#include <lib/fpromise/result.h>
 
 #include <optional>
 
-#include "fuchsia/bluetooth/sys/cpp/fidl.h"
-#include "lib/fidl/cpp/type_converter.h"
-#include "lib/fidl/cpp/vector.h"
-#include "lib/fpromise/result.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/error.h"
@@ -115,9 +113,14 @@
 // Convert a bt::att::Error to fuchsia.bluetooth.gatt2.Error.
 fuchsia::bluetooth::gatt2::Error AttErrorToGattFidlError(const bt::att::Error& error);
 
+// Convert a fuchsia::bluetooth::Uuid to bt::UUID for old HLCPP FIDL bindings
 bt::UUID UuidFromFidl(const fuchsia::bluetooth::Uuid& input);
+// Convert a bt::UUID to fuchsia::bluetooth::Uuid for old HLCPP FIDL bindings
 fuchsia::bluetooth::Uuid UuidToFidl(const bt::UUID& uuid);
 
+// Convert a fuchsia_bluetooth::Uuid to bt::UUID for new C++ FIDL bindings
+bt::UUID NewUuidFromFidl(const fuchsia_bluetooth::Uuid& input);
+
 // Functions that convert FIDL types to library objects.
 bt::sm::IOCapability IoCapabilityFromFidl(const fuchsia::bluetooth::sys::InputCapability,
                                           const fuchsia::bluetooth::sys::OutputCapability);
@@ -183,6 +186,10 @@
 
 // Constructs a sdp::ServiceRecord from a FIDL ServiceDefinition |definition|
 fpromise::result<bt::sdp::ServiceRecord, fuchsia::bluetooth::ErrorCode>
+ServiceDefinitionToServiceRecord(const fuchsia_bluetooth_bredr::ServiceDefinition& definition);
+
+// Constructs a sdp::ServiceRecord from a FIDL ServiceDefinition |definition|
+fpromise::result<bt::sdp::ServiceRecord, fuchsia::bluetooth::ErrorCode>
 ServiceDefinitionToServiceRecord(const fuchsia::bluetooth::bredr::ServiceDefinition& definition);
 
 bt::gap::BrEdrSecurityRequirements FidlToBrEdrSecurityRequirements(
@@ -241,8 +248,12 @@
     fuchsia::bluetooth::bredr::AudioSamplingFrequency sampling_frequency,
     fuchsia::bluetooth::bredr::AudioChannelMode channel_mode);
 
+// For old HLCPP FIDL bindings
 std::optional<bt::sdp::DataElement> FidlToDataElement(
     const fuchsia::bluetooth::bredr::DataElement& fidl);
+// For new C++ FIDL bindings
+std::optional<bt::sdp::DataElement> NewFidlToDataElement(
+    const fuchsia_bluetooth_bredr::DataElement& fidl);
 
 }  // namespace bthost::fidl_helpers
 
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/helpers_test.cc b/src/connectivity/bluetooth/core/bt-host/fidl/helpers_test.cc
index 8db2457..cbc10b7 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/helpers_test.cc
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/helpers_test.cc
@@ -26,8 +26,8 @@
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sco/sco.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sdp/sdp.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sm/types.h"
+#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
-#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
 
 namespace fble = fuchsia::bluetooth::le;
 namespace fbt = fuchsia::bluetooth;
@@ -36,7 +36,6 @@
 namespace fbg2 = fuchsia::bluetooth::gatt2;
 namespace fbredr = fuchsia::bluetooth::bredr;
 namespace faudio = fuchsia::hardware::audio;
-namespace android_hci = pw::bluetooth::vendor::android_hci;
 
 namespace fuchsia::bluetooth {
 // Make UUIDs equality comparable for advanced testing matchers. ADL rules mandate the namespace.
@@ -76,7 +75,7 @@
 };
 const fsys::Ltk kTestLtkFidl{.key = kTestKeyFidl, .ediv = 0, .rand = 0};
 
-class HelpersTestWithLoop : public ::gtest::TestLoopFixture {
+class HelpersTestWithLoop : public bt::testing::TestLoopFixture {
  public:
   pw::async::Dispatcher& pw_dispatcher() { return pw_dispatcher_; }
 
@@ -157,6 +156,7 @@
 }
 
 TEST(HelpersTest, UuidFromFidl) {
+  // Test HLCPP FIDL bindings with fuchsia::bluetooth::Uuid
   fbt::Uuid input;
   input.value = {{0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x0d,
                   0x18, 0x00, 0x00}};
@@ -165,6 +165,16 @@
   bt::UUID output = UuidFromFidl(input);
   EXPECT_EQ("0000180d-0000-1000-8000-00805f9b34fb", output.ToString());
   EXPECT_EQ(2u, output.CompactSize());
+
+  // Test new C++ FIDL bindings with fuchsia_bluetooth::Uuid
+  fuchsia_bluetooth::Uuid input2;
+  input2.value({0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x0d, 0x18,
+                0x00, 0x00});
+
+  // We expect the input bytes to be carried over directly.
+  output = NewUuidFromFidl(input2);
+  EXPECT_EQ("0000180d-0000-1000-8000-00805f9b34fb", output.ToString());
+  EXPECT_EQ(2u, output.CompactSize());
 }
 
 TEST(HelpersTest, FidlToScmsTEnableTest) {
@@ -372,6 +382,164 @@
   }
 }
 
+template <typename T>
+void NewFidlToDataElementIntegerTest(
+    const std::function<fuchsia_bluetooth_bredr::DataElement(T)>& func,
+    bt::sdp::DataElement::Type type) {
+  fuchsia_bluetooth_bredr::DataElement data_element = func(std::numeric_limits<T>::max());
+  std::optional<bt::sdp::DataElement> result = NewFidlToDataElement(data_element);
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(type, result->type());
+  EXPECT_EQ(std::numeric_limits<T>::max(), result->Get<T>());
+
+  // result->size() returns an enum member of DataElement::Size indicating the number of bytes
+  uint8_t exponent = static_cast<uint8_t>(result->size());
+  EXPECT_EQ(sizeof(T), std::pow(2, exponent));
+}
+
+TEST(HelpersTest, NewFidlToDataElementInt8Test) {
+  NewFidlToDataElementIntegerTest(std::function(fuchsia_bluetooth_bredr::DataElement::WithInt8),
+                                  bt::sdp::DataElement::Type::kSignedInt);
+}
+
+TEST(HelpersTest, NewFidlToDataElementInt16Test) {
+  NewFidlToDataElementIntegerTest(std::function(fuchsia_bluetooth_bredr::DataElement::WithInt16),
+                                  bt::sdp::DataElement::Type::kSignedInt);
+}
+
+TEST(HelpersTest, NewFidlToDataElementInt32Test) {
+  NewFidlToDataElementIntegerTest(std::function(fuchsia_bluetooth_bredr::DataElement::WithInt32),
+                                  bt::sdp::DataElement::Type::kSignedInt);
+}
+
+TEST(HelpersTest, NewFidlToDataElementInt64Test) {
+  NewFidlToDataElementIntegerTest(std::function(fuchsia_bluetooth_bredr::DataElement::WithInt64),
+                                  bt::sdp::DataElement::Type::kSignedInt);
+}
+
+TEST(HelpersTest, NewFidlToDataElementUint8Test) {
+  NewFidlToDataElementIntegerTest(std::function(fuchsia_bluetooth_bredr::DataElement::WithUint8),
+                                  bt::sdp::DataElement::Type::kUnsignedInt);
+}
+
+TEST(HelpersTest, NewFidlToDataElementUint16Test) {
+  NewFidlToDataElementIntegerTest(std::function(fuchsia_bluetooth_bredr::DataElement::WithUint16),
+                                  bt::sdp::DataElement::Type::kUnsignedInt);
+}
+
+TEST(HelpersTest, NewFidlToDataElementUint32Test) {
+  NewFidlToDataElementIntegerTest(std::function(fuchsia_bluetooth_bredr::DataElement::WithUint32),
+                                  bt::sdp::DataElement::Type::kUnsignedInt);
+}
+
+TEST(HelpersTest, NewFidlToDataElementUint64Test) {
+  NewFidlToDataElementIntegerTest(std::function(fuchsia_bluetooth_bredr::DataElement::WithUint64),
+                                  bt::sdp::DataElement::Type::kUnsignedInt);
+}
+
+TEST(HelpersTest, NewFidlToDataElementEmptyStringTest) {
+  std::vector<uint8_t> data;
+  ASSERT_EQ(0u, data.size());
+
+  fuchsia_bluetooth_bredr::DataElement data_element =
+      fuchsia_bluetooth_bredr::DataElement::WithStr(std::move(data));
+  std::optional<bt::sdp::DataElement> result = NewFidlToDataElement(data_element);
+
+  EXPECT_TRUE(result.has_value());
+  EXPECT_EQ(bt::sdp::DataElement::Type::kString, result->type());
+  EXPECT_EQ("", result->Get<std::string>());
+  EXPECT_EQ(bt::sdp::DataElement::Size::kNextOne, result->size());
+}
+
+TEST(HelpersTest, NewFidlToDataElementStringTest) {
+  std::string expected_str = "foobarbaz";
+  std::vector<uint8_t> data(expected_str.size(), 0);
+  std::memcpy(data.data(), expected_str.data(), expected_str.size());
+
+  fuchsia_bluetooth_bredr::DataElement data_element =
+      fuchsia_bluetooth_bredr::DataElement::WithStr(std::move(data));
+  std::optional<bt::sdp::DataElement> result = NewFidlToDataElement(data_element);
+
+  EXPECT_TRUE(result.has_value());
+  EXPECT_EQ(bt::sdp::DataElement::Type::kString, result->type());
+  EXPECT_EQ(expected_str, result->Get<std::string>());
+  EXPECT_EQ(bt::sdp::DataElement::Size::kNextOne, result->size());
+}
+
+TEST(HelpersTest, NewFidlToDataElementUrlTest) {
+  std::string url = "http://www.google.com";
+  std::string moved = url;
+  fuchsia_bluetooth_bredr::DataElement data_element =
+      fuchsia_bluetooth_bredr::DataElement::WithUrl(std::move(moved));
+  std::optional<bt::sdp::DataElement> result = NewFidlToDataElement(data_element);
+
+  EXPECT_TRUE(result.has_value());
+  EXPECT_EQ(bt::sdp::DataElement::Type::kUrl, result->type());
+  EXPECT_EQ(url, result->GetUrl());
+  EXPECT_EQ(bt::sdp::DataElement::Size::kNextOne, result->size());
+}
+
+TEST(HelpersTest, NewFidlToDataElementBooleanTest) {
+  bool expected = true;
+  bool moved = expected;
+  fuchsia_bluetooth_bredr::DataElement data_element =
+      fuchsia_bluetooth_bredr::DataElement::WithB(std::move(moved));
+  std::optional<bt::sdp::DataElement> result = NewFidlToDataElement(data_element);
+
+  EXPECT_TRUE(result.has_value());
+  EXPECT_EQ(bt::sdp::DataElement::Type::kBoolean, result->type());
+  EXPECT_EQ(expected, result->Get<bool>());
+  EXPECT_EQ(bt::sdp::DataElement::Size::kOneByte, result->size());
+}
+
+TEST(HelpersTest, NewFidlToDataElementUuidTest) {
+  fuchsia_bluetooth::Uuid uuid;
+  uuid.value().fill(123);
+
+  fuchsia_bluetooth_bredr::DataElement data_element =
+      fuchsia_bluetooth_bredr::DataElement::WithUuid(std::move(uuid));
+  std::optional<bt::sdp::DataElement> result = NewFidlToDataElement(data_element);
+
+  ASSERT_TRUE(result.has_value());
+  EXPECT_EQ(bt::sdp::DataElement::Type::kUuid, result->type());
+  EXPECT_EQ(bt::sdp::DataElement::Size::kSixteenBytes, result->size());
+
+  bt::DynamicByteBuffer bytes(16);
+  bytes.Fill(123);
+
+  bt::UUID expected;
+  ASSERT_TRUE(bt::UUID::FromBytes(bytes, &expected));
+  EXPECT_EQ(expected, result->Get<bt::UUID>());
+}
+
+TEST(HelpersTest, NewFidlToDataElementSequenceTest) {
+  int8_t size = 3;
+  std::vector<fidl::Box<::fuchsia_bluetooth_bredr::DataElement>> moved;
+  std::vector<bt::sdp::DataElement> expected;
+
+  for (int16_t i = 0; i < size; i++) {
+    expected.emplace_back(i);
+    moved.push_back(std::make_unique<fuchsia_bluetooth_bredr::DataElement>(
+        fuchsia_bluetooth_bredr::DataElement::WithInt16(std::move(i))));
+  }
+
+  fuchsia_bluetooth_bredr::DataElement data_element =
+      fuchsia_bluetooth_bredr::DataElement::WithSequence(std::move(moved));
+  std::optional<bt::sdp::DataElement> result = NewFidlToDataElement(data_element);
+
+  EXPECT_TRUE(result.has_value());
+  EXPECT_EQ(bt::sdp::DataElement::Type::kSequence, result->type());
+  EXPECT_EQ(bt::sdp::DataElement::Size::kNextOne, result->size());
+
+  std::optional<std::vector<bt::sdp::DataElement>> actual =
+      result->Get<std::vector<bt::sdp::DataElement>>();
+  EXPECT_TRUE(actual);
+
+  for (int8_t i = 0; i < size; i++) {
+    EXPECT_EQ(expected[i].Get<int16_t>(), actual.value()[i].Get<int16_t>());
+  }
+}
+
 TEST(HelpersTest, AdvertisingDataFromFidlEmpty) {
   fble::AdvertisingData input;
   ASSERT_TRUE(input.IsEmpty());
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/host_server.cc b/src/connectivity/bluetooth/core/bt-host/fidl/host_server.cc
index 4f7207a..7ccc6cb 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/host_server.cc
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/host_server.cc
@@ -8,6 +8,7 @@
 
 #include <utility>
 
+#include "fuchsia/bluetooth/host/cpp/fidl.h"
 #include "gatt2_server_server.h"
 #include "gatt_server_server.h"
 #include "helpers.h"
@@ -31,6 +32,7 @@
 
 namespace fbt = fuchsia::bluetooth;
 namespace fsys = fuchsia::bluetooth::sys;
+namespace fhost = fuchsia::bluetooth::host;
 
 using bt::PeerId;
 using bt::gap::BrEdrSecurityModeToString;
@@ -138,10 +140,39 @@
   adapter->peer_cache()->ForEach([this](const bt::gap::Peer& peer) { OnPeerUpdated(peer); });
 }
 
-HostServer::~HostServer() { Close(); }
+HostServer::~HostServer() { Shutdown(); }
+
+void HostServer::RequestProtocol(fhost::ProtocolRequest request) {
+  switch (request.Which()) {
+    case fhost::ProtocolRequest::Tag::kCentral:
+      BindServer<LowEnergyCentralServer>(adapter()->AsWeakPtr(), std::move(request.central()),
+                                         gatt_);
+      break;
+    case fhost::ProtocolRequest::Tag::kPeripheral:
+      BindServer<LowEnergyPeripheralServer>(adapter()->AsWeakPtr(), gatt_,
+                                            std::move(request.peripheral()));
+      break;
+    case fhost::ProtocolRequest::Tag::kGattServer:
+      BindServer<GattServerServer>(gatt_->GetWeakPtr(), std::move(request.gatt_server()));
+      break;
+    case fhost::ProtocolRequest::Tag::kGatt2Server:
+      BindServer<Gatt2ServerServer>(gatt_->GetWeakPtr(), std::move(request.gatt2_server()));
+      break;
+    case fhost::ProtocolRequest::Tag::kProfile:
+      BindServer<ProfileServer>(adapter()->AsWeakPtr(), std::move(request.profile()));
+      break;
+    default:
+      bt_log(WARN, "fidl", "received unknown protocol request");
+      // The unknown protocol will be closed when `request` is destroyed.
+      break;
+  }
+}
 
 void HostServer::WatchState(WatchStateCallback callback) {
-  info_getter_.Watch(std::move(callback));
+  info_getter_.Watch([cb = std::move(callback)](fsys::HostInfo info) {
+    cb(fhost::Host_WatchState_Result::WithResponse(
+        fhost::Host_WatchState_Response(std::move(info))));
+  });
 }
 
 void HostServer::SetLocalData(fsys::HostData host_data) {
@@ -154,7 +185,11 @@
 }
 
 void HostServer::WatchPeers(WatchPeersCallback callback) {
-  watch_peers_getter_.Watch(std::move(callback));
+  watch_peers_getter_.Watch([cb = std::move(callback)](std::vector<fsys::Peer> updated,
+                                                       std::vector<fbt::PeerId> removed) {
+    cb(fhost::Host_WatchPeers_Result::WithResponse(
+        fhost::Host_WatchPeers_Response({std::move(updated), std::move(removed)})));
+  });
 }
 
 void HostServer::SetLocalName(::std::string local_name, SetLocalNameCallback callback) {
@@ -303,14 +338,13 @@
                               RestoreBondsCallback callback) {
   bt_log(INFO, "fidl", "%s", __FUNCTION__);
 
-  std::vector<fsys::BondingData> errors;
-
   if (bonds.empty()) {
     // Nothing to do. Reply with an empty list.
-    callback(std::move(errors));
+    callback(fhost::Host_RestoreBonds_Result::WithResponse(fhost::Host_RestoreBonds_Response()));
     return;
   }
 
+  std::vector<fsys::BondingData> errors;
   for (auto& bond : bonds) {
     if (!bond.has_identifier() || !bond.has_address() ||
         !(bond.has_le_bond() || bond.has_bredr_bond())) {
@@ -348,7 +382,8 @@
     }
   }
 
-  callback(std::move(errors));
+  callback(fhost::Host_RestoreBonds_Result::WithResponse(
+      fhost::Host_RestoreBonds_Response(std::move(errors))));
 }
 
 void HostServer::OnPeerBonded(const bt::gap::Peer& peer) {
@@ -718,48 +753,7 @@
   adapter()->bredr()->Pair(peer_id, security, std::move(on_complete));
 }
 
-void HostServer::RequestLowEnergyCentral(
-    fidl::InterfaceRequest<fuchsia::bluetooth::le::Central> central) {
-  BindServer<LowEnergyCentralServer>(std::move(central), gatt_);
-}
-
-void HostServer::RequestLowEnergyPeripheral(
-    fidl::InterfaceRequest<fuchsia::bluetooth::le::Peripheral> peripheral) {
-  BindServer<LowEnergyPeripheralServer>(gatt_, std::move(peripheral));
-}
-
-void HostServer::RequestGattServer(
-    fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Server> server) {
-  auto self = weak_self_.GetWeakPtr();
-  auto server_ptr = std::make_unique<GattServerServer>(gatt_->GetWeakPtr(), std::move(server));
-  server_ptr->set_error_handler([self, server = server_ptr.get()](zx_status_t status) {
-    if (self.is_alive()) {
-      bt_log(DEBUG, "bt-host", "GATT server disconnected");
-      self->servers_.erase(server);
-    }
-  });
-  servers_[server_ptr.get()] = std::move(server_ptr);
-}
-
-void HostServer::RequestGatt2Server(
-    fidl::InterfaceRequest<fuchsia::bluetooth::gatt2::Server> server) {
-  auto self = weak_self_.GetWeakPtr();
-  auto server_ptr = std::make_unique<Gatt2ServerServer>(gatt_->GetWeakPtr(), std::move(server));
-  server_ptr->set_error_handler([self, server = server_ptr.get()](zx_status_t status) {
-    if (self.is_alive()) {
-      bt_log(DEBUG, "bt-host", "GATT2 server disconnected");
-      self->servers_.erase(server);
-    }
-  });
-  servers_[server_ptr.get()] = std::move(server_ptr);
-}
-
-void HostServer::RequestProfile(
-    fidl::InterfaceRequest<fuchsia::bluetooth::bredr::Profile> profile) {
-  BindServer<ProfileServer>(std::move(profile));
-}
-
-void HostServer::Close() {
+void HostServer::Shutdown() {
   bt_log(INFO, "fidl", "closing FIDL handles");
 
   // Invalidate all weak pointers. This will guarantee that all pending tasks
@@ -801,6 +795,10 @@
   }
 }
 
+void HostServer::handle_unknown_method(uint64_t ordinal, bool method_has_response) {
+  bt_log(WARN, "fidl", "Received unknown method with ordinal: %lu", ordinal);
+}
+
 bt::sm::IOCapability HostServer::io_capability() const {
   bt_log(DEBUG, "fidl", "I/O capability: %s",
          bt::sm::util::IOCapabilityToString(io_capability_).c_str());
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/host_server.h b/src/connectivity/bluetooth/core/bt-host/fidl/host_server.h
index 5ca7e8b..289c53e 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/host_server.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/host_server.h
@@ -75,6 +75,7 @@
   ~HostServer() override;
 
   // ::fuchsia::bluetooth::host::Host overrides:
+  void RequestProtocol(::fuchsia::bluetooth::host::ProtocolRequest request) override;
   void WatchState(WatchStateCallback callback) override;
   void SetLocalData(::fuchsia::bluetooth::sys::HostData host_data) override;
   void WatchPeers(WatchPeersCallback callback) override;
@@ -101,18 +102,8 @@
   void Pair(::fuchsia::bluetooth::PeerId id, ::fuchsia::bluetooth::sys::PairingOptions options,
             PairCallback callback) override;
   void Forget(::fuchsia::bluetooth::PeerId id, ForgetCallback callback) override;
-
-  void RequestLowEnergyCentral(
-      ::fidl::InterfaceRequest<fuchsia::bluetooth::le::Central> central) override;
-  void RequestLowEnergyPeripheral(
-      ::fidl::InterfaceRequest<fuchsia::bluetooth::le::Peripheral> peripheral) override;
-  void RequestGattServer(
-      ::fidl::InterfaceRequest<fuchsia::bluetooth::gatt::Server> server) override;
-  void RequestGatt2Server(
-      ::fidl::InterfaceRequest<fuchsia::bluetooth::gatt2::Server> server) override;
-  void RequestProfile(
-      ::fidl::InterfaceRequest<fuchsia::bluetooth::bredr::Profile> profile) override;
-  void Close() override;
+  void Shutdown() override;
+  void handle_unknown_method(uint64_t ordinal, bool method_has_response) override;
 
  private:
   // bt::gap::PairingDelegate overrides:
@@ -165,7 +156,7 @@
   // ServerType.
   template <typename ServerType, typename... Args>
   void BindServer(Args... args) {
-    auto server = std::make_unique<ServerType>(adapter()->AsWeakPtr(), std::move(args)...);
+    auto server = std::make_unique<ServerType>(std::move(args)...);
     Server* s = server.get();
     server->set_error_handler([this, s](zx_status_t status) { this->OnConnectionError(s); });
     servers_[server.get()] = std::move(server);
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/host_server_test.cc b/src/connectivity/bluetooth/core/bt-host/fidl/host_server_test.cc
index ce9617c..879eef9 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/host_server_test.cc
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/host_server_test.cc
@@ -50,6 +50,7 @@
 
 namespace fbt = fuchsia::bluetooth;
 namespace fsys = fuchsia::bluetooth::sys;
+namespace fhost = fuchsia::bluetooth::host;
 
 const bt::PeerId kTestId(1);
 const bt::DeviceAddress kLeTestAddr(bt::DeviceAddress::Type::kLEPublic, {0x01, 0, 0, 0, 0, 0});
@@ -167,11 +168,11 @@
     return peer;
   }
 
-  using ConnectResult = fpromise::result<void, fsys::Error>;
+  using ConnectResult = fhost::Host_Connect_Result;
   std::optional<ConnectResult> ConnectFakePeer(bt::PeerId id) {
     std::optional<ConnectResult> result;
     host_client()->Connect(fbt::PeerId{id.value()},
-                           [&](ConnectResult _result) { result = _result; });
+                           [&](ConnectResult _result) { result = std::move(_result); });
     RunLoopUntilIdle();
     return result;
   }
@@ -188,7 +189,7 @@
 
     auto connect_result = ConnectFakePeer(peer->identifier());
 
-    if (!connect_result || connect_result->is_error()) {
+    if (!connect_result || connect_result->is_err()) {
       peer = nullptr;
       fake_chan.reset();
     }
@@ -199,12 +200,13 @@
   void TestRestoreBonds(std::vector<fsys::BondingData> bonds,
                         std::vector<fsys::BondingData> expected) {
     bool called = false;
-    host_server()->RestoreBonds(std::move(bonds), [&](auto errors) {
+    host_server()->RestoreBonds(std::move(bonds), [&](fhost::Host_RestoreBonds_Result result) {
+      ASSERT_TRUE(result.is_response());
       called = true;
-      ASSERT_EQ(expected.size(), errors.size());
-      for (size_t i = 0; i < errors.size(); i++) {
+      ASSERT_EQ(expected.size(), result.response().errors.size());
+      for (size_t i = 0; i < result.response().errors.size(); i++) {
         SCOPED_TRACE(i);
-        EXPECT_TRUE(fidl::Equals(errors[i], expected[i]));
+        EXPECT_TRUE(fidl::Equals(result.response().errors[i], expected[i]));
       }
     });
     EXPECT_TRUE(called);
@@ -529,7 +531,10 @@
 
 TEST_F(HostServerTest, WatchState) {
   std::optional<fsys::HostInfo> info;
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   ASSERT_TRUE(info.has_value());
   ASSERT_TRUE(info->has_id());
   ASSERT_TRUE(info->has_technology());
@@ -552,12 +557,18 @@
   std::optional<fsys::HostInfo> info;
 
   // Make initial watch call so that subsequent calls remain pending.
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   ASSERT_TRUE(info.has_value());
   info.reset();
 
   // Watch for updates.
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   EXPECT_FALSE(info.has_value());
 
   host_server()->StartDiscovery([](auto) {});
@@ -567,7 +578,10 @@
   EXPECT_TRUE(info->discovering());
 
   info.reset();
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   EXPECT_FALSE(info.has_value());
   host_server()->StopDiscovery();
   RunLoopUntilIdle();
@@ -580,12 +594,18 @@
   std::optional<fsys::HostInfo> info;
 
   // Make initial watch call so that subsequent calls remain pending.
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   ASSERT_TRUE(info.has_value());
   info.reset();
 
   // Watch for updates.
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   EXPECT_FALSE(info.has_value());
 
   host_server()->SetDiscoverable(/*discoverable=*/true, [](auto) {});
@@ -595,7 +615,10 @@
   EXPECT_TRUE(info->discoverable());
 
   info.reset();
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   EXPECT_FALSE(info.has_value());
   host_server()->SetDiscoverable(/*discoverable=*/false, [](auto) {});
   RunLoopUntilIdle();
@@ -628,10 +651,10 @@
   };
   fake_chan()->SetSendCallback(expect_default_bytebuffer, pw_dispatcher());
 
-  std::optional<fpromise::result<void, fsys::Error>> pair_result;
+  std::optional<fhost::Host_Pair_Result> pair_result;
   fsys::PairingOptions opts;
   host_client()->Pair(fbt::PeerId{peer()->identifier().value()}, std::move(opts),
-                      [&](auto result) { pair_result = std::move(result); });
+                      [&](fhost::Host_Pair_Result result) { pair_result = std::move(result); });
   RunLoopUntilIdle();
 
   // TODO(https://fxbug.dev/42169848): We don't have a good mechanism for driving pairing to
@@ -663,7 +686,7 @@
   };
   fake_chan()->SetSendCallback(expect_default_bytebuffer, pw_dispatcher());
 
-  std::optional<fpromise::result<void, fsys::Error>> pair_result;
+  std::optional<fhost::Host_Pair_Result> pair_result;
   fsys::PairingOptions opts;
   opts.set_le_security_level(fsys::PairingSecurityLevel::ENCRYPTED);
   host_client()->Pair(fbt::PeerId{peer()->identifier().value()}, std::move(opts),
@@ -701,7 +724,7 @@
   };
   fake_chan()->SetSendCallback(expect_default_bytebuffer, pw_dispatcher());
 
-  std::optional<fpromise::result<void, fsys::Error>> pair_result;
+  std::optional<fhost::Host_Pair_Result> pair_result;
   fsys::PairingOptions opts;
   opts.set_bondable_mode(fsys::BondableMode::NON_BONDABLE);
   host_client()->Pair(fbt::PeerId{peer()->identifier().value()}, std::move(opts),
@@ -722,7 +745,7 @@
   ASSERT_TRUE(fake_chan.is_alive());
   ASSERT_EQ(bt::gap::Peer::ConnectionState::kConnected, peer->le()->connection_state());
 
-  std::optional<fpromise::result<void, fsys::Error>> pair_result;
+  std::optional<fhost::Host_Pair_Result> pair_result;
   fsys::PairingOptions opts;
   // Set pairing option with classic
   opts.set_transport(fsys::TechnologyType::CLASSIC);
@@ -733,14 +756,15 @@
   host_client()->Pair(fbt::PeerId{peer->identifier().value()}, std::move(opts), std::move(pair_cb));
   RunLoopUntilIdle();
   ASSERT_TRUE(pair_result);
-  ASSERT_EQ(pair_result->error(), fsys::Error::PEER_NOT_FOUND);
+  ASSERT_TRUE(pair_result->is_err());
+  ASSERT_EQ(pair_result->err(), fsys::Error::PEER_NOT_FOUND);
 }
 
 TEST_F(HostServerTest, WatchPeersHangsOnFirstCallWithNoExistingPeers) {
   // By default the peer cache contains no entries when HostServer is first constructed. The first
   // call to WatchPeers should hang.
   bool replied = false;
-  host_server()->WatchPeers([&](auto, auto) { replied = true; });
+  host_server()->WatchPeers([&](auto) { replied = true; });
   EXPECT_FALSE(replied);
 }
 
@@ -751,9 +775,10 @@
 
   // The first call to WatchPeers immediately resolves with the contents of the peer cache.
   bool replied = false;
-  host_server()->WatchPeers([&](auto updated, auto removed) {
-    EXPECT_EQ(1u, updated.size());
-    EXPECT_TRUE(removed.empty());
+  host_server()->WatchPeers([&](fhost::Host_WatchPeers_Result result) {
+    ASSERT_TRUE(result.is_response());
+    EXPECT_EQ(1u, result.response().updated.size());
+    EXPECT_TRUE(result.response().removed.empty());
     replied = true;
   });
   EXPECT_TRUE(replied);
@@ -774,12 +799,13 @@
   ResetHostServer();
 
   bool replied = false;
-  host_client()->WatchPeers([&](auto updated, [[maybe_unused]] auto removed) {
+  host_client()->WatchPeers([&](fhost::Host_WatchPeers_Result result) {
     // Client should still receive updates to this peer.
     replied = true;
     const fbt::PeerId id = {peer->identifier().value()};
-    ASSERT_THAT(updated, Contains(Property(&fsys::Peer::id, id)));
-    EXPECT_FALSE(updated.front().has_appearance());
+    ASSERT_TRUE(result.is_response());
+    ASSERT_THAT(result.response().updated, Contains(Property(&fsys::Peer::id, id)));
+    EXPECT_FALSE(result.response().updated.front().has_appearance());
   });
   RunLoopUntilIdle();
   EXPECT_TRUE(replied);
@@ -790,9 +816,10 @@
   std::optional<std::vector<fbt::PeerId>> removed;
 
   // Initial watch call hangs as the cache is empty.
-  host_server()->WatchPeers([&](auto updated_arg, auto removed_arg) {
-    updated = std::move(updated_arg);
-    removed = std::move(removed_arg);
+  host_server()->WatchPeers([&](fhost::Host_WatchPeers_Result result) {
+    ASSERT_TRUE(result.is_response());
+    updated = std::move(result.response().updated);
+    removed = std::move(result.response().removed);
   });
   ASSERT_FALSE(updated.has_value());
   ASSERT_FALSE(removed.has_value());
@@ -808,9 +835,10 @@
   removed.reset();
 
   // The next call should hang.
-  host_server()->WatchPeers([&](auto updated_arg, auto removed_arg) {
-    updated = std::move(updated_arg);
-    removed = std::move(removed_arg);
+  host_server()->WatchPeers([&](fhost::Host_WatchPeers_Result result) {
+    ASSERT_TRUE(result.is_response());
+    updated = std::move(result.response().updated);
+    removed = std::move(result.response().removed);
   });
   ASSERT_FALSE(updated.has_value());
   ASSERT_FALSE(removed.has_value());
@@ -838,10 +866,11 @@
   }
 
   bool replied = false;
-  host_server()->WatchPeers([&replied, id](auto updated, auto removed) {
-    EXPECT_TRUE(updated.empty());
-    EXPECT_EQ(1u, removed.size());
-    EXPECT_TRUE(fidl::Equals(fbt::PeerId{id.value()}, removed[0]));
+  host_server()->WatchPeers([&replied, id](fhost::Host_WatchPeers_Result result) {
+    ASSERT_TRUE(result.is_response());
+    EXPECT_TRUE(result.response().updated.empty());
+    EXPECT_EQ(1u, result.response().removed.size());
+    EXPECT_TRUE(fidl::Equals(fbt::PeerId{id.value()}, result.response().removed[0]));
     replied = true;
   });
   EXPECT_TRUE(replied);
@@ -886,7 +915,7 @@
 
   auto result = ConnectFakePeer(peer->identifier());
   ASSERT_TRUE(result);
-  ASSERT_FALSE(result->is_error());
+  ASSERT_FALSE(result->is_err());
 
   EXPECT_FALSE(peer->bredr());
   ASSERT_TRUE(peer->le());
@@ -903,7 +932,7 @@
 
   auto result = ConnectFakePeer(peer->identifier());
   ASSERT_TRUE(result);
-  ASSERT_FALSE(result->is_error());
+  ASSERT_FALSE(result->is_err());
 
   EXPECT_FALSE(peer->le());
   ASSERT_TRUE(peer->bredr());
@@ -924,7 +953,7 @@
 
   auto result = ConnectFakePeer(peer->identifier());
   ASSERT_TRUE(result);
-  ASSERT_FALSE(result->is_error());
+  ASSERT_FALSE(result->is_err());
 
   // bt-host should only attempt to connect the BR/EDR transport.
   EXPECT_FALSE(peer->le()->connected());
@@ -1284,11 +1313,17 @@
 TEST_F(HostServerTestFakeAdapter, SetLocalNameNotifiesWatchState) {
   std::vector<fsys::HostInfo> info;
   // Consume initial state value.
-  host_client()->WatchState([&](auto value) { info.push_back(std::move(value)); });
+  host_client()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info.push_back(std::move(result.response().info));
+  });
   RunLoopUntilIdle();
   EXPECT_EQ(info.size(), 1u);
   // Second watch state will hang until state is updated.
-  host_client()->WatchState([&](auto value) { info.push_back(std::move(value)); });
+  host_client()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info.push_back(std::move(result.response().info));
+  });
   RunLoopUntilIdle();
   EXPECT_EQ(info.size(), 1u);
 
@@ -1309,12 +1344,18 @@
   std::optional<fsys::HostInfo> info;
 
   // Make an initial watch call so that subsequent calls remain pending.
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   ASSERT_TRUE(info.has_value());
   info.reset();
 
   // Next request to watch should hang and not produce a result.
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   EXPECT_FALSE(info.has_value());
 
   host_server()->EnablePrivacy(/*enabled=*/true);
@@ -1338,7 +1379,10 @@
                               info->addresses()[1].bytes));
 
   info.reset();
-  host_server()->WatchState([&](auto value) { info = std::move(value); });
+  host_server()->WatchState([&](fhost::Host_WatchState_Result result) {
+    ASSERT_TRUE(result.is_response());
+    info = std::move(result.response().info);
+  });
   EXPECT_FALSE(info.has_value());
   // Disabling privacy is a synchronous operation - the random LE address should no longer be used.
   host_server()->EnablePrivacy(/*enabled=*/false);
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/host_server_watch_peers_fuzztest.cc b/src/connectivity/bluetooth/core/bt-host/fidl/host_server_watch_peers_fuzztest.cc
index 2ef71fa..b55550a 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/host_server_watch_peers_fuzztest.cc
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/host_server_watch_peers_fuzztest.cc
@@ -41,7 +41,11 @@
     // TODO(https://fxbug.dev/42144165): WatchPeers will trigger this test as a failure if we try to
     // encode a lot of peers, even though fuzzing multiple peers would be helpful.
     int watch_peers_responses = 0;
-    host_client()->WatchPeers([this, peer, &watch_peers_responses](auto updated, auto removed) {
+    host_client()->WatchPeers([this, peer, &watch_peers_responses](
+                                  fuchsia::bluetooth::host::Host_WatchPeers_Result result) {
+      BT_ASSERT(result.is_response());
+      std::vector<::fuchsia::bluetooth::sys::Peer> updated = std::move(result.response().updated);
+      std::vector<::fuchsia::bluetooth::PeerId> removed = std::move(result.response().removed);
       BT_ASSERT_MSG(updated.size() == 1, "peer %s: peers updated = %zu", bt_str(*peer),
                     updated.size());
       BT_ASSERT_MSG(removed.size() == 0, "peer %s: peers removed = %zu", bt_str(*peer),
@@ -76,9 +80,14 @@
                                 std::vector<fuchsia::bluetooth::PeerId> removed) {
     call_counter++;
     BT_ASSERT_MSG(call_counter <= max_call_depth, "max depth (%d) exceeded", call_counter);
-    host.WatchPeers([this, &host, &call_counter, max_call_depth](auto updated, auto removed) {
-      this->HandleWatchPeersResponse(host, call_counter, max_call_depth, std::move(updated),
-                                     std::move(removed));
+    host.WatchPeers([this, &host, &call_counter,
+                     max_call_depth](fuchsia::bluetooth::host::Host_WatchPeers_Result result) {
+      BT_ASSERT(result.is_response());
+      std::vector<::fuchsia::bluetooth::sys::Peer> updated = std::move(result.response().updated);
+      std::vector<::fuchsia::bluetooth::PeerId> removed = std::move(result.response().removed);
+      this->HandleWatchPeersResponse(host, call_counter, max_call_depth,
+                                     std::move(result.response().updated),
+                                     std::move(result.response().removed));
     });
   }
 
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/profile_server.cc b/src/connectivity/bluetooth/core/bt-host/fidl/profile_server.cc
index 5b10672..2165f1b 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/profile_server.cc
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/profile_server.cc
@@ -16,11 +16,11 @@
 #include "lib/fidl/cpp/binding.h"
 #include "lib/fidl/cpp/interface_ptr.h"
 #include "lib/fpromise/result.h"
+#include "pw_intrusive_ptr/intrusive_ptr.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/host_error.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/log.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/uuid.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/weak_self.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/types.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/types.h"
 #include "zircon/errors.h"
 
@@ -281,7 +281,7 @@
   }
 
   const uint32_t a2dp_offload_capabilities =
-      adapter_state.android_vendor_capabilities.a2dp_source_offload_capability_mask();
+      adapter_state.android_vendor_capabilities->a2dp_source_offload_capability_mask();
   const uint32_t sbc_capability = static_cast<uint32_t>(android_hci::A2dpCodecType::SBC);
   const uint32_t aac_capability = static_cast<uint32_t>(android_hci::A2dpCodecType::AAC);
 
@@ -552,9 +552,19 @@
   };
 
   fidlbredr::ConnectionReceiverPtr receiver = request.mutable_receiver()->Bind();
-
-  receiver.set_error_handler(
-      [this, next](zx_status_t /*status*/) { OnConnectionReceiverError(next); });
+  // Monitor events on the `ConnectionReceiver`. Remove the service if the FIDL client revokes the
+  // service registration.
+  receiver.events().OnRevoke = [this, ad_id = next]() {
+    bt_log(DEBUG, "fidl", "Connection receiver revoked. Ending service advertisement %lu", ad_id);
+    OnConnectionReceiverClosed(ad_id);
+  };
+  // Errors on the `ConnectionReceiver` will result in service unregistration.
+  receiver.set_error_handler([this, ad_id = next](zx_status_t status) {
+    bt_log(DEBUG, "fidl",
+           "Connection receiver closed with error: %s. Ending service advertisement %lu",
+           zx_status_get_string(status), ad_id);
+    OnConnectionReceiverClosed(ad_id);
+  });
 
   current_advertised_.try_emplace(next, std::move(receiver), registration_handle,
                                   std::move(callback));
@@ -672,7 +682,7 @@
   }
   auto params = params_result.value();
 
-  auto sco_request = fbl::MakeRefCounted<ScoRequest>();
+  pw::IntrusivePtr<ScoRequest> sco_request = pw::MakeRefCounted<ScoRequest>();
   client.set_error_handler(
       [sco_request](zx_status_t status) { sco_request->request_handle.reset(); });
   sco_request->receiver = std::move(client);
@@ -755,11 +765,8 @@
   it->second.receiver->Connected(peer_id, std::move(fidl_chan), std::move(list));
 }
 
-void ProfileServer::OnConnectionReceiverError(uint64_t ad_id) {
-  bt_log(DEBUG, "fidl", "Connection receiver closed, ending advertisement %lu", ad_id);
-
+void ProfileServer::OnConnectionReceiverClosed(uint64_t ad_id) {
   auto it = current_advertised_.find(ad_id);
-
   if (it == current_advertised_.end() || !adapter().is_alive()) {
     return;
   }
@@ -831,7 +838,7 @@
 }
 
 void ProfileServer::OnScoConnectionResult(
-    fbl::RefPtr<ScoRequest> request,  // NOLINT(performance-unnecessary-value-param)
+    pw::IntrusivePtr<ScoRequest> request,  // NOLINT(performance-unnecessary-value-param)
     bt::sco::ScoConnectionManager::AcceptConnectionResult result) {
   auto receiver = std::move(request->receiver);
 
@@ -979,7 +986,7 @@
   }
 
   if (adapter()->state().IsControllerFeatureSupported(FeaturesBits::kAndroidVendorExtensions) &&
-      adapter()->state().android_vendor_capabilities.a2dp_source_offload_capability_mask()) {
+      adapter()->state().android_vendor_capabilities->a2dp_source_offload_capability_mask()) {
     fidl_chan.set_ext_audio_offload(BindAudioOffloadExtServer(channel));
   }
 
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/profile_server.h b/src/connectivity/bluetooth/core/bt-host/fidl/profile_server.h
index e480e29..a184ebe 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/profile_server.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/profile_server.h
@@ -7,9 +7,8 @@
 
 #include <fuchsia/bluetooth/bredr/cpp/fidl.h>
 
-#include <fbl/ref_counted.h>
-
 #include "lib/fidl/cpp/binding.h"
+#include "pw_intrusive_ptr/intrusive_ptr.h"
 #include "src/connectivity/bluetooth/core/bt-host/fidl/server_base.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/macros.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/bredr_connection_manager.h"
@@ -126,7 +125,7 @@
     fit::callback<void(fuchsia::bluetooth::bredr::RxPacketStatus, std::vector<uint8_t>)> read_cb_;
   };
 
-  struct ScoRequest : public fbl::RefCounted<ScoRequest> {
+  struct ScoRequest : public pw::RefCounted<ScoRequest> {
     std::optional<bt::gap::BrEdrConnectionManager::ScoRequestHandle> request_handle;
     fuchsia::bluetooth::bredr::ScoConnectionReceiverPtr receiver;
     std::vector<fuchsia::bluetooth::bredr::ScoConnectionParameters> parameters;
@@ -142,8 +141,8 @@
   void ConnectSco(::fuchsia::bluetooth::bredr::ProfileConnectScoRequest request) override;
   void handle_unknown_method(uint64_t ordinal, bool method_has_response) override;
 
-  // Callback when clients close their connection targets
-  void OnConnectionReceiverError(uint64_t ad_id);
+  // Callback when clients close or revoke their connection targets
+  void OnConnectionReceiverClosed(uint64_t ad_id);
 
   // Callback when clients close their search results
   void OnSearchResultError(uint64_t search_id, zx_status_t status);
@@ -157,7 +156,7 @@
                       const std::map<bt::sdp::AttributeId, bt::sdp::DataElement>& attributes);
 
   // Callback for SCO connections requests.
-  void OnScoConnectionResult(fbl::RefPtr<ScoRequest> request,
+  void OnScoConnectionResult(pw::IntrusivePtr<ScoRequest> request,
                              bt::sco::ScoConnectionManager::AcceptConnectionResult);
 
   // Callback when clients close their audio direction extension.
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/profile_server_test.cc b/src/connectivity/bluetooth/core/bt-host/fidl/profile_server_test.cc
index 16a5eb8..dd49022 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/profile_server_test.cc
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/profile_server_test.cc
@@ -201,7 +201,9 @@
  public:
   FakeConnectionReceiver(fidl::InterfaceRequest<ConnectionReceiver> request,
                          async_dispatcher_t* dispatcher)
-      : binding_(this, std::move(request), dispatcher), connected_count_(0) {}
+      : binding_(this, std::move(request), dispatcher), connected_count_(0), closed_(false) {
+    binding_.set_error_handler([&](zx_status_t /*status*/) { closed_ = true; });
+  }
 
   void Connected(fuchsia::bluetooth::PeerId peer_id, fidlbredr::Channel channel,
                  std::vector<fidlbredr::ProtocolDescriptor> protocol) override {
@@ -211,12 +213,15 @@
     connected_count_++;
   }
 
+  void Revoke() { binding_.events().OnRevoke(); }
+
   size_t connected_count() const { return connected_count_; }
   const std::optional<fuchsia::bluetooth::PeerId>& peer_id() const { return peer_id_; }
   const std::optional<fidlbredr::Channel>& channel() const { return channel_; }
   const std::optional<std::vector<fidlbredr::ProtocolDescriptor>>& protocol() const {
     return protocol_;
   }
+  bool closed() { return closed_; }
 
   std::optional<fidlbredr::AudioDirectionExtPtr> bind_ext_direction() {
     if (!channel().has_value()) {
@@ -238,6 +243,7 @@
   std::optional<fuchsia::bluetooth::PeerId> peer_id_;
   std::optional<fidlbredr::Channel> channel_;
   std::optional<std::vector<fidlbredr::ProtocolDescriptor>> protocol_;
+  bool closed_;
 
   void NotImplemented_(const std::string& name) override {
     FAIL() << name << " is not implemented";
@@ -431,6 +437,39 @@
   ASSERT_EQ(cb_count, 1u);
 }
 
+TEST_F(ProfileServerTest, RevokeConnectionReceiverUnregistersAdvertisement) {
+  fidlbredr::ConnectionReceiverHandle receiver_handle;
+  FakeConnectionReceiver connect_receiver(receiver_handle.NewRequest(), dispatcher());
+
+  std::vector<fidlbredr::ServiceDefinition> services;
+  services.emplace_back(MakeFIDLServiceDefinition());
+
+  size_t cb_count = 0;
+  auto cb = [&](fidlbredr::Profile_Advertise_Result result) {
+    cb_count++;
+    EXPECT_TRUE(result.is_response());
+  };
+
+  fidlbredr::ProfileAdvertiseRequest adv_request;
+  adv_request.set_services(std::move(services));
+  adv_request.set_receiver(std::move(receiver_handle));
+  client()->Advertise(std::move(adv_request), std::move(cb));
+  RunLoopUntilIdle();
+
+  // Advertisement is still active, callback shouldn't get triggered.
+  ASSERT_EQ(cb_count, 0u);
+  ASSERT_FALSE(connect_receiver.closed());
+
+  // Server end of `ConnectionReceiver` revokes the advertisement.
+  connect_receiver.Revoke();
+  RunLoopUntilIdle();
+
+  // Profile server should drop the advertisement and notify the callback of termination. The
+  // `connect_receiver` should be closed.
+  ASSERT_EQ(cb_count, 1u);
+  ASSERT_TRUE(connect_receiver.closed());
+}
+
 class ProfileServerTestConnectedPeer : public ProfileServerTest {
  public:
   ProfileServerTestConnectedPeer() = default;
@@ -1537,9 +1576,11 @@
       params;
   params.SetToZeros();
   params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
-  params.view().a2dp_source_offload_capability_mask().BackingStorage().UncheckedWriteUInt(
-      static_cast<uint32_t>(android_hci::A2dpCodecType::AAC));
-  adapter()->mutable_state().android_vendor_capabilities.Initialize(params.view());
+  params.view().version_supported().major_number().Write(0);
+  params.view().version_supported().minor_number().Write(98);
+  params.view().a2dp_source_offload_capability_mask().aac().Write(true);
+  adapter()->mutable_state().android_vendor_capabilities =
+      bt::gap::AndroidVendorCapabilities::New(params.view());
 
   // Set L2CAP channel parameters
   fidlbredr::L2capParameters l2cap_params;
@@ -1604,8 +1645,11 @@
       pw::bluetooth::vendor::android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>
       params;
   params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
+  params.view().version_supported().major_number().Write(0);
+  params.view().version_supported().minor_number().Write(98);
   params.view().a2dp_source_offload_capability_mask().sbc().Write(true);
-  adapter()->mutable_state().android_vendor_capabilities.Initialize(params.view());
+  adapter()->mutable_state().android_vendor_capabilities =
+      bt::gap::AndroidVendorCapabilities::New(params.view());
 
   // set up a fake channel and connection
   FakeChannel::WeakPtr fake_channel;
@@ -1695,9 +1739,12 @@
         params;
     params.SetToZeros();
     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
+    params.view().version_supported().major_number().Write(0);
+    params.view().version_supported().minor_number().Write(98);
     params.view().a2dp_source_offload_capability_mask().BackingStorage().UncheckedWriteUInt(
         a2dp_offload_capabilities);
-    adapter()->mutable_state().android_vendor_capabilities.Initialize(params.view());
+    adapter()->mutable_state().android_vendor_capabilities =
+        bt::gap::AndroidVendorCapabilities::New(params.view());
   }
 
   const bt::PeerId peer_id(1);
@@ -1766,9 +1813,12 @@
         params;
     params.SetToZeros();
     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
+    params.view().version_supported().major_number().Write(0);
+    params.view().version_supported().minor_number().Write(98);
     params.view().a2dp_source_offload_capability_mask().BackingStorage().UncheckedWriteUInt(
         a2dp_offload_capabilities);
-    adapter()->mutable_state().android_vendor_capabilities.Initialize(params.view());
+    adapter()->mutable_state().android_vendor_capabilities =
+        bt::gap::AndroidVendorCapabilities::New(params.view());
   }
 
   const bt::PeerId peer_id(1);
@@ -1859,9 +1909,12 @@
         params;
     params.SetToZeros();
     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
+    params.view().version_supported().major_number().Write(0);
+    params.view().version_supported().minor_number().Write(98);
     params.view().a2dp_source_offload_capability_mask().BackingStorage().UncheckedWriteUInt(
         a2dp_offload_capabilities);
-    adapter()->mutable_state().android_vendor_capabilities.Initialize(params.view());
+    adapter()->mutable_state().android_vendor_capabilities =
+        bt::gap::AndroidVendorCapabilities::New(params.view());
   }
 
   const bt::PeerId peer_id(1);
@@ -1955,9 +2008,12 @@
         params;
     params.SetToZeros();
     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
+    params.view().version_supported().major_number().Write(0);
+    params.view().version_supported().minor_number().Write(98);
     params.view().a2dp_source_offload_capability_mask().BackingStorage().UncheckedWriteUInt(
         a2dp_offload_capabilities);
-    adapter()->mutable_state().android_vendor_capabilities.Initialize(params.view());
+    adapter()->mutable_state().android_vendor_capabilities =
+        bt::gap::AndroidVendorCapabilities::New(params.view());
   }
 
   const bt::PeerId peer_id(1);
@@ -2051,9 +2107,12 @@
         params;
     params.SetToZeros();
     params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
+    params.view().version_supported().major_number().Write(0);
+    params.view().version_supported().minor_number().Write(98);
     params.view().a2dp_source_offload_capability_mask().BackingStorage().UncheckedWriteUInt(
         a2dp_offload_capabilities);
-    adapter()->mutable_state().android_vendor_capabilities.Initialize(params.view());
+    adapter()->mutable_state().android_vendor_capabilities =
+        bt::gap::AndroidVendorCapabilities::New(params.view());
   }
 
   const bt::PeerId peer_id(1);
diff --git a/src/connectivity/bluetooth/core/bt-host/fidl/server_base.h b/src/connectivity/bluetooth/core/bt-host/fidl/server_base.h
index 813f90b..0bfef7a 100644
--- a/src/connectivity/bluetooth/core/bt-host/fidl/server_base.h
+++ b/src/connectivity/bluetooth/core/bt-host/fidl/server_base.h
@@ -9,8 +9,6 @@
 
 #include <utility>
 
-#include <fbl/ref_ptr.h>
-
 #include "lib/fidl/cpp/binding.h"
 #include "lib/fidl/cpp/interface_request.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/assert.h"
diff --git a/src/connectivity/bluetooth/core/bt-host/gap/adapter.cc b/src/connectivity/bluetooth/core/bt-host/gap/adapter.cc
index a377490..5bc78331 100644
--- a/src/connectivity/bluetooth/core/bt-host/gap/adapter.cc
+++ b/src/connectivity/bluetooth/core/bt-host/gap/adapter.cc
@@ -40,6 +40,7 @@
 namespace bt::gap {
 
 namespace hci_android = hci_spec::vendor::android;
+namespace android_hci = pw::bluetooth::vendor::android_hci;
 
 static constexpr const char* kInspectLowEnergyDiscoveryManagerNodeName =
     "low_energy_discovery_manager";
@@ -397,6 +398,11 @@
   // reconfigure the LE random address.
   bool IsLeRandomAddressChangeAllowed();
 
+  // Called when we receive an LE Get Vendor Capabilities Command Complete from
+  // the Controller
+  void ParseLEGetVendorCapabilitiesCommandComplete(
+      const hci::EmbossEventPacket& event);
+
   std::unique_ptr<hci::LowEnergyAdvertiser> CreateAdvertiser(bool extended) {
     if (extended) {
       return std::make_unique<hci::ExtendedLowEnergyAdvertiser>(hci_);
@@ -404,19 +410,28 @@
 
     constexpr pw::bluetooth::Controller::FeaturesBits feature =
         pw::bluetooth::Controller::FeaturesBits::kAndroidVendorExtensions;
-    if (state().IsControllerFeatureSupported(feature)) {
-      uint8_t max_advt =
-          state().android_vendor_capabilities.max_simultaneous_advertisements();
-      bt_log(INFO,
-             "gap",
-             "controller supports android vendor extensions, max simultaneous "
-             "advertisements: %d",
-             max_advt);
-      return std::make_unique<hci::AndroidExtendedLowEnergyAdvertiser>(
-          hci_, max_advt);
+    if (!state().IsControllerFeatureSupported(feature)) {
+      return std::make_unique<hci::LegacyLowEnergyAdvertiser>(hci_);
     }
 
-    return std::make_unique<hci::LegacyLowEnergyAdvertiser>(hci_);
+    if (!state().android_vendor_capabilities) {
+      bt_log(
+          WARN,
+          "gap",
+          "controller supports android vendor extensions, but failed to parse "
+          "LEGetVendorCapabilitiesCommandComplete, using legacy advertiser");
+      return std::make_unique<hci::LegacyLowEnergyAdvertiser>(hci_);
+    }
+
+    uint8_t max_advt =
+        state().android_vendor_capabilities->max_simultaneous_advertisements();
+    bt_log(INFO,
+           "gap",
+           "controller supports android vendor extensions, max simultaneous "
+           "advertisements: %d",
+           max_advt);
+    return std::make_unique<hci::AndroidExtendedLowEnergyAdvertiser>(hci_,
+                                                                     max_advt);
   }
 
   std::unique_ptr<hci::LowEnergyConnector> CreateConnector(bool extended) {
@@ -767,6 +782,68 @@
       metrics_bredr_node_, "open_l2cap_channel_requests");
 }
 
+void AdapterImpl::ParseLEGetVendorCapabilitiesCommandComplete(
+    const hci::EmbossEventPacket& event) {
+  // NOTE: There can be various versions of this command complete event
+  // sent by the Controller. As fields are added, the version_supported
+  // field is incremented to signify which fields are available. In a previous
+  // undertaking (pwrev.dev/203950, fxrev.dev/1029396), we attempted to use
+  // Emboss' conditional fields feature to define fields based on the version
+  // they are included in. However, in practice, we've found vendors sometimes
+  // send the wrong number of bytes required for the version they claim to send.
+  // To tolerate these types of errors, we simply define all the fields in
+  // Emboss. If we receive a response smaller than what we expect, we use what
+  // the vendor sends, and fill the rest with zero to disable the feature. If we
+  // receive a response larger than what we expect, we read up to what we
+  // support and drop the rest of the data.
+  StaticPacket<android_hci::LEGetVendorCapabilitiesCommandCompleteEventView>
+      packet;
+  packet.SetToZeros();
+  size_t copy_size = std::min(packet.data().size(), event.size());
+  packet.mutable_data().Write(event.data().data(), copy_size);
+
+  auto params = packet.view();
+  state_.android_vendor_capabilities = AndroidVendorCapabilities::New(params);
+
+  size_t expected_size = 0;
+  uint8_t major = params.version_supported().major_number().Read();
+  uint8_t minor = params.version_supported().minor_number().Read();
+
+  if (major == 0 && minor == 0) {
+    // The version_supported field was only introduced into the command in
+    // Version 0.95. Controllers that use the base version, Version 0.55,
+    // don't have the version_supported field.
+    expected_size = android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+        version_0_55_size();
+  } else if (major == 0 && minor == 95) {
+    expected_size = android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+        version_0_95_size();
+  } else if (major == 0 && minor == 96) {
+    expected_size = android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+        version_0_96_size();
+  } else if (major == 0 && minor == 98) {
+    expected_size = android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+        version_0_98_size();
+  } else if (major == 1 && minor == 03) {
+    expected_size = android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+        version_1_03_size();
+  } else if (major == 1 && minor == 04) {
+    expected_size = android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+        version_1_04_size();
+  }
+
+  if (event.size() != expected_size) {
+    bt_log(WARN,
+           "gap",
+           "LE Get Vendor Capabilities Command Complete, received %zu bytes, "
+           "expected %zu bytes, version: %d.%d",
+           event.size(),
+           expected_size,
+           major,
+           minor);
+  }
+}
+
 void AdapterImpl::InitializeStep1() {
   state_.controller_features = hci_->GetFeatures();
 
@@ -842,8 +919,8 @@
            "controller supports android hci extensions, querying exact feature "
            "set");
     init_seq_runner_->QueueCommand(
-        hci::EmbossCommandPacket::New<pw::bluetooth::vendor::android_hci::
-                                          LEGetVendorCapabilitiesCommandView>(
+        hci::EmbossCommandPacket::New<
+            android_hci::LEGetVendorCapabilitiesCommandView>(
             hci_android::kLEGetVendorCapabilities),
         [this](const hci::EmbossEventPacket& event) {
           if (hci_is_error(
@@ -854,10 +931,7 @@
             return;
           }
 
-          auto params =
-              event.view<pw::bluetooth::vendor::android_hci::
-                             LEGetVendorCapabilitiesCommandCompleteEventView>();
-          state_.android_vendor_capabilities.Initialize(params);
+          ParseLEGetVendorCapabilitiesCommandComplete(event);
         });
   }
 
diff --git a/src/connectivity/bluetooth/core/bt-host/gap/adapter_test.cc b/src/connectivity/bluetooth/core/bt-host/gap/adapter_test.cc
index b11c771..cad3c99 100644
--- a/src/connectivity/bluetooth/core/bt-host/gap/adapter_test.cc
+++ b/src/connectivity/bluetooth/core/bt-host/gap/adapter_test.cc
@@ -22,6 +22,7 @@
 namespace {
 
 using namespace inspect::testing;
+namespace hci_android = hci_spec::vendor::android;
 using testing::FakeController;
 using testing::FakePeer;
 using TestingBase = testing::FakeDispatcherControllerTest<FakeController>;
@@ -184,7 +185,7 @@
   InitializeAdapter(std::move(init_cb));
   EXPECT_TRUE(success);
   EXPECT_EQ(1, init_cb_count);
-  EXPECT_TRUE(adapter()->state().android_vendor_capabilities.IsInitialized());
+  EXPECT_TRUE(adapter()->state().android_vendor_capabilities.has_value());
 }
 
 TEST_F(AdapterTest,
@@ -210,7 +211,7 @@
   InitializeAdapter(std::move(init_cb));
   EXPECT_FALSE(success);
   EXPECT_EQ(1, init_cb_count);
-  EXPECT_FALSE(adapter()->state().android_vendor_capabilities.IsInitialized());
+  EXPECT_FALSE(adapter()->state().android_vendor_capabilities.has_value());
 }
 
 TEST_F(AdapterTest, InitializeSuccess) {
diff --git a/src/connectivity/bluetooth/core/bt-host/gap/android_vendor_capabilities.cc b/src/connectivity/bluetooth/core/bt-host/gap/android_vendor_capabilities.cc
index 253ca3e..31ed2a59 100644
--- a/src/connectivity/bluetooth/core/bt-host/gap/android_vendor_capabilities.cc
+++ b/src/connectivity/bluetooth/core/bt-host/gap/android_vendor_capabilities.cc
@@ -5,47 +5,115 @@
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/android_vendor_capabilities.h"
 
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/log.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
 
 namespace bt::gap {
 
-void AndroidVendorCapabilities::Initialize(
-    const pw::bluetooth::vendor::android_hci::
-        LEGetVendorCapabilitiesCommandCompleteEventView& c) {
-  initialized_ = false;
+namespace android_hci = pw::bluetooth::vendor::android_hci;
 
-  if (c.status().Read() != pw::bluetooth::emboss::StatusCode::SUCCESS) {
+namespace {
+bool AsBool(const android_hci::Capability& capability) {
+  return capability == android_hci::Capability::CAPABLE;
+}
+}  // namespace
+
+bool AndroidVendorCapabilities::SupportsVersion(uint8_t major,
+                                                uint8_t minor) const {
+  if (version_major_ > major) {
+    return true;
+  }
+
+  if (version_major_ == major && version_minor_ >= minor) {
+    return true;
+  }
+
+  return false;
+}
+
+AndroidVendorCapabilities AndroidVendorCapabilities::New(
+    const android_hci::LEGetVendorCapabilitiesCommandCompleteEventView& e) {
+  AndroidVendorCapabilities c;
+
+  if (e.status().Read() != pw::bluetooth::emboss::StatusCode::SUCCESS) {
     bt_log(INFO,
            "android_vendor_extensions",
            "refusing to parse non-success vendor capabilities");
-    return;
+    return c;
   }
 
-  max_simultaneous_advertisement_ = c.max_advt_instances().Read();
-  supports_offloaded_rpa_ =
-      static_cast<bool>(c.offloaded_resolution_of_private_address().Read());
-  scan_results_storage_bytes_ = c.total_scan_results_storage().Read();
-  irk_list_size_ = c.max_irk_list_sz().Read();
-  supports_filtering_ = static_cast<bool>(c.filtering_support().Read());
-  max_filters_ = c.max_filter().Read();
-  supports_activity_energy_info_ =
-      static_cast<bool>(c.activity_energy_info_support().Read());
-  version_minor_ = c.version_supported().minor_number().Read();
-  version_major_ = c.version_supported().major_number().Read();
-  max_advertisers_tracked_ = c.total_num_of_advt_tracked().Read();
-  supports_extended_scan_ = static_cast<bool>(c.extended_scan_support().Read());
-  supports_debug_logging_ =
-      static_cast<bool>(c.debug_logging_supported().Read());
-  supports_offloading_le_address_generation_ =
-      static_cast<bool>(c.le_address_generation_offloading_support().Read());
-  a2dp_source_offload_capability_mask_ =
-      c.a2dp_source_offload_capability_mask().BackingStorage().ReadUInt();
-  supports_bluetooth_quality_report_ =
-      static_cast<bool>(c.bluetooth_quality_report_support().Read());
-  supports_dynamic_audio_buffer_ =
-      c.dynamic_audio_buffer_support().BackingStorage().ReadUInt();
+  // Version 0.55
+  c.max_simultaneous_advertisement_ = e.max_advt_instances().Read();
+  c.supports_offloaded_rpa_ =
+      AsBool(e.offloaded_resolution_of_private_address().Read());
+  c.scan_results_storage_bytes_ = e.total_scan_results_storage().Read();
+  c.irk_list_size_ = e.max_irk_list_sz().Read();
+  c.supports_filtering_ = AsBool(e.filtering_support().Read());
+  c.max_filters_ = e.max_filter().Read();
+  c.supports_activity_energy_info_ =
+      AsBool(e.activity_energy_info_support().Read());
 
-  initialized_ = true;
+  // There can be various versions of this command complete event sent by the
+  // Controller. As fields are added, the version_supported field is incremented
+  // to signify which fields are available. However, version_supported was only
+  // introduced into the command in Version 0.95. Controllers that use the base
+  // version, Version 0.55, don't have the version_supported field. As such, we
+  // must jump through some hoops to figure out which version we received,
+  // exactly.
+  //
+  // NOTE: Android's definition for this command complete event is available in
+  // AOSP: LeGetVendorCapabilitiesComplete and friends
+  // https://cs.android.com/android/platform/superproject/+/main:packages/modules/Bluetooth/system/gd/hci/hci_packets.pdl
+  //
+  // NOTE: An example implementation of how this command is filled in by a
+  // Controller is available within AOSP:
+  // le_get_vendor_capabilities_handler(...)
+  // https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/Bluetooth/system/gd/hci/controller.cc
+  if (e.version_supported().major_number().IsComplete()) {
+    c.version_major_ = e.version_supported().major_number().Read();
+  }
+
+  if (e.version_supported().minor_number().IsComplete()) {
+    c.version_minor_ = e.version_supported().minor_number().Read();
+  }
+
+  // If we didn't receive a version number from the Controller, assume it's the
+  // base version, Version 0.55.
+  if (c.version_major_ == 0 && c.version_minor_ == 0) {
+    c.version_minor_ = 55;
+  }
+
+  // Version 0.95
+  if (c.SupportsVersion(0, 95)) {
+    c.max_advertisers_tracked_ = e.total_num_of_advt_tracked().Read();
+    c.supports_extended_scan_ = AsBool(e.extended_scan_support().Read());
+    c.supports_debug_logging_ = AsBool(e.debug_logging_supported().Read());
+  }
+
+  // Version 0.96
+  if (c.SupportsVersion(0, 96)) {
+    c.supports_offloading_le_address_generation_ =
+        AsBool(e.le_address_generation_offloading_support().Read());
+  }
+
+  // Version 0.98
+  if (c.SupportsVersion(0, 98)) {
+    c.a2dp_source_offload_capability_mask_ =
+        e.a2dp_source_offload_capability_mask().BackingStorage().ReadUInt();
+    c.supports_bluetooth_quality_report_ =
+        AsBool(e.bluetooth_quality_report_support().Read());
+  }
+
+  // Version 1.03
+  if (c.SupportsVersion(1, 03)) {
+    c.supports_dynamic_audio_buffer_ =
+        e.dynamic_audio_buffer_support().BackingStorage().ReadUInt();
+  }
+
+  // Version 1.04
+  if (c.SupportsVersion(1, 04)) {
+    c.a2dp_offload_v2_support_ = AsBool(e.a2dp_offload_v2_support().Read());
+  }
+
+  return c;
 }
 
 }  // namespace bt::gap
diff --git a/src/connectivity/bluetooth/core/bt-host/gap/android_vendor_capabilities_test.cc b/src/connectivity/bluetooth/core/bt-host/gap/android_vendor_capabilities_test.cc
index 1f8f873..7021adc 100644
--- a/src/connectivity/bluetooth/core/bt-host/gap/android_vendor_capabilities_test.cc
+++ b/src/connectivity/bluetooth/core/bt-host/gap/android_vendor_capabilities_test.cc
@@ -6,98 +6,382 @@
 
 #include <gtest/gtest.h>
 
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_control_packets.h"
 
 namespace bt::gap {
 namespace {
 
-class AndroidVendorCapabilitiesTest : public ::testing::Test {
- public:
-  void SetUp() override {
-    bt::StaticPacket<pw::bluetooth::vendor::android_hci::
-                         LEGetVendorCapabilitiesCommandCompleteEventWriter>
-        params;
-    params.SetToZeros();
-    params.view().status().Write(pw::bluetooth::emboss::StatusCode::SUCCESS);
+namespace android_hci = pw::bluetooth::vendor::android_hci;
+namespace pwemb = pw::bluetooth::emboss;
 
-    // select values other than the zero value to ensure the results of
-    // std::memset don't propagate
-    params.view().max_advt_instances().Write(1);
-    params.view().offloaded_resolution_of_private_address().Write(
-        pw::bluetooth::vendor::android_hci::Capability::CAPABLE);
-    params.view().total_scan_results_storage().Write(2);
-    params.view().max_irk_list_sz().Write(3);
-    params.view().filtering_support().Write(
-        pw::bluetooth::vendor::android_hci::Capability::CAPABLE);
-    params.view().max_filter().Write(4);
-    params.view().activity_energy_info_support().Write(
-        pw::bluetooth::vendor::android_hci::Capability::CAPABLE);
-    params.view().version_supported().major_number().Write(5);
-    params.view().version_supported().minor_number().Write(6);
-    params.view().total_num_of_advt_tracked().Write(7);
-    params.view().extended_scan_support().Write(
-        pw::bluetooth::vendor::android_hci::Capability::CAPABLE);
-    params.view().debug_logging_supported().Write(
-        pw::bluetooth::vendor::android_hci::Capability::CAPABLE);
-    params.view().le_address_generation_offloading_support().Write(
-        pw::bluetooth::vendor::android_hci::Capability::CAPABLE);
-    params.view()
-        .a2dp_source_offload_capability_mask()
-        .BackingStorage()
-        .WriteUInt(8);
-    params.view().bluetooth_quality_report_support().Write(
-        pw::bluetooth::vendor::android_hci::Capability::CAPABLE);
-    params.view().dynamic_audio_buffer_support().sbc().Write(true);
-    params.view().dynamic_audio_buffer_support().aptx_hd().Write(true);
+using android_hci::Capability;
 
-    vendor_capabilities_.Initialize(params.view());
-  }
+TEST(AndroidVendorCapabilitiesTest, NonSuccess) {
+  auto params = hci::EmbossEventPacket::New<
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>(
+      hci_spec::kCommandCompleteEventCode,
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+          version_0_55_size());
 
- protected:
-  AndroidVendorCapabilities& vendor_capabilities() {
-    return vendor_capabilities_;
-  }
+  auto view = params.unchecked_view_t();
+  view.status().Write(pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
 
- private:
-  AndroidVendorCapabilities vendor_capabilities_;
-};
+  view.max_advt_instances().Write(1);
+  view.offloaded_resolution_of_private_address().Write(Capability::CAPABLE);
+  view.total_scan_results_storage().Write(2);
+  view.max_irk_list_sz().Write(3);
+  view.filtering_support().Write(Capability::CAPABLE);
+  view.max_filter().Write(4);
+  view.activity_energy_info_support().Write(Capability::CAPABLE);
 
-TEST_F(AndroidVendorCapabilitiesTest, CorrectExtraction) {
-  EXPECT_TRUE(vendor_capabilities().IsInitialized());
-
-  EXPECT_EQ(1u, vendor_capabilities().max_simultaneous_advertisements());
-  EXPECT_EQ(true, vendor_capabilities().supports_offloaded_rpa());
-  EXPECT_EQ(2u, vendor_capabilities().scan_results_storage_bytes());
-  EXPECT_EQ(3u, vendor_capabilities().irk_list_size());
-  EXPECT_EQ(true, vendor_capabilities().supports_filtering());
-  EXPECT_EQ(4u, vendor_capabilities().max_filters());
-  EXPECT_EQ(true, vendor_capabilities().supports_activity_energy_info());
-  EXPECT_EQ(5u, vendor_capabilities().version_major());
-  EXPECT_EQ(6u, vendor_capabilities().version_minor());
-  EXPECT_EQ(7u, vendor_capabilities().max_advertisers_tracked());
-  EXPECT_EQ(true, vendor_capabilities().supports_extended_scan());
-  EXPECT_EQ(true, vendor_capabilities().supports_debug_logging());
-  EXPECT_EQ(true,
-            vendor_capabilities().supports_offloading_le_address_generation());
-  EXPECT_EQ(8u, vendor_capabilities().a2dp_source_offload_capability_mask());
-  EXPECT_EQ(true, vendor_capabilities().supports_bluetooth_quality_report());
-  EXPECT_EQ(9u, vendor_capabilities().supports_dynamic_audio_buffer());
+  AndroidVendorCapabilities capabilities = AndroidVendorCapabilities::New(view);
+  EXPECT_EQ(0u, capabilities.max_simultaneous_advertisements());
+  EXPECT_EQ(false, capabilities.supports_offloaded_rpa());
+  EXPECT_EQ(0u, capabilities.scan_results_storage_bytes());
+  EXPECT_EQ(0u, capabilities.irk_list_size());
+  EXPECT_EQ(false, capabilities.supports_filtering());
+  EXPECT_EQ(0u, capabilities.max_filters());
+  EXPECT_EQ(false, capabilities.supports_activity_energy_info());
+  EXPECT_EQ(0u, capabilities.version_major());
+  EXPECT_EQ(0u, capabilities.version_minor());
+  EXPECT_EQ(0u, capabilities.max_advertisers_tracked());
+  EXPECT_EQ(false, capabilities.supports_extended_scan());
+  EXPECT_EQ(false, capabilities.supports_debug_logging());
+  EXPECT_EQ(false, capabilities.supports_offloading_le_address_generation());
+  EXPECT_EQ(0u, capabilities.a2dp_source_offload_capability_mask());
+  EXPECT_EQ(false, capabilities.supports_bluetooth_quality_report());
+  EXPECT_EQ(0u, capabilities.supports_dynamic_audio_buffer());
+  EXPECT_EQ(false, capabilities.supports_a2dp_offload_v2());
 }
 
-TEST_F(AndroidVendorCapabilitiesTest, InitializeFailure) {
-  EXPECT_TRUE(vendor_capabilities().IsInitialized());
+TEST(AndroidVendorCapabilitiesTest, Version055) {
+  auto params = hci::EmbossEventPacket::New<
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>(
+      hci_spec::kCommandCompleteEventCode,
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+          version_0_55_size());
 
-  bt::StaticPacket<pw::bluetooth::vendor::android_hci::
-                       LEGetVendorCapabilitiesCommandCompleteEventWriter>
-      params;
-  params.SetToZeros();
-  params.view().status().Write(
-      pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
-  vendor_capabilities().Initialize(params.view());
+  auto view = params.unchecked_view_t();
+  view.status().Write(pwemb::StatusCode::SUCCESS);
 
-  EXPECT_FALSE(vendor_capabilities().IsInitialized());
+  view.max_advt_instances().Write(1);
+  view.offloaded_resolution_of_private_address().Write(Capability::CAPABLE);
+  view.total_scan_results_storage().Write(2);
+  view.max_irk_list_sz().Write(3);
+  view.filtering_support().Write(Capability::CAPABLE);
+  view.max_filter().Write(4);
+  view.activity_energy_info_support().Write(Capability::CAPABLE);
+
+  AndroidVendorCapabilities capabilities = AndroidVendorCapabilities::New(view);
+  EXPECT_EQ(1u, capabilities.max_simultaneous_advertisements());
+  EXPECT_EQ(true, capabilities.supports_offloaded_rpa());
+  EXPECT_EQ(2u, capabilities.scan_results_storage_bytes());
+  EXPECT_EQ(3u, capabilities.irk_list_size());
+  EXPECT_EQ(true, capabilities.supports_filtering());
+  EXPECT_EQ(4u, capabilities.max_filters());
+  EXPECT_EQ(true, capabilities.supports_activity_energy_info());
+  EXPECT_EQ(0u, capabilities.version_major());
+  EXPECT_EQ(55u, capabilities.version_minor());
+  EXPECT_EQ(0u, capabilities.max_advertisers_tracked());
+  EXPECT_EQ(false, capabilities.supports_extended_scan());
+  EXPECT_EQ(false, capabilities.supports_debug_logging());
+  EXPECT_EQ(false, capabilities.supports_offloading_le_address_generation());
+  EXPECT_EQ(0u, capabilities.a2dp_source_offload_capability_mask());
+  EXPECT_EQ(false, capabilities.supports_bluetooth_quality_report());
+  EXPECT_EQ(0u, capabilities.supports_dynamic_audio_buffer());
+  EXPECT_EQ(false, capabilities.supports_a2dp_offload_v2());
+}
+
+TEST(AndroidVendorCapabilitiesTest, Version095) {
+  auto params = hci::EmbossEventPacket::New<
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>(
+      hci_spec::kCommandCompleteEventCode,
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+          version_0_95_size());
+
+  auto view = params.unchecked_view_t();
+  view.status().Write(pwemb::StatusCode::SUCCESS);
+
+  view.max_advt_instances().Write(1);
+  view.offloaded_resolution_of_private_address().Write(Capability::CAPABLE);
+  view.total_scan_results_storage().Write(2);
+  view.max_irk_list_sz().Write(3);
+  view.filtering_support().Write(Capability::CAPABLE);
+  view.max_filter().Write(4);
+  view.activity_energy_info_support().Write(Capability::CAPABLE);
+  view.version_supported().major_number().Write(0);
+  view.version_supported().minor_number().Write(95);
+
+  ASSERT_TRUE(view.has_total_num_of_advt_tracked().ValueOr(false));
+  view.total_num_of_advt_tracked().UncheckedWrite(5u);
+
+  ASSERT_TRUE(view.has_extended_scan_support().ValueOr(false));
+  view.extended_scan_support().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_debug_logging_supported().ValueOr(false));
+  view.debug_logging_supported().UncheckedWrite(Capability::CAPABLE);
+
+  AndroidVendorCapabilities capabilities = AndroidVendorCapabilities::New(view);
+  EXPECT_EQ(1u, capabilities.max_simultaneous_advertisements());
+  EXPECT_EQ(true, capabilities.supports_offloaded_rpa());
+  EXPECT_EQ(2u, capabilities.scan_results_storage_bytes());
+  EXPECT_EQ(3u, capabilities.irk_list_size());
+  EXPECT_EQ(true, capabilities.supports_filtering());
+  EXPECT_EQ(4u, capabilities.max_filters());
+  EXPECT_EQ(true, capabilities.supports_activity_energy_info());
+  EXPECT_EQ(0u, capabilities.version_major());
+  EXPECT_EQ(95u, capabilities.version_minor());
+  EXPECT_EQ(5u, capabilities.max_advertisers_tracked());
+  EXPECT_EQ(true, capabilities.supports_extended_scan());
+  EXPECT_EQ(true, capabilities.supports_debug_logging());
+  EXPECT_EQ(false, capabilities.supports_offloading_le_address_generation());
+  EXPECT_EQ(0u, capabilities.a2dp_source_offload_capability_mask());
+  EXPECT_EQ(false, capabilities.supports_bluetooth_quality_report());
+  EXPECT_EQ(0u, capabilities.supports_dynamic_audio_buffer());
+  EXPECT_EQ(false, capabilities.supports_a2dp_offload_v2());
+}
+
+TEST(AndroidVendorCapabilitiesTest, Version096) {
+  auto params = hci::EmbossEventPacket::New<
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>(
+      hci_spec::kCommandCompleteEventCode,
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+          version_0_96_size());
+
+  auto view = params.unchecked_view_t();
+  view.status().Write(pwemb::StatusCode::SUCCESS);
+
+  view.max_advt_instances().Write(1);
+  view.offloaded_resolution_of_private_address().Write(Capability::CAPABLE);
+  view.total_scan_results_storage().Write(2);
+  view.max_irk_list_sz().Write(3);
+  view.filtering_support().Write(Capability::CAPABLE);
+  view.max_filter().Write(4);
+  view.activity_energy_info_support().Write(Capability::CAPABLE);
+  view.version_supported().major_number().Write(0);
+  view.version_supported().minor_number().Write(96);
+
+  ASSERT_TRUE(view.has_total_num_of_advt_tracked().ValueOr(false));
+  view.total_num_of_advt_tracked().UncheckedWrite(5u);
+
+  ASSERT_TRUE(view.has_extended_scan_support().ValueOr(false));
+  view.extended_scan_support().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_debug_logging_supported().ValueOr(false));
+  view.debug_logging_supported().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(
+      view.has_le_address_generation_offloading_support().ValueOr(false));
+  view.le_address_generation_offloading_support().Write(Capability::CAPABLE);
+
+  AndroidVendorCapabilities capabilities = AndroidVendorCapabilities::New(view);
+  EXPECT_EQ(1u, capabilities.max_simultaneous_advertisements());
+  EXPECT_EQ(true, capabilities.supports_offloaded_rpa());
+  EXPECT_EQ(2u, capabilities.scan_results_storage_bytes());
+  EXPECT_EQ(3u, capabilities.irk_list_size());
+  EXPECT_EQ(true, capabilities.supports_filtering());
+  EXPECT_EQ(4u, capabilities.max_filters());
+  EXPECT_EQ(true, capabilities.supports_activity_energy_info());
+  EXPECT_EQ(0u, capabilities.version_major());
+  EXPECT_EQ(96u, capabilities.version_minor());
+  EXPECT_EQ(5u, capabilities.max_advertisers_tracked());
+  EXPECT_EQ(true, capabilities.supports_extended_scan());
+  EXPECT_EQ(true, capabilities.supports_debug_logging());
+  EXPECT_EQ(true, capabilities.supports_offloading_le_address_generation());
+  EXPECT_EQ(0u, capabilities.a2dp_source_offload_capability_mask());
+  EXPECT_EQ(false, capabilities.supports_bluetooth_quality_report());
+  EXPECT_EQ(0u, capabilities.supports_dynamic_audio_buffer());
+  EXPECT_EQ(false, capabilities.supports_a2dp_offload_v2());
+}
+
+TEST(AndroidVendorCapabilitiesTest, Version098) {
+  auto params = hci::EmbossEventPacket::New<
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>(
+      hci_spec::kCommandCompleteEventCode,
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+          version_0_98_size());
+
+  auto view = params.unchecked_view_t();
+  view.status().Write(pwemb::StatusCode::SUCCESS);
+
+  view.max_advt_instances().Write(1);
+  view.offloaded_resolution_of_private_address().Write(Capability::CAPABLE);
+  view.total_scan_results_storage().Write(2);
+  view.max_irk_list_sz().Write(3);
+  view.filtering_support().Write(Capability::CAPABLE);
+  view.max_filter().Write(4);
+  view.activity_energy_info_support().Write(Capability::CAPABLE);
+  view.version_supported().major_number().Write(0);
+  view.version_supported().minor_number().Write(98);
+
+  ASSERT_TRUE(view.has_total_num_of_advt_tracked().ValueOr(false));
+  view.total_num_of_advt_tracked().UncheckedWrite(5u);
+
+  ASSERT_TRUE(view.has_extended_scan_support().ValueOr(false));
+  view.extended_scan_support().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_debug_logging_supported().ValueOr(false));
+  view.debug_logging_supported().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(
+      view.has_le_address_generation_offloading_support().ValueOr(false));
+  view.le_address_generation_offloading_support().Write(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_a2dp_source_offload_capability_mask().ValueOr(false));
+  view.a2dp_source_offload_capability_mask().BackingStorage().WriteUInt(6);
+
+  ASSERT_TRUE(view.has_bluetooth_quality_report_support().ValueOr(false));
+  view.bluetooth_quality_report_support().Write(Capability::CAPABLE);
+
+  AndroidVendorCapabilities capabilities = AndroidVendorCapabilities::New(view);
+  EXPECT_EQ(1u, capabilities.max_simultaneous_advertisements());
+  EXPECT_EQ(true, capabilities.supports_offloaded_rpa());
+  EXPECT_EQ(2u, capabilities.scan_results_storage_bytes());
+  EXPECT_EQ(3u, capabilities.irk_list_size());
+  EXPECT_EQ(true, capabilities.supports_filtering());
+  EXPECT_EQ(4u, capabilities.max_filters());
+  EXPECT_EQ(true, capabilities.supports_activity_energy_info());
+  EXPECT_EQ(0u, capabilities.version_major());
+  EXPECT_EQ(98u, capabilities.version_minor());
+  EXPECT_EQ(5u, capabilities.max_advertisers_tracked());
+  EXPECT_EQ(true, capabilities.supports_extended_scan());
+  EXPECT_EQ(true, capabilities.supports_debug_logging());
+  EXPECT_EQ(true, capabilities.supports_offloading_le_address_generation());
+  EXPECT_EQ(6u, capabilities.a2dp_source_offload_capability_mask());
+  EXPECT_EQ(true, capabilities.supports_bluetooth_quality_report());
+  EXPECT_EQ(0u, capabilities.supports_dynamic_audio_buffer());
+  EXPECT_EQ(false, capabilities.supports_a2dp_offload_v2());
+}
+
+TEST(AndroidVendorCapabilitiesTest, Version103) {
+  auto params = hci::EmbossEventPacket::New<
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>(
+      hci_spec::kCommandCompleteEventCode,
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+          version_1_03_size());
+
+  auto view = params.unchecked_view_t();
+  view.status().Write(pwemb::StatusCode::SUCCESS);
+
+  view.max_advt_instances().Write(1);
+  view.offloaded_resolution_of_private_address().Write(Capability::CAPABLE);
+  view.total_scan_results_storage().Write(2);
+  view.max_irk_list_sz().Write(3);
+  view.filtering_support().Write(Capability::CAPABLE);
+  view.max_filter().Write(4);
+  view.activity_energy_info_support().Write(Capability::CAPABLE);
+  view.version_supported().major_number().Write(1);
+  view.version_supported().minor_number().Write(03);
+
+  ASSERT_TRUE(view.has_total_num_of_advt_tracked().ValueOr(false));
+  view.total_num_of_advt_tracked().UncheckedWrite(5u);
+
+  ASSERT_TRUE(view.has_extended_scan_support().ValueOr(false));
+  view.extended_scan_support().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_debug_logging_supported().ValueOr(false));
+  view.debug_logging_supported().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(
+      view.has_le_address_generation_offloading_support().ValueOr(false));
+  view.le_address_generation_offloading_support().Write(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_a2dp_source_offload_capability_mask().ValueOr(false));
+  view.a2dp_source_offload_capability_mask().BackingStorage().WriteUInt(6);
+
+  ASSERT_TRUE(view.has_bluetooth_quality_report_support().ValueOr(false));
+  view.bluetooth_quality_report_support().Write(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_dynamic_audio_buffer_support().ValueOr(false));
+  view.dynamic_audio_buffer_support().sbc().Write(true);
+  view.dynamic_audio_buffer_support().aac().Write(true);
+  view.dynamic_audio_buffer_support().aptx().Write(true);
+
+  AndroidVendorCapabilities capabilities = AndroidVendorCapabilities::New(view);
+  EXPECT_EQ(1u, capabilities.max_simultaneous_advertisements());
+  EXPECT_EQ(true, capabilities.supports_offloaded_rpa());
+  EXPECT_EQ(2u, capabilities.scan_results_storage_bytes());
+  EXPECT_EQ(3u, capabilities.irk_list_size());
+  EXPECT_EQ(true, capabilities.supports_filtering());
+  EXPECT_EQ(4u, capabilities.max_filters());
+  EXPECT_EQ(true, capabilities.supports_activity_energy_info());
+  EXPECT_EQ(1u, capabilities.version_major());
+  EXPECT_EQ(03u, capabilities.version_minor());
+  EXPECT_EQ(5u, capabilities.max_advertisers_tracked());
+  EXPECT_EQ(true, capabilities.supports_extended_scan());
+  EXPECT_EQ(true, capabilities.supports_debug_logging());
+  EXPECT_EQ(true, capabilities.supports_offloading_le_address_generation());
+  EXPECT_EQ(6u, capabilities.a2dp_source_offload_capability_mask());
+  EXPECT_EQ(true, capabilities.supports_bluetooth_quality_report());
+  EXPECT_EQ(7u, capabilities.supports_dynamic_audio_buffer());
+  EXPECT_EQ(false, capabilities.supports_a2dp_offload_v2());
+}
+
+TEST(AndroidVendorCapabilitiesTest, Version104) {
+  auto params = hci::EmbossEventPacket::New<
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>(
+      hci_spec::kCommandCompleteEventCode,
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEvent::
+          version_1_04_size());
+
+  auto view = params.unchecked_view_t();
+  view.status().Write(pwemb::StatusCode::SUCCESS);
+
+  view.max_advt_instances().Write(1);
+  view.offloaded_resolution_of_private_address().Write(Capability::CAPABLE);
+  view.total_scan_results_storage().Write(2);
+  view.max_irk_list_sz().Write(3);
+  view.filtering_support().Write(Capability::CAPABLE);
+  view.max_filter().Write(4);
+  view.activity_energy_info_support().Write(Capability::CAPABLE);
+  view.version_supported().major_number().Write(1);
+  view.version_supported().minor_number().Write(04);
+
+  ASSERT_TRUE(view.has_total_num_of_advt_tracked().ValueOr(false));
+  view.total_num_of_advt_tracked().UncheckedWrite(5u);
+
+  ASSERT_TRUE(view.has_extended_scan_support().ValueOr(false));
+  view.extended_scan_support().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_debug_logging_supported().ValueOr(false));
+  view.debug_logging_supported().UncheckedWrite(Capability::CAPABLE);
+
+  ASSERT_TRUE(
+      view.has_le_address_generation_offloading_support().ValueOr(false));
+  view.le_address_generation_offloading_support().Write(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_a2dp_source_offload_capability_mask().ValueOr(false));
+  view.a2dp_source_offload_capability_mask().BackingStorage().WriteUInt(6);
+
+  ASSERT_TRUE(view.has_bluetooth_quality_report_support().ValueOr(false));
+  view.bluetooth_quality_report_support().Write(Capability::CAPABLE);
+
+  ASSERT_TRUE(view.has_dynamic_audio_buffer_support().ValueOr(false));
+  view.dynamic_audio_buffer_support().sbc().Write(true);
+  view.dynamic_audio_buffer_support().aac().Write(true);
+  view.dynamic_audio_buffer_support().aptx().Write(true);
+
+  ASSERT_TRUE(view.has_a2dp_offload_v2_support().ValueOr(false));
+  view.a2dp_offload_v2_support().Write(Capability::CAPABLE);
+
+  AndroidVendorCapabilities capabilities = AndroidVendorCapabilities::New(view);
+  EXPECT_EQ(1u, capabilities.max_simultaneous_advertisements());
+  EXPECT_EQ(true, capabilities.supports_offloaded_rpa());
+  EXPECT_EQ(2u, capabilities.scan_results_storage_bytes());
+  EXPECT_EQ(3u, capabilities.irk_list_size());
+  EXPECT_EQ(true, capabilities.supports_filtering());
+  EXPECT_EQ(4u, capabilities.max_filters());
+  EXPECT_EQ(true, capabilities.supports_activity_energy_info());
+  EXPECT_EQ(1u, capabilities.version_major());
+  EXPECT_EQ(04u, capabilities.version_minor());
+  EXPECT_EQ(5u, capabilities.max_advertisers_tracked());
+  EXPECT_EQ(true, capabilities.supports_extended_scan());
+  EXPECT_EQ(true, capabilities.supports_debug_logging());
+  EXPECT_EQ(true, capabilities.supports_offloading_le_address_generation());
+  EXPECT_EQ(6u, capabilities.a2dp_source_offload_capability_mask());
+  EXPECT_EQ(true, capabilities.supports_bluetooth_quality_report());
+  EXPECT_EQ(7u, capabilities.supports_dynamic_audio_buffer());
+  EXPECT_EQ(true, capabilities.supports_a2dp_offload_v2());
 }
 
 }  // namespace
diff --git a/src/connectivity/bluetooth/core/bt-host/hci/connection.cc b/src/connectivity/bluetooth/core/bt-host/hci/connection.cc
index d0374c1..dd93634 100644
--- a/src/connectivity/bluetooth/core/bt-host/hci/connection.cc
+++ b/src/connectivity/bluetooth/core/bt-host/hci/connection.cc
@@ -6,6 +6,8 @@
 
 #include <endian.h>
 
+#include <utility>
+
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/log.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/defaults.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
@@ -23,13 +25,13 @@
 Connection::Connection(hci_spec::ConnectionHandle handle,
                        const DeviceAddress& local_address,
                        const DeviceAddress& peer_address,
-                       const Transport::WeakPtr& hci,
+                       Transport::WeakPtr hci,
                        fit::callback<void()> on_disconnection_complete)
     : handle_(handle),
       local_address_(local_address),
       peer_address_(peer_address),
       conn_state_(State::kConnected),
-      hci_(hci),
+      hci_(std::move(hci)),
       weak_self_(this) {
   BT_ASSERT(hci_.is_alive());
 
diff --git a/src/connectivity/bluetooth/core/bt-host/hci/extended_low_energy_scanner.cc b/src/connectivity/bluetooth/core/bt-host/hci/extended_low_energy_scanner.cc
index 48ec86d..db6da19 100644
--- a/src/connectivity/bluetooth/core/bt-host/hci/extended_low_energy_scanner.cc
+++ b/src/connectivity/bluetooth/core/bt-host/hci/extended_low_energy_scanner.cc
@@ -229,7 +229,7 @@
     LowEnergyScanResult result;
     std::unique_ptr<PendingScanResult> pending = RemovePendingResult(address);
     if (pending) {
-      result = std::move(pending->result());
+      result = pending->result();
     } else {
       result = LowEnergyScanResult(address, resolved, is_connectable);
     }
diff --git a/src/connectivity/bluetooth/core/bt-host/hci/low_energy_scanner.cc b/src/connectivity/bluetooth/core/bt-host/hci/low_energy_scanner.cc
index a6dc703..939e050 100644
--- a/src/connectivity/bluetooth/core/bt-host/hci/low_energy_scanner.cc
+++ b/src/connectivity/bluetooth/core/bt-host/hci/low_energy_scanner.cc
@@ -59,7 +59,7 @@
     pw::async::Dispatcher& dispatcher,
     pw::chrono::SystemClock::duration timeout,
     fit::closure timeout_handler)
-    : result_(std::move(result)), timeout_(timeout), timeout_task_(dispatcher) {
+    : result_(result), timeout_(timeout), timeout_task_(dispatcher) {
   timeout_task_.set_function(
       [timeout_handler = std::move(timeout_handler)](pw::async::Context /*ctx*/,
                                                      pw::Status status) {
diff --git a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/adapter_state.h b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/adapter_state.h
index 53af4fe..6fdf758 100644
--- a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/adapter_state.h
+++ b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/adapter_state.h
@@ -103,7 +103,7 @@
   // Android vendor extensions capabilities
   // NOTE: callers should separately check that the controller actually supports
   // android vendor extensions first.
-  AndroidVendorCapabilities android_vendor_capabilities;
+  std::optional<AndroidVendorCapabilities> android_vendor_capabilities;
 
   // Local name
   std::string local_name;
diff --git a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/android_vendor_capabilities.h b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/android_vendor_capabilities.h
index 92c7e1e..98dcc09 100644
--- a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/android_vendor_capabilities.h
+++ b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/gap/android_vendor_capabilities.h
@@ -9,13 +9,11 @@
 
 namespace bt::gap {
 
-namespace hci_android = hci_spec::vendor::android;
-
 class AndroidVendorCapabilities final {
  public:
-  void Initialize(const pw::bluetooth::vendor::android_hci::
-                      LEGetVendorCapabilitiesCommandCompleteEventView& c);
-  bool IsInitialized() const { return initialized_; }
+  static AndroidVendorCapabilities New(
+      const pw::bluetooth::vendor::android_hci::
+          LEGetVendorCapabilitiesCommandCompleteEventView& c);
 
   // Number of advertisement instances supported.
   //
@@ -94,8 +92,16 @@
     return supports_dynamic_audio_buffer_;
   }
 
+  // Supports A2DP offloading with version 2 commands
+  bool supports_a2dp_offload_v2() const { return a2dp_offload_v2_support_; }
+
  private:
-  bool initialized_ = false;
+  AndroidVendorCapabilities() = default;
+
+  // Determines if the currently configured version is less than or equal to the
+  // given version's major and minor.
+  bool SupportsVersion(uint8_t major, uint8_t minor) const;
+
   uint8_t max_simultaneous_advertisement_ = 0;
   bool supports_offloaded_rpa_ = false;
   uint16_t scan_results_storage_bytes_ = 0;
@@ -103,8 +109,8 @@
   bool supports_filtering_ = false;
   uint8_t max_filters_ = 0;
   bool supports_activity_energy_info_ = false;
-  uint8_t version_minor_ = 0;
   uint8_t version_major_ = 0;
+  uint8_t version_minor_ = 0;
   uint16_t max_advertisers_tracked_ = 0;
   bool supports_extended_scan_ = false;
   bool supports_debug_logging_ = false;
@@ -112,6 +118,7 @@
   uint32_t a2dp_source_offload_capability_mask_ = 0;
   bool supports_bluetooth_quality_report_ = false;
   uint32_t supports_dynamic_audio_buffer_ = 0;
+  bool a2dp_offload_v2_support_ = false;
 };
 }  // namespace bt::gap
 
diff --git a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/connection.h b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/connection.h
index 944f431..1b28b16 100644
--- a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/connection.h
+++ b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/connection.h
@@ -86,7 +86,7 @@
   Connection(hci_spec::ConnectionHandle handle,
              const DeviceAddress& local_address,
              const DeviceAddress& peer_address,
-             const Transport::WeakPtr& hci,
+             Transport::WeakPtr hci,
              fit::callback<void()> on_disconnection_complete);
 
   const Transport::WeakPtr& hci() { return hci_; }
diff --git a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/extended_low_energy_scanner.h b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/extended_low_energy_scanner.h
index 0ffbe15..0465b1f 100644
--- a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/extended_low_energy_scanner.h
+++ b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/extended_low_energy_scanner.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_PUBLIC_PW_BLUETOOTH_SAPPHIRE_INTERNAL_HOST_HCI_EXTENDED_LOW_ENERGY_SCANNER_H
-#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_PUBLIC_PW_BLUETOOTH_SAPPHIRE_INTERNAL_HOST_HCI_EXTENDED_LOW_ENERGY_SCANNER_H
+#ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_PUBLIC_PW_BLUETOOTH_SAPPHIRE_INTERNAL_HOST_HCI_EXTENDED_LOW_ENERGY_SCANNER_H_
+#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_PUBLIC_PW_BLUETOOTH_SAPPHIRE_INTERNAL_HOST_HCI_EXTENDED_LOW_ENERGY_SCANNER_H_
 
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/low_energy_scanner.h"
 namespace bt::hci {
@@ -48,7 +48,7 @@
 
   // Parse out all the advertising reports that came in an HCI LE Extended
   // Advertising Report.
-  std::vector<pw::bluetooth::emboss::LEExtendedAdvertisingReportDataView>
+  static std::vector<pw::bluetooth::emboss::LEExtendedAdvertisingReportDataView>
   ParseAdvertisingReports(const EmbossEventPacket& event);
 
   // Event handler for HCI LE Extended Advertising Report event.
@@ -62,4 +62,4 @@
 
 }  // namespace bt::hci
 
-#endif
+#endif  // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_PUBLIC_PW_BLUETOOTH_SAPPHIRE_INTERNAL_HOST_HCI_EXTENDED_LOW_ENERGY_SCANNER_H_
diff --git a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/low_energy_connector.h b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/low_energy_connector.h
index bd3c2f7..ef916ba 100644
--- a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/low_energy_connector.h
+++ b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/low_energy_connector.h
@@ -145,7 +145,7 @@
     StatusCallback status_callback;
   };
 
-  EmbossCommandPacket BuildExtendedCreateConnectionPacket(
+  static EmbossCommandPacket BuildExtendedCreateConnectionPacket(
       const DeviceAddress& local_address,
       const DeviceAddress& peer_address,
       const hci_spec::LEPreferredConnectionParameters& initial_params,
@@ -153,7 +153,7 @@
       uint16_t scan_interval,
       uint16_t scan_window);
 
-  EmbossCommandPacket BuildCreateConnectionPacket(
+  static EmbossCommandPacket BuildCreateConnectionPacket(
       const DeviceAddress& local_address,
       const DeviceAddress& peer_address,
       const hci_spec::LEPreferredConnectionParameters& initial_params,
diff --git a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h
index f523e56..8eeb62ae 100644
--- a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h
+++ b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/loop_fixture.h
@@ -15,6 +15,7 @@
  public:
   async_dispatcher_t* dispatcher() { return loop_.dispatcher(); }
   void RunLoopUntilIdle() { loop_.RunUntilIdle(); }
+  void RunLoopFor(zx::duration duration) { loop_.RunFor(duration); }
 
  private:
   async::TestLoop loop_;
diff --git a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_control_packets.h b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_control_packets.h
index a18ccd7..c8a18ea 100644
--- a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_control_packets.h
+++ b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_control_packets.h
@@ -155,6 +155,11 @@
     return view<ViewT>(args...);
   }
 
+  template <typename... Args>
+  ViewT unchecked_view_t(Args... args) {
+    return unchecked_view<ViewT>(args...);
+  }
+
  private:
   friend class EmbossEventPacket;
 
diff --git a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_packet.h b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_packet.h
index a68e523..6dbca2f 100644
--- a/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_packet.h
+++ b/src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/emboss_packet.h
@@ -129,6 +129,11 @@
   }
 
   template <typename T, typename... Args>
+  T unchecked_view(Args... args) {
+    return T(args..., buffer_.mutable_data(), size());
+  }
+
+  template <typename T, typename... Args>
   T unchecked_view(Args... args) const {
     return T(args..., buffer_.data(), size());
   }
diff --git a/src/connectivity/bluetooth/core/bt-host/testing/fake_controller.cc b/src/connectivity/bluetooth/core/bt-host/testing/fake_controller.cc
index 7bc31b5..79e7573 100644
--- a/src/connectivity/bluetooth/core/bt-host/testing/fake_controller.cc
+++ b/src/connectivity/bluetooth/core/bt-host/testing/fake_controller.cc
@@ -199,12 +199,13 @@
 void FakeController::Settings::ApplyAndroidVendorExtensionDefaults() {
   // Settings for the android vendor extensions component within the Fake
   // Controller. These settings correspond to the vendor capabilities returned
-  // by the controller. See
-  // src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h
-  // and LEGetVendorCapabilities for more information.
-  android_extension_settings.view().status().Write(pwemb::StatusCode::SUCCESS);
-  android_extension_settings.view().max_advt_instances().Write(3);
-  android_extension_settings.view().total_scan_results_storage().Write(1024);
+  // by the controller. See hci_vendor.emb LEGetVendorCapabilities for more
+  // information.
+  auto view = android_extension_settings.view();
+  view.status().Write(pwemb::StatusCode::SUCCESS);
+  view.max_advt_instances().Write(3);
+  view.version_supported().major_number().Write(0);
+  view.version_supported().minor_number().Write(55);
 }
 
 bool FakeController::Settings::is_event_unmasked(
@@ -3247,8 +3248,18 @@
 }
 
 void FakeController::OnAndroidLEGetVendorCapabilities() {
-  RespondWithCommandComplete(hci_android::kLEGetVendorCapabilities,
-                             settings_.android_extension_settings.data());
+  // We use the android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter
+  // as storage. This is the full HCI packet, including the header. Ensure we
+  // don't accidentally send the header twice by using the overloaded
+  // RespondWithCommandComplete that takes in an EmbossEventPacket. The one that
+  // takes a BufferView allocates space for the header, assuming that it's been
+  // sent only the payload.
+  auto packet = hci::EmbossEventPacket::New<
+      android_hci::LEGetVendorCapabilitiesCommandCompleteEventWriter>(
+      hci_android::kLEGetVendorCapabilities);
+  MutableBufferView buffer = packet.mutable_data();
+  settings_.android_extension_settings.data().Copy(&buffer);
+  RespondWithCommandComplete(hci_android::kLEGetVendorCapabilities, &packet);
 }
 
 void FakeController::OnAndroidStartA2dpOffload(
diff --git a/src/connectivity/bluetooth/examples/BUILD.gn b/src/connectivity/bluetooth/examples/BUILD.gn
index ffdce69..4686eb1 100644
--- a/src/connectivity/bluetooth/examples/BUILD.gn
+++ b/src/connectivity/bluetooth/examples/BUILD.gn
@@ -25,5 +25,9 @@
 group("tests") {
   testonly = true
 
-  deps = [ "bt-le-battery-monitor:tests" ]
+  deps = [
+    "bt-device-id-client:tests",
+    "bt-fastpair-client:tests",
+    "bt-le-battery-monitor:tests",
+  ]
 }
diff --git a/src/connectivity/bluetooth/examples/bt-device-id-client/BUILD.gn b/src/connectivity/bluetooth/examples/bt-device-id-client/BUILD.gn
index 46ce9bf..2f91fb5 100644
--- a/src/connectivity/bluetooth/examples/bt-device-id-client/BUILD.gn
+++ b/src/connectivity/bluetooth/examples/bt-device-id-client/BUILD.gn
@@ -8,6 +8,7 @@
 rustc_binary("bin") {
   edition = "2021"
   output_name = "bt_device_id_client"
+  with_unit_tests = true
 
   deps = [
     "//sdk/fidl/fuchsia.bluetooth.deviceid:fuchsia.bluetooth.deviceid_rust",
@@ -19,6 +20,12 @@
     "//third_party/rust_crates:tracing",
   ]
 
+  test_deps = [
+    "//src/connectivity/bluetooth/lib/async-helpers:async-test-helpers",
+    "//src/lib/async-utils",
+    "//src/lib/fuchsia-async",
+  ]
+
   sources = [ "src/main.rs" ]
 
   configs -= [ "//build/config/rust/lints:allow_unused_results" ]
@@ -33,3 +40,12 @@
 fuchsia_package("bt-device-id-client") {
   deps = [ ":component" ]
 }
+
+fuchsia_unittest_package("bt-device-id-client-tests") {
+  deps = [ ":bin_test" ]
+}
+
+group("tests") {
+  testonly = true
+  deps = [ ":bt-device-id-client-tests" ]
+}
diff --git a/src/connectivity/bluetooth/examples/bt-device-id-client/src/main.rs b/src/connectivity/bluetooth/examples/bt-device-id-client/src/main.rs
index e89ca65..61800f9 100644
--- a/src/connectivity/bluetooth/examples/bt-device-id-client/src/main.rs
+++ b/src/connectivity/bluetooth/examples/bt-device-id-client/src/main.rs
@@ -51,3 +51,45 @@
     info!("Example DI client exiting...");
     Ok(())
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use async_test_helpers::expect_stream_item;
+    use async_utils::PollExt;
+    use fuchsia_async as fasync;
+    use futures::pin_mut;
+
+    #[test]
+    fn lifetime_of_device_id_request() {
+        let mut exec = fasync::TestExecutor::new();
+
+        let (di_client, mut di_server) =
+            fidl::endpoints::create_proxy_and_stream::<di::DeviceIdentificationMarker>().unwrap();
+        let (fut, _token) = set_device_identification(di_client).expect("can set DI record");
+        pin_mut!(fut);
+        exec.run_until_stalled(&mut fut).expect_pending("waiting for response");
+
+        // Expect the DI server to receive the request.
+        let (_token, responder) = match expect_stream_item(&mut exec, &mut di_server) {
+            Ok(di::DeviceIdentificationRequest::SetDeviceIdentification {
+                records,
+                token,
+                responder,
+            }) => {
+                assert_eq!(records.len(), 1);
+                (token, responder)
+            }
+            x => panic!("Expected DI request, got: {x:?}"),
+        };
+
+        // A response for the request is only expected when the DI advertisement terminates, so we
+        // expect the `fut` to remain active.
+        exec.run_until_stalled(&mut fut).expect_pending("waiting for response");
+
+        // Server terminates the advertisement by responding.
+        let _ = responder.send(Ok(()));
+        let () = exec.run_until_stalled(&mut fut).expect("DI response received");
+    }
+}
diff --git a/src/connectivity/bluetooth/examples/bt-fastpair-client/BUILD.gn b/src/connectivity/bluetooth/examples/bt-fastpair-client/BUILD.gn
index 034805b..80778b3 100644
--- a/src/connectivity/bluetooth/examples/bt-fastpair-client/BUILD.gn
+++ b/src/connectivity/bluetooth/examples/bt-fastpair-client/BUILD.gn
@@ -9,10 +9,12 @@
 rustc_binary("bin") {
   edition = "2021"
   output_name = "bt_fastpair_client"
+  with_unit_tests = true
 
   deps = [
     "//sdk/fidl/fuchsia.bluetooth.fastpair:fuchsia.bluetooth.fastpair_rust",
     "//sdk/fidl/fuchsia.bluetooth.sys:fuchsia.bluetooth.sys_rust",
+    "//src/connectivity/bluetooth/lib/fuchsia-bluetooth",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia",
     "//src/lib/fuchsia-component",
@@ -20,6 +22,14 @@
     "//third_party/rust_crates:futures",
     "//third_party/rust_crates:tracing",
   ]
+
+  test_deps = [
+    "//sdk/fidl/fuchsia.bluetooth:fuchsia.bluetooth_rust",
+    "//src/connectivity/bluetooth/lib/async-helpers:async-test-helpers",
+    "//src/lib/async-utils",
+    "//src/lib/fuchsia-async",
+  ]
+
   sources = [ "src/main.rs" ]
 
   configs -= [ "//build/config/rust/lints:allow_unused_results" ]
@@ -39,3 +49,12 @@
 core_shard("core-shard") {
   shard_file = "meta/bt-fastpair-client.core_shard.cml"
 }
+
+fuchsia_unittest_package("bt-fastpair-client-tests") {
+  deps = [ ":bin_test" ]
+}
+
+group("tests") {
+  testonly = true
+  deps = [ ":bt-fastpair-client-tests" ]
+}
diff --git a/src/connectivity/bluetooth/examples/bt-fastpair-client/src/main.rs b/src/connectivity/bluetooth/examples/bt-fastpair-client/src/main.rs
index 918b182..feca49e 100644
--- a/src/connectivity/bluetooth/examples/bt-fastpair-client/src/main.rs
+++ b/src/connectivity/bluetooth/examples/bt-fastpair-client/src/main.rs
@@ -11,6 +11,7 @@
     InputCapability, OutputCapability, PairingDelegateMarker, PairingDelegateRequest,
     PairingDelegateRequestStream, PairingMarker,
 };
+use fuchsia_bluetooth::types::PeerId;
 use fuchsia_component::client::connect_to_protocol;
 use futures::{select, stream::TryStreamExt, FutureExt};
 use std::pin::pin;
@@ -20,7 +21,7 @@
     while let Some(request) = stream.try_next().await? {
         let (id, responder) = request.into_on_pairing_complete().expect("only one method");
         let _ = responder.send();
-        info!(?id, "Successful Fast Pair pairing");
+        info!(id = %PeerId::from(id), "Successful Fast Pair pairing");
     }
     info!("Provider service ended");
     Ok(())
@@ -40,7 +41,7 @@
                 let _ = responder.send(true, displayed_passkey);
             }
             PairingDelegateRequest::OnPairingComplete { id, success, .. } => {
-                info!(?id, "Normal pairing complete (success = {})", success);
+                info!(id = %PeerId::from(id), "Normal pairing complete (success = {})", success);
             }
             _ => {}
         }
@@ -83,3 +84,73 @@
     }
     Ok(())
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use async_test_helpers::run_while;
+    use async_utils::PollExt;
+    use fidl_fuchsia_bluetooth_sys::{PairingMethod, Peer};
+    use fuchsia_async as fasync;
+    use futures::pin_mut;
+
+    #[fuchsia::test]
+    fn process_pairing_requests() {
+        let mut exec = fasync::TestExecutor::new();
+
+        let (pairing_client, pairing_server) =
+            fidl::endpoints::create_proxy_and_stream::<PairingDelegateMarker>().unwrap();
+        let pairing_fut = process_pairing_events(pairing_server);
+        pin_mut!(pairing_fut);
+        exec.run_until_stalled(&mut pairing_fut).expect_pending("server active");
+
+        // Incoming pairing request - expect the server to receive it and reply positively.
+        let passkey = 123456;
+        let mut request_fut = pairing_client.on_pairing_request(
+            &Peer::default(),
+            PairingMethod::PasskeyComparison,
+            passkey,
+        );
+        let (pairing_result, mut pairing_fut) =
+            run_while(&mut exec, &mut pairing_fut, &mut request_fut);
+
+        let (success, returned_passkey) = pairing_result.expect("successful FIDL request");
+        assert!(success);
+        assert_eq!(returned_passkey, passkey);
+
+        // Incoming normal pairing complete event. Should be received, but no work to be done.
+        let id = fidl_fuchsia_bluetooth::PeerId { value: 123 };
+        pairing_client
+            .on_pairing_complete(&id.into(), /* success*/ true)
+            .expect("successful request");
+        exec.run_until_stalled(&mut pairing_fut).expect_pending("server active");
+
+        // Upstream disconnects.
+        drop(pairing_client);
+        let result = exec.run_until_stalled(&mut pairing_fut).expect("stream terminated");
+        assert!(result.is_ok());
+    }
+
+    #[fuchsia::test]
+    fn process_fastpair_events() {
+        let mut exec = fasync::TestExecutor::new();
+
+        let (provider_client, provider_server) =
+            fidl::endpoints::create_proxy_and_stream::<ProviderWatcherMarker>().unwrap();
+        let provider_fut = process_provider_events(provider_server);
+        pin_mut!(provider_fut);
+        exec.run_until_stalled(&mut provider_fut).expect_pending("server active");
+
+        let id = fidl_fuchsia_bluetooth::PeerId { value: 123 };
+        let mut complete_fut = provider_client.on_pairing_complete(&id);
+        let (result, mut provider_fut) = run_while(&mut exec, &mut provider_fut, &mut complete_fut);
+        // Server should handle the request and respond.
+        assert!(result.is_ok());
+
+        // Upstream disconnects.
+        drop(provider_client);
+        let result = exec.run_until_stalled(&mut provider_fut).expect("stream terminated");
+        assert!(result.is_ok());
+    }
+}
diff --git a/src/connectivity/bluetooth/fidl/BUILD.gn b/src/connectivity/bluetooth/fidl/BUILD.gn
index ae27f6f..ae9714be 100644
--- a/src/connectivity/bluetooth/fidl/BUILD.gn
+++ b/src/connectivity/bluetooth/fidl/BUILD.gn
@@ -4,23 +4,6 @@
 
 import("//build/fidl/fidl.gni")
 
-fidl("host") {
-  sdk_category = "internal"
-  name = "fuchsia.bluetooth.host"
-
-  sources = [ "host.fidl" ]
-
-  public_deps = [
-    "//sdk/fidl/fuchsia.bluetooth",
-    "//sdk/fidl/fuchsia.bluetooth.bredr",
-    "//sdk/fidl/fuchsia.bluetooth.gatt",
-    "//sdk/fidl/fuchsia.bluetooth.gatt2",
-    "//sdk/fidl/fuchsia.bluetooth.le",
-    "//sdk/fidl/fuchsia.bluetooth.sys",
-  ]
-  enable_hlcpp = true
-}
-
 fidl("component") {
   name = "fuchsia.bluetooth.component"
 
diff --git a/src/connectivity/bluetooth/fidl/README.md b/src/connectivity/bluetooth/fidl/README.md
index 950b788..9c0ad7c 100644
--- a/src/connectivity/bluetooth/fidl/README.md
+++ b/src/connectivity/bluetooth/fidl/README.md
@@ -4,11 +4,6 @@
 are not published in the SDK. No component outside of the //src/connectivity/bluetooth subtree
 is allowed to access or interact with them without an explicit exception.
 
-## host.fidl
-
-This protocol is used between the core bt-gap component and the bt-host devices that it
-manages.
-
 ## lifecycle.fidl
 
 This protocol allows components to query the state of other components' lifecycles.
diff --git a/src/connectivity/bluetooth/hci/virtual/emulated_peer.cc b/src/connectivity/bluetooth/hci/virtual/emulated_peer.cc
index ed0fdcd..8fb1266 100644
--- a/src/connectivity/bluetooth/hci/virtual/emulated_peer.cc
+++ b/src/connectivity/bluetooth/hci/virtual/emulated_peer.cc
@@ -4,28 +4,28 @@
 
 #include "emulated_peer.h"
 
-#include <fuchsia/bluetooth/test/cpp/fidl.h>
+#include "src/connectivity/bluetooth/core/bt-host/fidl/helpers.h"
 
-namespace fbt = fuchsia::bluetooth;
-namespace ftest = fuchsia::bluetooth::test;
+namespace fbt = fuchsia_bluetooth;
+namespace ftest = fuchsia_bluetooth_test;
 
 namespace bt_hci_virtual {
 namespace {
 
 bt::DeviceAddress::Type LeAddressTypeFromFidl(fbt::AddressType type) {
-  return (type == fbt::AddressType::RANDOM) ? bt::DeviceAddress::Type::kLERandom
-                                            : bt::DeviceAddress::Type::kLEPublic;
+  return (type == fbt::AddressType::kRandom) ? bt::DeviceAddress::Type::kLERandom
+                                             : bt::DeviceAddress::Type::kLEPublic;
 }
 
 bt::DeviceAddress LeAddressFromFidl(const fbt::Address& address) {
-  return bt::DeviceAddress(LeAddressTypeFromFidl(address.type), address.bytes);
+  return bt::DeviceAddress(LeAddressTypeFromFidl(address.type()), address.bytes());
 }
 
 pw::bluetooth::emboss::ConnectionRole ConnectionRoleFromFidl(fbt::ConnectionRole role) {
   switch (role) {
-    case fbt::ConnectionRole::LEADER:
+    case fbt::ConnectionRole::kLeader:
       return pw::bluetooth::emboss::ConnectionRole::CENTRAL;
-    case fbt::ConnectionRole::FOLLOWER:
+    case fbt::ConnectionRole::kFollower:
       [[fallthrough]];
     default:
       break;
@@ -36,28 +36,28 @@
 }  // namespace
 
 // static
-EmulatedPeer::Result EmulatedPeer::NewLowEnergy(
-    ftest::LowEnergyPeerParameters parameters,
-    fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
-    bt::testing::FakeController* fake_controller) {
+EmulatedPeer::Result EmulatedPeer::NewLowEnergy(ftest::LowEnergyPeerParameters parameters,
+                                                fidl::ServerEnd<ftest::Peer> request,
+                                                bt::testing::FakeController* fake_controller,
+                                                async_dispatcher_t* dispatcher) {
   ZX_DEBUG_ASSERT(request);
   ZX_DEBUG_ASSERT(fake_controller);
 
-  if (!parameters.has_address()) {
+  if (!parameters.address().has_value()) {
     bt_log(ERROR, "virtual", "A fake peer address is mandatory!\n");
-    return fpromise::error(ftest::EmulatorPeerError::PARAMETERS_INVALID);
+    return fpromise::error(ftest::EmulatorPeerError::kParametersInvalid);
   }
 
   bt::BufferView adv, scan_response;
-  if (parameters.has_advertisement()) {
-    adv = bt::BufferView(parameters.advertisement().data);
+  if (parameters.advertisement().has_value()) {
+    adv = bt::BufferView(parameters.advertisement()->data());
   }
-  if (parameters.has_scan_response()) {
-    scan_response = bt::BufferView(parameters.scan_response().data);
+  if (parameters.scan_response().has_value()) {
+    scan_response = bt::BufferView(parameters.scan_response()->data());
   }
 
-  auto address = LeAddressFromFidl(parameters.address());
-  bool connectable = parameters.has_connectable() && parameters.connectable();
+  auto address = LeAddressFromFidl(parameters.address().value());
+  bool connectable = parameters.connectable().has_value() && parameters.connectable().value();
   bool scannable = scan_response.size() != 0u;
 
   // TODO(armansito): We should consider splitting bt::testing::FakePeer into separate types for
@@ -72,39 +72,39 @@
   if (!fake_controller->AddPeer(std::move(peer))) {
     bt_log(ERROR, "virtual", "A fake LE peer with given address already exists: %s\n",
            address.ToString().c_str());
-    return fpromise::error(ftest::EmulatorPeerError::ADDRESS_REPEATED);
+    return fpromise::error(ftest::EmulatorPeerError::kAddressRepeated);
   }
 
   return fpromise::ok(std::unique_ptr<EmulatedPeer>(
-      new EmulatedPeer(address, std::move(request), fake_controller)));
+      new EmulatedPeer(address, std::move(request), fake_controller, dispatcher)));
 }
 
 // static
-EmulatedPeer::Result EmulatedPeer::NewBredr(
-    ftest::BredrPeerParameters parameters,
-    fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
-    bt::testing::FakeController* fake_controller) {
+EmulatedPeer::Result EmulatedPeer::NewBredr(ftest::BredrPeerParameters parameters,
+                                            fidl::ServerEnd<ftest::Peer> request,
+                                            bt::testing::FakeController* fake_controller,
+                                            async_dispatcher_t* dispatcher) {
   ZX_DEBUG_ASSERT(request);
   ZX_DEBUG_ASSERT(fake_controller);
 
-  if (!parameters.has_address()) {
+  if (!parameters.address().has_value()) {
     bt_log(ERROR, "virtual", "A fake peer address is mandatory!\n");
-    return fpromise::error(ftest::EmulatorPeerError::PARAMETERS_INVALID);
+    return fpromise::error(ftest::EmulatorPeerError::kParametersInvalid);
   }
 
-  auto address = bt::DeviceAddress(bt::DeviceAddress::Type::kBREDR, parameters.address().bytes);
-  bool connectable = parameters.has_connectable() && parameters.connectable();
+  auto address = bt::DeviceAddress(bt::DeviceAddress::Type::kBREDR, parameters.address()->bytes());
+  bool connectable = parameters.connectable().has_value() && parameters.connectable().value();
 
   // TODO(armansito): We should consider splitting bt::testing::FakePeer into separate types for
   // BR/EDR and LE transport emulation logic.
   auto peer = std::make_unique<bt::testing::FakePeer>(address, fake_controller->pw_dispatcher(),
                                                       connectable, false);
-  if (parameters.has_device_class()) {
-    peer->set_class_of_device(bt::DeviceClass(parameters.device_class().value));
+  if (parameters.device_class().has_value()) {
+    peer->set_class_of_device(bt::DeviceClass(parameters.device_class()->value()));
   }
-  if (parameters.has_service_definition()) {
+  if (parameters.service_definition().has_value()) {
     std::vector<bt::sdp::ServiceRecord> recs;
-    for (const auto& defn : parameters.service_definition()) {
+    for (const auto& defn : parameters.service_definition().value()) {
       auto rec = bthost::fidl_helpers::ServiceDefinitionToServiceRecord(defn);
       if (rec.is_ok()) {
         recs.emplace_back(std::move(rec.value()));
@@ -118,57 +118,76 @@
   if (!fake_controller->AddPeer(std::move(peer))) {
     bt_log(ERROR, "virtual", "A fake BR/EDR peer with given address already exists: %s\n",
            address.ToString().c_str());
-    return fpromise::error(ftest::EmulatorPeerError::ADDRESS_REPEATED);
+    return fpromise::error(ftest::EmulatorPeerError::kAddressRepeated);
   }
 
   return fpromise::ok(std::unique_ptr<EmulatedPeer>(
-      new EmulatedPeer(address, std::move(request), fake_controller)));
+      new EmulatedPeer(address, std::move(request), fake_controller, dispatcher)));
 }
 
-EmulatedPeer::EmulatedPeer(bt::DeviceAddress address, fidl::InterfaceRequest<ftest::Peer> request,
-                           bt::testing::FakeController* fake_controller)
-    : address_(address), fake_controller_(fake_controller), binding_(this, std::move(request)) {
+EmulatedPeer::EmulatedPeer(bt::DeviceAddress address, fidl::ServerEnd<ftest::Peer> request,
+                           bt::testing::FakeController* fake_controller,
+                           async_dispatcher_t* dispatcher)
+    : address_(address),
+      fake_controller_(fake_controller),
+      binding_(dispatcher, std::move(request), this, std::mem_fn(&EmulatedPeer::OnChannelClosed)) {
   ZX_DEBUG_ASSERT(fake_controller_);
-  ZX_DEBUG_ASSERT(binding_.is_bound());
-
-  binding_.set_error_handler(fit::bind_member<&EmulatedPeer::OnChannelClosed>(this));
 }
 
 EmulatedPeer::~EmulatedPeer() { CleanUp(); }
 
-void EmulatedPeer::AssignConnectionStatus(ftest::HciError status,
-                                          AssignConnectionStatusCallback callback) {
+void EmulatedPeer::AssignConnectionStatus(AssignConnectionStatusRequest& request,
+                                          AssignConnectionStatusCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "EmulatedPeer.AssignConnectionStatus\n");
 
   auto peer = fake_controller_->FindPeer(address_);
   if (peer) {
-    peer->set_connect_response(static_cast<pw::bluetooth::emboss::StatusCode>(status));
+    peer->set_connect_response(static_cast<pw::bluetooth::emboss::StatusCode>(request.status()));
   }
 
-  callback();
+  completer.Reply();
 }
 
-void EmulatedPeer::EmulateLeConnectionComplete(fbt::ConnectionRole role) {
+void EmulatedPeer::EmulateLeConnectionComplete(
+    EmulateLeConnectionCompleteRequest& request,
+    EmulateLeConnectionCompleteCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "EmulatedPeer.EmulateLeConnectionComplete\n");
-  fake_controller_->ConnectLowEnergy(address_, ConnectionRoleFromFidl(role));
+  fake_controller_->ConnectLowEnergy(address_, ConnectionRoleFromFidl(request.role()));
 }
 
-void EmulatedPeer::EmulateDisconnectionComplete() {
+void EmulatedPeer::EmulateDisconnectionComplete(
+    EmulateDisconnectionCompleteCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "EmulatedPeer.EmulateDisconnectionComplete\n");
   fake_controller_->Disconnect(address_);
 }
 
-void EmulatedPeer::WatchConnectionStates(WatchConnectionStatesCallback callback) {
+void EmulatedPeer::WatchConnectionStates(WatchConnectionStatesCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "EmulatedPeer.WatchConnectionState\n");
-  connection_state_getter_.Watch(std::move(callback));
+
+  connection_states_completers_.emplace(completer.ToAsync());
+  MaybeUpdateConnectionStates();
 }
 
 void EmulatedPeer::UpdateConnectionState(bool connected) {
-  connection_state_getter_.Add(connected ? ftest::ConnectionState::CONNECTED
-                                         : ftest::ConnectionState::DISCONNECTED);
+  ftest::ConnectionState state =
+      connected ? ftest::ConnectionState::kConnected : ftest::ConnectionState::kDisconnected;
+
+  connection_states_.emplace_back(state);
+  MaybeUpdateConnectionStates();
 }
 
-void EmulatedPeer::OnChannelClosed(zx_status_t status) {
+void EmulatedPeer::MaybeUpdateConnectionStates() {
+  if (connection_states_.empty() || connection_states_completers_.empty()) {
+    return;
+  }
+  while (!connection_states_completers_.empty()) {
+    connection_states_completers_.front().Reply(connection_states_);
+    connection_states_completers_.pop();
+  }
+  connection_states_.clear();
+}
+
+void EmulatedPeer::OnChannelClosed(fidl::UnbindInfo info) {
   bt_log(TRACE, "virtual", "EmulatedPeer channel closed\n");
   NotifyChannelClosed();
 }
diff --git a/src/connectivity/bluetooth/hci/virtual/emulated_peer.h b/src/connectivity/bluetooth/hci/virtual/emulated_peer.h
index ef8a483..cf259ba 100644
--- a/src/connectivity/bluetooth/hci/virtual/emulated_peer.h
+++ b/src/connectivity/bluetooth/hci/virtual/emulated_peer.h
@@ -5,21 +5,15 @@
 #ifndef SRC_CONNECTIVITY_BLUETOOTH_HCI_VIRTUAL_EMULATED_PEER_H_
 #define SRC_CONNECTIVITY_BLUETOOTH_HCI_VIRTUAL_EMULATED_PEER_H_
 
-#include <fuchsia/bluetooth/test/cpp/fidl.h>
-#include <lib/fidl/cpp/binding.h>
-#include <lib/fidl/cpp/interface_request.h>
+#include <fidl/fuchsia.bluetooth.test/cpp/fidl.h>
 #include <lib/fpromise/result.h>
 
-#include <optional>
 #include <vector>
 
 #include <fbl/macros.h>
 
-#include "src/connectivity/bluetooth/core/bt-host/fidl/helpers.h"
-#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/sdp/service_record.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
-#include "src/connectivity/bluetooth/lib/fidl/hanging_getter.h"
 
 namespace bt_hci_virtual {
 
@@ -29,22 +23,24 @@
 // When the remote end of the FIDL channel gets closed the underlying FakePeer will be removed from
 // the fake controller and the |closed_callback| that is passed to the constructor will get
 // notified. The owner of this object should act on this by destroying this Peer instance.
-class EmulatedPeer : public fuchsia::bluetooth::test::Peer {
+class EmulatedPeer : public fidl::Server<fuchsia_bluetooth_test::Peer> {
  public:
   using Result =
-      fpromise::result<std::unique_ptr<EmulatedPeer>, fuchsia::bluetooth::test::EmulatorPeerError>;
+      fpromise::result<std::unique_ptr<EmulatedPeer>, fuchsia_bluetooth_test::EmulatorPeerError>;
 
   // Registers a peer with the FakeController using the provided LE parameters. Returns the peer on
   // success or an error reporting the failure.
-  static Result NewLowEnergy(fuchsia::bluetooth::test::LowEnergyPeerParameters parameters,
-                             fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
-                             bt::testing::FakeController* fake_controller);
+  static Result NewLowEnergy(fuchsia_bluetooth_test::LowEnergyPeerParameters parameters,
+                             fidl::ServerEnd<fuchsia_bluetooth_test::Peer> request,
+                             bt::testing::FakeController* fake_controller,
+                             async_dispatcher_t* dispatcher);
 
   // Registers a peer with the FakeController using the provided BR/EDR parameters. Returns the peer
   // on success or an error reporting the failure.
-  static Result NewBredr(fuchsia::bluetooth::test::BredrPeerParameters parameters,
-                         fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
-                         bt::testing::FakeController* fake_controller);
+  static Result NewBredr(fuchsia_bluetooth_test::BredrPeerParameters parameters,
+                         fidl::ServerEnd<fuchsia_bluetooth_test::Peer> request,
+                         bt::testing::FakeController* fake_controller,
+                         async_dispatcher_t* dispatcher);
 
   // The destructor unregisters the Peer if initialized.
   ~EmulatedPeer();
@@ -58,33 +54,35 @@
     closed_callback_ = std::move(closed_callback);
   }
 
-  // fuchsia::bluetooth::test::Peer overrides:
-  void AssignConnectionStatus(fuchsia::bluetooth::test::HciError status,
-                              AssignConnectionStatusCallback callback) override;
-  void EmulateLeConnectionComplete(fuchsia::bluetooth::ConnectionRole role) override;
-  void EmulateDisconnectionComplete() override;
-  void WatchConnectionStates(WatchConnectionStatesCallback callback) override;
+  // fuchsia_bluetooth_test::Peer overrides:
+  void AssignConnectionStatus(AssignConnectionStatusRequest& request,
+                              AssignConnectionStatusCompleter::Sync& completer) override;
+  void EmulateLeConnectionComplete(EmulateLeConnectionCompleteRequest& request,
+                                   EmulateLeConnectionCompleteCompleter::Sync& completer) override;
+  void EmulateDisconnectionComplete(
+      EmulateDisconnectionCompleteCompleter::Sync& completer) override;
+  void WatchConnectionStates(WatchConnectionStatesCompleter::Sync& completer) override;
 
   // Updates this peer with the current connection state which is used to notify its FIDL client
   // of state changes that it is observing.
   void UpdateConnectionState(bool connected);
+  void MaybeUpdateConnectionStates();
 
  private:
-  EmulatedPeer(bt::DeviceAddress address,
-               fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
-               bt::testing::FakeController* fake_controller);
+  EmulatedPeer(bt::DeviceAddress address, fidl::ServerEnd<fuchsia_bluetooth_test::Peer> request,
+               bt::testing::FakeController* fake_controller, async_dispatcher_t* dispatcher);
 
-  void OnChannelClosed(zx_status_t status);
+  void OnChannelClosed(fidl::UnbindInfo info);
   void CleanUp();
   void NotifyChannelClosed();
 
   bt::DeviceAddress address_;
   bt::testing::FakeController* fake_controller_;
-  fidl::Binding<fuchsia::bluetooth::test::Peer> binding_;
+  fidl::ServerBinding<fuchsia_bluetooth_test::Peer> binding_;
   fit::callback<void()> closed_callback_;
 
-  bt_lib_fidl::HangingVectorGetter<fuchsia::bluetooth::test::ConnectionState>
-      connection_state_getter_;
+  std::vector<fuchsia_bluetooth_test::ConnectionState> connection_states_;
+  std::queue<WatchConnectionStatesCompleter::Async> connection_states_completers_;
 
   DISALLOW_COPY_ASSIGN_AND_MOVE(EmulatedPeer);
 };
diff --git a/src/connectivity/bluetooth/hci/virtual/emulator.cc b/src/connectivity/bluetooth/hci/virtual/emulator.cc
index be7a20b..974ec72 100644
--- a/src/connectivity/bluetooth/hci/virtual/emulator.cc
+++ b/src/connectivity/bluetooth/hci/virtual/emulator.cc
@@ -4,6 +4,7 @@
 
 #include "emulator.h"
 
+#include <fidl/fuchsia.bluetooth.test/cpp/fidl.h>
 #include <fuchsia/hardware/bt/hci/cpp/banjo.h>
 #include <lib/async/cpp/task.h>
 #include <lib/async/default.h>
@@ -12,16 +13,11 @@
 #include <zircon/status.h>
 #include <zircon/types.h>
 
-#include <cstdio>
-#include <future>
-#include <thread>
-
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/random.h"
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
 #include "src/connectivity/bluetooth/hci/vendor/broadcom/packets.h"
 
-namespace fbt = fuchsia::bluetooth;
-namespace ftest = fuchsia::bluetooth::test;
+namespace ftest = fuchsia_bluetooth_test;
 
 using bt::DeviceAddress;
 using bt::testing::FakeController;
@@ -46,44 +42,49 @@
 
 FakeController::Settings SettingsFromFidl(const ftest::EmulatorSettings& input) {
   FakeController::Settings settings;
-  if (input.has_hci_config() && input.hci_config() == ftest::HciConfig::LE_ONLY) {
+  if (input.hci_config().has_value() && input.hci_config().value() == ftest::HciConfig::kLeOnly) {
     settings.ApplyLEOnlyDefaults();
   } else {
     settings.ApplyDualModeDefaults();
   }
 
-  if (input.has_address()) {
-    settings.bd_addr = DeviceAddress(DeviceAddress::Type::kBREDR, input.address().bytes);
+  if (input.address().has_value()) {
+    settings.bd_addr = DeviceAddress(DeviceAddress::Type::kBREDR, input.address()->bytes());
   }
 
   // TODO(armansito): Don't ignore "extended_advertising" setting when
   // supported.
-  if (input.has_acl_buffer_settings()) {
-    settings.acl_data_packet_length = input.acl_buffer_settings().data_packet_length;
-    settings.total_num_acl_data_packets = input.acl_buffer_settings().total_num_data_packets;
+  if (input.acl_buffer_settings().has_value()) {
+    settings.acl_data_packet_length = input.acl_buffer_settings()->data_packet_length();
+    settings.total_num_acl_data_packets = input.acl_buffer_settings()->total_num_data_packets();
   }
 
-  if (input.has_le_acl_buffer_settings()) {
-    settings.le_acl_data_packet_length = input.le_acl_buffer_settings().data_packet_length;
-    settings.le_total_num_acl_data_packets = input.le_acl_buffer_settings().total_num_data_packets;
+  if (input.le_acl_buffer_settings().has_value()) {
+    settings.le_acl_data_packet_length = input.le_acl_buffer_settings()->data_packet_length();
+    settings.le_total_num_acl_data_packets =
+        input.le_acl_buffer_settings()->total_num_data_packets();
   }
 
   return settings;
 }
 
-fuchsia::bluetooth::AddressType LeOwnAddressTypeToFidl(
+std::optional<fuchsia_bluetooth::AddressType> LeOwnAddressTypeToFidl(
     pw::bluetooth::emboss::LEOwnAddressType type) {
+  std::optional<fuchsia_bluetooth::AddressType> res;
+
   switch (type) {
     case pw::bluetooth::emboss::LEOwnAddressType::PUBLIC:
     case pw::bluetooth::emboss::LEOwnAddressType::PRIVATE_DEFAULT_TO_PUBLIC:
-      return fuchsia::bluetooth::AddressType::PUBLIC;
+      res.emplace(fuchsia_bluetooth::AddressType::kPublic);
+      return res;
     case pw::bluetooth::emboss::LEOwnAddressType::RANDOM:
     case pw::bluetooth::emboss::LEOwnAddressType::PRIVATE_DEFAULT_TO_RANDOM:
-      return fuchsia::bluetooth::AddressType::RANDOM;
+      res.emplace(fuchsia_bluetooth::AddressType::kRandom);
+      return res;
   }
 
   ZX_PANIC("unsupported own address type");
-  return fuchsia::bluetooth::AddressType::PUBLIC;
+  return res;
 }
 
 constexpr EmulatorDevice* DEV(void* ctx) { return static_cast<EmulatorDevice*>(ctx); }
@@ -155,8 +156,7 @@
       parent_(device),
       hci_dev_(nullptr),
       emulator_dev_(nullptr),
-      fake_device_(pw_dispatcher_),
-      binding_(this) {}
+      fake_device_(pw_dispatcher_) {}
 
 zx_status_t EmulatorDevice::Bind(std::string_view name) {
   bt_log(TRACE, "virtual", "bind\n");
@@ -196,6 +196,8 @@
   fake_device_.set_connection_state_callback(
       fit::bind_member<&EmulatorDevice::OnPeerConnectionStateChanged>(this));
 
+  bt_log(INFO, "virtual", "Starting new thread");
+
   loop_.StartThread("bt_hci_virtual");
 
   return status;
@@ -208,7 +210,7 @@
   // It is OK to capture a self-reference since this function blocks on the task completion.
   async::PostTask(loop_.dispatcher(), [this, &completion] {
     // Stop servicing HciEmulator FIDL messages from higher layers.
-    binding_.Unbind();
+    bindings_.CloseAll(ZX_OK);
     completion.Signal();
   });
 
@@ -271,7 +273,8 @@
                     [this, in = std::move(in)]() mutable { StartAclChannel(std::move(in)); });
   } else if (chan_type == Channel::EMULATOR) {
     async::PostTask(loop_.dispatcher(), [this, in = std::move(in)]() mutable {
-      StartEmulatorInterface(std::move(in));
+      fidl::ServerEnd<ftest::HciEmulator> server_end(std::move(in));
+      StartEmulatorInterface(std::move(server_end));
     });
   } else if (chan_type == Channel::ISO) {
     async::PostTask(loop_.dispatcher(),
@@ -282,40 +285,38 @@
   return ZX_OK;
 }
 
-void EmulatorDevice::StartEmulatorInterface(zx::channel chan) {
+void EmulatorDevice::StartEmulatorInterface(fidl::ServerEnd<ftest::HciEmulator> request) {
   bt_log(TRACE, "virtual", "start HciEmulator interface\n");
 
-  if (binding_.is_bound()) {
+  if (bindings_.size() > 0) {
     bt_log(TRACE, "virtual", "HciEmulator channel already bound\n");
     return;
   }
 
-  // Process HciEmulator messages on a thread that can safely access the
-  // FakeController, which is thread-hostile.
-  binding_.Bind(std::move(chan), loop_.dispatcher());
-  binding_.set_error_handler([this](zx_status_t status) {
+  // Process HciEmulator messages on a thread that can safely access the FakeController, which is
+  // thread-hostile.
+  auto cb = [this](auto impl, fidl::UnbindInfo info) {
     bt_log(TRACE, "virtual", "emulator channel closed (status: %s); unpublish device\n",
-           zx_status_get_string(status));
+           zx_status_get_string(info.status()));
     UnpublishHci();
-  });
+  };
+  bindings_.AddBinding(loop_.dispatcher(), std::move(request), this, std::move(cb));
 }
 
-void EmulatorDevice::Publish(ftest::EmulatorSettings in_settings, PublishCallback callback) {
+void EmulatorDevice::Publish(PublishRequest& request, PublishCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "HciEmulator.Publish\n");
 
-  ftest::HciEmulator_Publish_Result result;
-  std::lock_guard<std::mutex> lock(hci_dev_lock_);
   // Between Device::Unbind & Device::Release, this->hci_dev_ == nullptr, but this->fake_device_
-  // != nullptr. This seems like it might cause issues for this logic; however, because binding_ is
+  // != nullptr. This seems like it might cause issues for this logic; however, because bindings_ is
   // unbound during Device::Unbind, it is impossible for further messages, including Publish, to be
   // received during this window.
+  std::lock_guard<std::mutex> lock(hci_dev_lock_);
   if (hci_dev_) {
-    result.set_err(ftest::EmulatorError::HCI_ALREADY_PUBLISHED);
-    callback(std::move(result));
+    completer.Reply(fit::error(ftest::EmulatorError::kHciAlreadyPublished));
     return;
   }
 
-  FakeController::Settings settings = SettingsFromFidl(in_settings);
+  FakeController::Settings settings = SettingsFromFidl(request.settings());
   fake_device_.set_settings(settings);
 
   // Publish the bt-hci device.
@@ -328,64 +329,62 @@
   };
   zx_status_t status = device_add(emulator_dev_, &args, &hci_dev_);
   if (status != ZX_OK) {
-    result.set_err(ftest::EmulatorError::FAILED);
+    bt_log(WARN, "virtual", "Failed to publish bt-hci device node");
+    completer.Reply(fit::error(ftest::EmulatorError::kFailed));
   } else {
-    result.set_response(ftest::HciEmulator_Publish_Response{});
+    bt_log(INFO, "virtual", "Successfully published bt-hci device node");
+    completer.Reply(fit::success());
   }
-
-  callback(std::move(result));
 }
 
-void EmulatorDevice::AddLowEnergyPeer(ftest::LowEnergyPeerParameters params,
-                                      fidl::InterfaceRequest<ftest::Peer> request,
-                                      AddLowEnergyPeerCallback callback) {
+void EmulatorDevice::AddLowEnergyPeer(AddLowEnergyPeerRequest& request,
+                                      AddLowEnergyPeerCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "HciEmulator.AddLowEnergyPeer\n");
 
-  ftest::HciEmulator_AddLowEnergyPeer_Result fidl_result;
-
-  auto result = EmulatedPeer::NewLowEnergy(std::move(params), std::move(request), &fake_device_);
+  auto result = EmulatedPeer::NewLowEnergy(request.parameters(), std::move(request.peer()),
+                                           &fake_device_, loop_.dispatcher());
   if (result.is_error()) {
-    fidl_result.set_err(result.error());
-    callback(std::move(fidl_result));
+    completer.Reply(fit::error(result.error()));
     return;
   }
 
   AddPeer(result.take_value());
-  fidl_result.set_response(ftest::HciEmulator_AddLowEnergyPeer_Response{});
-  callback(std::move(fidl_result));
+  completer.Reply(fit::success());
 }
 
-void EmulatorDevice::AddBredrPeer(ftest::BredrPeerParameters params,
-                                  fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
-                                  AddBredrPeerCallback callback) {
+void EmulatorDevice::AddBredrPeer(AddBredrPeerRequest& request,
+                                  AddBredrPeerCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "HciEmulator.AddBredrPeer\n");
 
-  ftest::HciEmulator_AddBredrPeer_Result fidl_result;
-
-  auto result = EmulatedPeer::NewBredr(std::move(params), std::move(request), &fake_device_);
+  auto result = EmulatedPeer::NewBredr(request.parameters(), std::move(request.peer()),
+                                       &fake_device_, loop_.dispatcher());
   if (result.is_error()) {
-    fidl_result.set_err(result.error());
-    callback(std::move(fidl_result));
+    completer.Reply(fit::error(result.error()));
     return;
   }
 
   AddPeer(result.take_value());
-  fidl_result.set_response(ftest::HciEmulator_AddBredrPeer_Response{});
-  callback(std::move(fidl_result));
+  completer.Reply(fit::success());
 }
 
-void EmulatorDevice::WatchControllerParameters(WatchControllerParametersCallback callback) {
+void EmulatorDevice::WatchControllerParameters(
+    WatchControllerParametersCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "HciEmulator.WatchControllerParameters\n");
-  controller_parameters_getter_.Watch(std::move(callback));
+
+  controller_parameters_completer_.emplace(completer.ToAsync());
+  MaybeUpdateControllerParametersChanged();
 }
 
-void EmulatorDevice::WatchLeScanStates(WatchLeScanStatesCallback callback) {
+void EmulatorDevice::WatchLeScanStates(WatchLeScanStatesCompleter::Sync& completer) {
   // TODO(https://fxbug.dev/42162739): Implement
 }
 
-void EmulatorDevice::WatchLegacyAdvertisingStates(WatchLegacyAdvertisingStatesCallback callback) {
+void EmulatorDevice::WatchLegacyAdvertisingStates(
+    WatchLegacyAdvertisingStatesCompleter::Sync& completer) {
   bt_log(TRACE, "virtual", "HciEmulator.WatchLegacyAdvertisingState\n");
-  legacy_adv_state_getter_.Watch(std::move(callback));
+
+  legacy_adv_states_completers_.emplace(completer.ToAsync());
+  MaybeUpdateLegacyAdvertisingStates();
 }
 
 void EmulatorDevice::GetFeatures(GetFeaturesCompleter::Sync& completer) {
@@ -461,16 +460,29 @@
   bt_log(TRACE, "virtual", "HciEmulator.OnControllerParametersChanged\n");
 
   ftest::ControllerParameters fidl_value;
-  fidl_value.set_local_name(fake_device_.local_name());
+  fidl_value.local_name(fake_device_.local_name());
 
   const auto& device_class_bytes = fake_device_.device_class().bytes();
   uint32_t device_class = 0;
   device_class |= device_class_bytes[0];
   device_class |= static_cast<uint32_t>(device_class_bytes[1]) << 8;
   device_class |= static_cast<uint32_t>(device_class_bytes[2]) << 16;
-  fidl_value.set_device_class(fbt::DeviceClass{device_class});
 
-  controller_parameters_getter_.Set(std::move(fidl_value));
+  std::optional<fuchsia_bluetooth::DeviceClass> device_class_option =
+      fuchsia_bluetooth::DeviceClass{device_class};
+  fidl_value.device_class(device_class_option);
+
+  controller_parameters_.emplace(fidl_value);
+  MaybeUpdateControllerParametersChanged();
+}
+
+void EmulatorDevice::MaybeUpdateControllerParametersChanged() {
+  if (!controller_parameters_.has_value() || !controller_parameters_completer_.has_value()) {
+    return;
+  }
+  controller_parameters_completer_->Reply(std::move(controller_parameters_.value()));
+  controller_parameters_.reset();
+  controller_parameters_completer_.reset();
 }
 
 void EmulatorDevice::OnLegacyAdvertisingStateChanged() {
@@ -479,33 +491,45 @@
   // We have requests to resolve. Construct the FIDL table for the current state.
   ftest::LegacyAdvertisingState fidl_state;
   const FakeController::LEAdvertisingState& adv_state = fake_device_.legacy_advertising_state();
-  fidl_state.set_enabled(adv_state.enabled);
+  fidl_state.enabled(adv_state.enabled);
 
   // Populate the rest only if advertising is enabled.
-  fidl_state.set_type(static_cast<ftest::LegacyAdvertisingType>(adv_state.adv_type));
-  fidl_state.set_address_type(LeOwnAddressTypeToFidl(adv_state.own_address_type));
+  fidl_state.type(static_cast<ftest::LegacyAdvertisingType>(adv_state.adv_type));
+  fidl_state.address_type(LeOwnAddressTypeToFidl(adv_state.own_address_type));
 
   if (adv_state.interval_min) {
-    fidl_state.set_interval_min(adv_state.interval_min);
+    fidl_state.interval_min(adv_state.interval_min);
   }
   if (adv_state.interval_max) {
-    fidl_state.set_interval_max(adv_state.interval_max);
+    fidl_state.interval_max(adv_state.interval_max);
   }
 
   if (adv_state.data_length) {
     std::vector<uint8_t> output(adv_state.data_length);
     bt::MutableBufferView output_view(output.data(), output.size());
     output_view.Write(adv_state.data, adv_state.data_length);
-    fidl_state.set_advertising_data(std::move(output));
+    fidl_state.advertising_data(std::move(output));
   }
   if (adv_state.scan_rsp_length) {
     std::vector<uint8_t> output(adv_state.scan_rsp_length);
     bt::MutableBufferView output_view(output.data(), output.size());
     output_view.Write(adv_state.scan_rsp_data, adv_state.scan_rsp_length);
-    fidl_state.set_scan_response(std::move(output));
+    fidl_state.scan_response(std::move(output));
   }
 
-  legacy_adv_state_getter_.Add(std::move(fidl_state));
+  legacy_adv_states_.emplace_back(fidl_state);
+  MaybeUpdateLegacyAdvertisingStates();
+}
+
+void EmulatorDevice::MaybeUpdateLegacyAdvertisingStates() {
+  if (legacy_adv_states_.empty() || legacy_adv_states_completers_.empty()) {
+    return;
+  }
+  while (!legacy_adv_states_completers_.empty()) {
+    legacy_adv_states_completers_.front().Reply(legacy_adv_states_);
+    legacy_adv_states_completers_.pop();
+  }
+  legacy_adv_states_.clear();
 }
 
 void EmulatorDevice::UnpublishHci() {
diff --git a/src/connectivity/bluetooth/hci/virtual/emulator.h b/src/connectivity/bluetooth/hci/virtual/emulator.h
index 9d4d2ce..d1d9578 100644
--- a/src/connectivity/bluetooth/hci/virtual/emulator.h
+++ b/src/connectivity/bluetooth/hci/virtual/emulator.h
@@ -5,7 +5,8 @@
 #ifndef SRC_CONNECTIVITY_BLUETOOTH_HCI_VIRTUAL_EMULATOR_H_
 #define SRC_CONNECTIVITY_BLUETOOTH_HCI_VIRTUAL_EMULATOR_H_
 
-#include <fidl/fuchsia.hardware.bluetooth/cpp/wire.h>
+#include <fidl/fuchsia.bluetooth.test/cpp/fidl.h>
+#include <fidl/fuchsia.hardware.bluetooth/cpp/fidl.h>
 #include <fuchsia/hardware/bt/hci/cpp/banjo.h>
 #include <fuchsia/hardware/test/cpp/banjo.h>
 #include <lib/async-loop/cpp/loop.h>
@@ -26,14 +27,13 @@
 
 #include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
 #include "src/connectivity/bluetooth/hci/virtual/emulated_peer.h"
-#include "src/connectivity/bluetooth/lib/fidl/hanging_getter.h"
 #include "third_party/pigweed/backends/pw_random/zircon_random_generator.h"
 
 namespace bt_hci_virtual {
 
 enum class Channel : uint8_t { ACL, COMMAND, EMULATOR, ISO, SNOOP };
 
-class EmulatorDevice : public fuchsia::bluetooth::test::HciEmulator,
+class EmulatorDevice : public fidl::Server<fuchsia_bluetooth_test::HciEmulator>,
                        public fidl::WireServer<fuchsia_hardware_bluetooth::Hci>,
                        public fidl::WireServer<fuchsia_hardware_bluetooth::Vendor>,
                        public fidl::WireServer<fuchsia_hardware_bluetooth::Emulator> {
@@ -73,20 +73,17 @@
   }
 
  private:
-  void StartEmulatorInterface(zx::channel chan);
+  void StartEmulatorInterface(fidl::ServerEnd<fuchsia_bluetooth_test::HciEmulator> request);
 
-  // fuchsia::bluetooth::test::HciEmulator overrides:
-  void Publish(fuchsia::bluetooth::test::EmulatorSettings settings,
-               PublishCallback callback) override;
-  void AddLowEnergyPeer(fuchsia::bluetooth::test::LowEnergyPeerParameters params,
-                        fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
-                        AddLowEnergyPeerCallback callback) override;
-  void AddBredrPeer(fuchsia::bluetooth::test::BredrPeerParameters params,
-                    fidl::InterfaceRequest<fuchsia::bluetooth::test::Peer> request,
-                    AddBredrPeerCallback callback) override;
-  void WatchControllerParameters(WatchControllerParametersCallback callback) override;
-  void WatchLeScanStates(WatchLeScanStatesCallback callback) override;
-  void WatchLegacyAdvertisingStates(WatchLegacyAdvertisingStatesCallback callback) override;
+  // fuchsia_bluetooth_test::HciEmulator overrides:
+  void Publish(PublishRequest& request, PublishCompleter::Sync& completer) override;
+  void AddLowEnergyPeer(AddLowEnergyPeerRequest& request,
+                        AddLowEnergyPeerCompleter::Sync& completer) override;
+  void AddBredrPeer(AddBredrPeerRequest& request, AddBredrPeerCompleter::Sync& completer) override;
+  void WatchControllerParameters(WatchControllerParametersCompleter::Sync& completer) override;
+  void WatchLeScanStates(WatchLeScanStatesCompleter::Sync& completer) override;
+  void WatchLegacyAdvertisingStates(
+      WatchLegacyAdvertisingStatesCompleter::Sync& completer) override;
 
   // fuchsia_hardware_bluetooth::Vendor overrides:
   void GetFeatures(GetFeaturesCompleter::Sync& completer) override;
@@ -105,7 +102,9 @@
   void AddPeer(std::unique_ptr<EmulatedPeer> peer);
 
   void OnControllerParametersChanged();
+  void MaybeUpdateControllerParametersChanged();
   void OnLegacyAdvertisingStateChanged();
+  void MaybeUpdateLegacyAdvertisingStates();
 
   // Remove the bt-hci device.
   void UnpublishHci();
@@ -174,15 +173,16 @@
 
   // Binding for fuchsia.bluetooth.test.HciEmulator channel. |binding_| is only accessed on
   // |loop_|'s dispatcher.
-  fidl::Binding<fuchsia::bluetooth::test::HciEmulator> binding_;
+  fidl::ServerBindingGroup<fuchsia_bluetooth_test::HciEmulator> bindings_;
 
   // List of active peers that have been registered with us.
   std::unordered_map<bt::DeviceAddress, std::unique_ptr<EmulatedPeer>> peers_;
 
-  bt_lib_fidl::HangingGetter<fuchsia::bluetooth::test::ControllerParameters>
-      controller_parameters_getter_;
-  bt_lib_fidl::HangingVectorGetter<fuchsia::bluetooth::test::LegacyAdvertisingState>
-      legacy_adv_state_getter_;
+  std::optional<fuchsia_bluetooth_test::ControllerParameters> controller_parameters_;
+  std::optional<WatchControllerParametersCompleter::Async> controller_parameters_completer_;
+
+  std::vector<fuchsia_bluetooth_test::LegacyAdvertisingState> legacy_adv_states_;
+  std::queue<WatchLegacyAdvertisingStatesCompleter::Async> legacy_adv_states_completers_;
 
   zx::channel cmd_channel_;
   zx::channel acl_channel_;
diff --git a/src/connectivity/bluetooth/lib/fuchsia-audio-device/BUILD.gn b/src/connectivity/bluetooth/lib/fuchsia-audio-device/BUILD.gn
index 2edef743..6e3a281 100644
--- a/src/connectivity/bluetooth/lib/fuchsia-audio-device/BUILD.gn
+++ b/src/connectivity/bluetooth/lib/fuchsia-audio-device/BUILD.gn
@@ -35,9 +35,10 @@
   sources = [
     "src/audio_frame_sink.rs",
     "src/audio_frame_stream.rs",
-    "src/driver.rs",
+    "src/codec.rs",
     "src/frame_vmo.rs",
     "src/lib.rs",
+    "src/stream_config.rs",
     "src/types.rs",
   ]
 
diff --git a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/audio_frame_sink.rs b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/audio_frame_sink.rs
index c5e96fd..df910fe 100644
--- a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/audio_frame_sink.rs
+++ b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/audio_frame_sink.rs
@@ -13,42 +13,42 @@
 use std::{pin::Pin, sync::Arc};
 use tracing::warn;
 
-use crate::driver::{PcmOrTask, SoftPcm};
 use crate::frame_vmo;
+use crate::stream_config::{SoftStreamConfig, StreamConfigOrTask};
 use crate::types::{Error, Result};
 
 /// A sink that accepts audio frames to send as input to Fuchsia audio
-/// Usually acquired via SoftPcm::create_input()
+/// Usually acquired via SoftStreamConfig::create_input()
 pub struct AudioFrameSink {
     /// Handle to the VMO that is receiving the frames.
     frame_vmo: Arc<Mutex<frame_vmo::FrameVmo>>,
     /// The index of the next frame we are writing.
     next_frame_index: usize,
-    /// SoftPcm this is attached to, or the SoftPcm::process_requests task
-    pcm: PcmOrTask,
+    /// StreamConfig this is attached to, or the SoftStreamConfig::process_requests task
+    stream_config: StreamConfigOrTask,
     /// Inspect node
     inspect: inspect::Node,
 }
 
 impl AudioFrameSink {
-    pub fn new(pcm: SoftPcm) -> AudioFrameSink {
+    pub fn new(stream_config: SoftStreamConfig) -> AudioFrameSink {
         AudioFrameSink {
-            frame_vmo: pcm.frame_vmo(),
+            frame_vmo: stream_config.frame_vmo(),
             next_frame_index: 0,
-            pcm: PcmOrTask::Pcm(pcm),
+            stream_config: StreamConfigOrTask::StreamConfig(stream_config),
             inspect: Default::default(),
         }
     }
 
     /// Start the requests task if not started, and poll the task.
     fn poll_task(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>> {
-        if let PcmOrTask::Complete = &self.pcm {
+        if let StreamConfigOrTask::Complete = &self.stream_config {
             return Poll::Ready(Err(Error::InvalidState));
         }
-        if let PcmOrTask::Task(ref mut task) = &mut self.pcm {
+        if let StreamConfigOrTask::Task(ref mut task) = &mut self.stream_config {
             return task.poll_unpin(cx);
         }
-        self.pcm.start();
+        self.stream_config.start();
         self.poll_task(cx)
     }
 }
@@ -60,8 +60,8 @@
         name: impl AsRef<str>,
     ) -> core::result::Result<(), AttachError> {
         self.inspect = parent.create_child(name.as_ref());
-        if let PcmOrTask::Pcm(ref mut o) = &mut self.pcm {
-            return o.iattach(&self.inspect, "soft_pcm");
+        if let StreamConfigOrTask::StreamConfig(ref mut o) = &mut self.stream_config {
+            return o.iattach(&self.inspect, "soft_stream_config");
         }
         Ok(())
     }
@@ -74,7 +74,7 @@
         buf: &[u8],
     ) -> Poll<std::result::Result<usize, io::Error>> {
         if let Poll::Ready(r) = self.poll_task(cx) {
-            self.pcm = PcmOrTask::Complete;
+            self.stream_config = StreamConfigOrTask::Complete;
             if let Some(error) = r.err() {
                 return Poll::Ready(Err(io::Error::new(io::ErrorKind::Other, error)));
             } else {
@@ -110,7 +110,7 @@
         mut self: Pin<&mut Self>,
         _cx: &mut Context<'_>,
     ) -> Poll<std::result::Result<(), io::Error>> {
-        self.pcm = PcmOrTask::Complete;
+        self.stream_config = StreamConfigOrTask::Complete;
         Poll::Ready(Ok(()))
     }
 }
@@ -141,7 +141,7 @@
             frames_per_second: 44100,
             channel_map: vec![AudioChannelId::Lf, AudioChannelId::Rf],
         };
-        let (client, frame_sink) = SoftPcm::create_input(
+        let (client, frame_sink) = SoftStreamConfig::create_input(
             TEST_UNIQUE_ID,
             "Google",
             "UnitTest",
@@ -156,7 +156,7 @@
     #[fixture(with_audio_frame_sink)]
     #[fuchsia::test]
     #[rustfmt::skip]
-    fn soft_pcm_audio_in(mut exec: fasync::TestExecutor, stream_config: StreamConfigProxy, mut frame_sink: AudioFrameSink) {
+    fn audio_in(mut exec: fasync::TestExecutor, stream_config: StreamConfigProxy, mut frame_sink: AudioFrameSink) {
 
         // Some test "audio" data.  Silence in signed 16-bit, for 10ms
         let mut send_audio = Vec::new();
diff --git a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/audio_frame_stream.rs b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/audio_frame_stream.rs
index 091189c..9f236e8 100644
--- a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/audio_frame_stream.rs
+++ b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/audio_frame_stream.rs
@@ -13,13 +13,13 @@
 use std::{pin::Pin, sync::Arc};
 use tracing::info;
 
-use crate::driver::{PcmOrTask, SoftPcm};
 use crate::frame_vmo;
+use crate::stream_config::{SoftStreamConfig, StreamConfigOrTask};
 use crate::types::{Error, Result};
 
 /// A stream that produces audio frames.
 /// Frames are of constant length.
-/// Usually acquired via SoftPcm::create_output()
+/// Usually acquired via SoftStreamConfig::create_output()
 pub struct AudioFrameStream {
     /// Handle to the VMO that is receiving the frames.
     frame_vmo: Arc<Mutex<frame_vmo::FrameVmo>>,
@@ -30,33 +30,33 @@
     /// Vector that will be filled with a packet.
     /// Replaced when stream produces a packet.
     next_packet: std::cell::RefCell<Vec<u8>>,
-    /// SoftPcm this is attached to, or the SoftPcm::process_requests task
-    pcm: PcmOrTask,
+    /// SoftStreamConfig this is attached to, or the SoftStreamConfig::process_requests task
+    stream_task: StreamConfigOrTask,
     /// Inspect node
     inspect: inspect::Node,
 }
 
 impl AudioFrameStream {
-    pub fn new(pcm: SoftPcm) -> AudioFrameStream {
+    pub fn new(stream: SoftStreamConfig) -> AudioFrameStream {
         AudioFrameStream {
-            frame_vmo: pcm.frame_vmo(),
+            frame_vmo: stream.frame_vmo(),
             next_frame: 0,
-            packet_frames: pcm.packet_frames(),
+            packet_frames: stream.packet_frames(),
             next_packet: Vec::new().into(),
-            pcm: PcmOrTask::Pcm(pcm),
+            stream_task: StreamConfigOrTask::StreamConfig(stream),
             inspect: Default::default(),
         }
     }
 
     /// Start the requests task if not started, and poll the task.
     fn poll_task(&mut self, cx: &mut Context<'_>) -> Poll<Result<()>> {
-        if let PcmOrTask::Complete = &self.pcm {
+        if let StreamConfigOrTask::Complete = &self.stream_task {
             return Poll::Ready(Err(Error::InvalidState));
         }
-        if let PcmOrTask::Task(ref mut task) = &mut self.pcm {
+        if let StreamConfigOrTask::Task(ref mut task) = &mut self.stream_task {
             return task.poll_unpin(cx);
         }
-        self.pcm.start();
+        self.stream_task.start();
         self.poll_task(cx)
     }
 }
@@ -66,7 +66,7 @@
 
     fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
         if let Poll::Ready(r) = self.poll_task(cx) {
-            self.pcm = PcmOrTask::Complete;
+            self.stream_task = StreamConfigOrTask::Complete;
             return Poll::Ready(r.err().map(Result::Err));
         }
         if self.next_packet.borrow().len() == 0 {
@@ -101,8 +101,8 @@
 
 impl FusedStream for AudioFrameStream {
     fn is_terminated(&self) -> bool {
-        match self.pcm {
-            PcmOrTask::Complete => true,
+        match self.stream_task {
+            StreamConfigOrTask::Complete => true,
             _ => false,
         }
     }
@@ -115,8 +115,8 @@
         name: impl AsRef<str>,
     ) -> core::result::Result<(), AttachError> {
         self.inspect = parent.create_child(name.as_ref());
-        if let PcmOrTask::Pcm(ref mut o) = &mut self.pcm {
-            return o.iattach(&self.inspect, "soft_pcm");
+        if let StreamConfigOrTask::StreamConfig(ref mut o) = &mut self.stream_task {
+            return o.iattach(&self.inspect, "stream_config");
         }
         Ok(())
     }
@@ -133,7 +133,7 @@
     use fuchsia_zircon as zx;
     use futures::StreamExt;
 
-    use crate::driver::tests::with_audio_frame_stream;
+    use crate::stream_config::tests::with_audio_frame_stream;
 
     const TEST_UNIQUE_ID: &[u8; 16] = &[5; 16];
     const TEST_CLOCK_DOMAIN: u32 = 0x00010203;
@@ -141,7 +141,7 @@
     #[fixture(with_audio_frame_stream)]
     #[fuchsia::test]
     #[rustfmt::skip]
-    fn soft_pcm_audio_out(mut exec: fasync::TestExecutor, stream_config: StreamConfigProxy, mut frame_stream: AudioFrameStream) {
+    fn soft_audio_out(mut exec: fasync::TestExecutor, stream_config: StreamConfigProxy, mut frame_stream: AudioFrameStream) {
         let mut frame_fut = frame_stream.next();
         // Poll the frame stream, which should start the processing of proxy requests.
         exec.run_until_stalled(&mut frame_fut).expect_pending("no frames yet");
diff --git a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/codec.rs b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/codec.rs
new file mode 100644
index 0000000..ed004e7
--- /dev/null
+++ b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/codec.rs
@@ -0,0 +1,9 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// A software fuchsia audio codec.
+/// Codecs communicate their capabilities to the system and provide control points for components
+/// to start, stop, and configure media capabilities.
+/// See [[Audio Codec Interface]](https://fuchsia.dev/fuchsia-src/concepts/drivers/driver_architectures/audio_drivers/audio_codec
+pub struct SoftCodec {}
diff --git a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/frame_vmo.rs b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/frame_vmo.rs
index b59d522..3b9615a 100644
--- a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/frame_vmo.rs
+++ b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/frame_vmo.rs
@@ -9,7 +9,7 @@
 use futures::FutureExt;
 use tracing::debug;
 
-use crate::driver::frames_from_duration;
+use crate::stream_config::frames_from_duration;
 use crate::types::{AudioSampleFormat, Error, Result};
 
 /// A FrameVmo wraps a VMO with time tracking.  When a FrameVmo is started, it
diff --git a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/lib.rs b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/lib.rs
index fdee1f7..bff04c4 100644
--- a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/lib.rs
+++ b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/lib.rs
@@ -2,6 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+//! Fuchsia Audio Device Library
+//!
+//! Provides a method to create audio devices that are backed by software in Fuchsia.
+//!
+//! SoftStreamConfig creates a StreamConfig client that is suitable for adding to
+//! [[fuchsia.media.AudioDeviceEnumerator]] via AddDeviceByChannel or
+//! [[fuchsia.audio.device.Provider]] via AddDevice. It produces either an
+//! AudioFrameStream (for output audio) or an AudioFrameSink (for input audio)
+//!
+//! SoftCodec creates a Codec client suitable for adding to [[fuchsia.audio.device.Provider]]
+//! via AddCodec.  It provides a CodecDevice to capture and respond to control events from Media,
+//! and shutdown the Codec (retrieving a new Codec client which can be used to re-add the Codec)
+
 #![recursion_limit = "256"]
 
 pub use crate::types::{Error, Result};
@@ -10,18 +23,24 @@
 #[macro_use]
 mod types;
 
-/// Software Audio Driver
-pub mod driver;
+/// Software Stream Config Audio Input/Output
+pub mod stream_config;
 
 /// Audio Frame Stream (output stream)
+/// Produces audio packets as if it was an audio output using a [`stream_config::SoftStreamConfig`]
 pub mod audio_frame_stream;
 
 pub use audio_frame_stream::AudioFrameStream;
 
 /// Audio Frame Sink (input sink)
+/// Acts as a microphone or audio input, accepting audio packets using a
+/// [`stream_config::SoftStreamConfig`]
 pub mod audio_frame_sink;
 
 pub use audio_frame_sink::AudioFrameSink;
 
-/// Frame VMO Helper
+/// Software Codec Audio Input/Output
+pub mod codec;
+
+/// Frame VMO Helper module
 mod frame_vmo;
diff --git a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/driver.rs b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/stream_config.rs
similarity index 95%
rename from src/connectivity/bluetooth/lib/fuchsia-audio-device/src/driver.rs
rename to src/connectivity/bluetooth/lib/fuchsia-audio-device/src/stream_config.rs
index 76149ea..7bd61af 100644
--- a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/driver.rs
+++ b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/stream_config.rs
@@ -20,18 +20,20 @@
 use crate::frame_vmo;
 use crate::types::{AudioSampleFormat, Error, Result};
 
-pub(crate) enum PcmOrTask {
-    Pcm(SoftPcm),
+pub(crate) enum StreamConfigOrTask {
+    StreamConfig(SoftStreamConfig),
     Task(fasync::Task<Result<()>>),
     Complete,
 }
 
-impl PcmOrTask {
+impl StreamConfigOrTask {
     /// Start the task if it's not running.
     /// Does nothing if the task is running or completed.
     pub(crate) fn start(&mut self) {
-        *self = match std::mem::replace(self, PcmOrTask::Complete) {
-            PcmOrTask::Pcm(pcm) => PcmOrTask::Task(fasync::Task::spawn(pcm.process_requests())),
+        *self = match std::mem::replace(self, StreamConfigOrTask::Complete) {
+            StreamConfigOrTask::StreamConfig(st) => {
+                StreamConfigOrTask::Task(fasync::Task::spawn(st.process_requests()))
+            }
             x => x,
         }
     }
@@ -50,7 +52,7 @@
 /// A software fuchsia audio output, which implements Audio Driver Streaming Interface
 /// as defined in //docs/concepts/drivers/driver_interfaces/audio_streaming.md
 #[derive(Inspect)]
-pub struct SoftPcm {
+pub struct SoftStreamConfig {
     /// The Stream channel handles format negotiation, plug detection, and gain
     stream_config_stream: StreamConfigRequestStream,
 
@@ -102,17 +104,17 @@
 
     /// Inspect node
     #[inspect(forward)]
-    inspect: SoftPcmInspect,
+    inspect: SoftStreamConfigInspect,
 }
 
 #[derive(Default, Inspect)]
-struct SoftPcmInspect {
+struct SoftStreamConfigInspect {
     inspect_node: inspect::Node,
     ring_buffer_format: IValue<Option<String>>,
     frame_vmo_status: IValue<Option<String>>,
 }
 
-impl SoftPcmInspect {
+impl SoftStreamConfigInspect {
     fn record_current_format(&mut self, current: &(u32, AudioSampleFormat, u16)) {
         self.ring_buffer_format
             .iset(Some(format!("{} rate: {} channels: {}", current.1, current.0, current.2)));
@@ -123,7 +125,7 @@
     }
 }
 
-impl SoftPcm {
+impl SoftStreamConfig {
     /// Create a new software audio device, returning a client channel which can be supplied
     /// to the AudioCore and will act correctly as an audio output driver channel which can
     /// render audio in the `pcm_format` format, and an AudioFrameStream which produces the
@@ -143,7 +145,7 @@
         packet_duration: zx::Duration,
         initial_external_delay: zx::Duration,
     ) -> Result<(ClientEnd<StreamConfigMarker>, AudioFrameStream)> {
-        let (client, soft_pcm) = SoftPcm::build(
+        let (client, soft_stream_config) = SoftStreamConfig::build(
             unique_id,
             manufacturer,
             product,
@@ -153,7 +155,7 @@
             packet_duration,
             initial_external_delay,
         )?;
-        Ok((client, AudioFrameStream::new(soft_pcm)))
+        Ok((client, AudioFrameStream::new(soft_stream_config)))
     }
 
     pub fn create_input(
@@ -164,7 +166,7 @@
         pcm_format: fidl_fuchsia_media::PcmFormat,
         buffer: zx::Duration,
     ) -> Result<(ClientEnd<StreamConfigMarker>, AudioFrameSink)> {
-        let (client, soft_pcm) = SoftPcm::build(
+        let (client, soft_stream_config) = SoftStreamConfig::build(
             unique_id,
             manufacturer,
             product,
@@ -174,7 +176,7 @@
             buffer,
             zx::Duration::from_nanos(0),
         )?;
-        Ok((client, AudioFrameSink::new(soft_pcm)))
+        Ok((client, AudioFrameSink::new(soft_stream_config)))
     }
 
     fn build(
@@ -186,7 +188,7 @@
         pcm_format: fidl_fuchsia_media::PcmFormat,
         packet_duration: zx::Duration,
         initial_external_delay: zx::Duration,
-    ) -> Result<(ClientEnd<StreamConfigMarker>, SoftPcm)> {
+    ) -> Result<(ClientEnd<StreamConfigMarker>, SoftStreamConfig)> {
         if pcm_format.bits_per_sample % 8 != 0 {
             // Non-byte-aligned format not allowed.
             return Err(Error::InvalidArgs);
@@ -210,7 +212,7 @@
         let packet_frames =
             frames_from_duration(pcm_format.frames_per_second as usize, packet_duration);
 
-        let soft_pcm = SoftPcm {
+        let soft_stream_config = SoftStreamConfig {
             stream_config_stream: request_stream,
             unique_id: unique_id.clone(),
             manufacturer: manufacturer.to_string(),
@@ -229,7 +231,7 @@
             delay_info_replied: false,
             inspect: Default::default(),
         };
-        Ok((client, soft_pcm))
+        Ok((client, soft_stream_config))
     }
 
     pub(crate) fn frame_vmo(&self) -> Arc<Mutex<frame_vmo::FrameVmo>> {
@@ -514,7 +516,7 @@
             frames_per_second: 44100,
             channel_map: vec![AudioChannelId::Lf, AudioChannelId::Rf],
         };
-        let (client, frame_stream) = SoftPcm::create_output(
+        let (client, frame_stream) = SoftStreamConfig::create_output(
             TEST_UNIQUE_ID,
             "Google",
             "UnitTest",
@@ -553,7 +555,7 @@
     }
 
     #[fuchsia::test]
-    fn soft_pcm_audio_should_end_when_stream_dropped() {
+    fn soft_stream_config_audio_should_end_when_stream_dropped() {
         let format = PcmFormat {
             pcm_mode: AudioPcmMode::Linear,
             bits_per_sample: 16,
@@ -562,7 +564,7 @@
         };
 
         let mut exec = fasync::TestExecutor::new_with_fake_time();
-        let (client, frame_stream) = SoftPcm::build(
+        let (client, frame_stream) = SoftStreamConfig::build(
             TEST_UNIQUE_ID,
             &"Google".to_string(),
             &"UnitTest".to_string(),
diff --git a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/types.rs b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/types.rs
index 2a83de3..36f11a3 100644
--- a/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/types.rs
+++ b/src/connectivity/bluetooth/lib/fuchsia-audio-device/src/types.rs
@@ -43,6 +43,10 @@
     #[error("Encountered an error on a RequestStream: {}", _0)]
     RequestStreamError(#[from] fidl::Error),
 
+    /// Peer performed an disallowed action and the server will close
+    #[error("Peer performed an invalid action: {}", _0)]
+    PeerError(String),
+
     /// Action tried in an invalid state
     #[error("Tried to do an action in an invalid state")]
     InvalidState,
@@ -130,7 +134,7 @@
                         AudioSampleFormat::ThirtyTwo { unsigned: is_unsigned, invert_endian: false }
                     }
                     _ => panic!(
-                        "audio valie bits per sample {:?} not supported",
+                        "audio valid bits per sample {:?} not supported",
                         v.valid_bits_per_sample
                     ),
                 },
diff --git a/src/connectivity/bluetooth/profiles/bt-a2dp/src/sources.rs b/src/connectivity/bluetooth/profiles/bt-a2dp/src/sources.rs
index 261f3fd..1ba920a 100644
--- a/src/connectivity/bluetooth/profiles/bt-a2dp/src/sources.rs
+++ b/src/connectivity/bluetooth/profiles/bt-a2dp/src/sources.rs
@@ -6,7 +6,7 @@
 use fidl_fuchsia_bluetooth_bredr as bredr;
 use fidl_fuchsia_media::{AudioDeviceEnumeratorMarker, PcmFormat};
 use fuchsia_async as fasync;
-use fuchsia_audio_device::driver::SoftPcm;
+use fuchsia_audio_device::stream_config::SoftStreamConfig;
 use fuchsia_bluetooth::types::{peer_audio_stream_id, PeerId, Uuid};
 use fuchsia_inspect_derive::Inspect;
 use fuchsia_zircon::{self as zx, DurationNum};
@@ -89,7 +89,7 @@
         external_delay: zx::Duration,
     ) -> Result<fuchsia_audio_device::AudioFrameStream, Error> {
         let id = peer_audio_stream_id(*peer_id, AUDIO_SOURCE_UUID);
-        let (client, frame_stream) = SoftPcm::create_output(
+        let (client, frame_stream) = SoftStreamConfig::create_output(
             &id,
             "Google",
             "Bluetooth A2DP",
diff --git a/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/audio/inband.rs b/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/audio/inband.rs
index 8f30686..0fcda4e 100644
--- a/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/audio/inband.rs
+++ b/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/audio/inband.rs
@@ -7,15 +7,17 @@
 use fidl_fuchsia_media as media;
 use fuchsia_async as fasync;
 use fuchsia_audio_codec::{StreamProcessor, StreamProcessorOutputStream};
-use fuchsia_audio_device::{driver::SoftPcm, AudioFrameSink, AudioFrameStream};
-use fuchsia_bluetooth::types::{peer_audio_stream_id, Uuid};
+use fuchsia_audio_device::{stream_config::SoftStreamConfig, AudioFrameSink, AudioFrameStream};
+use fuchsia_bluetooth::types::{peer_audio_stream_id, PeerId, Uuid};
 use fuchsia_zircon as zx;
 use futures::{task::Context, AsyncWriteExt, FutureExt, StreamExt};
 use media::AudioDeviceEnumeratorProxy;
 use std::pin::pin;
 use tracing::{error, info, warn};
 
-use super::*;
+use crate::audio::{AudioControl, AudioError};
+use crate::sco_connector::ScoConnection;
+use crate::CodecId;
 
 /// AudioControl for inband audio, i.e. encoding and decoding audio before sending them
 /// to the controller via HCI (in contrast to offloaded audio).
@@ -267,7 +269,7 @@
         codec_id: CodecId,
     ) -> Result<AudioFrameSink, AudioError> {
         let audio_dev_id = peer_audio_stream_id(peer_id, Self::HF_INPUT_UUID);
-        let (client, sink) = SoftPcm::create_input(
+        let (client, sink) = SoftStreamConfig::create_input(
             &audio_dev_id,
             "Fuchsia",
             "Bluetooth HFP",
@@ -287,7 +289,7 @@
         codec_id: CodecId,
     ) -> Result<AudioFrameStream, AudioError> {
         let audio_dev_id = peer_audio_stream_id(peer_id, Self::HF_OUTPUT_UUID);
-        let (client, stream) = SoftPcm::create_output(
+        let (client, stream) = SoftStreamConfig::create_output(
             &audio_dev_id,
             "Fuchsia",
             "Bluetooth HFP",
diff --git a/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/hfp.rs b/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/hfp.rs
index 8b6e899..3f73fbf 100644
--- a/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/hfp.rs
+++ b/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/hfp.rs
@@ -208,7 +208,7 @@
                 })
                 .is_some()
             {
-                info!(?id, "Search returned AudioGateway, skipping");
+                info!(%id, "Search returned AudioGateway, skipping");
                 return Ok(());
             }
         }
diff --git a/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/peer.rs b/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/peer.rs
index ff510d5..116c296 100644
--- a/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/peer.rs
+++ b/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/peer.rs
@@ -377,12 +377,8 @@
         let id = PeerId(1);
         let mut peer = make_peer(id).0;
 
-        // Stop the inner task and wait until it has fully stopped
-        // The inner task is replaced by a no-op task so that it can be consumed and canceled.
-        let task = std::mem::replace(&mut peer.task, fasync::Task::local(async move {}));
-        let cancellation = task.cancel();
-        let mut cancellation = pin!(cancellation);
-        let _ = exec.run_until_stalled(&mut cancellation).expect("task to stop completely");
+        // Replace the task with a no-op task which will cancel the task.
+        peer.task = fasync::Task::local(std::future::ready(()));
 
         // create profile_event_fut in a block to limit its lifetime
         {
@@ -461,12 +457,8 @@
         let id = PeerId(1);
         let mut peer = make_peer(id).0;
 
-        // Stop the inner task and wait until it has fully stopped
-        // The inner task is replaced by a no-op task so that it can be consumed and canceled.
-        let cancellation =
-            std::mem::replace(&mut peer.task, fasync::Task::local(async move {})).cancel();
-        let mut cancellation = pin!(cancellation);
-        let _ = exec.run_until_stalled(&mut cancellation).expect("task to stop completely");
+        // Replace the task with a no-op task which will cancel the task.
+        peer.task = fasync::Task::local(std::future::ready(()));
 
         let build_handler_fut = peer.build_handler();
         let mut build_handler_fut = pin!(build_handler_fut);
diff --git a/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/sco_connector.rs b/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/sco_connector.rs
index 0d26dba..5c63e42 100644
--- a/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/sco_connector.rs
+++ b/src/connectivity/bluetooth/profiles/bt-hfp-audio-gateway/src/sco_connector.rs
@@ -199,7 +199,7 @@
         codecs: Vec<CodecId>,
     ) -> impl Future<Output = Result<ScoConnection, ScoConnectError>> + 'static {
         let params = self.parameters_for_codecs(codecs);
-        info!("Initiating SCO connection for {}: {:?}", peer_id, &params);
+        info!(%peer_id, ?params, "Initiating SCO connection");
 
         let proxy = self.proxy.clone();
         async move {
@@ -215,10 +215,10 @@
                     // Return early if there is a FIDL issue, or we succeeded.
                     Err(ScoConnectError::Fidl { .. }) | Ok(_) => return result,
                     // Otherwise continue to try the next params.
-                    Err(e) => debug!(?peer_id, ?param, ?e, "Connection failed, trying next set.."),
+                    Err(e) => debug!(%peer_id, ?param, ?e, "Connection failed, trying next set.."),
                 }
             }
-            info!(?peer_id, "Exhausted SCO connection parameters");
+            info!(%peer_id, "Exhausted SCO connection parameters");
             Err(ScoConnectError::ScoFailed)
         }
     }
@@ -229,7 +229,7 @@
         codecs: Vec<CodecId>,
     ) -> impl Future<Output = Result<ScoConnection, ScoConnectError>> + 'static {
         let params = self.parameters_for_codecs(codecs);
-        info!("Accepting SCO connection for {}: {:?}.", peer_id, &params);
+        info!(%peer_id, ?params, "Accepting SCO connection");
 
         let proxy = self.proxy.clone();
         Self::setup_sco_connection(proxy, peer_id, ScoInitiatorRole::Accept, params)
diff --git a/src/connectivity/bluetooth/testing/bt-test-harness/BUILD.gn b/src/connectivity/bluetooth/testing/bt-test-harness/BUILD.gn
index 16005eb..b70d6c9 100644
--- a/src/connectivity/bluetooth/testing/bt-test-harness/BUILD.gn
+++ b/src/connectivity/bluetooth/testing/bt-test-harness/BUILD.gn
@@ -15,6 +15,7 @@
     "//sdk/fidl/fuchsia.bluetooth:fuchsia.bluetooth_rust",
     "//sdk/fidl/fuchsia.bluetooth.bredr:fuchsia.bluetooth.bredr_rust",
     "//sdk/fidl/fuchsia.bluetooth.gatt:fuchsia.bluetooth.gatt_rust",
+    "//sdk/fidl/fuchsia.bluetooth.host:fuchsia.bluetooth.host_rust",
     "//sdk/fidl/fuchsia.bluetooth.le:fuchsia.bluetooth.le_rust",
     "//sdk/fidl/fuchsia.bluetooth.snoop:fuchsia.bluetooth.snoop_rust",
     "//sdk/fidl/fuchsia.bluetooth.sys:fuchsia.bluetooth.sys_rust",
@@ -26,7 +27,6 @@
     "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
     "//sdk/fidl/fuchsia.logger:fuchsia.logger_rust",
     "//sdk/fidl/fuchsia.stash:fuchsia.stash_rust",
-    "//src/connectivity/bluetooth/fidl:host_rust",
     "//src/connectivity/bluetooth/lib/fuchsia-bluetooth",
     "//src/connectivity/bluetooth/testing/hci-emulator-client",
     "//src/connectivity/bluetooth/testing/realmbuilder-mock-helpers",
@@ -60,7 +60,6 @@
     "//sdk/fidl/fuchsia.process:fuchsia.process_rust",
     "//src/lib/fuchsia-component",
     "//src/lib/fuchsia-sync",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:proptest",
     "//third_party/rust_crates:thiserror",
   ]
diff --git a/src/connectivity/bluetooth/testing/bt-test-harness/src/access.rs b/src/connectivity/bluetooth/testing/bt-test-harness/src/access.rs
index 6a6cad8..8f2acb8 100644
--- a/src/connectivity/bluetooth/testing/bt-test-harness/src/access.rs
+++ b/src/connectivity/bluetooth/testing/bt-test-harness/src/access.rs
@@ -98,8 +98,9 @@
         let _ = harness.write_state().peers.insert(peer.id, peer);
     }
     for id in removed.into_iter() {
-        if harness.write_state().peers.remove(&id.into()).is_none() {
-            warn!(?id, "Unknown peer removed from peer state");
+        let id = id.into();
+        if harness.write_state().peers.remove(&id).is_none() {
+            warn!(%id, "Unknown peer removed from peer state");
         }
     }
     harness.notify_state_changed();
diff --git a/src/connectivity/bluetooth/testing/bt-test-harness/src/host.rs b/src/connectivity/bluetooth/testing/bt-test-harness/src/host.rs
index 613546c..3fd047d 100644
--- a/src/connectivity/bluetooth/testing/bt-test-harness/src/host.rs
+++ b/src/connectivity/bluetooth/testing/bt-test-harness/src/host.rs
@@ -178,8 +178,9 @@
             harness.notify_state_changed();
         }
         for id in removed.into_iter() {
-            if harness.write_state().peers.remove(&id.into()).is_none() {
-                warn!(?id, "HostHarness: Removed id that wasn't present");
+            let id = id.into();
+            if harness.write_state().peers.remove(&id).is_none() {
+                warn!(%id, "HostHarness: Removed id that wasn't present");
             }
         }
     }
diff --git a/src/connectivity/bluetooth/testing/mock-piconet-server/src/lib.rs b/src/connectivity/bluetooth/testing/mock-piconet-server/src/lib.rs
index ff4b8b5..1be4405 100644
--- a/src/connectivity/bluetooth/testing/mock-piconet-server/src/lib.rs
+++ b/src/connectivity/bluetooth/testing/mock-piconet-server/src/lib.rs
@@ -885,14 +885,22 @@
         super::*,
         assert_matches::assert_matches,
         cm_rust::{
-            Availability, DependencyType, OfferDecl, OfferProtocolDecl, OfferSource, OfferTarget,
-            UseDecl, UseProtocolDecl, UseSource,
+            Availability, ChildRef, DependencyType, OfferDecl, OfferProtocolDecl, OfferSource,
+            OfferTarget, UseDecl, UseProtocolDecl, UseSource,
         },
         cm_types::Name,
         fidl_fuchsia_component_test as fctest,
         fuchsia_component_test::error::Error as RealmBuilderError,
     };
 
+    fn offer_source_static_child(name: &str) -> OfferSource {
+        OfferSource::Child(ChildRef { name: name.parse().unwrap(), collection: None })
+    }
+
+    fn offer_target_static_child(name: &str) -> cm_rust::OfferTarget {
+        OfferTarget::Child(ChildRef { name: name.parse().unwrap(), collection: None })
+    }
+
     async fn assert_realm_contains(builder: &RealmBuilder, child_name: &str) {
         let err = builder
             .add_child(child_name, "test://example-url", ChildOptions::new())
@@ -1107,10 +1115,10 @@
         let profile_test_name = Name::new(bredr::ProfileTestMarker::PROTOCOL_NAME).unwrap();
         let root = builder.get_realm_decl().await.expect("failed to get root");
         let offer_profile_test = OfferDecl::Protocol(OfferProtocolDecl {
-            source: OfferSource::static_child(super::mock_piconet_server_moniker().to_string()),
+            source: offer_source_static_child(&super::mock_piconet_server_moniker()),
             source_name: profile_test_name.clone(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child(member_spec.name.clone()),
+            target: offer_target_static_child(&member_spec.name),
             target_name: profile_test_name,
             dependency_type: DependencyType::Strong,
             availability: Availability::Required,
@@ -1177,10 +1185,10 @@
 
         // Profile is offered by root to profile from interposer
         let profile_offer = OfferDecl::Protocol(OfferProtocolDecl {
-            source: OfferSource::static_child(interposer_name.clone()),
+            source: offer_source_static_child(&interposer_name),
             source_name: profile_capability_name.clone(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child(profile_name.to_string()),
+            target: offer_target_static_child(&profile_name),
             target_name: profile_capability_name.clone(),
             dependency_type: DependencyType::Strong,
             availability: Availability::Required,
@@ -1190,10 +1198,10 @@
 
         // ProfileTest is offered by root to interposer from Mock Piconet Server
         let profile_test_offer = OfferDecl::Protocol(OfferProtocolDecl {
-            source: OfferSource::static_child(super::mock_piconet_server_moniker().to_string()),
+            source: offer_source_static_child(&super::mock_piconet_server_moniker()),
             source_name: profile_test_name.clone(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child(interposer_name.clone()),
+            target: offer_target_static_child(&interposer_name),
             target_name: profile_test_name.clone(),
             dependency_type: DependencyType::Strong,
             availability: Availability::Required,
@@ -1206,7 +1214,7 @@
             source: OfferSource::Parent,
             source_name: log_capability_name.clone(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child(profile_name.to_string()),
+            target: offer_target_static_child(&profile_name),
             target_name: log_capability_name.clone(),
             dependency_type: DependencyType::Strong,
             availability: Availability::Required,
@@ -1246,20 +1254,20 @@
 
         // `Profile` is offered by root to bt-rfcomm from interposer.
         let profile_offer1 = OfferDecl::Protocol(OfferProtocolDecl {
-            source: OfferSource::static_child(interposer_name.clone()),
+            source: offer_source_static_child(&interposer_name),
             source_name: profile_capability_name.clone(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child(bt_rfcomm_name.clone()),
+            target: offer_target_static_child(&bt_rfcomm_name),
             target_name: profile_capability_name.clone(),
             dependency_type: DependencyType::Strong,
             availability: Availability::Required,
         });
         // `Profile` is offered from bt-rfcomm to profile.
         let profile_offer2 = OfferDecl::Protocol(OfferProtocolDecl {
-            source: OfferSource::static_child(bt_rfcomm_name.clone()),
+            source: offer_source_static_child(&bt_rfcomm_name),
             source_name: profile_capability_name.clone(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child(profile_name.to_string()),
+            target: offer_target_static_child(&profile_name),
             target_name: profile_capability_name.clone(),
             dependency_type: DependencyType::Strong,
             availability: Availability::Required,
@@ -1327,7 +1335,7 @@
             source: OfferSource::Parent,
             source_name: fake_cap3.clone().parse().unwrap(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child(profile_name.to_string()),
+            target: offer_target_static_child(&profile_name),
             target_name: fake_cap3.parse().unwrap(),
             dependency_type: DependencyType::Strong,
             availability: Availability::Required,
diff --git a/src/connectivity/bluetooth/tests/audio-device-output-harness/src/main.rs b/src/connectivity/bluetooth/tests/audio-device-output-harness/src/main.rs
index e2e318c..e84a127 100644
--- a/src/connectivity/bluetooth/tests/audio-device-output-harness/src/main.rs
+++ b/src/connectivity/bluetooth/tests/audio-device-output-harness/src/main.rs
@@ -5,7 +5,7 @@
 use {
     anyhow::Context,
     fidl_fuchsia_media::{AudioChannelId, AudioDeviceEnumeratorMarker, AudioPcmMode, PcmFormat},
-    fuchsia_audio_device::driver::SoftPcm,
+    fuchsia_audio_device::stream_config::SoftStreamConfig,
     fuchsia_zircon::DurationNum,
     futures::StreamExt,
     tracing::info,
@@ -22,7 +22,7 @@
     };
 
     let id = [2; 16];
-    let (client, mut frame_stream) = SoftPcm::create_output(
+    let (client, mut frame_stream) = SoftStreamConfig::create_output(
         &id,
         "Fuchsia",
         "AudioOutHarness",
diff --git a/src/connectivity/bluetooth/tests/bt-host-integration/BUILD.gn b/src/connectivity/bluetooth/tests/bt-host-integration/BUILD.gn
index 6e115a7..f11dc52 100644
--- a/src/connectivity/bluetooth/tests/bt-host-integration/BUILD.gn
+++ b/src/connectivity/bluetooth/tests/bt-host-integration/BUILD.gn
@@ -10,9 +10,9 @@
   source_root = "src/lib.rs"
   deps = [
     "//sdk/fidl/fuchsia.bluetooth:fuchsia.bluetooth_rust",
+    "//sdk/fidl/fuchsia.bluetooth.host:fuchsia.bluetooth.host_rust",
     "//sdk/fidl/fuchsia.bluetooth.sys:fuchsia.bluetooth.sys_rust",
     "//sdk/fidl/fuchsia.bluetooth.test:fuchsia.bluetooth.test_rust",
-    "//src/connectivity/bluetooth/fidl:host_rust",
     "//src/connectivity/bluetooth/lib/fuchsia-bluetooth",
     "//src/connectivity/bluetooth/testing/bt-test-harness",
     "//src/connectivity/bluetooth/testing/hci-emulator-client",
diff --git a/src/connectivity/bluetooth/tests/bt-host-integration/src/lib.rs b/src/connectivity/bluetooth/tests/bt-host-integration/src/lib.rs
index b21f969..6ae5484 100644
--- a/src/connectivity/bluetooth/tests/bt-host-integration/src/lib.rs
+++ b/src/connectivity/bluetooth/tests/bt-host-integration/src/lib.rs
@@ -213,8 +213,8 @@
         .and(expectation::host_driver::discovering(true));
     let _ = host_expectation::host_state(&harness, active_state).await.unwrap();
 
-    // Close should cancel these procedures.
-    proxy.close().unwrap();
+    // Shutdown should cancel these procedures.
+    proxy.shutdown().unwrap();
 
     let closed_state_update = expectation::host_driver::discoverable(false)
         .and(expectation::host_driver::discovering(false));
diff --git a/src/connectivity/bluetooth/tests/bt-manifest-integration-tests/BUILD.gn b/src/connectivity/bluetooth/tests/bt-manifest-integration-tests/BUILD.gn
index 142d34d4..b2e1b5a 100644
--- a/src/connectivity/bluetooth/tests/bt-manifest-integration-tests/BUILD.gn
+++ b/src/connectivity/bluetooth/tests/bt-manifest-integration-tests/BUILD.gn
@@ -252,6 +252,7 @@
   deps = [
     "//sdk/fidl/fuchsia.bluetooth.bredr:fuchsia.bluetooth.bredr_rust",
     "//sdk/fidl/fuchsia.bluetooth.gatt:fuchsia.bluetooth.gatt_rust",
+    "//sdk/fidl/fuchsia.bluetooth.host:fuchsia.bluetooth.host_rust",
     "//sdk/fidl/fuchsia.bluetooth.le:fuchsia.bluetooth.le_rust",
     "//sdk/fidl/fuchsia.bluetooth.rfcomm.test:fuchsia.bluetooth.rfcomm.test_rust",
     "//sdk/fidl/fuchsia.bluetooth.snoop:fuchsia.bluetooth.snoop_rust",
@@ -262,7 +263,6 @@
     "//sdk/fidl/fuchsia.logger:fuchsia.logger_rust",
     "//sdk/fidl/fuchsia.stash:fuchsia.stash_rust",
     "//src/connectivity/bluetooth/core/bt-gap:test-stash-secure",
-    "//src/connectivity/bluetooth/fidl:host_rust",
     "//src/connectivity/bluetooth/hci/virtual:driver",
     "//src/connectivity/bluetooth/lib/fuchsia-bluetooth",
     "//src/connectivity/bluetooth/testing/realmbuilder-mock-helpers",
diff --git a/src/connectivity/bluetooth/tools/bt-cli/src/main.rs b/src/connectivity/bluetooth/tools/bt-cli/src/main.rs
index e762c75..5e64d088 100644
--- a/src/connectivity/bluetooth/tools/bt-cli/src/main.rs
+++ b/src/connectivity/bluetooth/tools/bt-cli/src/main.rs
@@ -269,7 +269,7 @@
     if let Some((pairing_task, mut recv)) = pairing {
         if let Some((paired_id, paired)) = recv.next().await {
             // If pairing was completed, exit.
-            let _ = pairing_task.cancel().await;
+            let _ = pairing_task.cancel();
             println!(
                 "Completed {} pairing for {}.",
                 if paired { "successful" } else { "unsuccessful" },
@@ -427,7 +427,7 @@
 
     if let Some((paired_id, paired)) = receiver.next().await {
         // If pairing was completed, exit.
-        let _ = delegate_task.cancel().await;
+        let _ = delegate_task.cancel();
         return Ok(format!(
             "Completed {} pairing with {}.",
             if paired { "successful" } else { "unsuccessful" },
diff --git a/src/connectivity/bluetooth/tools/bt-le-central/src/gatt.rs b/src/connectivity/bluetooth/tools/bt-le-central/src/gatt.rs
index 7637263..2646e1a 100644
--- a/src/connectivity/bluetooth/tools/bt-le-central/src/gatt.rs
+++ b/src/connectivity/bluetooth/tools/bt-le-central/src/gatt.rs
@@ -740,7 +740,7 @@
     };
     match task {
         Some(task) => {
-            let _ = task.cancel().await;
+            let _ = task.cancel();
             println!("(id = {}) done", id);
         }
         None => println!("(id = {}) notifications not enabled", id),
diff --git a/src/connectivity/ethernet/drivers/third_party/igc/igc_driver.cc b/src/connectivity/ethernet/drivers/third_party/igc/igc_driver.cc
index d061542..7230108 100644
--- a/src/connectivity/ethernet/drivers/third_party/igc/igc_driver.cc
+++ b/src/connectivity/ethernet/drivers/third_party/igc/igc_driver.cc
@@ -232,7 +232,6 @@
   ** mac from that.
   */
   igc_reset_hw(hw);
-  igc_power_up_phy(hw);
 
   /* Make sure we have a good EEPROM before we read from it */
   if (igc_validate_nvm_checksum(hw) < 0) {
@@ -280,18 +279,11 @@
   adapter_->rxdr = reinterpret_cast<union igc_adv_rx_desc*>(adapter_->txdr + kEthTxDescRingCount);
   adapter_->rxd_phys = txrx_phy_addr + kEthTxDescBufTotalSize;
 
-  InitTransmitUnit();
-  InitReceiveUnit();
-
   u32 ctrl;
   ctrl = IGC_READ_REG(hw, IGC_CTRL);
   ctrl |= IGC_CTRL_VME;
   IGC_WRITE_REG(hw, IGC_CTRL, ctrl);
 
-  // Promiscuous settings.
-  IfSetPromisc(kIffPromisc);
-  igc_clear_hw_cntrs_base_generic(hw);
-
   // Clear all pending interrupts.
   IGC_READ_REG(hw, IGC_ICR);
   IGC_WRITE_REG(hw, IGC_ICS, IGC_ICS_LSC);
@@ -612,26 +604,38 @@
   port_binding_ = fdf::BindServer(netdev_dispatcher_.get(), std::move(endpoints->server), this);
   adapter_->netdev_ifc.buffer(arena)
       ->AddPort(kPortId, std::move(endpoints->client))
-      .Then([this, completer = completer.ToAsync()](
+      .Then([completer = completer.ToAsync()](
                 fdf::WireUnownedResult<netdriver::NetworkDeviceIfc::AddPort>& result) mutable {
         fdf::Arena arena(0u);
         if (!result.ok()) {
           FDF_LOG(ERROR, "Failed to add port: %s", result.FormatDescription().c_str());
         }
         completer.buffer(arena).Reply(result.status());
-        // Enable the interrupt now that the data path is set up. It's not safe to enable
-        // it before netdev_ifc is bound because the interrupt handler uses it.
-        EnableInterrupt();
       });
 }
 
 void IgcDriver::Start(fdf::Arena& arena, StartCompleter::Sync& completer) {
+  // Promiscuous settings.
+  IfSetPromisc(kIffPromisc);
+  igc_clear_hw_cntrs_base_generic(&adapter_->hw);
+
+  igc_power_up_phy(&adapter_->hw);
+
+  InitTransmitUnit();
+  InitReceiveUnit();
+
+  EnableInterrupt();
+
+  OnlineStatusUpdate();
+
   started_ = true;
   completer.buffer(arena).Reply(ZX_OK);
 }
 
 void IgcDriver::Stop(fdf::Arena& arena, StopCompleter::Sync& completer) {
   started_ = false;
+  DisableInterrupt();
+
   {
     // Reclaim all the buffers queued in rx descriptor ring.
     std::lock_guard lock(adapter_->rx_lock);
@@ -678,31 +682,38 @@
     }
   }
 
-  // Reclaim all tx buffers. Tx data path is protected by start lock.
-  // Assume TX depth here to simplify this and avoid having to deal with batching.
-  static_assert(kEthTxBufCount < netdriver::wire::kMaxTxResults,
-                "TX depth exceeds maximum TX results that can be completed");
-  // Just use the provided arena here, no need to try to optimize this by trying to get everything
-  // allocated on the stack. This is not part of the critical path.
-  fidl::VectorView<netdriver::wire::TxResult> results(arena, kEthTxBufCount);
+  {
+    // Reclaim all tx buffers.
+    std::lock_guard lock(adapter_->tx_lock);
+    // Assume TX depth here to simplify this and avoid having to deal with batching.
+    static_assert(kEthTxBufCount < netdriver::wire::kMaxTxResults,
+                  "TX depth exceeds maximum TX results that can be completed");
+    // Just use the provided arena here, no need to try to optimize this by trying to get everything
+    // allocated on the stack. This is not part of the critical path.
+    fidl::VectorView<netdriver::wire::TxResult> results(arena, kEthTxBufCount);
 
-  size_t res_idx = 0;
-  uint32_t& txh = adapter_->txh_ind;
-  while (adapter_->txr_len > 0) {
-    adapter_->txdr[txh].upper.fields.status = 0;
-    results[res_idx].id = tx_buffers_[txh].buffer_id;
-    results[res_idx].status = ZX_ERR_UNAVAILABLE;
-    res_idx++;
-    adapter_->txr_len--;
-    txh = (txh + 1) & (kEthTxDescRingCount - 1);
-  }
-  if (res_idx > 0) {
-    results.set_count(res_idx);
-    if (fidl::OneWayStatus status = adapter_->netdev_ifc.buffer(arena)->CompleteTx(results);
-        !status.ok()) {
-      FDF_LOG(ERROR, "Failed to complete TX during stop: %s", status.FormatDescription().c_str());
+    size_t res_idx = 0;
+    uint32_t& txh = adapter_->txh_ind;
+    while (adapter_->txr_len > 0) {
+      adapter_->txdr[txh].upper.fields.status = 0;
+      results[res_idx].id = tx_buffers_[txh].buffer_id;
+      results[res_idx].status = ZX_ERR_UNAVAILABLE;
+      res_idx++;
+      adapter_->txr_len--;
+      txh = (txh + 1) & (kEthTxDescRingCount - 1);
+    }
+    if (res_idx > 0) {
+      results.set_count(res_idx);
+      if (fidl::OneWayStatus status = adapter_->netdev_ifc.buffer(arena)->CompleteTx(results);
+          !status.ok()) {
+        FDF_LOG(ERROR, "Failed to complete TX during stop: %s", status.FormatDescription().c_str());
+      }
     }
   }
+
+  igc_reset_hw(&adapter_->hw);
+  IGC_WRITE_REG(&adapter_->hw, IGC_WUC, 0);
+
   completer.buffer(arena).Reply();
 }
 
@@ -921,7 +932,15 @@
   completer.buffer(arena).Reply();
 }
 
-void IgcDriver::EnableInterrupt() { IGC_WRITE_REG(&adapter_->hw, IGC_IMS, IMS_ENABLE_MASK); }
+void IgcDriver::EnableInterrupt() {
+  IGC_WRITE_REG(&adapter_->hw, IGC_IMS, IMS_ENABLE_MASK);
+  IGC_WRITE_FLUSH(&adapter_->hw);
+}
+
+void IgcDriver::DisableInterrupt() {
+  IGC_WRITE_REG(&adapter_->hw, IGC_IMC, 0xFFFFFFFFu);
+  IGC_WRITE_FLUSH(&adapter_->hw);
+}
 
 void IgcDriver::HandleIrq(async_dispatcher_t* dispatcher, async::IrqBase* irq_base,
                           zx_status_t status, const zx_packet_interrupt_t* interrupt) {
diff --git a/src/connectivity/ethernet/drivers/third_party/igc/igc_driver.h b/src/connectivity/ethernet/drivers/third_party/igc/igc_driver.h
index e21b96c..fe43975 100644
--- a/src/connectivity/ethernet/drivers/third_party/igc/igc_driver.h
+++ b/src/connectivity/ethernet/drivers/third_party/igc/igc_driver.h
@@ -193,6 +193,7 @@
   void ReapTxBuffers();
 
   void EnableInterrupt();
+  void DisableInterrupt();
   void HandleIrq(async_dispatcher_t* dispatcher, async::IrqBase* irq_base, zx_status_t status,
                  const zx_packet_interrupt_t* interrupt);
 
diff --git a/src/connectivity/ethernet/drivers/virtio/netdevice.cc b/src/connectivity/ethernet/drivers/virtio/netdevice.cc
index fea5274..c24faec 100644
--- a/src/connectivity/ethernet/drivers/virtio/netdevice.cc
+++ b/src/connectivity/ethernet/drivers/virtio/netdevice.cc
@@ -383,6 +383,13 @@
       auto iter = tx_return.begin();
       {
         std::lock_guard lock(tx_lock_);
+        // Free all TX ring entries to prevent the IRQ handler from completing these buffers.
+        tx_.IrqRingUpdate([this](vring_used_elem* used_elem) {
+          []() __TA_ASSERT(tx_lock_) {}();
+          const uint16_t id = static_cast<uint16_t>(used_elem->id & 0xffff);
+          tx_.FreeDesc(id);
+        });
+
         for (int i = 0; i < kMaxDepth; ++i) {
           if (tx_in_flight_active_[i]) {
             *iter++ = {
@@ -405,6 +412,13 @@
       auto parts_iter = rx_return_parts.begin();
       {
         std::lock_guard lock(rx_lock_);
+        // Free all RX ring entries to prevent the IRQ handler from completing these buffers.
+        rx_.IrqRingUpdate([this](vring_used_elem* used_elem) {
+          []() __TA_ASSERT(rx_lock_) {}();
+          const uint16_t id = static_cast<uint16_t>(used_elem->id & 0xffff);
+          rx_.FreeDesc(id);
+        });
+
         while (!rx_in_flight_.Empty()) {
           Descriptor d = rx_in_flight_.Pop();
           *iter++ = {
diff --git a/src/connectivity/ethernet/drivers/virtio/netdevice_test.cc b/src/connectivity/ethernet/drivers/virtio/netdevice_test.cc
index 23c136d..0aa078e 100644
--- a/src/connectivity/ethernet/drivers/virtio/netdevice_test.cc
+++ b/src/connectivity/ethernet/drivers/virtio/netdevice_test.cc
@@ -379,6 +379,60 @@
   }
 }
 
+TEST_F(NetworkDeviceTests, StopDuringIrqUpdate) {
+  ASSERT_NO_FATAL_FAILURE(StartDevice());
+  ASSERT_NO_FATAL_FAILURE(PrepareVmo());
+
+  std::array<tx_buffer_t, NetworkDevice::kMaxDepth> tx_buffers;
+  std::array<rx_space_buffer_t, NetworkDevice::kMaxDepth> rx_spaces;
+
+  constexpr buffer_region_t kPlaceholderRegion = {
+      .vmo = kVmoId,
+      .offset = 0,
+      .length = NetworkDevice::kFrameSize,
+  };
+
+  for (uint32_t i = 0; i < tx_buffers.size(); ++i) {
+    tx_buffers[i] = {.id = i,
+                     .data_list = &kPlaceholderRegion,
+                     .data_count = 1,
+                     .meta = kFrameMetadata,
+                     .head_length = device().virtio_header_len()};
+  }
+
+  for (uint32_t i = 0; i < rx_spaces.size(); ++i) {
+    rx_spaces[i] = {.id = i, .region = kPlaceholderRegion};
+  }
+
+  // Queue some rx and tx buffers so we observe them being returned on stop.
+  device().NetworkDeviceImplQueueRxSpace(rx_spaces.data(), rx_spaces.size());
+  device().NetworkDeviceImplQueueTx(tx_buffers.data(), tx_buffers.size());
+
+  // Populate TX descriptors in the ring to indicate that everything was transmitted so that
+  // IrqRingUpdate has something to do.
+  vring& tx_ring = tx_vring();
+  for (const auto& tx_buffer : tx_buffers) {
+    tx_ring.used[tx_ring.used->idx++] = {.idx = static_cast<uint16_t>(tx_buffer.id)};
+  }
+
+  // Also Populate RX descriptors in the ring to indicate that everything was received.
+  vring& rx_ring = rx_vring();
+  for (const auto& rx_space : rx_spaces) {
+    rx_ring.used[rx_ring.used->idx++] = {.idx = static_cast<uint16_t>(rx_space.id)};
+  }
+
+  // Now call Stop first to return all buffers.
+  libsync::Completion stop_called;
+  device().NetworkDeviceImplStop(
+      [](void* cookie) { reinterpret_cast<libsync::Completion*>(cookie)->Signal(); }, &stop_called);
+  stop_called.Wait();
+
+  // Then behave as if an IRQ ring update was pending but blocked on one of the locks in Stop and is
+  // now allowed to continue running. If the TX or RX ring is not correctly cleared in Stop this
+  // will trigger an assertion and crash.
+  device().IrqRingUpdate();
+}
+
 TEST_F(NetworkDeviceTests, UpdateStatus) {
   const struct {
     const char* name;
diff --git a/src/connectivity/lib/packet-formats/src/icmp/mld.rs b/src/connectivity/lib/packet-formats/src/icmp/mld.rs
index 1bce48e..24d968e7 100644
--- a/src/connectivity/lib/packet-formats/src/icmp/mld.rs
+++ b/src/connectivity/lib/packet-formats/src/icmp/mld.rs
@@ -241,7 +241,7 @@
     ///
     /// It should be `()` for Report and Done messages,
     /// and be `Mldv1ResponseDelay` for Query messages.
-    type MaxRespDelay: MaxRespCode + Debug + Copy;
+    type MaxRespDelay: MaxCode<U16> + Debug + Copy;
     /// The type used to represent the group_addr in the message.
     ///
     /// For Query Messages, it is just `Ipv6Addr` because
@@ -257,32 +257,143 @@
 {
 }
 
-/// The trait for MLD maximum response codes.
-///
-/// The type implementing this trait should be able
-/// to convert itself from/to `U16`
-pub trait MaxRespCode {
-    /// Convert to `U16`
-    #[allow(clippy::wrong_self_convention)]
-    fn as_code(self) -> U16;
-
-    /// Convert from `U16`
-    fn from_code(code: U16) -> Self;
+/// Creates a bitmask of [n] bits, [n] must be <= 31.
+/// E.g. for n = 12 yields 0xFFF.
+const fn bitmask(n: u8) -> u32 {
+    (1 << n) - 1
 }
 
-impl MaxRespCode for () {
-    fn as_code(self) -> U16 {
-        U16::ZERO
+/// The trait converts a code to a floating point value: in a linear fashion up to [SWITCHPOINT]
+/// and then using a floating point representation to allow the conversion of larger values.
+/// In MLD and IGMP there are different codes that follow this pattern, e.g. QQIC, ResponseDelay
+/// ([RFC 3376 section 4.1], [RFC 3810 section 5.1]), which all convert a code with the following
+/// underlying structure:
+///
+///       0    NUM_EXP_BITS       NUM_MANT_BITS
+///      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+///      |X|      exp      |          mant         |
+///      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+///
+/// This trait simplifies the implementation by providing methods to perform the conversion.
+///
+/// [RFC 3376 section 4.1]: https://datatracker.ietf.org/doc/html/rfc3376#section-4.1
+/// [RFC 3810 section 5.1]: https://datatracker.ietf.org/doc/html/rfc3810#section-5.1
+// TODO(https://fxbug.dev/42071006): extract the trait in a common file to use it for for IGMPv3.
+pub trait LinExpConversion<C: Debug + core::cmp::PartialEq + Copy + Clone>:
+    Into<C> + Copy + Clone
+{
+    // Specified by Implementors
+    /// Number of bits used for the mantissa.
+    const NUM_MANT_BITS: u8;
+    /// Number of bits used for the exponent.
+    const NUM_EXP_BITS: u8;
+    /// Perform a lossy conversion from the `C` type.
+    /// Not all values in `C` can be exactly represented using the code and they will be rounded to
+    /// a code that represents a value close the provided one.
+    fn lossy_try_from(value: C) -> Result<Self, MldError>;
+
+    // Provided for Implementors
+    /// How much the exponent needs to be incremented when performing the exponential conversion.
+    const EXP_INCR: u32 = 3;
+    /// Bitmask for the mantissa.
+    const MANT_BITMASK: u32 = bitmask(Self::NUM_MANT_BITS);
+    /// Bitmask for the exponent.
+    const EXP_BITMASK: u32 = bitmask(Self::NUM_EXP_BITS);
+    /// First value for which we start the exponential conversion.
+    const SWITCHPOINT: u32 = 0x1 << (Self::NUM_MANT_BITS + Self::NUM_EXP_BITS);
+    /// Prefix for capturing the mantissa.
+    const MANT_PREFIX: u32 = 0x1 << Self::NUM_MANT_BITS;
+    /// Maximum value the code supports.
+    const MAX_VALUE: u32 =
+        (Self::MANT_BITMASK | Self::MANT_PREFIX) << (Self::EXP_INCR + Self::EXP_BITMASK);
+
+    /// Converts the provided code to a value: in a linear way until [Self::SWITCHPOINT] and using
+    /// a floating representation for larger values.
+    fn to_expanded(code: u16) -> u32 {
+        let code = code.into();
+        if code < Self::SWITCHPOINT {
+            code
+        } else {
+            let mant = code & Self::MANT_BITMASK;
+            let exp = (code >> Self::NUM_MANT_BITS) & Self::EXP_BITMASK;
+            (mant | Self::MANT_PREFIX) << (Self::EXP_INCR + exp)
+        }
     }
 
-    fn from_code(_: U16) -> Self {}
+    /// Performs a lossy conversion from [value].
+    ///
+    /// The function will always succeed for values within the valid range. However, the code might
+    /// not exactly represent the provided input. E.g. a value of `MAX_VALUE - 1` cannot be exactly
+    /// represented with a corresponding code, due the exponential representation. However, the
+    /// function will be able to provide a code representing a value close to the provided one.
+    ///
+    /// If stronger guarantees are needed consider using [exact_try_from_expanded].
+    fn lossy_try_from_expanded(value: u32) -> Result<u16, MldError> {
+        if value > Self::MAX_VALUE {
+            Err(MldError::MaxRespCodeOverflow)
+        } else if value < Self::SWITCHPOINT {
+            // Given that Value is < Self::SWITCHPOINT, unwrapping here is safe.
+            let code = value.try_into().unwrap();
+            Ok(code)
+        } else {
+            let msb = (u32::BITS - value.leading_zeros()) - 1;
+            let exp = msb - u32::from(Self::NUM_MANT_BITS);
+            let mant = (value >> exp) & Self::MANT_BITMASK;
+            // Unwrap guaranteed by the structure of the built int:
+            let code = (Self::SWITCHPOINT | ((exp - Self::EXP_INCR) << Self::NUM_MANT_BITS) | mant)
+                .try_into()
+                .unwrap();
+            Ok(code)
+        }
+    }
+
+    /// Performs an exact conversion from [value].
+    ///
+    /// The function will succeed only for values within the valid range that can be exactly
+    /// represented by the produced code. E.g. a value of FLOATING_POINT_MAX_VALUE - 1 cannot be
+    /// exactly represented with a corresponding, code due the exponential representation. In this
+    /// case, the function will return an error.
+    ///
+    /// If a lossy conversion can be tolerated consider using [lossy_try_from_expanded].
+    fn exact_try_from(value: C) -> Result<Self, MldError>
+    where
+        Self: core::marker::Sized,
+    {
+        let res = Self::lossy_try_from(value)?;
+        if value == res.into() {
+            Ok(res)
+        } else {
+            Err(MldError::MaxRespCodeLossyConversion)
+        }
+    }
+}
+
+/// The trait for MLD codes that can be further interpreted using different methods e.g. QQIC.
+///
+/// The type implementing this trait should be able
+/// to convert itself from/to `T`
+pub trait MaxCode<T: Default + Debug + FromBytes + AsBytes> {
+    /// Convert to `T`
+    #[allow(clippy::wrong_self_convention)]
+    fn as_code(self) -> T;
+
+    /// Convert from `T`
+    fn from_code(code: T) -> Self;
+}
+
+impl<T: Default + Debug + FromBytes + AsBytes> MaxCode<T> for () {
+    fn as_code(self) -> T {
+        T::default()
+    }
+
+    fn from_code(_: T) -> Self {}
 }
 
 /// Maximum Response Delay used in Query messages.
 #[derive(PartialEq, Eq, Debug, Clone, Copy)]
 pub struct Mldv1ResponseDelay(u16);
 
-impl MaxRespCode for Mldv1ResponseDelay {
+impl MaxCode<U16> for Mldv1ResponseDelay {
     fn as_code(self) -> U16 {
         U16::new(self.0)
     }
@@ -422,104 +533,24 @@
     }
 }
 
-const FLOATING_POINT_SWITCH_POINT: u16 = 32768;
-const FLOATING_POINT_MAX_VALUE: u32 = (0x0FFF | 0x1000) << (7 + 3);
-
-/// Maximum Response Delay used in Queryv2 messages, defined in [RFC 3810 section 5.1.3]
+/// Maximum Response Delay used in Queryv2 messages, defined in [RFC 3810 section 5.1.3].
 /// [RFC 3810 section 5.1.3]: https://datatracker.ietf.org/doc/html/rfc3810#section-5.1.3
 #[derive(PartialEq, Eq, Debug, Clone, Copy)]
 pub struct Mldv2ResponseDelay(u16);
 
-impl Mldv2ResponseDelay {
-    /// Parses a code that may be representing a floating point value.
-    ///
-    /// Defined in [RFC 3810 section 5.1] and used in MLDv2 multicast listener queries and multicast
-    /// listener reports.
-    ///
-    /// The floating point format is as follows:
-    ///
-    ///   If Maximum Response Code < 32768,
-    ///      Maximum Response Delay = Maximum Response Code
+impl LinExpConversion<Duration> for Mldv2ResponseDelay {
+    const NUM_MANT_BITS: u8 = 12;
+    const NUM_EXP_BITS: u8 = 3;
 
-    ///   If Maximum Response Code >=32768, Maximum Response Code represents a
-    ///   floating-point value as follows:
-
-    ///       0 1 2 3 4 5 6 7 8 9 A B C D E F
-    ///      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    ///      |1| exp |          mant         |
-    ///      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    ///
-    ///   Maximum Response Delay = (mant | 0x1000) << (exp+3)
-    ///
-    /// Which yields the maximum representable value as:
-    ///   8387584 = (0x0FFF | 0x1000) << (7 + 3)
-    ///
-    /// [RFC 3810 section 5.1]: https://datatracker.ietf.org/doc/html/rfc3810#section-5.1
-    fn as_millis(&self) -> u64 {
-        if self.0 < FLOATING_POINT_SWITCH_POINT {
-            self.0.into()
-        } else {
-            let code: u64 = self.0.into();
-            let mant = code & 0x0FFF;
-            let exp = (code >> 12) & 0x07;
-            (mant | 0x1000) << (3 + exp)
-        }
-    }
-
-    /// Makes an `u16` code out of an `u32` value that can be represented as
-    /// a floating point.
-    ///
-    /// The function will always succeed for values within the valid range. However, the code might
-    /// not exactly represent the provided input. E.g. a value of FLOATING_POINT_MAX_VALUE - 1
-    /// cannot be exactly represented with a corresponding code, due the exponential
-    /// representation. However, the function will be able to provide a code representing a value
-    /// close to the provided one.
-    ///
-    /// If stronger guarantees are needed consider using [try_from_millis_exact].
-    ///
-    /// For the conversion definition see [as_millis].
-    // u32 is used as input as is it the first type that fits 8387584.
-    pub fn try_from_millis_lossy(val: u32) -> Result<Self, MldError> {
-        // The max value for [Mldv2ResponseDelay] is 8387584 which smaller than [std::u32::MAX], if
-        // [period] does not fit in u32 it won't fit in [Mldv2ResponseDelay].
-        if val > FLOATING_POINT_MAX_VALUE {
-            Err(MldError::MaxRespCodeOverflow)
-        } else if val < FLOATING_POINT_SWITCH_POINT.into() {
-            // Value is < 32768, unwrapping here is safe.
-            let code = val.try_into().unwrap();
-            Ok(Self(code))
-        } else {
-            let msb = (32 - val.leading_zeros()) - 1;
-            let exp = msb - 12;
-            let mant = (val >> exp) & 0x0FFF;
-            // Unwrap guaranteed by the structure of the built int:
-            let code = (0x8000 | ((exp - 3) << 12) | mant).try_into().unwrap();
-            Ok(Self(code))
-        }
-    }
-
-    /// Makes an `u16` code out of an `u32` value that can be represented as
-    /// a floating point.
-    ///
-    /// The function will succeed only for values within the valid range that can be exactly
-    /// represented by the produced code. E.g. a value of FLOATING_POINT_MAX_VALUE - 1 cannot be
-    /// exactly represented with a corresponding, code due the exponential representation. In
-    /// this case, the function will return an error.
-    ///
-    /// If a lossy conversion can be tolerated consider using [try_from_millis_lossy].
-    ///
-    /// For the conversion definition see [as_millis].
-    pub fn try_from_millis_exact(val: u32) -> Result<Self, MldError> {
-        let res = Self::try_from_millis_lossy(val)?;
-        if res.as_millis() == val.into() {
-            Ok(res)
-        } else {
-            Err(MldError::MaxRespCodeLossyConversion)
-        }
+    fn lossy_try_from(value: Duration) -> Result<Self, MldError> {
+        let millis: u32 =
+            value.as_millis().try_into().map_err(|_| MldError::MaxRespCodeOverflow)?;
+        let code = Self::lossy_try_from_expanded(millis)?;
+        Ok(Self(code))
     }
 }
 
-impl MaxRespCode for Mldv2ResponseDelay {
+impl MaxCode<U16> for Mldv2ResponseDelay {
     fn as_code(self) -> U16 {
         U16::new(self.0)
     }
@@ -531,7 +562,43 @@
 
 impl From<Mldv2ResponseDelay> for Duration {
     fn from(code: Mldv2ResponseDelay) -> Self {
-        Duration::from_millis(code.as_millis())
+        Duration::from_millis(Mldv2ResponseDelay::to_expanded(code.0).into())
+    }
+}
+
+/// QQIC (Querier's Query Interval Code) used in Queryv2 messages, defined in
+/// [RFC 3810 section 5.1.9].
+/// [RFC 3810 section 5.1.9]: https://datatracker.ietf.org/doc/html/rfc3810#section-5.1.9
+#[derive(PartialEq, Eq, Debug, Clone, Copy)]
+pub struct Mldv2QQIC(u8);
+
+impl MaxCode<u8> for Mldv2QQIC {
+    fn as_code(self) -> u8 {
+        self.0
+    }
+
+    fn from_code(code: u8) -> Self {
+        Mldv2QQIC(code)
+    }
+}
+
+impl LinExpConversion<Duration> for Mldv2QQIC {
+    const NUM_MANT_BITS: u8 = 4;
+    const NUM_EXP_BITS: u8 = 3;
+
+    fn lossy_try_from(value: Duration) -> Result<Self, MldError> {
+        let secs: u32 = value.as_secs().try_into().map_err(|_| MldError::MaxRespCodeOverflow)?;
+        let code = Self::lossy_try_from_expanded(secs)?
+            .try_into()
+            .map_err(|_| MldError::MaxRespCodeOverflow)?;
+        Ok(Self(code))
+    }
+}
+
+impl From<Mldv2QQIC> for Duration {
+    fn from(code: Mldv2QQIC) -> Self {
+        let secs: u64 = Mldv2QQIC::to_expanded(code.0.into()).into();
+        Duration::from_secs(secs)
     }
 }
 
@@ -810,27 +877,29 @@
     #[test]
     fn test_mld_parse_and_serialize_response_delay_v2_linear() {
         // Linear code:duration mapping
-        for code in 0..FLOATING_POINT_SWITCH_POINT {
+        for code in 0..(Mldv2ResponseDelay::SWITCHPOINT as u16) {
             let response_delay = Mldv2ResponseDelay::from_code(U16::from(code));
             let duration = Duration::from(response_delay);
             assert_eq!(duration.as_millis(), code.into());
 
+            let duration = Duration::from_millis(code.into());
             let response_delay_code: u16 =
-                Mldv2ResponseDelay::try_from_millis_lossy(code.into()).unwrap().as_code().into();
+                Mldv2ResponseDelay::lossy_try_from(duration).unwrap().as_code().into();
             assert_eq!(response_delay_code, code);
 
+            let duration = Duration::from_millis(code.into());
             let response_delay_code: u16 =
-                Mldv2ResponseDelay::try_from_millis_exact(code.into()).unwrap().as_code().into();
+                Mldv2ResponseDelay::exact_try_from(duration).unwrap().as_code().into();
             assert_eq!(response_delay_code, code);
         }
     }
 
-    #[test_case(FLOATING_POINT_SWITCH_POINT.into(), 0x8000; "min exponential value")]
-    #[test_case(32784,                              0x8002; "exponental value 32784")]
-    #[test_case(227744,                             0xABCD; "exponental value 227744")]
-    #[test_case(1821184,                            0xDBCA; "exponental value 1821184")]
-    #[test_case(8385536,                            0xFFFD; "exponental value 8385536")]
-    #[test_case(FLOATING_POINT_MAX_VALUE.into(),    0xFFFF; "max exponential value")]
+    #[test_case(Mldv2ResponseDelay::SWITCHPOINT, 0x8000; "min exponential value")]
+    #[test_case(32784,                           0x8002; "exponental value 32784")]
+    #[test_case(227744,                          0xABCD; "exponental value 227744")]
+    #[test_case(1821184,                         0xDBCA; "exponental value 1821184")]
+    #[test_case(8385536,                         0xFFFD; "exponental value 8385536")]
+    #[test_case(Mldv2ResponseDelay::MAX_VALUE,   0xFFFF; "max exponential value")]
     fn test_mld_parse_and_serialize_response_delay_v2_exponential_exact(
         duration_millis: u32,
         resp_code: u16,
@@ -840,32 +909,85 @@
         assert_eq!(duration.as_millis(), duration_millis.into());
 
         let response_delay_code: u16 =
-            Mldv2ResponseDelay::try_from_millis_lossy(duration_millis).unwrap().as_code().into();
+            Mldv2ResponseDelay::lossy_try_from(duration).unwrap().as_code().into();
         assert_eq!(response_delay_code, resp_code);
 
         let response_delay_code: u16 =
-            Mldv2ResponseDelay::try_from_millis_exact(duration_millis).unwrap().as_code().into();
+            Mldv2ResponseDelay::exact_try_from(duration).unwrap().as_code().into();
         assert_eq!(response_delay_code, resp_code);
     }
 
     #[test]
     fn test_mld_parse_and_serialize_response_delay_v2_errors() {
-        let duration_millis = FLOATING_POINT_MAX_VALUE + 1;
+        let duration = Duration::from_millis((Mldv2ResponseDelay::MAX_VALUE + 1).into());
         assert_eq!(
-            Mldv2ResponseDelay::try_from_millis_lossy(duration_millis),
+            Mldv2ResponseDelay::lossy_try_from(duration),
             Err(MldError::MaxRespCodeOverflow)
         );
 
-        let duration_millis = FLOATING_POINT_MAX_VALUE + 1;
+        let duration = Duration::from_millis((Mldv2ResponseDelay::MAX_VALUE + 1).into());
         assert_eq!(
-            Mldv2ResponseDelay::try_from_millis_exact(duration_millis),
+            Mldv2ResponseDelay::exact_try_from(duration),
             Err(MldError::MaxRespCodeOverflow)
         );
 
-        let duration_millis = FLOATING_POINT_MAX_VALUE - 1;
+        let duration = Duration::from_millis((Mldv2ResponseDelay::MAX_VALUE - 1).into());
         assert_eq!(
-            Mldv2ResponseDelay::try_from_millis_exact(duration_millis),
+            Mldv2ResponseDelay::exact_try_from(duration),
             Err(MldError::MaxRespCodeLossyConversion)
         );
     }
+
+    #[test]
+    fn test_mld_parse_and_serialize_response_qqic_v2_linear() {
+        // Linear code:duration mapping
+        for code in 0..(Mldv2QQIC::SWITCHPOINT as u8) {
+            let response_delay = Mldv2QQIC::from_code(code);
+            let duration = Duration::from(response_delay);
+            assert_eq!(duration.as_secs(), code.into());
+
+            let duration = Duration::from_secs(code.into());
+            let response_delay_code: u8 =
+                Mldv2QQIC::lossy_try_from(duration).unwrap().as_code().into();
+            assert_eq!(response_delay_code, code);
+
+            let duration = Duration::from_secs(code.into());
+            let response_delay_code: u8 =
+                Mldv2QQIC::exact_try_from(duration).unwrap().as_code().into();
+            assert_eq!(response_delay_code, code);
+        }
+    }
+
+    #[test_case(Mldv2QQIC::SWITCHPOINT, 0x80; "min exponential value")]
+    #[test_case(144,                    0x82; "exponental value 144")]
+    #[test_case(928,                    0xAD; "exponental value 928")]
+    #[test_case(6656,                   0xDA; "exponental value 6656")]
+    #[test_case(29696,                  0xFD; "exponental value 29696")]
+    #[test_case(Mldv2QQIC::MAX_VALUE,   0xFF; "max exponential value")]
+    fn test_mld_parse_and_serialize_response_qqic_v2_exponential_exact(
+        duration_secs: u32,
+        resp_code: u8,
+    ) {
+        let response_delay = Mldv2QQIC::from_code(resp_code.into());
+        let duration = Duration::from(response_delay);
+        assert_eq!(duration.as_secs(), duration_secs.into());
+
+        let response_delay_code: u8 = Mldv2QQIC::lossy_try_from(duration).unwrap().as_code().into();
+        assert_eq!(response_delay_code, resp_code);
+
+        let response_delay_code: u8 = Mldv2QQIC::exact_try_from(duration).unwrap().as_code().into();
+        assert_eq!(response_delay_code, resp_code);
+    }
+
+    #[test]
+    fn test_mld_parse_and_serialize_response_qqic_v2_errors() {
+        let duration = Duration::from_secs((Mldv2QQIC::MAX_VALUE + 1).into());
+        assert_eq!(Mldv2QQIC::lossy_try_from(duration), Err(MldError::MaxRespCodeOverflow));
+
+        let duration = Duration::from_secs((Mldv2QQIC::MAX_VALUE + 1).into());
+        assert_eq!(Mldv2QQIC::exact_try_from(duration), Err(MldError::MaxRespCodeOverflow));
+
+        let duration = Duration::from_secs((Mldv2QQIC::MAX_VALUE - 1).into());
+        assert_eq!(Mldv2QQIC::exact_try_from(duration), Err(MldError::MaxRespCodeLossyConversion));
+    }
 }
diff --git a/src/connectivity/lowpan/drivers/lowpan-ot-driver/src/driver/border_agent.rs b/src/connectivity/lowpan/drivers/lowpan-ot-driver/src/driver/border_agent.rs
index 693381b..8e641b74 100644
--- a/src/connectivity/lowpan/drivers/lowpan-ot-driver/src/driver/border_agent.rs
+++ b/src/connectivity/lowpan/drivers/lowpan-ot-driver/src/driver/border_agent.rs
@@ -282,7 +282,7 @@
 
             if let Some(task) = original_task {
                 // We must wait for the original task to fully stop.
-                if let Err(err) = task.cancel().await.transpose() {
+                if let Err(err) = task.cancel().transpose() {
                     warn!(tag="meshcop","update_border_agent_service: Previous publication task ended with an error: {:?}", err);
                 }
             }
@@ -293,7 +293,7 @@
                 .border_agent_service
                 .lock()
                 .replace(fasync::Task::spawn(task))
-                .and_then(|x| x.cancel().now_or_never().flatten())
+                .and_then(|x| x.cancel())
                 .transpose()
             {
                 warn!(tag="meshcop","update_border_agent_service: Previous publication task ended with an error: {:?}", err);
diff --git a/src/connectivity/lowpan/lib/openthread_fuchsia/src/backing/alarm.rs b/src/connectivity/lowpan/lib/openthread_fuchsia/src/backing/alarm.rs
index 548df0e..e5d82ca 100644
--- a/src/connectivity/lowpan/lib/openthread_fuchsia/src/backing/alarm.rs
+++ b/src/connectivity/lowpan/lib/openthread_fuchsia/src/backing/alarm.rs
@@ -96,10 +96,7 @@
         // The receiver end of the channel is being serviced by Platform::process_poll,
         // which makes sure that the timer callback gets fired on the main
         // thread. The previous alarm task, if any, is cancelled.
-        if let Some(old_task) = self.task_alarm.replace(Some(fasync::Task::spawn(future))) {
-            // Cancel the previous/old alarm task, if any.
-            old_task.cancel().now_or_never();
-        }
+        self.task_alarm.set(Some(fasync::Task::spawn(future)));
     }
 
     fn on_alarm_milli_stop(&self, _instance: Option<&ot::Instance>) {
@@ -113,11 +110,8 @@
             )
         }
 
-        if let Some(old_task) = self.task_alarm.take() {
+        if self.task_alarm.take().is_some() {
             trace!(tag = "alarm", "on_alarm_milli_stop: Alarm cancelled");
-
-            // Cancel the previous/old alarm task, if any.
-            old_task.cancel().now_or_never();
         }
     }
 
diff --git a/src/connectivity/network/BUILD.gn b/src/connectivity/network/BUILD.gn
index c95cb97..1c1f0d3 100644
--- a/src/connectivity/network/BUILD.gn
+++ b/src/connectivity/network/BUILD.gn
@@ -106,6 +106,21 @@
   deps = [ "drivers/network-device" ]
 }
 
+group("benchmarks") {
+  testonly = true
+  deps = [
+    "drivers/network-device/device:benchmarks",
+    "netstack3:benchmarks",
+    "tests/benchmarks",
+  ]
+}
+
+group("e2e_tests") {
+  testonly = true
+
+  deps = [ "//src/connectivity/network/testing/conformance/emulator:e2e_tests" ]
+}
+
 group("tests") {
   testonly = true
   deps = [
diff --git a/src/connectivity/network/drivers/network-device/device/device_interface.cc b/src/connectivity/network/drivers/network-device/device/device_interface.cc
index 03078b6..20b0962 100644
--- a/src/connectivity/network/drivers/network-device/device/device_interface.cc
+++ b/src/connectivity/network/drivers/network-device/device/device_interface.cc
@@ -115,17 +115,6 @@
   binder_ptr->Teardown([binder = std::move(binder)]() mutable { binder.reset(); });
 }
 
-// Helper to call event hooks (represented by a fit::function or anything that has the same share
-// behavior) while ensuring that the event is kept alive throughout the invocation of the event
-// handler. This allows event handlers to re-assign the same event handler during invocation.
-// Otherwise the handler would be destroyed during its own invocation which could result in attempts
-// to access invalid state in the event handler, such as captures.
-template <typename Event, typename... Args>
-auto TriggerEvent(Event& event, Args&&... args) {
-  auto shared_event = event.share();
-  return event(std::forward<Args>(args)...);
-}
-
 }  // namespace
 
 namespace network {
@@ -822,9 +811,7 @@
     control_lock_.Release();
   }
 
-  if (evt_session_started_) {
-    TriggerEvent(evt_session_started_, session.name());
-  }
+  evt_session_started_.Trigger(session.name());
 }
 
 bool DeviceInterface::SessionStoppedInner(Session& session) {
@@ -1365,9 +1352,7 @@
           const std::string session_name = session.name();
           control_lock_.Acquire();
           dead_sessions_.erase(session);
-          if (evt_session_died_) {
-            TriggerEvent(evt_session_died_, session_name.c_str());
-          }
+          evt_session_died_.Trigger(session_name.c_str());
           ContinueTeardown(TeardownState::SESSIONS);
         });
       });
@@ -1462,17 +1447,9 @@
   return ZX_OK;
 }
 
-void DeviceInterface::NotifyRxQueuePacket(uint64_t key) {
-  if (evt_rx_queue_packet_) {
-    TriggerEvent(evt_rx_queue_packet_, key);
-  }
-}
+void DeviceInterface::NotifyRxQueuePacket(uint64_t key) { evt_rx_queue_packet_.Trigger(key); }
 
-void DeviceInterface::NotifyTxComplete() {
-  if (evt_tx_complete_) {
-    TriggerEvent(evt_tx_complete_);
-  }
-}
+void DeviceInterface::NotifyTxComplete() { evt_tx_complete_.Trigger(); }
 
 DeviceInterface::DeviceInterface(const DeviceInterfaceDispatchers& dispatchers)
     : dispatchers_(dispatchers),
diff --git a/src/connectivity/network/drivers/network-device/device/device_interface.h b/src/connectivity/network/drivers/network-device/device/device_interface.h
index c7f92dd..c1b565c 100644
--- a/src/connectivity/network/drivers/network-device/device/device_interface.h
+++ b/src/connectivity/network/drivers/network-device/device/device_interface.h
@@ -13,6 +13,7 @@
 #include "definitions.h"
 #include "device_port.h"
 #include "diagnostics_service.h"
+#include "event_hook.h"
 #include "port_watcher.h"
 #include "public/locks.h"
 #include "public/network_device.h"
@@ -337,11 +338,11 @@
   SharedLock control_lock_ __TA_ACQUIRED_AFTER(tx_lock_, rx_lock_);
 
   // Event hooks used in tests:
-  fit::function<void(const char*)> evt_session_started_;
+  EventHook<fit::function<void(const char*)>> evt_session_started_;
   // NB: This will be called with control_lock_ held.
-  fit::function<void(const char*)> evt_session_died_;
-  fit::function<void(uint64_t)> evt_rx_queue_packet_;
-  fit::function<void()> evt_tx_complete_;
+  EventHook<fit::function<void(const char*)>> evt_session_died_;
+  EventHook<fit::function<void(uint64_t)>> evt_rx_queue_packet_;
+  EventHook<fit::function<void()>> evt_tx_complete_;
 };
 
 }  // namespace network::internal
diff --git a/src/connectivity/network/drivers/network-device/device/event_hook.h b/src/connectivity/network/drivers/network-device/device/event_hook.h
new file mode 100644
index 0000000..6d4d510
--- /dev/null
+++ b/src/connectivity/network/drivers/network-device/device/event_hook.h
@@ -0,0 +1,74 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_EVENT_HOOK_H_
+#define SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_EVENT_HOOK_H_
+
+#include <atomic>
+#include <utility>
+
+#include <fbl/auto_lock.h>
+#include <fbl/mutex.h>
+
+namespace network::internal {
+
+// An event hook class used to install event hooks for testing purposes. A hook is represented by a
+// fit::function (or any other callable that allows sharing). For example:
+//
+//   EventHook<fit::function<void (SomeParam*)>> some_param_event_;
+//
+// To install a hook, do:
+//
+//   some_param_event_.Set([](SomeParam* param) { InspectParam(param); });
+//
+// And the code that triggers the event would look like this:
+//
+//   some_param_event_.Trigger(&param);
+//
+// The call to Trigger will efficiently (without locks) return early if no event hook has been
+// installed.
+template <typename Function>
+class EventHook {
+ public:
+  void Set(Function&& function) {
+    fbl::AutoLock lock(&lock_);
+    function_ = std::move(function);
+    is_set_ = static_cast<bool>(function_);
+  }
+
+  // The event hook is currently limited in that return values from the function will be ignored.
+  // This is because the call to Trigger has to be able to return if the handler is no longer valid.
+  // There is currently no need for return types so to make things easy Trigger just returns void.
+  template <typename... Args>
+  void Trigger(Args... args) {
+    if (!is_set_.load(std::memory_order_relaxed)) {
+      return;
+    }
+    Function function;
+    {
+      fbl::AutoLock lock(&lock_);
+      // Check again, because we didn't hold the lock when checking is_set_ the function could have
+      // disappeared by now.
+      if (!function_) {
+        return;
+      }
+      // Ensure that the function is kept alive for the entire call in case the function re-sets or
+      // clears its own event hook. This also allows the function to be called without holding the
+      // lock.
+      function = function_.share();
+    }
+    // At this point function has to be valid. The check in the lock scope should return otherwise.
+    function(std::forward<Args>(args)...);
+  }
+
+ private:
+  Function function_ __TA_GUARDED(lock_);
+  // is_set_ exists to allow for IsSet checks without having to acquire the lock.
+  std::atomic<bool> is_set_ = false;
+  fbl::Mutex lock_;
+};
+
+}  // namespace network::internal
+
+#endif  // SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_EVENT_HOOK_H_
diff --git a/src/connectivity/network/drivers/network-device/device/mac_addr_shim.cc b/src/connectivity/network/drivers/network-device/device/mac_addr_shim.cc
index fbe86b2..4914efd 100644
--- a/src/connectivity/network/drivers/network-device/device/mac_addr_shim.cc
+++ b/src/connectivity/network/drivers/network-device/device/mac_addr_shim.cc
@@ -6,14 +6,13 @@
 
 namespace network {
 
-void MacAddrShim::Bind(fdf_dispatcher_t* dispatcher, ddk::MacAddrProtocolClient client_impl,
-                       fdf::ServerEnd<netdriver::MacAddr> server_end) {
-  std::unique_ptr impl = std::make_unique<MacAddrShim>(client_impl);
-
-  fdf::BindServer(dispatcher, std::move(server_end), std::move(impl));
-}
-
-MacAddrShim::MacAddrShim(ddk::MacAddrProtocolClient impl) : impl_(impl) {}
+MacAddrShim::MacAddrShim(fdf_dispatcher_t* dispatcher, ddk::MacAddrProtocolClient client_impl,
+                         fdf::ServerEnd<netdriver::MacAddr> server_end,
+                         fit::callback<void(MacAddrShim*)>&& on_unbound)
+    : impl_(client_impl),
+      on_unbound_(std::move(on_unbound)),
+      binding_(dispatcher, std::move(server_end), this,
+               std::mem_fn(&MacAddrShim::OnMacAddrUnbound)) {}
 
 void MacAddrShim::SetMode(netdriver::wire::MacAddrSetModeRequest* request, fdf::Arena& arena,
                           SetModeCompleter::Sync& completer) {
@@ -49,4 +48,10 @@
   completer.buffer(arena).Reply(mac);
 }
 
+void MacAddrShim::OnMacAddrUnbound(fidl::UnbindInfo info) {
+  if (on_unbound_) {
+    on_unbound_(this);
+  }
+}
+
 }  // namespace network
diff --git a/src/connectivity/network/drivers/network-device/device/mac_addr_shim.h b/src/connectivity/network/drivers/network-device/device/mac_addr_shim.h
index fb997ac..0df04d2 100644
--- a/src/connectivity/network/drivers/network-device/device/mac_addr_shim.h
+++ b/src/connectivity/network/drivers/network-device/device/mac_addr_shim.h
@@ -8,7 +8,7 @@
 #include <fidl/fuchsia.hardware.network.driver/cpp/driver/wire.h>
 #include <fuchsia/hardware/network/driver/cpp/banjo.h>
 
-#include <optional>
+#include <fbl/intrusive_double_list.h>
 
 namespace network {
 
@@ -20,12 +20,12 @@
 // port speaks FIDL. This type translates calls from from netdevice into the parent from FIDL to
 // Banjo. The MacAddr protocol does not have corresponding Ifc protocol in the other direction so
 // this type only needs to work in one direction.
-class MacAddrShim : public fdf::WireServer<netdriver::MacAddr> {
+class MacAddrShim : public fdf::WireServer<netdriver::MacAddr>,
+                    public fbl::DoublyLinkedListable<std::unique_ptr<MacAddrShim>> {
  public:
-  static void Bind(fdf_dispatcher_t* dispatcher, ddk::MacAddrProtocolClient client_impl,
-                   fdf::ServerEnd<netdriver::MacAddr> server_end);
-
-  explicit MacAddrShim(ddk::MacAddrProtocolClient impl);
+  MacAddrShim(fdf_dispatcher_t* dispatcher, ddk::MacAddrProtocolClient client_impl,
+              fdf::ServerEnd<netdriver::MacAddr> server_end,
+              fit::callback<void(MacAddrShim*)>&& on_unbound);
 
   void SetMode(netdriver::wire::MacAddrSetModeRequest* request, fdf::Arena& arena,
                SetModeCompleter::Sync& completer) override;
@@ -33,7 +33,11 @@
   void GetAddress(fdf::Arena& arena, GetAddressCompleter::Sync& completer) override;
 
  private:
+  void OnMacAddrUnbound(fidl::UnbindInfo info);
+
   ddk::MacAddrProtocolClient impl_;
+  fit::callback<void(MacAddrShim*)> on_unbound_;
+  fdf::ServerBinding<netdriver::MacAddr> binding_;
 };
 
 }  // namespace network
diff --git a/src/connectivity/network/drivers/network-device/device/network_device-test.cc b/src/connectivity/network/drivers/network-device/device/network_device-test.cc
index 9c87096..b046ee0 100644
--- a/src/connectivity/network/drivers/network-device/device/network_device-test.cc
+++ b/src/connectivity/network/drivers/network-device/device/network_device-test.cc
@@ -238,8 +238,15 @@
     // RX queue, AFTER NetworkDeviceImpl::Start has replied with its completer.
     impl_.SetOnStart([this] {
       SetEvtRxQueuePacketHandler([this](uint64_t key) {
-        SetEvtRxQueuePacketHandler(nullptr);
-        impl_.events().signal(0, kEventStartCompleted);
+        // It's possible to encounter a kSessionSwitchKey packet here depending on scheduling. That
+        // packet is queued before Start is called but may not be processed until after Start has
+        // come to this point. Ignore the kSessionSwitchKey and only signal completion on the
+        // kTriggerRxKey packet as that is what actually signals that the RX queue is ready. And
+        // that is the packet we need to consume to ensure it doesn't interfere with the tests.
+        if (key == internal::RxQueue::kTriggerRxKey) {
+          SetEvtRxQueuePacketHandler(nullptr);
+          impl_.events().signal(0, kEventStartCompleted);
+        }
       });
     });
 
@@ -294,11 +301,11 @@
   }
 
   void SetEvtRxQueuePacketHandler(fit::function<void(uint64_t)> h) {
-    static_cast<internal::DeviceInterface*>(device_.get())->evt_rx_queue_packet_ = std::move(h);
+    static_cast<internal::DeviceInterface*>(device_.get())->evt_rx_queue_packet_.Set(std::move(h));
   }
 
   void SetEvtTxCompleteHandler(fit::function<void()> h) {
-    static_cast<internal::DeviceInterface*>(device_.get())->evt_tx_complete_ = std::move(h);
+    static_cast<internal::DeviceInterface*>(device_.get())->evt_tx_complete_.Set(std::move(h));
   }
 
   void SetBacktraceCallback(fit::function<void()> cb) {
@@ -306,6 +313,25 @@
     dev->diagnostics().trigger_stack_trace_ = std::move(cb);
   }
 
+  // Create an RX queue packet event handler that will signal a completion once the RX queue has
+  // been triggered. The completion is created and owned by the handler and a pointer to the
+  // completion will be placed in the |out_completion| parameter. This ensures that even if the
+  // event handler is called after the test has gone out of scope or as the event handler is being
+  // reset it will not attempt to use a completion stored on the stack of the test.
+  fit::function<void(uint64_t)> CreateTriggerRxHandler(libsync::Completion** out_completion) {
+    std::unique_ptr completion = std::make_unique<libsync::Completion>();
+    *out_completion = completion.get();
+    return [completion = std::move(completion)](uint64_t key) {
+      // Ignore any kFifoWatchKey events as they may occur before the kTriggerRxKey event when
+      // completing RX buffers.
+      if (key == internal::RxQueue::kFifoWatchKey) {
+        return;
+      }
+      EXPECT_EQ(key, internal::RxQueue::kTriggerRxKey);
+      completion->Signal();
+    };
+  }
+
  protected:
   fdf_testing::DriverRuntime driver_runtime_;
   fdf::UnsynchronizedDispatcher impl_dispatcher_;
@@ -575,14 +601,11 @@
   // Ensure no more rx buffers were actually returned:
   ASSERT_TRUE(buffers.is_empty());
 
-  libsync::Completion completion;
-  SetEvtRxQueuePacketHandler([&completion](uint64_t key) {
-    ASSERT_EQ(key, internal::RxQueue::kTriggerRxKey);
-    completion.Signal();
-  });
+  libsync::Completion* completion = nullptr;
+  SetEvtRxQueuePacketHandler(CreateTriggerRxHandler(&completion));
   //  Commit the returned buffers.
   return_session.Commit();
-  ASSERT_OK(completion.Wait(TEST_DEADLINE));
+  ASSERT_OK(completion->Wait(TEST_DEADLINE));
   SetEvtRxQueuePacketHandler(nullptr);
 
   // Check that all descriptors were returned to the queue:
@@ -881,13 +904,10 @@
     ASSERT_OK(buff->WriteData(data, vmo_provider));
     return_session.Enqueue(std::move(buff), kPort13);
   }
-  libsync::Completion completion;
-  SetEvtRxQueuePacketHandler([&completion](uint64_t key) {
-    EXPECT_EQ(key, internal::RxQueue::kTriggerRxKey);
-    completion.Signal();
-  });
+  libsync::Completion* completion = nullptr;
+  SetEvtRxQueuePacketHandler(CreateTriggerRxHandler(&completion));
   return_session.Commit();
-  ASSERT_OK(completion.Wait(TEST_DEADLINE));
+  ASSERT_OK(completion->Wait(TEST_DEADLINE));
   SetEvtRxQueuePacketHandler(nullptr);
 
   auto checker = [kBufferCount, kDataLen](TestSession& session) {
@@ -1201,6 +1221,7 @@
   TestSession session;
   ASSERT_OK(OpenSession(&session));
   ASSERT_OK(AttachSessionPort(session, port13_));
+  ASSERT_OK(WaitStart());
   session.ZeroVmo();
   const netdev::wire::PortId port13_id = GetSaltedPortId(kPort13);
   {
@@ -1824,13 +1845,10 @@
   {
     RxFidlReturnTransaction transaction(&impl_);
     transaction.Enqueue(std::move(ret));
-    libsync::Completion completion;
-    SetEvtRxQueuePacketHandler([&completion](uint64_t key) {
-      EXPECT_EQ(key, internal::RxQueue::kTriggerRxKey);
-      completion.Signal();
-    });
+    libsync::Completion* completion = nullptr;
+    SetEvtRxQueuePacketHandler(CreateTriggerRxHandler(&completion));
     transaction.Commit();
-    ASSERT_OK(completion.Wait(TEST_DEADLINE));
+    ASSERT_OK(completion->Wait(TEST_DEADLINE));
     SetEvtRxQueuePacketHandler(nullptr);
   }
 
@@ -2708,6 +2726,7 @@
     }
     ASSERT_OK(AttachSessionPort(s.session, port13_));
   }
+  ASSERT_OK(WaitStart());
 
   ASSERT_OK(WaitRxAvailable());
   RxFidlReturnTransaction txn(&impl_);
@@ -2728,13 +2747,10 @@
     };
     txn.Enqueue(std::move(rx_space), kPort13);
   }
-  libsync::Completion completion;
-  SetEvtRxQueuePacketHandler([&completion](uint64_t key) {
-    EXPECT_EQ(key, internal::RxQueue::kTriggerRxKey);
-    completion.Signal();
-  });
+  libsync::Completion* completion = nullptr;
+  SetEvtRxQueuePacketHandler(CreateTriggerRxHandler(&completion));
   txn.Commit();
-  ASSERT_OK(completion.Wait(TEST_DEADLINE));
+  ASSERT_OK(completion->Wait(TEST_DEADLINE));
 
   SetEvtRxQueuePacketHandler(nullptr);
 
@@ -2790,6 +2806,7 @@
   ASSERT_OK(OpenSession(&listen, netdev::wire::SessionFlags::kListenTx, kDefaultDescriptorCount,
                         kDefaultBufferLength, "listen"));
   ASSERT_OK(AttachSessionPort(listen, port13_));
+  ASSERT_OK(WaitStart());
 
   constexpr uint32_t kRxDescriptorLen = 30;
   constexpr uint16_t kRxDescriptorCount = 3;
@@ -2930,6 +2947,7 @@
   TestSession session;
   ASSERT_OK(OpenSession(&session));
   ASSERT_OK(AttachSessionPort(session, port13_));
+  ASSERT_OK(WaitStart());
   session.ResetDescriptor(kDescriptorIndex0);
   ASSERT_OK(session.SendRx(kDescriptorIndex0));
   ASSERT_OK(WaitRxAvailable());
@@ -3059,6 +3077,7 @@
   TestSession session;
   ASSERT_OK(OpenSession(&session));
   ASSERT_OK(AttachSessionPort(session, port13_));
+  ASSERT_OK(WaitStart());
 
   zx::result port = OpenPort(kPort13);
   ASSERT_OK(port.status_value());
@@ -3085,15 +3104,12 @@
     return std::make_unique<RxFidlReturn>(std::move(buffer), kPort13);
   };
 
-  libsync::Completion rx_event;
-  SetEvtRxQueuePacketHandler([&rx_event](uint64_t key) {
-    ASSERT_EQ(key, internal::RxQueue::kTriggerRxKey);
-    rx_event.Signal();
-  });
+  libsync::Completion* rx_event = nullptr;
+  SetEvtRxQueuePacketHandler(CreateTriggerRxHandler(&rx_event));
 
-  auto wait_for_rx = [&rx_event] {
-    rx_event.Wait();
-    rx_event.Reset();
+  auto wait_for_rx = [rx_event] {
+    rx_event->Wait();
+    rx_event->Reset();
   };
 
   auto assert_counters = [&port_connection](uint64_t frames, uint64_t bytes,
@@ -3151,6 +3167,7 @@
   TestSession session;
   ASSERT_OK(OpenSession(&session));
   ASSERT_OK(AttachSessionPort(session, port13_));
+  ASSERT_OK(WaitStart());
 
   zx::result port = OpenPort(kPort13);
   ASSERT_OK(port.status_value());
@@ -3256,6 +3273,7 @@
   TestSession session;
   ASSERT_OK(OpenSession(&session));
   ASSERT_OK(AttachSessionPort(session, port13_));
+  ASSERT_OK(WaitStart());
 
   std::array<TestSession, MAX_VMOS - 1> idle_sessions;
 
@@ -3507,5 +3525,34 @@
   ASSERT_OK(mac.status());
 }
 
+TEST_F(NetworkDeviceShimTest, TeardownAndThenPortClientUnbinds) {
+  // Verify asynchronous Teardown when a port client is still bound during the teardown call and
+  // later unbound.
+  ASSERT_OK(InitImpl());
+
+  fdf::WireSyncClient<netdriver::NetworkPort> port_client;
+  ifc_.add_port_ = [&](netdriver::wire::NetworkDeviceIfcAddPortRequest* request, fdf::Arena& arena,
+                       FakeNetworkDeviceIfc::AddPortCompleter::Sync& completer) {
+    port_client.Bind(std::move(request->port));
+    completer.buffer(arena).Reply(ZX_OK);
+  };
+
+  banjo::FakeNetworkPortImpl port;
+  auto port_proto = port.protocol();
+  ASSERT_OK(AddPortSync(12, &port_proto));
+
+  fdf::Arena arena('NETD');
+  auto mac = port_client.buffer(arena)->GetMac();
+  ASSERT_OK(mac.status());
+
+  libsync::Completion teardown_complete;
+  ASSERT_EQ(shim_->Teardown([&] { teardown_complete.Signal(); }),
+            NetworkDeviceImplBinder::Synchronicity::Async);
+  ASSERT_FALSE(teardown_complete.signaled());
+  // Unbinding the client (by destroying it) should trigger port removal and complete the teardown.
+  port_client = {};
+  teardown_complete.Wait();
+}
+
 }  // namespace testing
 }  // namespace network
diff --git a/src/connectivity/network/drivers/network-device/device/network_device_shim.cc b/src/connectivity/network/drivers/network-device/device/network_device_shim.cc
index bdb4508..3e46527 100644
--- a/src/connectivity/network/drivers/network-device/device/network_device_shim.cc
+++ b/src/connectivity/network/drivers/network-device/device/network_device_shim.cc
@@ -12,7 +12,6 @@
 #include <fbl/auto_lock.h>
 
 #include "log.h"
-#include "network_port_shim.h"
 
 namespace network {
 
@@ -29,48 +28,62 @@
     return endpoints.take_error();
   }
   {
-    fbl::AutoLock lock(&binding_lock_);
+    fbl::AutoLock lock(&lock_);
     binding_ = fdf::BindServer(dispatchers_.shim_->get(), std::move(endpoints->server), this,
                                [this](NetworkDeviceShim*, fidl::UnbindInfo info,
                                       fdf::ServerEnd<netdriver::NetworkDeviceImpl>) {
-                                 // It's not safe to hold the lock during the call to
-                                 // on_teardown_complete_. The NetworkDeviceShim could potentially
-                                 // be deleted in the callback which would mean that when the
-                                 // autolock destructs and tries to unlock the mutex the mutex has
-                                 // already been destroyed. Instead move the callback to a local
-                                 // variable and use that if available.
-                                 fit::callback<void()> on_teardown_complete;
-                                 {
-                                   fbl::AutoLock lock(&binding_lock_);
-                                   binding_.reset();
-                                   on_teardown_complete = std::move(on_teardown_complete_);
-                                 }
-                                 if (on_teardown_complete) {
-                                   on_teardown_complete();
-                                 }
+                                 lock_.Acquire();
+                                 binding_.reset();
+                                 MaybeFinishTeardown();
                                });
   }
   return zx::ok(std::move(endpoints->client));
 }
 
+NetworkDeviceShim::~NetworkDeviceShim() {
+  ZX_ASSERT_MSG(!binding_.has_value(), "NetworkDeviceShim destroyed before server unbound");
+  ZX_ASSERT_MSG(network_port_shims_.is_empty(),
+                "NetworkDeviceShim destroyed before all port shims destroyed");
+}
+
 NetworkDeviceImplBinder::Synchronicity NetworkDeviceShim::Teardown(
     fit::callback<void()>&& on_teardown_complete) {
-  fbl::AutoLock lock(&binding_lock_);
-  if (binding_.has_value()) {
+  fbl::AutoLock lock(&lock_);
+  if (binding_.has_value() || !network_port_shims_.is_empty()) {
     ZX_ASSERT(!on_teardown_complete_);
+    // When Teardown is called all ports should already be removed or be in the process of being
+    // removed. All that needs to be done is store the callback and unbind the server.
     on_teardown_complete_ = std::move(on_teardown_complete);
-    // Make sure that unbinding happens asynchronously. Because the shim dispatchers are created
-    // with an owner that's separate from the dispatcher that calls this method there is a chance
-    // that the unbinding could get inlined if called directly. The FIDL part of the unbinding will
-    // deadlock if that happens.
-    async::PostTask(dispatchers_.shim_->async_dispatcher(),
-                    [binding = std::move(binding_)]() mutable { binding->Unbind(); });
+    if (binding_.has_value()) {
+      // Make sure that unbinding happens asynchronously. Because the shim dispatchers are created
+      // with an owner that's separate from the dispatcher that calls this method there is a chance
+      // that the unbinding could get inlined if called directly. The FIDL part of the unbinding
+      // will deadlock if that happens.
+      async::PostTask(dispatchers_.shim_->async_dispatcher(),
+                      [binding = std::move(binding_)]() mutable { binding->Unbind(); });
+    }
     return Synchronicity::Async;
   }
   // Nothing to tear down, completed synchronously.
   return Synchronicity::Sync;
 }
 
+void NetworkDeviceShim::MaybeFinishTeardown() {
+  // It's not safe to hold the lock during the call to on_teardown_complete_. The NetworkDeviceShim
+  // could potentially be deleted in the callback which would mean that when the autolock destructs
+  // and tries to unlock the mutex the mutex has already been destroyed. Instead move the callback
+  // to a local variable and use that if available.
+  fit::callback<void()> on_teardown_complete;
+  if (on_teardown_complete_ && !binding_.has_value() && network_port_shims_.is_empty()) {
+    // Everything is torn down, tear down is complete.
+    on_teardown_complete = std::move(on_teardown_complete_);
+  }
+  lock_.Release();
+  if (on_teardown_complete) {
+    on_teardown_complete();
+  }
+}
+
 void NetworkDeviceShim::Init(netdriver::wire::NetworkDeviceImplInitRequest* request,
                              fdf::Arena& arena, InitCompleter::Sync& completer) {
   device_ifc_ = fdf::WireSharedClient<netdriver::NetworkDeviceIfc>(std::move(request->iface),
@@ -289,16 +302,6 @@
                                                 const network_port_protocol_t* port,
                                                 network_device_ifc_add_port_callback callback,
                                                 void* cookie) {
-  ddk::NetworkPortProtocolClient impl(port);
-  zx::result endpoints = fdf::CreateEndpoints<netdriver::NetworkPort>();
-  if (endpoints.is_error()) {
-    LOGF_ERROR("failed to create endpoints: %s", endpoints.status_string());
-    callback(cookie, ZX_ERR_NO_RESOURCES);
-    return;
-  }
-
-  NetworkPortShim::Bind(impl, dispatchers_.port_->get(), std::move(endpoints->server));
-
   if (!device_ifc_.is_valid()) {
     LOGF_ERROR("invalid device interface, adding port before Init called?");
     callback(cookie, ZX_ERR_BAD_STATE);
@@ -310,24 +313,51 @@
     return;
   }
 
-  fdf::Arena arena('NETD');
-  device_ifc_.buffer(arena)
-      ->AddPort(port_id, std::move(endpoints->client))
-      .Then([callback, cookie](auto& result) {
-        if (!result.ok()) {
-          LOGF_ERROR("AddPort failed: %s", result.FormatDescription().c_str());
-          callback(cookie, result.status());
-        } else {
-          callback(cookie, result.value().status);
-        }
-      });
+  // The NetworkPortShim constructor has to run on the same dispatcher that it's binding to. The
+  // binding object in the port only allows access from that one dispatcher.
+  async::PostTask(dispatchers_.port_->async_dispatcher(), [callback, cookie, port = *port, port_id,
+                                                           this]() mutable {
+    zx::result endpoints = fdf::CreateEndpoints<netdriver::NetworkPort>();
+    if (endpoints.is_error()) {
+      LOGF_ERROR("failed to create endpoints: %s", endpoints.status_string());
+      callback(cookie, ZX_ERR_NO_RESOURCES);
+      return;
+    }
+
+    ddk::NetworkPortProtocolClient impl(&port);
+    std::unique_ptr port_shim = std::make_unique<NetworkPortShim>(
+        impl, dispatchers_.port_->get(), std::move(endpoints->server),
+        [this](NetworkPortShim* port_shim) {
+          lock_.Acquire();
+          network_port_shims_.erase(*port_shim);
+          MaybeFinishTeardown();
+        });
+
+    fdf::Arena arena('NETD');
+    device_ifc_.buffer(arena)
+        ->AddPort(port_id, std::move(endpoints->client))
+        .Then([callback, cookie, this, port_shim = std::move(port_shim)](auto& result) mutable {
+          if (!result.ok()) {
+            LOGF_ERROR("AddPort failed: %s", result.FormatDescription().c_str());
+            callback(cookie, result.status());
+          } else if (result.value().status != ZX_OK) {
+            callback(cookie, result.value().status);
+          } else {
+            {
+              fbl::AutoLock lock(&lock_);
+              network_port_shims_.push_front(std::move(port_shim));
+            }
+            callback(cookie, ZX_OK);
+          }
+        });
+  });
 }
 
 void NetworkDeviceShim::NetworkDeviceIfcRemovePort(uint8_t port_id) {
   fdf::Arena arena('NETD');
   fidl::OneWayStatus status = device_ifc_.buffer(arena)->RemovePort(port_id);
   if (!status.ok()) {
-    LOGF_ERROR("PortStatusChanged error: %s", status.status_string());
+    LOGF_ERROR("RemovePort error: %s", status.status_string());
   }
 }
 
@@ -395,7 +425,8 @@
 }
 
 void NetworkDeviceShim::NetworkDeviceIfcSnoop(const rx_buffer_t* rx_list, size_t rx_count) {
-  // TODO(https://fxbug.dev/42119287): Not implemented in netdev, implement here as well when needed.
+  // TODO(https://fxbug.dev/42119287): Not implemented in netdev, implement here as well when
+  // needed.
 }
 
 }  // namespace network
diff --git a/src/connectivity/network/drivers/network-device/device/network_device_shim.h b/src/connectivity/network/drivers/network-device/device/network_device_shim.h
index b3cdbba..32ffdd3 100644
--- a/src/connectivity/network/drivers/network-device/device/network_device_shim.h
+++ b/src/connectivity/network/drivers/network-device/device/network_device_shim.h
@@ -10,8 +10,10 @@
 
 #include <optional>
 
+#include <fbl/intrusive_double_list.h>
 #include <fbl/mutex.h>
 
+#include "network_port_shim.h"
 #include "public/network_device.h"
 
 namespace network {
@@ -28,6 +30,7 @@
                           public NetworkDeviceImplBinder {
  public:
   NetworkDeviceShim(ddk::NetworkDeviceImplProtocolClient impl, const ShimDispatchers& dispatchers);
+  ~NetworkDeviceShim() override;
 
   // NetworkDeviceImplBinder implementation
   zx::result<fdf::ClientEnd<netdriver::NetworkDeviceImpl>> Bind() override;
@@ -60,11 +63,15 @@
   void NetworkDeviceIfcSnoop(const rx_buffer_t* rx_list, size_t rx_count);
 
  private:
+  using NetworkPortShimList = fbl::SizedDoublyLinkedList<std::unique_ptr<NetworkPortShim>>;
+
+  void MaybeFinishTeardown() __TA_REQUIRES(lock_) __TA_RELEASE(lock_);
+
   ddk::NetworkDeviceImplProtocolClient impl_;
-  std::optional<fdf::ServerBindingRef<netdriver::NetworkDeviceImpl>> binding_
-      __TA_GUARDED(binding_lock_);
-  fit::callback<void()> on_teardown_complete_ __TA_GUARDED(binding_lock_);
-  fbl::Mutex binding_lock_;
+  std::optional<fdf::ServerBindingRef<netdriver::NetworkDeviceImpl>> binding_ __TA_GUARDED(lock_);
+  fit::callback<void()> on_teardown_complete_ __TA_GUARDED(lock_);
+  NetworkPortShimList network_port_shims_ __TA_GUARDED(lock_);
+  fbl::Mutex lock_;
 
   const ShimDispatchers dispatchers_;
   fdf::WireSharedClient<netdriver::NetworkDeviceIfc> device_ifc_;
diff --git a/src/connectivity/network/drivers/network-device/device/network_port_shim.cc b/src/connectivity/network/drivers/network-device/device/network_port_shim.cc
index fd6e21f..c179a52 100644
--- a/src/connectivity/network/drivers/network-device/device/network_port_shim.cc
+++ b/src/connectivity/network/drivers/network-device/device/network_port_shim.cc
@@ -4,21 +4,18 @@
 
 #include "network_port_shim.h"
 
-#include "mac_addr_shim.h"
-
 namespace network {
 
 namespace netdev = fuchsia_hardware_network;
 
-void NetworkPortShim::Bind(ddk::NetworkPortProtocolClient client_impl, fdf_dispatcher_t* dispatcher,
-                           fdf::ServerEnd<netdriver::NetworkPort> server_end) {
-  std::unique_ptr<NetworkPortShim> impl(new NetworkPortShim(client_impl, dispatcher));
-
-  fdf::BindServer(impl->dispatcher_, std::move(server_end), std::move(impl));
-}
-
-NetworkPortShim::NetworkPortShim(ddk::NetworkPortProtocolClient impl, fdf_dispatcher_t* dispatcher)
-    : impl_(impl), dispatcher_(dispatcher) {}
+NetworkPortShim::NetworkPortShim(ddk::NetworkPortProtocolClient impl, fdf_dispatcher_t* dispatcher,
+                                 fdf::ServerEnd<netdriver::NetworkPort> server_end,
+                                 fit::callback<void(NetworkPortShim*)>&& on_unbound)
+    : impl_(impl),
+      dispatcher_(dispatcher),
+      on_unbound_(std::move(on_unbound)),
+      binding_(dispatcher, std::move(server_end), this,
+               std::mem_fn(&NetworkPortShim::OnPortUnbound)) {}
 
 void NetworkPortShim::GetInfo(fdf::Arena& arena, GetInfoCompleter::Sync& completer) {
   port_base_info_t info;
@@ -79,7 +76,12 @@
     return;
   }
 
-  MacAddrShim::Bind(dispatcher_, mac_addr, std::move(endpoints->server));
+  // MacAddrShim must be created on the same dispatcher that it's served on. Since the GetMac
+  // request is already served on that dispatcher it's safe to directly construct it here.
+  auto mac_addr_shim = std::make_unique<MacAddrShim>(
+      dispatcher_, mac_addr, std::move(endpoints->server),
+      [this](MacAddrShim* mac_addr_shim) { mac_addr_shims_.erase(*mac_addr_shim); });
+  mac_addr_shims_.push_front(std::move(mac_addr_shim));
 
   completer.buffer(arena).Reply(std::move(endpoints->client));
 }
@@ -88,4 +90,10 @@
   impl_.Removed();
 }
 
+void NetworkPortShim::OnPortUnbound(fidl::UnbindInfo info) {
+  if (on_unbound_) {
+    on_unbound_(this);
+  }
+}
+
 }  // namespace network
diff --git a/src/connectivity/network/drivers/network-device/device/network_port_shim.h b/src/connectivity/network/drivers/network-device/device/network_port_shim.h
index c20e595..4b4d822 100644
--- a/src/connectivity/network/drivers/network-device/device/network_port_shim.h
+++ b/src/connectivity/network/drivers/network-device/device/network_port_shim.h
@@ -8,6 +8,10 @@
 #include <fidl/fuchsia.hardware.network.driver/cpp/driver/fidl.h>
 #include <fuchsia/hardware/network/driver/cpp/banjo.h>
 
+#include <fbl/intrusive_double_list.h>
+
+#include "mac_addr_shim.h"
+
 namespace network {
 
 namespace netdriver = fuchsia_hardware_network_driver;
@@ -18,11 +22,14 @@
 // port speaks FIDL. This type translates calls from from netdevice into the parent from FIDL to
 // Banjo. The NetworkPort protocol does not have corresponding Ifc protocol in the other direction
 // so this type only needs to work in one direction.
-class NetworkPortShim : public fdf::WireServer<netdriver::NetworkPort> {
+class NetworkPortShim : public fdf::WireServer<netdriver::NetworkPort>,
+                        public fbl::DoublyLinkedListable<std::unique_ptr<NetworkPortShim>> {
  public:
-  static void Bind(ddk::NetworkPortProtocolClient client_impl, fdf_dispatcher_t* dispatcher,
-                   fdf::ServerEnd<netdriver::NetworkPort> server_end);
+  NetworkPortShim(ddk::NetworkPortProtocolClient impl, fdf_dispatcher_t* dispatcher,
+                  fdf::ServerEnd<netdriver::NetworkPort> server_end,
+                  fit::callback<void(NetworkPortShim*)>&& on_unbound);
 
+  // NetworkPort implementation
   void GetInfo(fdf::Arena& arena, GetInfoCompleter::Sync& completer) override;
   void GetStatus(fdf::Arena& arena, GetStatusCompleter::Sync& completer) override;
   void SetActive(netdriver::wire::NetworkPortSetActiveRequest* request, fdf::Arena& arena,
@@ -31,12 +38,19 @@
   void Removed(fdf::Arena& arena, RemovedCompleter::Sync& completer) override;
 
  private:
-  NetworkPortShim(ddk::NetworkPortProtocolClient impl, fdf_dispatcher_t* dispatcher);
+  using MacAddrShimList = fbl::SizedDoublyLinkedList<std::unique_ptr<MacAddrShim>>;
+
+  void OnPortUnbound(fidl::UnbindInfo info);
 
   ddk::NetworkPortProtocolClient impl_;
   fdf_dispatcher_t* dispatcher_;
+  // All access to this list must by design happen on the above dispatcher. MacAddrShim objects can
+  // only be constructed on the same dispatcher they are bound and unbound on.
+  MacAddrShimList mac_addr_shims_;
+  fit::callback<void(NetworkPortShim*)> on_unbound_;
+  fdf::ServerBinding<netdriver::NetworkPort> binding_;
 };
 
-#endif  // SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_NETWORK_PORT_SHIM_H_
-
 }  // namespace network
+
+#endif  // SRC_CONNECTIVITY_NETWORK_DRIVERS_NETWORK_DEVICE_DEVICE_NETWORK_PORT_SHIM_H_
diff --git a/src/connectivity/network/drivers/network-device/device/test_util.cc b/src/connectivity/network/drivers/network-device/device/test_util.cc
index 79456f6..90f599ed 100644
--- a/src/connectivity/network/drivers/network-device/device/test_util.cc
+++ b/src/connectivity/network/drivers/network-device/device/test_util.cc
@@ -522,10 +522,10 @@
   }
 
   auto& value = device.value();
-  value->evt_session_started_ = [this](const char* session) {
-    event_.signal(0, kEventSessionStarted);
-  };
-  value->evt_session_died_ = [this](const char* session) { event_.signal(0, kEventSessionDied); };
+  value->evt_session_started_.Set(
+      [this](const char* session) { event_.signal(0, kEventSessionStarted); });
+  value->evt_session_died_.Set(
+      [this](const char* session) { event_.signal(0, kEventSessionDied); });
   return zx::ok(std::move(value));
 }
 
diff --git a/src/connectivity/network/drivers/network-device/device/test_util_banjo.cc b/src/connectivity/network/drivers/network-device/device/test_util_banjo.cc
index f3976b8..56aa73a 100644
--- a/src/connectivity/network/drivers/network-device/device/test_util_banjo.cc
+++ b/src/connectivity/network/drivers/network-device/device/test_util_banjo.cc
@@ -348,10 +348,10 @@
   }
 
   auto& value = device.value();
-  value->evt_session_started_ = [this](const char* session) {
-    event_.signal(0, kEventSessionStarted);
-  };
-  value->evt_session_died_ = [this](const char* session) { event_.signal(0, kEventSessionDied); };
+  value->evt_session_started_.Set(
+      [this](const char* session) { event_.signal(0, kEventSessionStarted); });
+  value->evt_session_died_.Set(
+      [this](const char* session) { event_.signal(0, kEventSessionDied); });
   return zx::ok(std::move(value));
 }
 
diff --git a/src/connectivity/network/lib/sockaddr/src/lib.rs b/src/connectivity/network/lib/sockaddr/src/lib.rs
index 4b12ae4..57491ce 100644
--- a/src/connectivity/network/lib/sockaddr/src/lib.rs
+++ b/src/connectivity/network/lib/sockaddr/src/lib.rs
@@ -123,6 +123,42 @@
     }
 }
 
+/// Socket address for a Pure IP packet socket.
+pub struct PureIpSockaddr {
+    /// The interface identifier, or `None` for no interface.
+    pub interface_id: Option<NonZeroU64>,
+    /// The IP version.
+    pub protocol: net_types::ip::IpVersion,
+}
+
+impl From<PureIpSockaddr> for libc::sockaddr_ll {
+    fn from(value: PureIpSockaddr) -> Self {
+        let PureIpSockaddr { interface_id, protocol } = value;
+        let protocol = match protocol {
+            net_types::ip::IpVersion::V4 => libc::ETH_P_IP,
+            net_types::ip::IpVersion::V6 => libc::ETH_P_IPV6,
+        };
+        libc::sockaddr_ll {
+            sll_family: libc::AF_PACKET
+                .try_into()
+                .expect("libc::AF_PACKET should fit in sll_family field"),
+            sll_ifindex: interface_id
+                .map_or(0, NonZeroU64::get)
+                .try_into()
+                .expect("interface_id should fit in sll_ifindex field"),
+            // Network order is big endian.
+            sll_protocol: u16::try_from(protocol)
+                .expect("protocol should fit in sll_protocol field")
+                .to_be(),
+            // Pure IP devices don't have a hardware address.
+            sll_halen: 0,
+            sll_addr: [0, 0, 0, 0, 0, 0, 0, 0],
+            sll_hatype: 0,  // unused by sendto() or bind()
+            sll_pkttype: 0, // unused by sendto() or bind()
+        }
+    }
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/src/connectivity/network/meta/common.shard.cml b/src/connectivity/network/meta/common.shard.cml
index 9c6e89a..1d39d68 100644
--- a/src/connectivity/network/meta/common.shard.cml
+++ b/src/connectivity/network/meta/common.shard.cml
@@ -210,6 +210,12 @@
             to: [ "#http-client" ],
         },
         {
+            from: "parent",
+            to: "#http-client",
+            config: "fuchsia.http-client.StopOnIdleTimeoutMillis",
+            availability: "same_as_target",
+        },
+        {
             storage: "cache",
             from: "parent",
             to: [ "#netstack" ],
diff --git a/src/connectivity/network/meta/netstack-common.shard.cml b/src/connectivity/network/meta/netstack-common.shard.cml
index 0666ba1..3a576e5 100644
--- a/src/connectivity/network/meta/netstack-common.shard.cml
+++ b/src/connectivity/network/meta/netstack-common.shard.cml
@@ -14,8 +14,6 @@
             protocol: [
                 "fuchsia.net.debug.Diagnostics",
                 "fuchsia.net.debug.Interfaces",
-                "fuchsia.net.filter.Control",
-                "fuchsia.net.filter.deprecated.Filter",
                 "fuchsia.net.interfaces.admin.Installer",
                 "fuchsia.net.interfaces.State",
                 "fuchsia.net.multicast.admin.Ipv6RoutingTableController",
@@ -43,8 +41,6 @@
             protocol: [
                 "fuchsia.net.debug.Diagnostics",
                 "fuchsia.net.debug.Interfaces",
-                "fuchsia.net.filter.Control",
-                "fuchsia.net.filter.deprecated.Filter",
                 "fuchsia.net.interfaces.admin.Installer",
                 "fuchsia.net.interfaces.State",
                 "fuchsia.net.multicast.admin.Ipv6RoutingTableController",
diff --git a/src/connectivity/network/meta/netstack2.shard.cml b/src/connectivity/network/meta/netstack2.shard.cml
index 24a888e..61a0c47 100644
--- a/src/connectivity/network/meta/netstack2.shard.cml
+++ b/src/connectivity/network/meta/netstack2.shard.cml
@@ -12,7 +12,6 @@
     expose: [
         {
             protocol: [
-                "fuchsia.net.filter.Control",
                 "fuchsia.net.stackmigrationdeprecated.Control",
                 "fuchsia.net.stackmigrationdeprecated.State",
             ],
diff --git a/src/connectivity/network/netstack/BUILD.gn b/src/connectivity/network/netstack/BUILD.gn
index 8a2f07f..400259e 100644
--- a/src/connectivity/network/netstack/BUILD.gn
+++ b/src/connectivity/network/netstack/BUILD.gn
@@ -244,7 +244,6 @@
     "link/bridge:tests",
     "link/netdevice:tests",
     "routes:tests",
-    "tests",
     "time:tests",
     "tracing:tests",
     "udp_serde:tests",
diff --git a/src/connectivity/network/netstack/meta/netstack.cml b/src/connectivity/network/netstack/meta/netstack.cml
index c1a20c3..0836428 100644
--- a/src/connectivity/network/netstack/meta/netstack.cml
+++ b/src/connectivity/network/netstack/meta/netstack.cml
@@ -6,7 +6,7 @@
         "//src/connectivity/network/meta/netstack-common.shard.cml",
         "//src/connectivity/network/netstack/meta/netstack2-common.shard.cml",
         "//src/connectivity/network/netstack/meta/netstack2-prod.shard.cml",
-        "//src/connectivity/network/netstack/meta/netstack2-void-dhcp-client.shard.cml",
+        "//src/connectivity/network/netstack/meta/netstack2-void-exposes.shard.cml",
     ],
     program: {
         binary: "bin/netstack",
diff --git a/src/connectivity/network/netstack/meta/netstack2-common.shard.cml b/src/connectivity/network/netstack/meta/netstack2-common.shard.cml
index 54fa02d..707f342 100644
--- a/src/connectivity/network/netstack/meta/netstack2-common.shard.cml
+++ b/src/connectivity/network/netstack/meta/netstack2-common.shard.cml
@@ -15,6 +15,7 @@
     capabilities: [
         {
             protocol: [
+                "fuchsia.net.filter.deprecated.Filter",
                 "fuchsia.net.multicast.admin.Ipv4RoutingTableController",
                 "fuchsia.net.stack.Log",
             ],
@@ -41,6 +42,7 @@
     expose: [
         {
             protocol: [
+                "fuchsia.net.filter.deprecated.Filter",
                 "fuchsia.net.multicast.admin.Ipv4RoutingTableController",
                 "fuchsia.net.stack.Log",
             ],
diff --git a/src/connectivity/network/netstack/meta/netstack2-void-dhcp-client.shard.cml b/src/connectivity/network/netstack/meta/netstack2-void-dhcp-client.shard.cml
deleted file mode 100644
index 1a1af92..0000000
--- a/src/connectivity/network/netstack/meta/netstack2-void-dhcp-client.shard.cml
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This shard exists to add a void offer for DHCP client for Netstack2. It can't
-// be in netstack2-prod.shard.cml because that is shared with the migration
-// proxy.
-{
-    expose: [
-        // TODO(https://fxbug.dev/42076541): Remove once DHCP client is used by
-        // both netstacks and is moved into the network realm.
-        {
-            protocol: "fuchsia.net.dhcp.ClientProvider",
-            from: "void",
-            availability: "optional",
-        },
-    ],
-}
diff --git a/src/connectivity/network/netstack/meta/netstack2-void-exposes.shard.cml b/src/connectivity/network/netstack/meta/netstack2-void-exposes.shard.cml
new file mode 100644
index 0000000..6493ae7
--- /dev/null
+++ b/src/connectivity/network/netstack/meta/netstack2-void-exposes.shard.cml
@@ -0,0 +1,28 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This shard exists to add a void expose for the fuchsia.net.filter.Control and
+// fuchsia.net.dhcp.ClientProvider protocols from Netstack2, which doesn't
+// implement the filter protocol or use the out of stack DHCP client.
+//
+// These can't be in netstack2-common.shard.cml because that is shared with the
+// migration proxy component, which also includes Netstack3's component manifest
+// shard, and would therefore have two conflicting expose clauses for the same
+// protocol.
+{
+    expose: [
+        // TODO(https://fxbug.dev/42076541): Remove once DHCP client is used by
+        // both netstacks and is moved into the network realm.
+        {
+            protocol: "fuchsia.net.dhcp.ClientProvider",
+            from: "void",
+            availability: "optional",
+        },
+        {
+            protocol: "fuchsia.net.filter.Control",
+            from: "void",
+            availability: "optional",
+        },
+    ],
+}
diff --git a/src/connectivity/network/netstack/meta/netstack_with_fast_udp.cml b/src/connectivity/network/netstack/meta/netstack_with_fast_udp.cml
index 1412dfde..857dea6 100644
--- a/src/connectivity/network/netstack/meta/netstack_with_fast_udp.cml
+++ b/src/connectivity/network/netstack/meta/netstack_with_fast_udp.cml
@@ -6,7 +6,7 @@
         "//src/connectivity/network/meta/netstack-common.shard.cml",
         "//src/connectivity/network/netstack/meta/netstack2-common.shard.cml",
         "//src/connectivity/network/netstack/meta/netstack2-prod.shard.cml",
-        "//src/connectivity/network/netstack/meta/netstack2-void-dhcp-client.shard.cml",
+        "//src/connectivity/network/netstack/meta/netstack2-void-exposes.shard.cml",
     ],
     program: {
         binary: "bin/netstack",
diff --git a/src/connectivity/network/netstack/meta/netstack_with_fast_udp_tracing.cml b/src/connectivity/network/netstack/meta/netstack_with_fast_udp_tracing.cml
index 8b44b22..187d40f 100644
--- a/src/connectivity/network/netstack/meta/netstack_with_fast_udp_tracing.cml
+++ b/src/connectivity/network/netstack/meta/netstack_with_fast_udp_tracing.cml
@@ -6,7 +6,7 @@
         "//src/connectivity/network/meta/netstack-common.shard.cml",
         "//src/connectivity/network/netstack/meta/netstack2-common.shard.cml",
         "//src/connectivity/network/netstack/meta/netstack2-prod.shard.cml",
-        "//src/connectivity/network/netstack/meta/netstack2-void-dhcp-client.shard.cml",
+        "//src/connectivity/network/netstack/meta/netstack2-void-exposes.shard.cml",
         "trace/use.shard.cml",
     ],
     program: {
diff --git a/src/connectivity/network/netstack/meta/netstack_with_tracing.cml b/src/connectivity/network/netstack/meta/netstack_with_tracing.cml
index 481f34c..f0862a7 100644
--- a/src/connectivity/network/netstack/meta/netstack_with_tracing.cml
+++ b/src/connectivity/network/netstack/meta/netstack_with_tracing.cml
@@ -6,7 +6,7 @@
         "//src/connectivity/network/meta/netstack-common.shard.cml",
         "//src/connectivity/network/netstack/meta/netstack2-common.shard.cml",
         "//src/connectivity/network/netstack/meta/netstack2-prod.shard.cml",
-        "//src/connectivity/network/netstack/meta/netstack2-void-dhcp-client.shard.cml",
+        "//src/connectivity/network/netstack/meta/netstack2-void-exposes.shard.cml",
         "trace/use.shard.cml",
     ],
     program: {
diff --git a/src/connectivity/network/netstack/ndp_test.go b/src/connectivity/network/netstack/ndp_test.go
index cd130ed..263d8f7c 100644
--- a/src/connectivity/network/netstack/ndp_test.go
+++ b/src/connectivity/network/netstack/ndp_test.go
@@ -133,11 +133,7 @@
 	dest := tcpip.AddressWithPrefix{Address: util.Parse("abcd:ee00::"), PrefixLen: 32}.Subnet()
 	r1 := tcpip.Route{Destination: dest, NIC: ifs1.nicid, Gateway: testLinkLocalV6Addr1}
 	r2 := tcpip.Route{Destination: dest, NIC: ifs2.nicid, Gateway: testLinkLocalV6Addr1}
-	broadcastSubnet := util.PointSubnet(header.IPv4Broadcast)
 	expectedRouteTable := []tcpip.Route{
-		{Destination: broadcastSubnet, NIC: ifs1.nicid},
-		{Destination: broadcastSubnet, NIC: ifs2.nicid},
-
 		{Destination: ipv4MulticastSubnet().Subnet(), NIC: ifs1.nicid},
 		{Destination: ipv4MulticastSubnet().Subnet(), NIC: ifs2.nicid},
 
@@ -159,7 +155,7 @@
 	}
 
 	// Flip the preferences of r1 and r2.
-	expectedRouteTable[6], expectedRouteTable[7] = expectedRouteTable[7], expectedRouteTable[6]
+	expectedRouteTable[4], expectedRouteTable[5] = expectedRouteTable[5], expectedRouteTable[4]
 	ndpDisp.OnOffLinkRouteUpdated(r2.NIC, r2.Destination, r2.Gateway, header.HighRoutePreference)
 	ndpDisp.OnOffLinkRouteUpdated(r1.NIC, r1.Destination, r1.Gateway, header.LowRoutePreference)
 	waitForEmptyQueue(ndpDisp)
diff --git a/src/connectivity/network/netstack/netstack.go b/src/connectivity/network/netstack/netstack.go
index a36109d..e85f3f8 100644
--- a/src/connectivity/network/netstack/netstack.go
+++ b/src/connectivity/network/netstack/netstack.go
@@ -1118,22 +1118,6 @@
 				_ = syslog.Errorf("error enabling NIC %s in stack.Stack: %s", name, err)
 			}
 
-			// DHCPv4 sends packets to the IPv4 broadcast address so make sure there is
-			// a valid route to it. This route is only needed for the initial DHCPv4
-			// transaction. Marking the route as dynamic will result in it being removed
-			// when configurations are acquired via DHCPv4, which is okay as following
-			// DHCPv4 requests will be sent directly to the DHCPv4 server instead of
-			// broadcasting it to the whole link.
-			ifs.ns.routeTable.AddRoute(
-				tcpip.Route{Destination: util.PointSubnet(header.IPv4Broadcast), NIC: ifs.nicid},
-				routetypes.MediumPreference,
-				lowPriorityRoute,
-				false, /* metricTracksInterface */
-				true,  /* dynamic */
-				true,  /* enabled */
-				routetypes.GlobalRouteSet(),
-			)
-
 			// Re-enable static routes out this interface.
 			ifs.ns.UpdateRoutesByInterfaceLocked(ifs.nicid, routetypes.ActionEnableStatic)
 			if ifs.mu.dhcp.enabled {
diff --git a/src/connectivity/network/netstack/tests/BUILD.gn b/src/connectivity/network/netstack/tests/BUILD.gn
deleted file mode 100644
index 733b16a..0000000
--- a/src/connectivity/network/netstack/tests/BUILD.gn
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2016 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-group("tests") {
-  testonly = true
-
-  deps = [ "manual" ]
-}
diff --git a/src/connectivity/network/netstack/tests/manual/BUILD.gn b/src/connectivity/network/netstack/tests/manual/BUILD.gn
deleted file mode 100644
index e70a043..0000000
--- a/src/connectivity/network/netstack/tests/manual/BUILD.gn
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2016 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/components.gni")
-
-names = [
-  "sockopttest",
-  "gethostbyname_test",
-]
-
-foreach(name, names) {
-  executable(name) {
-    testonly = true
-    sources = [ "$name.c" ]
-    deps = [
-      "//sdk/lib/fdio",
-      "//src/zircon/lib/zircon",
-    ]
-  }
-}
-
-fuchsia_shell_package("netstack-manual-tests") {
-  testonly = true
-
-  deps = []
-  foreach(name, names) {
-    deps += [ ":$name" ]
-  }
-}
-
-group("manual") {
-  testonly = true
-  deps = [ ":netstack-manual-tests" ]
-}
diff --git a/src/connectivity/network/netstack/tests/manual/gethostbyname_test.c b/src/connectivity/network/netstack/tests/manual/gethostbyname_test.c
deleted file mode 100644
index 52206cc..0000000
--- a/src/connectivity/network/netstack/tests/manual/gethostbyname_test.c
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-void print_hostent(struct hostent* h) {
-  printf("h_name: %s\n", h->h_name);
-  for (int i = 0; h->h_aliases[i] != NULL; i++) {
-    printf("h_aliases[%d]: %s\n", i, h->h_aliases[i]);
-  }
-  printf("h_addrtype: %d\n", h->h_addrtype);
-  printf("h_length: %d\n", h->h_length);
-  for (int i = 0; h->h_addr_list[i] != NULL; i++) {
-    char buf[INET6_ADDRSTRLEN];
-    switch (h->h_length) {
-      case 4:
-        printf("h_addr_list[%d]: %s\n", i,
-               inet_ntop(AF_INET, h->h_addr_list[i], buf, sizeof(buf)));
-        break;
-      case 16:
-        printf("h_addr_list[%d]: %s\n", i,
-               inet_ntop(AF_INET6, h->h_addr_list[i], buf, sizeof(buf)));
-        break;
-    }
-  }
-}
-
-void call_gethostbyname(char* name, int af, size_t buflen) {
-  char* buf = malloc(buflen);
-
-  struct hostent* res;
-  int h_err;
-  struct hostent h;
-
-  int r = gethostbyname2_r(name, af, &h, buf, buflen, &res, &h_err);
-  if (r != 0) {
-    switch (r) {
-      case ERANGE:
-        printf("Buffer is too small (%zd bytes) to store the result\n", buflen);
-        break;
-      default:
-        printf("Unknown return val: %d\n", r);
-        break;
-    }
-  } else if (res == NULL) {
-    switch (h_err) {
-      case HOST_NOT_FOUND:
-        printf("Host Not Found\n");
-        break;
-      case NO_RECOVERY:
-        printf("No Recovery\n");
-        break;
-      case TRY_AGAIN:
-        printf("Try Again\n");
-        break;
-      default:
-        printf("h_err: %d\n", h_err);
-        break;
-    }
-  } else {
-    print_hostent(res);
-  }
-
-  free(buf);
-}
-
-void usage(void) {
-  printf("usage: gethostbyname_test name [buflen (default:1024)]\n");
-}
-
-int main(int argc, char** argv) {
-  if (argc < 2 || argc > 3) {
-    usage();
-    return 1;
-  }
-
-  size_t buflen = 1024;
-  if (argc == 3) {
-    buflen = atoi(argv[2]);
-  }
-
-  printf("[AF_INET]\n");
-  call_gethostbyname(argv[1], AF_INET, buflen);
-
-  printf("\n[AF_INET6]\n");
-  call_gethostbyname(argv[1], AF_INET6, buflen);
-
-  return 0;
-}
diff --git a/src/connectivity/network/netstack/tests/manual/sockopttest.c b/src/connectivity/network/netstack/tests/manual/sockopttest.c
deleted file mode 100644
index f16084c..0000000
--- a/src/connectivity/network/netstack/tests/manual/sockopttest.c
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2017 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <errno.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-
-// I got these results running this test on my local linux machine:
-//
-// SO_BROADCAST: default = off... setsockopt success = on
-// SO_DEBUG: default = off... setsockopt error (13)
-// SO_DONTROUTE: default = off... setsockopt success = on
-// SO_ERROR: default = 0... setsockopt error (92)
-// SO_KEEPALIVE: default = off... setsockopt success = on
-// SO_LINGER: default = l_onoff:0, l_linger:0... setsockopt success = l_onoff:0,
-// l_linger:0 SO_OOBINLINE: default = off... setsockopt success = on SO_RCVBUF:
-// default = 87380... setsockopt unchanged SO_SNDBUF: default = 16384...
-// setsockopt unchanged SO_RCVLOWAT: default = 1... setsockopt success = 43
-// SO_SNDLOWAT: default = 1... setsockopt error (92)
-// SO_RCVTIMEO: default = 0s 0usec... setsockopt success = 0s 0usec
-// SO_SNDTIMEO: default = 0s 0usec... setsockopt success = 0s 0usec
-// SO_REUSEADDR: default = off... setsockopt success = on
-// SO_REUSEPORT: default = off... setsockopt success = on
-// SO_TYPE: default = 1... setsockopt error (92)
-// SO_DOMAIN: initial = 2... setsockopt error (92)
-// IP_TOS: default = 0... setsockopt unchanged
-// IP_TTL: default = 64... setsockopt success = 106
-// IPV6_UNICAST_HOPS: default = 64... setsockopt success = 106
-// IPV6_V6ONLY: default = off... setsockopt success = on
-// TCP_NODELAY: default = off... setsockopt success = on
-// TCP_MAXSEG: default = 536... setsockopt unchanged
-// TCP_CORK: default = off... setsockopt success = on
-// TCP_KEEPIDLE: default = 7200... setsockopt success = 7242
-// TCP_KEEPINTVL: default = 75... setsockopt success = 117
-// TCP_KEEPCNT: default = 9... setsockopt success = 51
-// TCP_SYNCNT: default = 3... setsockopt success = 45
-// TCP_LINGER2: default = 60... setsockopt unchanged
-// TCP_DEFER_ACCEPT: default = 0... setsockopt unchanged
-// TCP_WINDOW_CLAMP: default = 0... setsockopt unchanged
-// TCP_INFO: default = size (16) not sizeof(int)... setsockopt error (92)
-// TCP_QUICKACK: default = on... setsockopt success = off
-
-#ifndef countof
-#define countof sizeof
-#endif
-
-union val {
-  int i_val;
-};
-
-static char strres[128];
-
-static char* sock_str_flag(union val* ptr, int len) {
-  if (len != sizeof(int)) {
-    snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
-  } else {
-    snprintf(strres, sizeof(strres), "%s", (ptr->i_val == 0) ? "off" : "on");
-  }
-  return (strres);
-}
-
-static char* sock_str_int(union val* ptr, int len) {
-  if (len != sizeof(int)) {
-    snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
-  } else {
-    snprintf(strres, sizeof(strres), "%d", ptr->i_val);
-  }
-  return (strres);
-}
-
-struct sock_opts {
-  const char* opt_str;
-  int opt_level;
-  int opt_name;
-  char* (*opt_val_str)(union val*, int);
-} sock_opts_table[] = {{"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, sock_str_flag},
-                       {"SO_DEBUG", SOL_SOCKET, SO_DEBUG, sock_str_flag},
-                       {"SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE, sock_str_flag},
-                       {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, sock_str_flag},
-                       {"SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE, sock_str_flag},
-                       {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, sock_str_int},
-                       {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, sock_str_flag},
-                       {"IPV6_V6ONLY", IPPROTO_IPV6, IPV6_V6ONLY, sock_str_flag},
-                       {"TCP_MAXSEG", IPPROTO_TCP, TCP_MAXSEG, sock_str_int},
-                       {"TCP_CORK", IPPROTO_TCP, TCP_CORK, sock_str_flag},
-                       {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, sock_str_int},
-                       {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, sock_str_int},
-                       {"TCP_SYNCNT", IPPROTO_TCP, TCP_SYNCNT, sock_str_int},
-                       {"TCP_LINGER2", IPPROTO_TCP, TCP_LINGER2, sock_str_int},
-                       {"TCP_DEFER_ACCEPT", IPPROTO_TCP, TCP_DEFER_ACCEPT, sock_str_int},
-                       {"TCP_WINDOW_CLAMP", IPPROTO_TCP, TCP_WINDOW_CLAMP, sock_str_int},
-                       {"TCP_QUICKACK", IPPROTO_TCP, TCP_QUICKACK, sock_str_flag},
-                       {NULL, 0, 0, NULL}};
-
-int test_setsockopt(int fd, struct sock_opts* ptr, union val* valp, socklen_t len) {
-  if (setsockopt(fd, ptr->opt_level, ptr->opt_name, valp, len) == -1) {
-    printf("setsockopt error (%d)", errno);
-  } else {
-    union val new_val;
-    new_val.i_val = 0xdeadbeef;
-    socklen_t new_len = sizeof(new_val);
-    if (getsockopt(fd, ptr->opt_level, ptr->opt_name, &new_val, &new_len) == -1) {
-      printf("getsockopt error (%d)", errno);
-    } else if (new_val.i_val == (int)0xdeadbeef) {
-      printf("setsockopt unchanged");
-    } else if (len != new_len) {
-      printf("getsockopt returned a different size (%d) than expected (%d)", new_len, len);
-    } else if (memcmp(valp, &new_val, len) != 0) {
-      printf("getsockopt returned a different val (%s)", ptr->opt_val_str(&new_val, new_len));
-      printf(" than expected (%s)", ptr->opt_val_str(valp, len));
-    } else {
-      printf("setsockopt success = %s", ptr->opt_val_str(valp, len));
-      return 0;
-    }
-  }
-  return -1;
-}
-
-int main(int argc, char** argv) {
-  socklen_t len;
-  struct sock_opts* ptr;
-
-  for (ptr = sock_opts_table; ptr->opt_str != NULL; ptr++) {
-    int fd = -1;
-    int sock_type = SOCK_STREAM;
-    if (ptr->opt_name == IP_MULTICAST_TTL)
-      sock_type = SOCK_DGRAM;
-    switch (ptr->opt_level) {
-      case SOL_SOCKET:
-      case IPPROTO_IP:
-      case IPPROTO_TCP:
-        fd = socket(AF_INET, sock_type, 0);
-        break;
-      case IPPROTO_IPV6:
-        fd = socket(AF_INET6, sock_type, 0);
-        break;
-    }
-
-    printf("%s: ", ptr->opt_str);
-    if (ptr->opt_val_str == NULL) {
-      printf("(undefined)\n");
-    } else {
-      union val ini_val;
-      len = sizeof(ini_val);
-      if (getsockopt(fd, ptr->opt_level, ptr->opt_name, &ini_val, &len) == -1) {
-        printf("getsockopt error (%d)... ", errno);
-      } else {
-        printf("initial = %s... ", ptr->opt_val_str(&ini_val, len));
-      }
-
-      // Change the option and see if it was successful.
-      union val val = ini_val;
-      if (ptr->opt_val_str == sock_str_flag) {
-        val.i_val = !val.i_val;
-      } else if (ptr->opt_val_str == sock_str_int) {
-        val.i_val += 42;
-      }
-      if (test_setsockopt(fd, ptr, &val, len) == 0) {
-        printf("... ");
-        // Change the option back to the initial value.
-        test_setsockopt(fd, ptr, &ini_val, len);
-      }
-      printf("\n");
-    }
-  }
-
-  return 0;
-}
diff --git a/src/connectivity/network/netstack3/BUILD.gn b/src/connectivity/network/netstack3/BUILD.gn
index fc80bcb..85ce058 100644
--- a/src/connectivity/network/netstack3/BUILD.gn
+++ b/src/connectivity/network/netstack3/BUILD.gn
@@ -12,7 +12,6 @@
   "//sdk/fidl/fuchsia.net.debug:fuchsia.net.debug_rust",
   "//sdk/fidl/fuchsia.net.dhcp:fuchsia.net.dhcp_rust",
   "//sdk/fidl/fuchsia.net.filter:fuchsia.net.filter_rust",
-  "//sdk/fidl/fuchsia.net.filter.deprecated:fuchsia.net.filter.deprecated_rust",
   "//sdk/fidl/fuchsia.net.interfaces:fuchsia.net.interfaces_rust",
   "//sdk/fidl/fuchsia.net.interfaces.admin:fuchsia.net.interfaces.admin_rust",
   "//sdk/fidl/fuchsia.net.name:fuchsia.net.name_rust",
@@ -145,13 +144,16 @@
 config("netstack3_configs") {
   if (!is_debug) {
     configs = [
-      # Allow cross-crate optimization since netstack3 is split between multiple
-      # crates.
-      "//build/config/lto:thinlto",
-
       # Always optimize speed, even if it increases size.
       "//build/config:optimize_speed",
     ]
+
+    # Add thinlto config if lto variants are not used.
+    if (!is_lto_variant) {
+      # Allow cross-crate optimization since netstack3 is split between multiple
+      # crates.
+      configs += [ "//build/config/lto:thinlto" ]
+    }
   }
 }
 
diff --git a/src/connectivity/network/netstack3/core/BUILD.gn b/src/connectivity/network/netstack3/core/BUILD.gn
index 974790d..b445aaa 100644
--- a/src/connectivity/network/netstack3/core/BUILD.gn
+++ b/src/connectivity/network/netstack3/core/BUILD.gn
@@ -9,6 +9,19 @@
 import(
     "//src/connectivity/network/netstack3/core/rustc_library_with_features.gni")
 
+_all_core_crates = [
+  "base:netstack3-base",
+  "base:netstack3-base-testutils",
+  "filter:netstack3-filter",
+  "filter:netstack3-filter-benchmarks",
+  "filter:netstack3-filter-instrumented",
+  "filter:netstack3-filter-testutils",
+  "filter:netstack3-filter-loom",
+  "sync:netstack3-sync",
+  "sync:netstack3-sync-instrumented",
+  "sync:netstack3-sync-loom",
+]
+
 rustc_library_with_features("netstack3-core") {
   version = "0.1.0"
   edition = "2021"
@@ -114,7 +127,6 @@
 
     # Placeholder comment so the auto formatter does not move one of these
     # dependencies above "fakestd".
-    "base:netstack3-base",
     "lock-order",
     "macros:netstack3-macros",
     "//src/connectivity/lib/net-types",
@@ -152,6 +164,7 @@
     {
       features = []
       deps += [
+        "base:netstack3-base",
         "filter:netstack3-filter",
         "sync:netstack3-sync",
       ]
@@ -164,11 +177,20 @@
       target_name = "netstack3-core-instrumented"
       features = [ "instrumented" ]
       with_unit_tests = true
-      deps += [
-        "filter:netstack3-filter-testutils",
+      non_test_deps = [
+        "base:netstack3-base",
+        "filter:netstack3-filter-instrumented",
         "sync:netstack3-sync-instrumented",
       ]
-      test_deps += [ "//third_party/rust_crates:scopeguard" ]
+      test_deps += [
+        "base:netstack3-base-testutils",
+        "filter:netstack3-filter-testutils",
+        "sync:netstack3-sync-instrumented",
+        "//third_party/rust_crates:scopeguard",
+      ]
+
+      # Guard against bad crate variants.
+      assert_no_deps = _all_core_crates - non_test_deps
 
       # TODO(https://fxbug.dev/42086491): Split up large tests.
       # Compiling the tests OOMs on RBE with these variants.
@@ -189,11 +211,18 @@
         "instrumented",
         "testutils",
       ]
-      deps += [
-        "filter:netstack3-filter",
+
+      _core_deps = [
+        "base:netstack3-base-testutils",
+        "filter:netstack3-filter-testutils",
         "sync:netstack3-sync-instrumented",
-        "//third_party/rust_crates:rand_xorshift",
       ]
+
+      deps += _core_deps
+      deps += [ "//third_party/rust_crates:rand_xorshift" ]
+
+      # Guard against bad crate variants.
+      assert_no_deps = _all_core_crates - _core_deps
     },
 
     # A variant of the netstack3-core library that is built for running
@@ -202,13 +231,22 @@
       target_name = "netstack3-core-benchmarks"
       testonly = true
       features = []
-      deps += [
-        "filter:netstack3-filter-testutils",
+
+      _core_deps = [
+        "base:netstack3-base-testutils",
+        "filter:netstack3-filter-benchmarks",
         "sync:netstack3-sync",
+      ]
+      deps += _core_deps
+      deps += [
         "//third_party/rust_crates:criterion",
         "//third_party/rust_crates:rand_xorshift",
       ]
       deps += test_deps
+
+      # Guard against bad crate variants.
+      assert_no_deps = _all_core_crates - _core_deps
+
       configs += [ ":benchmark" ]
     },
   ]
@@ -224,11 +262,17 @@
           "instrumented",
           "testutils",
         ]
-        deps += [
+        _core_deps = [
+          "base:netstack3-base-testutils",
           "filter:netstack3-filter-loom",
           "sync:netstack3-sync-loom",
-          "//third_party/rust_crates:rand_xorshift",
         ]
+        deps += _core_deps
+        deps += [ "//third_party/rust_crates:rand_xorshift" ]
+
+        # Guard against bad crate variants.
+        assert_no_deps = _all_core_crates - _core_deps
+
         configs += [ ":loom" ]
       },
     ]
@@ -304,6 +348,7 @@
     deps = [ ":fuzz-single-device" ]
   }
 }
+
 group("tests") {
   testonly = true
   public_deps = [
diff --git a/src/connectivity/network/netstack3/core/base/BUILD.gn b/src/connectivity/network/netstack3/core/base/BUILD.gn
index 624b0a4..24000a6 100644
--- a/src/connectivity/network/netstack3/core/base/BUILD.gn
+++ b/src/connectivity/network/netstack3/core/base/BUILD.gn
@@ -4,10 +4,11 @@
 
 import("//build/components.gni")
 import("//build/rust/rustc_library.gni")
+import(
+    "//src/connectivity/network/netstack3/core/rustc_library_with_features.gni")
 
-rustc_library("netstack3-base") {
+rustc_library_with_features("netstack3-base") {
   edition = "2021"
-  with_unit_tests = true
   configs -= [ "//build/config/rust/lints:allow_unused_results" ]
   sources = [
     "src/context.rs",
@@ -26,6 +27,20 @@
   if (!is_host) {
     configs += [ "//src/connectivity/network/netstack3:netstack3_configs" ]
   }
+
+  feature_sets = [
+    {
+      features = []
+      with_unit_tests = true
+    },
+
+    # A variant of the netstack3-base library that exposes test utilities.
+    {
+      target_name = "netstack3-base-testutils"
+      testonly = true
+      features = [ "testutils" ]
+    },
+  ]
 }
 
 fuchsia_unittest_package("netstack3-core-base-test") {
diff --git a/src/connectivity/network/netstack3/core/base/src/lib.rs b/src/connectivity/network/netstack3/core/base/src/lib.rs
index 0b76970..ffef0be 100644
--- a/src/connectivity/network/netstack3/core/base/src/lib.rs
+++ b/src/connectivity/network/netstack3/core/base/src/lib.rs
@@ -22,12 +22,11 @@
 pub use inspect::{Inspectable, InspectableValue, Inspector, InspectorDeviceExt};
 pub use time::{
     local_timer_heap::LocalTimerHeap, CoreTimerContext, Instant, InstantBindingsTypes,
-    InstantContext, IntoCoreTimerCtx, TimerBindingsTypes, TimerContext2,
+    InstantContext, IntoCoreTimerCtx, NestedIntoCoreTimerCtx, TimerBindingsTypes, TimerContext2,
 };
 
 /// Test utilities provided to all crates.
+#[cfg(any(test, feature = "testutils"))]
 pub mod testutil {
-    pub use crate::time::local_timer_heap::testutil::LocalTimerHeapTestExt;
-
     pub use crate::time::testutil::{FakeInstant, FakeInstantCtx};
 }
diff --git a/src/connectivity/network/netstack3/core/base/src/time.rs b/src/connectivity/network/netstack3/core/base/src/time.rs
index 20d08e7..213d365 100644
--- a/src/connectivity/network/netstack3/core/base/src/time.rs
+++ b/src/connectivity/network/netstack3/core/base/src/time.rs
@@ -5,9 +5,10 @@
 //! Common time abstractions.
 
 pub(crate) mod local_timer_heap;
+#[cfg(any(test, feature = "testutils"))]
 pub(crate) mod testutil;
 
-use core::{fmt::Debug, time::Duration};
+use core::{convert::Infallible as Never, fmt::Debug, marker::PhantomData, time::Duration};
 
 use crate::inspect::InspectableValue;
 
@@ -151,15 +152,31 @@
     }
 }
 
-/// A timer context that performs conversions based on `Into` implementations.
-pub struct IntoCoreTimerCtx;
+/// An uninstantiable type that performs conversions based on `Into`
+/// implementations.
+pub enum IntoCoreTimerCtx {}
 
 impl<T, BT> CoreTimerContext<T, BT> for IntoCoreTimerCtx
 where
     BT: TimerBindingsTypes,
     T: Into<BT::DispatchId>,
 {
-    fn convert_timer(dispatch_id: T) -> <BT as TimerBindingsTypes>::DispatchId {
+    fn convert_timer(dispatch_id: T) -> BT::DispatchId {
         dispatch_id.into()
     }
 }
+
+/// An uninstantiable type that performs conversions based on `Into`
+/// implementations and an available outer [`CoreTimerContext`] `CC`.
+pub struct NestedIntoCoreTimerCtx<CC, N>(Never, PhantomData<(CC, N)>);
+
+impl<CC, N, T, BT> CoreTimerContext<T, BT> for NestedIntoCoreTimerCtx<CC, N>
+where
+    BT: TimerBindingsTypes,
+    CC: CoreTimerContext<N, BT>,
+    T: Into<N>,
+{
+    fn convert_timer(dispatch_id: T) -> BT::DispatchId {
+        CC::convert_timer(dispatch_id.into())
+    }
+}
diff --git a/src/connectivity/network/netstack3/core/base/src/time/local_timer_heap.rs b/src/connectivity/network/netstack3/core/base/src/time/local_timer_heap.rs
index c1c0060..f33b2f1 100644
--- a/src/connectivity/network/netstack3/core/base/src/time/local_timer_heap.rs
+++ b/src/connectivity/network/netstack3/core/base/src/time/local_timer_heap.rs
@@ -105,6 +105,11 @@
         scheduled
     }
 
+    /// Gets an iterator over the installed timers.
+    pub fn iter(&self) -> impl Iterator<Item = (&K, &V, &BC::Instant)> {
+        self.heap.map.iter().map(|(k, MapEntry { time, value })| (k, value, time))
+    }
+
     fn heal_and_reschedule(&mut self, bindings_ctx: &mut BC) {
         let Self { next_wakeup, heap } = self;
         let mut new_top = None;
@@ -302,24 +307,33 @@
     }
 }
 
-// TODO(https://fxbug.dev/332936622): Gate behind testutil feature flag or move
-// to testutil only crate.
-pub(crate) mod testutil {
+#[cfg(any(test, feature = "testutils"))]
+mod testutil {
     use core::fmt::Debug;
 
     use super::*;
 
-    /// Test assertion extensions for [`LocalTimerHeap`].
-    pub trait LocalTimerHeapTestExt<K, V, BC: TimerContext2>: Sealed {
+    impl<K, V, BC> LocalTimerHeap<K, V, BC>
+    where
+        K: Hash + Eq + Clone + Debug,
+        V: Debug + Eq + PartialEq,
+        BC: TimerContext2,
+    {
         /// Asserts installed timers with an iterator of `(key, value, instant)`
         /// tuples.
         #[track_caller]
-        fn assert_timers(&self, timers: impl IntoIterator<Item = (K, V, BC::Instant)>);
+        pub fn assert_timers(&self, timers: impl IntoIterator<Item = (K, V, BC::Instant)>) {
+            let map = timers
+                .into_iter()
+                .map(|(k, value, time)| (k, MapEntry { value, time }))
+                .collect::<HashMap<_, _>>();
+            assert_eq!(&self.heap.map, &map);
+        }
 
         /// Like [`LocalTimerHeap::assert_timers`], but asserts based on a
         /// duration after `bindings_ctx.now()`.
         #[track_caller]
-        fn assert_timers_after(
+        pub fn assert_timers_after(
             &self,
             bindings_ctx: &mut BC,
             timers: impl IntoIterator<Item = (K, V, Duration)>,
@@ -329,30 +343,8 @@
         }
 
         /// Assets that the next time to fire has `key` and `value`.
-        fn assert_top(&mut self, key: &K, value: &V);
-    }
-
-    pub trait Sealed {}
-
-    impl<K, V, BC: InstantBindingsTypes + TimerBindingsTypes> Sealed for LocalTimerHeap<K, V, BC> {}
-
-    impl<K, V, BC> LocalTimerHeapTestExt<K, V, BC> for LocalTimerHeap<K, V, BC>
-    where
-        K: Hash + Eq + Clone + Debug,
-        V: Debug + Eq + PartialEq,
-        BC: TimerContext2,
-    {
         #[track_caller]
-        fn assert_timers(&self, timers: impl IntoIterator<Item = (K, V, BC::Instant)>) {
-            let map = timers
-                .into_iter()
-                .map(|(k, value, time)| (k, MapEntry { value, time }))
-                .collect::<HashMap<_, _>>();
-            assert_eq!(&self.heap.map, &map);
-        }
-
-        #[track_caller]
-        fn assert_top(&mut self, key: &K, value: &V) {
+        pub fn assert_top(&mut self, key: &K, value: &V) {
             // NB: We can't know that the top of the heap holds a valid entry,
             // so we need to do the slow thing and look in the map for this
             // assertion.
diff --git a/src/connectivity/network/netstack3/core/filter/BUILD.gn b/src/connectivity/network/netstack3/core/filter/BUILD.gn
index 66167fc..8716f57 100644
--- a/src/connectivity/network/netstack3/core/filter/BUILD.gn
+++ b/src/connectivity/network/netstack3/core/filter/BUILD.gn
@@ -8,7 +8,6 @@
 
 rustc_library_with_features("netstack3-filter") {
   edition = "2021"
-  with_unit_tests = true
   configs -= [ "//build/config/rust/lints:allow_unused_results" ]
   sources = [
     "src/api.rs",
@@ -24,20 +23,13 @@
   deps = [
     "//src/connectivity/lib/net-types",
     "//src/connectivity/lib/packet-formats",
-    "//src/connectivity/network/netstack3/core/base:netstack3-base",
     "//src/lib/fakealloc",
     "//src/lib/network/packet",
+    "//third_party/rust_crates:assert_matches",
     "//third_party/rust_crates:derivative",
     "//third_party/rust_crates:tracing",
     "//third_party/rust_crates:zerocopy",
   ]
-  test_deps = [
-    "//src/connectivity/lib/ip-test-macro",
-    "//src/connectivity/lib/net-declare",
-    "//src/lib/const-unwrap",
-    "//third_party/rust_crates:assert_matches",
-    "//third_party/rust_crates:test-case",
-  ]
 
   if (!is_host) {
     configs += [ "//src/connectivity/network/netstack3:netstack3_configs" ]
@@ -46,8 +38,10 @@
   feature_sets = [
     {
       features = []
-      deps +=
-          [ "//src/connectivity/network/netstack3/core/sync:netstack3-sync" ]
+      deps += [
+        "//src/connectivity/network/netstack3/core/base:netstack3-base",
+        "//src/connectivity/network/netstack3/core/sync:netstack3-sync",
+      ]
     },
 
     {
@@ -55,15 +49,37 @@
       features = [ "instrumented" ]
       with_unit_tests = true
       deps += [ "//src/connectivity/network/netstack3/core/sync:netstack3-sync-instrumented" ]
+      non_test_deps =
+          [ "//src/connectivity/network/netstack3/core/base:netstack3-base" ]
+      test_deps = [
+        "//src/connectivity/lib/ip-test-macro",
+        "//src/connectivity/lib/net-declare",
+        "//src/connectivity/network/netstack3/core/base:netstack3-base-testutils",
+        "//src/lib/const-unwrap",
+        "//third_party/rust_crates:test-case",
+      ]
     },
 
     {
       target_name = "netstack3-filter-testutils"
+      testonly = true
       features = [
         "testutils",
         "instrumented",
       ]
-      deps += [ "//src/connectivity/network/netstack3/core/sync:netstack3-sync-instrumented" ]
+      deps += [
+        "//src/connectivity/network/netstack3/core/base:netstack3-base-testutils",
+        "//src/connectivity/network/netstack3/core/sync:netstack3-sync-instrumented",
+      ]
+    },
+    {
+      target_name = "netstack3-filter-benchmarks"
+      testonly = true
+      features = [ "testutils" ]
+      deps += [
+        "//src/connectivity/network/netstack3/core/base:netstack3-base-testutils",
+        "//src/connectivity/network/netstack3/core/sync:netstack3-sync",
+      ]
     },
   ]
 
@@ -74,6 +90,7 @@
         testonly = true
         features = []
         deps += [
+          "//src/connectivity/network/netstack3/core/base:netstack3-base-testutils",
           "//src/connectivity/network/netstack3/core/sync:netstack3-sync-loom",
         ]
         configs += [ "//src/connectivity/network/netstack3/core:loom" ]
@@ -83,13 +100,13 @@
 }
 
 fuchsia_unittest_package("netstack3-filter-test") {
-  deps = [ ":netstack3-filter_test" ]
+  deps = [ ":netstack3-filter-instrumented_test" ]
 }
 
 group("tests") {
   testonly = true
   public_deps = [
+    ":netstack3-filter-instrumented_test($host_toolchain)",
     ":netstack3-filter-test",
-    ":netstack3-filter_test($host_toolchain)",
   ]
 }
diff --git a/src/connectivity/network/netstack3/core/filter/src/api.rs b/src/connectivity/network/netstack3/core/filter/src/api.rs
index 4d144f0..361eeaa 100644
--- a/src/connectivity/network/netstack3/core/filter/src/api.rs
+++ b/src/connectivity/network/netstack3/core/filter/src/api.rs
@@ -3,9 +3,12 @@
 // found in the LICENSE file.
 
 use net_types::ip::{Ipv4, Ipv6};
-use netstack3_base::ContextPair;
+use netstack3_base::{ContextPair, Inspector};
+use tracing::info;
 
-use crate::{FilterBindingsTypes, FilterContext, Routines, ValidRoutines, ValidationError};
+use crate::{
+    FilterBindingsTypes, FilterContext, FilterIpContext, Routines, ValidRoutines, ValidationError,
+};
 
 /// The filtering API.
 pub struct FilterApi<C>(C);
@@ -20,7 +23,9 @@
 impl<C> FilterApi<C>
 where
     C: ContextPair,
-    C::CoreContext: FilterContext<C::BindingsContext>,
+    C::CoreContext: FilterContext<C::BindingsContext>
+        + FilterIpContext<Ipv4, C::BindingsContext>
+        + FilterIpContext<Ipv6, C::BindingsContext>,
     C::BindingsContext: FilterBindingsTypes,
 {
     fn core_ctx(&mut self) -> &mut C::CoreContext {
@@ -42,16 +47,36 @@
         v4: Routines<Ipv4, <C::BindingsContext as FilterBindingsTypes>::DeviceClass, RuleInfo>,
         v6: Routines<Ipv6, <C::BindingsContext as FilterBindingsTypes>::DeviceClass, RuleInfo>,
     ) -> Result<(), ValidationError<RuleInfo>> {
-        let v4 = ValidRoutines::new(v4)?;
-        let v6 = ValidRoutines::new(v6)?;
+        let (v4_installed, v4_uninstalled) = ValidRoutines::new(v4)?;
+        let (v6_installed, v6_uninstalled) = ValidRoutines::new(v6)?;
 
-        tracing::info!("updating filtering state:\nv4: {:?}\nv6: {:?}", v4.get(), v6.get());
+        info!(
+            "updating filtering state:\nv4: {:?}\nv6: {:?}",
+            v4_installed.get(),
+            v6_installed.get(),
+        );
 
-        self.core_ctx().with_all_filter_state_mut(|state_v4, state_v6| {
-            state_v4.routines = v4;
-            state_v6.routines = v6;
+        self.core_ctx().with_all_filter_state_mut(|v4, v6| {
+            v4.installed_routines = v4_installed;
+            v4.uninstalled_routines = v4_uninstalled;
+            v6.installed_routines = v6_installed;
+            v6.uninstalled_routines = v6_uninstalled;
         });
 
         Ok(())
     }
+
+    /// Exports filtering state into `inspector`.
+    pub fn inspect_state<N: Inspector>(&mut self, inspector: &mut N) {
+        inspector.record_child("IPv4", |inspector| {
+            FilterIpContext::<Ipv4, _>::with_filter_state(self.core_ctx(), |state| {
+                inspector.delegate_inspectable(state);
+            });
+        });
+        inspector.record_child("IPv6", |inspector| {
+            FilterIpContext::<Ipv6, _>::with_filter_state(self.core_ctx(), |state| {
+                inspector.delegate_inspectable(state);
+            });
+        });
+    }
 }
diff --git a/src/connectivity/network/netstack3/core/filter/src/conntrack.rs b/src/connectivity/network/netstack3/core/filter/src/conntrack.rs
index c4c64389..8f7f639 100644
--- a/src/connectivity/network/netstack3/core/filter/src/conntrack.rs
+++ b/src/connectivity/network/netstack3/core/filter/src/conntrack.rs
@@ -5,9 +5,13 @@
 use alloc::{collections::HashMap, sync::Arc};
 use core::hash::Hash;
 
+use derivative::Derivative;
 use packet_formats::ip::IpExt;
 
-use crate::{packets::TransportPacket, IpPacket, MaybeTransportPacket};
+use crate::{
+    context::FilterBindingsContext, packets::TransportPacket, FilterBindingsTypes, IpPacket,
+    MaybeTransportPacket,
+};
 use netstack3_sync::Mutex;
 
 /// Implements a connection tracking subsystem.
@@ -16,15 +20,16 @@
 /// struct and can be extracted with the [`Connection::external_data()`]
 /// function.
 #[allow(dead_code)]
-#[derive(Default)]
-pub struct Table<I: IpExt, E> {
+#[derive(Derivative)]
+#[derivative(Default(bound = ""))]
+pub struct Table<I: IpExt, BT: FilterBindingsTypes, E> {
     /// A connection is inserted into the map twice: once for the original
     /// tuple, and once for the reply tuple.
-    map: Mutex<HashMap<Tuple<I>, Arc<ConnectionShared<I, E>>>>,
+    map: Mutex<HashMap<Tuple<I>, Arc<ConnectionShared<I, BT, E>>>>,
 }
 
 #[allow(dead_code)]
-impl<I: IpExt, E> Table<I, E> {
+impl<I: IpExt, BT: FilterBindingsTypes, E> Table<I, BT, E> {
     pub(crate) fn new() -> Self {
         Self { map: Mutex::new(HashMap::new()) }
     }
@@ -49,7 +54,7 @@
     /// to be able to manipulate its internal map.
     pub(crate) fn finalize_connection(
         &self,
-        connection: Connection<I, E>,
+        connection: Connection<I, BT, E>,
     ) -> Result<bool, FinalizeConnectionError> {
         let exclusive = match connection {
             Connection::Exclusive(c) => c,
@@ -94,7 +99,7 @@
 }
 
 #[allow(dead_code)]
-impl<I: IpExt, E: Default> Table<I, E> {
+impl<I: IpExt, BC: FilterBindingsContext, E: Default> Table<I, BC, E> {
     /// Returns a [`Connection`] for the packet's flow. If a connection does not
     /// currently exist, a new one is created.
     ///
@@ -106,16 +111,30 @@
     /// connection.
     pub(crate) fn get_connection_for_packet_and_update<P: IpPacket<I>>(
         &self,
+        bindings_ctx: &BC,
         packet: &P,
-    ) -> Option<Connection<I, E>> {
+    ) -> Option<Connection<I, BC, E>> {
         let tuple = Tuple::from_packet(packet)?;
 
-        // TODO(https://fxbug.dev/328064022): Add call to Connection::update()
-        // once that's implemented.
-        if let Some(connection) = self.map.lock().get(&tuple) {
-            Some(Connection::Shared(connection.clone()))
-        } else {
-            Some(Connection::Exclusive(tuple.into()))
+        let mut connection = match self.map.lock().get(&tuple) {
+            Some(connection) => Connection::Shared(connection.clone()),
+            None => {
+                Connection::Exclusive(ConnectionExclusive::from_tuple(bindings_ctx, tuple.clone()))
+            }
+        };
+
+        match connection.update(bindings_ctx, &tuple) {
+            Ok(()) => Some(connection),
+            Err(e) => match e {
+                ConnectionUpdateError::NonMatchingTuple => {
+                    panic!(
+                        "Tuple didn't match. tuple={:?}, conn.original={:?}, conn.reply={:?}",
+                        &tuple,
+                        connection.original_tuple(),
+                        connection.reply_tuple()
+                    );
+                }
+            },
         }
     }
 }
@@ -186,22 +205,29 @@
     Conflict,
 }
 
+/// An error returned from [`Connection::update`].
+#[derive(Debug)]
+pub(crate) enum ConnectionUpdateError {
+    /// The provided tuple doesn't belong to the connection being updated.
+    NonMatchingTuple,
+}
+
 /// A `Connection` contains all of the information about a single connection
 /// tracked by conntrack.
 #[derive(Debug)]
 #[allow(dead_code)]
-pub enum Connection<I: IpExt, E> {
+pub enum Connection<I: IpExt, BT: FilterBindingsTypes, E> {
     /// A connection that is directly owned by the packet that originated the
     /// connection and no others. All fields are modifiable.
-    Exclusive(ConnectionExclusive<I, E>),
+    Exclusive(ConnectionExclusive<I, BT, E>),
 
     /// This is an existing connection, and there are possibly many other
     /// packets that are concurrently modifying it.
-    Shared(Arc<ConnectionShared<I, E>>),
+    Shared(Arc<ConnectionShared<I, BT, E>>),
 }
 
 #[allow(dead_code)]
-impl<I: IpExt, E> Connection<I, E> {
+impl<I: IpExt, BT: FilterBindingsTypes, E> Connection<I, BT, E> {
     /// Returns the tuple of the original direction of this connection
     pub(crate) fn original_tuple(&self) -> &Tuple<I> {
         match self {
@@ -242,11 +268,35 @@
             None
         }
     }
+
+    /// Returns a copy of the internal connection state
+    pub(crate) fn state(&self) -> ConnectionState<BT> {
+        match self {
+            Connection::Exclusive(c) => c.state.clone(),
+            Connection::Shared(c) => c.state.lock().clone(),
+        }
+    }
+}
+
+impl<I: IpExt, BC: FilterBindingsContext, E> Connection<I, BC, E> {
+    fn update(&mut self, bindings_ctx: &BC, tuple: &Tuple<I>) -> Result<(), ConnectionUpdateError> {
+        let direction = match self.direction(tuple) {
+            Some(d) => d,
+            None => return Err(ConnectionUpdateError::NonMatchingTuple),
+        };
+
+        let now = bindings_ctx.now();
+
+        match self {
+            Connection::Exclusive(c) => c.state.update(direction, now),
+            Connection::Shared(c) => c.state.lock().update(direction, now),
+        }
+    }
 }
 
 /// Fields common to both [`ConnectionExclusive`] and [`ConnectionShared`].
 #[derive(Debug)]
-pub(crate) struct ConnectionCommon<I: IpExt, E> {
+pub struct ConnectionCommon<I: IpExt, E> {
     /// The 5-tuple for the connection in the original direction. This is
     /// arbitrary, and is just the direction where a packet was first seen.
     pub(crate) original_tuple: Tuple<I>,
@@ -261,6 +311,37 @@
     pub(crate) external_data: E,
 }
 
+/// Dynamic per-connection state.
+#[derive(Debug, Derivative)]
+#[derivative(Clone(bound = ""))]
+pub(crate) struct ConnectionState<BT: FilterBindingsTypes> {
+    /// Whether this connection has seen packets in both directions.
+    established: bool,
+
+    /// The time the last packet was seen for this connection (in either of the
+    /// original or reply directions).
+    last_packet_time: BT::Instant,
+}
+
+impl<BT: FilterBindingsTypes> ConnectionState<BT> {
+    fn update(
+        &mut self,
+        dir: ConnectionDirection,
+        now: BT::Instant,
+    ) -> Result<(), ConnectionUpdateError> {
+        match dir {
+            ConnectionDirection::Original => (),
+            ConnectionDirection::Reply => self.established = true,
+        };
+
+        if self.last_packet_time < now {
+            self.last_packet_time = now;
+        }
+
+        Ok(())
+    }
+}
+
 /// A conntrack connection with single ownership.
 ///
 /// Because of this, many fields may be updated without synchronization. There
@@ -268,25 +349,27 @@
 /// out-of-sync with the table (e.g. by changing the tuples once the connection
 /// has been inserted).
 #[derive(Debug)]
-pub(crate) struct ConnectionExclusive<I: IpExt, E> {
+pub struct ConnectionExclusive<I: IpExt, BT: FilterBindingsTypes, E> {
     pub(crate) inner: ConnectionCommon<I, E>,
+    pub(crate) state: ConnectionState<BT>,
 }
 
 #[allow(dead_code)]
-impl<I: IpExt, E> ConnectionExclusive<I, E> {
+impl<I: IpExt, BT: FilterBindingsTypes, E> ConnectionExclusive<I, BT, E> {
     /// Turn this exclusive connection into a shared one. This is required in
     /// order to insert into the [`Table`] table.
-    fn make_shared(self) -> Arc<ConnectionShared<I, E>> {
-        Arc::new(ConnectionShared { inner: self.inner })
+    fn make_shared(self) -> Arc<ConnectionShared<I, BT, E>> {
+        Arc::new(ConnectionShared { inner: self.inner, state: Mutex::new(self.state) })
     }
 }
 
-impl<I: IpExt, E: Default> From<Tuple<I>> for ConnectionExclusive<I, E> {
-    fn from(original_tuple: Tuple<I>) -> Self {
+impl<I: IpExt, BC: FilterBindingsContext, E: Default> ConnectionExclusive<I, BC, E> {
+    fn from_tuple(bindings_ctx: &BC, original_tuple: Tuple<I>) -> Self {
         let reply_tuple = original_tuple.clone().invert();
 
         Self {
             inner: ConnectionCommon { original_tuple, reply_tuple, external_data: E::default() },
+            state: ConnectionState { established: false, last_packet_time: bindings_ctx.now() },
         }
     }
 }
@@ -297,13 +380,14 @@
 /// itself, will be depending on them not to change. Fields must be accessed
 /// through the associated methods.
 #[derive(Debug)]
-pub(crate) struct ConnectionShared<I: IpExt, E> {
+pub struct ConnectionShared<I: IpExt, BT: FilterBindingsTypes, E> {
     inner: ConnectionCommon<I, E>,
+    state: Mutex<ConnectionState<BT>>,
 }
 
 #[cfg(test)]
 mod tests {
-    use core::convert::Infallible as Never;
+    use core::{convert::Infallible as Never, time::Duration};
 
     use assert_matches::assert_matches;
     use ip_test_macro::ip_test;
@@ -313,7 +397,10 @@
     use test_case::test_case;
 
     use super::*;
-    use crate::packets::testutil::internal::{FakeIpPacket, FakeTcpSegment, TransportPacketExt};
+    use crate::{
+        context::testutil::FakeBindingsCtx,
+        packets::testutil::internal::{FakeIpPacket, FakeTcpSegment, TransportPacketExt},
+    };
 
     trait TestIpExt: Ip {
         const SRC_ADDR: Self::Addr;
@@ -409,6 +496,8 @@
     #[test_case(IpProto::Udp)]
     #[test_case(IpProto::Tcp)]
     fn connection_from_tuple<I: Ip + IpExt + TestIpExt>(protocol: IpProto) {
+        let bindings_ctx = FakeBindingsCtx::new();
+
         let original_tuple = Tuple::<I> {
             protocol: protocol.into(),
             src_addr: I::SRC_ADDR,
@@ -418,7 +507,8 @@
         };
         let reply_tuple = original_tuple.clone().invert();
 
-        let connection: ConnectionExclusive<I, ()> = original_tuple.clone().into();
+        let connection =
+            ConnectionExclusive::<_, _, ()>::from_tuple(&bindings_ctx, original_tuple.clone());
 
         assert_eq!(&connection.inner.original_tuple, &original_tuple);
         assert_eq!(&connection.inner.reply_tuple, &reply_tuple);
@@ -426,6 +516,8 @@
 
     #[ip_test]
     fn connection_make_shared_has_same_underlying_info<I: Ip + IpExt + TestIpExt>() {
+        let bindings_ctx = FakeBindingsCtx::new();
+
         let original_tuple = Tuple::<I> {
             protocol: I::Proto::from(IpProto::Tcp),
             src_addr: I::SRC_ADDR,
@@ -435,7 +527,7 @@
         };
         let reply_tuple = original_tuple.clone().invert();
 
-        let mut connection: ConnectionExclusive<I, u32> = original_tuple.clone().into();
+        let mut connection = ConnectionExclusive::from_tuple(&bindings_ctx, original_tuple.clone());
         connection.inner.external_data = 1234;
         let shared = connection.make_shared();
 
@@ -453,6 +545,8 @@
     #[test_case(ConnectionKind::Exclusive)]
     #[test_case(ConnectionKind::Shared)]
     fn connection_getters<I: Ip + IpExt + TestIpExt>(connection_kind: ConnectionKind) {
+        let bindings_ctx = FakeBindingsCtx::new();
+
         let original_tuple = Tuple::<I> {
             protocol: I::Proto::from(IpProto::Tcp),
             src_addr: I::SRC_ADDR,
@@ -462,7 +556,7 @@
         };
         let reply_tuple = original_tuple.clone().invert();
 
-        let mut connection: ConnectionExclusive<I, u32> = original_tuple.clone().into();
+        let mut connection = ConnectionExclusive::from_tuple(&bindings_ctx, original_tuple.clone());
         connection.inner.external_data = 1234;
 
         let connection = match connection_kind {
@@ -479,6 +573,8 @@
     #[test_case(ConnectionKind::Exclusive)]
     #[test_case(ConnectionKind::Shared)]
     fn connection_direction<I: Ip + IpExt + TestIpExt>(connection_kind: ConnectionKind) {
+        let bindings_ctx = FakeBindingsCtx::new();
+
         let original_tuple = Tuple::<I> {
             protocol: I::Proto::from(IpProto::Tcp),
             src_addr: I::SRC_ADDR,
@@ -491,7 +587,8 @@
         let mut other_tuple = original_tuple.clone();
         other_tuple.src_port_or_id += 1;
 
-        let connection: ConnectionExclusive<I, ()> = original_tuple.clone().into();
+        let connection =
+            ConnectionExclusive::<_, _, ()>::from_tuple(&bindings_ctx, original_tuple.clone());
         let connection = match connection_kind {
             ConnectionKind::Exclusive => Connection::Exclusive(connection),
             ConnectionKind::Shared => Connection::Shared(connection.make_shared()),
@@ -503,8 +600,60 @@
     }
 
     #[ip_test]
+    #[test_case(ConnectionKind::Exclusive)]
+    #[test_case(ConnectionKind::Shared)]
+    fn connection_update<I: Ip + IpExt + TestIpExt>(connection_kind: ConnectionKind) {
+        let mut bindings_ctx = FakeBindingsCtx::new();
+        bindings_ctx.set_time_elapsed(Duration::from_secs(12));
+
+        let original_tuple = Tuple::<I> {
+            protocol: I::Proto::from(IpProto::Tcp),
+            src_addr: I::SRC_ADDR,
+            dst_addr: I::DST_ADDR,
+            src_port_or_id: I::SRC_PORT,
+            dst_port_or_id: I::DST_PORT,
+        };
+        let reply_tuple = original_tuple.clone().invert();
+
+        let mut other_tuple = original_tuple.clone();
+        other_tuple.src_port_or_id += 1;
+
+        let connection =
+            ConnectionExclusive::<_, _, ()>::from_tuple(&bindings_ctx, original_tuple.clone());
+        let mut connection = match connection_kind {
+            ConnectionKind::Exclusive => Connection::Exclusive(connection),
+            ConnectionKind::Shared => Connection::Shared(connection.make_shared()),
+        };
+
+        assert_matches!(connection.update(&bindings_ctx, &original_tuple), Ok(()));
+        let state = connection.state();
+        assert!(!state.established);
+        assert_eq!(state.last_packet_time.offset, Duration::from_secs(12));
+
+        // Tuple in reply direction should set established to true and obviously
+        // update last packet time.
+        bindings_ctx.set_time_elapsed(Duration::from_secs(13));
+        assert_matches!(connection.update(&bindings_ctx, &reply_tuple), Ok(()));
+        let state = connection.state();
+        assert!(state.established);
+        assert_eq!(state.last_packet_time.offset, Duration::from_secs(13));
+
+        // Unrelated connection should return an error and otherwise not touch
+        // anything.
+        bindings_ctx.set_time_elapsed(Duration::from_secs(14));
+        assert_matches!(
+            connection.update(&bindings_ctx, &other_tuple),
+            Err(ConnectionUpdateError::NonMatchingTuple)
+        );
+        assert!(state.established);
+        assert_eq!(state.last_packet_time.offset, Duration::from_secs(13));
+    }
+
+    #[ip_test]
     fn table_get_exclusive_connection_and_finalize_shared<I: Ip + IpExt + TestIpExt>() {
-        let table = Table::<I, ()>::new();
+        let mut bindings_ctx = FakeBindingsCtx::new();
+        bindings_ctx.set_time_elapsed(Duration::from_secs(12));
+        let table = Table::<_, _, ()>::new();
 
         let packet = FakeIpPacket::<I, _> {
             src_ip: I::SRC_ADDR,
@@ -521,9 +670,12 @@
         let original_tuple = Tuple::from_packet(&packet).expect("packet should be valid");
         let reply_tuple = Tuple::from_packet(&reply_packet).expect("packet should be valid");
 
-        // TODO(https://fxbug.dev/328064022): Add check for state update.
-        let conn =
-            table.get_connection_for_packet_and_update(&packet).expect("packet should be valid");
+        let conn = table
+            .get_connection_for_packet_and_update(&bindings_ctx, &packet)
+            .expect("packet should be valid");
+        let state = conn.state();
+        assert!(!state.established);
+        assert_eq!(state.last_packet_time.offset, Duration::from_secs(12));
 
         // Since the connection isn't present in the map, we should get a
         // freshly-allocated exclusive connection and the map should not have
@@ -539,17 +691,27 @@
 
         // We should now get a shared connection back for packets in either
         // direction now that the connection is present in the table.
-        let conn = table.get_connection_for_packet_and_update(&packet);
-        let conn = assert_matches!(conn, Some(Connection::Shared(conn)) => conn);
+        bindings_ctx.set_time_elapsed(Duration::from_secs(13));
+        let conn = table.get_connection_for_packet_and_update(&bindings_ctx, &packet);
+        let conn = assert_matches!(conn, Some(conn) => conn);
+        let state = conn.state();
+        assert!(!state.established);
+        assert_eq!(state.last_packet_time.offset, Duration::from_secs(13));
+        let conn = assert_matches!(conn, Connection::Shared(conn) => conn);
 
-        let reply_conn = table.get_connection_for_packet_and_update(&reply_packet);
-        let reply_conn = assert_matches!(reply_conn, Some(Connection::Shared(conn)) => conn);
+        bindings_ctx.set_time_elapsed(Duration::from_secs(14));
+        let reply_conn = table.get_connection_for_packet_and_update(&bindings_ctx, &reply_packet);
+        let reply_conn = assert_matches!(reply_conn, Some(conn) => conn);
+        let state = reply_conn.state();
+        assert!(state.established);
+        assert_eq!(state.last_packet_time.offset, Duration::from_secs(14));
+        let reply_conn = assert_matches!(reply_conn, Connection::Shared(conn) => conn);
 
         // We should be getting the same connection in both directions.
         assert!(Arc::ptr_eq(&conn, &reply_conn));
 
         // Inserting the connection a second time shouldn't change the map.
-        let conn = table.get_connection_for_packet_and_update(&packet).unwrap();
+        let conn = table.get_connection_for_packet_and_update(&bindings_ctx, &packet).unwrap();
         assert_matches!(table.finalize_connection(conn), Ok(false));
         assert!(table.contains_tuple(&original_tuple));
         assert!(table.contains_tuple(&reply_tuple));
@@ -557,7 +719,8 @@
 
     #[ip_test]
     fn table_conflict<I: Ip + IpExt + TestIpExt>() {
-        let table = Table::new();
+        let bindings_ctx = FakeBindingsCtx::new();
+        let table = Table::<_, _, ()>::new();
 
         let original_tuple = Tuple::<I> {
             protocol: I::Proto::from(IpProto::Tcp),
@@ -583,17 +746,22 @@
             dst_port_or_id: I::SRC_PORT + 1,
         };
 
-        let conn1: Connection<I, ()> = Connection::Exclusive(original_tuple.clone().into());
+        let conn1 = Connection::Exclusive(ConnectionExclusive::<_, _, ()>::from_tuple(
+            &bindings_ctx,
+            original_tuple.clone(),
+        ));
 
         // Fake NAT that ends up allocating the same reply tuple as an existing
         // connection.
-        let mut conn2: ConnectionExclusive<I, ()> = original_tuple.clone().into();
+        let mut conn2 =
+            ConnectionExclusive::<_, _, ()>::from_tuple(&bindings_ctx, original_tuple.clone());
         conn2.inner.original_tuple = nated_original_tuple.clone();
         let conn2 = Connection::Exclusive(conn2);
 
         // Fake NAT that ends up allocating the same original tuple as an
         // existing connection.
-        let mut conn3: ConnectionExclusive<I, ()> = original_tuple.clone().into();
+        let mut conn3 =
+            ConnectionExclusive::<_, _, ()>::from_tuple(&bindings_ctx, original_tuple.clone());
         conn3.inner.reply_tuple = nated_reply_tuple.clone();
         let conn3 = Connection::Exclusive(conn3);
 
diff --git a/src/connectivity/network/netstack3/core/filter/src/context.rs b/src/connectivity/network/netstack3/core/filter/src/context.rs
index 32d1641..864d483 100644
--- a/src/connectivity/network/netstack3/core/filter/src/context.rs
+++ b/src/connectivity/network/netstack3/core/filter/src/context.rs
@@ -5,20 +5,25 @@
 use core::fmt::Debug;
 
 use net_types::ip::{Ipv4, Ipv6};
+use netstack3_base::{InstantBindingsTypes, InstantContext};
 use packet_formats::ip::IpExt;
 
 use crate::state::State;
 
-/// Trait defining the `DeviceClass` type provided by bindings.
+/// Trait defining required types for filtering provided by bindings.
 ///
 /// Allows rules that match on device class to be installed, storing the
 /// [`FilterBindingsTypes::DeviceClass`] type at rest, while allowing Netstack3
 /// Core to have Bindings provide the type since it is platform-specific.
-pub trait FilterBindingsTypes {
+pub trait FilterBindingsTypes: InstantBindingsTypes {
     /// The device class type for devices installed in the netstack.
     type DeviceClass: Clone + Debug;
 }
 
+/// Trait aggregating functionality required from bindings.
+pub trait FilterBindingsContext: InstantContext + FilterBindingsTypes {}
+impl<BC: InstantContext + FilterBindingsTypes> FilterBindingsContext for BC {}
+
 /// The IP version-specific execution context for packet filtering.
 ///
 /// This trait exists to abstract over access to the filtering state. It is
@@ -29,17 +34,14 @@
 /// a given lock level, while keeping test code free of locking concerns.
 pub trait FilterIpContext<I: IpExt, BT: FilterBindingsTypes> {
     /// Calls the function with a reference to filtering state.
-    fn with_filter_state<O, F: FnOnce(&State<I, BT::DeviceClass>) -> O>(&mut self, cb: F) -> O;
+    fn with_filter_state<O, F: FnOnce(&State<I, BT>) -> O>(&mut self, cb: F) -> O;
 }
 
 /// A context for mutably accessing all filtering state at once, to allow IPv4
 /// and IPv6 filtering state to be modified atomically.
 pub trait FilterContext<BT: FilterBindingsTypes> {
     /// Calls the function with a mutable reference to all filtering state.
-    fn with_all_filter_state_mut<
-        O,
-        F: FnOnce(&mut State<Ipv4, BT::DeviceClass>, &mut State<Ipv6, BT::DeviceClass>) -> O,
-    >(
+    fn with_all_filter_state_mut<O, F: FnOnce(&mut State<Ipv4, BT>, &mut State<Ipv6, BT>) -> O>(
         &mut self,
         cb: F,
     ) -> O;
@@ -47,6 +49,10 @@
 
 #[cfg(test)]
 pub(crate) mod testutil {
+    use core::time::Duration;
+
+    use netstack3_base::testutil::FakeInstant;
+
     use super::*;
     use crate::{
         conntrack,
@@ -61,24 +67,67 @@
 
     pub enum FakeBindingsTypes {}
 
+    impl InstantBindingsTypes for FakeBindingsTypes {
+        type Instant = FakeInstant;
+    }
+
     impl FilterBindingsTypes for FakeBindingsTypes {
         type DeviceClass = FakeDeviceClass;
     }
 
-    pub struct FakeCtx<I: IpExt>(State<I, FakeDeviceClass>);
+    pub struct FakeCtx<I: IpExt, BT: FilterBindingsTypes>(State<I, BT>);
 
-    impl<I: IpExt> FakeCtx<I> {
-        pub fn with_ip_routines(routines: IpRoutines<I, FakeDeviceClass, ()>) -> Self {
-            let valid_state = ValidRoutines::new(Routines { ip: routines, ..Default::default() })
-                .expect("invalid state");
-            Self(State { routines: valid_state, conntrack: conntrack::Table::new() })
+    impl<I: IpExt, BT: FilterBindingsTypes> FakeCtx<I, BT> {
+        #[allow(dead_code)]
+        pub fn with_ip_routines(routines: IpRoutines<I, BT::DeviceClass, ()>) -> Self {
+            let (installed_routines, uninstalled_routines) =
+                ValidRoutines::new(Routines { ip: routines, ..Default::default() })
+                    .expect("invalid state");
+            Self(State {
+                installed_routines,
+                uninstalled_routines,
+                conntrack: conntrack::Table::new(),
+            })
         }
     }
 
-    impl<I: IpExt> FilterIpContext<I, FakeBindingsTypes> for FakeCtx<I> {
-        fn with_filter_state<O, F: FnOnce(&State<I, FakeDeviceClass>) -> O>(&mut self, cb: F) -> O {
+    impl<I: IpExt> FilterIpContext<I, FakeBindingsTypes> for FakeCtx<I, FakeBindingsTypes> {
+        fn with_filter_state<O, F: FnOnce(&State<I, FakeBindingsTypes>) -> O>(
+            &mut self,
+            cb: F,
+        ) -> O {
             let Self(state) = self;
             cb(&*state)
         }
     }
+
+    #[derive(Debug)]
+    pub struct FakeBindingsCtx {
+        time_elapsed: Duration,
+    }
+
+    #[allow(dead_code)]
+    impl FakeBindingsCtx {
+        pub(crate) fn new() -> Self {
+            Self { time_elapsed: Duration::from_secs(0) }
+        }
+
+        pub(crate) fn set_time_elapsed(&mut self, time_elapsed: Duration) {
+            self.time_elapsed = time_elapsed;
+        }
+    }
+
+    impl InstantBindingsTypes for FakeBindingsCtx {
+        type Instant = FakeInstant;
+    }
+
+    impl FilterBindingsTypes for FakeBindingsCtx {
+        type DeviceClass = FakeDeviceClass;
+    }
+
+    impl InstantContext for FakeBindingsCtx {
+        fn now(&self) -> Self::Instant {
+            Self::Instant { offset: self.time_elapsed }
+        }
+    }
 }
diff --git a/src/connectivity/network/netstack3/core/filter/src/lib.rs b/src/connectivity/network/netstack3/core/filter/src/lib.rs
index ae111fe..02fee08 100644
--- a/src/connectivity/network/netstack3/core/filter/src/lib.rs
+++ b/src/connectivity/network/netstack3/core/filter/src/lib.rs
@@ -17,9 +17,12 @@
 mod packets;
 mod state;
 
+/// A connection as tracked by conntrack.
+pub type ConntrackConnection<I, BT> = conntrack::Connection<I, BT, state::ConntrackExternalData>;
+
 pub use api::FilterApi;
-pub use context::{FilterBindingsTypes, FilterContext, FilterIpContext};
-pub use logic::{FilterHandler, FilterImpl, Verdict};
+pub use context::{FilterBindingsContext, FilterBindingsTypes, FilterContext, FilterIpContext};
+pub use logic::{FilterHandler, FilterImpl, ProofOfEgressCheck, Verdict};
 pub use matchers::{
     AddressMatcher, AddressMatcherType, InterfaceMatcher, InterfaceProperties, PacketMatcher,
     PortMatcher, TransportProtocolMatcher,
@@ -30,8 +33,8 @@
 };
 pub use state::{
     validation::{ValidRoutines, ValidationError},
-    Action, ConntrackExternalData, Hook, IpRoutines, NatRoutines, Routine, Routines, Rule, State,
-    UninstalledRoutine,
+    Action, ConntrackExternalData, FilterIpMetadata, Hook, IpRoutines, NatRoutines, Routine,
+    Routines, Rule, State, UninstalledRoutine,
 };
 
 /// Testing-related utilities for use by other crates.
diff --git a/src/connectivity/network/netstack3/core/filter/src/logic.rs b/src/connectivity/network/netstack3/core/filter/src/logic.rs
index 02d847d..19dd02d 100644
--- a/src/connectivity/network/netstack3/core/filter/src/logic.rs
+++ b/src/connectivity/network/netstack3/core/filter/src/logic.rs
@@ -9,6 +9,7 @@
     matchers::InterfaceProperties,
     packets::IpPacket,
     state::{Action, Hook, Routine, Rule},
+    FilterIpMetadata,
 };
 
 /// The result of packet processing at a given filtering hook.
@@ -20,6 +21,12 @@
     Drop,
 }
 
+/// A witness type to indicate that the egress filtering hook has been run.
+#[derive(Debug)]
+pub struct ProofOfEgressCheck {
+    _private_field_to_prevent_construction_outside_of_module: (),
+}
+
 pub(crate) struct Interfaces<'a, D> {
     pub ingress: Option<&'a D>,
     pub egress: Option<&'a D>,
@@ -90,43 +97,64 @@
 pub trait FilterHandler<I: IpExt, BT: FilterBindingsTypes> {
     /// The ingress hook intercepts incoming traffic before a routing decision
     /// has been made.
-    fn ingress_hook<P, D>(&mut self, packet: &mut P, interface: &D) -> Verdict
+    fn ingress_hook<P, D, M>(&mut self, packet: &mut P, interface: &D, metadata: &mut M) -> Verdict
     where
         P: IpPacket<I>,
-        D: InterfaceProperties<BT::DeviceClass>;
+        D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>;
 
     /// The local ingress hook intercepts incoming traffic that is destined for
     /// the local host.
-    fn local_ingress_hook<P, D>(&mut self, packet: &mut P, interface: &D) -> Verdict
+    fn local_ingress_hook<P, D, M>(
+        &mut self,
+        packet: &mut P,
+        interface: &D,
+        metadata: &mut M,
+    ) -> Verdict
     where
         P: IpPacket<I>,
-        D: InterfaceProperties<BT::DeviceClass>;
+        D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>;
 
     /// The forwarding hook intercepts incoming traffic that is destined for
     /// another host.
-    fn forwarding_hook<P, D>(
+    fn forwarding_hook<P, D, M>(
         &mut self,
         packet: &mut P,
         in_interface: &D,
         out_interface: &D,
+        metadata: &mut M,
     ) -> Verdict
     where
         P: IpPacket<I>,
-        D: InterfaceProperties<BT::DeviceClass>;
+        D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>;
 
     /// The local egress hook intercepts locally-generated traffic before a
     /// routing decision has been made.
-    fn local_egress_hook<P, D>(&mut self, packet: &mut P, interface: &D) -> Verdict
+    fn local_egress_hook<P, D, M>(
+        &mut self,
+        packet: &mut P,
+        interface: &D,
+        metadata: &mut M,
+    ) -> Verdict
     where
         P: IpPacket<I>,
-        D: InterfaceProperties<BT::DeviceClass>;
+        D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>;
 
     /// The egress hook intercepts all outgoing traffic after a routing decision
     /// has been made.
-    fn egress_hook<P, D>(&mut self, packet: &mut P, interface: &D) -> Verdict
+    fn egress_hook<P, D, M>(
+        &mut self,
+        packet: &mut P,
+        interface: &D,
+        metadata: &mut M,
+    ) -> (Verdict, ProofOfEgressCheck)
     where
         P: IpPacket<I>,
-        D: InterfaceProperties<BT::DeviceClass>;
+        D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>;
 }
 
 /// The "production" implementation of packet filtering.
@@ -138,84 +166,108 @@
 impl<I: IpExt, BT: FilterBindingsTypes, CC: FilterIpContext<I, BT>> FilterHandler<I, BT>
     for FilterImpl<'_, CC>
 {
-    fn ingress_hook<P, D>(&mut self, packet: &mut P, interface: &D) -> Verdict
+    fn ingress_hook<P, D, M>(&mut self, packet: &mut P, interface: &D, _metadata: &mut M) -> Verdict
     where
         P: IpPacket<I>,
         D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>,
     {
         let Self(this) = self;
         this.with_filter_state(|state| {
             check_routines_for_hook(
-                &state.routines.get().ip.ingress,
+                &state.installed_routines.get().ip.ingress,
                 packet,
                 Interfaces { ingress: Some(interface), egress: None },
             )
         })
     }
 
-    fn local_ingress_hook<P, D>(&mut self, packet: &mut P, interface: &D) -> Verdict
-    where
-        P: IpPacket<I>,
-        D: InterfaceProperties<BT::DeviceClass>,
-    {
-        let Self(this) = self;
-        this.with_filter_state(|state| {
-            check_routines_for_hook(
-                &state.routines.get().ip.local_ingress,
-                packet,
-                Interfaces { ingress: Some(interface), egress: None },
-            )
-        })
-    }
-
-    fn forwarding_hook<P, D>(
+    fn local_ingress_hook<P, D, M>(
         &mut self,
         packet: &mut P,
-        in_interface: &D,
-        out_interface: &D,
+        interface: &D,
+        _metadata: &mut M,
     ) -> Verdict
     where
         P: IpPacket<I>,
         D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>,
     {
         let Self(this) = self;
         this.with_filter_state(|state| {
             check_routines_for_hook(
-                &state.routines.get().ip.forwarding,
+                &state.installed_routines.get().ip.local_ingress,
+                packet,
+                Interfaces { ingress: Some(interface), egress: None },
+            )
+        })
+    }
+
+    fn forwarding_hook<P, D, M>(
+        &mut self,
+        packet: &mut P,
+        in_interface: &D,
+        out_interface: &D,
+        _metadata: &mut M,
+    ) -> Verdict
+    where
+        P: IpPacket<I>,
+        D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>,
+    {
+        let Self(this) = self;
+        this.with_filter_state(|state| {
+            check_routines_for_hook(
+                &state.installed_routines.get().ip.forwarding,
                 packet,
                 Interfaces { ingress: Some(in_interface), egress: Some(out_interface) },
             )
         })
     }
 
-    fn local_egress_hook<P, D>(&mut self, packet: &mut P, interface: &D) -> Verdict
+    fn local_egress_hook<P, D, M>(
+        &mut self,
+        packet: &mut P,
+        interface: &D,
+        _metadata: &mut M,
+    ) -> Verdict
     where
         P: IpPacket<I>,
         D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>,
     {
         let Self(this) = self;
         this.with_filter_state(|state| {
             check_routines_for_hook(
-                &state.routines.get().ip.local_egress,
+                &state.installed_routines.get().ip.local_egress,
                 packet,
                 Interfaces { ingress: None, egress: Some(interface) },
             )
         })
     }
 
-    fn egress_hook<P, D>(&mut self, packet: &mut P, interface: &D) -> Verdict
+    fn egress_hook<P, D, M>(
+        &mut self,
+        packet: &mut P,
+        interface: &D,
+        _metadata: &mut M,
+    ) -> (Verdict, ProofOfEgressCheck)
     where
         P: IpPacket<I>,
         D: InterfaceProperties<BT::DeviceClass>,
+        M: FilterIpMetadata<I, BT>,
     {
         let Self(this) = self;
-        this.with_filter_state(|state| {
-            check_routines_for_hook(
-                &state.routines.get().ip.egress,
-                packet,
-                Interfaces { ingress: None, egress: Some(interface) },
-            )
-        })
+        (
+            this.with_filter_state(|state| {
+                check_routines_for_hook(
+                    &state.installed_routines.get().ip.egress,
+                    packet,
+                    Interfaces { ingress: None, egress: Some(interface) },
+                )
+            }),
+            ProofOfEgressCheck { _private_field_to_prevent_construction_outside_of_module: () },
+        )
     }
 }
 
@@ -232,44 +284,61 @@
     pub struct NoopImpl;
 
     impl<I: IpExt, BT: FilterBindingsTypes> FilterHandler<I, BT> for NoopImpl {
-        fn ingress_hook<P, D>(&mut self, _: &mut P, _: &D) -> Verdict
+        fn ingress_hook<P, D, M>(&mut self, _: &mut P, _: &D, _: &mut M) -> Verdict
         where
             P: IpPacket<I>,
             D: InterfaceProperties<BT::DeviceClass>,
+            M: FilterIpMetadata<I, BT>,
         {
             Verdict::Accept
         }
 
-        fn local_ingress_hook<P, D>(&mut self, _: &mut P, _: &D) -> Verdict
+        fn local_ingress_hook<P, D, M>(&mut self, _: &mut P, _: &D, _: &mut M) -> Verdict
         where
             P: IpPacket<I>,
             D: InterfaceProperties<BT::DeviceClass>,
+            M: FilterIpMetadata<I, BT>,
         {
             Verdict::Accept
         }
 
-        fn forwarding_hook<P, D>(&mut self, _: &mut P, _: &D, _: &D) -> Verdict
+        fn forwarding_hook<P, D, M>(&mut self, _: &mut P, _: &D, _: &D, _: &mut M) -> Verdict
         where
             P: IpPacket<I>,
             D: InterfaceProperties<BT::DeviceClass>,
+            M: FilterIpMetadata<I, BT>,
         {
             Verdict::Accept
         }
 
-        fn local_egress_hook<P, D>(&mut self, _: &mut P, _: &D) -> Verdict
+        fn local_egress_hook<P, D, M>(&mut self, _: &mut P, _: &D, _: &mut M) -> Verdict
         where
             P: IpPacket<I>,
             D: InterfaceProperties<BT::DeviceClass>,
+            M: FilterIpMetadata<I, BT>,
         {
             Verdict::Accept
         }
 
-        fn egress_hook<P, D>(&mut self, _: &mut P, _: &D) -> Verdict
+        fn egress_hook<P, D, M>(
+            &mut self,
+            _: &mut P,
+            _: &D,
+            _: &mut M,
+        ) -> (Verdict, ProofOfEgressCheck)
         where
             P: IpPacket<I>,
             D: InterfaceProperties<BT::DeviceClass>,
+            M: FilterIpMetadata<I, BT>,
         {
-            Verdict::Accept
+            (Verdict::Accept, ProofOfEgressCheck::forge_proof_for_test())
+        }
+    }
+
+    impl ProofOfEgressCheck {
+        /// For tests where it's not feasible to run the egress hook.
+        pub(crate) fn forge_proof_for_test() -> Self {
+            ProofOfEgressCheck { _private_field_to_prevent_construction_outside_of_module: () }
         }
     }
 }
@@ -291,7 +360,7 @@
         packets::testutil::internal::{
             ArbitraryValue, FakeIpPacket, FakeTcpSegment, TestIpExt, TransportPacketExt,
         },
-        state::{IpRoutines, UninstalledRoutine},
+        state::{ConntrackExternalData, IpRoutines, UninstalledRoutine},
     };
 
     impl<I: IpExt> Rule<I, FakeDeviceClass, ()> {
@@ -320,7 +389,7 @@
             rules: vec![
                 Rule::new(
                     PacketMatcher::default(),
-                    Action::Jump(UninstalledRoutine::new(Vec::new())),
+                    Action::Jump(UninstalledRoutine::new(Vec::new(), 0)),
                 ),
                 Rule::new(PacketMatcher::default(), Action::Drop),
             ],
@@ -335,6 +404,23 @@
         );
     }
 
+    struct NullMetadata {}
+
+    impl<I: IpExt, BT: FilterBindingsTypes> FilterIpMetadata<I, BT> for NullMetadata {
+        fn take_conntrack_connection(
+            &mut self,
+        ) -> Option<crate::conntrack::Connection<I, BT, ConntrackExternalData>> {
+            unimplemented!();
+        }
+
+        fn replace_conntrack_connection(
+            &mut self,
+            _conn: crate::conntrack::Connection<I, BT, ConntrackExternalData>,
+        ) -> Option<crate::conntrack::Connection<I, BT, ConntrackExternalData>> {
+            unimplemented!();
+        }
+    }
+
     #[test]
     fn accept_by_default_if_no_matching_rules_in_hook() {
         assert_eq!(
@@ -390,10 +476,10 @@
                 // Jump to a routine that accepts all traffic.
                 Rule::new(
                     PacketMatcher::default(),
-                    Action::Jump(UninstalledRoutine::new(vec![Rule::new(
-                        PacketMatcher::default(),
-                        Action::Accept,
-                    )])),
+                    Action::Jump(UninstalledRoutine::new(
+                        vec![Rule::new(PacketMatcher::default(), Action::Accept)],
+                        0,
+                    )),
                 ),
                 // Drop all traffic.
                 Rule::new(PacketMatcher::default(), Action::Drop),
@@ -470,10 +556,10 @@
         let routine = Routine {
             rules: vec![Rule::new(
                 PacketMatcher::default(),
-                Action::Jump(UninstalledRoutine::new(vec![Rule::new(
-                    PacketMatcher::default(),
-                    Action::Drop,
-                )])),
+                Action::Jump(UninstalledRoutine::new(
+                    vec![Rule::new(PacketMatcher::default(), Action::Drop)],
+                    0,
+                )),
             )],
         };
         assert_eq!(
@@ -491,10 +577,10 @@
             rules: vec![
                 Rule::new(
                     PacketMatcher::default(),
-                    Action::Jump(UninstalledRoutine::new(vec![Rule::new(
-                        PacketMatcher::default(),
-                        Action::Accept,
-                    )])),
+                    Action::Jump(UninstalledRoutine::new(
+                        vec![Rule::new(PacketMatcher::default(), Action::Accept)],
+                        0,
+                    )),
                 ),
                 Rule::new(PacketMatcher::default(), Action::Drop),
             ],
@@ -514,10 +600,10 @@
             rules: vec![
                 Rule::new(
                     PacketMatcher::default(),
-                    Action::Jump(UninstalledRoutine::new(vec![Rule::new(
-                        PacketMatcher::default(),
-                        Action::Return,
-                    )])),
+                    Action::Jump(UninstalledRoutine::new(
+                        vec![Rule::new(PacketMatcher::default(), Action::Return)],
+                        0,
+                    )),
                 ),
                 Rule::new(PacketMatcher::default(), Action::Drop),
             ],
@@ -572,7 +658,8 @@
         assert_eq!(
             FilterImpl(&mut ctx).ingress_hook(
                 &mut FakeIpPacket::<I, FakeTcpSegment>::arbitrary_value(),
-                &wlan_interface()
+                &wlan_interface(),
+                &mut NullMetadata {},
             ),
             Verdict::Drop
         );
@@ -589,7 +676,8 @@
         assert_eq!(
             FilterImpl(&mut ctx).local_ingress_hook(
                 &mut FakeIpPacket::<I, FakeTcpSegment>::arbitrary_value(),
-                &wlan_interface()
+                &wlan_interface(),
+                &mut NullMetadata {},
             ),
             Verdict::Drop
         );
@@ -608,7 +696,8 @@
             FilterImpl(&mut ctx).forwarding_hook(
                 &mut FakeIpPacket::<I, FakeTcpSegment>::arbitrary_value(),
                 &wlan_interface(),
-                &ethernet_interface()
+                &ethernet_interface(),
+                &mut NullMetadata {},
             ),
             Verdict::Drop
         );
@@ -625,7 +714,8 @@
         assert_eq!(
             FilterImpl(&mut ctx).local_egress_hook(
                 &mut FakeIpPacket::<I, FakeTcpSegment>::arbitrary_value(),
-                &wlan_interface()
+                &wlan_interface(),
+                &mut NullMetadata {},
             ),
             Verdict::Drop
         );
@@ -640,10 +730,13 @@
             ..Default::default()
         });
         assert_eq!(
-            FilterImpl(&mut ctx).egress_hook(
-                &mut FakeIpPacket::<I, FakeTcpSegment>::arbitrary_value(),
-                &wlan_interface()
-            ),
+            FilterImpl(&mut ctx)
+                .egress_hook(
+                    &mut FakeIpPacket::<I, FakeTcpSegment>::arbitrary_value(),
+                    &wlan_interface(),
+                    &mut NullMetadata {},
+                )
+                .0,
             Verdict::Drop
         );
     }
@@ -716,6 +809,7 @@
                 ..ArbitraryValue::arbitrary_value()
             },
             &wlan_interface(),
+            &mut NullMetadata {},
         )
     }
 
@@ -746,6 +840,7 @@
         FilterImpl(&mut ctx).local_ingress_hook(
             &mut FakeIpPacket::<I, FakeTcpSegment>::arbitrary_value(),
             &interface,
+            &mut NullMetadata {},
         )
     }
 }
diff --git a/src/connectivity/network/netstack3/core/filter/src/state.rs b/src/connectivity/network/netstack3/core/filter/src/state.rs
index 1660b40..8ab537b 100644
--- a/src/connectivity/network/netstack3/core/filter/src/state.rs
+++ b/src/connectivity/network/netstack3/core/filter/src/state.rs
@@ -4,7 +4,7 @@
 
 pub mod validation;
 
-use alloc::{sync::Arc, vec::Vec};
+use alloc::{format, string::ToString as _, sync::Arc, vec::Vec};
 use core::{
     fmt::Debug,
     hash::{Hash, Hasher},
@@ -12,9 +12,10 @@
 
 use derivative::Derivative;
 use net_types::ip::{GenericOverIp, Ip};
+use netstack3_base::{Inspectable, Inspector as _};
 use packet_formats::ip::IpExt;
 
-use crate::{conntrack, matchers::PacketMatcher, ValidRoutines};
+use crate::{conntrack, context::FilterBindingsTypes, matchers::PacketMatcher, ValidRoutines};
 
 /// The action to take on a packet.
 #[derive(Derivative)]
@@ -47,31 +48,43 @@
     Return,
 }
 
+impl<I: IpExt, DeviceClass: Debug> Inspectable for Action<I, DeviceClass, ()> {
+    fn record<Inspector: netstack3_base::Inspector>(&self, inspector: &mut Inspector) {
+        let value = match self {
+            Self::Accept | Self::Drop | Self::Return => format!("{self:?}"),
+            Self::Jump(UninstalledRoutine { routine: _, id }) => {
+                format!("Jump(UninstalledRoutine({id:?}))")
+            }
+        };
+        inspector.record_string("action", value);
+    }
+}
+
 /// A handle to a [`Routine`] that is not installed in a particular hook, and
 /// therefore is only run if jumped to from another routine.
 #[derive(Derivative)]
 #[derivative(Clone(bound = ""), Debug(bound = "DeviceClass: Debug"))]
-pub struct UninstalledRoutine<I: IpExt, DeviceClass, RuleInfo>(
-    pub(crate) Arc<Routine<I, DeviceClass, RuleInfo>>,
-);
+pub struct UninstalledRoutine<I: IpExt, DeviceClass, RuleInfo> {
+    pub(crate) routine: Arc<Routine<I, DeviceClass, RuleInfo>>,
+    id: usize,
+}
 
 impl<I: IpExt, DeviceClass, RuleInfo> UninstalledRoutine<I, DeviceClass, RuleInfo> {
     /// Creates a new uninstalled routine with the provided contents.
-    pub fn new(rules: Vec<Rule<I, DeviceClass, RuleInfo>>) -> Self {
-        Self(Arc::new(Routine { rules }))
+    pub fn new(rules: Vec<Rule<I, DeviceClass, RuleInfo>>, id: usize) -> Self {
+        Self { routine: Arc::new(Routine { rules }), id }
     }
 
     /// Returns the inner routine.
     pub fn get(&self) -> &Routine<I, DeviceClass, RuleInfo> {
-        let Self(inner) = self;
-        &*inner
+        &*self.routine
     }
 }
 
 impl<I: IpExt, DeviceClass, RuleInfo> PartialEq for UninstalledRoutine<I, DeviceClass, RuleInfo> {
     fn eq(&self, other: &Self) -> bool {
-        let Self(lhs) = self;
-        let Self(rhs) = other;
+        let Self { routine: lhs, id: _ } = self;
+        let Self { routine: rhs, id: _ } = other;
         Arc::ptr_eq(lhs, rhs)
     }
 }
@@ -80,8 +93,17 @@
 
 impl<I: IpExt, DeviceClass, RuleInfo> Hash for UninstalledRoutine<I, DeviceClass, RuleInfo> {
     fn hash<H: Hasher>(&self, state: &mut H) {
-        let Self(inner) = self;
-        Arc::as_ptr(inner).hash(state)
+        let Self { routine, id: _ } = self;
+        Arc::as_ptr(routine).hash(state)
+    }
+}
+
+impl<I: IpExt, DeviceClass: Debug> Inspectable for UninstalledRoutine<I, DeviceClass, ()> {
+    fn record<Inspector: netstack3_base::Inspector>(&self, inspector: &mut Inspector) {
+        let Self { routine, id } = self;
+        inspector.record_child(&id.to_string(), |inspector| {
+            inspector.delegate_inspectable(&**routine);
+        });
     }
 }
 
@@ -107,6 +129,38 @@
     pub validation_info: RuleInfo,
 }
 
+impl<I: IpExt, DeviceClass: Debug> Inspectable for Rule<I, DeviceClass, ()> {
+    fn record<Inspector: netstack3_base::Inspector>(&self, inspector: &mut Inspector) {
+        let Self { matcher, action, validation_info: () } = self;
+        inspector.record_child("matchers", |inspector| {
+            let PacketMatcher {
+                in_interface,
+                out_interface,
+                src_address,
+                dst_address,
+                transport_protocol,
+            } = matcher;
+
+            fn record_matcher<Inspector: netstack3_base::Inspector, M: Debug>(
+                inspector: &mut Inspector,
+                name: &str,
+                matcher: &Option<M>,
+            ) {
+                if let Some(matcher) = matcher {
+                    inspector.record_string(name, format!("{matcher:?}"))
+                }
+            }
+
+            record_matcher(inspector, "in_interface", in_interface);
+            record_matcher(inspector, "out_interface", out_interface);
+            record_matcher(inspector, "src_address", src_address);
+            record_matcher(inspector, "dst_address", dst_address);
+            record_matcher(inspector, "transport_protocol", transport_protocol);
+        });
+        inspector.delegate_inspectable(action);
+    }
+}
+
 /// A sequence of [`Rule`]s.
 #[derive(Derivative, GenericOverIp)]
 #[generic_over_ip(I, Ip)]
@@ -119,6 +173,16 @@
     pub rules: Vec<Rule<I, DeviceClass, RuleInfo>>,
 }
 
+impl<I: IpExt, DeviceClass: Debug> Inspectable for Routine<I, DeviceClass, ()> {
+    fn record<Inspector: netstack3_base::Inspector>(&self, inspector: &mut Inspector) {
+        let Self { rules } = self;
+        inspector.record_usize("rules", rules.len());
+        for rule in rules {
+            inspector.record_unnamed_child(|inspector| inspector.delegate_inspectable(rule));
+        }
+    }
+}
+
 /// A particular entry point for packet processing in which filtering routines
 /// are installed.
 #[derive(Derivative, GenericOverIp)]
@@ -129,6 +193,18 @@
     pub routines: Vec<Routine<I, DeviceClass, RuleInfo>>,
 }
 
+impl<I: IpExt, DeviceClass: Debug> Inspectable for Hook<I, DeviceClass, ()> {
+    fn record<Inspector: netstack3_base::Inspector>(&self, inspector: &mut Inspector) {
+        let Self { routines } = self;
+        inspector.record_usize("routines", routines.len());
+        for routine in routines {
+            inspector.record_unnamed_child(|inspector| {
+                inspector.delegate_inspectable(routine);
+            });
+        }
+    }
+}
+
 /// Routines that perform ordinary IP filtering.
 #[derive(Derivative)]
 #[derivative(Default(bound = ""), Debug(bound = "DeviceClass: Debug"))]
@@ -182,9 +258,59 @@
 /// IP version-specific filtering state.
 #[derive(Derivative)]
 #[derivative(Default(bound = ""))]
-pub struct State<I: IpExt, DeviceClass> {
-    /// Routines used for filtering packets.
-    pub routines: ValidRoutines<I, DeviceClass>,
+pub struct State<I: IpExt, BT: FilterBindingsTypes> {
+    /// Routines used for filtering packets that are installed on hooks.
+    pub installed_routines: ValidRoutines<I, BT::DeviceClass>,
+    /// Routines that are only executed if jumped to from other routines.
+    ///
+    /// Jump rules refer to their targets by holding a reference counted pointer
+    /// to the inner routine; we hold this index of all uninstalled routines
+    /// that have any references in order to report them in inspect data.
+    pub(crate) uninstalled_routines: Vec<UninstalledRoutine<I, BT::DeviceClass, ()>>,
     /// Connection tracking state.
-    pub conntrack: conntrack::Table<I, ConntrackExternalData>,
+    #[allow(dead_code)]
+    pub(crate) conntrack: conntrack::Table<I, BT, ConntrackExternalData>,
+}
+
+impl<I: IpExt, BT: FilterBindingsTypes> Inspectable for State<I, BT> {
+    fn record<Inspector: netstack3_base::Inspector>(&self, inspector: &mut Inspector) {
+        let Self { installed_routines, uninstalled_routines, conntrack: _ } = self;
+        // TODO(https://fxbug.dev/318717702): when we implement NAT, report NAT
+        // routines in inspect data.
+        let Routines { ip, nat: _ } = installed_routines.get();
+        let IpRoutines { ingress, local_ingress, forwarding, local_egress, egress } = ip;
+
+        inspector.record_child("ingress", |inspector| inspector.delegate_inspectable(ingress));
+        inspector.record_child("local_ingress", |inspector| {
+            inspector.delegate_inspectable(local_ingress)
+        });
+        inspector
+            .record_child("forwarding", |inspector| inspector.delegate_inspectable(forwarding));
+        inspector
+            .record_child("local_egress", |inspector| inspector.delegate_inspectable(local_egress));
+        inspector.record_child("egress", |inspector| inspector.delegate_inspectable(egress));
+
+        inspector.record_child("uninstalled", |inspector| {
+            inspector.record_usize("routines", uninstalled_routines.len());
+            for routine in uninstalled_routines {
+                inspector.delegate_inspectable(routine);
+            }
+        });
+    }
+}
+
+/// A trait for interacting with the pieces of packet metadata that are
+/// important for filtering.
+pub trait FilterIpMetadata<I: IpExt, BT: FilterBindingsTypes> {
+    /// Removes the conntrack connection, if it exists.
+    fn take_conntrack_connection(
+        &mut self,
+    ) -> Option<conntrack::Connection<I, BT, ConntrackExternalData>>;
+
+    /// Puts a new conntrack connection into the metadata struct, returning the
+    /// previous value.
+    fn replace_conntrack_connection(
+        &mut self,
+        conn: conntrack::Connection<I, BT, ConntrackExternalData>,
+    ) -> Option<conntrack::Connection<I, BT, ConntrackExternalData>>;
 }
diff --git a/src/connectivity/network/netstack3/core/filter/src/state/validation.rs b/src/connectivity/network/netstack3/core/filter/src/state/validation.rs
index 35dff38..b1b52f5 100644
--- a/src/connectivity/network/netstack3/core/filter/src/state/validation.rs
+++ b/src/connectivity/network/netstack3/core/filter/src/state/validation.rs
@@ -5,9 +5,11 @@
 use alloc::{
     collections::{hash_map::Entry, HashMap},
     sync::Arc,
+    vec::Vec,
 };
 use core::fmt::Debug;
 
+use assert_matches::assert_matches;
 use derivative::Derivative;
 use packet_formats::ip::IpExt;
 
@@ -37,8 +39,9 @@
 }
 
 impl<I: IpExt, DeviceClass: Clone + Debug> ValidRoutines<I, DeviceClass> {
-    /// Validates the provide state and creates a new `ValidState` or returns a
-    /// `ValidationError` if the state is invalid.
+    /// Validates the provide state and creates a new `ValidRoutines` along with a
+    /// list of all uninstalled routines that are referred to from an installed
+    /// routine. Returns a `ValidationError` if the state is invalid.
     ///
     /// The provided state must not contain any cyclical routine graphs (formed by
     /// rules with jump actions). The behavior in this case is unspecified but could
@@ -48,9 +51,10 @@
     ///
     /// Panics if the provided state includes cyclic routine graphs.
     pub fn new<RuleInfo: Clone>(
-        state: Routines<I, DeviceClass, RuleInfo>,
-    ) -> Result<Self, ValidationError<RuleInfo>> {
-        let Routines { ip: ip_routines, nat: nat_routines } = &state;
+        routines: Routines<I, DeviceClass, RuleInfo>,
+    ) -> Result<(Self, Vec<UninstalledRoutine<I, DeviceClass, ()>>), ValidationError<RuleInfo>>
+    {
+        let Routines { ip: ip_routines, nat: nat_routines } = &routines;
 
         // Ensure that no rule has a matcher that is unavailable in the context in which
         // the rule will be evaluated.
@@ -72,7 +76,9 @@
         // appended. For example, NAT rules are not allowed outside of NAT
         // routines, and the TPROXY action is only allowed in the INGRESS hook.
 
-        Ok(Self(state.strip_debug_info()))
+        let mut index = UninstalledRoutineIndex::default();
+        let routines = routines.strip_debug_info(&mut index);
+        Ok((Self(routines), index.into_values()))
     }
 }
 
@@ -112,8 +118,8 @@
         match action {
             Action::Accept | Action::Drop | Action::Return => {}
             Action::Jump(target) => {
-                let UninstalledRoutine(inner) = target;
-                validate_routine(&*inner, unavailable_matcher)?
+                let UninstalledRoutine { routine, id: _ } = target;
+                validate_routine(&*routine, unavailable_matcher)?
             }
         }
     }
@@ -160,15 +166,24 @@
         assert_eq!(previous, Some(ConvertedRoutine::InProgress));
         converted
     }
+
+    fn into_values(self) -> Vec<UninstalledRoutine<I, DeviceClass, ()>> {
+        self.index
+            .into_values()
+            .map(|routine| assert_matches!(routine, ConvertedRoutine::Done(routine) => routine))
+            .collect()
+    }
 }
 
 impl<I: IpExt, DeviceClass: Clone + Debug, RuleInfo: Clone> Routines<I, DeviceClass, RuleInfo> {
-    fn strip_debug_info(self) -> Routines<I, DeviceClass, ()> {
+    fn strip_debug_info(
+        self,
+        index: &mut UninstalledRoutineIndex<I, DeviceClass, RuleInfo>,
+    ) -> Routines<I, DeviceClass, ()> {
         let Self { ip: ip_routines, nat: nat_routines } = self;
-        let mut index = UninstalledRoutineIndex::default();
         Routines {
-            ip: ip_routines.strip_debug_info(&mut index),
-            nat: nat_routines.strip_debug_info(&mut index),
+            ip: ip_routines.strip_debug_info(index),
+            nat: nat_routines.strip_debug_info(index),
         }
     }
 }
@@ -247,8 +262,11 @@
             Self::Jump(target) => {
                 let converted = index.get_or_insert_with(target.clone(), |index| {
                     // Recursively strip debug info from the target routine.
-                    let UninstalledRoutine(ref inner) = target;
-                    UninstalledRoutine(Arc::new(Routine::clone(&*inner).strip_debug_info(index)))
+                    let UninstalledRoutine { ref routine, id } = target;
+                    UninstalledRoutine {
+                        routine: Arc::new(Routine::clone(&*routine).strip_debug_info(index)),
+                        id,
+                    }
                 });
                 Action::Jump(converted)
             }
@@ -258,7 +276,7 @@
 
 #[cfg(test)]
 mod tests {
-    use alloc::{vec, vec::Vec};
+    use alloc::vec;
 
     use assert_matches::assert_matches;
     use ip_test_macro::ip_test;
@@ -347,15 +365,18 @@
             routines: vec![Routine {
                 rules: vec![Rule {
                     matcher: PacketMatcher::default(),
-                    action: Action::Jump(UninstalledRoutine::new(vec![rule(
-                        PacketMatcher {
-                            in_interface: Some(InterfaceMatcher::DeviceClass(
-                                FakeDeviceClass::Ethernet,
-                            )),
-                            ..Default::default()
-                        },
-                        RuleId::Invalid,
-                    )])),
+                    action: Action::Jump(UninstalledRoutine::new(
+                        vec![rule(
+                            PacketMatcher {
+                                in_interface: Some(InterfaceMatcher::DeviceClass(
+                                    FakeDeviceClass::Ethernet,
+                                )),
+                                ..Default::default()
+                            },
+                            RuleId::Invalid,
+                        )],
+                        0,
+                    )),
                     validation_info: RuleId::Valid,
                 }],
             }],
@@ -369,15 +390,18 @@
             routines: vec![Routine {
                 rules: vec![Rule {
                     matcher: PacketMatcher::default(),
-                    action: Action::Jump(UninstalledRoutine::new(vec![rule(
-                        PacketMatcher {
-                            out_interface: Some(InterfaceMatcher::DeviceClass(
-                                FakeDeviceClass::Ethernet,
-                            )),
-                            ..Default::default()
-                        },
-                        RuleId::Invalid,
-                    )])),
+                    action: Action::Jump(UninstalledRoutine::new(
+                        vec![rule(
+                            PacketMatcher {
+                                out_interface: Some(InterfaceMatcher::DeviceClass(
+                                    FakeDeviceClass::Ethernet,
+                                )),
+                                ..Default::default()
+                            },
+                            RuleId::Invalid,
+                        )],
+                        0,
+                    )),
                     validation_info: RuleId::Valid,
                 }],
             }],
@@ -396,7 +420,8 @@
     #[test]
     fn strip_debug_info_reuses_uninstalled_routines() {
         // Two routines in the hook jump to the same uninstalled routine.
-        let uninstalled_routine = UninstalledRoutine::<Ipv4, FakeDeviceClass, _>::new(Vec::new());
+        let uninstalled_routine =
+            UninstalledRoutine::<Ipv4, FakeDeviceClass, _>::new(Vec::new(), 0);
         let hook = Hook {
             routines: vec![
                 Routine {
diff --git a/src/connectivity/network/netstack3/core/lock-order/src/relation.rs b/src/connectivity/network/netstack3/core/lock-order/src/relation.rs
index a4ee88a..1041753 100644
--- a/src/connectivity/network/netstack3/core/lock-order/src/relation.rs
+++ b/src/connectivity/network/netstack3/core/lock-order/src/relation.rs
@@ -99,7 +99,7 @@
 ///
 /// This should be implemented for lock types to specify that, in the lock
 /// ordering graph, `A` comes before `Self`. So if `B: LockAfter<A>`, lock type
-/// `B` can be acquired after `A` but `A` cannot be acquired before `B`.
+/// `B` can be acquired after `A` but `A` cannot be acquired after `B`.
 ///
 /// Note, though, that it's preferred to use the [`impl_lock_after`] macro
 /// instead of writing trait impls directly to avoid the possibility of lock
diff --git a/src/connectivity/network/netstack3/core/src/context.rs b/src/connectivity/network/netstack3/core/src/context.rs
index 7370f31..b7ba57f1 100644
--- a/src/connectivity/network/netstack3/core/src/context.rs
+++ b/src/connectivity/network/netstack3/core/src/context.rs
@@ -50,8 +50,8 @@
 };
 
 pub use netstack3_base::{
-    ContextPair, CoreTimerContext, InstantBindingsTypes, InstantContext, TimerBindingsTypes,
-    TimerContext2,
+    ContextPair, CoreTimerContext, InstantBindingsTypes, InstantContext, NestedIntoCoreTimerCtx,
+    TimerBindingsTypes, TimerContext2,
 };
 
 /// A marker trait indicating that the implementor is not the [`FakeCoreCtx`]
@@ -1017,14 +1017,17 @@
     /// A fake [`FrameContext`].
     pub struct FakeFrameCtx<Meta> {
         frames: Vec<(Meta, Vec<u8>)>,
-        should_error_for_frame: Option<Box<dyn Fn(&Meta) -> bool>>,
+        should_error_for_frame: Option<Box<dyn Fn(&Meta) -> bool + Send>>,
     }
 
     #[cfg(test)]
     impl<Meta> FakeFrameCtx<Meta> {
         /// Closure which can decide to cause an error to be thrown when
         /// handling a frame, based on the metadata.
-        pub(crate) fn set_should_error_for_frame<F: Fn(&Meta) -> bool + 'static>(&mut self, f: F) {
+        pub(crate) fn set_should_error_for_frame<F: Fn(&Meta) -> bool + Send + 'static>(
+            &mut self,
+            f: F,
+        ) {
             self.should_error_for_frame = Some(Box::new(f));
         }
     }
diff --git a/src/connectivity/network/netstack3/core/src/data_structures/ref_counted_hash_map.rs b/src/connectivity/network/netstack3/core/src/data_structures/ref_counted_hash_map.rs
index 709ec52..0924acd 100644
--- a/src/connectivity/network/netstack3/core/src/data_structures/ref_counted_hash_map.rs
+++ b/src/connectivity/network/netstack3/core/src/data_structures/ref_counted_hash_map.rs
@@ -109,15 +109,6 @@
     }
 
     /// An iterator visiting all key-value pairs in arbitrary order, with
-    /// immutable references to the values and the count for each pair.
-    #[cfg(test)]
-    pub(crate) fn iter_with_counts<'a>(
-        &'a self,
-    ) -> impl 'a + Iterator<Item = (&'a K, &'a V, NonZeroUsize)> {
-        self.inner.iter().map(|(key, (count, value))| (key, value, *count))
-    }
-
-    /// An iterator visiting all key-value pairs in arbitrary order, with
     /// mutable references to the values.
     pub(crate) fn iter_mut<'a>(&'a mut self) -> impl 'a + Iterator<Item = (&'a K, &'a mut V)> {
         self.inner.iter_mut().map(|(key, (_, value))| (key, value))
diff --git a/src/connectivity/network/netstack3/core/src/device/api.rs b/src/connectivity/network/netstack3/core/src/device/api.rs
index fea0896..569b385 100644
--- a/src/connectivity/network/netstack3/core/src/device/api.rs
+++ b/src/connectivity/network/netstack3/core/src/device/api.rs
@@ -27,13 +27,15 @@
         pure_ip::PureIpDevice,
         state::{BaseDeviceState, DeviceStateSpec, IpLinkDeviceStateInner},
         AnyDevice, BaseDeviceId, BasePrimaryDeviceId, BaseWeakDeviceId, Device,
-        DeviceCollectionContext, DeviceCounters, DeviceId, DeviceIdContext, DeviceLayerStateTypes,
-        DeviceLayerTypes, DeviceProvider, DeviceReceiveFrameSpec, OriginTrackerContext,
+        DeviceCollectionContext, DeviceCounters, DeviceId, DeviceIdAnyCompatContext,
+        DeviceIdContext, DeviceLayerStateTypes, DeviceLayerTypes, DeviceProvider,
+        DeviceReceiveFrameSpec, OriginTrackerContext,
     },
     for_any_device_id,
     ip::{
         device::{
-            IpDeviceBindingsContext, IpDeviceConfigurationContext, Ipv6DeviceConfigurationContext,
+            IpDeviceBindingsContext, IpDeviceConfigurationContext, IpDeviceTimerId,
+            Ipv6DeviceConfigurationContext,
         },
         types::RawMetric,
     },
@@ -91,14 +93,24 @@
         properties: D::CreationProperties,
         metric: RawMetric,
         external_state: D::External<C::BindingsContext>,
-    ) -> <C::CoreContext as DeviceIdContext<D>>::DeviceId {
+    ) -> <C::CoreContext as DeviceIdContext<D>>::DeviceId
+    where
+        C::CoreContext: DeviceApiIpLayerCoreContext<D, C::BindingsContext>,
+    {
         debug!("adding {} device with {:?} metric:{metric}", D::DEBUG_TYPE, properties);
         let (core_ctx, bindings_ctx) = self.contexts();
         let origin = core_ctx.origin_tracker();
         let primary = BasePrimaryDeviceId::new(
             |weak_ref| {
-                IpLinkDeviceStateInner::new(
-                    D::new_link_state::<C::CoreContext, _>(bindings_ctx, weak_ref, properties),
+                let link = D::new_link_state::<C::CoreContext, _>(
+                    bindings_ctx,
+                    weak_ref.clone(),
+                    properties,
+                );
+                IpLinkDeviceStateInner::new::<_, C::CoreContext>(
+                    bindings_ctx,
+                    weak_ref.into(),
+                    link,
                     metric,
                     origin,
                 )
@@ -125,6 +137,7 @@
     where
         <C::BindingsContext as DeviceLayerStateTypes>::DeviceIdentifier: Default,
         D::External<C::BindingsContext>: Default,
+        C::CoreContext: DeviceApiIpLayerCoreContext<D, C::BindingsContext>,
     {
         self.add_device(Default::default(), properties, metric, Default::default())
     }
@@ -411,3 +424,20 @@
 
 impl<O> DeviceApiBindingsContext for O where O: DeviceLayerTypes + ReferenceNotifiers + TimerContext2
 {}
+
+/// A marker trait with traits required to tie the device layer with the IP
+/// layer to fulfill [`DeviceApi`].
+pub trait DeviceApiIpLayerCoreContext<D: Device, BC: DeviceLayerTypes>:
+    DeviceIdAnyCompatContext<D>
+    + CoreTimerContext<IpDeviceTimerId<Ipv6, <Self as DeviceIdContext<AnyDevice>>::DeviceId>, BC>
+{
+}
+
+impl<O, D, BC> DeviceApiIpLayerCoreContext<D, BC> for O
+where
+    D: Device,
+    BC: DeviceLayerTypes,
+    O: DeviceIdAnyCompatContext<D>
+        + CoreTimerContext<IpDeviceTimerId<Ipv6, <Self as DeviceIdContext<AnyDevice>>::DeviceId>, BC>,
+{
+}
diff --git a/src/connectivity/network/netstack3/core/src/device/arp.rs b/src/connectivity/network/netstack3/core/src/device/arp.rs
index 9423ed7d..039139e 100644
--- a/src/connectivity/network/netstack3/core/src/device/arp.rs
+++ b/src/connectivity/network/netstack3/core/src/device/arp.rs
@@ -767,30 +767,11 @@
     impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtxImpl {
         type DeviceId = FakeLinkDeviceId;
         type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            self.get_ref().inner.downgrade_device_id(device_id)
-        }
-        fn upgrade_weak_device_id(
-            &self,
-            weak_device_id: &Self::WeakDeviceId,
-        ) -> Option<Self::DeviceId> {
-            self.get_ref().inner.upgrade_weak_device_id(weak_device_id)
-        }
     }
 
     impl DeviceIdContext<EthernetLinkDevice> for FakeArpInnerCtx {
         type DeviceId = FakeLinkDeviceId;
         type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            FakeWeakDeviceId(device_id.clone())
-        }
-        fn upgrade_weak_device_id(
-            &self,
-            weak_device_id: &Self::WeakDeviceId,
-        ) -> Option<Self::DeviceId> {
-            let FakeWeakDeviceId(id) = weak_device_id;
-            Some(id.clone())
-        }
     }
 
     impl ArpContext<EthernetLinkDevice, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
diff --git a/src/connectivity/network/netstack3/core/src/device/base.rs b/src/connectivity/network/netstack3/core/src/device/base.rs
index 09f1308..ca40b27 100644
--- a/src/connectivity/network/netstack3/core/src/device/base.rs
+++ b/src/connectivity/network/netstack3/core/src/device/base.rs
@@ -67,15 +67,37 @@
 
     /// The type of weakly referenced device IDs.
     type WeakDeviceId: WeakId<Strong = Self::DeviceId> + 'static;
+}
 
-    /// Returns a weak ID for the strong ID.
-    fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId;
+/// A marker trait tying [`DeviceIdContext`] implementations.
+///
+/// To call into the IP layer, we need to be able to represent device
+/// identifiers in the [`AnyDevice`] domain. This trait is a statement that a
+/// [`DeviceIdContext`] in some domain `D` has its identifiers convertible into
+/// the [`AnyDevice`] domain with `From` bounds.
+///
+/// It is provided as a blanket implementation for [`DeviceIdContext`]s that
+/// fulfill the conversion.
+pub trait DeviceIdAnyCompatContext<D: Device>:
+    DeviceIdContext<D>
+    + DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId_, WeakDeviceId = Self::WeakDeviceId_>
+{
+    type DeviceId_: StrongId<Weak = Self::WeakDeviceId_>
+        + From<<Self as DeviceIdContext<D>>::DeviceId>;
+    type WeakDeviceId_: WeakId<Strong = Self::DeviceId_>
+        + From<<Self as DeviceIdContext<D>>::WeakDeviceId>;
+}
 
-    /// Attempts to upgrade the weak device ID to a strong ID.
-    ///
-    /// Returns `None` if the device has been removed.
-    fn upgrade_weak_device_id(&self, weak_device_id: &Self::WeakDeviceId)
-        -> Option<Self::DeviceId>;
+impl<CC, D> DeviceIdAnyCompatContext<D> for CC
+where
+    D: Device,
+    CC: DeviceIdContext<D> + DeviceIdContext<AnyDevice>,
+    <CC as DeviceIdContext<AnyDevice>>::WeakDeviceId:
+        From<<CC as DeviceIdContext<D>>::WeakDeviceId>,
+    <CC as DeviceIdContext<AnyDevice>>::DeviceId: From<<CC as DeviceIdContext<D>>::DeviceId>,
+{
+    type DeviceId_ = <CC as DeviceIdContext<AnyDevice>>::DeviceId;
+    type WeakDeviceId_ = <CC as DeviceIdContext<AnyDevice>>::WeakDeviceId;
 }
 
 pub(super) struct RecvIpFrameMeta<D, I: Ip> {
@@ -580,6 +602,11 @@
 pub(crate) mod testutil {
     use super::*;
 
+    #[cfg(test)]
+    use alloc::sync::Arc;
+    #[cfg(test)]
+    use core::sync::atomic::AtomicBool;
+
     use crate::ip::device::config::{
         IpDeviceConfigurationUpdate, Ipv4DeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate,
     };
@@ -596,8 +623,13 @@
         }
     }
 
-    impl<D: StrongId<Weak = Self>> WeakId for FakeWeakDeviceId<D> {
+    impl<D: FakeStrongDeviceId> WeakId for FakeWeakDeviceId<D> {
         type Strong = D;
+
+        fn upgrade(&self) -> Option<D> {
+            let Self(inner) = self;
+            inner.is_alive().then(|| inner.clone())
+        }
     }
 
     impl<D: crate::device::Id> crate::device::Id for FakeWeakDeviceId<D> {
@@ -613,6 +645,10 @@
 
     impl StrongId for FakeDeviceId {
         type Weak = FakeWeakDeviceId<Self>;
+
+        fn downgrade(&self) -> Self::Weak {
+            FakeWeakDeviceId(self.clone())
+        }
     }
 
     impl crate::device::Id for FakeDeviceId {
@@ -635,11 +671,110 @@
         }
     }
 
+    impl FakeStrongDeviceId for FakeDeviceId {
+        fn is_alive(&self) -> bool {
+            true
+        }
+    }
+
+    /// A fake device ID for use in testing.
+    ///
+    /// [`FakeReferencyDeviceId`] behaves like a referency device ID, each
+    /// constructed instance represents a new device.
+    #[derive(Clone, Debug, Default)]
     #[cfg(test)]
-    pub trait FakeStrongDeviceId: StrongId<Weak = FakeWeakDeviceId<Self>> + 'static + Ord {}
+    pub(crate) struct FakeReferencyDeviceId {
+        removed: Arc<AtomicBool>,
+    }
 
     #[cfg(test)]
-    impl<D: StrongId<Weak = FakeWeakDeviceId<Self>> + 'static + Ord> FakeStrongDeviceId for D {}
+    impl core::hash::Hash for FakeReferencyDeviceId {
+        fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+            let Self { removed } = self;
+            core::ptr::hash(alloc::sync::Arc::as_ptr(removed), state)
+        }
+    }
+
+    #[cfg(test)]
+    impl core::cmp::Eq for FakeReferencyDeviceId {}
+
+    #[cfg(test)]
+    impl core::cmp::PartialEq for FakeReferencyDeviceId {
+        fn eq(&self, Self { removed: other }: &Self) -> bool {
+            let Self { removed } = self;
+            alloc::sync::Arc::ptr_eq(removed, other)
+        }
+    }
+
+    #[cfg(test)]
+    impl core::cmp::Ord for FakeReferencyDeviceId {
+        fn cmp(&self, Self { removed: other }: &Self) -> core::cmp::Ordering {
+            let Self { removed } = self;
+            alloc::sync::Arc::as_ptr(removed).cmp(&alloc::sync::Arc::as_ptr(other))
+        }
+    }
+
+    #[cfg(test)]
+    impl core::cmp::PartialOrd for FakeReferencyDeviceId {
+        fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+            Some(self.cmp(other))
+        }
+    }
+
+    #[cfg(test)]
+    impl FakeReferencyDeviceId {
+        /// Marks this device as removed, all weak references will not be able
+        /// to upgrade anymore.
+        pub(crate) fn mark_removed(&self) {
+            self.removed.store(true, core::sync::atomic::Ordering::Relaxed);
+        }
+    }
+
+    #[cfg(test)]
+    impl StrongId for FakeReferencyDeviceId {
+        type Weak = FakeWeakDeviceId<Self>;
+
+        fn downgrade(&self) -> Self::Weak {
+            FakeWeakDeviceId(self.clone())
+        }
+    }
+
+    #[cfg(test)]
+    impl crate::device::Id for FakeReferencyDeviceId {
+        fn is_loopback(&self) -> bool {
+            false
+        }
+    }
+
+    #[cfg(test)]
+    impl crate::filter::InterfaceProperties<()> for FakeReferencyDeviceId {
+        fn id_matches(&self, _: &core::num::NonZeroU64) -> bool {
+            unimplemented!()
+        }
+
+        fn name_matches(&self, _: &str) -> bool {
+            unimplemented!()
+        }
+
+        fn device_class_matches(&self, _: &()) -> bool {
+            unimplemented!()
+        }
+    }
+
+    #[cfg(test)]
+    impl FakeStrongDeviceId for FakeReferencyDeviceId {
+        fn is_alive(&self) -> bool {
+            !self.removed.load(core::sync::atomic::Ordering::Relaxed)
+        }
+    }
+
+    pub trait FakeStrongDeviceId: StrongId<Weak = FakeWeakDeviceId<Self>> + 'static + Ord {
+        /// Returns whether this ID is still alive.
+        ///
+        /// This is used by [`FakeWeakDeviceId`] to return `None` when trying to
+        /// upgrade back a `FakeStrongDeviceId`.
+        fn is_alive(&self) -> bool;
+    }
 
     pub fn enable_device<BC: BindingsContext>(
         ctx: &mut crate::testutil::Ctx<BC>,
@@ -727,6 +862,17 @@
     #[cfg(test)]
     impl StrongId for MultipleDevicesId {
         type Weak = FakeWeakDeviceId<Self>;
+
+        fn downgrade(&self) -> Self::Weak {
+            FakeWeakDeviceId(self.clone())
+        }
+    }
+
+    #[cfg(test)]
+    impl FakeStrongDeviceId for MultipleDevicesId {
+        fn is_alive(&self) -> bool {
+            true
+        }
     }
 
     #[cfg(test)]
diff --git a/src/connectivity/network/netstack3/core/src/device/ethernet.rs b/src/connectivity/network/netstack3/core/src/device/ethernet.rs
index bb2d3d5..4fd47107 100644
--- a/src/connectivity/network/netstack3/core/src/device/ethernet.rs
+++ b/src/connectivity/network/netstack3/core/src/device/ethernet.rs
@@ -1919,30 +1919,11 @@
     impl DeviceIdContext<EthernetLinkDevice> for FakeCoreCtx {
         type DeviceId = FakeDeviceId;
         type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            self.inner.downgrade_device_id(device_id)
-        }
-        fn upgrade_weak_device_id(
-            &self,
-            weak_device_id: &Self::WeakDeviceId,
-        ) -> Option<Self::DeviceId> {
-            self.inner.upgrade_weak_device_id(weak_device_id)
-        }
     }
 
     impl DeviceIdContext<EthernetLinkDevice> for FakeInnerCtx {
         type DeviceId = FakeDeviceId;
         type WeakDeviceId = FakeWeakDeviceId<FakeDeviceId>;
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            FakeWeakDeviceId(device_id.clone())
-        }
-        fn upgrade_weak_device_id(
-            &self,
-            weak_device_id: &Self::WeakDeviceId,
-        ) -> Option<Self::DeviceId> {
-            let FakeWeakDeviceId(id) = weak_device_id;
-            Some(id.clone())
-        }
     }
 
     impl CounterContext<ArpCounters> for FakeCoreCtx {
diff --git a/src/connectivity/network/netstack3/core/src/device/id.rs b/src/connectivity/network/netstack3/core/src/device/id.rs
index 096c70e..4be1e4f 100644
--- a/src/connectivity/network/netstack3/core/src/device/id.rs
+++ b/src/connectivity/network/netstack3/core/src/device/id.rs
@@ -28,21 +28,29 @@
     fn is_loopback(&self) -> bool;
 }
 
-/// A marker for a Strong device reference.
+/// A strong device reference.
 ///
-/// Types marked with [`StrongId`] indicates that the referenced device is alive
-/// while the type exists.
+/// [`StrongId`] indicates that the referenced device is alive while the
+/// instance exists.
 pub trait StrongId: Id {
     /// The weak version of this identifier.
     type Weak: WeakId<Strong = Self>;
+
+    /// Returns a weak ID for this strong ID.
+    fn downgrade(&self) -> Self::Weak;
 }
 
-/// A marker for a Weak device reference.
+/// A weak device reference.
 ///
-/// This is the weak marker equivalent of [`StrongId`].
+/// This is the weak reference equivalent of [`StrongId`].
 pub trait WeakId: Id + PartialEq<Self::Strong> {
     /// The strong version of this identifier.
     type Strong: StrongId<Weak = Self>;
+
+    /// Attempts to upgrade this weak ID to a strong ID.
+    ///
+    /// Returns `None` if the resource has been destroyed.
+    fn upgrade(&self) -> Option<Self::Strong>;
 }
 
 /// A weak ID identifying a device.
@@ -161,6 +169,10 @@
 
 impl<BT: DeviceLayerTypes> WeakId for WeakDeviceId<BT> {
     type Strong = DeviceId<BT>;
+
+    fn upgrade(&self) -> Option<Self::Strong> {
+        self.upgrade()
+    }
 }
 
 impl<BT: DeviceLayerTypes> Debug for WeakDeviceId<BT> {
@@ -363,6 +375,10 @@
 
 impl<BT: DeviceLayerTypes> StrongId for DeviceId<BT> {
     type Weak = WeakDeviceId<BT>;
+
+    fn downgrade(&self) -> Self::Weak {
+        self.downgrade()
+    }
 }
 
 impl<BT: DeviceLayerTypes> Debug for DeviceId<BT> {
@@ -438,6 +454,10 @@
 
 impl<T: DeviceStateSpec, BT: DeviceLayerTypes> WeakId for BaseWeakDeviceId<T, BT> {
     type Strong = BaseDeviceId<T, BT>;
+
+    fn upgrade(&self) -> Option<Self::Strong> {
+        self.upgrade()
+    }
 }
 
 impl<T: DeviceStateSpec, BT: DeviceLayerTypes> BaseWeakDeviceId<T, BT> {
@@ -522,6 +542,10 @@
 
 impl<T: DeviceStateSpec, BT: DeviceLayerTypes> StrongId for BaseDeviceId<T, BT> {
     type Weak = BaseWeakDeviceId<T, BT>;
+
+    fn downgrade(&self) -> Self::Weak {
+        self.downgrade()
+    }
 }
 
 impl<T: DeviceStateSpec, BT: DeviceLayerTypes> BaseDeviceId<T, BT> {
diff --git a/src/connectivity/network/netstack3/core/src/device/integration.rs b/src/connectivity/network/netstack3/core/src/device/integration.rs
index 1fb8f87..44db39a 100644
--- a/src/connectivity/network/netstack3/core/src/device/integration.rs
+++ b/src/connectivity/network/netstack3/core/src/device/integration.rs
@@ -4,7 +4,6 @@
 
 //! Implementations of device layer traits for [`CoreCtx`].
 
-use alloc::boxed::Box;
 use core::{num::NonZeroU8, ops::Deref as _};
 
 use lock_order::{
@@ -42,7 +41,7 @@
         PureIpDeviceCounters, RecvIpFrameMeta, WeakDeviceId,
     },
     error::{ExistsError, NotFoundError},
-    filter::{FilterHandler as _, FilterHandlerProvider as _, IpPacket},
+    filter::{IpPacket, ProofOfEgressCheck},
     for_any_device_id,
     ip::{
         device::{
@@ -52,9 +51,10 @@
                 NudUserConfig,
             },
             state::{
-                AssignedAddress as _, DualStackIpDeviceState, IpDeviceFlags, Ipv4AddressEntry,
-                Ipv4AddressState, Ipv4DeviceConfiguration, Ipv6AddressEntry, Ipv6AddressState,
-                Ipv6DadState, Ipv6DeviceConfiguration, Ipv6NetworkLearnedParameters,
+                AddressIdIter, AssignedAddress as _, DualStackIpDeviceState, IpDeviceFlags,
+                Ipv4AddressEntry, Ipv4AddressState, Ipv4DeviceConfiguration, Ipv6AddressEntry,
+                Ipv6AddressState, Ipv6DadState, Ipv6DeviceConfiguration,
+                Ipv6NetworkLearnedParameters,
             },
             IpDeviceAddressContext, IpDeviceAddressIdContext, IpDeviceConfigurationContext,
             IpDeviceIpExt, IpDeviceSendContext, IpDeviceStateContext, Ipv6DeviceAddr,
@@ -172,6 +172,7 @@
         local_addr: SpecifiedAddr<<I as Ip>::Addr>,
         body: S,
         broadcast: Option<<I as IpTypesIpExt>::BroadcastMarker>,
+        ProofOfEgressCheck { .. }: ProofOfEgressCheck,
     ) -> Result<(), S>
     where
         S: Serializer + IpPacket<I>,
@@ -196,6 +197,7 @@
         local_addr: SpecifiedAddr<<I as Ip>::Addr>,
         body: S,
         broadcast: Option<<I as IpTypesIpExt>::BroadcastMarker>,
+        ProofOfEgressCheck { .. }: ProofOfEgressCheck,
     ) -> Result<(), S>
     where
         S: Serializer + IpPacket<I>,
@@ -393,12 +395,10 @@
         })
     }
 
+    type AddressIdsIter<'a> = AddressIdIter<'a, BC::Instant, Ipv4>;
     fn with_address_ids<
         O,
-        F: FnOnce(
-            Box<dyn Iterator<Item = Self::AddressId> + '_>,
-            &mut Self::IpDeviceAddressCtx<'_>,
-        ) -> O,
+        F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
     >(
         &mut self,
         device_id: &Self::DeviceId,
@@ -409,7 +409,7 @@
                 .read_lock_with_and::<crate::lock_ordering::IpDeviceAddresses<Ipv4>, _>(|c| {
                     c.right()
                 });
-            cb(Box::new(state.iter().map(PrimaryRc::clone_strong)), &mut locked.cast_core_ctx())
+            cb(state.strong_iter(), &mut locked.cast_core_ctx())
         })
     }
 
@@ -684,12 +684,10 @@
         })
     }
 
+    type AddressIdsIter<'a> = AddressIdIter<'a, BC::Instant, Ipv6>;
     fn with_address_ids<
         O,
-        F: FnOnce(
-            Box<dyn Iterator<Item = Self::AddressId> + '_>,
-            &mut Self::IpDeviceAddressCtx<'_>,
-        ) -> O,
+        F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
     >(
         &mut self,
         device_id: &Self::DeviceId,
@@ -700,7 +698,7 @@
                 .read_lock_with_and::<crate::lock_ordering::IpDeviceAddresses<Ipv6>, _>(
                 |c| c.right(),
             );
-            cb(Box::new(state.iter().map(PrimaryRc::clone_strong)), &mut core_ctx.cast_core_ctx())
+            cb(state.strong_iter(), &mut core_ctx.cast_core_ctx())
         })
     }
 
@@ -813,16 +811,6 @@
 impl<BT: BindingsTypes, L> DeviceIdContext<EthernetLinkDevice> for CoreCtx<'_, BT, L> {
     type DeviceId = EthernetDeviceId<BT>;
     type WeakDeviceId = EthernetWeakDeviceId<BT>;
-    fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-        device_id.downgrade()
-    }
-
-    fn upgrade_weak_device_id(
-        &self,
-        weak_device_id: &Self::WeakDeviceId,
-    ) -> Option<Self::DeviceId> {
-        weak_device_id.upgrade()
-    }
 }
 
 impl<'a, CC: DeviceIdContext<EthernetLinkDevice> + CounterContext<DeviceCounters>>
@@ -830,18 +818,6 @@
 {
     type DeviceId = CC::DeviceId;
     type WeakDeviceId = CC::WeakDeviceId;
-    fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-        let Self { core_ctx, device_id: _ } = self;
-        CC::downgrade_device_id(core_ctx, device_id)
-    }
-
-    fn upgrade_weak_device_id(
-        &self,
-        weak_device_id: &Self::WeakDeviceId,
-    ) -> Option<Self::DeviceId> {
-        let Self { core_ctx, device_id: _ } = self;
-        CC::upgrade_weak_device_id(core_ctx, weak_device_id)
-    }
 }
 
 impl<BC: socket::DeviceSocketBindingsContext<DeviceId<BC>> + DeviceLayerEventDispatcher>
@@ -923,17 +899,9 @@
     }
 }
 
-impl<BC: BindingsContext, L> DeviceIdContext<AnyDevice> for CoreCtx<'_, BC, L> {
-    type DeviceId = DeviceId<BC>;
-    type WeakDeviceId = WeakDeviceId<BC>;
-
-    fn downgrade_device_id(&self, device_id: &DeviceId<BC>) -> WeakDeviceId<BC> {
-        device_id.downgrade()
-    }
-
-    fn upgrade_weak_device_id(&self, weak_device_id: &WeakDeviceId<BC>) -> Option<DeviceId<BC>> {
-        weak_device_id.upgrade()
-    }
+impl<BT: BindingsTypes, L> DeviceIdContext<AnyDevice> for CoreCtx<'_, BT, L> {
+    type DeviceId = DeviceId<BT>;
+    type WeakDeviceId = WeakDeviceId<BT>;
 }
 
 impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::EthernetRxDequeue>>
@@ -1104,15 +1072,15 @@
     bindings_ctx: &mut BC,
     device: &DeviceId<BC>,
     local_addr: SpecifiedAddr<A>,
-    mut body: S,
+    body: S,
     broadcast: Option<<A::Version as IpTypesIpExt>::BroadcastMarker>,
 ) -> Result<(), S>
 where
     BC: BindingsContext,
-    S: Serializer + IpPacket<A::Version>,
+    S: Serializer,
     S::Buffer: BufferMut,
     A: IpAddress,
-    L: LockBefore<crate::lock_ordering::FilterState<A::Version>>
+    L: LockBefore<crate::lock_ordering::IpState<A::Version>>
         + LockBefore<crate::lock_ordering::LoopbackTxQueue>
         + LockBefore<crate::lock_ordering::PureIpDeviceTxQueue>,
     A::Version: EthernetIpExt + IpTypesIpExt,
@@ -1120,11 +1088,6 @@
         + NudHandler<A::Version, EthernetLinkDevice, BC>
         + TransmitQueueHandler<EthernetLinkDevice, BC, Meta = ()>,
 {
-    match core_ctx.filter_handler().egress_hook(&mut body, device) {
-        crate::filter::Verdict::Drop => return Ok(()),
-        crate::filter::Verdict::Accept => {}
-    }
-
     match device {
         DeviceId::Ethernet(id) => ethernet::send_ip_frame::<_, _, A, _>(
             core_ctx,
diff --git a/src/connectivity/network/netstack3/core/src/device/link.rs b/src/connectivity/network/netstack3/core/src/device/link.rs
index 2713e99..c9667b2 100644
--- a/src/connectivity/network/netstack3/core/src/device/link.rs
+++ b/src/connectivity/network/netstack3/core/src/device/link.rs
@@ -71,7 +71,10 @@
     use super::*;
     use crate::{
         context::testutil::FakeCoreCtx,
-        device::{testutil::FakeWeakDeviceId, DeviceIdContext, Id, StrongId},
+        device::{
+            testutil::{FakeStrongDeviceId, FakeWeakDeviceId},
+            DeviceIdContext, Id, StrongId,
+        },
     };
 
     /// A fake [`LinkDevice`].
@@ -115,11 +118,15 @@
     }
 
     /// A fake ID identifying a [`FakeLinkDevice`].
-    #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+    #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
     pub(crate) struct FakeLinkDeviceId;
 
     impl StrongId for FakeLinkDeviceId {
         type Weak = FakeWeakDeviceId<Self>;
+
+        fn downgrade(&self) -> Self::Weak {
+            FakeWeakDeviceId(*self)
+        }
     }
 
     impl Id for FakeLinkDeviceId {
@@ -131,17 +138,11 @@
     impl<S, M> DeviceIdContext<FakeLinkDevice> for FakeCoreCtx<S, M, FakeLinkDeviceId> {
         type DeviceId = FakeLinkDeviceId;
         type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
+    }
 
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            FakeWeakDeviceId(device_id.clone())
-        }
-
-        fn upgrade_weak_device_id(
-            &self,
-            weak_device_id: &Self::WeakDeviceId,
-        ) -> Option<Self::DeviceId> {
-            let FakeWeakDeviceId(id) = weak_device_id;
-            Some(id.clone())
+    impl FakeStrongDeviceId for FakeLinkDeviceId {
+        fn is_alive(&self) -> bool {
+            true
         }
     }
 }
diff --git a/src/connectivity/network/netstack3/core/src/device/loopback.rs b/src/connectivity/network/netstack3/core/src/device/loopback.rs
index 2390aa8..3d35e99 100644
--- a/src/connectivity/network/netstack3/core/src/device/loopback.rs
+++ b/src/connectivity/network/netstack3/core/src/device/loopback.rs
@@ -111,15 +111,6 @@
 impl<BT: BindingsTypes, L> DeviceIdContext<LoopbackDevice> for CoreCtx<'_, BT, L> {
     type DeviceId = LoopbackDeviceId<BT>;
     type WeakDeviceId = LoopbackWeakDeviceId<BT>;
-    fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-        device_id.downgrade()
-    }
-    fn upgrade_weak_device_id(
-        &self,
-        weak_device_id: &Self::WeakDeviceId,
-    ) -> Option<Self::DeviceId> {
-        weak_device_id.upgrade()
-    }
 }
 
 /// Properties used to create a loopback device.
diff --git a/src/connectivity/network/netstack3/core/src/device/ndp.rs b/src/connectivity/network/netstack3/core/src/device/ndp.rs
index a55dbf6..9d248f6 100644
--- a/src/connectivity/network/netstack3/core/src/device/ndp.rs
+++ b/src/connectivity/network/netstack3/core/src/device/ndp.rs
@@ -361,7 +361,7 @@
             let Ctx { core_ctx, bindings_ctx } = &mut ctx;
             assert_matches!(bindings_ctx.copy_ethernet_frames()[..], []);
 
-            crate::ip::send_ip_packet_from_device::<Ipv6, _, _, _>(
+            crate::ip::IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
                 &mut core_ctx.context(),
                 bindings_ctx,
                 SendIpPacketMeta {
@@ -537,9 +537,9 @@
         id: EthernetDeviceId<FakeBindingsCtx>,
     ) -> TimerId<crate::testutil::FakeBindingsCtx> {
         TimerId(TimerIdInner::Ipv6Device(
-            Ipv6DeviceTimerId::Rs(crate::ip::device::router_solicitation::RsTimerId {
-                device_id: id.into(),
-            })
+            Ipv6DeviceTimerId::Rs(crate::ip::device::router_solicitation::RsTimerId::new(
+                id.downgrade().into(),
+            ))
             .into(),
         ))
     }
@@ -1155,7 +1155,7 @@
             );
             let (mut core_ctx, bindings_ctx) = ctx.contexts();
             assert_eq!(get_ipv6_hop_limit(&mut core_ctx, device_id).get(), hop_limit);
-            crate::ip::send_ip_packet_from_device::<Ipv6, _, _, _>(
+            crate::ip::IpLayerHandler::<Ipv6, _>::send_ip_packet_from_device(
                 &mut core_ctx,
                 bindings_ctx,
                 SendIpPacketMeta {
diff --git a/src/connectivity/network/netstack3/core/src/device/pure_ip/integration.rs b/src/connectivity/network/netstack3/core/src/device/pure_ip/integration.rs
index acb6f1c..7e98b18 100644
--- a/src/connectivity/network/netstack3/core/src/device/pure_ip/integration.rs
+++ b/src/connectivity/network/netstack3/core/src/device/pure_ip/integration.rs
@@ -43,15 +43,6 @@
 impl<BT: BindingsTypes, L> DeviceIdContext<PureIpDevice> for CoreCtx<'_, BT, L> {
     type DeviceId = PureIpDeviceId<BT>;
     type WeakDeviceId = PureIpWeakDeviceId<BT>;
-    fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-        device_id.downgrade()
-    }
-    fn upgrade_weak_device_id(
-        &self,
-        weak_device_id: &Self::WeakDeviceId,
-    ) -> Option<Self::DeviceId> {
-        weak_device_id.upgrade()
-    }
 }
 
 impl<'a, BT, L> DeviceCollectionContext<PureIpDevice, BT> for CoreCtx<'a, BT, L>
diff --git a/src/connectivity/network/netstack3/core/src/device/socket.rs b/src/connectivity/network/netstack3/core/src/device/socket.rs
index 3da5307..897786e 100644
--- a/src/connectivity/network/netstack3/core/src/device/socket.rs
+++ b/src/connectivity/network/netstack3/core/src/device/socket.rs
@@ -23,7 +23,10 @@
 
 use crate::{
     context::{ContextPair, SendFrameContext},
-    device::{self, AnyDevice, Device, DeviceId, DeviceIdContext, FrameDestination, WeakDeviceId},
+    device::{
+        self, AnyDevice, Device, DeviceId, DeviceIdContext, FrameDestination, StrongId as _,
+        WeakDeviceId, WeakId as _,
+    },
     for_any_device_id,
     sync::{Mutex, PrimaryRc, RwLock, StrongRc},
     CoreCtx, StackState,
@@ -241,36 +244,15 @@
 pub trait SocketStateAccessor<BC: DeviceSocketBindingsContext<Self::DeviceId>>:
     DeviceSocketContextTypes + DeviceIdContext<AnyDevice>
 {
-    /// Core context available in callbacks to methods on this context.
-    type SocketStateCoreCtx<'a>: DeviceIdContext<
-        AnyDevice,
-        DeviceId = Self::DeviceId,
-        WeakDeviceId = Self::WeakDeviceId,
-    >;
-
     /// Provides read-only access to the state of a socket.
-    fn with_socket_state<
-        F: FnOnce(
-            &BC::SocketState,
-            &Target<Self::WeakDeviceId>,
-            &mut Self::SocketStateCoreCtx<'_>,
-        ) -> R,
-        R,
-    >(
+    fn with_socket_state<F: FnOnce(&BC::SocketState, &Target<Self::WeakDeviceId>) -> R, R>(
         &mut self,
         socket: &Self::SocketId,
         cb: F,
     ) -> R;
 
     /// Provides mutable access to the state of a socket.
-    fn with_socket_state_mut<
-        F: FnOnce(
-            &BC::SocketState,
-            &mut Target<Self::WeakDeviceId>,
-            &mut Self::SocketStateCoreCtx<'_>,
-        ) -> R,
-        R,
-    >(
+    fn with_socket_state_mut<F: FnOnce(&BC::SocketState, &mut Target<Self::WeakDeviceId>) -> R, R>(
         &mut self,
         socket: &Self::SocketId,
         cb: F,
@@ -371,13 +353,13 @@
         // delivered to the socket from either device.
         let old_device = core_ctx.with_socket_state_mut(
             socket,
-            |_: &BC::SocketState, Target { protocol, device }, core_ctx| {
+            |_: &BC::SocketState, Target { protocol, device }| {
                 match protocol_update {
                     MaybeUpdate::NewValue(p) => *protocol = Some(p),
                     MaybeUpdate::NoChange => (),
                 };
                 let old_device = match &device {
-                    TargetDevice::SpecificDevice(device) => core_ctx.upgrade_weak_device_id(device),
+                    TargetDevice::SpecificDevice(device) => device.upgrade(),
                     TargetDevice::AnyDevice => {
                         assert!(any_device_sockets.remove(socket));
                         None
@@ -385,9 +367,7 @@
                 };
                 *device = match &new_device {
                     TargetDevice::AnyDevice => TargetDevice::AnyDevice,
-                    TargetDevice::SpecificDevice(d) => {
-                        TargetDevice::SpecificDevice(core_ctx.downgrade_device_id(d))
-                    }
+                    TargetDevice::SpecificDevice(d) => TargetDevice::SpecificDevice(d.downgrade()),
                 };
                 old_device
             },
@@ -497,13 +477,9 @@
         &mut self,
         id: &<C::CoreContext as DeviceSocketContextTypes>::SocketId,
     ) -> SocketInfo<<C::CoreContext as DeviceIdContext<AnyDevice>>::WeakDeviceId> {
-        self.core_ctx().with_socket_state(
-            id,
-            |_external_state, Target { device, protocol }, _core_ctx| SocketInfo {
-                device: device.clone(),
-                protocol: *protocol,
-            },
-        )
+        self.core_ctx().with_socket_state(id, |_external_state, Target { device, protocol }| {
+            SocketInfo { device: device.clone(), protocol: *protocol }
+        })
     }
 
     /// Removes a bound socket.
@@ -515,19 +491,16 @@
     pub fn remove(&mut self, id: <C::CoreContext as DeviceSocketContextTypes>::SocketId) {
         let core_ctx = self.core_ctx();
         core_ctx.with_any_device_sockets_mut(|AnyDeviceSockets(any_device_sockets), core_ctx| {
-            let old_device =
-                core_ctx.with_socket_state_mut(&id, |_external_state, target, core_ctx| {
-                    let Target { device, protocol: _ } = target;
-                    match &device {
-                        TargetDevice::SpecificDevice(device) => {
-                            core_ctx.upgrade_weak_device_id(device)
-                        }
-                        TargetDevice::AnyDevice => {
-                            assert!(any_device_sockets.remove(&id));
-                            None
-                        }
+            let old_device = core_ctx.with_socket_state_mut(&id, |_external_state, target| {
+                let Target { device, protocol: _ } = target;
+                match &device {
+                    TargetDevice::SpecificDevice(device) => device.upgrade(),
+                    TargetDevice::AnyDevice => {
+                        assert!(any_device_sockets.remove(&id));
+                        None
                     }
-                });
+                }
+            });
             if let Some(device) = old_device {
                 core_ctx.with_device_sockets_mut(
                     &device,
@@ -553,8 +526,8 @@
         S::Buffer: BufferMut,
     {
         let (core_ctx, bindings_ctx) = self.contexts();
-        let metadata = match core_ctx.with_socket_state(id, |_external_state, target, core_ctx| {
-            make_send_metadata(core_ctx, target, params, None)
+        let metadata = match core_ctx.with_socket_state(id, |_external_state, target| {
+            make_send_metadata::<C::CoreContext>(target, params, None)
         }) {
             Ok(metadata) => metadata,
             Err(e) => return Err((body, e)),
@@ -578,7 +551,7 @@
         let (core_ctx, bindings_ctx) = self.contexts();
         let metadata = match core_ctx.with_socket_state(
             id,
-            |_external_state, target @ Target { device: _, protocol }, core_ctx| {
+            |_external_state, target @ Target { device: _, protocol }| {
                 let SendDatagramParams { frame, protocol: target_protocol, dest_addr } = params;
                 let protocol = match target_protocol.or_else(|| {
                     protocol.and_then(|p| match p {
@@ -590,8 +563,7 @@
                     Some(p) => p,
                 };
 
-                make_send_metadata(
-                    core_ctx,
+                make_send_metadata::<C::CoreContext>(
                     target,
                     frame,
                     Some(DatagramHeader { dest_addr, protocol: EtherType::from(protocol.get()) }),
@@ -621,7 +593,6 @@
 }
 
 fn make_send_metadata<CC: DeviceIdContext<AnyDevice>>(
-    core_ctx: &mut CC,
     bound: &Target<CC::WeakDeviceId>,
     params: SendFrameParams<<CC as DeviceIdContext<AnyDevice>>::DeviceId>,
     header: Option<DatagramHeader>,
@@ -631,7 +602,7 @@
 
     let device_id = match target_device.or_else(|| match device {
         TargetDevice::AnyDevice => None,
-        TargetDevice::SpecificDevice(d) => core_ctx.upgrade_weak_device_id(d),
+        TargetDevice::SpecificDevice(d) => d.upgrade(),
     }) {
         Some(d) => d,
         None => return Err(SendFrameError::NoDevice),
@@ -818,7 +789,7 @@
                 for socket in any_device_sockets.iter().chain(device_sockets) {
                     core_ctx.with_socket_state(
                         socket,
-                        |external_state, Target { protocol, device: _ }, _core_ctx| {
+                        |external_state, Target { protocol, device: _ }| {
                             let should_deliver = match protocol {
                                 None => false,
                                 Some(p) => match p {
@@ -910,30 +881,17 @@
 impl<BC: crate::BindingsContext, L: LockBefore<crate::lock_ordering::DeviceSocketState>>
     SocketStateAccessor<BC> for CoreCtx<'_, BC, L>
 {
-    type SocketStateCoreCtx<'a> = CoreCtx<'a, BC, crate::lock_ordering::DeviceSocketState>;
-
-    fn with_socket_state<
-        F: FnOnce(
-            &BC::SocketState,
-            &Target<Self::WeakDeviceId>,
-            &mut Self::SocketStateCoreCtx<'_>,
-        ) -> R,
-        R,
-    >(
+    fn with_socket_state<F: FnOnce(&BC::SocketState, &Target<Self::WeakDeviceId>) -> R, R>(
         &mut self,
         StrongId(strong): &Self::SocketId,
         cb: F,
     ) -> R {
         let SocketState { external_state, target, all_sockets_index: _ } = &**strong;
-        cb(external_state, &*target.lock(), &mut self.cast_locked())
+        cb(external_state, &*target.lock())
     }
 
     fn with_socket_state_mut<
-        F: FnOnce(
-            &BC::SocketState,
-            &mut Target<Self::WeakDeviceId>,
-            &mut Self::SocketStateCoreCtx<'_>,
-        ) -> R,
+        F: FnOnce(&BC::SocketState, &mut Target<Self::WeakDeviceId>) -> R,
         R,
     >(
         &mut self,
@@ -941,7 +899,7 @@
         cb: F,
     ) -> R {
         let SocketState { external_state, target, all_sockets_index: _ } = &**primary;
-        cb(external_state, &mut *target.lock(), &mut self.cast_locked())
+        cb(external_state, &mut *target.lock())
     }
 }
 
@@ -1080,7 +1038,9 @@
     use crate::{
         context::ContextProvider,
         device::{
-            testutil::{FakeStrongDeviceId, FakeWeakDeviceId, MultipleDevicesId},
+            testutil::{
+                FakeReferencyDeviceId, FakeStrongDeviceId, FakeWeakDeviceId, MultipleDevicesId,
+            },
             Id,
         },
     };
@@ -1286,11 +1246,6 @@
                 all_sockets: FakeAllSockets::<D>::default(),
             }
         }
-
-        fn remove_device(&mut self, device: &D) -> DeviceSockets<FakeStrongId> {
-            let Self { any_device_sockets: _, device_sockets, all_sockets: _ } = self;
-            device_sockets.remove(device).unwrap()
-        }
     }
 
     /// Simplified trait that provides a blanket impl of [`DeviceIdContext`].
@@ -1302,23 +1257,6 @@
     impl<CC: FakeDeviceIdContext> DeviceIdContext<AnyDevice> for CC {
         type DeviceId = CC::DeviceId;
         type WeakDeviceId = FakeWeakDeviceId<CC::DeviceId>;
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            FakeWeakDeviceId(device_id.clone())
-        }
-        fn upgrade_weak_device_id(&self, device_id: &Self::WeakDeviceId) -> Option<Self::DeviceId> {
-            self.contains_id(&device_id.0).then_some(device_id.0.clone())
-        }
-    }
-
-    impl<D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeCoreCtx<D> {
-        type DeviceId = D;
-        type WeakDeviceId = D::Weak;
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            self.get_ref().device_sockets.downgrade_device_id(device_id)
-        }
-        fn upgrade_weak_device_id(&self, device_id: &Self::WeakDeviceId) -> Option<Self::DeviceId> {
-            self.get_ref().device_sockets.upgrade_weak_device_id(device_id)
-        }
     }
 
     impl<
@@ -1331,40 +1269,30 @@
     where
         As::Devices: FakeDeviceIdContext<DeviceId = DeviceId>,
     {
-        type SocketStateCoreCtx<'a> = FakeSocketsMutRefs<'a, As::AnyDevice, (), As::Devices>;
-
         fn with_socket_state<
-            F: FnOnce(
-                &ExternalSocketState<Self::DeviceId>,
-                &Target<Self::WeakDeviceId>,
-                &mut Self::SocketStateCoreCtx<'_>,
-            ) -> R,
+            F: FnOnce(&ExternalSocketState<Self::DeviceId>, &Target<Self::WeakDeviceId>) -> R,
             R,
         >(
             &mut self,
             socket: &Self::SocketId,
             cb: F,
         ) -> R {
-            let FakeSocketsMutRefs(any_device, all_sockets, devices) = self.as_sockets_ref();
+            let FakeSocketsMutRefs(_, all_sockets, _) = self.as_sockets_ref();
             let (state, target) = all_sockets.get(socket.0).unwrap();
-            cb(state, target, &mut FakeSocketsMutRefs(any_device, &mut (), devices))
+            cb(state, target)
         }
 
         fn with_socket_state_mut<
-            F: FnOnce(
-                &ExternalSocketState<Self::DeviceId>,
-                &mut Target<Self::WeakDeviceId>,
-                &mut Self::SocketStateCoreCtx<'_>,
-            ) -> R,
+            F: FnOnce(&ExternalSocketState<Self::DeviceId>, &mut Target<Self::WeakDeviceId>) -> R,
             R,
         >(
             &mut self,
             socket: &Self::SocketId,
             cb: F,
         ) -> R {
-            let FakeSocketsMutRefs(any_device, all_sockets, devices) = self.as_sockets_ref();
+            let FakeSocketsMutRefs(_, all_sockets, _) = self.as_sockets_ref();
             let (state, target) = all_sockets.get_mut(socket.0).unwrap();
-            cb(state, target, &mut FakeSocketsMutRefs(any_device, &mut (), devices))
+            cb(state, target)
         }
     }
 
@@ -1623,29 +1551,30 @@
 
     #[test]
     fn change_device_after_removal() {
-        let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::with_state(FakeSockets::new(
-            MultipleDevicesId::all(),
-        )));
+        let device_to_remove = FakeReferencyDeviceId::default();
+        let device_to_maintain = FakeReferencyDeviceId::default();
+        let mut ctx = FakeCtx::with_core_ctx(FakeCoreCtx::with_state(FakeSockets::new([
+            device_to_remove.clone(),
+            device_to_maintain.clone(),
+        ])));
         let mut api = ctx.device_socket_api();
 
         let bound = api.create(Default::default());
         // Set the device for the socket before removing the device state
         // entirely.
-        const DEVICE_TO_REMOVE: MultipleDevicesId = MultipleDevicesId::A;
-        api.set_device(&bound, TargetDevice::SpecificDevice(&DEVICE_TO_REMOVE));
+        api.set_device(&bound, TargetDevice::SpecificDevice(&device_to_remove));
 
         // Now remove the device; this should cause future attempts to upgrade
         // the device ID to fail.
-        let removed = api.core_ctx().get_mut().remove_device(&DEVICE_TO_REMOVE);
-        assert_eq!(removed, DeviceSockets(HashSet::from([bound.clone()])));
+        device_to_remove.mark_removed();
 
         // Changing the device should gracefully handle the fact that the
         // earlier-bound device is now gone.
-        api.set_device(&bound, TargetDevice::SpecificDevice(&MultipleDevicesId::B));
+        api.set_device(&bound, TargetDevice::SpecificDevice(&device_to_maintain));
         assert_eq!(
             api.get_info(&bound),
             SocketInfo {
-                device: TargetDevice::SpecificDevice(FakeWeakDeviceId(MultipleDevicesId::B)),
+                device: TargetDevice::SpecificDevice(FakeWeakDeviceId(device_to_maintain.clone())),
                 protocol: None,
             }
         );
@@ -1653,7 +1582,7 @@
         let FakeSockets { device_sockets, any_device_sockets: _, all_sockets: _ } =
             api.core_ctx().get_ref();
         let DeviceSockets(weak_sockets) =
-            device_sockets.get(&MultipleDevicesId::B).expect("device state exists");
+            device_sockets.get(&device_to_maintain).expect("device state exists");
         assert_eq!(weak_sockets, &HashSet::from([bound]));
     }
 
diff --git a/src/connectivity/network/netstack3/core/src/device/state.rs b/src/connectivity/network/netstack3/core/src/device/state.rs
index 74079e0..ab94255 100644
--- a/src/connectivity/network/netstack3/core/src/device/state.rs
+++ b/src/connectivity/network/netstack3/core/src/device/state.rs
@@ -7,6 +7,8 @@
 use alloc::sync::Arc;
 use core::fmt::Debug;
 
+use net_types::ip::Ipv6;
+
 use crate::{
     context::{CoreTimerContext, TimerContext2},
     device::{
@@ -14,7 +16,10 @@
         OriginTracker,
     },
     inspect::Inspectable,
-    ip::{device::state::DualStackIpDeviceState, types::RawMetric},
+    ip::{
+        device::{state::DualStackIpDeviceState, IpDeviceTimerId},
+        types::RawMetric,
+    },
     sync::RwLock,
     sync::WeakRc,
 };
@@ -83,11 +88,17 @@
     pub(super) counters: DeviceCounters,
 }
 
-impl<T, BT: DeviceLayerTypes> IpLinkDeviceStateInner<T, BT> {
+impl<T, BC: DeviceLayerTypes + TimerContext2> IpLinkDeviceStateInner<T, BC> {
     /// Create a new `IpLinkDeviceState` with a link-specific state `link`.
-    pub(super) fn new(link: T, metric: RawMetric, origin: OriginTracker) -> Self {
+    pub(super) fn new<D: device::StrongId, CC: CoreTimerContext<IpDeviceTimerId<Ipv6, D>, BC>>(
+        bindings_ctx: &mut BC,
+        device_id: D::Weak,
+        link: T,
+        metric: RawMetric,
+        origin: OriginTracker,
+    ) -> Self {
         Self {
-            ip: DualStackIpDeviceState::new(metric),
+            ip: DualStackIpDeviceState::new::<_, CC>(bindings_ctx, device_id, metric),
             link,
             origin,
             sockets: RwLock::new(HeldDeviceSockets::default()),
diff --git a/src/connectivity/network/netstack3/core/src/filter/integration.rs b/src/connectivity/network/netstack3/core/src/filter/integration.rs
index 01780fa..6a75bc4 100644
--- a/src/connectivity/network/netstack3/core/src/filter/integration.rs
+++ b/src/connectivity/network/netstack3/core/src/filter/integration.rs
@@ -34,7 +34,7 @@
 impl<I: IpExt, BC: BindingsContext, L: LockBefore<crate::lock_ordering::FilterState<I>>>
     FilterIpContext<I, BC> for CoreCtx<'_, BC, L>
 {
-    fn with_filter_state<O, F: FnOnce(&State<I, BC::DeviceClass>) -> O>(&mut self, cb: F) -> O {
+    fn with_filter_state<O, F: FnOnce(&State<I, BC>) -> O>(&mut self, cb: F) -> O {
         let state = self.read_lock::<crate::lock_ordering::FilterState<I>>();
         cb(&state)
     }
@@ -43,10 +43,7 @@
 impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::FilterState<Ipv4>>> FilterContext<BC>
     for CoreCtx<'_, BC, L>
 {
-    fn with_all_filter_state_mut<
-        O,
-        F: FnOnce(&mut State<Ipv4, BC::DeviceClass>, &mut State<Ipv6, BC::DeviceClass>) -> O,
-    >(
+    fn with_all_filter_state_mut<O, F: FnOnce(&mut State<Ipv4, BC>, &mut State<Ipv6, BC>) -> O>(
         &mut self,
         cb: F,
     ) -> O {
@@ -59,13 +56,13 @@
 impl<I: IpExt, BC: BindingsContext> RwLockFor<crate::lock_ordering::FilterState<I>>
     for StackState<BC>
 {
-    type Data = State<I, BC::DeviceClass>;
+    type Data = State<I, BC>;
 
-    type ReadGuard<'l> = crate::sync::RwLockReadGuard<'l, State<I, BC::DeviceClass>>
+    type ReadGuard<'l> = crate::sync::RwLockReadGuard<'l, State<I, BC>>
     where
         Self: 'l;
 
-    type WriteGuard<'l> = crate::sync::RwLockWriteGuard<'l, State<I, BC::DeviceClass>>
+    type WriteGuard<'l> = crate::sync::RwLockWriteGuard<'l, State<I, BC>>
     where
         Self: 'l;
 
diff --git a/src/connectivity/network/netstack3/core/src/ip/api.rs b/src/connectivity/network/netstack3/core/src/ip/api.rs
index a96c1ec..933db9b 100644
--- a/src/connectivity/network/netstack3/core/src/ip/api.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/api.rs
@@ -12,7 +12,7 @@
 
 use crate::{
     context::ContextPair,
-    device::{AnyDevice, DeviceIdContext},
+    device::{self, AnyDevice, DeviceIdContext},
     inspect::{Inspector, InspectorDeviceExt},
     ip::{
         base::{IpLayerBindingsContext, IpLayerContext, ResolveRouteError},
@@ -205,12 +205,14 @@
 pub trait RoutesApiBindingsContext<I, D>:
     IpDeviceBindingsContext<I, D> + IpLayerBindingsContext<I, D>
 where
+    D: device::StrongId,
     I: IpLayerIpExt + IpDeviceIpExt,
 {
 }
 
 impl<I, D, BC> RoutesApiBindingsContext<I, D> for BC
 where
+    D: device::StrongId,
     I: IpLayerIpExt + IpDeviceIpExt,
     BC: IpDeviceBindingsContext<I, D> + IpLayerBindingsContext<I, D>,
 {
diff --git a/src/connectivity/network/netstack3/core/src/ip/base.rs b/src/connectivity/network/netstack3/core/src/ip/base.rs
index 0200b03..7307978 100644
--- a/src/connectivity/network/netstack3/core/src/ip/base.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/base.rs
@@ -6,15 +6,14 @@
 use core::{
     borrow::Borrow,
     cmp::Ordering,
-    convert::Infallible as Never,
     fmt::Debug,
     hash::Hash,
-    marker::PhantomData,
     num::{NonZeroU32, NonZeroU8},
     sync::atomic::{self, AtomicU16},
 };
 
 use const_unwrap::const_unwrap_option;
+use derivative::Derivative;
 use explicit::ResultExt as _;
 use lock_order::lock::UnlockedAccess;
 use lock_order::{
@@ -42,15 +41,16 @@
 
 use crate::{
     context::{
-        CoreTimerContext, CounterContext, EventContext, InstantContext, NonTestCtxMarker,
-        TimerBindingsTypes, TimerContext2, TimerHandler, TracingContext,
+        CoreTimerContext, CounterContext, EventContext, InstantContext, NestedIntoCoreTimerCtx,
+        NonTestCtxMarker, TimerContext2, TimerHandler, TracingContext,
     },
     counters::Counter,
     data_structures::token_bucket::TokenBucket,
     device::{AnyDevice, DeviceId, DeviceIdContext, FrameDestination, Id, StrongId, WeakDeviceId},
     filter::{
-        FilterBindingsTypes, FilterHandler as _, FilterHandlerProvider, ForwardedPacket,
-        MaybeTransportPacket, NestedWithInnerIpPacket,
+        ConntrackConnection, FilterBindingsContext, FilterBindingsTypes, FilterHandler as _,
+        FilterHandlerProvider, FilterIpMetadata, ForwardedPacket, IpPacket, MaybeTransportPacket,
+        NestedWithInnerIpPacket,
     },
     inspect::{Inspectable, Inspector},
     ip::{
@@ -134,6 +134,31 @@
     PortUnreachable,
 }
 
+/// Sidecar metadata passed along with the packet.
+///
+/// NOTE: This metadata may be reset after a packet goes through reassembly, and
+/// consumers must be able to handle this case.
+#[derive(Derivative)]
+#[derivative(Default(bound = ""))]
+pub struct IpLayerPacketMetadata<I: packet_formats::ip::IpExt, BT: FilterBindingsTypes> {
+    conntrack_connection: Option<ConntrackConnection<I, BT>>,
+}
+
+impl<I: packet_formats::ip::IpExt, BT: FilterBindingsTypes> FilterIpMetadata<I, BT>
+    for IpLayerPacketMetadata<I, BT>
+{
+    fn take_conntrack_connection(&mut self) -> Option<ConntrackConnection<I, BT>> {
+        self.conntrack_connection.take()
+    }
+
+    fn replace_conntrack_connection(
+        &mut self,
+        conn: ConntrackConnection<I, BT>,
+    ) -> Option<ConntrackConnection<I, BT>> {
+        self.conntrack_connection.replace(conn)
+    }
+}
+
 /// An [`Ip`] extension trait adding functionality specific to the IP layer.
 pub trait IpExt: packet_formats::ip::IpExt + IcmpIpExt + IpTypesIpExt {
     /// The type used to specify an IP packet's source address in a call to
@@ -400,17 +425,11 @@
     }
 }
 
-impl<S: Id, W: Id> EitherDeviceId<&'_ S, &'_ W> {
-    pub(crate) fn as_strong_ref<
-        'a,
-        CC: DeviceIdContext<AnyDevice, DeviceId = S, WeakDeviceId = W>,
-    >(
-        &'a self,
-        core_ctx: &CC,
-    ) -> Option<Cow<'a, CC::DeviceId>> {
+impl<S: Id, W: crate::device::WeakId<Strong = S>> EitherDeviceId<&'_ S, &'_ W> {
+    pub(crate) fn as_strong_ref<'a>(&'a self) -> Option<Cow<'a, S>> {
         match self {
             EitherDeviceId::Strong(s) => Some(Cow::Borrowed(s)),
-            EitherDeviceId::Weak(w) => core_ctx.upgrade_weak_device_id(w).map(Cow::Owned),
+            EitherDeviceId::Weak(w) => w.upgrade().map(Cow::Owned),
         }
     }
 }
@@ -428,23 +447,19 @@
     }
 }
 
-impl<S: Id, W: Id> EitherDeviceId<S, W> {
-    pub(crate) fn as_strong<'a, CC: DeviceIdContext<AnyDevice, DeviceId = S, WeakDeviceId = W>>(
-        &'a self,
-        core_ctx: &CC,
-    ) -> Option<Cow<'a, CC::DeviceId>> {
+impl<S: crate::device::StrongId<Weak = W>, W: crate::device::WeakId<Strong = S>>
+    EitherDeviceId<S, W>
+{
+    pub(crate) fn as_strong<'a>(&'a self) -> Option<Cow<'a, S>> {
         match self {
             EitherDeviceId::Strong(s) => Some(Cow::Borrowed(s)),
-            EitherDeviceId::Weak(w) => core_ctx.upgrade_weak_device_id(w).map(Cow::Owned),
+            EitherDeviceId::Weak(w) => w.upgrade().map(Cow::Owned),
         }
     }
 
-    pub(crate) fn as_weak<'a, CC: DeviceIdContext<AnyDevice, DeviceId = S, WeakDeviceId = W>>(
-        &'a self,
-        core_ctx: &CC,
-    ) -> Cow<'a, CC::WeakDeviceId> {
+    pub(crate) fn as_weak<'a>(&'a self) -> Cow<'a, W> {
         match self {
-            EitherDeviceId::Strong(s) => Cow::Owned(core_ctx.downgrade_device_id(s)),
+            EitherDeviceId::Strong(s) => Cow::Owned(s.downgrade()),
             EitherDeviceId::Weak(w) => Cow::Borrowed(w),
         }
     }
@@ -628,7 +643,7 @@
 
 /// The bindings execution context for the IP layer.
 pub trait IpLayerBindingsContext<I: Ip, DeviceId>:
-    InstantContext + EventContext<IpLayerEvent<DeviceId, I>> + TracingContext + FilterBindingsTypes
+    InstantContext + EventContext<IpLayerEvent<DeviceId, I>> + TracingContext + FilterBindingsContext
 {
 }
 impl<
@@ -637,7 +652,7 @@
         BC: InstantContext
             + EventContext<IpLayerEvent<DeviceId, I>>
             + TracingContext
-            + FilterBindingsTypes,
+            + FilterBindingsContext,
     > IpLayerBindingsContext<I, DeviceId> for BC
 {
 }
@@ -896,11 +911,9 @@
             + IpLayerBindingsContext<I, CC::DeviceId>
             + IpSocketBindingsContext,
         CC: IpLayerContext<I, BC>
+            + IpLayerEgressContext<I, BC>
             + device::IpDeviceConfigurationContext<I, BC>
-            + IpDeviceStateContext<I, BC>
-            + NonTestCtxMarker
-            + IpDeviceSendContext<I, BC>
-            + FilterHandlerProvider<I, BC>,
+            + NonTestCtxMarker,
     > IpSocketContext<I, BC> for CC
 {
     fn lookup_route(
@@ -922,12 +935,13 @@
             SpecifiedAddr<I::Addr>,
         >,
         body: S,
+        packet_metadata: IpLayerPacketMetadata<I, BC>,
     ) -> Result<(), S>
     where
         S: Serializer + MaybeTransportPacket,
         S::Buffer: BufferMut,
     {
-        send_ip_packet_from_device(self, bindings_ctx, meta.into(), body)
+        send_ip_packet_from_device(self, bindings_ctx, meta.into(), body, packet_metadata)
     }
 }
 
@@ -998,9 +1012,6 @@
 }
 
 /// A marker trait for all the contexts required for IP ingress.
-///
-/// This is a shorthand for all the traits required to operate on an ingress IP
-/// frame.
 pub(crate) trait IpLayerIngressContext<
     I: IpLayerIpExt + IcmpHandlerIpExt,
     BC: IpLayerBindingsContext<I, Self::DeviceId>,
@@ -1039,6 +1050,32 @@
     type DeviceId_ = Self::DeviceId;
 }
 
+/// A marker trait for all the contexts required for IP egress.
+pub(crate) trait IpLayerEgressContext<I, BC>:
+    IpDeviceSendContext<I, BC, DeviceId = Self::DeviceId_> + FilterHandlerProvider<I, BC>
+where
+    I: IpLayerIpExt,
+    BC: FilterBindingsTypes,
+{
+    // This is working around the fact that currently, where clauses are only
+    // elaborated for supertraits, and not, for example, bounds on associated types
+    // as we have here.
+    //
+    // See https://github.com/rust-lang/rust/issues/20671#issuecomment-1905186183
+    // for more discussion.
+    type DeviceId_: crate::filter::InterfaceProperties<BC::DeviceClass> + StrongId + Debug;
+}
+
+impl<I, BC, CC> IpLayerEgressContext<I, BC> for CC
+where
+    I: IpLayerIpExt,
+    BC: FilterBindingsTypes,
+    CC: IpDeviceSendContext<I, BC> + FilterHandlerProvider<I, BC>,
+    Self::DeviceId: crate::filter::InterfaceProperties<BC::DeviceClass>,
+{
+    type DeviceId_ = Self::DeviceId;
+}
+
 impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IcmpAllSocketsSet<Ipv4>>>
     IpTransportDispatchContext<Ipv4, BC> for CoreCtx<'_, BC, L>
 {
@@ -1209,11 +1246,11 @@
     pub(super) inner: IpStateInner<Ipv4, StrongDeviceId, BT>,
     pub(super) icmp: Icmpv4State<StrongDeviceId::Weak, BT>,
     pub(super) next_packet_id: AtomicU16,
-    pub(super) filter: RwLock<crate::filter::State<Ipv4, BT::DeviceClass>>,
+    pub(super) filter: RwLock<crate::filter::State<Ipv4, BT>>,
 }
 
 impl<StrongDeviceId: StrongId, BT: IpLayerBindingsTypes> Ipv4State<StrongDeviceId, BT> {
-    pub fn filter(&self) -> &RwLock<crate::filter::State<Ipv4, BT::DeviceClass>> {
+    pub fn filter(&self) -> &RwLock<crate::filter::State<Ipv4, BT>> {
         &self.filter
     }
 
@@ -1244,7 +1281,7 @@
     pub(super) inner: IpStateInner<Ipv6, StrongDeviceId, BT>,
     pub(super) icmp: Icmpv6State<StrongDeviceId::Weak, BT>,
     pub(super) slaac_counters: SlaacCounters,
-    pub(super) filter: RwLock<crate::filter::State<Ipv6, BT::DeviceClass>>,
+    pub(super) filter: RwLock<crate::filter::State<Ipv6, BT>>,
 }
 
 impl<StrongDeviceId: StrongId, BT: IpLayerBindingsTypes> Ipv6State<StrongDeviceId, BT> {
@@ -1252,7 +1289,7 @@
         &self.slaac_counters
     }
 
-    pub fn filter(&self) -> &RwLock<crate::filter::State<Ipv6, BT::DeviceClass>> {
+    pub fn filter(&self) -> &RwLock<crate::filter::State<Ipv6, BT>> {
         &self.filter
     }
 
@@ -1532,10 +1569,10 @@
     pub fn new<CC: CoreTimerContext<IpLayerTimerId, BC>>(bindings_ctx: &mut BC) -> Self {
         Self {
             table: Default::default(),
-            fragment_cache: Mutex::new(IpPacketFragmentCache::new::<IpLayerTimerCtx<CC>>(
-                bindings_ctx,
-            )),
-            pmtu_cache: Mutex::new(PmtuCache::new::<IpLayerTimerCtx<CC>>(bindings_ctx)),
+            fragment_cache: Mutex::new(
+                IpPacketFragmentCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx),
+            ),
+            pmtu_cache: Mutex::new(PmtuCache::new::<NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx)),
             counters: Default::default(),
         }
     }
@@ -1567,31 +1604,6 @@
     }
 }
 
-/// An uninstantiable type providing timer ID conversion for the IP layer.
-struct IpLayerTimerCtx<CC>(Never, PhantomData<CC>);
-
-impl<I, CC, BT> CoreTimerContext<FragmentTimerId<I>, BT> for IpLayerTimerCtx<CC>
-where
-    I: Ip,
-    CC: CoreTimerContext<IpLayerTimerId, BT>,
-    BT: TimerBindingsTypes,
-{
-    fn convert_timer(timer: FragmentTimerId<I>) -> BT::DispatchId {
-        CC::convert_timer(IpLayerTimerId::from(timer))
-    }
-}
-
-impl<I, CC, BT> CoreTimerContext<PmtuTimerId<I>, BT> for IpLayerTimerCtx<CC>
-where
-    BT: TimerBindingsTypes,
-    I: Ip,
-    CC: CoreTimerContext<IpLayerTimerId, BT>,
-{
-    fn convert_timer(timer: PmtuTimerId<I>) -> BT::DispatchId {
-        CC::convert_timer(IpLayerTimerId::from(timer))
-    }
-}
-
 impl<CC, BC> TimerHandler<BC, IpLayerTimerId> for CC
 where
     CC: TimerHandler<BC, FragmentTimerId<Ipv4>>
@@ -1643,6 +1655,7 @@
     proto: Ipv4Proto,
     body: B,
     parse_metadata: Option<ParseMetadata>,
+    mut packet_metadata: IpLayerPacketMetadata<Ipv4, BC>,
 ) {
     core_ctx.increment(|counters| &counters.dispatch_receive_ip_packet);
 
@@ -1656,9 +1669,11 @@
         | None => (),
     }
 
+    let _ = packet_metadata;
     match core_ctx.filter_handler().local_ingress_hook(
         &mut crate::filter::RxPacket::new(src_ip, dst_ip.get(), proto, &body),
         device,
+        &mut packet_metadata,
     ) {
         crate::filter::Verdict::Drop => return,
         crate::filter::Verdict::Accept => {}
@@ -1741,6 +1756,7 @@
     proto: Ipv6Proto,
     body: B,
     parse_metadata: Option<ParseMetadata>,
+    mut packet_metadata: IpLayerPacketMetadata<Ipv6, BC>,
 ) {
     // TODO(https://fxbug.dev/42095067): Once we support multiple extension
     // headers in IPv6, we will need to verify that the callers of this
@@ -1760,9 +1776,11 @@
         | None => (),
     }
 
+    let _ = packet_metadata;
     match core_ctx.filter_handler().local_ingress_hook(
         &mut crate::filter::RxPacket::new(src_ip.get(), dst_ip.get(), proto, &body),
         device,
+        &mut packet_metadata,
     ) {
         crate::filter::Verdict::Drop => return,
         crate::filter::Verdict::Accept => {}
@@ -1822,6 +1840,32 @@
     }
 }
 
+pub(crate) fn send_ip_frame<I, CC, BC, S>(
+    core_ctx: &mut CC,
+    bindings_ctx: &mut BC,
+    device: &CC::DeviceId,
+    next_hop: SpecifiedAddr<I::Addr>,
+    mut body: S,
+    broadcast: Option<I::BroadcastMarker>,
+    mut packet_metadata: IpLayerPacketMetadata<I, BC>,
+) -> Result<(), S>
+where
+    I: IpLayerIpExt,
+    BC: FilterBindingsTypes,
+    CC: IpLayerEgressContext<I, BC>,
+    S: Serializer + IpPacket<I>,
+    S::Buffer: BufferMut,
+{
+    let (verdict, proof) =
+        core_ctx.filter_handler().egress_hook(&mut body, device, &mut packet_metadata);
+    match verdict {
+        crate::filter::Verdict::Drop => return Ok(()),
+        crate::filter::Verdict::Accept => {}
+    }
+
+    core_ctx.send_ip_frame(bindings_ctx, device, next_hop, body, broadcast, proof)
+}
+
 /// Drop a packet and undo the effects of parsing it.
 ///
 /// `drop_packet_and_undo_parse!` takes a `$packet` and a `$buffer` which the
@@ -1844,7 +1888,7 @@
 /// ready to do so. If the packet isn't fragmented, or a packet was reassembled,
 /// attempt to dispatch the packet.
 macro_rules! process_fragment {
-    ($core_ctx:expr, $bindings_ctx:expr, $dispatch:ident, $device:ident, $frame_dst:expr, $buffer:expr, $packet:expr, $src_ip:expr, $dst_ip:expr, $ip:ident) => {{
+    ($core_ctx:expr, $bindings_ctx:expr, $dispatch:ident, $device:ident, $frame_dst:expr, $buffer:expr, $packet:expr, $src_ip:expr, $dst_ip:expr, $ip:ident, $packet_metadata:expr) => {{
         match FragmentHandler::<$ip, _>::process_fragment::<&mut [u8]>(
             $core_ctx,
             $bindings_ctx,
@@ -1866,6 +1910,7 @@
                     proto,
                     $buffer,
                     Some(meta),
+                    $packet_metadata,
                 );
             }
             // Ready to reassemble a packet.
@@ -1887,7 +1932,13 @@
                         // TODO(joshlf):
                         // - Check for already-expired TTL?
                         let (_, _, proto, meta) = packet.into_metadata();
-                        $dispatch::<_, Buf<Vec<u8>>, _>(
+                        // Since each fragment had its own packet metadata, it's
+                        // not clear what metadata to use for the reassembled
+                        // packet. Resetting the metadata is the safest bet,
+                        // though it means downstream consumers must be aware of
+                        // this case.
+                        let packet_metadata = IpLayerPacketMetadata::default();
+                        $dispatch::<_, Buf<Vec<u8>>, _,>(
                             $core_ctx,
                             $bindings_ctx,
                             $device,
@@ -1897,6 +1948,7 @@
                             proto,
                             buffer,
                             Some(meta),
+                            packet_metadata,
                         );
                     }
                     // TODO(ghanan): Handle reassembly errors, remove
@@ -2068,7 +2120,8 @@
 
     // TODO(ghanan): Act upon options.
 
-    match core_ctx.filter_handler().ingress_hook(&mut packet, device) {
+    let mut packet_metadata = IpLayerPacketMetadata::default();
+    match core_ctx.filter_handler().ingress_hook(&mut packet, device, &mut packet_metadata) {
         crate::filter::Verdict::Drop => return,
         crate::filter::Verdict::Accept => {}
     }
@@ -2101,7 +2154,8 @@
                 packet,
                 src_ip,
                 dst_ip,
-                Ipv4
+                Ipv4,
+                packet_metadata
             );
         }
         ReceivePacketAction::Forward { dst: Destination { device: dst_device, next_hop } } => {
@@ -2114,7 +2168,12 @@
             if ttl > 1 {
                 trace!("receive_ipv4_packet: forwarding");
 
-                match core_ctx.filter_handler().forwarding_hook(&mut packet, device, &dst_device) {
+                match core_ctx.filter_handler().forwarding_hook(
+                    &mut packet,
+                    device,
+                    &dst_device,
+                    &mut packet_metadata,
+                ) {
                     crate::filter::Verdict::Drop => return,
                     crate::filter::Verdict::Accept => {}
                 }
@@ -2122,13 +2181,15 @@
                 packet.set_ttl(ttl - 1);
                 let (src, dst, proto, meta) = packet.into_metadata();
                 let packet = ForwardedPacket::new(src, dst, proto, meta, buffer);
-                match IpDeviceSendContext::<Ipv4, _>::send_ip_frame(
+
+                match send_ip_frame(
                     core_ctx,
                     bindings_ctx,
                     &dst_device,
                     next_hop,
                     packet,
                     broadcast,
+                    packet_metadata,
                 ) {
                     Ok(()) => (),
                     Err(p) => {
@@ -2311,7 +2372,8 @@
         }
     };
 
-    match core_ctx.filter_handler().ingress_hook(&mut packet, device) {
+    let mut packet_metadata = IpLayerPacketMetadata::default();
+    match core_ctx.filter_handler().ingress_hook(&mut packet, device, &mut packet_metadata) {
         crate::filter::Verdict::Drop => return,
         crate::filter::Verdict::Accept => {}
     }
@@ -2362,6 +2424,7 @@
                         proto,
                         buffer,
                         Some(meta),
+                        packet_metadata,
                     );
                 }
                 Ipv6PacketAction::ProcessFragment => {
@@ -2395,7 +2458,8 @@
                         packet,
                         src_ip,
                         dst_ip,
-                        Ipv6
+                        Ipv6,
+                        packet_metadata
                     );
                 }
             }
@@ -2420,7 +2484,12 @@
                     Ipv6PacketAction::ProcessFragment => unreachable!("When forwarding packets, we should only ever look at the hop by hop options extension header (if present)"),
                 }
 
-                match core_ctx.filter_handler().forwarding_hook(&mut packet, device, &dst_device) {
+                match core_ctx.filter_handler().forwarding_hook(
+                    &mut packet,
+                    device,
+                    &dst_device,
+                    &mut packet_metadata,
+                ) {
                     crate::filter::Verdict::Drop => return,
                     crate::filter::Verdict::Accept => {}
                 }
@@ -2433,13 +2502,15 @@
                 packet.set_ttl(ttl - 1);
                 let (src, dst, proto, meta) = packet.into_metadata();
                 let packet = ForwardedPacket::new(src, dst, proto, meta, buffer);
-                if let Err(packet) = IpDeviceSendContext::<Ipv6, _>::send_ip_frame(
+
+                if let Err(packet) = send_ip_frame(
                     core_ctx,
                     bindings_ctx,
                     &dst_device,
                     next_hop,
                     packet,
                     None,
+                    packet_metadata,
                 ) {
                     // TODO(https://fxbug.dev/42167236): Encode the MTU error more
                     // obviously in the type system.
@@ -2820,7 +2891,14 @@
     }
 }
 
+/// Trait for abstracting the IP layer for locally-generated traffic.  That is,
+/// traffic generated by the netstack itself (e.g. ICMP, IGMP, or MLD).
+///
+/// NOTE: Due to filtering rules, it is possible that the device provided in
+/// `meta` will not be the device that final IP packet is actually sent from.
 pub(crate) trait IpLayerHandler<I: IpExt, BC>: DeviceIdContext<AnyDevice> {
+    /// Encapsulate and send the provided transport packet and from the device
+    /// provided in `meta`.
     fn send_ip_packet_from_device<S>(
         &mut self,
         bindings_ctx: &mut BC,
@@ -2830,12 +2908,30 @@
     where
         S: Serializer + MaybeTransportPacket,
         S::Buffer: BufferMut;
+
+    /// Send an IP packet that doesn't require the encapsulation and other
+    /// processing of [`send_ip_packet_from_device`] from the device specified
+    /// in `meta`.
+    // TODO(https://fxbug.dev/333908066): The packets going through this
+    // function only hit the EGRESS filter hook, bypassing LOCAL_EGRESS.
+    // Refactor callers and other functions to prevent this.
+    fn send_ip_frame<S>(
+        &mut self,
+        bindings_ctx: &mut BC,
+        device: &Self::DeviceId,
+        next_hop: SpecifiedAddr<I::Addr>,
+        body: S,
+        broadcast: Option<I::BroadcastMarker>,
+    ) -> Result<(), S>
+    where
+        S: Serializer + IpPacket<I>,
+        S::Buffer: BufferMut;
 }
 
 impl<
         I: IpLayerIpExt,
         BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
-        CC: IpDeviceStateContext<I, BC> + IpDeviceSendContext<I, BC> + NonTestCtxMarker,
+        CC: IpLayerEgressContext<I, BC> + IpDeviceStateContext<I, BC>,
     > IpLayerHandler<I, BC> for CC
 {
     fn send_ip_packet_from_device<S>(
@@ -2848,7 +2944,30 @@
         S: Serializer + MaybeTransportPacket,
         S::Buffer: BufferMut,
     {
-        send_ip_packet_from_device(self, bindings_ctx, meta, body)
+        send_ip_packet_from_device(self, bindings_ctx, meta, body, IpLayerPacketMetadata::default())
+    }
+
+    fn send_ip_frame<S>(
+        &mut self,
+        bindings_ctx: &mut BC,
+        device: &Self::DeviceId,
+        next_hop: SpecifiedAddr<I::Addr>,
+        body: S,
+        broadcast: Option<I::BroadcastMarker>,
+    ) -> Result<(), S>
+    where
+        S: Serializer + IpPacket<I>,
+        S::Buffer: BufferMut,
+    {
+        send_ip_frame(
+            self,
+            bindings_ctx,
+            device,
+            next_hop,
+            body,
+            broadcast,
+            IpLayerPacketMetadata::default(),
+        )
     }
 }
 
@@ -2867,11 +2986,12 @@
         Option<SpecifiedAddr<I::Addr>>,
     >,
     body: S,
+    packet_metadata: IpLayerPacketMetadata<I, BC>,
 ) -> Result<(), S>
 where
     I: IpLayerIpExt,
     BC: IpLayerBindingsContext<I, <CC as DeviceIdContext<AnyDevice>>::DeviceId>,
-    CC: IpDeviceStateContext<I, BC> + IpDeviceSendContext<I, BC>,
+    CC: IpLayerEgressContext<I, BC> + IpDeviceStateContext<I, BC>,
     S: Serializer + MaybeTransportPacket,
     S::Buffer: BufferMut,
 {
@@ -2906,12 +3026,10 @@
 
     if let Some(mtu) = mtu {
         let body = NestedWithInnerIpPacket::new(body.with_size_limit(mtu as usize));
-        core_ctx
-            .send_ip_frame(bindings_ctx, device, next_hop, body, broadcast)
+        send_ip_frame(core_ctx, bindings_ctx, device, next_hop, body, broadcast, packet_metadata)
             .map_err(|ser| ser.into_inner().into_inner())
     } else {
-        core_ctx
-            .send_ip_frame(bindings_ctx, device, next_hop, body, broadcast)
+        send_ip_frame(core_ctx, bindings_ctx, device, next_hop, body, broadcast, packet_metadata)
             .map_err(|ser| ser.into_inner())
     }
 }
@@ -3194,7 +3312,7 @@
 pub(crate) mod testutil {
     use super::*;
 
-    use alloc::collections::HashSet;
+    use core::marker::PhantomData;
 
     use derivative::Derivative;
     use net_types::ip::IpInvariant;
@@ -3204,21 +3322,13 @@
         device::testutil::{FakeStrongDeviceId, FakeWeakDeviceId},
     };
 
-    impl<S: AsRef<FakeIpDeviceIdCtx<D>>, Meta, D: StrongId + 'static> DeviceIdContext<AnyDevice>
+    impl<S, Meta, D: StrongId + 'static> DeviceIdContext<AnyDevice>
         for crate::context::testutil::FakeCoreCtx<S, Meta, D>
     where
         FakeIpDeviceIdCtx<D>: DeviceIdContext<AnyDevice, DeviceId = D, WeakDeviceId = D::Weak>,
     {
         type DeviceId = D;
         type WeakDeviceId = D::Weak;
-
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            self.get_ref().as_ref().downgrade_device_id(device_id)
-        }
-
-        fn upgrade_weak_device_id(&self, device_id: &Self::WeakDeviceId) -> Option<Self::DeviceId> {
-            self.get_ref().as_ref().upgrade_weak_device_id(device_id)
-        }
     }
 
     impl<Outer, Inner: DeviceIdContext<AnyDevice>> DeviceIdContext<AnyDevice>
@@ -3226,14 +3336,6 @@
     {
         type DeviceId = Inner::DeviceId;
         type WeakDeviceId = Inner::WeakDeviceId;
-
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            self.inner.downgrade_device_id(device_id)
-        }
-
-        fn upgrade_weak_device_id(&self, device_id: &Self::WeakDeviceId) -> Option<Self::DeviceId> {
-            self.inner.upgrade_weak_device_id(device_id)
-        }
     }
 
     #[derive(Debug, GenericOverIp)]
@@ -3263,28 +3365,13 @@
     }
 
     #[cfg(test)]
-    impl<
-            I: packet_formats::ip::IpExt + IpTypesIpExt,
-            S,
-            Id,
-            Event: Debug,
-            DeviceId,
-            BindingsCtxState,
-        >
-        crate::context::SendFrameContext<
-            crate::context::testutil::FakeBindingsCtx<Id, Event, BindingsCtxState, ()>,
-            SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>,
-        >
+    impl<I: packet_formats::ip::IpExt + IpTypesIpExt, S, DeviceId, BC>
+        crate::context::SendFrameContext<BC, SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>>
         for crate::context::testutil::FakeCoreCtx<S, DualStackSendIpPacketMeta<DeviceId>, DeviceId>
     {
         fn send_frame<SS>(
             &mut self,
-            bindings_ctx: &mut crate::context::testutil::FakeBindingsCtx<
-                Id,
-                Event,
-                BindingsCtxState,
-                (),
-            >,
+            bindings_ctx: &mut BC,
             metadata: SendIpPacketMeta<I, DeviceId, SpecifiedAddr<I::Addr>>,
             frame: SS,
         ) -> Result<(), SS>
@@ -3292,7 +3379,7 @@
             SS: Serializer,
             SS::Buffer: BufferMut,
         {
-            self.send_frame(bindings_ctx, DualStackSendIpPacketMeta::from(metadata), frame)
+            self.frames.send_frame(bindings_ctx, DualStackSendIpPacketMeta::from(metadata), frame)
         }
     }
 
@@ -3330,36 +3417,11 @@
 
     #[derive(Derivative)]
     #[derivative(Default(bound = ""))]
-    pub(crate) struct FakeIpDeviceIdCtx<D> {
-        devices_removed: HashSet<D>,
-    }
-
-    impl<D: Eq + Hash> FakeIpDeviceIdCtx<D> {
-        pub(crate) fn set_device_removed(&mut self, device: D, removed: bool) {
-            let Self { devices_removed } = self;
-            let _existed: bool = if removed {
-                devices_removed.insert(device)
-            } else {
-                devices_removed.remove(&device)
-            };
-        }
-    }
+    pub(crate) struct FakeIpDeviceIdCtx<D>(PhantomData<D>);
 
     impl<DeviceId: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeIpDeviceIdCtx<DeviceId> {
         type DeviceId = DeviceId;
         type WeakDeviceId = FakeWeakDeviceId<DeviceId>;
-
-        fn downgrade_device_id(&self, device_id: &DeviceId) -> FakeWeakDeviceId<DeviceId> {
-            FakeWeakDeviceId(device_id.clone())
-        }
-
-        fn upgrade_weak_device_id(
-            &self,
-            FakeWeakDeviceId(device_id): &FakeWeakDeviceId<DeviceId>,
-        ) -> Option<DeviceId> {
-            let Self { devices_removed } = self;
-            (!devices_removed.contains(&device_id)).then(|| device_id.clone())
-        }
     }
 
     impl<
diff --git a/src/connectivity/network/netstack3/core/src/ip/device.rs b/src/connectivity/network/netstack3/core/src/ip/device.rs
index 9dda293..8132ae4 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device.rs
@@ -39,9 +39,9 @@
     context::{
         EventContext, InstantBindingsTypes, InstantContext, RngContext, TimerContext, TimerHandler,
     },
-    device::{AnyDevice, DeviceIdContext},
+    device::{self, AnyDevice, DeviceIdContext, WeakId as _},
     error::{ExistsError, NotFoundError},
-    filter::IpPacket,
+    filter::{IpPacket, ProofOfEgressCheck},
     inspect::Inspectable,
     ip::{
         device::{
@@ -57,8 +57,8 @@
             router_solicitation::{RsHandler, RsTimerId},
             slaac::{SlaacHandler, SlaacTimerId},
             state::{
-                IpDeviceConfiguration, IpDeviceFlags, IpDeviceState, IpDeviceStateIpExt,
-                Ipv4AddrConfig, Ipv4AddressState, Ipv4DeviceConfiguration,
+                IpDeviceConfiguration, IpDeviceFlags, IpDeviceState, IpDeviceStateBindingsTypes,
+                IpDeviceStateIpExt, Ipv4AddrConfig, Ipv4AddressState, Ipv4DeviceConfiguration,
                 Ipv4DeviceConfigurationAndFlags, Ipv4DeviceState, Ipv6AddrConfig,
                 Ipv6AddrManualConfig, Ipv6AddressFlags, Ipv6AddressState, Ipv6DeviceConfiguration,
                 Ipv6DeviceConfigurationAndFlags, Ipv6DeviceState, Lifetime,
@@ -85,41 +85,44 @@
 /// handle `IpDeviceTimerId` timers.
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, GenericOverIp)]
 #[generic_over_ip(I, Ip)]
-pub struct IpDeviceTimerId<I: IpDeviceIpExt, DeviceId>(I::Timer<DeviceId>);
+pub struct IpDeviceTimerId<I: IpDeviceIpExt, D: device::StrongId>(I::Timer<D>);
 
 /// A timer ID for IPv4 devices.
+// TODO(https://fxbug.dev/42083407): Change to a weak device id bound once all
+// internal timers are transitioned.
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
-pub struct Ipv4DeviceTimerId<DeviceId>(IgmpTimerId<DeviceId>);
+pub struct Ipv4DeviceTimerId<D: device::StrongId>(IgmpTimerId<D>);
 
-impl<DeviceId> Ipv4DeviceTimerId<DeviceId> {
-    fn device_id(&self) -> &DeviceId {
+impl<D: device::StrongId> Ipv4DeviceTimerId<D> {
+    /// Gets the device ID from this timer IFF the device hasn't been destroyed.
+    fn device_id(&self) -> Option<D> {
         let Self(this) = self;
-        this.device_id()
+        Some(this.device_id().clone())
     }
 }
 
-impl<DeviceId> From<IpDeviceTimerId<Ipv4, DeviceId>> for Ipv4DeviceTimerId<DeviceId> {
-    fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv4, DeviceId>) -> Self {
+impl<D: device::StrongId> From<IpDeviceTimerId<Ipv4, D>> for Ipv4DeviceTimerId<D> {
+    fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv4, D>) -> Self {
         inner
     }
 }
 
-impl<DeviceId> From<Ipv4DeviceTimerId<DeviceId>> for IpDeviceTimerId<Ipv4, DeviceId> {
-    fn from(value: Ipv4DeviceTimerId<DeviceId>) -> Self {
+impl<D: device::StrongId> From<Ipv4DeviceTimerId<D>> for IpDeviceTimerId<Ipv4, D> {
+    fn from(value: Ipv4DeviceTimerId<D>) -> Self {
         Self(value)
     }
 }
 
-impl<DeviceId> From<IgmpTimerId<DeviceId>> for Ipv4DeviceTimerId<DeviceId> {
-    fn from(id: IgmpTimerId<DeviceId>) -> Ipv4DeviceTimerId<DeviceId> {
+impl<D: device::StrongId> From<IgmpTimerId<D>> for Ipv4DeviceTimerId<D> {
+    fn from(id: IgmpTimerId<D>) -> Ipv4DeviceTimerId<D> {
         Ipv4DeviceTimerId(id)
     }
 }
 
 impl_timer_context!(
-    DeviceId,
-    IpDeviceTimerId<Ipv4, DeviceId>,
-    Ipv4DeviceTimerId<DeviceId>,
+    D: device::StrongId,
+    IpDeviceTimerId<Ipv4, D>,
+    Ipv4DeviceTimerId<D>,
     IpDeviceTimerId(id),
     id
 );
@@ -127,21 +130,17 @@
 // If we are provided with an impl of `TimerContext<Ipv4DeviceTimerId<_>>`, then
 // we can in turn provide an impl of `TimerContext` for IGMP.
 impl_timer_context!(
-    DeviceId,
-    Ipv4DeviceTimerId<DeviceId>,
-    IgmpTimerId::<DeviceId>,
+    D: device::StrongId,
+    Ipv4DeviceTimerId<D>,
+    IgmpTimerId::<D>,
     Ipv4DeviceTimerId(id),
     id
 );
 
-impl<DeviceId, BC, CC: TimerHandler<BC, IgmpTimerId<DeviceId>>>
-    TimerHandler<BC, Ipv4DeviceTimerId<DeviceId>> for CC
+impl<D: device::StrongId, BC, CC: TimerHandler<BC, IgmpTimerId<D>>>
+    TimerHandler<BC, Ipv4DeviceTimerId<D>> for CC
 {
-    fn handle_timer(
-        &mut self,
-        bindings_ctx: &mut BC,
-        Ipv4DeviceTimerId(id): Ipv4DeviceTimerId<DeviceId>,
-    ) {
+    fn handle_timer(&mut self, bindings_ctx: &mut BC, Ipv4DeviceTimerId(id): Ipv4DeviceTimerId<D>) {
         TimerHandler::handle_timer(self, bindings_ctx, id)
     }
 }
@@ -156,7 +155,9 @@
         bindings_ctx: &mut BC,
         IpDeviceTimerId(id): IpDeviceTimerId<Ipv4, CC::DeviceId>,
     ) {
-        let device_id = id.device_id().clone();
+        let Some(device_id) = id.device_id() else {
+            return;
+        };
         self.with_ip_device_configuration(&device_id, |_state, mut core_ctx| {
             TimerHandler::handle_timer(&mut core_ctx, bindings_ctx, id)
         })
@@ -164,73 +165,76 @@
 }
 
 /// A timer ID for IPv6 devices.
+// TODO(https://fxbug.dev/42083407): Change to a weak device id bound once all
+// internal timers are transitioned.
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
-pub enum Ipv6DeviceTimerId<DeviceId> {
-    Mld(MldDelayedReportTimerId<DeviceId>),
-    Dad(DadTimerId<DeviceId>),
-    Rs(RsTimerId<DeviceId>),
-    RouteDiscovery(Ipv6DiscoveredRouteTimerId<DeviceId>),
-    Slaac(SlaacTimerId<DeviceId>),
+pub enum Ipv6DeviceTimerId<D: device::StrongId> {
+    Mld(MldDelayedReportTimerId<D>),
+    Dad(DadTimerId<D>),
+    Rs(RsTimerId<D::Weak>),
+    RouteDiscovery(Ipv6DiscoveredRouteTimerId<D::Weak>),
+    Slaac(SlaacTimerId<D>),
 }
 
-impl<DeviceId> From<IpDeviceTimerId<Ipv6, DeviceId>> for Ipv6DeviceTimerId<DeviceId> {
-    fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv6, DeviceId>) -> Self {
+impl<D: device::StrongId> From<IpDeviceTimerId<Ipv6, D>> for Ipv6DeviceTimerId<D> {
+    fn from(IpDeviceTimerId(inner): IpDeviceTimerId<Ipv6, D>) -> Self {
         inner
     }
 }
 
-impl<DeviceId> From<Ipv6DeviceTimerId<DeviceId>> for IpDeviceTimerId<Ipv6, DeviceId> {
-    fn from(value: Ipv6DeviceTimerId<DeviceId>) -> Self {
+impl<D: device::StrongId> From<Ipv6DeviceTimerId<D>> for IpDeviceTimerId<Ipv6, D> {
+    fn from(value: Ipv6DeviceTimerId<D>) -> Self {
         Self(value)
     }
 }
 
-impl<DeviceId> Ipv6DeviceTimerId<DeviceId> {
-    fn device_id(&self) -> &DeviceId {
+impl<D: device::StrongId> Ipv6DeviceTimerId<D> {
+    /// Gets the device ID from this timer IFF the device hasn't been destroyed.
+    fn device_id(&self) -> Option<D> {
         match self {
-            Self::Mld(id) => id.device_id(),
-            Self::Dad(id) => id.device_id(),
-            Self::Rs(id) => id.device_id(),
-            Self::RouteDiscovery(id) => id.device_id(),
-            Self::Slaac(id) => id.device_id(),
+            Self::Mld(id) => Some(id.device_id().clone()),
+            Self::Dad(id) => Some(id.device_id().clone()),
+            Self::Rs(id) => id.device_id().upgrade(),
+            Self::RouteDiscovery(id) => id.device_id().upgrade(),
+            Self::Slaac(id) => Some(id.device_id().clone()),
         }
     }
 }
 
-impl<DeviceId> From<MldDelayedReportTimerId<DeviceId>> for Ipv6DeviceTimerId<DeviceId> {
-    fn from(id: MldDelayedReportTimerId<DeviceId>) -> Ipv6DeviceTimerId<DeviceId> {
+impl<D: device::StrongId> From<MldDelayedReportTimerId<D>> for Ipv6DeviceTimerId<D> {
+    fn from(id: MldDelayedReportTimerId<D>) -> Ipv6DeviceTimerId<D> {
         Ipv6DeviceTimerId::Mld(id)
     }
 }
 
-impl<DeviceId> From<DadTimerId<DeviceId>> for Ipv6DeviceTimerId<DeviceId> {
-    fn from(id: DadTimerId<DeviceId>) -> Ipv6DeviceTimerId<DeviceId> {
+impl<D: device::StrongId> From<DadTimerId<D>> for Ipv6DeviceTimerId<D> {
+    fn from(id: DadTimerId<D>) -> Ipv6DeviceTimerId<D> {
         Ipv6DeviceTimerId::Dad(id)
     }
 }
 
-impl<DeviceId> From<RsTimerId<DeviceId>> for Ipv6DeviceTimerId<DeviceId> {
-    fn from(id: RsTimerId<DeviceId>) -> Ipv6DeviceTimerId<DeviceId> {
+impl<D: device::StrongId> From<RsTimerId<D::Weak>> for Ipv6DeviceTimerId<D> {
+    fn from(id: RsTimerId<D::Weak>) -> Ipv6DeviceTimerId<D> {
         Ipv6DeviceTimerId::Rs(id)
     }
 }
 
-impl<DeviceId> From<Ipv6DiscoveredRouteTimerId<DeviceId>> for Ipv6DeviceTimerId<DeviceId> {
-    fn from(id: Ipv6DiscoveredRouteTimerId<DeviceId>) -> Ipv6DeviceTimerId<DeviceId> {
+impl<D: device::StrongId> From<Ipv6DiscoveredRouteTimerId<D::Weak>> for Ipv6DeviceTimerId<D> {
+    fn from(id: Ipv6DiscoveredRouteTimerId<D::Weak>) -> Ipv6DeviceTimerId<D> {
         Ipv6DeviceTimerId::RouteDiscovery(id)
     }
 }
 
-impl<DeviceId> From<SlaacTimerId<DeviceId>> for Ipv6DeviceTimerId<DeviceId> {
-    fn from(id: SlaacTimerId<DeviceId>) -> Ipv6DeviceTimerId<DeviceId> {
+impl<D: device::StrongId> From<SlaacTimerId<D>> for Ipv6DeviceTimerId<D> {
+    fn from(id: SlaacTimerId<D>) -> Ipv6DeviceTimerId<D> {
         Ipv6DeviceTimerId::Slaac(id)
     }
 }
 
 impl_timer_context!(
-    DeviceId,
-    IpDeviceTimerId<Ipv6, DeviceId>,
-    Ipv6DeviceTimerId<DeviceId>,
+    D: device::StrongId,
+    IpDeviceTimerId<Ipv6, D>,
+    Ipv6DeviceTimerId<D>,
     IpDeviceTimerId(id),
     id
 );
@@ -238,52 +242,38 @@
 // If we are provided with an impl of `TimerContext<Ipv6DeviceTimerId<_>>`, then
 // we can in turn provide an impl of `TimerContext` for MLD and DAD.
 impl_timer_context!(
-    DeviceId,
-    Ipv6DeviceTimerId<DeviceId>,
-    MldDelayedReportTimerId::<DeviceId>,
+    D: device::StrongId,
+    Ipv6DeviceTimerId<D>,
+    MldDelayedReportTimerId::<D>,
     Ipv6DeviceTimerId::Mld(id),
     id
 );
 impl_timer_context!(
-    DeviceId,
-    Ipv6DeviceTimerId<DeviceId>,
-    DadTimerId::<DeviceId>,
+    D: device::StrongId,
+    Ipv6DeviceTimerId<D>,
+    DadTimerId::<D>,
     Ipv6DeviceTimerId::Dad(id),
     id
 );
 impl_timer_context!(
-    DeviceId,
-    Ipv6DeviceTimerId<DeviceId>,
-    RsTimerId::<DeviceId>,
-    Ipv6DeviceTimerId::Rs(id),
-    id
-);
-impl_timer_context!(
-    DeviceId,
-    Ipv6DeviceTimerId<DeviceId>,
-    Ipv6DiscoveredRouteTimerId::<DeviceId>,
-    Ipv6DeviceTimerId::RouteDiscovery(id),
-    id
-);
-impl_timer_context!(
-    DeviceId,
-    Ipv6DeviceTimerId<DeviceId>,
-    SlaacTimerId::<DeviceId>,
+    D: device::StrongId,
+    Ipv6DeviceTimerId<D>,
+    SlaacTimerId::<D>,
     Ipv6DeviceTimerId::Slaac(id),
     id
 );
 
 impl<
-        DeviceId,
+        D: device::StrongId,
         BC,
-        CC: TimerHandler<BC, RsTimerId<DeviceId>>
-            + TimerHandler<BC, Ipv6DiscoveredRouteTimerId<DeviceId>>
-            + TimerHandler<BC, MldDelayedReportTimerId<DeviceId>>
-            + TimerHandler<BC, SlaacTimerId<DeviceId>>
-            + TimerHandler<BC, DadTimerId<DeviceId>>,
-    > TimerHandler<BC, Ipv6DeviceTimerId<DeviceId>> for CC
+        CC: TimerHandler<BC, RsTimerId<D::Weak>>
+            + TimerHandler<BC, Ipv6DiscoveredRouteTimerId<D::Weak>>
+            + TimerHandler<BC, MldDelayedReportTimerId<D>>
+            + TimerHandler<BC, SlaacTimerId<D>>
+            + TimerHandler<BC, DadTimerId<D>>,
+    > TimerHandler<BC, Ipv6DeviceTimerId<D>> for CC
 {
-    fn handle_timer(&mut self, bindings_ctx: &mut BC, id: Ipv6DeviceTimerId<DeviceId>) {
+    fn handle_timer(&mut self, bindings_ctx: &mut BC, id: Ipv6DeviceTimerId<D>) {
         match id {
             Ipv6DeviceTimerId::Mld(id) => TimerHandler::handle_timer(self, bindings_ctx, id),
             Ipv6DeviceTimerId::Dad(id) => TimerHandler::handle_timer(self, bindings_ctx, id),
@@ -306,7 +296,9 @@
         bindings_ctx: &mut BC,
         IpDeviceTimerId(id): IpDeviceTimerId<Ipv6, CC::DeviceId>,
     ) {
-        let device_id = id.device_id().clone();
+        let Some(device_id) = id.device_id() else {
+            return;
+        };
         self.with_ip_device_configuration(&device_id, |_state, mut core_ctx| {
             TimerHandler::handle_timer(&mut core_ctx, bindings_ctx, id)
         })
@@ -315,10 +307,10 @@
 
 /// An extension trait adding IP device properties.
 pub trait IpDeviceIpExt: IpDeviceStateIpExt {
-    type State<I: Instant>: AsRef<IpDeviceState<I, Self>> + AsMut<IpDeviceState<I, Self>>;
+    type State<BT: IpDeviceStateBindingsTypes>: AsRef<IpDeviceState<Self, BT>>
+        + AsMut<IpDeviceState<Self, BT>>;
     type Configuration: AsRef<IpDeviceConfiguration> + Clone;
-    type Timer<DeviceId>: Into<IpDeviceTimerId<Self, DeviceId>>
-        + From<IpDeviceTimerId<Self, DeviceId>>;
+    type Timer<D: device::StrongId>: Into<IpDeviceTimerId<Self, D>> + From<IpDeviceTimerId<Self, D>>;
     type AssignedWitness: Witness<Self::Addr>
         + Copy
         + PartialEq
@@ -344,9 +336,9 @@
 }
 
 impl IpDeviceIpExt for Ipv4 {
-    type State<I: Instant> = Ipv4DeviceState<I>;
+    type State<BT: IpDeviceStateBindingsTypes> = Ipv4DeviceState<BT>;
     type Configuration = Ipv4DeviceConfiguration;
-    type Timer<DeviceId> = Ipv4DeviceTimerId<DeviceId>;
+    type Timer<D: device::StrongId> = Ipv4DeviceTimerId<D>;
     type AssignedWitness = SpecifiedAddr<Ipv4Addr>;
     type AddressConfig<I: Instant> = Ipv4AddrConfig<I>;
     type ManualAddressConfig<I: Instant> = Ipv4AddrConfig<I>;
@@ -365,9 +357,9 @@
 }
 
 impl IpDeviceIpExt for Ipv6 {
-    type State<I: Instant> = Ipv6DeviceState<I>;
+    type State<BT: IpDeviceStateBindingsTypes> = Ipv6DeviceState<BT>;
     type Configuration = Ipv6DeviceConfiguration;
-    type Timer<DeviceId> = Ipv6DeviceTimerId<DeviceId>;
+    type Timer<D: device::StrongId> = Ipv6DeviceTimerId<D>;
     type AssignedWitness = Ipv6DeviceAddr;
     type AddressConfig<I: Instant> = Ipv6AddrConfig<I>;
     type ManualAddressConfig<I: Instant> = Ipv6AddrManualConfig<I>;
@@ -469,8 +461,7 @@
 
 impl<
         DeviceId,
-        BC: InstantContext
-            + EventContext<IpDeviceEvent<DeviceId, Ipv6, <BC as InstantBindingsTypes>::Instant>>,
+        BC: InstantBindingsTypes + EventContext<IpDeviceEvent<DeviceId, Ipv6, BC::Instant>>,
     > EventContext<DadEvent<DeviceId>> for BC
 {
     fn on_event(&mut self, event: DadEvent<DeviceId>) {
@@ -488,19 +479,19 @@
 }
 
 /// The bindings execution context for IP devices.
-pub trait IpDeviceBindingsContext<I: IpDeviceIpExt, DeviceId>:
+pub trait IpDeviceBindingsContext<I: IpDeviceIpExt, D: device::StrongId>:
     RngContext
-    + TimerContext<IpDeviceTimerId<I, DeviceId>>
-    + EventContext<IpDeviceEvent<DeviceId, I, <Self as InstantBindingsTypes>::Instant>>
+    + TimerContext<IpDeviceTimerId<I, D>>
+    + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>
 {
 }
 impl<
-        DeviceId,
+        D: device::StrongId,
         I: IpDeviceIpExt,
         BC: RngContext
-            + TimerContext<IpDeviceTimerId<I, DeviceId>>
-            + EventContext<IpDeviceEvent<DeviceId, I, <Self as InstantBindingsTypes>::Instant>>,
-    > IpDeviceBindingsContext<I, DeviceId> for BC
+            + TimerContext<IpDeviceTimerId<I, D>>
+            + EventContext<IpDeviceEvent<D, I, <Self as InstantBindingsTypes>::Instant>>,
+    > IpDeviceBindingsContext<I, D> for BC
 {
 }
 
@@ -541,17 +532,17 @@
     type AddressId: IpAddressId<I::Addr>;
 }
 
-pub trait IpDeviceAddressContext<I: IpDeviceIpExt, BC: InstantContext>:
+pub trait IpDeviceAddressContext<I: IpDeviceIpExt, BT: InstantBindingsTypes>:
     IpDeviceAddressIdContext<I>
 {
-    fn with_ip_address_state<O, F: FnOnce(&I::AddressState<BC::Instant>) -> O>(
+    fn with_ip_address_state<O, F: FnOnce(&I::AddressState<BT::Instant>) -> O>(
         &mut self,
         device_id: &Self::DeviceId,
         addr_id: &Self::AddressId,
         cb: F,
     ) -> O;
 
-    fn with_ip_address_state_mut<O, F: FnOnce(&mut I::AddressState<BC::Instant>) -> O>(
+    fn with_ip_address_state_mut<O, F: FnOnce(&mut I::AddressState<BT::Instant>) -> O>(
         &mut self,
         device_id: &Self::DeviceId,
         addr_id: &Self::AddressId,
@@ -560,12 +551,12 @@
 }
 
 /// Accessor for IP device state.
-pub trait IpDeviceStateContext<I: IpDeviceIpExt, BC: InstantContext>:
-    IpDeviceAddressContext<I, BC>
+pub trait IpDeviceStateContext<I: IpDeviceIpExt, BT: InstantBindingsTypes>:
+    IpDeviceAddressContext<I, BT>
 {
     type IpDeviceAddressCtx<'a>: IpDeviceAddressContext<
         I,
-        BC,
+        BT,
         DeviceId = Self::DeviceId,
         AddressId = Self::AddressId,
     >;
@@ -587,7 +578,7 @@
         &mut self,
         device_id: &Self::DeviceId,
         addr: AddrSubnet<I::Addr, I::AssignedWitness>,
-        config: I::AddressConfig<BC::Instant>,
+        config: I::AddressConfig<BT::Instant>,
     ) -> Result<Self::AddressId, ExistsError>;
 
     /// Removes an address from the device identified by the ID.
@@ -595,7 +586,7 @@
         &mut self,
         device_id: &Self::DeviceId,
         addr: Self::AddressId,
-    ) -> (AddrSubnet<I::Addr, I::AssignedWitness>, I::AddressConfig<BC::Instant>);
+    ) -> (AddrSubnet<I::Addr, I::AssignedWitness>, I::AddressConfig<BT::Instant>);
 
     /// Returns the address ID for the given address value.
     fn get_address_id(
@@ -604,15 +595,14 @@
         addr: SpecifiedAddr<I::Addr>,
     ) -> Result<Self::AddressId, NotFoundError>;
 
+    /// The iterator given to `with_address_ids`.
+    type AddressIdsIter<'a>: Iterator<Item = Self::AddressId> + 'a;
+
     /// Calls the function with an iterator over all the address IDs associated
     /// with the device.
-    // TODO(https://fxbug.dev/42059236): Avoid dynamic dispatch.
     fn with_address_ids<
         O,
-        F: FnOnce(
-            Box<dyn Iterator<Item = Self::AddressId> + '_>,
-            &mut Self::IpDeviceAddressCtx<'_>,
-        ) -> O,
+        F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
     >(
         &mut self,
         device_id: &Self::DeviceId,
@@ -639,7 +629,7 @@
     /// multicast group.
     fn join_link_multicast_group(
         &mut self,
-        bindings_ctx: &mut BC,
+        bindings_ctx: &mut BT,
         device_id: &Self::DeviceId,
         multicast_addr: MulticastAddr<I::Addr>,
     );
@@ -648,7 +638,7 @@
     /// multicast group.
     fn leave_link_multicast_group(
         &mut self,
-        bindings_ctx: &mut BC,
+        bindings_ctx: &mut BT,
         device_id: &Self::DeviceId,
         multicast_addr: MulticastAddr<I::Addr>,
     );
@@ -656,12 +646,12 @@
 
 /// The context provided to the callback passed to
 /// [`IpDeviceConfigurationContext::with_ip_device_configuration_mut`].
-pub trait WithIpDeviceConfigurationMutInner<I: IpDeviceIpExt, BC: InstantContext>:
+pub trait WithIpDeviceConfigurationMutInner<I: IpDeviceIpExt, BT: InstantBindingsTypes>:
     DeviceIdContext<AnyDevice>
 {
-    type IpDeviceStateCtx<'s>: IpDeviceStateContext<I, BC, DeviceId = Self::DeviceId>
-        + GmpHandler<I, BC>
-        + NudIpHandler<I, BC>
+    type IpDeviceStateCtx<'s>: IpDeviceStateContext<I, BT, DeviceId = Self::DeviceId>
+        + GmpHandler<I, BT>
+        + NudIpHandler<I, BT>
         + 's
     where
         Self: 's;
@@ -1096,6 +1086,7 @@
         local_addr: SpecifiedAddr<I::Addr>,
         body: S,
         broadcast: Option<I::BroadcastMarker>,
+        egress_proof: ProofOfEgressCheck,
     ) -> Result<(), S>
     where
         S: Serializer + IpPacket<I>,
@@ -1325,8 +1316,8 @@
 ///
 /// Returns an [`Iterator`] of `AddrSubnet`.
 pub(crate) fn with_assigned_ipv4_addr_subnets<
-    BC: InstantContext,
-    CC: IpDeviceStateContext<Ipv4, BC>,
+    BT: InstantBindingsTypes,
+    CC: IpDeviceStateContext<Ipv4, BT>,
     O,
     F: FnOnce(Box<dyn Iterator<Item = AddrSubnet<Ipv4Addr>> + '_>) -> O,
 >(
@@ -1339,7 +1330,7 @@
 }
 
 /// Gets a single IPv4 address and subnet for a device.
-pub(crate) fn get_ipv4_addr_subnet<BC: InstantContext, CC: IpDeviceStateContext<Ipv4, BC>>(
+pub(crate) fn get_ipv4_addr_subnet<BT: InstantBindingsTypes, CC: IpDeviceStateContext<Ipv4, BT>>(
     core_ctx: &mut CC,
     device_id: &CC::DeviceId,
 ) -> Option<AddrSubnet<Ipv4Addr>> {
@@ -1347,7 +1338,7 @@
 }
 
 /// Gets the hop limit for new IPv6 packets that will be sent out from `device`.
-pub(crate) fn get_ipv6_hop_limit<BC: InstantContext, CC: IpDeviceStateContext<Ipv6, BC>>(
+pub(crate) fn get_ipv6_hop_limit<BT: InstantBindingsTypes, CC: IpDeviceStateContext<Ipv6, BT>>(
     core_ctx: &mut CC,
     device: &CC::DeviceId,
 ) -> NonZeroU8 {
@@ -2068,7 +2059,7 @@
             let mut timers = vec![
                 (
                     TimerId(TimerIdInner::Ipv6Device(
-                        Ipv6DeviceTimerId::Rs(RsTimerId { device_id: device_id.clone() }).into(),
+                        Ipv6DeviceTimerId::Rs(RsTimerId::new(device_id.downgrade())).into(),
                     )),
                     ..,
                 ),
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/integration.rs b/src/connectivity/network/netstack3/core/src/ip/device/integration.rs
index 924df7a..f738815 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/integration.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/integration.rs
@@ -4,7 +4,6 @@
 
 //! The integrations for protocols built on top of an IP device.
 
-use alloc::boxed::Box;
 use core::{
     borrow::Borrow,
     marker::PhantomData,
@@ -23,16 +22,19 @@
     LinkLocalUnicastAddr, MulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _,
 };
 use packet::{EmptyBuf, Serializer};
-use packet_formats::icmp::{
-    ndp::{NeighborSolicitation, RouterSolicitation},
-    IcmpUnusedCode,
+use packet_formats::{
+    icmp::{
+        ndp::{NeighborSolicitation, RouterSolicitation},
+        IcmpUnusedCode,
+    },
+    ip::IpExt,
 };
 
 use crate::{
-    context::{CounterContext, InstantContext},
+    context::{CoreTimerContext, CounterContext, InstantContext},
     device::{AnyDevice, DeviceId, DeviceIdContext},
     error::{ExistsError, NotFoundError},
-    filter::MaybeTransportPacket,
+    filter::{FilterHandlerProvider, FilterImpl, MaybeTransportPacket},
     ip::{
         self,
         device::{
@@ -45,18 +47,18 @@
                 Ipv6DiscoveredRoute, Ipv6DiscoveredRoutesContext, Ipv6RouteDiscoveryContext,
                 Ipv6RouteDiscoveryState,
             },
-            router_solicitation::{RsContext, RsHandler},
+            router_solicitation::{RsContext, RsHandler, RsState},
             slaac::{
                 SlaacAddressEntry, SlaacAddressEntryMut, SlaacAddresses, SlaacAddrsMutAndConfig,
                 SlaacContext, SlaacCounters,
             },
             state::{
                 DualStackIpDeviceState, IpDeviceConfiguration, IpDeviceFlags,
-                Ipv4DeviceConfiguration, Ipv6AddrConfig, Ipv6AddressFlags, Ipv6AddressState,
-                Ipv6DeviceConfiguration, SlaacConfig,
+                IpDeviceStateBindingsTypes, Ipv4DeviceConfiguration, Ipv6AddrConfig,
+                Ipv6AddressFlags, Ipv6AddressState, Ipv6DeviceConfiguration, SlaacConfig,
             },
             AddressRemovedReason, DelIpAddr, IpAddressId, IpDeviceAddr, IpDeviceBindingsContext,
-            IpDeviceIpExt, IpDeviceStateContext, Ipv6DeviceAddr,
+            IpDeviceIpExt, IpDeviceStateContext, IpDeviceTimerId, Ipv6DeviceAddr,
         },
         gmp::{
             self,
@@ -69,7 +71,7 @@
         AddressStatus, IpLayerIpExt, IpStateContext, Ipv4PresentAddressStatus,
         Ipv6PresentAddressStatus, DEFAULT_TTL,
     },
-    BindingsContext, CoreCtx, StackState,
+    BindingsContext, BindingsTypes, CoreCtx, StackState,
 };
 
 use super::state::Ipv6NetworkLearnedParameters;
@@ -81,14 +83,52 @@
         crate::lock_ordering::IpDeviceConfiguration<Ipv6>,
         BC,
     >,
-    pub(crate) device_id: <CoreCtxWithIpDeviceConfiguration<
-        'a,
-        &'a Ipv6DeviceConfiguration,
-        crate::lock_ordering::IpDeviceConfiguration<Ipv6>,
-        BC,
-    > as DeviceIdContext<AnyDevice>>::DeviceId,
+    pub(crate) device_id: DeviceId<BC>,
     pub(crate) config: &'a Ipv6DeviceConfiguration,
-    pub(crate) _marker: PhantomData<BC>,
+}
+
+/// Provides an Iterator for `SlaacAddrs` to implement `SlaacAddresses`.
+///
+/// Note that we use concrete types here instead of going through traits because
+/// it's the only way to satisfy the GAT bounds on `SlaacAddresses`' associated
+/// type.
+pub(crate) struct SlaacAddrsIter<'x, BC: BindingsContext> {
+    core_ctx: CoreCtx<'x, BC, crate::lock_ordering::IpDeviceAddresses<Ipv6>>,
+    addrs: ip::device::state::AddressIdIter<'x, BC::Instant, Ipv6>,
+    device_id: &'x DeviceId<BC>,
+}
+
+impl<'x, BC> Iterator for SlaacAddrsIter<'x, BC>
+where
+    BC: BindingsContext,
+{
+    type Item = SlaacAddressEntry<BC::Instant>;
+    fn next(&mut self) -> Option<Self::Item> {
+        let Self { core_ctx, addrs, device_id } = self;
+        // NB: This form is equivalent to using the `filter_map` combinator but
+        // keeps the type signature simple.
+        addrs.by_ref().find_map(|addr_id| {
+            device::IpDeviceAddressContext::<Ipv6, _>::with_ip_address_state(
+                core_ctx,
+                device_id,
+                &addr_id,
+                |Ipv6AddressState {
+                     flags: Ipv6AddressFlags { deprecated, assigned: _ },
+                     config,
+                 }| {
+                    let addr_sub = addr_id.addr_sub();
+                    match config {
+                        Ipv6AddrConfig::Slaac(config) => Some(SlaacAddressEntry {
+                            addr_sub,
+                            config: *config,
+                            deprecated: *deprecated,
+                        }),
+                        Ipv6AddrConfig::Manual(_manual_config) => None,
+                    }
+                },
+            )
+        })
+    }
 }
 
 impl<'a, BC: BindingsContext> CounterContext<SlaacCounters> for SlaacAddrs<'a, BC> {
@@ -99,7 +139,7 @@
 
 impl<'a, BC: BindingsContext> SlaacAddresses<BC> for SlaacAddrs<'a, BC> {
     fn for_each_addr_mut<F: FnMut(SlaacAddressEntryMut<'_, BC::Instant>)>(&mut self, mut cb: F) {
-        let SlaacAddrs { core_ctx, device_id, config: _, _marker } = self;
+        let SlaacAddrs { core_ctx, device_id, config: _ } = self;
         let CoreCtxWithIpDeviceConfiguration { config: _, core_ctx } = core_ctx;
         crate::device::integration::with_ip_device_state(core_ctx, device_id, |mut state| {
             let (addrs, mut locked) =
@@ -126,39 +166,15 @@
         })
     }
 
-    fn with_addrs<
-        O,
-        F: FnOnce(Box<dyn Iterator<Item = SlaacAddressEntry<BC::Instant>> + '_>) -> O,
-    >(
-        &mut self,
-        cb: F,
-    ) -> O {
-        let SlaacAddrs { core_ctx, device_id, config: _, _marker } = self;
+    type AddrsIter<'x> = SlaacAddrsIter<'x, BC>;
+
+    fn with_addrs<O, F: FnOnce(Self::AddrsIter<'_>) -> O>(&mut self, cb: F) -> O {
+        let SlaacAddrs { core_ctx, device_id, config: _ } = self;
         device::IpDeviceStateContext::<Ipv6, BC>::with_address_ids(
             core_ctx,
             device_id,
             |addrs, core_ctx| {
-                cb(Box::new(addrs.filter_map(|addr_id| {
-                    device::IpDeviceAddressContext::<Ipv6, _>::with_ip_address_state(
-                        core_ctx,
-                        device_id,
-                        &addr_id,
-                        |Ipv6AddressState {
-                             flags: Ipv6AddressFlags { deprecated, assigned: _ },
-                             config,
-                         }| {
-                            let addr_sub = addr_id.addr_sub();
-                            match config {
-                                Ipv6AddrConfig::Slaac(config) => Some(SlaacAddressEntry {
-                                    addr_sub,
-                                    config: *config,
-                                    deprecated: *deprecated,
-                                }),
-                                Ipv6AddrConfig::Manual(_manual_config) => None,
-                            }
-                        },
-                    )
-                })))
+                cb(SlaacAddrsIter { core_ctx: core_ctx.as_owned(), addrs, device_id })
             },
         )
     }
@@ -170,7 +186,7 @@
         slaac_config: SlaacConfig<BC::Instant>,
         and_then: F,
     ) -> Result<O, ExistsError> {
-        let SlaacAddrs { core_ctx, device_id, config, _marker } = self;
+        let SlaacAddrs { core_ctx, device_id, config } = self;
 
         add_ip_addr_subnet_with_config(
             core_ctx,
@@ -207,7 +223,7 @@
         addr: &Ipv6DeviceAddr,
     ) -> Result<(AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>, SlaacConfig<BC::Instant>), NotFoundError>
     {
-        let SlaacAddrs { core_ctx, device_id, config, _marker } = self;
+        let SlaacAddrs { core_ctx, device_id, config } = self;
         del_ip_addr_inner(
             core_ctx,
             bindings_ctx,
@@ -312,13 +328,13 @@
 
 impl<
         's,
-        BC: InstantContext,
+        BT: IpDeviceStateBindingsTypes,
         I: Ip + IpLayerIpExt + IpDeviceIpExt,
         Devices: Iterator<Item = Accessor::DeviceId>,
-        Accessor: IpDeviceStateContext<I, BC> + GmpQueryHandler<I, BC>,
-    > Iterator for FilterPresentWithDevices<I, Devices, Accessor, BC>
+        Accessor: IpDeviceStateContext<I, BT> + GmpQueryHandler<I, BT>,
+    > Iterator for FilterPresentWithDevices<I, Devices, Accessor, BT>
 where
-    <I as IpDeviceIpExt>::State<BC::Instant>: 's,
+    <I as IpDeviceIpExt>::State<BT>: 's,
 {
     type Item = (Accessor::DeviceId, I::AddressStatus);
     fn next(&mut self) -> Option<Self::Item> {
@@ -332,7 +348,7 @@
     }
 }
 
-impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpDeviceGmp<Ipv4>>>
+impl<BC: BindingsContext, L: LockBefore<crate::lock_ordering::IpState<Ipv4>>>
     ip::IpDeviceStateContext<Ipv4, BC> for CoreCtx<'_, BC, L>
 {
     fn with_next_packet_id<O, F: FnOnce(&AtomicU16) -> O>(&self, cb: F) -> O {
@@ -670,22 +686,6 @@
 {
     type DeviceId = <CoreCtx<'a, BC, L> as DeviceIdContext<AnyDevice>>::DeviceId;
     type WeakDeviceId = <CoreCtx<'a, BC, L> as DeviceIdContext<AnyDevice>>::WeakDeviceId;
-
-    fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-        let Self { config: _, core_ctx } = self;
-        <CoreCtx<'a, BC, L> as DeviceIdContext<AnyDevice>>::downgrade_device_id(core_ctx, device_id)
-    }
-
-    fn upgrade_weak_device_id(
-        &self,
-        weak_device_id: &Self::WeakDeviceId,
-    ) -> Option<Self::DeviceId> {
-        let Self { config: _, core_ctx } = self;
-        <CoreCtx<'a, BC, L> as DeviceIdContext<AnyDevice>>::upgrade_weak_device_id(
-            core_ctx,
-            weak_device_id,
-        )
-    }
 }
 
 impl<'a, Config: Borrow<Ipv6DeviceConfiguration>, BC: BindingsContext> SlaacContext<BC>
@@ -730,8 +730,7 @@
 
         let core_ctx = CoreCtxWithIpDeviceConfiguration { config, core_ctx: core_ctx.as_owned() };
 
-        let mut addrs =
-            SlaacAddrs { core_ctx, device_id: device_id.clone(), config, _marker: PhantomData };
+        let mut addrs = SlaacAddrs { core_ctx, device_id: device_id.clone(), config };
 
         cb(SlaacAddrsMutAndConfig {
             addrs: &mut addrs,
@@ -894,13 +893,7 @@
 {
     type LinkLayerAddr = <CoreCtx<'a, BC,  crate::lock_ordering::IpDeviceConfiguration<Ipv6>> as device::Ipv6DeviceContext<BC>>::LinkLayerAddr;
 
-    /// Calls the callback with a mutable reference to the remaining number of
-    /// router soliciations to send and the maximum number of router solications
-    /// to send.
-    fn with_rs_remaining_mut_and_max<
-        O,
-        F: FnOnce(&mut Option<NonZeroU8>, Option<NonZeroU8>) -> O,
-    >(
+    fn with_rs_state_mut_and_max<O, F: FnOnce(&mut RsState<BC>, Option<NonZeroU8>) -> O>(
         &mut self,
         device_id: &Self::DeviceId,
         cb: F,
@@ -912,8 +905,6 @@
         })
     }
 
-    /// Gets the device's link-layer address bytes, if the device supports
-    /// link-layer addressing.
     fn get_link_layer_addr_bytes(
         &mut self,
         device_id: &Self::DeviceId,
@@ -922,10 +913,6 @@
         device::Ipv6DeviceContext::get_link_layer_addr_bytes(core_ctx, device_id)
     }
 
-    /// Sends an NDP Router Solicitation to the local-link.
-    ///
-    /// The callback is called with a source address suitable for an outgoing
-    /// router solicitation message and returns the message body.
     fn send_rs_packet<
         S: Serializer<Buffer = EmptyBuf> + MaybeTransportPacket,
         F: FnOnce(Option<UnicastAddr<Ipv6Addr>>) -> S,
@@ -1040,12 +1027,13 @@
         CoreCtx<'b, BC, crate::lock_ordering::Ipv6DeviceRouteDiscovery>;
 
     fn with_discovered_routes_mut<
-        F: FnOnce(&mut Ipv6RouteDiscoveryState, &mut Self::WithDiscoveredRoutesMutCtx<'_>),
+        O,
+        F: FnOnce(&mut Ipv6RouteDiscoveryState<BC>, &mut Self::WithDiscoveredRoutesMutCtx<'_>) -> O,
     >(
         &mut self,
         device_id: &Self::DeviceId,
         cb: F,
-    ) {
+    ) -> O {
         let Self { config: _, core_ctx } = self;
         crate::device::integration::with_ip_device_state_and_core_ctx(
             core_ctx,
@@ -1191,12 +1179,11 @@
         device::IpDeviceStateContext::<I, BC>::get_address_id(core_ctx, device_id, addr)
     }
 
+    type AddressIdsIter<'b> =
+        <CoreCtx<'a, BC, L> as device::IpDeviceStateContext<I, BC>>::AddressIdsIter<'b>;
     fn with_address_ids<
         O,
-        F: FnOnce(
-            Box<dyn Iterator<Item = Self::AddressId> + '_>,
-            &mut Self::IpDeviceAddressCtx<'_>,
-        ) -> O,
+        F: FnOnce(Self::AddressIdsIter<'_>, &mut Self::IpDeviceAddressCtx<'_>) -> O,
     >(
         &mut self,
         device_id: &Self::DeviceId,
@@ -1408,6 +1395,63 @@
     }
 }
 
+impl<
+        'a,
+        I: IpExt,
+        Config,
+        BC: BindingsContext,
+        L: LockBefore<crate::lock_ordering::FilterState<I>>,
+    > FilterHandlerProvider<I, BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
+{
+    type Handler<'b> = FilterImpl<'b, CoreCtx<'a, BC, L>> where Self: 'b;
+
+    fn filter_handler(&mut self) -> Self::Handler<'_> {
+        let Self { config: _, core_ctx } = self;
+        FilterHandlerProvider::filter_handler(core_ctx)
+    }
+}
+
+#[netstack3_macros::instantiate_ip_impl_block(I)]
+impl<
+        'a,
+        I: IpLayerIpExt,
+        Config,
+        BC: BindingsContext,
+        L: LockBefore<crate::lock_ordering::IpState<I>>,
+    > ip::IpDeviceStateContext<I, BC> for CoreCtxWithIpDeviceConfiguration<'a, Config, L, BC>
+{
+    fn with_next_packet_id<O, F: FnOnce(&<I as IpLayerIpExt>::PacketIdState) -> O>(
+        &self,
+        cb: F,
+    ) -> O {
+        let Self { config: _, core_ctx } = self;
+        ip::IpDeviceStateContext::<I, _>::with_next_packet_id(core_ctx, cb)
+    }
+
+    fn get_local_addr_for_remote(
+        &mut self,
+        device_id: &Self::DeviceId,
+        remote: Option<SpecifiedAddr<<I as Ip>::Addr>>,
+    ) -> Option<IpDeviceAddr<<I as Ip>::Addr>> {
+        let Self { config: _, core_ctx } = self;
+        ip::IpDeviceStateContext::<I, _>::get_local_addr_for_remote(core_ctx, device_id, remote)
+    }
+
+    fn get_hop_limit(&mut self, device_id: &Self::DeviceId) -> NonZeroU8 {
+        let Self { config: _, core_ctx } = self;
+        ip::IpDeviceStateContext::<I, _>::get_hop_limit(core_ctx, device_id)
+    }
+
+    fn address_status_for_device(
+        &mut self,
+        dst_ip: SpecifiedAddr<<I as Ip>::Addr>,
+        device_id: &Self::DeviceId,
+    ) -> AddressStatus<<I as IpLayerIpExt>::AddressStatus> {
+        let Self { config: _, core_ctx } = self;
+        ip::IpDeviceStateContext::<I, _>::address_status_for_device(core_ctx, dst_ip, device_id)
+    }
+}
+
 impl<BC: BindingsContext, I: Ip> UnlockedAccess<crate::lock_ordering::NudCounters<I>>
     for StackState<BC>
 {
@@ -1424,3 +1468,11 @@
         cb(self.unlocked_access::<crate::lock_ordering::NudCounters<I>>())
     }
 }
+
+impl<I: IpDeviceIpExt, BT: BindingsTypes, L> CoreTimerContext<IpDeviceTimerId<I, DeviceId<BT>>, BT>
+    for CoreCtx<'_, BT, L>
+{
+    fn convert_timer(dispatch_id: IpDeviceTimerId<I, DeviceId<BT>>) -> BT::DispatchId {
+        dispatch_id.into()
+    }
+}
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/nud.rs b/src/connectivity/network/netstack3/core/src/ip/device/nud.rs
index a2dcc54..d0d6e98 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/nud.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/nud.rs
@@ -44,7 +44,7 @@
     device::{
         self,
         link::{LinkAddress, LinkDevice, LinkUnicastAddress},
-        AnyDevice, DeviceIdContext, StrongId,
+        AnyDevice, DeviceIdContext, StrongId, WeakId as _,
     },
     error::AddressResolutionFailed,
     socket::address::SocketIpAddr,
@@ -1929,7 +1929,7 @@
             CC::WeakDeviceId,
         >,
     ) {
-        let Some(device_id) = self.upgrade_weak_device_id(&device_id) else {
+        let Some(device_id) = device_id.upgrade() else {
             return;
         };
         match timer_type {
@@ -2591,7 +2591,6 @@
         ip::{AddrSubnet, IpAddress as _, IpInvariant, Ipv4Addr, Ipv6Addr, Subnet},
         UnicastAddr, Witness as _,
     };
-    use netstack3_base::testutil::LocalTimerHeapTestExt as _;
     use packet::{InnerPacketBuilder as _, Serializer as _};
     use packet_formats::{
         ethernet::{EtherType, EthernetFrameLengthCheck},
@@ -2715,18 +2714,6 @@
     impl<I: Ip> DeviceIdContext<FakeLinkDevice> for FakeCoreCtxImpl<I> {
         type DeviceId = FakeLinkDeviceId;
         type WeakDeviceId = FakeWeakDeviceId<FakeLinkDeviceId>;
-
-        fn downgrade_device_id(&self, device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-            FakeWeakDeviceId(device_id.clone())
-        }
-
-        fn upgrade_weak_device_id(
-            &self,
-            weak_device_id: &Self::WeakDeviceId,
-        ) -> Option<Self::DeviceId> {
-            let FakeWeakDeviceId(id) = weak_device_id;
-            Some(id.clone())
-        }
     }
 
     impl<I: Ip> NudContext<I, FakeLinkDevice, FakeBindingsCtxImpl<I>> for FakeCoreCtxImpl<I> {
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/route_discovery.rs b/src/connectivity/network/netstack3/core/src/ip/device/route_discovery.rs
index 32df375..3e10945 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/route_discovery.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/route_discovery.rs
@@ -16,18 +16,36 @@
 use packet_formats::icmp::ndp::NonZeroNdpLifetime;
 
 use crate::{
-    context::{TimerContext, TimerHandler},
-    device::{AnyDevice, DeviceIdContext},
+    context::{
+        CoreTimerContext, InstantBindingsTypes, TimerBindingsTypes, TimerContext2, TimerHandler,
+    },
+    device::{self, AnyDevice, DeviceIdContext, WeakId as _},
+    time::LocalTimerHeap,
 };
 
-#[derive(Default)]
-#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
-pub struct Ipv6RouteDiscoveryState {
+#[cfg_attr(test, derive(Debug))]
+pub struct Ipv6RouteDiscoveryState<BT: Ipv6RouteDiscoveryBindingsTypes> {
     // The valid (non-zero lifetime) discovered routes.
     //
     // Routes with a finite lifetime must have a timer set; routes with an
     // infinite lifetime must not.
     routes: HashSet<Ipv6DiscoveredRoute>,
+    timers: LocalTimerHeap<Ipv6DiscoveredRoute, (), BT>,
+}
+
+impl<BC: Ipv6RouteDiscoveryBindingsContext> Ipv6RouteDiscoveryState<BC> {
+    pub fn new<D: device::WeakId, CC: CoreTimerContext<Ipv6DiscoveredRouteTimerId<D>, BC>>(
+        bindings_ctx: &mut BC,
+        device_id: D,
+    ) -> Self {
+        Self {
+            routes: Default::default(),
+            timers: LocalTimerHeap::new_with_context::<_, CC>(
+                bindings_ctx,
+                Ipv6DiscoveredRouteTimerId { device_id },
+            ),
+        }
+    }
 }
 
 /// A discovered route.
@@ -44,15 +62,13 @@
 
 /// A timer ID for IPv6 route discovery.
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
-pub struct Ipv6DiscoveredRouteTimerId<DeviceId> {
-    device_id: DeviceId,
-    route: Ipv6DiscoveredRoute,
+pub struct Ipv6DiscoveredRouteTimerId<D: device::WeakId> {
+    device_id: D,
 }
 
-impl<DeviceId> Ipv6DiscoveredRouteTimerId<DeviceId> {
-    pub(super) fn device_id(&self) -> &DeviceId {
-        let Self { device_id, route: _ } = self;
-        device_id
+impl<D: device::WeakId> Ipv6DiscoveredRouteTimerId<D> {
+    pub(super) fn device_id(&self) -> &D {
+        &self.device_id
     }
 }
 
@@ -60,7 +76,7 @@
 /// route discovery state.
 ///
 /// See [`Ipv6RouteDiscoveryContext::with_discovered_routes_mut`].
-pub(super) trait Ipv6DiscoveredRoutesContext<BC>: DeviceIdContext<AnyDevice> {
+pub trait Ipv6DiscoveredRoutesContext<BC>: DeviceIdContext<AnyDevice> {
     /// Adds a newly discovered IPv6 route to the routing table.
     fn add_discovered_ipv6_route(
         &mut self,
@@ -80,26 +96,33 @@
 }
 
 /// The execution context for IPv6 route discovery.
-pub(super) trait Ipv6RouteDiscoveryContext<BC>: DeviceIdContext<AnyDevice> {
-    type WithDiscoveredRoutesMutCtx<'a>: Ipv6DiscoveredRoutesContext<BC, DeviceId = Self::DeviceId>;
+pub trait Ipv6RouteDiscoveryContext<BT: Ipv6RouteDiscoveryBindingsTypes>:
+    DeviceIdContext<AnyDevice>
+{
+    type WithDiscoveredRoutesMutCtx<'a>: Ipv6DiscoveredRoutesContext<BT, DeviceId = Self::DeviceId>;
 
     /// Gets the route discovery state, mutably.
     fn with_discovered_routes_mut<
-        F: FnOnce(&mut Ipv6RouteDiscoveryState, &mut Self::WithDiscoveredRoutesMutCtx<'_>),
+        O,
+        F: FnOnce(&mut Ipv6RouteDiscoveryState<BT>, &mut Self::WithDiscoveredRoutesMutCtx<'_>) -> O,
     >(
         &mut self,
         device_id: &Self::DeviceId,
         cb: F,
-    );
+    ) -> O;
 }
 
+/// The bindings types for IPv6 route discovery.
+pub trait Ipv6RouteDiscoveryBindingsTypes: TimerBindingsTypes + InstantBindingsTypes {}
+impl<BT> Ipv6RouteDiscoveryBindingsTypes for BT where BT: TimerBindingsTypes + InstantBindingsTypes {}
+
 /// The bindings execution context for IPv6 route discovery.
-trait Ipv6RouteDiscoveryBindingsContext<DeviceId>:
-    TimerContext<Ipv6DiscoveredRouteTimerId<DeviceId>>
+pub trait Ipv6RouteDiscoveryBindingsContext:
+    Ipv6RouteDiscoveryBindingsTypes + TimerContext2
 {
 }
-impl<DeviceId, BC: TimerContext<Ipv6DiscoveredRouteTimerId<DeviceId>>>
-    Ipv6RouteDiscoveryBindingsContext<DeviceId> for BC
+impl<BC> Ipv6RouteDiscoveryBindingsContext for BC where
+    BC: Ipv6RouteDiscoveryBindingsTypes + TimerContext2
 {
 }
 
@@ -123,7 +146,7 @@
     fn invalidate_routes(&mut self, bindings_ctx: &mut BC, device_id: &Self::DeviceId);
 }
 
-impl<BC: Ipv6RouteDiscoveryBindingsContext<CC::DeviceId>, CC: Ipv6RouteDiscoveryContext<BC>>
+impl<BC: Ipv6RouteDiscoveryBindingsContext, CC: Ipv6RouteDiscoveryContext<BC>>
     RouteDiscoveryHandler<BC> for CC
 {
     fn update_route(
@@ -133,84 +156,77 @@
         route: Ipv6DiscoveredRoute,
         lifetime: Option<NonZeroNdpLifetime>,
     ) {
-        self.with_discovered_routes_mut(
-            device_id,
-            |Ipv6RouteDiscoveryState { routes }, core_ctx| {
-                match lifetime {
-                    Some(lifetime) => {
-                        let newly_added = routes.insert(route.clone());
-                        if newly_added {
-                            match core_ctx.add_discovered_ipv6_route(bindings_ctx, device_id, route)
-                            {
-                                Ok(()) => (),
-                                Err(crate::error::ExistsError) => {
-                                    // If we fail to add the route to the route table,
-                                    // remove it from our table of discovered routes and
-                                    // do nothing further.
-                                    let _: bool = routes.remove(&route);
-                                    return;
-                                }
-                            }
-                        }
-
-                        let timer_id =
-                            Ipv6DiscoveredRouteTimerId { device_id: device_id.clone(), route };
-                        let prev_timer_fires_at: Option<BC::Instant> = match lifetime {
-                            NonZeroNdpLifetime::Finite(lifetime) => {
-                                bindings_ctx.schedule_timer(lifetime.get(), timer_id.clone())
-                            }
-                            // Routes with an infinite lifetime have no timers
-                            //
-                            // TODO(https://fxbug.dev/42180014): Hold timers scheduled to
-                            // fire at infinity.
-                            NonZeroNdpLifetime::Infinite => {
-                                bindings_ctx.cancel_timer(timer_id.clone())
-                            }
-                        };
-
-                        if newly_added {
-                            if let Some(prev_timer_fires_at) = prev_timer_fires_at {
-                                panic!(
-                                    "newly added timer ID {:?} should not have already been \
-                             scheduled to fire at {:?}",
-                                    timer_id, prev_timer_fires_at,
-                                )
+        self.with_discovered_routes_mut(device_id, |state, core_ctx| {
+            let Ipv6RouteDiscoveryState { routes, timers } = state;
+            match lifetime {
+                Some(lifetime) => {
+                    let newly_added = routes.insert(route.clone());
+                    if newly_added {
+                        match core_ctx.add_discovered_ipv6_route(bindings_ctx, device_id, route) {
+                            Ok(()) => (),
+                            Err(crate::error::ExistsError) => {
+                                // If we fail to add the route to the route table,
+                                // remove it from our table of discovered routes and
+                                // do nothing further.
+                                let _: bool = routes.remove(&route);
+                                return;
                             }
                         }
                     }
-                    None => {
-                        if routes.remove(&route) {
-                            invalidate_route(core_ctx, bindings_ctx, device_id, route);
+
+                    let prev_timer_fires_at = match lifetime {
+                        NonZeroNdpLifetime::Finite(lifetime) => {
+                            timers.schedule_after(bindings_ctx, route, (), lifetime.get())
+                        }
+                        // Routes with an infinite lifetime have no timers.
+                        NonZeroNdpLifetime::Infinite => timers.cancel(bindings_ctx, &route),
+                    };
+
+                    if newly_added {
+                        if let Some((prev_timer_fires_at, ())) = prev_timer_fires_at {
+                            panic!(
+                                "newly added route {:?} should not have already been \
+                                 scheduled to fire at {:?}",
+                                route, prev_timer_fires_at,
+                            )
                         }
                     }
                 }
-            },
-        )
+                None => {
+                    if routes.remove(&route) {
+                        invalidate_route(core_ctx, bindings_ctx, device_id, state, route);
+                    }
+                }
+            }
+        })
     }
 
     fn invalidate_routes(&mut self, bindings_ctx: &mut BC, device_id: &CC::DeviceId) {
-        self.with_discovered_routes_mut(
-            device_id,
-            |Ipv6RouteDiscoveryState { routes }, core_ctx| {
-                for route in core::mem::take(routes).into_iter() {
-                    invalidate_route(core_ctx, bindings_ctx, device_id, route);
-                }
-            },
-        )
+        self.with_discovered_routes_mut(device_id, |state, core_ctx| {
+            for route in core::mem::take(&mut state.routes).into_iter() {
+                invalidate_route(core_ctx, bindings_ctx, device_id, state, route);
+            }
+        })
     }
 }
 
-impl<BC: Ipv6RouteDiscoveryBindingsContext<CC::DeviceId>, CC: Ipv6RouteDiscoveryContext<BC>>
-    TimerHandler<BC, Ipv6DiscoveredRouteTimerId<CC::DeviceId>> for CC
+impl<BC: Ipv6RouteDiscoveryBindingsContext, CC: Ipv6RouteDiscoveryContext<BC>>
+    TimerHandler<BC, Ipv6DiscoveredRouteTimerId<CC::WeakDeviceId>> for CC
 {
     fn handle_timer(
         &mut self,
         bindings_ctx: &mut BC,
-        Ipv6DiscoveredRouteTimerId { device_id, route }: Ipv6DiscoveredRouteTimerId<CC::DeviceId>,
+        Ipv6DiscoveredRouteTimerId { device_id }: Ipv6DiscoveredRouteTimerId<CC::WeakDeviceId>,
     ) {
+        let Some(device_id) = device_id.upgrade() else {
+            return;
+        };
         self.with_discovered_routes_mut(
             &device_id,
-            |Ipv6RouteDiscoveryState { routes }, core_ctx| {
+            |Ipv6RouteDiscoveryState { routes, timers }, core_ctx| {
+                let Some((route, ())) = timers.pop(bindings_ctx) else {
+                    return;
+                };
                 assert!(routes.remove(&route), "invalidated route should be discovered");
                 del_discovered_ipv6_route(core_ctx, bindings_ctx, &device_id, route);
             },
@@ -219,7 +235,7 @@
 }
 
 fn del_discovered_ipv6_route<
-    BC: Ipv6RouteDiscoveryBindingsContext<CC::DeviceId>,
+    BC: Ipv6RouteDiscoveryBindingsContext,
     CC: Ipv6DiscoveredRoutesContext<BC>,
 >(
     core_ctx: &mut CC,
@@ -230,30 +246,26 @@
     core_ctx.del_discovered_ipv6_route(bindings_ctx, device_id, route);
 }
 
-fn invalidate_route<
-    BC: Ipv6RouteDiscoveryBindingsContext<CC::DeviceId>,
-    CC: Ipv6DiscoveredRoutesContext<BC>,
->(
+fn invalidate_route<BC: Ipv6RouteDiscoveryBindingsContext, CC: Ipv6DiscoveredRoutesContext<BC>>(
     core_ctx: &mut CC,
     bindings_ctx: &mut BC,
     device_id: &CC::DeviceId,
+    state: &mut Ipv6RouteDiscoveryState<BC>,
     route: Ipv6DiscoveredRoute,
 ) {
     // Routes with an infinite lifetime have no timers.
-    //
-    // TODO(https://fxbug.dev/42180014): Hold timers scheduled to fire at infinity.
-    let _: Option<BC::Instant> = bindings_ctx
-        .cancel_timer(Ipv6DiscoveredRouteTimerId { device_id: device_id.clone(), route });
+    let _: Option<(BC::Instant, ())> = state.timers.cancel(bindings_ctx, &route);
     del_discovered_ipv6_route(core_ctx, bindings_ctx, device_id, route)
 }
 
 #[cfg(test)]
 mod tests {
-    use alloc::vec::Vec;
+    use alloc::{collections::HashMap, vec::Vec};
     use core::{convert::TryInto as _, time::Duration};
 
     use assert_matches::assert_matches;
     use net_types::{ip::Ipv6, Witness as _};
+    use netstack3_base::IntoCoreTimerCtx;
     use packet::{BufferMut, InnerPacketBuilder as _, Serializer as _};
     use packet_formats::{
         icmp::{
@@ -280,8 +292,8 @@
         },
         ip::{
             device::{
-                IpDeviceConfigurationUpdate, IpDeviceEvent, Ipv6DeviceConfigurationUpdate,
-                Ipv6DeviceTimerId,
+                IpDeviceBindingsContext, IpDeviceConfigurationUpdate, IpDeviceEvent,
+                Ipv6DeviceConfigurationContext, Ipv6DeviceConfigurationUpdate,
             },
             testutil::FakeIpDeviceIdCtx,
             types::{AddableEntry, AddableEntryEither, AddableMetric, Entry, Metric},
@@ -291,8 +303,6 @@
             DispatchedEvent, FakeEventDispatcherConfig, TestIpExt as _, DEFAULT_INTERFACE_METRIC,
             IPV6_MIN_IMPLIED_MAX_FRAME_SIZE,
         },
-        time::TimerIdInner,
-        TimerId,
     };
 
     #[derive(Default)]
@@ -311,17 +321,6 @@
         type DeviceId = <FakeIpDeviceIdCtx<FakeDeviceId> as DeviceIdContext<AnyDevice>>::DeviceId;
         type WeakDeviceId =
             <FakeIpDeviceIdCtx<FakeDeviceId> as DeviceIdContext<AnyDevice>>::WeakDeviceId;
-
-        fn downgrade_device_id(&self, device_id: &FakeDeviceId) -> FakeWeakDeviceId<FakeDeviceId> {
-            self.ip_device_id_ctx.downgrade_device_id(device_id)
-        }
-
-        fn upgrade_weak_device_id(
-            &self,
-            device_id: &FakeWeakDeviceId<FakeDeviceId>,
-        ) -> Option<FakeDeviceId> {
-            self.ip_device_id_ctx.upgrade_weak_device_id(device_id)
-        }
     }
 
     impl<C> Ipv6DiscoveredRoutesContext<C> for FakeWithDiscoveredRoutesMutCtx {
@@ -351,9 +350,8 @@
         }
     }
 
-    #[derive(Default)]
     struct FakeIpv6RouteDiscoveryContext {
-        state: Ipv6RouteDiscoveryState,
+        state: Ipv6RouteDiscoveryState<FakeBindingsCtxImpl>,
         route_table: FakeWithDiscoveredRoutesMutCtx,
         ip_device_id_ctx: FakeIpDeviceIdCtx<FakeDeviceId>,
     }
@@ -366,19 +364,27 @@
 
     type FakeCoreCtxImpl = FakeCoreCtx<FakeIpv6RouteDiscoveryContext, (), FakeDeviceId>;
 
-    type FakeBindingsCtxImpl =
-        FakeBindingsCtx<Ipv6DiscoveredRouteTimerId<FakeDeviceId>, DispatchedEvent, (), ()>;
+    type FakeBindingsCtxImpl = FakeBindingsCtx<
+        Ipv6DiscoveredRouteTimerId<FakeWeakDeviceId<FakeDeviceId>>,
+        DispatchedEvent,
+        (),
+        (),
+    >;
 
     impl Ipv6RouteDiscoveryContext<FakeBindingsCtxImpl> for FakeCoreCtxImpl {
         type WithDiscoveredRoutesMutCtx<'a> = FakeWithDiscoveredRoutesMutCtx;
 
         fn with_discovered_routes_mut<
-            F: FnOnce(&mut Ipv6RouteDiscoveryState, &mut Self::WithDiscoveredRoutesMutCtx<'_>),
+            O,
+            F: FnOnce(
+                &mut Ipv6RouteDiscoveryState<FakeBindingsCtxImpl>,
+                &mut Self::WithDiscoveredRoutesMutCtx<'_>,
+            ) -> O,
         >(
             &mut self,
             &FakeDeviceId: &Self::DeviceId,
             cb: F,
-        ) {
+        ) -> O {
             let FakeIpv6RouteDiscoveryContext { state, route_table, ip_device_id_ctx: _ } =
                 self.get_mut();
             cb(state, route_table)
@@ -401,10 +407,22 @@
     const THREE_SECONDS: NonZeroDuration =
         const_unwrap::const_unwrap_option(NonZeroDuration::from_secs(3));
 
+    fn new_context() -> crate::testutil::ContextPair<FakeCoreCtxImpl, FakeBindingsCtxImpl> {
+        FakeCtx::with_default_bindings_ctx(|bindings_ctx| {
+            FakeCoreCtxImpl::with_state(FakeIpv6RouteDiscoveryContext {
+                state: Ipv6RouteDiscoveryState::new::<_, IntoCoreTimerCtx>(
+                    bindings_ctx,
+                    FakeWeakDeviceId(FakeDeviceId),
+                ),
+                route_table: Default::default(),
+                ip_device_id_ctx: Default::default(),
+            })
+        })
+    }
+
     #[test]
     fn new_route_no_lifetime() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         RouteDiscoveryHandler::update_route(
             &mut core_ctx,
@@ -433,13 +451,11 @@
         let route_table = &core_ctx.get_ref().route_table.route_table;
         assert!(route_table.contains(&route), "route_table={route_table:?}");
 
-        bindings_ctx.timer_ctx().assert_some_timers_installed(match duration {
-            NonZeroNdpLifetime::Finite(duration) => Some((
-                Ipv6DiscoveredRouteTimerId { device_id: FakeDeviceId, route },
-                FakeInstant::from(duration.get()),
-            )),
+        let expect = match duration {
+            NonZeroNdpLifetime::Finite(duration) => Some((FakeInstant::from(duration.get()), &())),
             NonZeroNdpLifetime::Infinite => None,
-        })
+        };
+        assert_eq!(core_ctx.state.state.timers.get(&route), expect);
     }
 
     fn trigger_next_timer(
@@ -447,9 +463,10 @@
         bindings_ctx: &mut FakeBindingsCtxImpl,
         route: Ipv6DiscoveredRoute,
     ) {
+        core_ctx.state.state.timers.assert_top(&route, &());
         assert_eq!(
             bindings_ctx.trigger_next_timer(core_ctx),
-            Some(Ipv6DiscoveredRouteTimerId { device_id: FakeDeviceId, route })
+            Some(Ipv6DiscoveredRouteTimerId { device_id: FakeWeakDeviceId(FakeDeviceId) })
         );
     }
 
@@ -474,8 +491,7 @@
 
     #[test]
     fn new_route_already_exists() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         // Fake the route already being present in the routing table.
         assert!(core_ctx.get_mut().route_table.route_table.insert(ROUTE1));
@@ -498,8 +514,7 @@
 
     #[test]
     fn invalidated_route_not_found() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         discover_new_route(&mut core_ctx, &mut bindings_ctx, ROUTE1, NonZeroNdpLifetime::Infinite);
 
@@ -513,8 +528,7 @@
 
     #[test]
     fn new_route_with_infinite_lifetime() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         discover_new_route(&mut core_ctx, &mut bindings_ctx, ROUTE1, NonZeroNdpLifetime::Infinite);
         bindings_ctx.timer_ctx().assert_no_timers_installed();
@@ -522,8 +536,7 @@
 
     #[test]
     fn update_route_from_infinite_to_finite_lifetime() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         discover_new_route(&mut core_ctx, &mut bindings_ctx, ROUTE1, NonZeroNdpLifetime::Infinite);
         bindings_ctx.timer_ctx().assert_no_timers_installed();
@@ -535,10 +548,10 @@
             ROUTE1,
             Some(NonZeroNdpLifetime::Finite(ONE_SECOND)),
         );
-        bindings_ctx.timer_ctx().assert_some_timers_installed([(
-            Ipv6DiscoveredRouteTimerId { device_id: FakeDeviceId, route: ROUTE1 },
-            FakeInstant::from(ONE_SECOND.get()),
-        )]);
+        assert_eq!(
+            core_ctx.state.state.timers.get(&ROUTE1),
+            Some((FakeInstant::from(ONE_SECOND.get()), &()))
+        );
         assert_single_invalidation_timer(&mut core_ctx, &mut bindings_ctx, ROUTE1);
     }
 
@@ -553,8 +566,7 @@
 
     #[test]
     fn invalidate_route_with_infinite_lifetime() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         discover_new_route(&mut core_ctx, &mut bindings_ctx, ROUTE1, NonZeroNdpLifetime::Infinite);
         bindings_ctx.timer_ctx().assert_no_timers_installed();
@@ -563,8 +575,7 @@
     }
     #[test]
     fn new_route_with_finite_lifetime() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         discover_new_route(
             &mut core_ctx,
@@ -577,8 +588,7 @@
 
     #[test]
     fn update_route_from_finite_to_infinite_lifetime() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         discover_new_route(
             &mut core_ctx,
@@ -599,8 +609,7 @@
 
     #[test]
     fn update_route_from_finite_to_finite_lifetime() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         discover_new_route(
             &mut core_ctx,
@@ -616,18 +625,16 @@
             ROUTE1,
             Some(NonZeroNdpLifetime::Finite(TWO_SECONDS)),
         );
-        bindings_ctx.timer_ctx().assert_timers_installed([(
-            Ipv6DiscoveredRouteTimerId { device_id: FakeDeviceId, route: ROUTE1 },
-            FakeInstant::from(TWO_SECONDS.get()),
-        )]);
-
+        assert_eq!(
+            core_ctx.state.state.timers.get(&ROUTE1),
+            Some((FakeInstant::from(TWO_SECONDS.get()), &()))
+        );
         assert_single_invalidation_timer(&mut core_ctx, &mut bindings_ctx, ROUTE1);
     }
 
     #[test]
     fn invalidate_route_with_finite_lifetime() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
 
         discover_new_route(
             &mut core_ctx,
@@ -641,8 +648,7 @@
 
     #[test]
     fn invalidate_all_routes() {
-        let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::default());
+        let FakeCtx { mut core_ctx, mut bindings_ctx } = new_context();
         discover_new_route(
             &mut core_ctx,
             &mut bindings_ctx,
@@ -755,7 +761,7 @@
             )
             .unwrap();
 
-        ctx.bindings_ctx.timer_ctx().assert_no_timers_installed();
+        assert_timers_integration(&mut ctx.core_ctx(), &device_id, []);
 
         (ctx, device_id, Ipv6::FAKE_CONFIG)
     }
@@ -764,16 +770,6 @@
         d.get().as_secs().try_into().unwrap()
     }
 
-    fn timer_id(
-        route: Ipv6DiscoveredRoute,
-        device_id: DeviceId<crate::testutil::FakeBindingsCtx>,
-    ) -> TimerId<crate::testutil::FakeBindingsCtx> {
-        TimerId(TimerIdInner::Ipv6Device(
-            Ipv6DeviceTimerId::RouteDiscovery(Ipv6DiscoveredRouteTimerId { device_id, route })
-                .into(),
-        ))
-    }
-
     const LINK_LOCAL_SUBNET: Subnet<Ipv6Addr> = net_declare::net_subnet_v6!("fe80::/64");
 
     fn add_link_local_route(
@@ -801,6 +797,25 @@
         }
     }
 
+    // Assert internal timers in integration tests by going through the contexts
+    // to get the state.
+    #[track_caller]
+    fn assert_timers_integration<CC, BC, I>(core_ctx: &mut CC, device_id: &CC::DeviceId, timers: I)
+    where
+        CC: Ipv6DeviceConfigurationContext<BC>,
+        for<'a> CC::Ipv6DeviceStateCtx<'a>: Ipv6RouteDiscoveryContext<BC>,
+        BC: IpDeviceBindingsContext<Ipv6, CC::DeviceId> + Ipv6RouteDiscoveryBindingsContext,
+        I: IntoIterator<Item = (Ipv6DiscoveredRoute, BC::Instant)>,
+    {
+        let want = timers.into_iter().collect::<HashMap<_, _>>();
+        let got = core_ctx.with_ipv6_device_configuration(device_id, |_, mut core_ctx| {
+            core_ctx.with_discovered_routes_mut(device_id, |state, _| {
+                state.timers.iter().map(|(k, (), t)| (*k, *t)).collect::<HashMap<_, _>>()
+            })
+        });
+        assert_eq!(got, want);
+    }
+
     #[test]
     fn discovery_integration() {
         let (
@@ -833,8 +848,6 @@
             )
         };
 
-        let timer_id = |route| timer_id(route, device_id.clone());
-
         // Clear events so we can assert on route-added events later.
         let _: Vec<crate::testutil::DispatchedEvent> = ctx.bindings_ctx.take_events();
 
@@ -845,7 +858,7 @@
             Some(FrameDestination::Individual { local: true }),
             buf(0, false, as_secs(ONE_SECOND).into(), 0),
         );
-        ctx.bindings_ctx.timer_ctx().assert_no_timers_installed();
+        assert_timers_integration(&mut ctx.core_ctx(), &device_id, []);
 
         // Discover a default router only as on-link prefix has no valid
         // lifetime.
@@ -856,10 +869,11 @@
         );
         let gateway_route =
             Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) };
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([(
-            timer_id(gateway_route),
-            FakeInstant::from(ONE_SECOND.get()),
-        )]);
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [(gateway_route, FakeInstant::from(ONE_SECOND.get()))],
+        );
 
         let gateway_route_entry = discovered_route_to_entry(&device_id, gateway_route);
         assert_eq!(
@@ -878,11 +892,15 @@
         );
         let on_link_route = Ipv6DiscoveredRoute { subnet, gateway: None };
         let on_link_route_entry = discovered_route_to_entry(&device_id, on_link_route);
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([
-            (timer_id(gateway_route), FakeInstant::from(TWO_SECONDS.get())),
-            (timer_id(on_link_route), FakeInstant::from(ONE_SECOND.get())),
-        ]);
 
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [
+                (gateway_route, FakeInstant::from(TWO_SECONDS.get())),
+                (on_link_route, FakeInstant::from(ONE_SECOND.get())),
+            ],
+        );
         assert_eq!(
             ctx.bindings_ctx.take_events(),
             [crate::testutil::DispatchedEvent::IpLayerIpv6(IpLayerEvent::AddRoute(
@@ -903,11 +921,15 @@
         );
         let more_specific_route = Ipv6DiscoveredRoute { subnet, gateway: Some(src_ip) };
         let more_specific_route_entry = discovered_route_to_entry(&device_id, more_specific_route);
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([
-            (timer_id(gateway_route), FakeInstant::from(TWO_SECONDS.get())),
-            (timer_id(on_link_route), FakeInstant::from(ONE_SECOND.get())),
-            (timer_id(more_specific_route), FakeInstant::from(THREE_SECONDS.get())),
-        ]);
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [
+                (gateway_route, FakeInstant::from(TWO_SECONDS.get())),
+                (on_link_route, FakeInstant::from(ONE_SECOND.get())),
+                (more_specific_route, FakeInstant::from(THREE_SECONDS.get())),
+            ],
+        );
 
         assert_eq!(
             ctx.bindings_ctx.take_events(),
@@ -923,10 +945,11 @@
             Some(FrameDestination::Individual { local: true }),
             buf(0, true, as_secs(TWO_SECONDS).into(), 0),
         );
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([(
-            timer_id(on_link_route),
-            FakeInstant::from(TWO_SECONDS.get()),
-        )]);
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [(on_link_route, FakeInstant::from(TWO_SECONDS.get()))],
+        );
         {
             let crate::ip::types::Entry { subnet, device, gateway, metric: _ } =
                 gateway_route_entry;
@@ -947,10 +970,11 @@
             Some(FrameDestination::Individual { local: true }),
             buf(0, false, 0, 0),
         );
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([(
-            timer_id(on_link_route),
-            FakeInstant::from(TWO_SECONDS.get()),
-        )]);
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [(on_link_route, FakeInstant::from(TWO_SECONDS.get()))],
+        );
         assert_eq!(ctx.bindings_ctx.take_events(), []);
 
         // Invalidate on-link prefix.
@@ -959,7 +983,7 @@
             Some(FrameDestination::Individual { local: true }),
             buf(0, true, 0, 0),
         );
-        ctx.bindings_ctx.timer_ctx().assert_no_timers_installed();
+        assert_timers_integration(&mut ctx.core_ctx(), &device_id, []);
         {
             let crate::ip::types::Entry { subnet, device, gateway, metric: _ } =
                 on_link_route_entry;
@@ -1003,8 +1027,6 @@
             )
         };
 
-        let timer_id = |route| timer_id(route, device_id.clone());
-
         let gateway_route =
             Ipv6DiscoveredRoute { subnet: IPV6_DEFAULT_SUBNET, gateway: Some(src_ip) };
         let gateway_route_entry = discovered_route_to_entry(&device_id, gateway_route);
@@ -1023,10 +1045,11 @@
             Some(FrameDestination::Individual { local: true }),
             buf(router_lifetime_secs, true, prefix_lifetime_secs),
         );
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([(
-            timer_id(gateway_route),
-            FakeInstant::from(Duration::from_secs(router_lifetime_secs.into())),
-        )]);
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [(gateway_route, FakeInstant::from(Duration::from_secs(router_lifetime_secs.into())))],
+        );
         assert_eq!(
             ctx.bindings_ctx.take_events(),
             [
@@ -1047,16 +1070,20 @@
             Some(FrameDestination::Individual { local: true }),
             buf(router_lifetime_secs, true, prefix_lifetime_secs),
         );
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([
-            (
-                timer_id(gateway_route),
-                FakeInstant::from(Duration::from_secs(router_lifetime_secs.into())),
-            ),
-            (
-                timer_id(on_link_route),
-                FakeInstant::from(Duration::from_secs(prefix_lifetime_secs.into())),
-            ),
-        ]);
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [
+                (
+                    gateway_route,
+                    FakeInstant::from(Duration::from_secs(router_lifetime_secs.into())),
+                ),
+                (
+                    on_link_route,
+                    FakeInstant::from(Duration::from_secs(prefix_lifetime_secs.into())),
+                ),
+            ],
+        );
         assert_eq!(ctx.bindings_ctx.take_events(), []);
 
         // Router with finite lifetime and on-link prefix with infinite
@@ -1068,10 +1095,11 @@
             Some(FrameDestination::Individual { local: true }),
             buf(router_lifetime_secs, true, prefix_lifetime_secs),
         );
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([(
-            timer_id(gateway_route),
-            FakeInstant::from(Duration::from_secs(router_lifetime_secs.into())),
-        )]);
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [(gateway_route, FakeInstant::from(Duration::from_secs(router_lifetime_secs.into())))],
+        );
         assert_eq!(ctx.bindings_ctx.take_events(), []);
 
         // Router and prefix invalidated.
@@ -1082,7 +1110,7 @@
             Some(FrameDestination::Individual { local: true }),
             buf(router_lifetime_secs, true, prefix_lifetime_secs),
         );
-        ctx.bindings_ctx.timer_ctx().assert_no_timers_installed();
+        assert_timers_integration(&mut ctx.core_ctx(), &device_id, []);
 
         {
             let crate::ip::types::Entry { subnet, device, gateway, metric: _ } =
@@ -1126,8 +1154,6 @@
         // Clear events so we can assert on route-added events later.
         let _: Vec<crate::testutil::DispatchedEvent> = ctx.bindings_ctx.take_events();
 
-        let timer_id = |route| timer_id(route, device_id.clone());
-
         // Discover both an on-link prefix and default router.
         ctx.test_api().receive_ip_packet::<Ipv6, _>(
             &device_id,
@@ -1141,10 +1167,14 @@
                 None,
             ),
         );
-        ctx.bindings_ctx.timer_ctx().assert_timers_installed([
-            (timer_id(gateway_route), FakeInstant::from(TWO_SECONDS.get())),
-            (timer_id(on_link_route), FakeInstant::from(ONE_SECOND.get())),
-        ]);
+        assert_timers_integration(
+            &mut ctx.core_ctx(),
+            &device_id,
+            [
+                (gateway_route, FakeInstant::from(TWO_SECONDS.get())),
+                (on_link_route, FakeInstant::from(ONE_SECOND.get())),
+            ],
+        );
         assert_eq!(
             ctx.bindings_ctx.take_events(),
             [
@@ -1172,7 +1202,7 @@
                 },
             )
             .unwrap();
-        ctx.bindings_ctx.timer_ctx().assert_no_timers_installed();
+        assert_timers_integration(&mut ctx.core_ctx(), &device_id, []);
 
         {
             let crate::ip::types::Entry { subnet, device, gateway, metric: _ } =
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/router_solicitation.rs b/src/connectivity/network/netstack3/core/src/ip/device/router_solicitation.rs
index bde3da1..395bf92 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/router_solicitation.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/router_solicitation.rs
@@ -16,8 +16,8 @@
 use rand::Rng as _;
 
 use crate::{
-    context::{RngContext, TimerContext, TimerHandler},
-    device::{AnyDevice, DeviceIdContext},
+    context::{CoreTimerContext, RngContext, TimerBindingsTypes, TimerContext2, TimerHandler},
+    device::{self, AnyDevice, DeviceIdContext, WeakId as _},
     filter::MaybeTransportPacket,
 };
 
@@ -44,39 +44,58 @@
 pub(crate) const RTR_SOLICITATION_INTERVAL: Duration = Duration::from_secs(4);
 
 #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
-pub struct RsTimerId<DeviceId> {
-    pub(crate) device_id: DeviceId,
+pub struct RsTimerId<D: device::WeakId> {
+    device_id: D,
 }
 
-impl<DeviceId> RsTimerId<DeviceId> {
-    pub(super) fn device_id(&self) -> &DeviceId {
+impl<D: device::WeakId> RsTimerId<D> {
+    pub(super) fn device_id(&self) -> &D {
         let Self { device_id } = self;
         device_id
     }
+
+    #[cfg(test)]
+    pub(crate) fn new(device_id: D) -> Self {
+        Self { device_id }
+    }
+}
+
+/// A device's router solicitation state.
+pub struct RsState<BT: RsBindingsTypes> {
+    remaining: Option<NonZeroU8>,
+    timer: BT::Timer,
+}
+
+impl<BC: RsBindingsTypes + TimerContext2> RsState<BC> {
+    pub fn new<D: device::WeakId, CC: CoreTimerContext<RsTimerId<D>, BC>>(
+        bindings_ctx: &mut BC,
+        device_id: D,
+    ) -> Self {
+        Self { remaining: None, timer: CC::new_timer(bindings_ctx, RsTimerId { device_id }) }
+    }
 }
 
 /// The execution context for router solicitation.
-pub(super) trait RsContext<BC>: DeviceIdContext<AnyDevice> {
+pub(super) trait RsContext<BC: RsBindingsTypes>: DeviceIdContext<AnyDevice> {
     /// A link-layer address.
     type LinkLayerAddr: AsRef<[u8]>;
 
-    /// Calls the callback with a mutable reference to the remaining number of
-    /// router soliciations to send and the maximum number of router solications
-    /// to send.
-    fn with_rs_remaining_mut_and_max<O, F: FnOnce(&mut Option<NonZeroU8>, Option<NonZeroU8>) -> O>(
+    /// Calls the callback with a mutable reference to the router solicitation
+    /// state and the maximum number of router solications to send.
+    fn with_rs_state_mut_and_max<O, F: FnOnce(&mut RsState<BC>, Option<NonZeroU8>) -> O>(
         &mut self,
         device_id: &Self::DeviceId,
         cb: F,
     ) -> O;
 
-    /// Calls the callback with a mutable reference to the remaining number of
-    /// router soliciations to send.
-    fn with_rs_remaining_mut<F: FnOnce(&mut Option<NonZeroU8>)>(
+    /// Calls the callback with a mutable reference to the router solicitation
+    /// state.
+    fn with_rs_state_mut<F: FnOnce(&mut RsState<BC>)>(
         &mut self,
         device_id: &Self::DeviceId,
         cb: F,
     ) {
-        self.with_rs_remaining_mut_and_max(device_id, |remaining, _max| cb(remaining))
+        self.with_rs_state_mut_and_max(device_id, |state, _max| cb(state))
     }
 
     /// Gets the device's link-layer address bytes, if the device supports
@@ -102,19 +121,17 @@
     ) -> Result<(), S>;
 }
 
+/// The bindings types for router solicitation.
+pub trait RsBindingsTypes: TimerBindingsTypes {}
+impl<BT> RsBindingsTypes for BT where BT: TimerBindingsTypes {}
+
 /// The bindings execution context for router solicitation.
-pub(super) trait RsBindingsContext<DeviceId>:
-    RngContext + TimerContext<RsTimerId<DeviceId>>
-{
-}
-impl<DeviceId, BC: RngContext + TimerContext<RsTimerId<DeviceId>>> RsBindingsContext<DeviceId>
-    for BC
-{
-}
+pub trait RsBindingsContext: RngContext + TimerContext2 {}
+impl<BC> RsBindingsContext for BC where BC: RngContext + TimerContext2 {}
 
 /// An implementation of Router Solicitation.
 pub trait RsHandler<BC>:
-    DeviceIdContext<AnyDevice> + TimerHandler<BC, RsTimerId<Self::DeviceId>>
+    DeviceIdContext<AnyDevice> + TimerHandler<BC, RsTimerId<Self::WeakDeviceId>>
 {
     /// Starts router solicitation.
     fn start_router_solicitation(&mut self, bindings_ctx: &mut BC, device_id: &Self::DeviceId);
@@ -125,50 +142,51 @@
     fn stop_router_solicitation(&mut self, bindings_ctx: &mut BC, device_id: &Self::DeviceId);
 }
 
-impl<BC: RsBindingsContext<CC::DeviceId>, CC: RsContext<BC>> RsHandler<BC> for CC {
+impl<BC: RsBindingsContext, CC: RsContext<BC>> RsHandler<BC> for CC {
     fn start_router_solicitation(&mut self, bindings_ctx: &mut BC, device_id: &Self::DeviceId) {
-        let remaining = self.with_rs_remaining_mut_and_max(device_id, |remaining, max| {
+        self.with_rs_state_mut_and_max(device_id, |state, max| {
+            let RsState { remaining, timer } = state;
             *remaining = max;
-            max
-        });
 
-        match remaining {
-            None => {}
-            Some(_) => {
-                // As per RFC 4861 section 6.3.7, delay the first transmission for a
-                // random amount of time between 0 and `MAX_RTR_SOLICITATION_DELAY` to
-                // alleviate congestion when many hosts start up on a link at the same
-                // time.
-                let delay =
-                    bindings_ctx.rng().gen_range(Duration::new(0, 0)..MAX_RTR_SOLICITATION_DELAY);
-                assert_eq!(
-                    bindings_ctx.schedule_timer(delay, RsTimerId { device_id: device_id.clone() },),
-                    None
-                );
+            match remaining {
+                None => {}
+                Some(_) => {
+                    // As per RFC 4861 section 6.3.7, delay the first transmission for a
+                    // random amount of time between 0 and `MAX_RTR_SOLICITATION_DELAY` to
+                    // alleviate congestion when many hosts start up on a link at the same
+                    // time.
+                    let delay = bindings_ctx
+                        .rng()
+                        .gen_range(Duration::new(0, 0)..MAX_RTR_SOLICITATION_DELAY);
+                    assert_eq!(bindings_ctx.schedule_timer2(delay, timer), None);
+                }
             }
-        }
+        });
     }
 
     fn stop_router_solicitation(&mut self, bindings_ctx: &mut BC, device_id: &Self::DeviceId) {
-        let _: Option<BC::Instant> =
-            bindings_ctx.cancel_timer(RsTimerId { device_id: device_id.clone() });
+        self.with_rs_state_mut(device_id, |state| {
+            let _: Option<BC::Instant> = bindings_ctx.cancel_timer2(&mut state.timer);
+        });
     }
 }
 
-impl<BC: RsBindingsContext<CC::DeviceId>, CC: RsContext<BC>>
-    TimerHandler<BC, RsTimerId<CC::DeviceId>> for CC
+impl<BC: RsBindingsContext, CC: RsContext<BC>> TimerHandler<BC, RsTimerId<CC::WeakDeviceId>>
+    for CC
 {
     fn handle_timer(
         &mut self,
         bindings_ctx: &mut BC,
-        RsTimerId { device_id }: RsTimerId<CC::DeviceId>,
+        RsTimerId { device_id }: RsTimerId<CC::WeakDeviceId>,
     ) {
-        do_router_solicitation(self, bindings_ctx, &device_id)
+        if let Some(device_id) = device_id.upgrade() {
+            do_router_solicitation(self, bindings_ctx, &device_id)
+        }
     }
 }
 
 /// Solicit routers once and schedule next message.
-fn do_router_solicitation<BC: RsBindingsContext<CC::DeviceId>, CC: RsContext<BC>>(
+fn do_router_solicitation<BC: RsBindingsContext, CC: RsContext<BC>>(
     core_ctx: &mut CC,
     bindings_ctx: &mut BC,
     device_id: &CC::DeviceId,
@@ -202,7 +220,7 @@
             })
         });
 
-    core_ctx.with_rs_remaining_mut(device_id, |remaining| {
+    core_ctx.with_rs_state_mut(device_id, |RsState { remaining, timer }| {
         *remaining = NonZeroU8::new(
             remaining
                 .expect("should only send a router solicitations when at least one is remaining")
@@ -213,13 +231,7 @@
         match *remaining {
             None => {}
             Some(NonZeroU8 { .. }) => {
-                assert_eq!(
-                    bindings_ctx.schedule_timer(
-                        RTR_SOLICITATION_INTERVAL,
-                        RsTimerId { device_id: device_id.clone() },
-                    ),
-                    None
-                );
+                assert_eq!(bindings_ctx.schedule_timer2(RTR_SOLICITATION_INTERVAL, timer), None);
             }
         }
     });
@@ -230,6 +242,7 @@
     use alloc::{vec, vec::Vec};
 
     use net_declare::net_ip_v6;
+    use netstack3_base::IntoCoreTimerCtx;
     use packet_formats::icmp::ndp::{options::NdpOption, Options};
     use test_case::test_case;
 
@@ -239,13 +252,13 @@
             testutil::{FakeBindingsCtx, FakeCoreCtx, FakeCtx, FakeTimerCtxExt as _},
             InstantContext as _, SendFrameContext as _,
         },
-        device::testutil::FakeDeviceId,
+        device::testutil::{FakeDeviceId, FakeWeakDeviceId},
         ip::testutil::FakeIpDeviceIdCtx,
     };
 
     struct FakeRsContext {
         max_router_solicitations: Option<NonZeroU8>,
-        router_soliciations_remaining: Option<NonZeroU8>,
+        rs_state: RsState<FakeBindingsCtxImpl>,
         source_address: Option<UnicastAddr<Ipv6Addr>>,
         link_layer_bytes: Option<Vec<u8>>,
         ip_device_id_ctx: FakeIpDeviceIdCtx<FakeDeviceId>,
@@ -263,37 +276,26 @@
     }
 
     type FakeCoreCtxImpl = FakeCoreCtx<FakeRsContext, RsMessageMeta, FakeDeviceId>;
-    type FakeBindingsCtxImpl = FakeBindingsCtx<RsTimerId<FakeDeviceId>, (), (), ()>;
+    type FakeBindingsCtxImpl =
+        FakeBindingsCtx<RsTimerId<FakeWeakDeviceId<FakeDeviceId>>, (), (), ()>;
 
     impl RsContext<FakeBindingsCtxImpl> for FakeCoreCtxImpl {
         type LinkLayerAddr = Vec<u8>;
 
-        fn with_rs_remaining_mut_and_max<
+        fn with_rs_state_mut_and_max<
             O,
-            F: FnOnce(&mut Option<NonZeroU8>, Option<NonZeroU8>) -> O,
+            F: FnOnce(&mut RsState<FakeBindingsCtxImpl>, Option<NonZeroU8>) -> O,
         >(
             &mut self,
             &FakeDeviceId: &FakeDeviceId,
             cb: F,
         ) -> O {
-            let FakeRsContext {
-                max_router_solicitations,
-                router_soliciations_remaining,
-                source_address: _,
-                link_layer_bytes: _,
-                ip_device_id_ctx: _,
-            } = self.get_mut();
-            cb(router_soliciations_remaining, *max_router_solicitations)
+            let FakeRsContext { max_router_solicitations, rs_state, .. } = self.get_mut();
+            cb(rs_state, *max_router_solicitations)
         }
 
         fn get_link_layer_addr_bytes(&mut self, &FakeDeviceId: &FakeDeviceId) -> Option<Vec<u8>> {
-            let FakeRsContext {
-                max_router_solicitations: _,
-                router_soliciations_remaining: _,
-                source_address: _,
-                link_layer_bytes,
-                ip_device_id_ctx: _,
-            } = self.get_ref();
+            let FakeRsContext { link_layer_bytes, .. } = self.get_ref();
             link_layer_bytes.clone()
         }
 
@@ -307,29 +309,29 @@
             message: RouterSolicitation,
             body: F,
         ) -> Result<(), S> {
-            let FakeRsContext {
-                max_router_solicitations: _,
-                router_soliciations_remaining: _,
-                source_address,
-                link_layer_bytes: _,
-                ip_device_id_ctx: _,
-            } = self.get_ref();
+            let FakeRsContext { source_address, .. } = self.get_ref();
             self.send_frame(bindings_ctx, RsMessageMeta { message }, body(*source_address))
         }
     }
 
-    const RS_TIMER_ID: RsTimerId<FakeDeviceId> = RsTimerId { device_id: FakeDeviceId };
+    const RS_TIMER_ID: RsTimerId<FakeWeakDeviceId<FakeDeviceId>> =
+        RsTimerId { device_id: FakeWeakDeviceId(FakeDeviceId) };
 
     #[test]
     fn stop_router_solicitation() {
         let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::with_state(FakeRsContext {
-                max_router_solicitations: NonZeroU8::new(1),
-                router_soliciations_remaining: None,
-                source_address: None,
-                link_layer_bytes: None,
-                ip_device_id_ctx: Default::default(),
-            }));
+            FakeCtx::with_default_bindings_ctx(|bindings_ctx| {
+                FakeCoreCtxImpl::with_state(FakeRsContext {
+                    max_router_solicitations: NonZeroU8::new(1),
+                    rs_state: RsState::new::<_, IntoCoreTimerCtx>(
+                        bindings_ctx,
+                        FakeWeakDeviceId(FakeDeviceId),
+                    ),
+                    source_address: None,
+                    link_layer_bytes: None,
+                    ip_device_id_ctx: Default::default(),
+                })
+            });
         RsHandler::start_router_solicitation(&mut core_ctx, &mut bindings_ctx, &FakeDeviceId);
 
         let now = bindings_ctx.now();
@@ -383,13 +385,18 @@
         expected_sll_bytes: Option<&[u8]>,
     ) {
         let FakeCtx { mut core_ctx, mut bindings_ctx } =
-            FakeCtx::with_core_ctx(FakeCoreCtxImpl::with_state(FakeRsContext {
-                max_router_solicitations: NonZeroU8::new(max_router_solicitations),
-                router_soliciations_remaining: None,
-                source_address,
-                link_layer_bytes,
-                ip_device_id_ctx: Default::default(),
-            }));
+            FakeCtx::with_default_bindings_ctx(|bindings_ctx| {
+                FakeCoreCtxImpl::with_state(FakeRsContext {
+                    max_router_solicitations: NonZeroU8::new(max_router_solicitations),
+                    rs_state: RsState::new::<_, IntoCoreTimerCtx>(
+                        bindings_ctx,
+                        FakeWeakDeviceId(FakeDeviceId),
+                    ),
+                    source_address,
+                    link_layer_bytes,
+                    ip_device_id_ctx: Default::default(),
+                })
+            });
         RsHandler::start_router_solicitation(&mut core_ctx, &mut bindings_ctx, &FakeDeviceId);
 
         assert_eq!(core_ctx.frames(), &[][..]);
@@ -397,7 +404,7 @@
         let mut duration = MAX_RTR_SOLICITATION_DELAY;
         for i in 0..max_router_solicitations {
             assert_eq!(
-                core_ctx.get_ref().router_soliciations_remaining,
+                core_ctx.get_ref().rs_state.remaining,
                 NonZeroU8::new(max_router_solicitations - i)
             );
             let now = bindings_ctx.now();
@@ -422,7 +429,7 @@
         }
 
         bindings_ctx.timer_ctx().assert_no_timers_installed();
-        assert_eq!(core_ctx.get_ref().router_soliciations_remaining, None);
+        assert_eq!(core_ctx.get_ref().rs_state.remaining, None);
         let frames = core_ctx.frames();
         assert_eq!(frames.len(), usize::from(max_router_solicitations), "frames = {:?}", frames);
     }
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/slaac.rs b/src/connectivity/network/netstack3/core/src/ip/device/slaac.rs
index 72b6c6b..b2b0ec4 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/slaac.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/slaac.rs
@@ -8,7 +8,7 @@
 //! [RFC 4862]: https://datatracker.ietf.org/doc/html/rfc4862
 //! [RFC 8981]: https://datatracker.ietf.org/doc/html/rfc8981
 
-use alloc::{boxed::Box, vec::Vec};
+use alloc::vec::Vec;
 use core::{marker::PhantomData, num::NonZeroU16, ops::ControlFlow, time::Duration};
 
 use assert_matches::assert_matches;
@@ -105,7 +105,7 @@
 
 /// The state associated with a SLAAC address.
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub(super) struct SlaacAddressEntry<Instant> {
+pub struct SlaacAddressEntry<Instant> {
     pub(super) addr_sub: AddrSubnet<Ipv6Addr, Ipv6DeviceAddr>,
     pub(super) config: SlaacConfig<Instant>,
     pub(super) deprecated: bool,
@@ -123,14 +123,11 @@
     /// state.
     fn for_each_addr_mut<F: FnMut(SlaacAddressEntryMut<'_, BC::Instant>)>(&mut self, cb: F);
 
-    /// Returns an iterator over the SLAAC addresses.
-    fn with_addrs<
-        O,
-        F: FnOnce(Box<dyn Iterator<Item = SlaacAddressEntry<BC::Instant>> + '_>) -> O,
-    >(
-        &mut self,
-        cb: F,
-    ) -> O;
+    /// The iterator provided to `with_addrs`.
+    type AddrsIter<'x>: Iterator<Item = SlaacAddressEntry<BC::Instant>>;
+
+    /// Calls the callback with an iterator over the addresses.
+    fn with_addrs<O, F: FnOnce(Self::AddrsIter<'_>) -> O>(&mut self, cb: F) -> O;
 
     fn add_addr_sub_and_then<O, F: FnOnce(SlaacAddressEntryMut<'_, BC::Instant>, &mut BC) -> O>(
         &mut self,
@@ -1737,15 +1734,11 @@
             })
         }
 
-        fn with_addrs<
-            O,
-            F: FnOnce(Box<dyn Iterator<Item = SlaacAddressEntry<FakeInstant>> + '_>) -> O,
-        >(
-            &mut self,
-            cb: F,
-        ) -> O {
+        type AddrsIter<'b> =
+            core::iter::Cloned<core::slice::Iter<'b, SlaacAddressEntry<FakeInstant>>>;
+        fn with_addrs<O, F: FnOnce(Self::AddrsIter<'_>) -> O>(&mut self, cb: F) -> O {
             let FakeSlaacAddrs { slaac_addrs, non_slaac_addr: _, counters: _ } = self;
-            cb(Box::new(slaac_addrs.iter().cloned()))
+            cb(slaac_addrs.iter().cloned())
         }
 
         fn add_addr_sub_and_then<
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/state.rs b/src/connectivity/network/netstack3/core/src/ip/device/state.rs
index 0580cf2..16c7669 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/state.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/state.rs
@@ -22,12 +22,17 @@
 use packet_formats::utils::NonZeroDuration;
 
 use crate::{
-    context::InstantBindingsTypes,
+    context::{
+        CoreTimerContext, InstantBindingsTypes, NestedIntoCoreTimerCtx, TimerBindingsTypes,
+        TimerContext2,
+    },
+    device,
     inspect::{Inspectable, InspectableValue, Inspector},
     ip::{
         device::{
-            route_discovery::Ipv6RouteDiscoveryState, slaac::SlaacConfiguration, IpAddressId,
-            IpDeviceAddr, Ipv6DeviceAddr,
+            route_discovery::Ipv6RouteDiscoveryState, router_solicitation::RsState,
+            slaac::SlaacConfiguration, IpAddressId, IpDeviceAddr, IpDeviceTimerId, Ipv6DeviceAddr,
+            Ipv6DeviceTimerId,
         },
         gmp::{igmp::IgmpGroupState, mld::MldGroupState, MulticastGroupSet},
         types::{IpTypesIpExt, RawMetric},
@@ -120,17 +125,17 @@
 #[derive(GenericOverIp)]
 #[generic_over_ip(I, Ip)]
 #[cfg_attr(test, derive(Debug))]
-pub struct IpDeviceState<Instant: crate::Instant, I: IpDeviceStateIpExt> {
+pub struct IpDeviceState<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> {
     /// IP addresses assigned to this device.
     ///
     /// IPv6 addresses may be tentative (performing NDP's Duplicate Address
     /// Detection).
     ///
     /// Does not contain any duplicates.
-    pub addrs: RwLock<IpDeviceAddresses<Instant, I>>,
+    pub addrs: RwLock<IpDeviceAddresses<BT::Instant, I>>,
 
     /// Multicast groups this device has joined.
-    pub multicast_groups: RwLock<MulticastGroupSet<I::Addr, I::GmpState<Instant>>>,
+    pub multicast_groups: RwLock<MulticastGroupSet<I::Addr, I::GmpState<BT::Instant>>>,
 
     /// The default TTL (IPv4) or hop limit (IPv6) for outbound packets sent
     /// over this device.
@@ -286,8 +291,8 @@
     }
 }
 
-impl<Instant: crate::Instant, I: IpDeviceStateIpExt> Default for IpDeviceState<Instant, I> {
-    fn default() -> IpDeviceState<Instant, I> {
+impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> Default for IpDeviceState<I, BT> {
+    fn default() -> IpDeviceState<I, BT> {
         IpDeviceState {
             addrs: Default::default(),
             multicast_groups: Default::default(),
@@ -316,10 +321,9 @@
         self.addrs.iter()
     }
 
-    /// Finds the entry for `addr` if any.
-    #[cfg(test)]
-    pub(crate) fn find(&self, addr: &I::Addr) -> Option<&PrimaryRc<I::AssignedAddress<Instant>>> {
-        self.addrs.iter().find(|entry| &entry.addr().addr() == addr)
+    /// Iterates over strong clones of addresses assigned to this device.
+    pub(crate) fn strong_iter(&self) -> AddressIdIter<'_, Instant, I> {
+        AddressIdIter(self.addrs.iter())
     }
 
     /// Adds an IP address to this interface.
@@ -351,9 +355,25 @@
     }
 }
 
+/// An iterator over address StrongIds. Created from `IpDeviceAddresses`.
+pub struct AddressIdIter<'a, Instant: crate::Instant, I: Ip + IpDeviceStateIpExt>(
+    core::slice::Iter<'a, PrimaryRc<I::AssignedAddress<Instant>>>,
+);
+
+impl<'a, Instant: crate::Instant, I: Ip + IpDeviceStateIpExt> Iterator
+    for AddressIdIter<'a, Instant, I>
+{
+    type Item = StrongRc<I::AssignedAddress<Instant>>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let Self(inner) = self;
+        inner.next().map(PrimaryRc::clone_strong)
+    }
+}
+
 /// The state common to all IPv4 devices.
-pub struct Ipv4DeviceState<I: Instant> {
-    pub(crate) ip_state: IpDeviceState<I, Ipv4>,
+pub struct Ipv4DeviceState<BT: IpDeviceStateBindingsTypes> {
+    pub(crate) ip_state: IpDeviceState<Ipv4, BT>,
     pub(super) config: RwLock<Ipv4DeviceConfiguration>,
 }
 
@@ -375,20 +395,20 @@
     }
 }
 
-impl<I: Instant> Default for Ipv4DeviceState<I> {
-    fn default() -> Ipv4DeviceState<I> {
+impl<BT: IpDeviceStateBindingsTypes> Default for Ipv4DeviceState<BT> {
+    fn default() -> Ipv4DeviceState<BT> {
         Ipv4DeviceState { ip_state: Default::default(), config: Default::default() }
     }
 }
 
-impl<I: Instant> AsRef<IpDeviceState<I, Ipv4>> for Ipv4DeviceState<I> {
-    fn as_ref(&self) -> &IpDeviceState<I, Ipv4> {
+impl<BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<Ipv4, BT>> for Ipv4DeviceState<BT> {
+    fn as_ref(&self) -> &IpDeviceState<Ipv4, BT> {
         &self.ip_state
     }
 }
 
-impl<I: Instant> AsMut<IpDeviceState<I, Ipv4>> for Ipv4DeviceState<I> {
-    fn as_mut(&mut self) -> &mut IpDeviceState<I, Ipv4> {
+impl<BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<Ipv4, BT>> for Ipv4DeviceState<BT> {
+    fn as_mut(&mut self) -> &mut IpDeviceState<Ipv4, BT> {
         &mut self.ip_state
     }
 }
@@ -580,8 +600,8 @@
 impl<BT: IpDeviceStateBindingsTypes> LockFor<crate::lock_ordering::Ipv6DeviceRouteDiscovery>
     for DualStackIpDeviceState<BT>
 {
-    type Data = Ipv6RouteDiscoveryState;
-    type Guard<'l> = crate::sync::LockGuard<'l, Ipv6RouteDiscoveryState>
+    type Data = Ipv6RouteDiscoveryState<BT>;
+    type Guard<'l> = crate::sync::LockGuard<'l, Ipv6RouteDiscoveryState<BT>>
         where
             Self: 'l;
     fn lock(&self) -> Self::Guard<'_> {
@@ -592,12 +612,12 @@
 impl<BT: IpDeviceStateBindingsTypes> LockFor<crate::lock_ordering::Ipv6DeviceRouterSolicitations>
     for DualStackIpDeviceState<BT>
 {
-    type Data = Option<NonZeroU8>;
-    type Guard<'l> = crate::sync::LockGuard<'l, Option<NonZeroU8>>
+    type Data = RsState<BT>;
+    type Guard<'l> = crate::sync::LockGuard<'l, RsState<BT>>
         where
             Self: 'l;
     fn lock(&self) -> Self::Guard<'_> {
-        self.ipv6.router_soliciations_remaining.lock()
+        self.ipv6.router_solicitations.lock()
     }
 }
 
@@ -640,57 +660,74 @@
 }
 
 /// The state common to all IPv6 devices.
-pub struct Ipv6DeviceState<I: Instant> {
+pub struct Ipv6DeviceState<BT: IpDeviceStateBindingsTypes> {
     pub(super) learned_params: RwLock<Ipv6NetworkLearnedParameters>,
-    pub(super) route_discovery: Mutex<Ipv6RouteDiscoveryState>,
-    pub(super) router_soliciations_remaining: Mutex<Option<NonZeroU8>>,
-    pub(crate) ip_state: IpDeviceState<I, Ipv6>,
+    pub(super) route_discovery: Mutex<Ipv6RouteDiscoveryState<BT>>,
+    pub(super) router_solicitations: Mutex<RsState<BT>>,
+    pub(crate) ip_state: IpDeviceState<Ipv6, BT>,
     pub(crate) config: RwLock<Ipv6DeviceConfiguration>,
 }
 
-impl<I: Instant> Default for Ipv6DeviceState<I> {
-    fn default() -> Ipv6DeviceState<I> {
+impl<BC: IpDeviceStateBindingsTypes + TimerContext2> Ipv6DeviceState<BC> {
+    pub fn new<D: device::StrongId, CC: CoreTimerContext<Ipv6DeviceTimerId<D>, BC>>(
+        bindings_ctx: &mut BC,
+        device_id: D::Weak,
+    ) -> Self {
         Ipv6DeviceState {
             learned_params: Default::default(),
-            route_discovery: Default::default(),
-            router_soliciations_remaining: Default::default(),
+            route_discovery: Mutex::new(Ipv6RouteDiscoveryState::new::<
+                _,
+                NestedIntoCoreTimerCtx<CC, _>,
+            >(bindings_ctx, device_id.clone())),
+            router_solicitations: Mutex::new(RsState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(
+                bindings_ctx,
+                device_id,
+            )),
             ip_state: Default::default(),
             config: Default::default(),
         }
     }
 }
 
-impl<I: Instant> AsRef<IpDeviceState<I, Ipv6>> for Ipv6DeviceState<I> {
-    fn as_ref(&self) -> &IpDeviceState<I, Ipv6> {
+impl<BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<Ipv6, BT>> for Ipv6DeviceState<BT> {
+    fn as_ref(&self) -> &IpDeviceState<Ipv6, BT> {
         &self.ip_state
     }
 }
 
-impl<I: Instant> AsMut<IpDeviceState<I, Ipv6>> for Ipv6DeviceState<I> {
-    fn as_mut(&mut self) -> &mut IpDeviceState<I, Ipv6> {
+impl<BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<Ipv6, BT>> for Ipv6DeviceState<BT> {
+    fn as_mut(&mut self) -> &mut IpDeviceState<Ipv6, BT> {
         &mut self.ip_state
     }
 }
 
 /// Bindings types required for IP device state.
-pub trait IpDeviceStateBindingsTypes: InstantBindingsTypes {}
-impl<BT> IpDeviceStateBindingsTypes for BT where BT: InstantBindingsTypes {}
+pub trait IpDeviceStateBindingsTypes: InstantBindingsTypes + TimerBindingsTypes {}
+impl<BT> IpDeviceStateBindingsTypes for BT where BT: InstantBindingsTypes + TimerBindingsTypes {}
 
 /// IPv4 and IPv6 state combined.
 pub(crate) struct DualStackIpDeviceState<BT: IpDeviceStateBindingsTypes> {
     /// IPv4 state.
-    pub ipv4: Ipv4DeviceState<BT::Instant>,
+    pub ipv4: Ipv4DeviceState<BT>,
 
     /// IPv6 state.
-    pub ipv6: Ipv6DeviceState<BT::Instant>,
+    pub ipv6: Ipv6DeviceState<BT>,
 
     /// The device's routing metric.
     pub metric: RawMetric,
 }
 
-impl<BT: InstantBindingsTypes> DualStackIpDeviceState<BT> {
-    pub(crate) fn new(metric: RawMetric) -> Self {
-        Self { ipv4: Default::default(), ipv6: Default::default(), metric }
+impl<BC: IpDeviceStateBindingsTypes + TimerContext2> DualStackIpDeviceState<BC> {
+    pub(crate) fn new<D: device::StrongId, CC: CoreTimerContext<IpDeviceTimerId<Ipv6, D>, BC>>(
+        bindings_ctx: &mut BC,
+        device_id: D::Weak,
+        metric: RawMetric,
+    ) -> Self {
+        Self {
+            ipv4: Default::default(),
+            ipv6: Ipv6DeviceState::new::<_, NestedIntoCoreTimerCtx<CC, _>>(bindings_ctx, device_id),
+            metric,
+        }
     }
 }
 
@@ -988,18 +1025,18 @@
 pub(crate) mod testutil {
     use super::*;
 
-    use net_types::{ip::IpInvariant, Witness as _};
+    use net_types::ip::IpInvariant;
 
-    impl<I: IpDeviceStateIpExt, Instant: crate::Instant> AsRef<Self> for IpDeviceState<Instant, I> {
+    impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> AsRef<Self> for IpDeviceState<I, BT> {
         fn as_ref(&self) -> &Self {
             self
         }
     }
 
-    impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<BT::Instant, I>>
+    impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> AsRef<IpDeviceState<I, BT>>
         for DualStackIpDeviceState<BT>
     {
-        fn as_ref(&self) -> &IpDeviceState<BT::Instant, I> {
+        fn as_ref(&self) -> &IpDeviceState<I, BT> {
             I::map_ip(
                 IpInvariant(self),
                 |IpInvariant(dual_stack)| &dual_stack.ipv4.ip_state,
@@ -1008,10 +1045,10 @@
         }
     }
 
-    impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<BT::Instant, I>>
+    impl<I: IpDeviceStateIpExt, BT: IpDeviceStateBindingsTypes> AsMut<IpDeviceState<I, BT>>
         for DualStackIpDeviceState<BT>
     {
-        fn as_mut(&mut self) -> &mut IpDeviceState<BT::Instant, I> {
+        fn as_mut(&mut self) -> &mut IpDeviceState<I, BT> {
             I::map_ip(
                 IpInvariant(self),
                 |IpInvariant(dual_stack)| &mut dual_stack.ipv4.ip_state,
@@ -1019,35 +1056,6 @@
             )
         }
     }
-
-    /// Adds an address and route for the size-1 subnet containing the address.
-    pub(crate) fn add_addr_subnet<A: IpAddress, Instant: crate::Instant>(
-        device_state: &mut IpDeviceState<Instant, A::Version>,
-        ip: SpecifiedAddr<A>,
-    ) where
-        A::Version: IpDeviceStateIpExt,
-    {
-        #[derive(GenericOverIp)]
-        #[generic_over_ip(I, Ip)]
-        struct Wrap<I: IpDeviceStateIpExt, Instant: crate::Instant>(I::AssignedAddress<Instant>);
-        let Wrap(entry) = <A::Version as Ip>::map_ip(
-            ip.get(),
-            |ip| {
-                Wrap(Ipv4AddressEntry::new(
-                    AddrSubnet::new(ip, 32).unwrap(),
-                    Ipv4AddrConfig::default(),
-                ))
-            },
-            |ip| {
-                Wrap(Ipv6AddressEntry::new(
-                    AddrSubnet::new(ip, 128).unwrap(),
-                    Ipv6DadState::Assigned,
-                    Ipv6AddrConfig::default(),
-                ))
-            },
-        );
-        let _addr_id = device_state.addrs.get_mut().add(entry).expect("add address");
-    }
 }
 
 #[cfg(test)]
diff --git a/src/connectivity/network/netstack3/core/src/ip/forwarding.rs b/src/connectivity/network/netstack3/core/src/ip/forwarding.rs
index ff0e67e..e6a7bb4 100644
--- a/src/connectivity/network/netstack3/core/src/ip/forwarding.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/forwarding.rs
@@ -193,8 +193,32 @@
         mut f: impl FnMut(&mut CC, &D) -> Option<R> + 'a,
     ) -> impl Iterator<Item = (Destination<I::Addr, &D>, R)> + 'a {
         let Self { table } = self;
-        // Get all potential routes we could take to reach `address`.
-        table.iter().filter_map(move |entry| {
+
+        #[derive(GenericOverIp)]
+        #[generic_over_ip(I, Ip)]
+        enum BroadcastCase<I: IpTypesIpExt> {
+            AllOnes(I::BroadcastMarker),
+            Subnet(I::BroadcastMarker),
+            NotBroadcast,
+        }
+
+        let bound_device_all_ones_broadcast_exemption = core::iter::once_with(move || {
+            // If we're bound to a device and trying to broadcast on the local
+            // network, then provide a matched broadcast route.
+            let local_device = local_device?;
+            let next_hop = I::map_ip::<_, Option<NextHop<I::Addr>>>(
+                address,
+                |address| {
+                    (address == Ipv4::LIMITED_BROADCAST_ADDRESS.get())
+                        .then_some(NextHop::Broadcast(()))
+                },
+                |_address| None,
+            )?;
+            Some(Destination { next_hop, device: local_device })
+        })
+        .filter_map(|x| x);
+
+        let viable_table_entries = table.iter().filter_map(move |entry| {
             let EntryAndGeneration {
                 entry: Entry { subnet, device, gateway, metric: _ },
                 generation: _,
@@ -206,55 +230,62 @@
                 return None;
             }
 
-            if !core_ctx.is_ip_device_enabled(device) {
-                return None;
-            }
-
-            f(core_ctx, device).map(|r| {
-                let next_hop = gateway.map_or(
+            let broadcast_case = I::map_ip::<_, BroadcastCase<I>>(
+                (address, *subnet),
+                |(address, subnet)| {
+                    // As per RFC 919 section 7,
+                    //      The address 255.255.255.255 denotes a broadcast on a local hardware
+                    //      network, which must not be forwarded.
+                    if address == Ipv4::LIMITED_BROADCAST_ADDRESS.get() {
+                        BroadcastCase::AllOnes(())
+                    // Or the destination address is the highest address in the subnet.
+                    // Per RFC 922,
+                    //       Since the local network layer can always map an IP address into data
+                    //       link layer address, the choice of an IP "broadcast host number" is
+                    //       somewhat arbitrary.  For simplicity, it should be one not likely to be
+                    //       assigned to a real host.  The number whose bits are all ones has this
+                    //       property; this assignment was first proposed in [6].  In the few cases
+                    //       where a host has been assigned an address with a host-number part of
+                    //       all ones, it does not seem onerous to require renumbering.
+                    // We require that the subnet contain more than one address (i.e. that the
+                    // prefix length is not 32) in order to decide that an address is a subnet
+                    // broadcast address.
+                    } else if subnet.prefix() < Ipv4Addr::BYTES * 8 && subnet.broadcast() == address
                     {
-                        let next_hop = I::map_ip(
-                            (address, *subnet),
-                            |(address, subnet)| {
-                                // As per RFC 919 section 7,
-                                //      The address 255.255.255.255 denotes a broadcast on a local
-                                //      hardware network, which must not be forwarded.
-                                if address == Ipv4::LIMITED_BROADCAST_ADDRESS.get()
-                                    // Or the destination address is the highest address in the
-                                    // subnet.
-                                    // Per RFC 922,
-                                    //       Since the local network layer can always map an IP
-                                    //       address into data link layer address, the choice of an
-                                    //       IP "broadcast host number" is somewhat arbitrary.  For
-                                    //       simplicity, it should be one not likely to be assigned
-                                    //       to a real host.  The number whose bits are all ones has
-                                    //       this property; this assignment was first proposed in
-                                    //       [6].  In the few cases where a host has been assigned
-                                    //       an address with a host-number part of all ones, it does
-                                    //       not seem onerous to require renumbering.
-                                    // We require that the subnet contain more than one address
-                                    // (i.e. that the prefix length is not 32) in order to decide
-                                    // that an address is a subnet broadcast address.
-                                    || subnet.prefix() < Ipv4Addr::BYTES * 8
-                                        && subnet.broadcast() == address
-                                {
-                                    NextHop::Broadcast(())
-                                } else {
-                                    NextHop::RemoteAsNeighbor
-                                }
-                            },
-                            // IPv6 has no notion of "broadcast".
-                            |(_address, _subnet)| NextHop::RemoteAsNeighbor,
-                        );
-                        next_hop
-                    },
-                    // Notably, if the route has a gateway, then
-                    // `NextHop::Broadcast(())` is never yielded.
-                    NextHop::Gateway,
-                );
-                (Destination { next_hop, device }, r)
-            })
-        })
+                        BroadcastCase::Subnet(())
+                    } else {
+                        BroadcastCase::NotBroadcast
+                    }
+                },
+                // IPv6 has no notion of "broadcast".
+                |(_address, _subnet)| BroadcastCase::NotBroadcast,
+            );
+
+            let next_hop = match broadcast_case {
+                // Always broadcast to the all-ones destination.
+                BroadcastCase::AllOnes(marker) => NextHop::Broadcast(marker),
+                // Only broadcast to the subnet broadcast address if the route does not have a
+                // gateway.
+                BroadcastCase::Subnet(marker) => {
+                    gateway.map_or(NextHop::Broadcast(marker), NextHop::Gateway)
+                }
+                BroadcastCase::NotBroadcast => {
+                    gateway.map_or(NextHop::RemoteAsNeighbor, NextHop::Gateway)
+                }
+            };
+
+            Some(Destination { next_hop, device })
+        });
+
+        bound_device_all_ones_broadcast_exemption.chain(viable_table_entries).filter_map(
+            move |destination| {
+                let device = &destination.device;
+                if !core_ctx.is_ip_device_enabled(device) {
+                    return None;
+                }
+                f(core_ctx, device).map(|r| (destination, r))
+            },
+        )
     }
 }
 
@@ -369,7 +400,7 @@
     use alloc::collections::HashSet;
 
     use derivative::Derivative;
-    use net_types::ip::{IpAddress, IpInvariant, Ipv6};
+    use net_types::ip::IpAddress;
 
     use super::*;
 
@@ -445,33 +476,6 @@
             !self.get_ref().disabled_devices.contains(device_id)
         }
     }
-
-    #[derive(Derivative)]
-    #[derivative(Default(bound = ""))]
-    pub(crate) struct DualStackForwardingTable<D> {
-        v4: ForwardingTable<Ipv4, D>,
-        v6: ForwardingTable<Ipv6, D>,
-    }
-
-    impl<D, I: Ip> AsRef<ForwardingTable<I, D>> for DualStackForwardingTable<D> {
-        fn as_ref(&self) -> &ForwardingTable<I, D> {
-            I::map_ip(
-                IpInvariant(self),
-                |IpInvariant(table)| &table.v4,
-                |IpInvariant(table)| &table.v6,
-            )
-        }
-    }
-
-    impl<D, I: Ip> AsMut<ForwardingTable<I, D>> for DualStackForwardingTable<D> {
-        fn as_mut(&mut self) -> &mut ForwardingTable<I, D> {
-            I::map_ip(
-                IpInvariant(self),
-                |IpInvariant(table)| &mut table.v4,
-                |IpInvariant(table)| &mut table.v6,
-            )
-        }
-    }
 }
 
 #[cfg(test)]
@@ -795,10 +799,7 @@
 
                 assert_eq!(
                     table.lookup(&mut core_ctx, None, Ipv4::LIMITED_BROADCAST_ADDRESS.get()),
-                    Some(Destination {
-                        next_hop: NextHop::Gateway(next_hop),
-                        device: device.clone()
-                    })
+                    Some(Destination { next_hop: NextHop::Broadcast(()), device: device.clone() })
                 );
             },
             |(_table, _config, _next_hop)| {
@@ -807,6 +808,170 @@
         );
     }
 
+    #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+    enum BroadcastCaseNextHop {
+        Neighbor,
+        Gateway,
+    }
+
+    #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+    enum LookupResultNextHop {
+        Neighbor,
+        Gateway,
+        Broadcast,
+    }
+
+    #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+    struct LookupResult {
+        next_hop: LookupResultNextHop,
+        device: MultipleDevicesId,
+    }
+
+    #[test_case::test_matrix(
+        [None, Some(BroadcastCaseNextHop::Neighbor), Some(BroadcastCaseNextHop::Gateway)],
+        [None, Some(MultipleDevicesId::A), Some(MultipleDevicesId::B)]
+    )]
+    fn all_ones_broadcast_lookup(
+        default_route: Option<BroadcastCaseNextHop>,
+        bind_device: Option<MultipleDevicesId>,
+    ) {
+        let mut core_ctx = FakeCtx::default();
+        let expected_lookup_result = match (default_route, bind_device) {
+            // Sending to all-ones with a bound device always results in a broadcast.
+            (_, Some(device)) => {
+                Some(LookupResult { next_hop: LookupResultNextHop::Broadcast, device })
+            }
+            // With no matching route and no bound device, we don't know where to broadcast to,
+            // so the lookup fails.
+            (None, None) => None,
+            (Some(_next_hop), None) => {
+                // Regardless of the default route's configured next hop, sending to all-ones
+                // should result in a broadcast.
+                Some(LookupResult {
+                    next_hop: LookupResultNextHop::Broadcast,
+                    device: MultipleDevicesId::A,
+                })
+            }
+        };
+
+        let mut table = ForwardingTable::<Ipv4, MultipleDevicesId>::default();
+        if let Some(next_hop) = default_route {
+            let entry = Entry {
+                subnet: Subnet::new(Ipv4::UNSPECIFIED_ADDRESS, 0).expect("default subnet"),
+                device: MultipleDevicesId::A,
+                gateway: match next_hop {
+                    BroadcastCaseNextHop::Neighbor => None,
+                    BroadcastCaseNextHop::Gateway => {
+                        Some(SpecifiedAddr::new(net_ip_v4!("192.168.0.1")).unwrap())
+                    }
+                },
+                metric: Metric::ExplicitMetric(RawMetric(0)),
+            };
+            assert_eq!(super::testutil::add_entry(&mut table, entry.clone()), Ok(&entry));
+        }
+
+        let got_lookup_result = table
+            .lookup(&mut core_ctx, bind_device.as_ref(), Ipv4::LIMITED_BROADCAST_ADDRESS.get())
+            .map(|Destination { next_hop, device }| LookupResult {
+                next_hop: match next_hop {
+                    NextHop::RemoteAsNeighbor => LookupResultNextHop::Neighbor,
+                    NextHop::Gateway(_) => LookupResultNextHop::Gateway,
+                    NextHop::Broadcast(()) => LookupResultNextHop::Broadcast,
+                },
+                device,
+            });
+
+        assert_eq!(got_lookup_result, expected_lookup_result);
+    }
+
+    #[test_case::test_matrix(
+        [None, Some(BroadcastCaseNextHop::Neighbor), Some(BroadcastCaseNextHop::Gateway)],
+        [None, Some(BroadcastCaseNextHop::Neighbor), Some(BroadcastCaseNextHop::Gateway)],
+        [None, Some(MultipleDevicesId::A), Some(MultipleDevicesId::B)]
+    )]
+    fn subnet_broadcast_lookup(
+        default_route: Option<BroadcastCaseNextHop>,
+        subnet_route: Option<BroadcastCaseNextHop>,
+        bind_device: Option<MultipleDevicesId>,
+    ) {
+        let mut core_ctx = FakeCtx::default();
+        let expected_lookup_result = match bind_device {
+            // Binding to a device not matching any routes in the table will fail the lookup.
+            Some(MultipleDevicesId::B) | Some(MultipleDevicesId::C) => None,
+            Some(MultipleDevicesId::A) | None => match (default_route, subnet_route) {
+                // No matching routes.
+                (None, None) => None,
+                // The subnet route will take precedence over the default route.
+                (None | Some(_), Some(next_hop)) => {
+                    Some(LookupResult {
+                        device: MultipleDevicesId::A,
+                        next_hop: match next_hop {
+                            // Allow broadcasting when this route is on-link.
+                            BroadcastCaseNextHop::Neighbor => LookupResultNextHop::Broadcast,
+                            // Continue to unicast when the route has a gateway, even though this is
+                            // the subnet's broadcast address.
+                            BroadcastCaseNextHop::Gateway => LookupResultNextHop::Gateway,
+                        },
+                    })
+                }
+                (Some(next_hop), None) => {
+                    Some(LookupResult {
+                        device: MultipleDevicesId::A,
+                        next_hop: match next_hop {
+                            // Since this is just matching the default route, it looks like
+                            // a regular unicast route rather than a broadcast one.
+                            BroadcastCaseNextHop::Neighbor => LookupResultNextHop::Neighbor,
+                            BroadcastCaseNextHop::Gateway => LookupResultNextHop::Gateway,
+                        },
+                    })
+                }
+            },
+        };
+
+        let subnet = net_declare::net_subnet_v4!("192.168.0.0/24");
+        let gateway = SpecifiedAddr::new(net_ip_v4!("192.168.0.1")).unwrap();
+
+        let mut table = ForwardingTable::<Ipv4, MultipleDevicesId>::default();
+        if let Some(next_hop) = default_route {
+            let entry = Entry {
+                subnet: Subnet::new(Ipv4::UNSPECIFIED_ADDRESS, 0).expect("default subnet"),
+                device: MultipleDevicesId::A,
+                gateway: match next_hop {
+                    BroadcastCaseNextHop::Neighbor => None,
+                    BroadcastCaseNextHop::Gateway => Some(gateway),
+                },
+                metric: Metric::ExplicitMetric(RawMetric(0)),
+            };
+            assert_eq!(super::testutil::add_entry(&mut table, entry.clone()), Ok(&entry));
+        }
+
+        if let Some(next_hop) = subnet_route {
+            let entry = Entry {
+                subnet,
+                device: MultipleDevicesId::A,
+                gateway: match next_hop {
+                    BroadcastCaseNextHop::Neighbor => None,
+                    BroadcastCaseNextHop::Gateway => Some(gateway),
+                },
+                metric: Metric::ExplicitMetric(RawMetric(0)),
+            };
+            assert_eq!(super::testutil::add_entry(&mut table, entry.clone()), Ok(&entry));
+        }
+
+        let got_lookup_result = table
+            .lookup(&mut core_ctx, bind_device.as_ref(), subnet.broadcast())
+            .map(|Destination { next_hop, device }| LookupResult {
+                next_hop: match next_hop {
+                    NextHop::RemoteAsNeighbor => LookupResultNextHop::Neighbor,
+                    NextHop::Gateway(_) => LookupResultNextHop::Gateway,
+                    NextHop::Broadcast(()) => LookupResultNextHop::Broadcast,
+                },
+                device,
+            });
+
+        assert_eq!(got_lookup_result, expected_lookup_result);
+    }
+
     #[ip_test]
     fn test_default_route_ip<I: Ip + TestIpExt>() {
         let mut core_ctx = FakeCtx::default();
diff --git a/src/connectivity/network/netstack3/core/src/ip/gmp.rs b/src/connectivity/network/netstack3/core/src/ip/gmp.rs
index 5b73619..60701f4 100644
--- a/src/connectivity/network/netstack3/core/src/ip/gmp.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/gmp.rs
@@ -38,8 +38,6 @@
 pub(crate) mod mld;
 
 use alloc::vec::Vec;
-#[cfg(test)]
-use core::num::NonZeroUsize;
 use core::{fmt::Debug, time::Duration};
 
 use assert_matches::assert_matches;
@@ -273,13 +271,6 @@
         self.inner.get_mut(group)
     }
 
-    #[cfg(test)]
-    pub(crate) fn iter_counts<'a>(
-        &'a self,
-    ) -> impl 'a + Iterator<Item = (&'a MulticastAddr<A>, NonZeroUsize)> {
-        self.inner.iter_with_counts().map(|(addr, _state, count)| (addr, count))
-    }
-
     fn iter_mut<'a>(&'a mut self) -> impl 'a + Iterator<Item = (&'a MulticastAddr<A>, &'a mut T)> {
         self.inner.iter_mut()
     }
@@ -461,6 +452,9 @@
 ///
 /// Memberships may be a non-member when joined locally but are not performing
 /// GMP.
+///
+/// Note that the special all-nodes addresses 224.0.0.1 and ff02::1 are modelled
+/// as permanently in `NonMember` state instead of `Idle` state in NS3.
 #[cfg_attr(test, derive(Debug))]
 struct NonMember;
 
@@ -703,15 +697,6 @@
 
     /// Performs the "leave group" transition, consuming the state by value, and
     /// returning the next state and a set of actions to execute.
-    ///
-    /// In the [IGMPv2] and [MLD] RFCs, the "leave group" transition moves from
-    /// any state to the Non-Member state. However, we don't allow `MemberState`
-    /// to be in the Non-Member state, so we instead implement `leave_group` by
-    /// consuming the state by value. This ensures that once a group has been
-    /// left, we don't spuriously store state for it.
-    ///
-    /// [IGMPv2]: https://tools.ietf.org/html/rfc2236
-    /// [MLD]: https://tools.ietf.org/html/rfc2710
     fn leave_group(self) -> (MemberState<I, P>, LeaveGroupActions) {
         // Rust can infer these types, but since we're just discarding `_state`,
         // we explicitly make sure it's the state we expect in case we introduce
@@ -1264,75 +1249,6 @@
         })
 }
 #[cfg(test)]
-mod testutil {
-    use net_types::{
-        ip::{GenericOverIp, Ip, IpAddress, IpInvariant},
-        MulticastAddr,
-    };
-
-    use crate::{
-        context::{testutil::FakeInstant, InstantContext, RngContext},
-        data_structures::ref_counted_hash_map::{InsertResult, RemoveResult},
-        ip::{
-            device::state::IpDeviceStateIpExt,
-            gmp::{GmpStateMachine, MulticastGroupSet, ProtocolSpecific},
-        },
-    };
-
-    #[derive(GenericOverIp)]
-    #[generic_over_ip(I, Ip)]
-    struct GroupWrapper<'a, I: IpDeviceStateIpExt>(
-        &'a mut MulticastGroupSet<I::Addr, I::GmpState<FakeInstant>>,
-    );
-
-    impl<A: IpAddress> MulticastGroupSet<A, <A::Version as IpDeviceStateIpExt>::GmpState<FakeInstant>>
-    where
-        A::Version: IpDeviceStateIpExt,
-    {
-        pub(crate) fn join_multicast_group<
-            BC: RngContext + InstantContext<Instant = FakeInstant>,
-        >(
-            &mut self,
-            bindings_ctx: &mut BC,
-            addr: MulticastAddr<A>,
-        ) {
-            fn new_state_machine<BC: RngContext + InstantContext, P: Default + ProtocolSpecific>(
-                bindings_ctx: &mut BC,
-            ) -> GmpStateMachine<BC::Instant, P> {
-                let now = bindings_ctx.now();
-                let (machine, _actions) =
-                    GmpStateMachine::join_group(&mut bindings_ctx.rng(), now, false);
-                machine
-            }
-
-            <A::Version as Ip>::map_ip(
-                (GroupWrapper(self), addr, IpInvariant(bindings_ctx)),
-                |(GroupWrapper(MulticastGroupSet { inner }), addr, IpInvariant(ctx))| {
-                    let _: InsertResult<_> =
-                        inner.insert_with(addr, || (new_state_machine(ctx).into(), ()));
-                },
-                |(GroupWrapper(MulticastGroupSet { inner }), addr, IpInvariant(ctx))| {
-                    let _: InsertResult<_> =
-                        inner.insert_with(addr, || (new_state_machine(ctx).into(), ()));
-                },
-            )
-        }
-
-        pub(crate) fn leave_multicast_group(&mut self, addr: MulticastAddr<A>) {
-            <A::Version as Ip>::map_ip(
-                (GroupWrapper(self), addr),
-                |(GroupWrapper(MulticastGroupSet { inner }), addr)| {
-                    let _: RemoveResult<_> = inner.remove(addr);
-                },
-                |(GroupWrapper(MulticastGroupSet { inner }), addr)| {
-                    let _: RemoveResult<_> = inner.remove(addr);
-                },
-            )
-        }
-    }
-}
-
-#[cfg(test)]
 mod test {
     use core::convert::Infallible as Never;
 
diff --git a/src/connectivity/network/netstack3/core/src/ip/gmp/igmp.rs b/src/connectivity/network/netstack3/core/src/ip/gmp/igmp.rs
index a9d8bd5..a2c62b8 100644
--- a/src/connectivity/network/netstack3/core/src/ip/gmp/igmp.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/gmp/igmp.rs
@@ -41,6 +41,7 @@
             GmpStateMachine, GmpTypeLayout, IpExt, MulticastGroupSet, ProtocolSpecific,
             QueryTarget,
         },
+        IpLayerHandler,
     },
     Instant,
 };
@@ -73,7 +74,7 @@
 
 /// The execution context for the Internet Group Management Protocol (IGMP).
 pub(crate) trait IgmpContext<BC: IgmpBindingsContext<Self::DeviceId>>:
-    DeviceIdContext<AnyDevice> + IpDeviceSendContext<Ipv4, BC>
+    DeviceIdContext<AnyDevice> + IpDeviceSendContext<Ipv4, BC> + IpLayerHandler<Ipv4, BC>
 {
     /// Calls the function with a mutable reference to the device's IGMP state
     /// and whether or not IGMP is enabled for the `device`.
@@ -173,8 +174,21 @@
 }
 
 impl IpExt for Ipv4 {
-    fn should_perform_gmp(_addr: MulticastAddr<Ipv4Addr>) -> bool {
-        true
+    fn should_perform_gmp(addr: MulticastAddr<Ipv4Addr>) -> bool {
+        // Per [RFC 2236 Section 6]:
+        //
+        //   The all-systems group (address 224.0.0.1) is handled as a special
+        //   case.  The host starts in Idle Member state for that group on every
+        //   interface, never transitions to another state, and never sends a
+        //   report for that group.
+        //
+        // We abide by this requirement by not executing [`Actions`] on these
+        // addresses. Executing [`Actions`] only produces externally-visible side
+        // effects, and is not required to maintain the correctness of the MLD state
+        // machines.
+        //
+        // [RFC 2236 Section 6]: https://datatracker.ietf.org/doc/html/rfc2236
+        addr != Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS
     }
 }
 
@@ -388,9 +402,15 @@
     };
     let body = body.into_serializer().encapsulate(builder);
 
-    core_ctx
-        .send_ip_frame(bindings_ctx, &device, dst_ip.into_specified(), body, None)
-        .map_err(|_| IgmpError::SendFailure { addr: *group_addr })
+    crate::ip::IpLayerHandler::send_ip_frame(
+        core_ctx,
+        bindings_ctx,
+        &device,
+        dst_ip.into_specified(),
+        body,
+        None,
+    )
+    .map_err(|_| IgmpError::SendFailure { addr: *group_addr })
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -530,7 +550,7 @@
     use alloc::vec::Vec;
     use assert_matches::assert_matches;
 
-    use net_types::{ethernet::Mac, ip::Ip as _};
+    use net_types::{ethernet::Mac, ip::Ip};
     use packet::{serialize::Buf, ParsablePacket as _};
     use packet_formats::{
         ethernet::EthernetFrameLengthCheck,
@@ -550,6 +570,7 @@
             testutil::FakeDeviceId,
             DeviceId,
         },
+        filter::{MaybeTransportPacket, ProofOfEgressCheck},
         ip::{
             device::{
                 config::{IpDeviceConfigurationUpdate, Ipv4DeviceConfigurationUpdate},
@@ -560,6 +581,8 @@
                 QueryReceivedActions, ReportReceivedActions, ReportTimerExpiredActions,
             },
             testutil::FakeIpDeviceIdCtx,
+            types::IpTypesIpExt,
+            IpLayerPacketMetadata,
         },
         state::StackStateBuilder,
         testutil::{
@@ -662,6 +685,48 @@
         }
     }
 
+    impl IpLayerHandler<Ipv4, FakeBindingsCtx> for FakeCoreCtx {
+        fn send_ip_packet_from_device<S>(
+            &mut self,
+            _bindings_ctx: &mut FakeBindingsCtx,
+            _meta: crate::ip::SendIpPacketMeta<
+                Ipv4,
+                &Self::DeviceId,
+                Option<SpecifiedAddr<<Ipv4 as Ip>::Addr>>,
+            >,
+            _body: S,
+        ) -> Result<(), S>
+        where
+            S: Serializer + MaybeTransportPacket,
+            S::Buffer: BufferMut,
+        {
+            unimplemented!();
+        }
+
+        fn send_ip_frame<S>(
+            &mut self,
+            bindings_ctx: &mut FakeBindingsCtx,
+            device: &Self::DeviceId,
+            next_hop: SpecifiedAddr<<Ipv4 as Ip>::Addr>,
+            body: S,
+            broadcast: Option<<Ipv4 as IpTypesIpExt>::BroadcastMarker>,
+        ) -> Result<(), S>
+        where
+            S: Serializer + netstack3_filter::IpPacket<Ipv4>,
+            S::Buffer: BufferMut,
+        {
+            crate::ip::send_ip_frame(
+                self,
+                bindings_ctx,
+                device,
+                next_hop,
+                body,
+                broadcast,
+                IpLayerPacketMetadata::default(),
+            )
+        }
+    }
+
     impl IpDeviceSendContext<Ipv4, FakeBindingsCtx> for FakeCoreCtx {
         fn send_ip_frame<S>(
             &mut self,
@@ -670,6 +735,7 @@
             local_addr: SpecifiedAddr<Ipv4Addr>,
             body: S,
             _broadcast: Option<()>,
+            ProofOfEgressCheck { .. }: ProofOfEgressCheck,
         ) -> Result<(), S>
         where
             S: Serializer,
@@ -1051,6 +1117,23 @@
     }
 
     #[test]
+    fn test_igmp_integration_always_idle_member() {
+        run_with_many_seeds(|seed| {
+            let FakeCtx { mut core_ctx, mut bindings_ctx } = setup_simple_test_environment(seed);
+            assert_eq!(
+                core_ctx.gmp_join_group(
+                    &mut bindings_ctx,
+                    &FakeDeviceId,
+                    Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS
+                ),
+                GroupJoinResult::Joined(())
+            );
+            assert_eq!(core_ctx.frames().len(), 0);
+            bindings_ctx.timer_ctx().assert_no_timers_installed();
+        });
+    }
+
+    #[test]
     fn test_igmp_integration_not_last_does_not_send_leave() {
         run_with_many_seeds(|seed| {
             let FakeCtx { mut core_ctx, mut bindings_ctx } = setup_simple_test_environment(seed);
@@ -1336,7 +1419,7 @@
         let timer_id = TimerId(TimerIdInner::Ipv4Device(
             Ipv4DeviceTimerId::from(IgmpTimerId::Gmp(GmpDelayedReportTimerId {
                 device: device_id.clone(),
-                group_addr: Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS,
+                group_addr: GROUP_ADDR,
             }))
             .into(),
         ));
@@ -1372,16 +1455,16 @@
                 parse_ip_packet_in_ethernet_frame::<Ipv4>(frame, EthernetFrameLengthCheck::NoCheck)
                     .unwrap();
             assert_eq!(src_mac, local_mac.get());
-            assert_eq!(dst_mac, Mac::from(&Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS));
+            assert_eq!(dst_mac, Mac::from(&GROUP_ADDR));
             assert_eq!(src_ip, MY_ADDR.get());
-            assert_eq!(dst_ip, Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS.get());
+            assert_eq!(dst_ip, GROUP_ADDR.get());
             assert_eq!(proto, Ipv4Proto::Igmp);
             assert_eq!(ttl, 1);
             let mut bv = &body[..];
             assert_matches!(
                 IgmpPacket::parse(&mut bv, ()).unwrap(),
                 IgmpPacket::MembershipReportV2(msg) => {
-                    assert_eq!(msg.group_addr(), Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS.get());
+                    assert_eq!(msg.group_addr(), GROUP_ADDR.get());
                 }
             );
         };
@@ -1403,16 +1486,14 @@
             assert_matches!(
                 IgmpPacket::parse(&mut bv, ()).unwrap(),
                 IgmpPacket::LeaveGroup(msg) => {
-                    assert_eq!(msg.group_addr(), Ipv4::ALL_SYSTEMS_MULTICAST_ADDRESS.get());
+                    assert_eq!(msg.group_addr(), GROUP_ADDR.get());
                 }
             );
         };
 
-        // Enable IPv4 and IGMP.
-        //
-        // Should send report for the all-systems multicast group that all
-        // interfaces join.
+        // Enable IPv4 and IGMP, then join `GROUP_ADDR`.
         set_config(&mut ctx, TestConfig { ip_enabled: true, gmp_enabled: true });
+        ctx.test_api().join_ip_multicast(&device_id, GROUP_ADDR);
         ctx.bindings_ctx
             .timer_ctx()
             .assert_timers_installed_range([(timer_id.clone(), range.clone())]);
diff --git a/src/connectivity/network/netstack3/core/src/ip/gmp/mld.rs b/src/connectivity/network/netstack3/core/src/ip/gmp/mld.rs
index 2b3a777..dafd290 100644
--- a/src/connectivity/network/netstack3/core/src/ip/gmp/mld.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/gmp/mld.rs
@@ -46,6 +46,7 @@
             GmpStateMachine, GmpTypeLayout, IpExt, MulticastGroupSet, ProtocolSpecific,
             QueryTarget,
         },
+        IpLayerHandler,
     },
     Instant,
 };
@@ -75,7 +76,7 @@
 
 /// The execution context for the Multicast Listener Discovery (MLD) protocol.
 pub(crate) trait MldContext<BC: MldBindingsContext<Self::DeviceId>>:
-    DeviceIdContext<AnyDevice> + IpDeviceSendContext<Ipv6, BC>
+    DeviceIdContext<AnyDevice> + IpDeviceSendContext<Ipv6, BC> + IpLayerHandler<Ipv6, BC>
 {
     /// Calls the function with a mutable reference to the device's MLD state
     /// and whether or not MLD is enabled for the `device`.
@@ -430,16 +431,22 @@
             .unwrap(),
         );
 
-    core_ctx
-        .send_ip_frame(bindings_ctx, &device, dst_ip.into_specified(), body, None)
-        .map_err(|_| MldError::SendFailure { addr: group_addr.into() })
+    crate::ip::IpLayerHandler::send_ip_frame(
+        core_ctx,
+        bindings_ctx,
+        &device,
+        dst_ip.into_specified(),
+        body,
+        None,
+    )
+    .map_err(|_| MldError::SendFailure { addr: group_addr.into() })
 }
 
 #[cfg(test)]
 mod tests {
 
     use assert_matches::assert_matches;
-    use net_types::ethernet::Mac;
+    use net_types::{ethernet::Mac, ip::Ip as _};
     use packet::{BufferMut, ParseBuffer};
     use packet_formats::{
         ethernet::EthernetFrameLengthCheck,
@@ -458,6 +465,7 @@
             testutil::FakeDeviceId,
             DeviceId,
         },
+        filter::ProofOfEgressCheck,
         ip::{
             device::{
                 config::{IpDeviceConfigurationUpdate, Ipv6DeviceConfigurationUpdate},
@@ -469,6 +477,8 @@
                 QueryReceivedActions, QueryReceivedGenericAction,
             },
             testutil::FakeIpDeviceIdCtx,
+            types::IpTypesIpExt,
+            IpLayerPacketMetadata,
         },
         state::StackStateBuilder,
         testutil::{
@@ -576,6 +586,48 @@
         }
     }
 
+    impl IpLayerHandler<Ipv6, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
+        fn send_ip_packet_from_device<S>(
+            &mut self,
+            _bindings_ctx: &mut FakeBindingsCtxImpl,
+            _meta: crate::ip::SendIpPacketMeta<
+                Ipv6,
+                &Self::DeviceId,
+                Option<SpecifiedAddr<<Ipv6 as Ip>::Addr>>,
+            >,
+            _body: S,
+        ) -> Result<(), S>
+        where
+            S: Serializer + MaybeTransportPacket,
+            S::Buffer: BufferMut,
+        {
+            unimplemented!();
+        }
+
+        fn send_ip_frame<S>(
+            &mut self,
+            bindings_ctx: &mut FakeBindingsCtxImpl,
+            device: &Self::DeviceId,
+            next_hop: SpecifiedAddr<<Ipv6 as Ip>::Addr>,
+            body: S,
+            broadcast: Option<<Ipv6 as IpTypesIpExt>::BroadcastMarker>,
+        ) -> Result<(), S>
+        where
+            S: Serializer + netstack3_filter::IpPacket<Ipv6>,
+            S::Buffer: BufferMut,
+        {
+            crate::ip::send_ip_frame(
+                self,
+                bindings_ctx,
+                device,
+                next_hop,
+                body,
+                broadcast,
+                IpLayerPacketMetadata::default(),
+            )
+        }
+    }
+
     impl IpDeviceSendContext<Ipv6, FakeBindingsCtxImpl> for FakeCoreCtxImpl {
         fn send_ip_frame<S>(
             &mut self,
@@ -584,6 +636,7 @@
             local_addr: SpecifiedAddr<Ipv6Addr>,
             body: S,
             _broadcast: Option<Never>,
+            ProofOfEgressCheck { .. }: ProofOfEgressCheck,
         ) -> Result<(), S>
         where
             S: Serializer,
diff --git a/src/connectivity/network/netstack3/core/src/ip/icmp.rs b/src/connectivity/network/netstack3/core/src/ip/icmp.rs
index e35b54e..8388551 100644
--- a/src/connectivity/network/netstack3/core/src/ip/icmp.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/icmp.rs
@@ -51,7 +51,7 @@
     },
     counters::Counter,
     data_structures::token_bucket::TokenBucket,
-    device::{self, AnyDevice, DeviceIdContext, FrameDestination},
+    device::{self, AnyDevice, DeviceIdContext, FrameDestination, StrongId as _, WeakId as _},
     filter::{MaybeTransportPacket, TransportPacketSerializer},
     ip::{
         device::{
@@ -757,9 +757,8 @@
     type IpSocketsCtx<'a>: TransportIpContext<I, BC>
         + MulticastMembershipHandler<I, BC>
         + DeviceIdContext<AnyDevice, DeviceId = Self::DeviceId, WeakDeviceId = Self::WeakDeviceId>
-        + IcmpStateContext
-        + CounterContext<IcmpTxCounters<I>>
-        + CounterContext<IcmpRxCounters<I>>;
+        + IcmpStateContext;
+
     // TODO(joshlf): If we end up needing to respond to these messages with new
     // outbound packets, then perhaps it'd be worth passing the original buffer
     // so that it can be reused?
@@ -947,7 +946,9 @@
     };
 
     let id = echo_request.message().id();
-    core_ctx.with_icmp_ctx_and_sockets_mut(|core_ctx, sockets| {
+    // NB: We extract out whether a socket was found to update the counter
+    // later, which simplifies the trait bounds on the inner context.
+    let delivered = core_ctx.with_icmp_ctx_and_sockets_mut(|_, sockets| {
             if let Some(conn) = sockets.socket_map.conns().get_by_addr(&ConnAddr {
                 ip: ConnIpAddr {
                     local: (original_src_ip, NonZeroU16::new(id).unwrap()),
@@ -955,9 +956,6 @@
                 },
                 device: None,
             }) {
-                core_ctx.increment(|counters: &IcmpRxCounters<I>| {
-                    &counters.error_delivered_to_socket
-                });
                 // NB: At the moment bindings has no need to consume ICMP
                 // errors, so we swallow them here.
                 debug!(
@@ -966,11 +964,16 @@
                     original_dst_ip,
                     original_src_ip,
                     conn
-                )
+                );
+                true
             } else {
                 trace!("IcmpIpTransportContext::receive_icmp_error: Got ICMP error message for nonexistent ICMP echo socket; either the socket responsible has since been removed, or the error message was sent in error or corrupted");
+                false
             }
-        })
+        });
+    if delivered {
+        core_ctx.increment(|counters: &IcmpRxCounters<I>| &counters.error_delivered_to_socket);
+    }
 }
 
 impl<
@@ -1053,7 +1056,7 @@
                 let id = echo_reply.message().id();
                 let meta = echo_reply.parse_metadata();
                 buffer.undo_parse(meta);
-                let device = core_ctx.downgrade_device_id(device);
+                let device = device.downgrade();
                 receive_icmp_echo_reply(core_ctx, bindings_ctx, src_ip, dst_ip, id, buffer, device);
             }
             Icmpv4Packet::TimestampRequest(timestamp_request) => {
@@ -1846,7 +1849,7 @@
                     let id = echo_reply.message().id();
                     let meta = echo_reply.parse_metadata();
                     buffer.undo_parse(meta);
-                    let device = core_ctx.downgrade_device_id(device);
+                    let device = device.downgrade();
                     receive_icmp_echo_reply(
                         core_ctx,
                         bindings_ctx,
@@ -1954,11 +1957,11 @@
             Some(original_dst_ip),
             original_src_ip,
             I::ICMP_IP_PROTO,
-            DefaultSendOptions,
+            &DefaultSendOptions,
             |src_ip| get_body_from_src_ip(src_ip.into()),
             None,
         )
-        .unwrap_or_else(|(err, DefaultSendOptions)| {
+        .unwrap_or_else(|err| {
             debug!("failed to send ICMP reply: {}", err);
         })
 }
@@ -2767,7 +2770,7 @@
             None,
             original_src_ip,
             Ipv4Proto::Icmp,
-            DefaultSendOptions,
+            &DefaultSendOptions,
             |local_ip| {
                 original_packet.encapsulate(IcmpPacketBuilder::<Ipv4, _>::new(
                     local_ip.addr(),
@@ -2821,7 +2824,7 @@
             None,
             original_src_ip,
             Ipv6Proto::Icmpv6,
-            DefaultSendOptions,
+            &DefaultSendOptions,
             |local_ip| {
                 let icmp_builder = IcmpPacketBuilder::<Ipv6, _>::new(
                     local_ip.addr(),
@@ -2991,10 +2994,8 @@
             return;
         }
     };
-    core_ctx.with_icmp_ctx_and_sockets_mut(|device_ctx, sockets| {
-        if let Some((id, strong_device)) =
-            NonZeroU16::new(id).zip(device_ctx.upgrade_weak_device_id(&device))
-        {
+    core_ctx.with_icmp_ctx_and_sockets_mut(|_core_ctx, sockets| {
+        if let Some((id, strong_device)) = NonZeroU16::new(id).zip(device.upgrade()) {
             let mut addrs_to_search = AddrVecIter::<I, CC::WeakDeviceId, IcmpAddrSpec>::with_device(
                 ConnIpAddr { local: (dst_ip, id), remote: (src_ip, ()) }.into(),
                 device,
@@ -3080,17 +3081,16 @@
             DeviceId,
         },
         ip::{
-            device::{
-                state::{IpDeviceStateBindingsTypes, IpDeviceStateIpExt},
-                IpDeviceAddr,
-            },
+            device::state::IpDeviceStateIpExt,
             icmp::socket::{
                 IcmpEchoSocketApi, IcmpSocketId, IcmpSocketSet, IcmpSocketState, StateContext,
             },
-            socket::testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx},
+            socket::{
+                testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx},
+                IpSock, IpSockCreationError, IpSockSendError, SendOptions,
+            },
             testutil::DualStackSendIpPacketMeta,
-            types::RoutableIpAddr,
-            IpCounters, IpLayerIpExt,
+            types::IpTypesIpExt,
         },
         state::StackStateBuilder,
         testutil::{Ctx, TestIpExt, FAKE_CONFIG_V4, FAKE_CONFIG_V6},
@@ -3100,90 +3100,15 @@
 
     /// The FakeCoreCtx held as the inner state of the [`WrappedFakeCoreCtx`] that
     /// is [`FakeCoreCtx`].
-    type FakeBufferCoreCtx<BT> = FakeCoreCtx<
-        FakeDualStackIpSocketCtx<FakeDeviceId, BT>,
+    type FakeBufferCoreCtx = FakeCoreCtx<
+        FakeDualStackIpSocketCtx<FakeDeviceId>,
         DualStackSendIpPacketMeta<FakeDeviceId>,
         FakeDeviceId,
     >;
 
-    impl<Inner, I: IpLayerIpExt, D, BT: IpDeviceStateBindingsTypes> CounterContext<IpCounters<I>>
-        for Wrapped<
-            Inner,
-            FakeCoreCtx<FakeDualStackIpSocketCtx<D, BT>, DualStackSendIpPacketMeta<D>, D>,
-        >
-    {
-        fn with_counters<O, F: FnOnce(&IpCounters<I>) -> O>(&self, cb: F) -> O {
-            cb(self.as_ref().get_ref().get_common_counters::<I>())
-        }
-    }
-
-    impl<I: Ip, D, BT: IpDeviceStateBindingsTypes> CounterContext<IcmpTxCounters<I>>
-        for FakeCoreCtx<FakeDualStackIpSocketCtx<D, BT>, DualStackSendIpPacketMeta<D>, D>
-    {
-        fn with_counters<O, F: FnOnce(&IcmpTxCounters<I>) -> O>(&self, cb: F) -> O {
-            cb(self.get_ref().icmp_tx_counters::<I>())
-        }
-    }
-
-    impl<Inner, I: Ip, D, BT: IpDeviceStateBindingsTypes> CounterContext<IcmpTxCounters<I>>
-        for Wrapped<
-            Inner,
-            FakeCoreCtx<FakeDualStackIpSocketCtx<D, BT>, DualStackSendIpPacketMeta<D>, D>,
-        >
-    {
-        fn with_counters<O, F: FnOnce(&IcmpTxCounters<I>) -> O>(&self, cb: F) -> O {
-            cb(self.as_ref().get_ref().icmp_tx_counters::<I>())
-        }
-    }
-
-    impl<I: Ip, D, BT: IpDeviceStateBindingsTypes> CounterContext<IcmpRxCounters<I>>
-        for FakeCoreCtx<FakeDualStackIpSocketCtx<D, BT>, DualStackSendIpPacketMeta<D>, D>
-    {
-        fn with_counters<O, F: FnOnce(&IcmpRxCounters<I>) -> O>(&self, cb: F) -> O {
-            cb(self.get_ref().icmp_rx_counters::<I>())
-        }
-    }
-
-    impl<Inner, I: Ip, D, BT: IpDeviceStateBindingsTypes> CounterContext<IcmpRxCounters<I>>
-        for Wrapped<
-            Inner,
-            FakeCoreCtx<FakeDualStackIpSocketCtx<D, BT>, DualStackSendIpPacketMeta<D>, D>,
-        >
-    {
-        fn with_counters<O, F: FnOnce(&IcmpRxCounters<I>) -> O>(&self, cb: F) -> O {
-            cb(self.as_ref().get_ref().icmp_rx_counters::<I>())
-        }
-    }
-
-    impl<D, BT: IpDeviceStateBindingsTypes> CounterContext<NdpCounters>
-        for FakeCoreCtx<FakeDualStackIpSocketCtx<D, BT>, DualStackSendIpPacketMeta<D>, D>
-    {
-        fn with_counters<O, F: FnOnce(&NdpCounters) -> O>(&self, cb: F) -> O {
-            cb(&self.get_ref().ndp_counters)
-        }
-    }
-
-    impl<Inner, D, BT: IpDeviceStateBindingsTypes> CounterContext<NdpCounters>
-        for Wrapped<
-            Inner,
-            FakeCoreCtx<FakeDualStackIpSocketCtx<D, BT>, DualStackSendIpPacketMeta<D>, D>,
-        >
-    {
-        fn with_counters<O, F: FnOnce(&NdpCounters) -> O>(&self, cb: F) -> O {
-            cb(&self.as_ref().get_ref().ndp_counters)
-        }
-    }
-
     /// `FakeCoreCtx` specialized for ICMP.
-    type FakeIcmpCoreCtx<I> = Wrapped<
-        IcmpSocketSet<I, FakeWeakDeviceId<FakeDeviceId>, FakeIcmpBindingsCtx<I>>,
-        FakeIcmpInnerCoreCtx<I>,
-    >;
-
-    type FakeIcmpInnerCoreCtx<I> = Wrapped<
-        FakeIcmpInnerCoreCtxState<I, FakeWeakDeviceId<FakeDeviceId>>,
-        FakeBufferCoreCtx<FakeIcmpBindingsCtx<I>>,
-    >;
+    type FakeIcmpCoreCtx<I> =
+        Wrapped<FakeIcmpCoreCtxState<I, FakeWeakDeviceId<FakeDeviceId>>, FakeBufferCoreCtx>;
 
     /// `FakeBindingsCtx` specialized for ICMP.
     type FakeIcmpBindingsCtx<I> = FakeBindingsCtx<(), (), FakeIcmpBindingsCtxState<I>, ()>;
@@ -3194,23 +3119,31 @@
     pub(super) type FakeIcmpCtx<I> =
         FakeCtxWithCoreCtx<FakeIcmpCoreCtx<I>, (), (), FakeIcmpBindingsCtxState<I>>;
 
-    pub(super) struct FakeIcmpInnerCoreCtxState<I: socket::IpExt, D: device::WeakId> {
+    pub(super) struct FakeIcmpCoreCtxState<I: socket::IpExt, D: device::WeakId> {
         bound_socket_map_and_allocator: BoundSockets<I, D, FakeIcmpBindingsCtx<I>>,
+        socket_set: IcmpSocketSet<I, FakeWeakDeviceId<FakeDeviceId>, FakeIcmpBindingsCtx<I>>,
         error_send_bucket: TokenBucket<FakeInstant>,
         receive_icmp_error: Vec<I::ErrorCode>,
+        rx_counters: IcmpRxCounters<I>,
+        tx_counters: IcmpTxCounters<I>,
+        ndp_counters: NdpCounters,
     }
 
-    impl<I: socket::IpExt, D: device::WeakId> FakeIcmpInnerCoreCtxState<I, D> {
+    impl<I: socket::IpExt, D: device::WeakId> FakeIcmpCoreCtxState<I, D> {
         fn with_errors_per_second(errors_per_second: u64) -> Self {
             Self {
+                socket_set: Default::default(),
                 bound_socket_map_and_allocator: Default::default(),
                 error_send_bucket: TokenBucket::new(errors_per_second),
                 receive_icmp_error: Default::default(),
+                rx_counters: Default::default(),
+                tx_counters: Default::default(),
+                ndp_counters: Default::default(),
             }
         }
     }
 
-    impl<I: TestIpExt + socket::IpExt> Default for FakeIcmpInnerCoreCtx<I> {
+    impl<I: TestIpExt + socket::IpExt> Default for FakeIcmpCoreCtx<I> {
         fn default() -> Self {
             Wrapped::with_inner_and_outer_state(
                 FakeDualStackIpSocketCtx::new(core::iter::once(FakeDeviceConfig {
@@ -3218,21 +3151,37 @@
                     local_ips: vec![I::FAKE_CONFIG.local_ip],
                     remote_ips: vec![I::FAKE_CONFIG.remote_ip],
                 })),
-                FakeIcmpInnerCoreCtxState::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND),
+                FakeIcmpCoreCtxState::with_errors_per_second(DEFAULT_ERRORS_PER_SECOND),
             )
         }
     }
 
-    impl<I: datagram::IpExt> IcmpStateContext for FakeIcmpInnerCoreCtx<I> {}
-    impl<BT: IpDeviceStateBindingsTypes> IcmpStateContext for FakeBufferCoreCtx<BT> {}
     impl<I: datagram::IpExt> IcmpStateContext for FakeIcmpCoreCtx<I> {}
-    impl IcmpStateContext for StackState<crate::testutil::FakeBindingsCtx> {}
+    impl IcmpStateContext for FakeBufferCoreCtx {}
+
+    impl<I: socket::IpExt> CounterContext<IcmpRxCounters<I>> for FakeIcmpCoreCtx<I> {
+        fn with_counters<O, F: FnOnce(&IcmpRxCounters<I>) -> O>(&self, cb: F) -> O {
+            cb(&self.outer.rx_counters)
+        }
+    }
+
+    impl<I: socket::IpExt> CounterContext<IcmpTxCounters<I>> for FakeIcmpCoreCtx<I> {
+        fn with_counters<O, F: FnOnce(&IcmpTxCounters<I>) -> O>(&self, cb: F) -> O {
+            cb(&self.outer.tx_counters)
+        }
+    }
+
+    impl<I: socket::IpExt> CounterContext<NdpCounters> for FakeIcmpCoreCtx<I> {
+        fn with_counters<O, F: FnOnce(&NdpCounters) -> O>(&self, cb: F) -> O {
+            cb(&self.outer.ndp_counters)
+        }
+    }
 
     impl<I: datagram::IpExt + IpDeviceStateIpExt> InnerIcmpContext<I, FakeIcmpBindingsCtx<I>>
-        for FakeIcmpInnerCoreCtx<I>
+        for FakeIcmpCoreCtx<I>
     {
         type DualStackContext = UninstantiableWrapper<Self>;
-        type IpSocketsCtx<'a> = FakeBufferCoreCtx<FakeIcmpBindingsCtx<I>>;
+        type IpSocketsCtx<'a> = FakeBufferCoreCtx;
         fn receive_icmp_error(
             &mut self,
             _bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
@@ -3243,9 +3192,8 @@
             original_body: &[u8],
             err: I::ErrorCode,
         ) {
-            let Self { outer, inner } = self;
-            inner.increment(|counters: &IcmpRxCounters<I>| &counters.error);
-            outer.receive_icmp_error.push(err);
+            self.increment(|counters: &IcmpRxCounters<I>| &counters.error);
+            self.outer.receive_icmp_error.push(err);
             if original_proto == I::ICMP_IP_PROTO {
                 receive_ip_transport_icmp_error(
                     self,
@@ -3291,10 +3239,8 @@
         }
     }
 
-    impl<I: datagram::IpExt + IpDeviceStateIpExt> StateContext<I, FakeIcmpBindingsCtx<I>>
-        for FakeIcmpCoreCtx<I>
-    {
-        type SocketStateCtx<'a> = FakeIcmpInnerCoreCtx<I>;
+    impl<I: datagram::IpExt> StateContext<I, FakeIcmpBindingsCtx<I>> for FakeIcmpCoreCtx<I> {
+        type SocketStateCtx<'a> = FakeIcmpCoreCtx<I>;
 
         fn with_all_sockets_mut<
             O,
@@ -3303,7 +3249,7 @@
             &mut self,
             cb: F,
         ) -> O {
-            cb(&mut self.outer)
+            cb(&mut self.outer.socket_set)
         }
 
         fn with_all_sockets<
@@ -3313,7 +3259,7 @@
             &mut self,
             cb: F,
         ) -> O {
-            cb(&self.outer)
+            cb(&self.outer.socket_set)
         }
 
         fn with_socket_state<
@@ -3327,7 +3273,7 @@
             id: &IcmpSocketId<I, Self::WeakDeviceId, FakeIcmpBindingsCtx<I>>,
             cb: F,
         ) -> O {
-            cb(&mut self.inner, &id.get())
+            cb(self, &id.get())
         }
 
         fn with_socket_state_mut<
@@ -3341,14 +3287,14 @@
             id: &IcmpSocketId<I, Self::WeakDeviceId, FakeIcmpBindingsCtx<I>>,
             cb: F,
         ) -> O {
-            cb(&mut self.inner, &mut id.get_mut())
+            cb(self, &mut id.get_mut())
         }
 
         fn with_bound_state_context<O, F: FnOnce(&mut Self::SocketStateCtx<'_>) -> O>(
             &mut self,
             cb: F,
         ) -> O {
-            cb(&mut self.inner)
+            cb(self)
         }
 
         fn for_each_socket<
@@ -3361,10 +3307,15 @@
             &mut self,
             mut cb: F,
         ) {
-            self.outer.keys().for_each(|id| {
-                let id = IcmpSocketId::from(id.clone());
-                cb(&mut self.inner, &id, &id.get());
-            })
+            let socks = self
+                .outer
+                .socket_set
+                .keys()
+                .map(|id| IcmpSocketId::from(id.clone()))
+                .collect::<Vec<_>>();
+            for id in socks {
+                cb(self, &id, &id.get());
+            }
         }
     }
 
@@ -4024,48 +3975,46 @@
         _marker: core::marker::PhantomData<I>,
     }
 
-    impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpInnerCoreCtx<Ipv4> {
+    impl InnerIcmpv4Context<FakeIcmpBindingsCtx<Ipv4>> for FakeIcmpCoreCtx<Ipv4> {
         fn should_send_timestamp_reply(&self) -> bool {
             false
         }
     }
-    impl_pmtu_handler!(FakeIcmpInnerCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
-    impl_pmtu_handler!(FakeIcmpInnerCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
+    impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv4>, FakeIcmpBindingsCtx<Ipv4>, Ipv4);
+    impl_pmtu_handler!(FakeIcmpCoreCtx<Ipv6>, FakeIcmpBindingsCtx<Ipv6>, Ipv6);
 
-    impl<I: datagram::IpExt + IpDeviceStateIpExt>
-        crate::ip::socket::IpSocketContext<I, FakeIcmpBindingsCtx<I>> for FakeIcmpInnerCoreCtx<I>
+    impl<I: datagram::IpExt> crate::ip::socket::IpSocketHandler<I, FakeIcmpBindingsCtx<I>>
+        for FakeIcmpCoreCtx<I>
     {
-        fn lookup_route(
+        fn new_ip_socket(
             &mut self,
             bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
-            device: Option<&FakeDeviceId>,
-            local_ip: Option<IpDeviceAddr<I::Addr>>,
-            addr: RoutableIpAddr<I::Addr>,
-        ) -> Result<crate::ip::types::ResolvedRoute<I, FakeDeviceId>, crate::ip::ResolveRouteError>
-        {
-            self.inner.lookup_route(bindings_ctx, device, local_ip, addr)
+            device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
+            local_ip: Option<SocketIpAddr<I::Addr>>,
+            remote_ip: SocketIpAddr<I::Addr>,
+            proto: I::Proto,
+        ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError> {
+            self.inner.new_ip_socket(bindings_ctx, device, local_ip, remote_ip, proto)
         }
 
-        fn send_ip_packet<S>(
+        fn send_ip_packet<S, O>(
             &mut self,
             bindings_ctx: &mut FakeIcmpBindingsCtx<I>,
-            meta: SendIpPacketMeta<I, &FakeDeviceId, SpecifiedAddr<I::Addr>>,
+            socket: &IpSock<I, Self::WeakDeviceId>,
             body: S,
-        ) -> Result<(), S>
+            mtu: Option<u32>,
+            options: &O,
+        ) -> Result<(), (S, IpSockSendError)>
         where
-            S: Serializer + MaybeTransportPacket,
+            S: TransportPacketSerializer,
             S::Buffer: BufferMut,
+            O: SendOptions<I, Self::WeakDeviceId>,
         {
-            crate::ip::socket::IpSocketContext::<_, _>::send_ip_packet(
-                &mut self.inner,
-                bindings_ctx,
-                meta,
-                body,
-            )
+            self.inner.send_ip_packet(bindings_ctx, socket, body, mtu, options)
         }
     }
 
-    impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpInnerCoreCtx<Ipv6> {
+    impl IpDeviceHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
         fn is_router_device(&mut self, _device_id: &Self::DeviceId) -> bool {
             unimplemented!()
         }
@@ -4075,7 +4024,7 @@
         }
     }
 
-    impl IpDeviceStateContext<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpInnerCoreCtx<Ipv6> {
+    impl IpDeviceStateContext<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
         fn with_next_packet_id<O, F: FnOnce(&()) -> O>(&self, cb: F) -> O {
             cb(&())
         }
@@ -4101,7 +4050,7 @@
         }
     }
 
-    impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpInnerCoreCtx<Ipv6> {
+    impl Ipv6DeviceHandler<FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
         type LinkLayerAddr = [u8; 0];
 
         fn get_link_layer_addr_bytes(&mut self, _device_id: &Self::DeviceId) -> Option<[u8; 0]> {
@@ -4163,7 +4112,7 @@
         }
     }
 
-    impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpInnerCoreCtx<Ipv6> {
+    impl IpLayerHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
         fn send_ip_packet_from_device<S>(
             &mut self,
             _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
@@ -4172,9 +4121,24 @@
         ) -> Result<(), S> {
             unimplemented!()
         }
+
+        fn send_ip_frame<S>(
+            &mut self,
+            _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
+            _device: &Self::DeviceId,
+            _next_hop: SpecifiedAddr<<Ipv6 as Ip>::Addr>,
+            _body: S,
+            _broadcast: Option<<Ipv6 as IpTypesIpExt>::BroadcastMarker>,
+        ) -> Result<(), S>
+        where
+            S: Serializer,
+            S::Buffer: BufferMut,
+        {
+            unimplemented!()
+        }
     }
 
-    impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpInnerCoreCtx<Ipv6> {
+    impl NudIpHandler<Ipv6, FakeIcmpBindingsCtx<Ipv6>> for FakeIcmpCoreCtx<Ipv6> {
         fn handle_neighbor_probe(
             &mut self,
             _bindings_ctx: &mut FakeIcmpBindingsCtx<Ipv6>,
@@ -4251,7 +4215,7 @@
                 .unwrap();
             let FakeCtxWithCoreCtx { core_ctx, bindings_ctx } = &mut ctx;
             <IcmpIpTransportContext as IpTransportContext<Ipv4, _, _>>::receive_ip_packet(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 &FakeDeviceId,
                 FAKE_CONFIG_V4.remote_ip.get(),
@@ -4271,22 +4235,14 @@
             for (ctr, expected) in assert_counters {
                 let actual = match *ctr {
                     "InnerIcmpContext::receive_icmp_error" => {
-                        core_ctx.inner.inner.state.icmp_rx_counters::<Ipv4>().error.get()
+                        core_ctx.outer.rx_counters.error.get()
                     }
-                    "IcmpIpTransportContext::receive_icmp_error" => core_ctx
-                        .inner
-                        .inner
-                        .state
-                        .icmp_rx_counters::<Ipv4>()
-                        .error_delivered_to_transport_layer
-                        .get(),
-                    "IcmpEchoBindingsContext::receive_icmp_error" => core_ctx
-                        .inner
-                        .inner
-                        .state
-                        .icmp_rx_counters::<Ipv4>()
-                        .error_delivered_to_socket
-                        .get(),
+                    "IcmpIpTransportContext::receive_icmp_error" => {
+                        core_ctx.outer.rx_counters.error_delivered_to_transport_layer.get()
+                    }
+                    "IcmpEchoBindingsContext::receive_icmp_error" => {
+                        core_ctx.outer.rx_counters.error_delivered_to_socket.get()
+                    }
                     c => panic!("unrecognized counter: {c}"),
                 };
                 assert_eq!(actual, *expected, "wrong count for {ctr}");
@@ -4334,7 +4290,7 @@
                 let err = Icmpv4ErrorCode::DestUnreachable(
                     Icmpv4DestUnreachableCode::DestNetworkUnreachable,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4349,7 +4305,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4366,7 +4322,7 @@
                 let err = Icmpv4ErrorCode::ParameterProblem(
                     Icmpv4ParameterProblemCode::PointerIndicatesError,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4400,7 +4356,7 @@
                 let err = Icmpv4ErrorCode::DestUnreachable(
                     Icmpv4DestUnreachableCode::DestNetworkUnreachable,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4415,7 +4371,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4432,7 +4388,7 @@
                 let err = Icmpv4ErrorCode::ParameterProblem(
                     Icmpv4ParameterProblemCode::PointerIndicatesError,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4464,7 +4420,7 @@
                 let err = Icmpv4ErrorCode::DestUnreachable(
                     Icmpv4DestUnreachableCode::DestNetworkUnreachable,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4479,7 +4435,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv4ErrorCode::TimeExceeded(Icmpv4TimeExceededCode::TtlExpired);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4496,7 +4452,7 @@
                 let err = Icmpv4ErrorCode::ParameterProblem(
                     Icmpv4ParameterProblemCode::PointerIndicatesError,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
     }
@@ -4544,7 +4500,7 @@
                 .unwrap();
             let FakeCtxWithCoreCtx { core_ctx, bindings_ctx } = &mut ctx;
             <IcmpIpTransportContext as IpTransportContext<Ipv6, _, _>>::receive_ip_packet(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 &FakeDeviceId,
                 FAKE_CONFIG_V6.remote_ip.get().try_into().unwrap(),
@@ -4564,29 +4520,17 @@
             for (ctr, count) in assert_counters {
                 match *ctr {
                     "InnerIcmpContext::receive_icmp_error" => assert_eq!(
-                        core_ctx.inner.inner.state.icmp_rx_counters::<Ipv6>().error.get(),
+                        core_ctx.outer.rx_counters.error.get(),
                         *count,
                         "wrong count for counter {ctr}",
                     ),
                     "IcmpIpTransportContext::receive_icmp_error" => assert_eq!(
-                        core_ctx
-                            .inner
-                            .inner
-                            .state
-                            .icmp_rx_counters::<Ipv6>()
-                            .error_delivered_to_transport_layer
-                            .get(),
+                        core_ctx.outer.rx_counters.error_delivered_to_transport_layer.get(),
                         *count,
                         "wrong count for counter {ctr}",
                     ),
                     "IcmpEchoBindingsContext::receive_icmp_error" => assert_eq!(
-                        core_ctx
-                            .inner
-                            .inner
-                            .state
-                            .icmp_rx_counters::<Ipv6>()
-                            .error_delivered_to_socket
-                            .get(),
+                        core_ctx.outer.rx_counters.error_delivered_to_socket.get(),
                         *count,
                         "wrong count for counter {ctr}",
                     ),
@@ -4634,7 +4578,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4649,7 +4593,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4666,7 +4610,7 @@
                 let err = Icmpv6ErrorCode::ParameterProblem(
                     Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4698,7 +4642,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4713,7 +4657,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4730,7 +4674,7 @@
                 let err = Icmpv6ErrorCode::ParameterProblem(
                     Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4760,7 +4704,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv6ErrorCode::DestUnreachable(Icmpv6DestUnreachableCode::NoRoute);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4775,7 +4719,7 @@
             ],
             |FakeCtxWithCoreCtx { core_ctx, bindings_ctx: _ }| {
                 let err = Icmpv6ErrorCode::TimeExceeded(Icmpv6TimeExceededCode::HopLimitExceeded);
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
 
@@ -4792,7 +4736,7 @@
                 let err = Icmpv6ErrorCode::ParameterProblem(
                     Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
                 );
-                assert_eq!(core_ctx.inner.outer.receive_icmp_error, [err]);
+                assert_eq!(core_ctx.outer.receive_icmp_error, [err]);
             },
         );
     }
@@ -4806,7 +4750,7 @@
             FakeCtxWithCoreCtx { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
         ) {
             send_icmpv4_ttl_expired(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 &FakeDeviceId,
                 Some(FrameDestination::Individual { local: true }),
@@ -4824,7 +4768,7 @@
             FakeCtxWithCoreCtx { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
         ) {
             send_icmpv4_parameter_problem(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 &FakeDeviceId,
                 Some(FrameDestination::Individual { local: true }),
@@ -4843,7 +4787,7 @@
             FakeCtxWithCoreCtx { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv4>,
         ) {
             send_icmpv4_dest_unreachable(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 Some(&FakeDeviceId),
                 Some(FrameDestination::Individual { local: true }),
@@ -4861,7 +4805,7 @@
             FakeCtxWithCoreCtx { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
         ) {
             send_icmpv6_ttl_expired(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 &FakeDeviceId,
                 Some(FrameDestination::Individual { local: true }),
@@ -4878,7 +4822,7 @@
             FakeCtxWithCoreCtx { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
         ) {
             send_icmpv6_packet_too_big(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 &FakeDeviceId,
                 Some(FrameDestination::Individual { local: true }),
@@ -4896,7 +4840,7 @@
             FakeCtxWithCoreCtx { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
         ) {
             send_icmpv6_parameter_problem(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 &FakeDeviceId,
                 Some(FrameDestination::Individual { local: true }),
@@ -4914,7 +4858,7 @@
             FakeCtxWithCoreCtx { core_ctx, bindings_ctx }: &mut FakeIcmpCtx<Ipv6>,
         ) {
             send_icmpv6_dest_unreachable(
-                &mut core_ctx.inner,
+                core_ctx,
                 bindings_ctx,
                 Some(&FakeDeviceId),
                 Some(FrameDestination::Individual { local: true }),
@@ -4955,43 +4899,31 @@
 
             for i in 0..ERRORS_PER_SECOND {
                 send(&mut ctx);
-                assert_eq!(
-                    ctx.core_ctx.inner.inner.state.icmp_tx_counters::<I>().error.get(),
-                    i + 1
-                );
+                assert_eq!(ctx.core_ctx.outer.tx_counters.error.get(), i + 1);
             }
 
-            assert_eq!(
-                ctx.core_ctx.inner.inner.state.icmp_tx_counters::<I>().error.get(),
-                ERRORS_PER_SECOND
-            );
+            assert_eq!(ctx.core_ctx.outer.tx_counters.error.get(), ERRORS_PER_SECOND);
             send(&mut ctx);
-            assert_eq!(
-                ctx.core_ctx.inner.inner.state.icmp_tx_counters::<I>().error.get(),
-                ERRORS_PER_SECOND
-            );
+            assert_eq!(ctx.core_ctx.outer.tx_counters.error.get(), ERRORS_PER_SECOND);
 
             // Test that, if we set a rate of 0, we are not able to send any
             // error messages regardless of how much time has elapsed.
 
             let mut ctx = with_errors_per_second(0);
             send(&mut ctx);
-            assert_eq!(ctx.core_ctx.inner.inner.state.icmp_tx_counters::<I>().error.get(), 0);
+            assert_eq!(ctx.core_ctx.outer.tx_counters.error.get(), 0);
             ctx.bindings_ctx.sleep_skip_timers(Duration::from_secs(1));
             send(&mut ctx);
-            assert_eq!(ctx.core_ctx.inner.inner.state.icmp_tx_counters::<I>().error.get(), 0);
+            assert_eq!(ctx.core_ctx.outer.tx_counters.error.get(), 0);
             ctx.bindings_ctx.sleep_skip_timers(Duration::from_secs(1));
             send(&mut ctx);
-            assert_eq!(ctx.core_ctx.inner.inner.state.icmp_tx_counters::<I>().error.get(), 0);
+            assert_eq!(ctx.core_ctx.outer.tx_counters.error.get(), 0);
         }
 
         fn with_errors_per_second_v4(errors_per_second: u64) -> FakeIcmpCtx<Ipv4> {
             FakeCtxWithCoreCtx::with_core_ctx(Wrapped {
-                outer: Default::default(),
-                inner: Wrapped {
-                    outer: FakeIcmpInnerCoreCtxState::with_errors_per_second(errors_per_second),
-                    inner: Default::default(),
-                },
+                outer: FakeIcmpCoreCtxState::with_errors_per_second(errors_per_second),
+                inner: Default::default(),
             })
         }
         run_test::<Ipv4, _, _>(with_errors_per_second_v4, send_icmpv4_ttl_expired_helper);
@@ -5000,11 +4932,8 @@
 
         fn with_errors_per_second_v6(errors_per_second: u64) -> FakeIcmpCtx<Ipv6> {
             FakeCtxWithCoreCtx::with_core_ctx(Wrapped {
-                outer: Default::default(),
-                inner: Wrapped {
-                    outer: FakeIcmpInnerCoreCtxState::with_errors_per_second(errors_per_second),
-                    inner: Default::default(),
-                },
+                outer: FakeIcmpCoreCtxState::with_errors_per_second(errors_per_second),
+                inner: Default::default(),
             })
         }
 
diff --git a/src/connectivity/network/netstack3/core/src/ip/icmp/socket.rs b/src/connectivity/network/netstack3/core/src/ip/icmp/socket.rs
index 9633dfe..5f99935 100644
--- a/src/connectivity/network/netstack3/core/src/ip/icmp/socket.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/icmp/socket.rs
@@ -9,7 +9,6 @@
     borrow::Borrow,
     convert::Infallible as Never,
     fmt::Debug,
-    hash::Hash,
     marker::PhantomData,
     num::{NonZeroU16, NonZeroU8},
 };
@@ -112,7 +111,7 @@
 impl<I: IpExt, D: device::WeakId, BT: IcmpEchoBindingsTypes> Debug for IcmpSocketId<I, D, BT> {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let Self(rc) = self;
-        f.debug_tuple("IcmpSocketId").field(&StrongRc::ptr_debug(rc)).finish()
+        f.debug_tuple("IcmpSocketId").field(&StrongRc::debug_id(rc)).finish()
     }
 }
 
@@ -162,7 +161,7 @@
 impl<I: IpExt, D: device::WeakId, BT: IcmpEchoBindingsTypes> Debug for WeakIcmpSocketId<I, D, BT> {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let Self(rc) = self;
-        f.debug_tuple("WeakIcmpSocketId").field(&rc.ptr_debug()).finish()
+        f.debug_tuple("WeakIcmpSocketId").field(&rc.debug_id()).finish()
     }
 }
 
@@ -183,11 +182,11 @@
     ip: S,
 }
 
-impl<'a, A: IpAddress, D> From<&'a IcmpConn<IpSock<A::Version, D, ()>>> for IcmpAddr<A>
+impl<'a, A: IpAddress, D> From<&'a IcmpConn<IpSock<A::Version, D>>> for IcmpAddr<A>
 where
     A::Version: IpExt,
 {
-    fn from(conn: &'a IcmpConn<IpSock<A::Version, D, ()>>) -> IcmpAddr<A> {
+    fn from(conn: &'a IcmpConn<IpSock<A::Version, D>>) -> IcmpAddr<A> {
         IcmpAddr {
             local_addr: *conn.ip.local_ip(),
             remote_addr: *conn.ip.remote_ip(),
@@ -299,7 +298,7 @@
 
     type SocketId<I: datagram::IpExt, D: device::WeakId> = IcmpSocketId<I, D, BT>;
 
-    type OtherStackIpOptions<I: datagram::IpExt> = ();
+    type OtherStackIpOptions<I: datagram::IpExt, D: device::WeakId> = ();
 
     type SharingState = ();
 
@@ -376,14 +375,13 @@
         <Self::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
     >;
 
-    type ConnState<I: datagram::IpExt, D: Debug + Eq + Hash + Send + Sync> =
-        datagram::ConnState<I, I, D, Self>;
+    type ConnState<I: datagram::IpExt, D: device::WeakId> = datagram::ConnState<I, I, D, Self>;
     // Store the remote port/id set by `connect`. This does not participate in
     // demuxing, so not part of the socketmap, but we need to store it so that
     // it can be reported later.
     type ConnStateExtra = u16;
 
-    fn conn_info_from_state<I: IpExt, D: Clone + Debug + Eq + Hash + Send + Sync>(
+    fn conn_info_from_state<I: IpExt, D: device::WeakId>(
         datagram::ConnState { addr: ConnAddr { ip, device }, extra, .. }: &Self::ConnState<I, D>,
     ) -> datagram::ConnInfo<I::Addr, D> {
         let ConnInfoAddr { local: (local_ip, local_identifier), remote: (remote_ip, ()) } =
diff --git a/src/connectivity/network/netstack3/core/src/ip/reassembly.rs b/src/connectivity/network/netstack3/core/src/ip/reassembly.rs
index 72fd0d0..d5b5d6c 100644
--- a/src/connectivity/network/netstack3/core/src/ip/reassembly.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/reassembly.rs
@@ -820,7 +820,7 @@
         ip::{Ipv4, Ipv6},
         Witness,
     };
-    use netstack3_base::{testutil::LocalTimerHeapTestExt as _, IntoCoreTimerCtx};
+    use netstack3_base::IntoCoreTimerCtx;
     use packet::{Buf, ParseBuffer, Serializer};
     use packet_formats::{
         ip::{IpProto, Ipv6ExtHdrType},
diff --git a/src/connectivity/network/netstack3/core/src/ip/socket.rs b/src/connectivity/network/netstack3/core/src/ip/socket.rs
index df0745c..31c03c5 100644
--- a/src/connectivity/network/netstack3/core/src/ip/socket.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/socket.rs
@@ -10,22 +10,22 @@
 
 use net_types::{
     ip::{Ip, Ipv6Addr, Ipv6SourceAddr, Mtu},
-    SpecifiedAddr,
+    MulticastAddress, SpecifiedAddr,
 };
 use packet::{BufferMut, SerializeError};
 use thiserror::Error;
 
 use crate::{
     context::{CounterContext, InstantContext, NonTestCtxMarker, TracingContext},
-    device::{AnyDevice, DeviceIdContext},
+    device::{self, AnyDevice, DeviceIdContext, WeakId as _},
     filter::{
         FilterBindingsTypes, FilterHandler as _, FilterHandlerProvider, TransportPacketSerializer,
     },
     ip::{
         device::{state::IpDeviceStateIpExt, IpDeviceAddr},
-        types::{NextHop, ResolvedRoute, RoutableIpAddr},
-        EitherDeviceId, IpCounters, IpDeviceContext, IpExt, IpLayerIpExt, ResolveRouteError,
-        SendIpPacketMeta,
+        types::{ResolvedRoute, RoutableIpAddr},
+        EitherDeviceId, IpCounters, IpDeviceContext, IpExt, IpLayerIpExt, IpLayerPacketMetadata,
+        ResolveRouteError, SendIpPacketMeta,
     },
     socket::address::SocketIpAddr,
     trace_duration,
@@ -47,15 +47,14 @@
     /// `new_ip_socket` returns an error if no route to the remote was found in
     /// the forwarding table or if the given local IP address is not valid for
     /// the found route.
-    fn new_ip_socket<O>(
+    fn new_ip_socket(
         &mut self,
         bindings_ctx: &mut BC,
         device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
         local_ip: Option<SocketIpAddr<I::Addr>>,
         remote_ip: SocketIpAddr<I::Addr>,
         proto: I::Proto,
-        options: O,
-    ) -> Result<IpSock<I, Self::WeakDeviceId, O>, (IpSockCreationError, O)>;
+    ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError>;
 
     /// Sends an IP packet on a socket.
     ///
@@ -72,14 +71,15 @@
     fn send_ip_packet<S, O>(
         &mut self,
         bindings_ctx: &mut BC,
-        socket: &IpSock<I, Self::WeakDeviceId, O>,
+        socket: &IpSock<I, Self::WeakDeviceId>,
         body: S,
         mtu: Option<u32>,
+        options: &O,
     ) -> Result<(), (S, IpSockSendError)>
     where
         S: TransportPacketSerializer,
         S::Buffer: BufferMut,
-        O: SendOptions<I>;
+        O: SendOptions<I, Self::WeakDeviceId>;
 
     /// Creates a temporary IP socket and sends a single packet on it.
     ///
@@ -110,27 +110,23 @@
         local_ip: Option<IpDeviceAddr<I::Addr>>,
         remote_ip: RoutableIpAddr<I::Addr>,
         proto: I::Proto,
-        options: O,
+        options: &O,
         get_body_from_src_ip: F,
         mtu: Option<u32>,
-    ) -> Result<(), SendOneShotIpPacketError<O, E>>
+    ) -> Result<(), SendOneShotIpPacketError<E>>
     where
         S: TransportPacketSerializer,
         S::Buffer: BufferMut,
         F: FnOnce(SocketIpAddr<I::Addr>) -> Result<S, E>,
-        O: SendOptions<I>,
+        O: SendOptions<I, Self::WeakDeviceId>,
     {
         let tmp = self
-            .new_ip_socket(bindings_ctx, device, local_ip, remote_ip, proto, options)
-            .map_err(|(err, options)| SendOneShotIpPacketError::CreateAndSendError {
-                err: err.into(),
-                options,
-            })?;
+            .new_ip_socket(bindings_ctx, device, local_ip, remote_ip, proto)
+            .map_err(|err| SendOneShotIpPacketError::CreateAndSendError { err: err.into() })?;
         let packet = get_body_from_src_ip(*tmp.local_ip())
             .map_err(SendOneShotIpPacketError::SerializeError)?;
-        self.send_ip_packet(bindings_ctx, &tmp, packet, mtu).map_err(|(_body, err)| {
-            let IpSock { options, definition: _ } = tmp;
-            SendOneShotIpPacketError::CreateAndSendError { err: err.into(), options }
+        self.send_ip_packet(bindings_ctx, &tmp, packet, mtu, options).map_err(|(_body, err)| {
+            SendOneShotIpPacketError::CreateAndSendError { err: err.into() }
         })
     }
 
@@ -142,15 +138,15 @@
         local_ip: Option<SocketIpAddr<I::Addr>>,
         remote_ip: SocketIpAddr<I::Addr>,
         proto: I::Proto,
-        options: O,
+        options: &O,
         get_body_from_src_ip: F,
         mtu: Option<u32>,
-    ) -> Result<(), (IpSockCreateAndSendError, O)>
+    ) -> Result<(), IpSockCreateAndSendError>
     where
         S: TransportPacketSerializer,
         S::Buffer: BufferMut,
         F: FnOnce(SocketIpAddr<I::Addr>) -> S,
-        O: SendOptions<I>,
+        O: SendOptions<I, Self::WeakDeviceId>,
     {
         self.send_oneshot_ip_packet_with_fallible_serializer(
             bindings_ctx,
@@ -163,7 +159,7 @@
             mtu,
         )
         .map_err(|err| match err {
-            SendOneShotIpPacketError::CreateAndSendError { err, options } => (err, options),
+            SendOneShotIpPacketError::CreateAndSendError { err } => err,
             SendOneShotIpPacketError::SerializeError(infallible) => match infallible {},
         })
     }
@@ -204,8 +200,8 @@
 }
 
 #[derive(Debug)]
-pub enum SendOneShotIpPacketError<O, E> {
-    CreateAndSendError { err: IpSockCreateAndSendError, options: O },
+pub enum SendOneShotIpPacketError<E> {
+    CreateAndSendError { err: IpSockCreateAndSendError },
     SerializeError(E),
 }
 
@@ -279,10 +275,10 @@
     ///
     /// This corresponds to the GET_MAXSIZES call described in:
     /// https://www.rfc-editor.org/rfc/rfc1122#section-3.4
-    fn get_mms<O: SendOptions<I>>(
+    fn get_mms(
         &mut self,
         bindings_ctx: &mut BC,
-        ip_sock: &IpSock<I, Self::WeakDeviceId, O>,
+        ip_sock: &IpSock<I, Self::WeakDeviceId>,
     ) -> Result<Mms, MmsError>;
 }
 
@@ -297,16 +293,11 @@
 /// An IP socket.
 #[derive(Clone, Debug)]
 #[cfg_attr(test, derive(PartialEq))]
-pub struct IpSock<I: IpExt, D, O> {
+pub struct IpSock<I: IpExt, D> {
     /// The definition of the socket.
     ///
     /// This does not change for the lifetime of the socket.
     definition: IpSockDefinition<I, D>,
-    /// Options set on the socket that are independent of the socket definition.
-    ///
-    /// TODO(https://fxbug.dev/42115343): use this to record multicast options.
-    #[allow(unused)]
-    options: O,
 }
 
 /// The definition of an IP socket.
@@ -329,7 +320,7 @@
     proto: I::Proto,
 }
 
-impl<I: IpExt, D, O> IpSock<I, D, O> {
+impl<I: IpExt, D> IpSock<I, D> {
     pub(crate) fn local_ip(&self) -> &SocketIpAddr<I::Addr> {
         &self.definition.local_ip
     }
@@ -345,23 +336,6 @@
     pub(crate) fn proto(&self) -> I::Proto {
         self.definition.proto
     }
-
-    pub(crate) fn options_mut(&mut self) -> &mut O {
-        &mut self.options
-    }
-
-    /// Swaps in `new_options` for the existing options and returns the old
-    /// options.
-    pub(crate) fn replace_options(&mut self, new_options: O) -> O {
-        core::mem::replace(self.options_mut(), new_options)
-    }
-
-    pub(crate) fn take_options(&mut self) -> O
-    where
-        O: Default,
-    {
-        self.replace_options(Default::default())
-    }
 }
 
 // TODO(joshlf): Once we support configuring transport-layer protocols using
@@ -400,6 +374,7 @@
         bindings_ctx: &mut BC,
         meta: SendIpPacketMeta<I, &Self::DeviceId, SpecifiedAddr<I::Addr>>,
         body: S,
+        packet_metadata: IpLayerPacketMetadata<I, BC>,
     ) -> Result<(), S>
     where
         S: TransportPacketSerializer,
@@ -410,79 +385,48 @@
 where
     I: IpLayerIpExt + IpDeviceStateIpExt,
     BC: IpSocketBindingsContext,
-    CC: IpSocketContext<I, BC> + CounterContext<IpCounters<I>>,
+    CC: IpSocketContext<I, BC> + CounterContext<IpCounters<I>> + NonTestCtxMarker,
     CC::DeviceId: crate::filter::InterfaceProperties<BC::DeviceClass>,
 {
-    fn new_ip_socket<O>(
+    fn new_ip_socket(
         &mut self,
         bindings_ctx: &mut BC,
         device: Option<EitherDeviceId<&CC::DeviceId, &CC::WeakDeviceId>>,
         local_ip: Option<SocketIpAddr<I::Addr>>,
         remote_ip: SocketIpAddr<I::Addr>,
         proto: I::Proto,
-        options: O,
-    ) -> Result<IpSock<I, CC::WeakDeviceId, O>, (IpSockCreationError, O)> {
-        let device = if let Some(device) = device.as_ref() {
-            if let Some(device) = device.as_strong_ref(self) {
-                Some(device)
-            } else {
-                return Err((IpSockCreationError::Route(ResolveRouteError::Unreachable), options));
-            }
-        } else {
-            None
-        };
-
+    ) -> Result<IpSock<I, CC::WeakDeviceId>, IpSockCreationError> {
+        let device = device
+            .as_ref()
+            .map(|d| d.as_strong_ref().ok_or(ResolveRouteError::Unreachable))
+            .transpose()?;
         let device = device.as_ref().map(|d| d.as_ref());
 
         // Make sure the remote is routable with a local address before creating
         // the socket. We do not care about the actual destination here because
         // we will recalculate it when we send a packet so that the best route
         // available at the time is used for each outgoing packet.
-        //
-        // TODO(https://fxbug.dev/323389672): Cache a reference to the route to
-        // avoid the route lookup on send as long as the routing table hasn't
-        // changed in between these operations.
-        let ResolvedRoute { src_addr, device: route_device, local_delivery_device, next_hop: _ } =
-            match self.lookup_route(bindings_ctx, device, local_ip, remote_ip) {
-                Ok(r) => r,
-                Err(e) => return Err((e.into(), options)),
-            };
-
-        // If the source or destination address require a device, make sure to
-        // set that in the socket definition. Otherwise defer to what was provided.
-        let socket_device = (crate::socket::must_have_zone(src_addr.as_ref())
-            || crate::socket::must_have_zone(remote_ip.as_ref()))
-        .then(|| {
-            // NB: The route device might be loopback, and in such cases
-            // we want to bind the socket to the device the source IP is
-            // assigned to instead.
-            local_delivery_device.unwrap_or(route_device)
-        })
-        .as_ref()
-        .or(device)
-        .map(|d| self.downgrade_device_id(d));
-
-        let definition =
-            IpSockDefinition { local_ip: src_addr, remote_ip, device: socket_device, proto };
-        Ok(IpSock { definition: definition, options })
+        let resolved_route = self.lookup_route(bindings_ctx, device, local_ip, remote_ip)?;
+        Ok(new_ip_socket(device, resolved_route, remote_ip, proto))
     }
 
     fn send_ip_packet<S, O>(
         &mut self,
         bindings_ctx: &mut BC,
-        ip_sock: &IpSock<I, CC::WeakDeviceId, O>,
+        ip_sock: &IpSock<I, CC::WeakDeviceId>,
         body: S,
         mtu: Option<u32>,
+        options: &O,
     ) -> Result<(), (S, IpSockSendError)>
     where
         S: TransportPacketSerializer,
         S::Buffer: BufferMut,
-        O: SendOptions<I>,
+        O: SendOptions<I, Self::WeakDeviceId>,
     {
         // TODO(joshlf): Call `trace!` with relevant fields from the socket.
         self.increment(|counters| &counters.send_ip_packet);
 
-        send_ip_packet(self, bindings_ctx, ip_sock, body, mtu)
+        send_ip_packet(self, bindings_ctx, ip_sock, body, mtu, options)
     }
 }
 
@@ -493,37 +437,74 @@
 /// instead of an inherent impl on a type so that users of sockets that don't
 /// need certain option types, like TCP for anything multicast-related, can
 /// avoid allocating space for those options.
-pub trait SendOptions<I: Ip> {
+pub trait SendOptions<I: Ip, D> {
     /// Returns the hop limit to set on a packet going to the given destination.
     ///
     /// If `Some(u)`, `u` will be used as the hop limit (IPv6) or TTL (IPv4) for
     /// a packet going to the given destination. Otherwise the default value
     /// will be used.
     fn hop_limit(&self, destination: &SpecifiedAddr<I::Addr>) -> Option<NonZeroU8>;
+
+    /// Returns the interface selected for outgoing multicast packets.`
+    fn multicast_interface(&self) -> Option<&D>;
 }
 
 /// Empty send options that never overrides default values.
 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
 pub(crate) struct DefaultSendOptions;
 
-impl<I: Ip> SendOptions<I> for DefaultSendOptions {
+impl<I: Ip, D> SendOptions<I, D> for DefaultSendOptions {
     fn hop_limit(&self, _destination: &SpecifiedAddr<I::Addr>) -> Option<NonZeroU8> {
         None
     }
+
+    fn multicast_interface(&self) -> Option<&D> {
+        None
+    }
 }
 
-impl<I: Ip, S: SendOptions<I>> SendOptions<I> for &'_ S {
-    fn hop_limit(&self, destination: &SpecifiedAddr<<I as Ip>::Addr>) -> Option<NonZeroU8> {
-        S::hop_limit(self, destination)
-    }
+fn new_ip_socket<I, D>(
+    requested_device: Option<&D>,
+    route: ResolvedRoute<I, D>,
+    remote_ip: SocketIpAddr<I::Addr>,
+    proto: I::Proto,
+) -> IpSock<I, D::Weak>
+where
+    I: IpLayerIpExt,
+    D: device::StrongId,
+{
+    // TODO(https://fxbug.dev/323389672): Cache a reference to the route to
+    // avoid the route lookup on send as long as the routing table hasn't
+    // changed in between these operations.
+    let ResolvedRoute { src_addr, device: route_device, local_delivery_device, next_hop: _ } =
+        route;
+
+    // If the source or destination address require a device, make sure to
+    // set that in the socket definition. Otherwise defer to what was provided.
+    let socket_device = (crate::socket::must_have_zone(src_addr.as_ref())
+        || crate::socket::must_have_zone(remote_ip.as_ref()))
+    .then(|| {
+        // NB: The route device might be loopback, and in such cases
+        // we want to bind the socket to the device the source IP is
+        // assigned to instead.
+        local_delivery_device.unwrap_or(route_device)
+    })
+    .as_ref()
+    .or(requested_device)
+    .map(|d| d.downgrade());
+
+    let definition =
+        IpSockDefinition { local_ip: src_addr, remote_ip, device: socket_device, proto };
+    IpSock { definition }
 }
 
 fn send_ip_packet<I, S, BC, CC, O>(
     core_ctx: &mut CC,
     bindings_ctx: &mut BC,
-    socket: &IpSock<I, CC::WeakDeviceId, O>,
+    socket: &IpSock<I, CC::WeakDeviceId>,
     body: S,
     mtu: Option<u32>,
+    options: &O,
 ) -> Result<(), (S, IpSockSendError)>
 where
     I: IpExt + IpDeviceStateIpExt + packet_formats::ip::IpExt,
@@ -532,20 +513,20 @@
     BC: IpSocketBindingsContext,
     CC: IpSocketContext<I, BC>,
     CC::DeviceId: crate::filter::InterfaceProperties<BC::DeviceClass>,
-    O: SendOptions<I>,
+    O: SendOptions<I, CC::WeakDeviceId> + ?Sized,
 {
     trace_duration!(bindings_ctx, c"ip::send_packet");
 
-    let IpSock { definition: IpSockDefinition { remote_ip, local_ip, device, proto }, options } =
-        socket;
+    let IpSock { definition: IpSockDefinition { remote_ip, local_ip, device, proto } } = socket;
 
-    let device = if let Some(device) = device {
-        let Some(device) = core_ctx.upgrade_weak_device_id(device) else {
-            return Err((body, ResolveRouteError::Unreachable.into()));
-        };
-        Some(device)
-    } else {
-        None
+    let device = device.as_ref().or_else(|| {
+        remote_ip.addr().is_multicast().then(|| options.multicast_interface()).flatten()
+    });
+
+    let device = match device.map(|d| d.upgrade()) {
+        Some(Some(device)) => Some(device),
+        Some(None) => return Err((body, ResolveRouteError::Unreachable.into())),
+        None => None,
     };
 
     let ResolvedRoute { src_addr: got_local_ip, local_delivery_device: _, device, next_hop } =
@@ -558,7 +539,9 @@
     // TODO(https://fxbug.dev/318717702): when we implement NAT, perform re-routing
     // after the LOCAL_EGRESS hook since the packet may have been changed.
     let mut packet = crate::filter::TxPacket::new(local_ip.addr(), remote_ip.addr(), *proto, &body);
-    match core_ctx.filter_handler().local_egress_hook(&mut packet, &device) {
+
+    let mut packet_metadata = IpLayerPacketMetadata::default();
+    match core_ctx.filter_handler().local_egress_hook(&mut packet, &device, &mut packet_metadata) {
         crate::filter::Verdict::Drop => return Ok(()),
         crate::filter::Verdict::Accept => {}
     }
@@ -566,11 +549,7 @@
     let remote_ip: SpecifiedAddr<_> = (*remote_ip).into();
     let local_ip: SpecifiedAddr<_> = (*local_ip).into();
 
-    let (next_hop, broadcast) = match next_hop {
-        NextHop::RemoteAsNeighbor => (remote_ip, None),
-        NextHop::Gateway(gateway) => (gateway, None),
-        NextHop::Broadcast(marker) => (remote_ip, Some(marker)),
-    };
+    let (next_hop, broadcast) = next_hop.into_next_hop_and_broadcast_marker(remote_ip);
 
     IpSocketContext::send_ip_packet(
         core_ctx,
@@ -586,6 +565,7 @@
             mtu,
         },
         body,
+        packet_metadata,
     )
     .map_err(|s| (s, IpSockSendError::Mtu))
 }
@@ -596,15 +576,15 @@
         CC: IpDeviceContext<I, BC> + IpSocketContext<I, BC> + NonTestCtxMarker,
     > DeviceIpSocketHandler<I, BC> for CC
 {
-    fn get_mms<O: SendOptions<I>>(
+    fn get_mms(
         &mut self,
         bindings_ctx: &mut BC,
-        ip_sock: &IpSock<I, Self::WeakDeviceId, O>,
+        ip_sock: &IpSock<I, Self::WeakDeviceId>,
     ) -> Result<Mms, MmsError> {
         let IpSockDefinition { remote_ip, local_ip, device, proto: _ } = &ip_sock.definition;
         let device = device
             .as_ref()
-            .map(|d| self.upgrade_weak_device_id(d).ok_or(ResolveRouteError::Unreachable))
+            .map(|d| d.upgrade().ok_or(ResolveRouteError::Unreachable))
             .transpose()?;
 
         let ResolvedRoute { src_addr: _, local_delivery_device: _, device, next_hop: _ } = self
@@ -935,38 +915,24 @@
 #[cfg(test)]
 pub(crate) mod testutil {
     use alloc::{boxed::Box, collections::HashMap, vec::Vec};
-    use core::{fmt::Debug, num::NonZeroUsize};
+    use core::num::NonZeroUsize;
 
     use derivative::Derivative;
     use net_types::{
-        ip::{GenericOverIp, IpAddr, IpInvariant, Ipv4, Ipv6},
-        MulticastAddr,
+        ip::{GenericOverIp, IpAddr, IpInvariant, Ipv4, Ipv4Addr, Ipv6},
+        MulticastAddr, Witness as _,
     };
-    use packet::Serializer;
 
     use super::*;
     use crate::{
-        context::{
-            testutil::{FakeBindingsCtx, FakeCoreCtx, FakeInstant},
-            RngContext, SendFrameContext,
-        },
+        context::{testutil::FakeCoreCtx, SendFrameContext},
         device::testutil::{FakeStrongDeviceId, FakeWeakDeviceId},
         ip::{
-            device::state::{
-                AssignedAddress as _, DualStackIpDeviceState, IpDeviceState,
-                IpDeviceStateBindingsTypes,
-            },
-            forwarding::{
-                testutil::{DualStackForwardingTable, FakeIpForwardingCtx},
-                ForwardingTable,
-            },
-            icmp::{IcmpRxCounters, IcmpTxCounters, NdpCounters},
+            forwarding::{testutil::FakeIpForwardingCtx, ForwardingTable},
             testutil::FakeIpDeviceIdCtx,
             types::Destination,
             HopLimits, MulticastMembershipHandler, TransportIpContext, DEFAULT_HOP_LIMITS,
         },
-        sync::PrimaryRc,
-        testutil::DEFAULT_INTERFACE_METRIC,
     };
 
     /// A fake implementation of [`IpSocketContext`].
@@ -977,349 +943,156 @@
     #[derive(Derivative, GenericOverIp)]
     #[generic_over_ip(I, Ip)]
     #[derivative(Default(bound = ""))]
-    pub(crate) struct FakeIpSocketCtx<I: IpLayerIpExt + IpDeviceStateIpExt, D> {
+    pub(crate) struct FakeIpSocketCtx<I: IpLayerIpExt, D> {
         pub(crate) table: ForwardingTable<I, D>,
-        device_state: HashMap<D, IpDeviceState<FakeInstant, I>>,
-        ip_forwarding_ctx: FakeIpForwardingCtx<D>,
-        pub(crate) counters: IpCounters<I>,
+        forwarding: FakeIpForwardingCtx<D>,
+        devices: HashMap<D, FakeDeviceState<I>>,
     }
 
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D, BC: FilterBindingsTypes>
-        FilterHandlerProvider<I, BC> for FakeIpSocketCtx<I, D>
-    {
-        type Handler<'a> = crate::filter::NoopImpl where Self: 'a;
-
-        fn filter_handler(&mut self) -> Self::Handler<'_> {
-            crate::filter::NoopImpl
-        }
-    }
-
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D> CounterContext<IpCounters<I>>
-        for FakeIpSocketCtx<I, D>
-    {
-        fn with_counters<O, F: FnOnce(&IpCounters<I>) -> O>(&self, cb: F) -> O {
-            cb(&self.counters)
-        }
-    }
-
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D> AsRef<FakeIpDeviceIdCtx<D>>
-        for FakeIpSocketCtx<I, D>
-    {
-        fn as_ref(&self) -> &FakeIpDeviceIdCtx<D> {
-            let FakeIpSocketCtx { device_state: _, table: _, ip_forwarding_ctx, counters: _ } =
-                self;
-            ip_forwarding_ctx.get_ref().as_ref()
-        }
-    }
-
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D> AsMut<FakeIpDeviceIdCtx<D>>
-        for FakeIpSocketCtx<I, D>
-    {
-        fn as_mut(&mut self) -> &mut FakeIpDeviceIdCtx<D> {
-            let FakeIpSocketCtx { device_state: _, table: _, ip_forwarding_ctx, counters: _ } =
-                self;
-            ip_forwarding_ctx.get_mut().as_mut()
-        }
-    }
-
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D> AsRef<Self> for FakeIpSocketCtx<I, D> {
+    impl<I: IpLayerIpExt, D> AsRef<Self> for FakeIpSocketCtx<I, D> {
         fn as_ref(&self) -> &Self {
             self
         }
     }
 
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D> AsMut<Self> for FakeIpSocketCtx<I, D> {
+    impl<I: IpLayerIpExt, D> AsMut<Self> for FakeIpSocketCtx<I, D> {
         fn as_mut(&mut self) -> &mut Self {
             self
         }
     }
 
-    // TODO(https://fxbug.dev/331777445): remove this marker trait once tests in the
-    // transport-layer modules use a fake implementation of IpSocketHandler rather
-    // than the blanket impl, which requires the `InterfaceProperties` trait on the
-    // device ID for filtering purposes.
-    pub(crate) trait FakeFilterDeviceId<DeviceClass>:
-        FakeStrongDeviceId + crate::filter::InterfaceProperties<DeviceClass>
+    impl<I: IpLayerIpExt, D: FakeStrongDeviceId, BC> TransportIpContext<I, BC>
+        for FakeIpSocketCtx<I, D>
     {
-    }
-
-    impl<DeviceClass, D: FakeStrongDeviceId + crate::filter::InterfaceProperties<DeviceClass>>
-        FakeFilterDeviceId<DeviceClass> for D
-    {
-    }
-
-    impl<
-            I: IpLayerIpExt + IpDeviceStateIpExt,
-            BC: InstantContext + TracingContext + FilterBindingsTypes,
-            DeviceId: FakeFilterDeviceId<BC::DeviceClass>,
-        > TransportIpContext<I, BC> for FakeIpSocketCtx<I, DeviceId>
-    {
-        fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
+        fn get_default_hop_limits(&mut self, device: Option<&D>) -> HopLimits {
             device.map_or(DEFAULT_HOP_LIMITS, |device| {
-                let hop_limit = self.get_device_state(device).default_hop_limit.read().clone();
+                let hop_limit = self.get_device_state(device).default_hop_limit;
                 HopLimits { unicast: hop_limit, multicast: DEFAULT_HOP_LIMITS.multicast }
             })
         }
 
-        type DevicesWithAddrIter<'a> = alloc::boxed::Box<dyn Iterator<Item = DeviceId> + 'a>;
+        type DevicesWithAddrIter<'a> = Box<dyn Iterator<Item = D> + 'a>;
 
         fn get_devices_with_assigned_addr(
             &mut self,
             addr: SpecifiedAddr<<I>::Addr>,
         ) -> Self::DevicesWithAddrIter<'_> {
-            Box::new(self.find_devices_with_addr(addr))
+            Box::new(self.devices.iter().filter_map(move |(device, state)| {
+                state.addresses.contains(&addr).then(|| device.clone())
+            }))
         }
 
         fn confirm_reachable_with_destination(
             &mut self,
             _bindings_ctx: &mut BC,
             _dst: SpecifiedAddr<<I>::Addr>,
-            _device: Option<&Self::DeviceId>,
+            _device: Option<&D>,
         ) {
         }
     }
 
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, DeviceId: FakeStrongDeviceId>
-        DeviceIdContext<AnyDevice> for FakeIpSocketCtx<I, DeviceId>
-    {
-        type DeviceId = <FakeIpDeviceIdCtx<DeviceId> as DeviceIdContext<AnyDevice>>::DeviceId;
-        type WeakDeviceId =
-            <FakeIpDeviceIdCtx<DeviceId> as DeviceIdContext<AnyDevice>>::WeakDeviceId;
-
-        fn downgrade_device_id(&self, device_id: &DeviceId) -> FakeWeakDeviceId<DeviceId> {
-            self.ip_forwarding_ctx.downgrade_device_id(device_id)
-        }
-
-        fn upgrade_weak_device_id(
-            &self,
-            device_id: &FakeWeakDeviceId<DeviceId>,
-        ) -> Option<DeviceId> {
-            self.ip_forwarding_ctx.upgrade_weak_device_id(device_id)
-        }
+    impl<I: IpLayerIpExt, D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeIpSocketCtx<I, D> {
+        type DeviceId = <FakeIpDeviceIdCtx<D> as DeviceIdContext<AnyDevice>>::DeviceId;
+        type WeakDeviceId = <FakeIpDeviceIdCtx<D> as DeviceIdContext<AnyDevice>>::WeakDeviceId;
     }
 
-    fn lookup_route<I: IpDeviceStateIpExt, D: FakeStrongDeviceId, Instant: crate::Instant>(
-        table: &ForwardingTable<I, D>,
-        ip_forwarding_ctx: &mut FakeIpForwardingCtx<D>,
-        device_state: &HashMap<D, impl AsRef<IpDeviceState<Instant, I>>>,
-        device: Option<&D>,
-        local_ip: Option<IpDeviceAddr<I::Addr>>,
-        addr: RoutableIpAddr<I::Addr>,
-    ) -> Result<ResolvedRoute<I, D>, ResolveRouteError> {
-        let (destination, ()) = table
-            .lookup_filter_map(ip_forwarding_ctx, device, addr.addr(), |_, d| match &local_ip {
-                None => Some(()),
-                Some(local_ip) => device_state.get(d).and_then(|state| {
-                    state.as_ref().addrs.read().find(&local_ip.addr()).map(|_| ())
-                }),
-            })
-            .next()
-            .ok_or(ResolveRouteError::Unreachable)?;
-
-        let Destination { device, next_hop } = destination;
-        let addrs = device_state.get(&device).unwrap().as_ref().addrs.read();
-        let mut addrs = addrs.iter();
-        let local_ip = match local_ip {
-            None => addrs.map(|e| e.addr()).next().ok_or(ResolveRouteError::NoSrcAddr)?,
-            Some(local_ip) => {
-                // We already constrained the set of devices so this
-                // should be a given.
-                assert!(
-                    addrs.any(|e| e.addr() == local_ip),
-                    "didn't find IP {:?} in {:?}",
-                    local_ip,
-                    addrs.collect::<Vec<_>>()
-                );
-                local_ip
-            }
-        };
-
-        Ok(ResolvedRoute {
-            src_addr: local_ip,
-            device: device.clone(),
-            local_delivery_device: None,
-            next_hop,
-        })
-    }
-
-    impl<
-            I: IpLayerIpExt + IpDeviceStateIpExt,
-            BC: InstantContext + TracingContext + FilterBindingsTypes,
-            DeviceId: FakeFilterDeviceId<BC::DeviceClass>,
-        > IpSocketContext<I, BC> for FakeIpSocketCtx<I, DeviceId>
+    impl<I, D, BC> IpSocketHandler<I, BC> for FakeIpSocketCtx<I, D>
+    where
+        I: IpLayerIpExt,
+        D: FakeStrongDeviceId,
     {
-        fn lookup_route(
+        fn new_ip_socket(
             &mut self,
             _bindings_ctx: &mut BC,
-            device: Option<&Self::DeviceId>,
-            local_ip: Option<IpDeviceAddr<I::Addr>>,
-            addr: RoutableIpAddr<I::Addr>,
-        ) -> Result<ResolvedRoute<I, Self::DeviceId>, ResolveRouteError> {
-            let FakeIpSocketCtx { device_state, table, ip_forwarding_ctx, counters: _ } = self;
-            lookup_route(table, ip_forwarding_ctx, device_state, device, local_ip, addr)
+            device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
+            local_ip: Option<SocketIpAddr<I::Addr>>,
+            remote_ip: SocketIpAddr<I::Addr>,
+            proto: I::Proto,
+        ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError> {
+            let device = device
+                .as_ref()
+                .map(|d| d.as_strong_ref().ok_or(ResolveRouteError::Unreachable))
+                .transpose()?;
+            let device = device.as_ref().map(|d| d.as_ref());
+            let resolved_route = self.lookup_route(device, local_ip, remote_ip)?;
+            Ok(new_ip_socket(device, resolved_route, remote_ip, proto))
         }
 
-        fn send_ip_packet<S>(
+        fn send_ip_packet<S, O>(
             &mut self,
             _bindings_ctx: &mut BC,
-            _meta: SendIpPacketMeta<I, &Self::DeviceId, SpecifiedAddr<I::Addr>>,
+            _socket: &IpSock<I, Self::WeakDeviceId>,
             _body: S,
-        ) -> Result<(), S> {
+            _mtu: Option<u32>,
+            _options: &O,
+        ) -> Result<(), (S, IpSockSendError)>
+        where
+            S: TransportPacketSerializer,
+            S::Buffer: BufferMut,
+            O: SendOptions<I, Self::WeakDeviceId>,
+        {
             panic!("FakeIpSocketCtx can't send packets, wrap it in a FakeCoreCtx instead");
         }
     }
 
     impl<
             I: IpLayerIpExt + IpDeviceStateIpExt,
-            S: AsRef<FakeIpSocketCtx<I, DeviceId>>
+            State: AsRef<FakeIpSocketCtx<I, DeviceId>>
                 + AsMut<FakeIpSocketCtx<I, DeviceId>>
                 + AsRef<FakeIpDeviceIdCtx<DeviceId>>,
-            Id,
             Meta,
-            Event: Debug,
-            DeviceId: FakeFilterDeviceId<()>,
-            BindingsCtxState,
-        > IpSocketContext<I, FakeBindingsCtx<Id, Event, BindingsCtxState, ()>>
-        for FakeCoreCtx<S, Meta, DeviceId>
+            DeviceId: FakeStrongDeviceId,
+            BC,
+        > IpSocketHandler<I, BC> for FakeCoreCtx<State, Meta, DeviceId>
     where
-        FakeCoreCtx<S, Meta, DeviceId>: SendFrameContext<
-            FakeBindingsCtx<Id, Event, BindingsCtxState, ()>,
-            SendIpPacketMeta<I, Self::DeviceId, SpecifiedAddr<I::Addr>>,
-        >,
+        FakeCoreCtx<State, Meta, DeviceId>:
+            SendFrameContext<BC, SendIpPacketMeta<I, Self::DeviceId, SpecifiedAddr<I::Addr>>>,
     {
-        fn lookup_route(
+        fn new_ip_socket(
             &mut self,
-            bindings_ctx: &mut FakeBindingsCtx<Id, Event, BindingsCtxState, ()>,
-            device: Option<&Self::DeviceId>,
-            local_ip: Option<IpDeviceAddr<I::Addr>>,
-            addr: RoutableIpAddr<I::Addr>,
-        ) -> Result<ResolvedRoute<I, Self::DeviceId>, ResolveRouteError> {
-            self.get_mut().as_mut().lookup_route(bindings_ctx, device, local_ip, addr)
+            bindings_ctx: &mut BC,
+            device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
+            local_ip: Option<SocketIpAddr<I::Addr>>,
+            remote_ip: SocketIpAddr<I::Addr>,
+            proto: I::Proto,
+        ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError> {
+            self.get_mut().as_mut().new_ip_socket(bindings_ctx, device, local_ip, remote_ip, proto)
         }
 
-        fn send_ip_packet<SS>(
+        fn send_ip_packet<S, O>(
             &mut self,
-            bindings_ctx: &mut FakeBindingsCtx<Id, Event, BindingsCtxState, ()>,
-            SendIpPacketMeta {  device, src_ip, dst_ip, broadcast, next_hop, proto, ttl, mtu }: SendIpPacketMeta<I, &Self::DeviceId, SpecifiedAddr<I::Addr>>,
-            body: SS,
-        ) -> Result<(), SS>
+            bindings_ctx: &mut BC,
+            socket: &IpSock<I, Self::WeakDeviceId>,
+            body: S,
+            mtu: Option<u32>,
+            options: &O,
+        ) -> Result<(), (S, IpSockSendError)>
         where
-            SS: Serializer,
-            SS::Buffer: BufferMut,
+            S: TransportPacketSerializer,
+            S::Buffer: BufferMut,
+            O: SendOptions<I, Self::WeakDeviceId>,
         {
-            let meta = SendIpPacketMeta {
-                device: device.clone(),
-                src_ip,
-                dst_ip,
-                broadcast,
-                next_hop,
-                proto,
-                ttl,
-                mtu,
-            };
-            self.send_frame(bindings_ctx, meta, body)
-        }
-    }
-
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D: FakeStrongDeviceId> FakeIpSocketCtx<I, D> {
-        pub(crate) fn with_devices_state(
-            devices: impl IntoIterator<
-                Item = (D, IpDeviceState<FakeInstant, I>, Vec<SpecifiedAddr<I::Addr>>),
-            >,
-        ) -> Self {
-            let mut table = ForwardingTable::default();
-            let mut device_state = HashMap::default();
-            for (device, state, addrs) in devices {
-                for ip in addrs {
-                    crate::ip::forwarding::testutil::add_on_link_forwarding_entry(
-                        &mut table,
-                        ip,
-                        device.clone(),
-                    )
+            let meta = match self.state.as_mut().resolve_send_meta(socket, mtu, options) {
+                Ok(meta) => meta,
+                Err(e) => {
+                    return Err((body, e));
                 }
-                assert!(
-                    device_state.insert(device.clone(), state).is_none(),
-                    "duplicate entries for {device:?}",
-                );
-            }
-
-            FakeIpSocketCtx {
-                table,
-                device_state,
-                ip_forwarding_ctx: Default::default(),
-                counters: Default::default(),
-            }
-        }
-
-        pub(crate) fn find_devices_with_addr(
-            &self,
-            addr: SpecifiedAddr<I::Addr>,
-        ) -> impl Iterator<Item = D> + '_ {
-            let Self { table: _, device_state, ip_forwarding_ctx: _, counters: _ } = self;
-            find_devices_with_addr::<I, _, _>(device_state, addr)
-        }
-
-        pub(crate) fn get_device_state(&self, device: &D) -> &IpDeviceState<FakeInstant, I> {
-            let Self { device_state, table: _, ip_forwarding_ctx: _, counters: _ } = self;
-            device_state.get(device).unwrap_or_else(|| panic!("no device {device:?}"))
+            };
+            self.send_frame(bindings_ctx, meta, body).map_err(|s| (s, IpSockSendError::Mtu))
         }
     }
 
-    fn find_devices_with_addr<
-        I: IpLayerIpExt + IpDeviceStateIpExt,
-        D: FakeStrongDeviceId,
-        Instant: crate::Instant,
-    >(
-        device_state: &HashMap<D, impl AsRef<IpDeviceState<Instant, I>>>,
-        addr: SpecifiedAddr<I::Addr>,
-    ) -> impl Iterator<Item = D> + '_ {
-        device_state.iter().filter_map(move |(device, state)| {
-            state
-                .as_ref()
-                .addrs
-                .read()
-                .find(&addr)
-                .map(|_: &PrimaryRc<I::AssignedAddress<_>>| device.clone())
-        })
-    }
-
-    fn multicast_memberships<
-        I: IpDeviceStateIpExt,
-        D: FakeStrongDeviceId,
-        Instant: crate::Instant,
-    >(
-        device_state: &HashMap<D, impl AsRef<IpDeviceState<Instant, I>>>,
-    ) -> HashMap<(D, MulticastAddr<I::Addr>), NonZeroUsize> {
-        device_state
-            .iter()
-            .flat_map(|(device, device_state)| {
-                device_state
-                    .as_ref()
-                    .multicast_groups
-                    .read()
-                    .iter_counts()
-                    .map(|(addr, count)| ((device.clone(), *addr), count))
-                    .collect::<Vec<_>>()
-            })
-            .collect()
-    }
-
-    impl<
-            I: IpLayerIpExt + IpDeviceStateIpExt,
-            D: FakeStrongDeviceId,
-            BC: RngContext + InstantContext<Instant = FakeInstant>,
-        > MulticastMembershipHandler<I, BC> for FakeIpSocketCtx<I, D>
+    impl<I: IpLayerIpExt, D: FakeStrongDeviceId, BC> MulticastMembershipHandler<I, BC>
+        for FakeIpSocketCtx<I, D>
     {
         fn join_multicast_group(
             &mut self,
-            bindings_ctx: &mut BC,
+            _bindings_ctx: &mut BC,
             device: &Self::DeviceId,
             addr: MulticastAddr<<I as Ip>::Addr>,
         ) {
-            let Self { device_state, table: _, ip_forwarding_ctx: _, counters: _ } = self;
-            let state =
-                device_state.get_mut(device).unwrap_or_else(|| panic!("no device {device:?}"));
-            state.multicast_groups.write().join_multicast_group(bindings_ctx, addr)
+            let value = self.get_device_state_mut(device).multicast_groups.entry(addr).or_insert(0);
+            *value = value.checked_add(1).unwrap();
         }
 
         fn leave_multicast_group(
@@ -1328,33 +1101,32 @@
             device: &Self::DeviceId,
             addr: MulticastAddr<<I as Ip>::Addr>,
         ) {
-            let Self { device_state, table: _, ip_forwarding_ctx: _, counters: _ } = self;
-            let state =
-                device_state.get_mut(device).unwrap_or_else(|| panic!("no device {device:?}"));
-            state.multicast_groups.write().leave_multicast_group(addr)
+            let value = self
+                .get_device_state_mut(device)
+                .multicast_groups
+                .get_mut(&addr)
+                .unwrap_or_else(|| panic!("no entry for {addr} on {device:?}"));
+            *value = value.checked_sub(1).unwrap();
         }
 
         fn select_device_for_multicast_group(
             &mut self,
             addr: MulticastAddr<<I as Ip>::Addr>,
         ) -> Result<Self::DeviceId, ResolveRouteError> {
-            let FakeIpSocketCtx { device_state, table, ip_forwarding_ctx, counters: _ } = self;
             let remote_ip = SocketIpAddr::new_from_multicast(addr);
-            let ResolvedRoute { device, .. } =
-                lookup_route(table, ip_forwarding_ctx, device_state, None, None, remote_ip)?;
-            Ok(device)
+            self.lookup_route(None, None, remote_ip).map(|ResolvedRoute { device, .. }| device)
         }
     }
 
     impl<
-            I: IpLayerIpExt + IpDeviceStateIpExt,
+            I: IpLayerIpExt,
             BC: InstantContext + TracingContext + FilterBindingsTypes,
-            D: FakeFilterDeviceId<BC::DeviceClass>,
-            State: TransportIpContext<I, BC, DeviceId = D> + CounterContext<IpCounters<I>>,
+            D: FakeStrongDeviceId,
+            State: TransportIpContext<I, BC, DeviceId = D>,
             Meta,
         > TransportIpContext<I, BC> for FakeCoreCtx<State, Meta, D>
     where
-        Self: IpSocketContext<I, BC, DeviceId = D, WeakDeviceId = FakeWeakDeviceId<D>>,
+        Self: IpSocketHandler<I, BC, DeviceId = D, WeakDeviceId = FakeWeakDeviceId<D>>,
     {
         type DevicesWithAddrIter<'a> = State::DevicesWithAddrIter<'a>
             where Self: 'a;
@@ -1387,351 +1159,179 @@
 
     #[derive(Derivative)]
     #[derivative(Default(bound = ""))]
-    pub(crate) struct FakeDualStackIpSocketCtx<D, BT: IpDeviceStateBindingsTypes> {
-        table: DualStackForwardingTable<D>,
-        device_state: HashMap<D, DualStackIpDeviceState<BT>>,
-        ip_forwarding_ctx: FakeIpForwardingCtx<D>,
-        pub(crate) v4_common_counters: IpCounters<Ipv4>,
-        pub(crate) v6_common_counters: IpCounters<Ipv6>,
-        pub(crate) tx_icmpv4_counters: IcmpTxCounters<Ipv4>,
-        pub(crate) rx_icmpv4_counters: IcmpRxCounters<Ipv4>,
-        pub(crate) tx_icmpv6_counters: IcmpTxCounters<Ipv6>,
-        pub(crate) rx_icmpv6_counters: IcmpRxCounters<Ipv6>,
-        pub(crate) ndp_counters: NdpCounters,
+    pub(crate) struct FakeDualStackIpSocketCtx<D> {
+        v4: FakeIpSocketCtx<Ipv4, D>,
+        v6: FakeIpSocketCtx<Ipv6, D>,
     }
 
-    impl<D: FakeStrongDeviceId, BT: IpDeviceStateBindingsTypes> FakeDualStackIpSocketCtx<D, BT> {
+    impl<D: FakeStrongDeviceId> FakeDualStackIpSocketCtx<D> {
         pub(crate) fn new<A: Into<SpecifiedAddr<IpAddr>>>(
             devices: impl IntoIterator<Item = FakeDeviceConfig<D, A>>,
         ) -> Self {
-            Self::with_devices_state(devices.into_iter().map(
-                |FakeDeviceConfig { device, local_ips, remote_ips }| {
-                    let mut device_state = DualStackIpDeviceState::new(DEFAULT_INTERFACE_METRIC);
-                    for ip in local_ips {
-                        match IpAddr::from(ip.into()) {
-                            IpAddr::V4(ip) => crate::ip::device::state::testutil::add_addr_subnet(
-                                device_state.as_mut(),
-                                ip,
-                            ),
-                            IpAddr::V6(ip) => crate::ip::device::state::testutil::add_addr_subnet(
-                                device_state.as_mut(),
-                                ip,
-                            ),
+            let partition =
+                |v: Vec<A>| -> (Vec<SpecifiedAddr<Ipv4Addr>>, Vec<SpecifiedAddr<Ipv6Addr>>) {
+                    v.into_iter().fold((Vec::new(), Vec::new()), |(mut v4, mut v6), i| {
+                        match IpAddr::from(i.into()) {
+                            IpAddr::V4(a) => v4.push(a),
+                            IpAddr::V6(a) => v6.push(a),
                         }
-                    }
-                    (device, device_state, remote_ips)
-                },
-            ))
+                        (v4, v6)
+                    })
+                };
+
+            let (v4, v6): (Vec<_>, Vec<_>) = devices
+                .into_iter()
+                .map(|FakeDeviceConfig { device, local_ips, remote_ips }| {
+                    let (local_v4, local_v6) = partition(local_ips);
+                    let (remote_v4, remote_v6) = partition(remote_ips);
+                    (
+                        FakeDeviceConfig {
+                            device: device.clone(),
+                            local_ips: local_v4,
+                            remote_ips: remote_v4,
+                        },
+                        FakeDeviceConfig { device, local_ips: local_v6, remote_ips: remote_v6 },
+                    )
+                })
+                .unzip();
+            Self { v4: FakeIpSocketCtx::new(v4), v6: FakeIpSocketCtx::new(v6) }
+        }
+
+        fn inner_mut<I: IpLayerIpExt>(&mut self) -> &mut FakeIpSocketCtx<I, D> {
+            I::map_ip(IpInvariant(self), |IpInvariant(s)| &mut s.v4, |IpInvariant(s)| &mut s.v6)
+        }
+
+        fn inner<I: IpLayerIpExt>(&self) -> &FakeIpSocketCtx<I, D> {
+            I::map_ip(IpInvariant(self), |IpInvariant(s)| &s.v4, |IpInvariant(s)| &s.v6)
         }
 
         pub(crate) fn add_route(&mut self, device: D, ip: SpecifiedAddr<IpAddr>) {
             match IpAddr::from(ip) {
                 IpAddr::V4(ip) => crate::ip::forwarding::testutil::add_on_link_forwarding_entry(
-                    self.table.as_mut(),
+                    &mut self.v4.table,
                     ip,
                     device,
                 ),
                 IpAddr::V6(ip) => crate::ip::forwarding::testutil::add_on_link_forwarding_entry(
-                    self.table.as_mut(),
+                    &mut self.v6.table,
                     ip,
                     device,
                 ),
             }
         }
 
-        pub(crate) fn get_device_state(&self, device: &D) -> &DualStackIpDeviceState<BT> {
-            let Self {
-                device_state,
-                table: _,
-                ip_forwarding_ctx: _,
-                v4_common_counters: _,
-                v6_common_counters: _,
-                tx_icmpv4_counters: _,
-                rx_icmpv4_counters: _,
-                tx_icmpv6_counters: _,
-                rx_icmpv6_counters: _,
-                ndp_counters: _,
-            } = self;
-            device_state.get(device).unwrap_or_else(|| panic!("no device {device:?}"))
+        pub(crate) fn get_device_state_mut<I: IpLayerIpExt>(
+            &mut self,
+            device: &D,
+        ) -> &mut FakeDeviceState<I> {
+            self.inner_mut::<I>().get_device_state_mut(device)
         }
 
-        pub(crate) fn find_devices_with_addr<I: IpLayerIpExt + IpDeviceStateIpExt>(
-            &self,
-            addr: SpecifiedAddr<I::Addr>,
-        ) -> impl Iterator<Item = D> + '_ {
-            let Self {
-                table: _,
-                device_state,
-                ip_forwarding_ctx: _,
-                v4_common_counters: _,
-                v6_common_counters: _,
-                tx_icmpv4_counters: _,
-                rx_icmpv4_counters: _,
-                tx_icmpv6_counters: _,
-                rx_icmpv6_counters: _,
-                ndp_counters: _,
-            } = self;
-            find_devices_with_addr::<I, _, _>(device_state, addr)
-        }
-
-        pub(crate) fn multicast_memberships<I: IpDeviceStateIpExt>(
+        pub(crate) fn multicast_memberships<I: IpLayerIpExt>(
             &self,
         ) -> HashMap<(D, MulticastAddr<I::Addr>), NonZeroUsize> {
-            let Self {
-                device_state,
-                table: _,
-                ip_forwarding_ctx: _,
-                v4_common_counters: _,
-                v6_common_counters: _,
-                tx_icmpv4_counters: _,
-                rx_icmpv4_counters: _,
-                tx_icmpv6_counters: _,
-                rx_icmpv6_counters: _,
-                ndp_counters: _,
-            } = self;
-            multicast_memberships::<I, _, _>(device_state)
-        }
-
-        pub(crate) fn with_devices_state(
-            devices: impl IntoIterator<
-                Item = (D, DualStackIpDeviceState<BT>, Vec<impl Into<SpecifiedAddr<IpAddr>>>),
-            >,
-        ) -> Self {
-            let mut table = DualStackForwardingTable::default();
-            let mut device_state = HashMap::default();
-            for (device, state, addrs) in devices {
-                for ip in addrs {
-                    match IpAddr::from(ip.into()) {
-                        IpAddr::V4(ip) => {
-                            crate::ip::forwarding::testutil::add_on_link_forwarding_entry(
-                                table.as_mut(),
-                                ip,
-                                device.clone(),
-                            );
-                        }
-                        IpAddr::V6(ip) => {
-                            crate::ip::forwarding::testutil::add_on_link_forwarding_entry(
-                                table.as_mut(),
-                                ip,
-                                device.clone(),
-                            );
-                        }
-                    }
-                }
-                assert!(
-                    device_state.insert(device.clone(), state).is_none(),
-                    "duplicate entries for {device:?}",
-                );
-            }
-            Self {
-                table,
-                device_state,
-                ip_forwarding_ctx: FakeIpForwardingCtx::default(),
-                v4_common_counters: Default::default(),
-                v6_common_counters: Default::default(),
-                tx_icmpv4_counters: Default::default(),
-                rx_icmpv4_counters: Default::default(),
-                tx_icmpv6_counters: Default::default(),
-                rx_icmpv6_counters: Default::default(),
-                ndp_counters: Default::default(),
-            }
+            self.inner::<I>().multicast_memberships()
         }
     }
 
-    impl<D, BT: IpDeviceStateBindingsTypes> FakeDualStackIpSocketCtx<D, BT> {
-        pub(crate) fn get_common_counters<I: IpLayerIpExt>(&self) -> &IpCounters<I> {
-            I::map_ip(
-                IpInvariant(self),
-                |IpInvariant(core_ctx)| &core_ctx.v4_common_counters,
-                |IpInvariant(core_ctx)| &core_ctx.v6_common_counters,
-            )
-        }
-
-        pub(crate) fn icmp_tx_counters<I: Ip>(&self) -> &IcmpTxCounters<I> {
-            I::map_ip(
-                IpInvariant(self),
-                |IpInvariant(core_ctx)| &core_ctx.tx_icmpv4_counters,
-                |IpInvariant(core_ctx)| &core_ctx.tx_icmpv6_counters,
-            )
-        }
-
-        pub(crate) fn icmp_rx_counters<I: Ip>(&self) -> &IcmpRxCounters<I> {
-            I::map_ip(
-                IpInvariant(self),
-                |IpInvariant(core_ctx)| &core_ctx.rx_icmpv4_counters,
-                |IpInvariant(core_ctx)| &core_ctx.rx_icmpv6_counters,
-            )
-        }
-    }
-
-    impl<I: IpExt, D, BC: FilterBindingsTypes + IpDeviceStateBindingsTypes>
-        FilterHandlerProvider<I, BC> for FakeDualStackIpSocketCtx<D, BC>
-    {
-        type Handler<'a> = crate::filter::NoopImpl where Self: 'a;
-
-        fn filter_handler(&mut self) -> Self::Handler<'_> {
-            crate::filter::NoopImpl
-        }
-    }
-
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D, BT: IpDeviceStateBindingsTypes>
-        CounterContext<IpCounters<I>> for FakeDualStackIpSocketCtx<D, BT>
-    {
-        fn with_counters<O, F: FnOnce(&IpCounters<I>) -> O>(&self, cb: F) -> O {
-            cb(self.get_common_counters::<I>())
-        }
-    }
-
-    impl<D: FakeStrongDeviceId, BT: IpDeviceStateBindingsTypes> AsRef<Self>
-        for FakeDualStackIpSocketCtx<D, BT>
-    {
+    impl<D: FakeStrongDeviceId> AsRef<Self> for FakeDualStackIpSocketCtx<D> {
         fn as_ref(&self) -> &Self {
             self
         }
     }
 
-    impl<D: FakeStrongDeviceId, BT: IpDeviceStateBindingsTypes> AsRef<FakeIpDeviceIdCtx<D>>
-        for FakeDualStackIpSocketCtx<D, BT>
-    {
-        fn as_ref(&self) -> &FakeIpDeviceIdCtx<D> {
-            self.ip_forwarding_ctx.get_ref().as_ref()
-        }
+    impl<D: FakeStrongDeviceId> DeviceIdContext<AnyDevice> for FakeDualStackIpSocketCtx<D> {
+        type DeviceId = D;
+        type WeakDeviceId = D::Weak;
     }
 
-    impl<D: FakeStrongDeviceId, BT: IpDeviceStateBindingsTypes> AsMut<FakeIpDeviceIdCtx<D>>
-        for FakeDualStackIpSocketCtx<D, BT>
+    impl<I: IpLayerIpExt, D: FakeStrongDeviceId, BC> IpSocketHandler<I, BC>
+        for FakeDualStackIpSocketCtx<D>
     {
-        fn as_mut(&mut self) -> &mut FakeIpDeviceIdCtx<D> {
-            self.ip_forwarding_ctx.get_mut().as_mut()
-        }
-    }
-
-    impl<DeviceId: FakeStrongDeviceId, BT: IpDeviceStateBindingsTypes> DeviceIdContext<AnyDevice>
-        for FakeDualStackIpSocketCtx<DeviceId, BT>
-    {
-        type DeviceId = DeviceId;
-        type WeakDeviceId = DeviceId::Weak;
-
-        fn downgrade_device_id(&self, device_id: &DeviceId) -> Self::WeakDeviceId {
-            self.ip_forwarding_ctx.downgrade_device_id(device_id)
-        }
-
-        fn upgrade_weak_device_id(
-            &self,
-            device_id: &FakeWeakDeviceId<DeviceId>,
-        ) -> Option<DeviceId> {
-            self.ip_forwarding_ctx.upgrade_weak_device_id(device_id)
-        }
-    }
-
-    impl<
-            I: IpDeviceStateIpExt + IpExt,
-            DeviceId: FakeStrongDeviceId,
-            BC: IpSocketBindingsContext,
-        > IpSocketContext<I, BC> for FakeDualStackIpSocketCtx<DeviceId, BC>
-    {
-        fn lookup_route(
+        fn new_ip_socket(
             &mut self,
-            _bindings_ctx: &mut BC,
-            device: Option<&Self::DeviceId>,
-            local_ip: Option<IpDeviceAddr<I::Addr>>,
-            addr: RoutableIpAddr<I::Addr>,
-        ) -> Result<ResolvedRoute<I, Self::DeviceId>, ResolveRouteError> {
-            let Self {
-                table,
-                device_state,
-                ip_forwarding_ctx,
-                v4_common_counters: _,
-                v6_common_counters: _,
-                tx_icmpv4_counters: _,
-                rx_icmpv4_counters: _,
-                tx_icmpv6_counters: _,
-                rx_icmpv6_counters: _,
-                ndp_counters: _,
-            } = self;
-            lookup_route(
-                table.as_ref(),
-                ip_forwarding_ctx.as_mut(),
-                device_state,
+            bindings_ctx: &mut BC,
+            device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
+            local_ip: Option<SocketIpAddr<I::Addr>>,
+            remote_ip: SocketIpAddr<I::Addr>,
+            proto: I::Proto,
+        ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError> {
+            IpSocketHandler::<I, BC>::new_ip_socket(
+                self.inner_mut::<I>(),
+                bindings_ctx,
                 device,
                 local_ip,
-                addr,
+                remote_ip,
+                proto,
             )
         }
 
-        /// Send an IP packet to the next-hop node.
-        fn send_ip_packet<S>(
+        fn send_ip_packet<S, O>(
             &mut self,
-            _bindings_ctx: &mut BC,
-            _meta: SendIpPacketMeta<I, &Self::DeviceId, SpecifiedAddr<I::Addr>>,
-            _body: S,
-        ) -> Result<(), S> {
-            panic!("FakeDualStackIpSocketCtx can't send packets, wrap it in a FakeCoreCtx instead");
-        }
-    }
-
-    impl<
-            I: IpDeviceStateIpExt + IpExt,
-            Id,
-            Meta,
-            Event: Debug,
-            DeviceId: FakeStrongDeviceId,
-            BindingsCtxState,
-        > IpSocketContext<I, FakeBindingsCtx<Id, Event, BindingsCtxState, ()>>
-        for FakeCoreCtx<
-            FakeDualStackIpSocketCtx<DeviceId, FakeBindingsCtx<Id, Event, BindingsCtxState, ()>>,
-            Meta,
-            DeviceId,
-        >
-    where
-        FakeCoreCtx<
-            FakeDualStackIpSocketCtx<DeviceId, FakeBindingsCtx<Id, Event, BindingsCtxState, ()>>,
-            Meta,
-            DeviceId,
-        >: SendFrameContext<
-            FakeBindingsCtx<Id, Event, BindingsCtxState, ()>,
-            SendIpPacketMeta<I, Self::DeviceId, SpecifiedAddr<I::Addr>>,
-        >,
-    {
-        fn lookup_route(
-            &mut self,
-            bindings_ctx: &mut FakeBindingsCtx<Id, Event, BindingsCtxState, ()>,
-            device: Option<&Self::DeviceId>,
-            local_ip: Option<IpDeviceAddr<I::Addr>>,
-            addr: RoutableIpAddr<I::Addr>,
-        ) -> Result<ResolvedRoute<I, Self::DeviceId>, ResolveRouteError> {
-            self.get_mut().lookup_route(bindings_ctx, device, local_ip, addr)
-        }
-
-        fn send_ip_packet<SS>(
-            &mut self,
-            bindings_ctx: &mut FakeBindingsCtx<Id, Event, BindingsCtxState, ()>,
-            SendIpPacketMeta {  device, src_ip, dst_ip, broadcast, next_hop, proto, ttl, mtu }: SendIpPacketMeta<I, &Self::DeviceId, SpecifiedAddr<I::Addr>>,
-            body: SS,
-        ) -> Result<(), SS>
+            bindings_ctx: &mut BC,
+            socket: &IpSock<I, Self::WeakDeviceId>,
+            body: S,
+            mtu: Option<u32>,
+            options: &O,
+        ) -> Result<(), (S, IpSockSendError)>
         where
-            SS: Serializer,
-            SS::Buffer: BufferMut,
+            S: TransportPacketSerializer,
+            S::Buffer: BufferMut,
+            O: SendOptions<I, Self::WeakDeviceId>,
         {
-            let meta = SendIpPacketMeta {
-                device: device.clone(),
-                src_ip,
-                dst_ip,
-                broadcast,
-                next_hop,
-                proto,
-                ttl,
+            IpSocketHandler::<I, BC>::send_ip_packet(
+                self.inner_mut::<I>(),
+                bindings_ctx,
+                socket,
+                body,
                 mtu,
-            };
-            self.send_frame(bindings_ctx, meta, body)
+                options,
+            )
         }
     }
 
-    impl<
-            I: IpDeviceStateIpExt,
-            D: FakeStrongDeviceId,
-            BC: RngContext + InstantContext<Instant = FakeInstant>,
-        > MulticastMembershipHandler<I, BC> for FakeDualStackIpSocketCtx<D, BC>
+    impl<I: IpLayerIpExt, Meta, DeviceId: FakeStrongDeviceId, BC> IpSocketHandler<I, BC>
+        for FakeCoreCtx<FakeDualStackIpSocketCtx<DeviceId>, Meta, DeviceId>
+    where
+        FakeCoreCtx<FakeDualStackIpSocketCtx<DeviceId>, Meta, DeviceId>:
+            SendFrameContext<BC, SendIpPacketMeta<I, Self::DeviceId, SpecifiedAddr<I::Addr>>>,
+    {
+        fn new_ip_socket(
+            &mut self,
+            bindings_ctx: &mut BC,
+            device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
+            local_ip: Option<SocketIpAddr<I::Addr>>,
+            remote_ip: SocketIpAddr<I::Addr>,
+            proto: I::Proto,
+        ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError> {
+            self.get_mut().new_ip_socket(bindings_ctx, device, local_ip, remote_ip, proto)
+        }
+
+        fn send_ip_packet<S, O>(
+            &mut self,
+            bindings_ctx: &mut BC,
+            socket: &IpSock<I, Self::WeakDeviceId>,
+            body: S,
+            mtu: Option<u32>,
+            options: &O,
+        ) -> Result<(), (S, IpSockSendError)>
+        where
+            S: TransportPacketSerializer,
+            S::Buffer: BufferMut,
+            O: SendOptions<I, Self::WeakDeviceId>,
+        {
+            let meta = match self.state.inner_mut::<I>().resolve_send_meta(socket, mtu, options) {
+                Ok(meta) => meta,
+                Err(e) => {
+                    return Err((body, e));
+                }
+            };
+            self.send_frame(bindings_ctx, meta, body).map_err(|s| (s, IpSockSendError::Mtu))
+        }
+    }
+
+    impl<I: IpLayerIpExt, D: FakeStrongDeviceId, BC> MulticastMembershipHandler<I, BC>
+        for FakeDualStackIpSocketCtx<D>
     {
         fn join_multicast_group(
             &mut self,
@@ -1739,97 +1339,67 @@
             device: &Self::DeviceId,
             addr: MulticastAddr<<I as Ip>::Addr>,
         ) {
-            let Self {
-                device_state,
-                table: _,
-                ip_forwarding_ctx: _,
-                v4_common_counters: _,
-                v6_common_counters: _,
-                tx_icmpv4_counters: _,
-                rx_icmpv4_counters: _,
-                tx_icmpv6_counters: _,
-                rx_icmpv6_counters: _,
-                ndp_counters: _,
-            } = self;
-            let state =
-                device_state.get_mut(device).unwrap_or_else(|| panic!("no device {device:?}"));
-            let state: &IpDeviceState<_, I> = state.as_ref();
-            let mut groups = state.multicast_groups.write();
-            groups.join_multicast_group(bindings_ctx, addr)
+            MulticastMembershipHandler::<I, BC>::join_multicast_group(
+                self.inner_mut::<I>(),
+                bindings_ctx,
+                device,
+                addr,
+            )
         }
 
         fn leave_multicast_group(
             &mut self,
-            _bindings_ctx: &mut BC,
+            bindings_ctx: &mut BC,
             device: &Self::DeviceId,
             addr: MulticastAddr<<I as Ip>::Addr>,
         ) {
-            let Self {
-                device_state,
-                table: _,
-                ip_forwarding_ctx: _,
-                v4_common_counters: _,
-                v6_common_counters: _,
-                tx_icmpv4_counters: _,
-                rx_icmpv4_counters: _,
-                tx_icmpv6_counters: _,
-                rx_icmpv6_counters: _,
-                ndp_counters: _,
-            } = self;
-            let state =
-                device_state.get_mut(device).unwrap_or_else(|| panic!("no device {device:?}"));
-            let state: &IpDeviceState<_, I> = state.as_ref();
-            let mut groups = state.multicast_groups.write();
-            groups.leave_multicast_group(addr)
+            MulticastMembershipHandler::<I, BC>::leave_multicast_group(
+                self.inner_mut::<I>(),
+                bindings_ctx,
+                device,
+                addr,
+            )
         }
 
         fn select_device_for_multicast_group(
             &mut self,
             addr: MulticastAddr<<I as Ip>::Addr>,
         ) -> Result<Self::DeviceId, ResolveRouteError> {
-            let Self { device_state, table, ip_forwarding_ctx, .. } = self;
-            let remote_ip = SocketIpAddr::new_from_multicast(addr);
-            let ResolvedRoute { device, .. }: ResolvedRoute<I, _> = lookup_route(
-                table.as_ref(),
-                ip_forwarding_ctx,
-                device_state,
-                None,
-                None,
-                remote_ip,
-            )?;
-            Ok(device)
+            MulticastMembershipHandler::<I, BC>::select_device_for_multicast_group(
+                self.inner_mut::<I>(),
+                addr,
+            )
         }
     }
 
-    impl<
-            I: IpLayerIpExt + IpDeviceStateIpExt,
-            BC: InstantContext + TracingContext + FilterBindingsTypes + 'static,
-            DeviceId: FakeFilterDeviceId<BC::DeviceClass>,
-        > TransportIpContext<I, BC> for FakeDualStackIpSocketCtx<DeviceId, BC>
+    impl<I: IpLayerIpExt, D: FakeStrongDeviceId, BC> TransportIpContext<I, BC>
+        for FakeDualStackIpSocketCtx<D>
     {
         fn get_default_hop_limits(&mut self, device: Option<&Self::DeviceId>) -> HopLimits {
-            device.map_or(DEFAULT_HOP_LIMITS, |device| {
-                let state: &IpDeviceState<_, I> = self.get_device_state(device).as_ref();
-                let hop_limit = state.default_hop_limit.read().clone();
-                HopLimits { unicast: hop_limit, multicast: DEFAULT_HOP_LIMITS.multicast }
-            })
+            TransportIpContext::<I, BC>::get_default_hop_limits(self.inner_mut::<I>(), device)
         }
 
-        type DevicesWithAddrIter<'a> = alloc::boxed::Box<dyn Iterator<Item = DeviceId> + 'a>;
+        type DevicesWithAddrIter<'a> = alloc::boxed::Box<dyn Iterator<Item = D> + 'a>;
 
         fn get_devices_with_assigned_addr(
             &mut self,
             addr: SpecifiedAddr<<I>::Addr>,
         ) -> Self::DevicesWithAddrIter<'_> {
-            Box::new(self.find_devices_with_addr::<I>(addr))
+            TransportIpContext::<I, BC>::get_devices_with_assigned_addr(self.inner_mut::<I>(), addr)
         }
 
         fn confirm_reachable_with_destination(
             &mut self,
-            _bindings_ctx: &mut BC,
-            _dst: SpecifiedAddr<<I>::Addr>,
-            _device: Option<&Self::DeviceId>,
+            bindings_ctx: &mut BC,
+            dst: SpecifiedAddr<<I>::Addr>,
+            device: Option<&Self::DeviceId>,
         ) {
+            TransportIpContext::<I, BC>::confirm_reachable_with_destination(
+                self.inner_mut::<I>(),
+                bindings_ctx,
+                dst,
+                device,
+            )
         }
     }
 
@@ -1841,21 +1411,144 @@
         pub(crate) remote_ips: Vec<A>,
     }
 
-    impl<I: IpLayerIpExt + IpDeviceStateIpExt, D: FakeStrongDeviceId> FakeIpSocketCtx<I, D> {
-        /// Creates a new `FakeIpSocketCtx<Ipv6>` with the given device
+    pub(crate) struct FakeDeviceState<I: Ip> {
+        pub default_hop_limit: NonZeroU8,
+        pub addresses: Vec<SpecifiedAddr<I::Addr>>,
+        pub multicast_groups: HashMap<MulticastAddr<I::Addr>, usize>,
+    }
+
+    impl<I: Ip> FakeDeviceState<I> {
+        pub fn is_in_multicast_group(&self, addr: &MulticastAddr<I::Addr>) -> bool {
+            self.multicast_groups.get(addr).is_some_and(|v| *v != 0)
+        }
+    }
+
+    impl<I: IpLayerIpExt, D: FakeStrongDeviceId> FakeIpSocketCtx<I, D> {
+        /// Creates a new `FakeIpSocketCtx` with the given device
         /// configs.
         pub(crate) fn new(
-            devices: impl IntoIterator<Item = FakeDeviceConfig<D, SpecifiedAddr<I::Addr>>>,
+            device_configs: impl IntoIterator<Item = FakeDeviceConfig<D, SpecifiedAddr<I::Addr>>>,
         ) -> Self {
-            FakeIpSocketCtx::with_devices_state(devices.into_iter().map(
-                |FakeDeviceConfig { device, local_ips, remote_ips }| {
-                    let mut device_state = IpDeviceState::default();
-                    for ip in local_ips {
-                        crate::ip::device::state::testutil::add_addr_subnet(&mut device_state, ip);
-                    }
-                    (device, device_state, remote_ips)
-                },
-            ))
+            let mut table = ForwardingTable::default();
+            let mut devices = HashMap::default();
+            for FakeDeviceConfig { device, local_ips, remote_ips } in device_configs {
+                for addr in remote_ips {
+                    crate::ip::forwarding::testutil::add_on_link_forwarding_entry(
+                        &mut table,
+                        addr,
+                        device.clone(),
+                    )
+                }
+                let state = FakeDeviceState {
+                    default_hop_limit: crate::ip::DEFAULT_HOP_LIMITS.unicast,
+                    addresses: local_ips,
+                    multicast_groups: Default::default(),
+                };
+                assert!(
+                    devices.insert(device.clone(), state).is_none(),
+                    "duplicate entries for {device:?}",
+                );
+            }
+
+            Self { table, devices, forwarding: Default::default() }
+        }
+
+        pub(crate) fn get_device_state(&self, device: &D) -> &FakeDeviceState<I> {
+            self.devices.get(device).unwrap_or_else(|| panic!("no device {device:?}"))
+        }
+
+        pub(crate) fn get_device_state_mut(&mut self, device: &D) -> &mut FakeDeviceState<I> {
+            self.devices.get_mut(device).unwrap_or_else(|| panic!("no device {device:?}"))
+        }
+
+        pub(crate) fn multicast_memberships(
+            &self,
+        ) -> HashMap<(D, MulticastAddr<I::Addr>), NonZeroUsize> {
+            self.devices
+                .iter()
+                .map(|(device, state)| {
+                    state.multicast_groups.iter().filter_map(|(group, count)| {
+                        NonZeroUsize::new(*count).map(|count| ((device.clone(), *group), count))
+                    })
+                })
+                .flatten()
+                .collect()
+        }
+
+        fn lookup_route(
+            &mut self,
+            device: Option<&D>,
+            local_ip: Option<IpDeviceAddr<I::Addr>>,
+            addr: RoutableIpAddr<I::Addr>,
+        ) -> Result<ResolvedRoute<I, D>, ResolveRouteError> {
+            let Self { table, devices, forwarding } = self;
+            let (destination, ()) = table
+                .lookup_filter_map(forwarding, device, addr.addr(), |_, d| match &local_ip {
+                    None => Some(()),
+                    Some(local_ip) => devices.get(d).and_then(|state| {
+                        state.addresses.contains(local_ip.as_ref()).then_some(())
+                    }),
+                })
+                .next()
+                .ok_or(ResolveRouteError::Unreachable)?;
+
+            let Destination { device, next_hop } = destination;
+            let mut addrs = devices.get(device).unwrap().addresses.iter();
+            let local_ip = match local_ip {
+                None => {
+                    let addr = addrs.next().ok_or(ResolveRouteError::NoSrcAddr)?;
+                    SocketIpAddr::new(addr.get()).expect("not valid socket addr")
+                }
+                Some(local_ip) => {
+                    // We already constrained the set of devices so this
+                    // should be a given.
+                    assert!(
+                        addrs.any(|a| a.get() == local_ip.addr()),
+                        "didn't find IP {:?} in {:?}",
+                        local_ip,
+                        addrs.collect::<Vec<_>>()
+                    );
+                    local_ip
+                }
+            };
+
+            Ok(ResolvedRoute {
+                src_addr: local_ip,
+                device: device.clone(),
+                local_delivery_device: None,
+                next_hop,
+            })
+        }
+
+        fn resolve_send_meta<O>(
+            &mut self,
+            socket: &IpSock<I, D::Weak>,
+            mtu: Option<u32>,
+            options: &O,
+        ) -> Result<SendIpPacketMeta<I, D, SpecifiedAddr<I::Addr>>, IpSockSendError>
+        where
+            O: SendOptions<I, D::Weak>,
+        {
+            let IpSockDefinition { remote_ip, local_ip, device, proto } = &socket.definition;
+            let device = device
+                .as_ref()
+                .map(|d| d.upgrade().ok_or(ResolveRouteError::Unreachable))
+                .transpose()?;
+            let ResolvedRoute { src_addr, device, next_hop, local_delivery_device: _ } =
+                self.lookup_route(device.as_ref(), Some(*local_ip), *remote_ip)?;
+
+            let remote_ip: &SpecifiedAddr<_> = remote_ip.as_ref();
+            let (next_hop, broadcast) = next_hop.into_next_hop_and_broadcast_marker(*remote_ip);
+            Ok(SendIpPacketMeta {
+                device,
+                src_ip: src_addr.into(),
+                dst_ip: *remote_ip,
+                broadcast,
+                next_hop,
+                proto: *proto,
+                ttl: options.hop_limit(remote_ip),
+                mtu,
+            })
         }
     }
 }
@@ -1876,7 +1569,7 @@
     use packet_formats::{
         ethernet::EthernetFrameLengthCheck,
         icmp::{IcmpIpExt, IcmpUnusedCode},
-        ip::{IpExt, IpPacket, Ipv4Proto},
+        ip::{IpExt, IpPacket},
         ipv4::{Ipv4OnlyMeta, Ipv4Packet},
         testutil::{parse_ethernet_frame, parse_ip_packet_in_ethernet_frame},
     };
@@ -1887,7 +1580,6 @@
         context::EventContext,
         device::{
             loopback::{LoopbackCreationProperties, LoopbackDevice},
-            testutil::FakeDeviceId,
             DeviceId, EthernetLinkDevice,
         },
         ip::{
@@ -1944,11 +1636,15 @@
     #[derive(Copy, Clone, Debug, Eq, PartialEq)]
     struct WithHopLimit(Option<NonZeroU8>);
 
-    impl<I: Ip> SendOptions<I> for WithHopLimit {
+    impl<I: Ip, D> SendOptions<I, D> for WithHopLimit {
         fn hop_limit(&self, _destination: &SpecifiedAddr<I::Addr>) -> Option<NonZeroU8> {
             let Self(hop_limit) = self;
             *hop_limit
         }
+
+        fn multicast_interface(&self) -> Option<&D> {
+            None
+        }
     }
 
     #[netstack3_macros::context_ip_bounds(I, FakeBindingsCtx, crate)]
@@ -2118,7 +1814,6 @@
                 device: weak_local_device.clone(),
                 proto,
             },
-            options: WithHopLimit(None),
         };
 
         let res = IpSocketHandler::<I, _>::new_ip_socket(
@@ -2128,32 +1823,8 @@
             from_ip.map(|a| SocketIpAddr::try_from(a).unwrap()),
             SocketIpAddr::try_from(to_ip).unwrap(),
             proto,
-            WithHopLimit(None),
-        )
-        .map_err(|(e, WithHopLimit(_))| e);
-        assert_eq!(res, get_expected_result(template.clone()));
-
-        // Hop Limit is specified.
-        const SPECIFIED_HOP_LIMIT: NonZeroU8 = const_unwrap_option(NonZeroU8::new(1));
-        assert_eq!(
-            IpSocketHandler::new_ip_socket(
-                &mut core_ctx.context(),
-                bindings_ctx,
-                weak_local_device.as_ref().map(EitherDeviceId::Weak),
-                from_ip.map(|a| SocketIpAddr::try_from(a).unwrap()),
-                SocketIpAddr::try_from(to_ip).unwrap(),
-                proto,
-                WithHopLimit(Some(SPECIFIED_HOP_LIMIT)),
-            )
-            .map_err(|(e, WithHopLimit(_))| e),
-            {
-                // The template socket, but with the TTL set to 1.
-                let mut template_with_hop_limit = template;
-                let IpSock { definition: _, options } = &mut template_with_hop_limit;
-                *options = WithHopLimit(Some(SPECIFIED_HOP_LIMIT));
-                get_expected_result(template_with_hop_limit)
-            }
         );
+        assert_eq!(res, get_expected_result(template));
     }
 
     #[ip_test]
@@ -2236,7 +1907,6 @@
             from_ip.map(|a| SocketIpAddr::try_from(a).unwrap()),
             SocketIpAddr::try_from(to_ip).unwrap(),
             I::ICMP_IP_PROTO,
-            DefaultSendOptions,
         )
         .unwrap();
 
@@ -2260,6 +1930,7 @@
             &sock,
             buffer.into_inner().buffer_view().as_ref().into_serializer(),
             None,
+            &DefaultSendOptions,
         )
         .unwrap();
 
@@ -2298,7 +1969,6 @@
             None,
             SocketIpAddr::try_from(remote_ip).unwrap(),
             proto,
-            socket_options,
         )
         .unwrap();
 
@@ -2347,6 +2017,7 @@
             &sock,
             (&[0u8][..]).into_serializer(),
             None,
+            &socket_options,
         )
         .unwrap();
         let mut check_sent_frame = |bindings_ctx: &mut crate::testutil::FakeBindingsCtx| {
@@ -2368,6 +2039,7 @@
             &sock,
             small_body_serializer,
             Some(Ipv6::MINIMUM_LINK_MTU.into()),
+            &socket_options,
         );
         assert_matches!(res, Ok(()));
         check_sent_frame(&mut bindings_ctx);
@@ -2380,6 +2052,7 @@
             &sock,
             small_body_serializer,
             Some(1), // mtu
+            &socket_options,
         );
         assert_matches!(res, Err((_, IpSockSendError::Mtu)));
 
@@ -2392,6 +2065,7 @@
             &sock,
             (&[0; Ipv6::MINIMUM_LINK_MTU.get() as usize][..]).into_serializer(),
             None,
+            &socket_options,
         );
         assert_matches!(res, Err((_, IpSockSendError::Mtu)));
 
@@ -2408,6 +2082,7 @@
             &sock,
             small_body_serializer,
             None,
+            &socket_options,
         );
         assert_matches!(res, Err((_, IpSockSendError::Unroutable(ResolveRouteError::Unreachable))));
     }
@@ -2422,11 +2097,15 @@
 
         const SET_HOP_LIMIT: NonZeroU8 = const_unwrap_option(NonZeroU8::new(42));
 
-        impl<A: IpAddress> SendOptions<A::Version> for SetHopLimitFor<A> {
+        impl<A: IpAddress, D> SendOptions<A::Version, D> for SetHopLimitFor<A> {
             fn hop_limit(&self, destination: &SpecifiedAddr<A>) -> Option<NonZeroU8> {
                 let Self(expected_destination) = self;
                 (destination == expected_destination).then_some(SET_HOP_LIMIT)
             }
+
+            fn multicast_interface(&self) -> Option<&D> {
+                None
+            }
         }
 
         let FakeEventDispatcherConfig::<I::Addr> {
@@ -2469,7 +2148,6 @@
                 None,
                 destination_ip,
                 I::ICMP_IP_PROTO,
-                options,
             )
             .unwrap();
 
@@ -2479,6 +2157,7 @@
                 &sock,
                 (&[0u8][..]).into_serializer(),
                 None,
+                &options,
             )
             .unwrap();
         };
@@ -2512,28 +2191,6 @@
         }
     }
 
-    #[test]
-    fn manipulate_options() {
-        // The values here don't matter since we won't actually be using this
-        // socket to send anything.
-        const START_OPTION: usize = 23;
-        const DEFAULT_OPTION: usize = 0;
-        const NEW_OPTION: usize = 55;
-        let mut socket = IpSock::<Ipv4, FakeDeviceId, _> {
-            definition: IpSockDefinition {
-                remote_ip: SocketIpAddr::new(Ipv4::LOOPBACK_ADDRESS.get()).unwrap(),
-                local_ip: SocketIpAddr::new(Ipv4::LOOPBACK_ADDRESS.get()).unwrap(),
-                device: None,
-                proto: Ipv4Proto::Icmp,
-            },
-            options: START_OPTION,
-        };
-
-        assert_eq!(socket.take_options(), START_OPTION);
-        assert_eq!(socket.replace_options(NEW_OPTION), DEFAULT_OPTION);
-        assert_eq!(socket.options, NEW_OPTION);
-    }
-
     #[ip_test]
     #[test_case(true; "remove device")]
     #[test_case(false; "dont remove device")]
@@ -2580,7 +2237,6 @@
             None,
             SocketIpAddr::try_from(I::multicast_addr(1)).unwrap(),
             I::ICMP_IP_PROTO,
-            WithHopLimit(None),
         )
         .unwrap();
 
diff --git a/src/connectivity/network/netstack3/core/src/ip/types.rs b/src/connectivity/network/netstack3/core/src/ip/types.rs
index f33a77e..dd8368c 100644
--- a/src/connectivity/network/netstack3/core/src/ip/types.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/types.rs
@@ -399,6 +399,23 @@
     type Type = NextHop<NewIp::Addr>;
 }
 
+impl<A> NextHop<A>
+where
+    A: IpAddress,
+    A::Version: IpTypesIpExt,
+{
+    pub(crate) fn into_next_hop_and_broadcast_marker(
+        self,
+        remote_ip: SpecifiedAddr<A>,
+    ) -> (SpecifiedAddr<A>, Option<<A::Version as IpTypesIpExt>::BroadcastMarker>) {
+        match self {
+            NextHop::RemoteAsNeighbor => (remote_ip, None),
+            NextHop::Gateway(gateway) => (gateway, None),
+            NextHop::Broadcast(marker) => (remote_ip, Some(marker)),
+        }
+    }
+}
+
 /// An IP Address that witnesses properties needed to be routed.
 pub type RoutableIpAddr<A> = SocketIpAddr<A>;
 
diff --git a/src/connectivity/network/netstack3/core/src/lib.rs b/src/connectivity/network/netstack3/core/src/lib.rs
index d9fb287..e04b9c4 100644
--- a/src/connectivity/network/netstack3/core/src/lib.rs
+++ b/src/connectivity/network/netstack3/core/src/lib.rs
@@ -111,14 +111,15 @@
     #[cfg(test)]
     pub(crate) use netstack3_filter::testutil::NoopImpl;
     pub use netstack3_filter::{
-        Action, AddressMatcher, AddressMatcherType, FilterApi, FilterBindingsTypes, Hook,
-        InterfaceMatcher, InterfaceProperties, IpRoutines, NatRoutines, PacketMatcher, PortMatcher,
-        Routine, Routines, Rule, TransportProtocolMatcher, UninstalledRoutine, ValidationError,
+        Action, AddressMatcher, AddressMatcherType, FilterApi, FilterBindingsContext,
+        FilterBindingsTypes, Hook, InterfaceMatcher, InterfaceProperties, IpRoutines, NatRoutines,
+        PacketMatcher, PortMatcher, ProofOfEgressCheck, Routine, Routines, Rule,
+        TransportProtocolMatcher, UninstalledRoutine, ValidationError,
     };
     pub(crate) use netstack3_filter::{
-        FilterContext, FilterHandler, FilterImpl, FilterIpContext, ForwardedPacket, IpPacket,
-        MaybeTransportPacket, NestedWithInnerIpPacket, RxPacket, State, TransportPacketSerializer,
-        TxPacket, Verdict,
+        ConntrackConnection, FilterContext, FilterHandler, FilterImpl, FilterIpContext,
+        FilterIpMetadata, ForwardedPacket, IpPacket, MaybeTransportPacket, NestedWithInnerIpPacket,
+        RxPacket, State, TransportPacketSerializer, TxPacket, Verdict,
     };
 }
 
diff --git a/src/connectivity/network/netstack3/core/src/macros.rs b/src/connectivity/network/netstack3/core/src/macros.rs
index 19602dc..6712d92 100644
--- a/src/connectivity/network/netstack3/core/src/macros.rs
+++ b/src/connectivity/network/netstack3/core/src/macros.rs
@@ -43,6 +43,13 @@
             impl_timer_context!(@inner $outer_timer_id, $inner_timer_id, $pat, $bound_variable);
         }
     };
+    ($other_type_arg:ident: $o_bound:path, $outer_timer_id:ty, $inner_timer_id:ty, $pat:pat, $bound_variable:ident) => {
+        impl<$other_type_arg: $o_bound, C: crate::context::TimerContext<$outer_timer_id>>
+            crate::context::TimerContext<$inner_timer_id> for C
+        {
+            impl_timer_context!(@inner $outer_timer_id, $inner_timer_id, $pat, $bound_variable);
+        }
+    };
     (@inner $outer_timer_id:ty, $inner_timer_id:ty, $pat:pat, $bound_variable:ident) => {
         fn schedule_timer_instant(
             &mut self,
diff --git a/src/connectivity/network/netstack3/core/src/marker.rs b/src/connectivity/network/netstack3/core/src/marker.rs
index 453506395..68ebe17 100644
--- a/src/connectivity/network/netstack3/core/src/marker.rs
+++ b/src/connectivity/network/netstack3/core/src/marker.rs
@@ -18,7 +18,7 @@
         self, AnyDevice, DeviceId, DeviceIdContext, DeviceLayerTypes, EthernetDeviceId,
         EthernetLinkDevice, EthernetWeakDeviceId, WeakDeviceId,
     },
-    filter::FilterBindingsTypes,
+    filter::{FilterBindingsContext, FilterBindingsTypes},
     ip::{
         self,
         device::{
@@ -142,6 +142,7 @@
     + RngContext
     + UdpBindingsContext<I, DeviceId<Self>>
     + TcpBindingsContext<I, WeakDeviceId<Self>>
+    + FilterBindingsContext
     + IcmpBindingsContext<I, DeviceId<Self>>
     + IpDeviceBindingsContext<I, DeviceId<Self>>
     + IpLayerBindingsContext<I, DeviceId<Self>>
@@ -161,6 +162,7 @@
         + RngContext
         + UdpBindingsContext<I, DeviceId<Self>>
         + TcpBindingsContext<I, WeakDeviceId<Self>>
+        + FilterBindingsContext
         + IcmpBindingsContext<I, DeviceId<Self>>
         + IpDeviceBindingsContext<I, DeviceId<Self>>
         + IpLayerBindingsContext<I, DeviceId<Self>>
diff --git a/src/connectivity/network/netstack3/core/src/socket/datagram.rs b/src/connectivity/network/netstack3/core/src/socket/datagram.rs
index 928d40c..5f29dc38e 100644
--- a/src/connectivity/network/netstack3/core/src/socket/datagram.rs
+++ b/src/connectivity/network/netstack3/core/src/socket/datagram.rs
@@ -32,7 +32,7 @@
     algorithm::ProtocolFlowId,
     context::{ReferenceNotifiers, RngContext},
     convert::{BidirectionalConverter, OwnedOrRefsBidirectionalConverter},
-    device::{self, AnyDevice, DeviceIdContext},
+    device::{self, AnyDevice, DeviceIdContext, StrongId as _, WeakId as _},
     error::ExistsError,
     error::{LocalAddressError, NotFoundError, RemoteAddressError, SocketError, ZonedAddressError},
     filter::TransportPacketSerializer,
@@ -86,7 +86,7 @@
 impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> Debug for DatagramSocketSet<I, D, S> {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let Self(rc) = self;
-        f.debug_list().entries(rc.keys().map(StrongRc::ptr_debug)).finish()
+        f.debug_list().entries(rc.keys().map(StrongRc::debug_id)).finish()
     }
 }
 
@@ -108,7 +108,7 @@
 
 #[derive(Derivative, GenericOverIp)]
 #[generic_over_ip(I, Ip)]
-#[derivative(Debug(bound = "D: Debug"))]
+#[derivative(Debug(bound = ""))]
 pub enum SocketState<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> {
     Unbound(UnboundSocketState<I, D, S>),
     Bound(BoundSocketState<I, D, S>),
@@ -306,14 +306,16 @@
 }
 
 #[derive(Derivative)]
-#[derivative(Debug(bound = "D: Debug"), Default(bound = ""))]
-pub struct UnboundSocketState<I: IpExt, D, S: DatagramSocketSpec> {
+#[derivative(Debug(bound = ""), Default(bound = ""))]
+pub struct UnboundSocketState<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> {
     device: Option<D>,
     sharing: S::SharingState,
     ip_options: IpOptions<I, D, S>,
 }
 
-impl<I: IpExt, D, S: DatagramSocketSpec> AsRef<IpOptions<I, D, S>> for UnboundSocketState<I, D, S> {
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsRef<IpOptions<I, D, S>>
+    for UnboundSocketState<I, D, S>
+{
     fn as_ref(&self) -> &IpOptions<I, D, S> {
         &self.ip_options
     }
@@ -321,12 +323,12 @@
 
 #[derive(Derivative)]
 #[derivative(Debug(bound = ""))]
-pub(crate) struct ListenerState<I: IpExt, D: Hash + Eq + Debug, S: DatagramSocketSpec + ?Sized> {
+pub(crate) struct ListenerState<I: IpExt, D: device::WeakId, S: DatagramSocketSpec + ?Sized> {
     pub(crate) ip_options: IpOptions<I, D, S>,
     pub(crate) addr: ListenerAddr<S::ListenerIpAddr<I>, D>,
 }
 
-impl<I: IpExt, D: Debug + Hash + Eq, S: DatagramSocketSpec> AsRef<IpOptions<I, D, S>>
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsRef<IpOptions<I, D, S>>
     for ListenerState<I, D, S>
 {
     fn as_ref(&self) -> &IpOptions<I, D, S> {
@@ -336,8 +338,13 @@
 
 #[derive(Derivative)]
 #[derivative(Debug(bound = "D: Debug"))]
-pub struct ConnState<WireI: IpExt, SocketI: IpExt, D: Eq + Hash, S: DatagramSocketSpec + ?Sized> {
-    pub(crate) socket: IpSock<WireI, D, SocketHopLimits<WireI>>,
+pub struct ConnState<
+    WireI: IpExt,
+    SocketI: IpExt,
+    D: device::WeakId,
+    S: DatagramSocketSpec + ?Sized,
+> {
+    pub(crate) socket: IpSock<WireI, D>,
     pub(crate) ip_options: IpOptions<SocketI, D, S>,
     pub(crate) shutdown: Shutdown,
     pub(crate) addr: ConnAddr<
@@ -371,7 +378,7 @@
     pub(crate) extra: S::ConnStateExtra,
 }
 
-impl<WireI: IpExt, SocketI: IpExt, D: Hash + Eq, S: DatagramSocketSpec>
+impl<WireI: IpExt, SocketI: IpExt, D: device::WeakId, S: DatagramSocketSpec>
     AsRef<IpOptions<SocketI, D, S>> for ConnState<WireI, SocketI, D, S>
 {
     fn as_ref(&self) -> &IpOptions<SocketI, D, S> {
@@ -379,7 +386,7 @@
     }
 }
 
-impl<WireI: IpExt, SocketI: IpExt, D: Hash + Eq, S: DatagramSocketSpec> AsRef<Shutdown>
+impl<WireI: IpExt, SocketI: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsRef<Shutdown>
     for ConnState<WireI, SocketI, D, S>
 {
     fn as_ref(&self) -> &Shutdown {
@@ -387,7 +394,7 @@
     }
 }
 
-impl<WireI: IpExt, SocketI: IpExt, D: Hash + Eq, S: DatagramSocketSpec>
+impl<WireI: IpExt, SocketI: IpExt, D: device::WeakId, S: DatagramSocketSpec>
     AsMut<IpOptions<SocketI, D, S>> for ConnState<WireI, SocketI, D, S>
 {
     fn as_mut(&mut self) -> &mut IpOptions<SocketI, D, S> {
@@ -395,7 +402,7 @@
     }
 }
 
-impl<WireI: IpExt, SocketI: IpExt, D: Hash + Eq, S: DatagramSocketSpec> AsMut<Shutdown>
+impl<WireI: IpExt, SocketI: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsMut<Shutdown>
     for ConnState<WireI, SocketI, D, S>
 {
     fn as_mut(&mut self) -> &mut Shutdown {
@@ -403,7 +410,7 @@
     }
 }
 
-impl<WireI: IpExt, SocketI: IpExt, D: Eq + Hash, S: DatagramSocketSpec>
+impl<WireI: IpExt, SocketI: IpExt, D: device::WeakId, S: DatagramSocketSpec>
     ConnState<WireI, SocketI, D, S>
 {
     pub(crate) fn should_receive(&self) -> bool {
@@ -422,16 +429,19 @@
 
 /// Connection state belong to either this-stack or the other-stack.
 #[derive(Derivative)]
-#[derivative(Debug(bound = "D: Debug"))]
-pub enum DualStackConnState<I: IpExt + DualStackIpExt, D: Eq + Hash, S: DatagramSocketSpec + ?Sized>
-{
+#[derivative(Debug(bound = ""))]
+pub enum DualStackConnState<
+    I: IpExt + DualStackIpExt,
+    D: device::WeakId,
+    S: DatagramSocketSpec + ?Sized,
+> {
     /// The [`ConnState`] for a socked connected with [`I::Version`].
     ThisStack(ConnState<I, I, D, S>),
     /// The [`ConnState`] for a socked connected with [`I::OtherVersion`].
     OtherStack(ConnState<I::OtherVersion, I, D, S>),
 }
 
-impl<I: IpExt, D: Hash + Eq, S: DatagramSocketSpec> AsRef<IpOptions<I, D, S>>
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsRef<IpOptions<I, D, S>>
     for DualStackConnState<I, D, S>
 {
     fn as_ref(&self) -> &IpOptions<I, D, S> {
@@ -442,7 +452,7 @@
     }
 }
 
-impl<I: IpExt, D: Hash + Eq, S: DatagramSocketSpec> AsMut<IpOptions<I, D, S>>
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsMut<IpOptions<I, D, S>>
     for DualStackConnState<I, D, S>
 {
     fn as_mut(&mut self) -> &mut IpOptions<I, D, S> {
@@ -453,7 +463,7 @@
     }
 }
 
-impl<I: IpExt, D: Hash + Eq, S: DatagramSocketSpec> AsRef<Shutdown>
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsRef<Shutdown>
     for DualStackConnState<I, D, S>
 {
     fn as_ref(&self) -> &Shutdown {
@@ -464,7 +474,7 @@
     }
 }
 
-impl<I: IpExt, D: Hash + Eq, S: DatagramSocketSpec> AsMut<Shutdown>
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsMut<Shutdown>
     for DualStackConnState<I, D, S>
 {
     fn as_mut(&mut self) -> &mut Shutdown {
@@ -477,26 +487,42 @@
 
 #[derive(Derivative, GenericOverIp)]
 #[generic_over_ip(I, Ip)]
-#[derivative(Clone(bound = "D: Clone"), Debug(bound = "D: Debug"), Default(bound = ""))]
-pub struct IpOptions<I: IpExt, D, S: DatagramSocketSpec + ?Sized> {
+#[derivative(Clone(bound = ""), Debug, Default(bound = ""))]
+pub struct IpOptions<I: IpExt, D: device::WeakId, S: DatagramSocketSpec + ?Sized> {
     multicast_memberships: MulticastMemberships<I::Addr, D>,
+    multicast_interface: Option<D>,
     hop_limits: SocketHopLimits<I>,
-    other_stack: S::OtherStackIpOptions<I>,
+    other_stack: S::OtherStackIpOptions<I, D>,
     transparent: bool,
 }
 
-impl<I: IpExt, D, S: DatagramSocketSpec> AsRef<Self> for IpOptions<I, D, S> {
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> AsRef<Self> for IpOptions<I, D, S> {
     fn as_ref(&self) -> &Self {
         self
     }
 }
 
-impl<I: IpExt, D, S: DatagramSocketSpec> IpOptions<I, D, S> {
-    pub(crate) fn other_stack(&self) -> &S::OtherStackIpOptions<I> {
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> IpOptions<I, D, S> {
+    pub(crate) fn other_stack(&self) -> &S::OtherStackIpOptions<I, D> {
         &self.other_stack
     }
 }
 
+impl<I: IpExt, D: device::WeakId, S: DatagramSocketSpec> SendOptions<I, D> for IpOptions<I, D, S> {
+    fn hop_limit(&self, destination: &SpecifiedAddr<I::Addr>) -> Option<NonZeroU8> {
+        let Self { hop_limits: SocketHopLimits { unicast, multicast, version: _ }, .. } = self;
+        if destination.is_multicast() {
+            *multicast
+        } else {
+            *unicast
+        }
+    }
+
+    fn multicast_interface(&self) -> Option<&D> {
+        self.multicast_interface.as_ref()
+    }
+}
+
 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
 pub(crate) struct SocketHopLimits<I: Ip> {
     pub(crate) unicast: Option<NonZeroU8>,
@@ -527,17 +553,6 @@
     }
 }
 
-impl<I: Ip> SendOptions<I> for SocketHopLimits<I> {
-    fn hop_limit(&self, destination: &SpecifiedAddr<I::Addr>) -> Option<NonZeroU8> {
-        let SocketHopLimits { unicast, multicast, version: _ } = self;
-        if destination.is_multicast() {
-            *multicast
-        } else {
-            *unicast
-        }
-    }
-}
-
 #[derive(Clone, Debug, Derivative)]
 #[derivative(Default(bound = ""))]
 pub(crate) struct MulticastMemberships<A, D>(HashSet<(MulticastAddr<A>, D)>);
@@ -548,7 +563,7 @@
     Leave,
 }
 
-impl<A: Eq + Hash, D: Eq + Hash + Clone> MulticastMemberships<A, D> {
+impl<A: Eq + Hash, D: device::WeakId> MulticastMemberships<A, D> {
     pub(crate) fn apply_membership_change(
         &mut self,
         address: MulticastAddr<A>,
@@ -597,7 +612,7 @@
     memberships: MulticastMemberships<A, CC::WeakDeviceId>,
 ) {
     for (addr, device) in memberships {
-        let Some(device) = core_ctx.upgrade_weak_device_id(&device) else {
+        let Some(device) = device.upgrade() else {
             continue;
         };
         core_ctx.leave_multicast_group(bindings_ctx, &device, addr)
@@ -794,11 +809,14 @@
     /// Returns if the socket state indicates dual-stack operation is enabled.
     fn dual_stack_enabled(&self, state: &impl AsRef<IpOptions<I, Self::WeakDeviceId, S>>) -> bool;
 
+    /// Type for [`SendOptions`] for the other stack.
+    type OtherSendOptions: SendOptions<I::OtherVersion, Self::WeakDeviceId>;
+
     /// Returns the [`SendOptions`] to use for packets in the other stack.
     fn to_other_send_options<'a>(
         &self,
         state: &'a IpOptions<I, Self::WeakDeviceId, S>,
-    ) -> &'a SocketHopLimits<I::OtherVersion>;
+    ) -> &'a Self::OtherSendOptions;
 
     /// Asserts that the socket state indicates dual-stack operation is enabled.
     ///
@@ -1006,7 +1024,7 @@
         + Into<ConnInfoAddr<Self::Addr, <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier>>;
 
     /// Connection state for a dual-stack socket.
-    type DualStackConnState<D: Eq + Hash + Debug + Send + Sync, S: DatagramSocketSpec>: Debug
+    type DualStackConnState<D: device::WeakId, S: DatagramSocketSpec>: Debug
         + AsRef<IpOptions<Self, D, S>>
         + AsMut<IpOptions<Self, D, S>>
         + Send
@@ -1024,7 +1042,7 @@
         Self: IpExt;
 
     /// Retrieves the associated connection address from the connection state.
-    fn conn_addr_from_state<D: Eq + Hash + Debug + Clone + Send + Sync, S: DatagramSocketSpec>(
+    fn conn_addr_from_state<D: device::WeakId, S: DatagramSocketSpec>(
         state: &Self::DualStackConnState<D, S>,
     ) -> ConnAddr<Self::DualStackConnIpAddr<S>, D>;
 }
@@ -1056,8 +1074,7 @@
         <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
     >;
     /// IPv4 sockets cannot connect on dual-stack addresses.
-    type DualStackConnState<D: Eq + Hash + Debug + Send + Sync, S: DatagramSocketSpec> =
-        ConnState<Self, Self, D, S>;
+    type DualStackConnState<D: device::WeakId, S: DatagramSocketSpec> = ConnState<Self, Self, D, S>;
 
     fn into_dual_stack_bound_socket_id<D: device::WeakId, S: DatagramSocketSpec>(
         id: S::SocketId<Self, D>,
@@ -1065,7 +1082,7 @@
         EitherIpSocket::V4(id)
     }
 
-    fn conn_addr_from_state<D: Clone + Debug + Eq + Hash + Send + Sync, S: DatagramSocketSpec>(
+    fn conn_addr_from_state<D: device::WeakId, S: DatagramSocketSpec>(
         state: &Self::DualStackConnState<D, S>,
     ) -> ConnAddr<Self::DualStackConnIpAddr<S>, D> {
         let ConnState {
@@ -1097,7 +1114,7 @@
     >;
     /// IPv6 sockets can connect on dual-stack addresses (if the protocol and
     /// socket are dual-stack-enabled).
-    type DualStackConnState<D: Eq + Hash + Debug + Send + Sync, S: DatagramSocketSpec> =
+    type DualStackConnState<D: device::WeakId, S: DatagramSocketSpec> =
         DualStackConnState<Self, D, S>;
 
     fn into_dual_stack_bound_socket_id<D: device::WeakId, S: DatagramSocketSpec>(
@@ -1106,7 +1123,7 @@
         id
     }
 
-    fn conn_addr_from_state<D: Clone + Debug + Eq + Hash + Send + Sync, S: DatagramSocketSpec>(
+    fn conn_addr_from_state<D: device::WeakId, S: DatagramSocketSpec>(
         state: &Self::DualStackConnState<D, S>,
     ) -> ConnAddr<Self::DualStackConnIpAddr<S>, D> {
         match state {
@@ -1175,7 +1192,7 @@
         + From<StrongRc<I, D, Self>>;
 
     /// IP-level options for sending `I::OtherVersion` IP packets.
-    type OtherStackIpOptions<I: IpExt>: Clone + Debug + Default + Send + Sync;
+    type OtherStackIpOptions<I: IpExt, D: device::WeakId>: Clone + Debug + Default + Send + Sync;
 
     /// The type of a listener IP address.
     ///
@@ -1213,7 +1230,7 @@
     /// [`DualStackIpExt::ConnState`], which will be one of [`ConnState`] or
     /// [`DualStackConnState`]. Non-dual-stack-capable protocols (like ICMP and
     /// raw IP sockets) should just use [`ConnState`].
-    type ConnState<I: IpExt, D: Debug + Eq + Hash + Send + Sync>: Debug
+    type ConnState<I: IpExt, D: device::WeakId>: Debug
         + AsRef<IpOptions<I, D, Self>>
         + AsMut<IpOptions<I, D, Self>>
         + Send
@@ -1286,7 +1303,7 @@
     ) -> Option<<Self::AddrSpec as SocketMapAddrSpec>::LocalIdentifier>;
 
     /// Retrieves the associated connection info from the connection state.
-    fn conn_info_from_state<I: IpExt, D: Clone + Debug + Eq + Hash + Send + Sync>(
+    fn conn_info_from_state<I: IpExt, D: device::WeakId>(
         state: &Self::ConnState<I, D>,
     ) -> ConnInfo<I::Addr, D>;
 
@@ -2377,7 +2394,7 @@
         .ok_or(LocalAddressError::FailedToAllocateLocalPort)?;
         let (addr, device, identifier) =
             try_pick_bound_address::<I, _, _, _>(addr, device, core_ctx, identifier)?;
-        let weak_device = device.map(|d| d.as_weak(core_ctx).into_owned());
+        let weak_device = device.map(|d| d.as_weak().into_owned());
 
         BoundStateHandler::<_, S, _>::try_insert_listener(
             bound,
@@ -2466,7 +2483,7 @@
                     .ok_or(LocalAddressError::FailedToAllocateLocalPort)?;
                     let (_addr, device, identifier) =
                         try_pick_bound_address::<I, _, _, _>(None, device, core_ctx, identifier)?;
-                    let weak_device = device.map(|d| d.as_weak(core_ctx).into_owned());
+                    let weak_device = device.map(|d| d.as_weak().into_owned());
 
                     BoundStateHandler::<_, S, _>::try_insert_listener(
                         &mut bound_pair,
@@ -2545,7 +2562,6 @@
     device: Option<D>,
     sharing: S::SharingState,
     ip_options: IpOptions<SocketI, D, S>,
-    send_options: SocketHopLimits<WireI>,
     socket_id:
         <S::SocketMapSpec<WireI, D> as DatagramSocketMapSpec<WireI, D, S::AddrSpec>>::BoundSocketId,
     original_shutdown: Option<Shutdown>,
@@ -2587,7 +2603,6 @@
         device,
         sharing,
         ip_options,
-        send_options,
         socket_id,
         original_shutdown,
         extra,
@@ -2608,9 +2623,7 @@
         local_ip.map(SocketIpAddr::into),
         remote_ip,
         S::ip_proto::<WireI>(),
-        send_options,
-    )
-    .map_err(|(e, _ip_options)| e)?;
+    )?;
 
     let local_port = match local_port {
         Some(id) => id.clone(),
@@ -2691,7 +2704,6 @@
                         device: device.clone(),
                         sharing: sharing.clone(),
                         ip_options: ip_options.clone(),
-                        send_options: ip_options.hop_limits,
                         socket_id: S::make_bound_socket_map_id(socket_id),
                         original_shutdown: None,
                         extra,
@@ -2719,7 +2731,6 @@
                                 device: device.clone(),
                                 sharing: sharing.clone(),
                                 ip_options: ip_options.clone(),
-                                send_options: ip_options.hop_limits,
                                 socket_id: S::make_bound_socket_map_id(socket_id),
                                 original_shutdown: None,
                                 extra,
@@ -2750,7 +2761,6 @@
                                 device: device.clone(),
                                 sharing: sharing.clone(),
                                 ip_options: ip_options.clone(),
-                                send_options: ip_options.hop_limits,
                                 socket_id: S::make_bound_socket_map_id(socket_id),
                                 original_shutdown: Some(shutdown.clone()),
                                 extra,
@@ -2831,7 +2841,6 @@
                             device: device.clone(),
                             sharing: sharing.clone(),
                             ip_options: ip_options.clone(),
-                            send_options: ip_options.hop_limits,
                             socket_id: S::make_bound_socket_map_id(socket_id),
                             original_shutdown: None,
                             extra,
@@ -2849,7 +2858,6 @@
                             device: device.clone(),
                             sharing: sharing.clone(),
                             ip_options: ip_options.clone(),
-                            send_options: core_ctx.to_other_send_options(ip_options).clone(),
                             socket_id: core_ctx.to_other_bound_socket_id(socket_id),
                             original_shutdown: None,
                             extra,
@@ -2897,7 +2905,6 @@
                                     device: device.clone(),
                                     sharing: sharing.clone(),
                                     ip_options: ip_options.clone(),
-                                    send_options: ip_options.hop_limits,
                                     socket_id: S::make_bound_socket_map_id(socket_id),
                                     original_shutdown: None,
                                     extra,
@@ -2920,7 +2927,6 @@
                                     device: device.clone(),
                                     sharing: sharing.clone(),
                                     ip_options: ip_options.clone(),
-                                    send_options: ip_options.hop_limits,
                                     socket_id: S::make_bound_socket_map_id(socket_id),
                                     original_shutdown: None,
                                     extra,
@@ -2944,9 +2950,6 @@
                                     device: device.clone(),
                                     sharing: sharing.clone(),
                                     ip_options: ip_options.clone(),
-                                    send_options: core_ctx
-                                        .to_other_send_options(ip_options)
-                                        .clone(),
                                     socket_id: core_ctx.to_other_bound_socket_id(socket_id),
                                     original_shutdown: None,
                                     extra,
@@ -2969,9 +2972,6 @@
                                     device: device.clone(),
                                     sharing: sharing.clone(),
                                     ip_options: ip_options.clone(),
-                                    send_options: core_ctx
-                                        .to_other_send_options(ip_options)
-                                        .clone(),
                                     socket_id: core_ctx.to_other_bound_socket_id(socket_id),
                                     original_shutdown: None,
                                     extra,
@@ -3020,7 +3020,6 @@
                                     device: device.clone(),
                                     sharing: sharing.clone(),
                                     ip_options: ip_options.clone(),
-                                    send_options: ip_options.hop_limits,
                                     socket_id: S::make_bound_socket_map_id(socket_id),
                                     original_shutdown: Some(shutdown.clone()),
                                     extra,
@@ -3053,9 +3052,6 @@
                                     device: device.clone(),
                                     sharing: sharing.clone(),
                                     ip_options: ip_options.clone(),
-                                    send_options: core_ctx
-                                        .to_other_send_options(ip_options)
-                                        .clone(),
                                     socket_id: core_ctx.to_other_bound_socket_id(socket_id),
                                     original_shutdown: Some(shutdown.clone()),
                                     extra,
@@ -3527,13 +3523,20 @@
             }
         };
 
-        struct SendParams<'a, I: IpExt, S: DatagramSocketSpec, D: device::WeakId> {
-            socket: &'a IpSock<I, D, SocketHopLimits<I>>,
+        struct SendParams<
+            'a,
+            I: IpExt,
+            S: DatagramSocketSpec,
+            D: device::WeakId,
+            O: SendOptions<I, D>,
+        > {
+            socket: &'a IpSock<I, D>,
             ip: &'a ConnIpAddr<
                 I::Addr,
                 <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
                 <S::AddrSpec as SocketMapAddrSpec>::RemoteIdentifier,
             >,
+            options: &'a O,
         }
 
         enum Operation<
@@ -3544,9 +3547,11 @@
             BC: DatagramStateBindingsContext<I, S>,
             DualStackSC: DualStackDatagramBoundStateContext<I, BC, S>,
             CC: DatagramBoundStateContext<I, BC, S>,
+            O: SendOptions<I, D>,
+            OtherO: SendOptions<I::OtherVersion, D>,
         > {
-            SendToThisStack((SendParams<'a, I, S, D>, &'a mut CC)),
-            SendToOtherStack((SendParams<'a, I::OtherVersion, S, D>, &'a mut DualStackSC)),
+            SendToThisStack((SendParams<'a, I, S, D, O>, &'a mut CC)),
+            SendToOtherStack((SendParams<'a, I::OtherVersion, S, D, OtherO>, &'a mut DualStackSC)),
             // Allow `Operation` to be generic over `B` and `C` so that they can
             // be used in trait bounds for `DualStackSC` and `SC`.
             _Phantom((Never, PhantomData<BC>)),
@@ -3556,33 +3561,53 @@
             MaybeDualStack::DualStack(dual_stack) => match dual_stack.converter().convert(state) {
                 DualStackConnState::ThisStack(ConnState {
                     socket,
-                    ip_options: _,
+                    ip_options,
                     clear_device_on_disconnect: _,
                     shutdown,
                     addr: ConnAddr { ip, device: _ },
                     extra: _,
-                }) => (shutdown, Operation::SendToThisStack((SendParams { socket, ip }, core_ctx))),
+                }) => (
+                    shutdown,
+                    Operation::SendToThisStack((
+                        SendParams { socket, ip, options: ip_options },
+                        core_ctx,
+                    )),
+                ),
                 DualStackConnState::OtherStack(ConnState {
                     socket,
-                    ip_options: _,
+                    ip_options,
                     clear_device_on_disconnect: _,
                     shutdown,
                     addr: ConnAddr { ip, device: _ },
                     extra: _,
-                }) => {
-                    (shutdown, Operation::SendToOtherStack((SendParams { socket, ip }, dual_stack)))
-                }
+                }) => (
+                    shutdown,
+                    Operation::SendToOtherStack((
+                        SendParams {
+                            socket,
+                            ip,
+                            options: dual_stack.to_other_send_options(ip_options),
+                        },
+                        dual_stack,
+                    )),
+                ),
             },
             MaybeDualStack::NotDualStack(not_dual_stack) => {
                 let ConnState {
                     socket,
-                    ip_options: _,
+                    ip_options,
                     clear_device_on_disconnect: _,
                     shutdown,
                     addr: ConnAddr { ip, device: _ },
                     extra: _,
                 } = not_dual_stack.converter().convert(state);
-                (shutdown, Operation::SendToThisStack((SendParams { socket, ip }, core_ctx)))
+                (
+                    shutdown,
+                    Operation::SendToThisStack((
+                        SendParams { socket, ip, options: ip_options },
+                        core_ctx,
+                    )),
+                )
             }
         };
 
@@ -3592,21 +3617,21 @@
         }
 
         match operation {
-            Operation::SendToThisStack((SendParams { socket, ip }, core_ctx)) => {
+            Operation::SendToThisStack((SendParams { socket, ip, options }, core_ctx)) => {
                 let packet =
                     S::make_packet::<I, _>(body, &ip).map_err(SendError::SerializeError)?;
                 core_ctx.with_transport_context(|core_ctx| {
                     core_ctx
-                        .send_ip_packet(bindings_ctx, &socket, packet, None)
+                        .send_ip_packet(bindings_ctx, &socket, packet, None, options)
                         .map_err(|(_serializer, send_error)| SendError::IpSock(send_error))
                 })
             }
-            Operation::SendToOtherStack((SendParams { socket, ip }, dual_stack)) => {
+            Operation::SendToOtherStack((SendParams { socket, ip, options }, dual_stack)) => {
                 let packet = S::make_packet::<I::OtherVersion, _>(body, &ip)
                     .map_err(SendError::SerializeError)?;
                 dual_stack.with_transport_context::<_, _>(|core_ctx| {
                     core_ctx
-                        .send_ip_packet(bindings_ctx, &socket, packet, None)
+                        .send_ip_packet(bindings_ctx, &socket, packet, None, options)
                         .map_err(|(_serializer, send_error)| SendError::IpSock(send_error))
                 })
             }
@@ -3669,8 +3694,8 @@
             BC: DatagramStateBindingsContext<I, S>,
             DualStackSC: DualStackDatagramBoundStateContext<I, BC, S>,
             CC: DatagramBoundStateContext<I, BC, S>,
-            O: SendOptions<I>,
-            OtherO: SendOptions<I::OtherVersion>,
+            O: SendOptions<I, D>,
+            OtherO: SendOptions<I::OtherVersion, D>,
         > {
             SendToThisStack((SendOneshotParameters<'a, I, S, D, O>, &'a mut CC)),
 
@@ -3705,7 +3730,7 @@
                                     remote_ip,
                                     remote_id: remote_identifier,
                                     device,
-                                    send_options: &ip_options.hop_limits,
+                                    send_options: ip_options,
                                 },
                                 core_ctx,
                             )),
@@ -3733,7 +3758,7 @@
                                     remote_ip,
                                     remote_id: remote_identifier,
                                     device,
-                                    send_options: &ip_options.hop_limits,
+                                    send_options: ip_options,
                                 },
                                 core_ctx,
                             )),
@@ -3764,7 +3789,7 @@
                                 remote_ip,
                                 remote_id: remote_identifier,
                                 device,
-                                send_options: &ip_options.hop_limits,
+                                send_options: ip_options,
                             },
                             core_ctx,
                         )),
@@ -3781,7 +3806,7 @@
                                 remote_ip,
                                 remote_id: remote_identifier,
                                 device,
-                                send_options: &ip_options.hop_limits,
+                                send_options: ip_options,
                             },
                             core_ctx,
                         )),
@@ -3852,7 +3877,7 @@
                                     remote_ip,
                                     remote_id: remote_identifier,
                                     device,
-                                    send_options: &ip_options.hop_limits,
+                                    send_options: ip_options,
                                 },
                                 core_ctx,
                             )),
@@ -3922,7 +3947,7 @@
     I: IpExt,
     S: DatagramSocketSpec,
     D: device::WeakId,
-    O: SendOptions<I>,
+    O: SendOptions<I, D>,
 > {
     local_ip: Option<SocketIpAddr<I::Addr>>,
     local_id: <S::AddrSpec as SocketMapAddrSpec>::LocalIdentifier,
@@ -3938,7 +3963,7 @@
     CC: IpSocketHandler<I, BC>,
     BC,
     B: BufferMut,
-    O: SendOptions<I>,
+    O: SendOptions<I, CC::WeakDeviceId>,
 >(
     core_ctx: &mut CC,
     bindings_ctx: &mut BC,
@@ -3977,9 +4002,7 @@
             None,
         )
         .map_err(|err| match err {
-            SendOneShotIpPacketError::CreateAndSendError { err, options: _ } => {
-                SendToError::CreateAndSend(err)
-            }
+            SendOneShotIpPacketError::CreateAndSendError { err } => SendToError::CreateAndSend(err),
             SendOneShotIpPacketError::SerializeError(err) => SendToError::SerializeError(err),
         })
 }
@@ -4060,7 +4083,7 @@
 
     match params {
         SetBoundDeviceParameters::Listener { ip, device } => {
-            let new_device = new_device.map(|d| core_ctx.downgrade_device_id(d));
+            let new_device = new_device.map(|d| d.downgrade());
             let old_addr = ListenerAddr { ip: ip.clone(), device: device.clone() };
             let new_addr = ListenerAddr { ip: ip.clone(), device: new_device.clone() };
             let entry = sockets
@@ -4082,18 +4105,15 @@
         }) => {
             let ConnAddr { ip, device } = addr;
             let ConnIpAddr { local: (local_ip, _local_id), remote: (remote_ip, _remote_id) } = ip;
-            let mut new_socket = core_ctx
+            let new_socket = core_ctx
                 .new_ip_socket(
                     bindings_ctx,
                     new_device.map(EitherDeviceId::Strong),
                     Some(local_ip.clone()),
                     remote_ip.clone(),
                     socket.proto(),
-                    // NB: Use default options; They'll be replaced later if
-                    // the insertion is successful.
-                    Default::default(),
                 )
-                .map_err(|_: (IpSockCreationError, _)| {
+                .map_err(|_: IpSockCreationError| {
                     SocketError::Remote(RemoteAddressError::NoRoute)
                 })?;
             let new_device = new_socket.device().cloned();
@@ -4106,9 +4126,6 @@
             let entry = entry
                 .try_update_addr(new_addr)
                 .map_err(|(ExistsError {}, _entry)| LocalAddressError::AddressInUse)?;
-            // Since the move was successful, replace the old socket with
-            // the new one but move the options over.
-            let _: SocketHopLimits<WireI> = new_socket.replace_options(socket.take_options());
             *socket = new_socket;
             // If this operation explicitly sets the device for the socket, it
             // should no longer be cleared on disconnect.
@@ -4213,7 +4230,7 @@
         match state {
             SocketState::Unbound(state) => {
                 let UnboundSocketState { ref mut device, sharing: _, ip_options: _ } = state;
-                *device = new_device.map(|d| core_ctx.downgrade_device_id(d));
+                *device = new_device.map(|d| d.downgrade());
                 Ok(())
             }
             SocketState::Bound(BoundSocketState { socket_type, original_bound_addr: _ }) => {
@@ -4338,13 +4355,13 @@
                             this: S::make_bound_socket_map_id(id),
                             other: core_ctx.to_other_bound_socket_id(id),
                         };
-                        core_ctx.with_both_bound_sockets_mut(|core_ctx, bound, other_bound| {
+                        core_ctx.with_both_bound_sockets_mut(|_core_ctx, bound, other_bound| {
                             set_bound_device_listener_both_stacks(
                                 device,
                                 identifier,
                                 PairedSocketMapMut { bound, other_bound },
                                 socket_id,
-                                new_device.map(|d| core_ctx.downgrade_device_id(d)),
+                                new_device.map(|d| d.downgrade()),
                             )
                         })
                     }
@@ -4516,13 +4533,13 @@
 
         let ip_options = get_options_mut(core_ctx, state);
 
-        let Some(strong_interface) = interface.as_strong(core_ctx) else {
+        let Some(strong_interface) = interface.as_strong() else {
             return Err(SetMulticastMembershipError::DeviceDoesNotExist);
         };
 
         let change = ip_options
             .multicast_memberships
-            .apply_membership_change(multicast_group, &interface.as_weak(core_ctx), want_membership)
+            .apply_membership_change(multicast_group, &interface.as_weak(), want_membership)
             .ok_or(if want_membership {
                 SetMulticastMembershipError::GroupAlreadyJoined
             } else {
@@ -4557,7 +4574,7 @@
 fn get_options_device_from_conn_state<
     WireI: IpExt,
     SocketI: IpExt,
-    D: Eq + Hash,
+    D: device::WeakId,
     S: DatagramSocketSpec,
 >(
     ConnState {
@@ -4671,8 +4688,6 @@
     id: &S::SocketId<I, CC::WeakDeviceId>,
     update: impl FnOnce(&mut SocketHopLimits<I>),
 ) {
-    // TODO(https://fxbug.dev/324279602): The options held by a connected
-    // socket's `IpSock` will now be out of sync with the options updated here.
     core_ctx.with_socket_state_mut(id, |core_ctx, state| {
         let options = get_options_mut(core_ctx, state);
 
@@ -4692,7 +4707,7 @@
 ) -> HopLimits {
     core_ctx.with_socket_state(id, |core_ctx, state| {
         let (options, device) = get_options_device(core_ctx, state);
-        let device = device.as_ref().and_then(|d| core_ctx.upgrade_weak_device_id(d));
+        let device = device.as_ref().and_then(|d| d.upgrade());
         DatagramBoundStateContext::<I, _, _>::with_transport_context(core_ctx, |core_ctx| {
             options.hop_limits.get_limits_with_defaults(
                 &TransportIpContext::<I, _>::get_default_hop_limits(core_ctx, device.as_ref()),
@@ -4701,7 +4716,7 @@
     })
 }
 
-/// Calls the callback with mutable access to [`S::OtherStackIpOptions<I>`].
+/// Calls the callback with mutable access to [`S::OtherStackIpOptions<I, D>`].
 ///
 /// If the socket is bound, the callback is not called, and instead an
 /// `ExpectedUnboundError` is returned.
@@ -4715,7 +4730,7 @@
     core_ctx: &mut CC,
     _bindings_ctx: &mut BC,
     id: &S::SocketId<I, CC::WeakDeviceId>,
-    cb: impl FnOnce(&mut S::OtherStackIpOptions<I>) -> R,
+    cb: impl FnOnce(&mut S::OtherStackIpOptions<I, CC::WeakDeviceId>) -> R,
 ) -> Result<R, ExpectedUnboundError> {
     core_ctx.with_socket_state_mut(id, |core_ctx, state| {
         let is_unbound = match state {
@@ -4731,7 +4746,7 @@
     })
 }
 
-/// Calls the callback with mutable access to [`S::OtherStackIpOptions<I>`].
+/// Calls the callback with mutable access to [`S::OtherStackIpOptions<I, D>`].
 pub(crate) fn with_other_stack_ip_options_mut<
     I: IpExt,
     CC: DatagramStateContext<I, BC, S>,
@@ -4742,7 +4757,7 @@
     core_ctx: &mut CC,
     _bindings_ctx: &mut BC,
     id: &S::SocketId<I, CC::WeakDeviceId>,
-    cb: impl FnOnce(&mut S::OtherStackIpOptions<I>) -> R,
+    cb: impl FnOnce(&mut S::OtherStackIpOptions<I, CC::WeakDeviceId>) -> R,
 ) -> R {
     core_ctx.with_socket_state_mut(id, |core_ctx, state| {
         let options = get_options_mut(core_ctx, state);
@@ -4750,7 +4765,7 @@
     })
 }
 
-/// Calls the callback with access to [`S::OtherStackIpOptions<I>`].
+/// Calls the callback with access to [`S::OtherStackIpOptions<I, D>`].
 pub(crate) fn with_other_stack_ip_options<
     I: IpExt,
     CC: DatagramStateContext<I, BC, S>,
@@ -4761,7 +4776,7 @@
     core_ctx: &mut CC,
     _bindings_ctx: &BC,
     id: &S::SocketId<I, CC::WeakDeviceId>,
-    cb: impl FnOnce(&S::OtherStackIpOptions<I>) -> R,
+    cb: impl FnOnce(&S::OtherStackIpOptions<I, CC::WeakDeviceId>) -> R,
 ) -> R {
     core_ctx.with_socket_state(id, |core_ctx, state| {
         let (options, _device) = get_options_device(core_ctx, state);
@@ -4770,7 +4785,7 @@
     })
 }
 
-/// Calls the callback with access to [`S::OtherStackIpOptions<I>`], and the
+/// Calls the callback with access to [`S::OtherStackIpOptions<I, D>`], and the
 /// default [`HopLimits`] for `I::OtherVersion`.
 ///
 /// If dualstack operations are not supported, the callback is not called, and
@@ -4785,11 +4800,11 @@
     core_ctx: &mut CC,
     _bindings_ctx: &BC,
     id: &S::SocketId<I, CC::WeakDeviceId>,
-    cb: impl FnOnce(&S::OtherStackIpOptions<I>, HopLimits) -> R,
+    cb: impl FnOnce(&S::OtherStackIpOptions<I, CC::WeakDeviceId>, HopLimits) -> R,
 ) -> Result<R, NotDualStackCapableError> {
     core_ctx.with_socket_state(id, |core_ctx, state| {
         let (options, device) = get_options_device(core_ctx, state);
-        let device = device.as_ref().and_then(|d| core_ctx.upgrade_weak_device_id(d));
+        let device = device.as_ref().and_then(|d| d.upgrade());
         match DatagramBoundStateContext::<I, _, _>::dual_stack_context(core_ctx) {
             MaybeDualStack::NotDualStack(_) => Err(NotDualStackCapableError),
             MaybeDualStack::DualStack(ds) => {
@@ -4956,7 +4971,7 @@
 
 #[cfg(test)]
 mod test {
-    use core::{convert::Infallible as Never, ops::DerefMut as _};
+    use core::convert::Infallible as Never;
 
     use alloc::vec;
     use assert_matches::assert_matches;
@@ -4975,13 +4990,14 @@
     use crate::{
         context::testutil::{FakeBindingsCtx, FakeCtxWithCoreCtx, Wrapped, WrappedFakeCoreCtx},
         data_structures::socketmap::SocketMap,
-        device::testutil::{FakeDeviceId, FakeStrongDeviceId, FakeWeakDeviceId, MultipleDevicesId},
+        device::testutil::{
+            FakeDeviceId, FakeReferencyDeviceId, FakeStrongDeviceId, FakeWeakDeviceId,
+            MultipleDevicesId,
+        },
         ip::{
-            device::state::{IpDeviceState, IpDeviceStateIpExt},
-            socket::testutil::{
-                FakeDeviceConfig, FakeDualStackIpSocketCtx, FakeFilterDeviceId, FakeIpSocketCtx,
-            },
-            testutil::{DualStackSendIpPacketMeta, FakeIpDeviceIdCtx},
+            device::state::IpDeviceStateIpExt,
+            socket::testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx, FakeIpSocketCtx},
+            testutil::DualStackSendIpPacketMeta,
             IpLayerIpExt, DEFAULT_HOP_LIMITS,
         },
         socket::{
@@ -5087,19 +5103,39 @@
     const FAKE_DATAGRAM_IPV4_PROTOCOL: Ipv4Proto = Ipv4Proto::Other(253);
     const FAKE_DATAGRAM_IPV6_PROTOCOL: Ipv6Proto = Ipv6Proto::Other(254);
 
+    #[derive(Clone, Default, Debug)]
+    struct OtherStackSocketState<I: IpExt> {
+        hop_limits: SocketHopLimits<I>,
+    }
+
+    impl<I: IpExt, D> SendOptions<I, D> for OtherStackSocketState<I> {
+        fn hop_limit(&self, destination: &SpecifiedAddr<I::Addr>) -> Option<NonZeroU8> {
+            let Self { hop_limits, .. } = self;
+            if destination.is_multicast() {
+                hop_limits.multicast
+            } else {
+                hop_limits.unicast
+            }
+        }
+
+        fn multicast_interface(&self) -> Option<&D> {
+            None
+        }
+    }
+
     impl DatagramSocketSpec for FakeStateSpec {
         const NAME: &'static str = "FAKE";
         type AddrSpec = FakeAddrSpec;
         type SocketId<I: IpExt, D: device::WeakId> = Id<I, D>;
-        type OtherStackIpOptions<I: IpExt> = SocketHopLimits<I::OtherVersion>;
+        type OtherStackIpOptions<I: IpExt, D: device::WeakId> =
+            OtherStackSocketState<I::OtherVersion>;
         type SocketMapSpec<I: IpExt, D: device::WeakId> = (Self, I, D);
         type SharingState = Sharing;
         type ListenerIpAddr<I: IpExt> =
             I::DualStackListenerIpAddr<<FakeAddrSpec as SocketMapAddrSpec>::LocalIdentifier>;
         type ConnIpAddr<I: IpExt> = I::DualStackConnIpAddr<Self>;
         type ConnStateExtra = ();
-        type ConnState<I: IpExt, D: Debug + Eq + Hash + Send + Sync> =
-            I::DualStackConnState<D, Self>;
+        type ConnState<I: IpExt, D: device::WeakId> = I::DualStackConnState<D, Self>;
         type ExternalData<I: Ip> = ();
 
         fn ip_proto<I: IpProtoExt>() -> I::Proto {
@@ -5134,7 +5170,7 @@
             (1..=u16::MAX).map(|i| NonZeroU16::new(i).unwrap()).find(|i| is_available(*i).is_ok())
         }
 
-        fn conn_info_from_state<I: IpExt, D: Clone + Debug + Eq + Hash + Send + Sync>(
+        fn conn_info_from_state<I: IpExt, D: device::WeakId>(
             state: &Self::ConnState<I, D>,
         ) -> ConnInfo<I::Addr, D> {
             let ConnAddr { ip, device } = I::conn_addr_from_state(state);
@@ -5362,7 +5398,7 @@
     type FakeSocketsState<I, D> = DatagramSocketSet<I, FakeWeakDeviceId<D>, FakeStateSpec>;
 
     type FakeInnerCoreCtx<D> = crate::context::testutil::FakeCoreCtx<
-        FakeDualStackIpSocketCtx<D, FakeBindingsCtx<(), (), (), ()>>,
+        FakeDualStackIpSocketCtx<D>,
         DualStackSendIpPacketMeta<D>,
         D,
     >;
@@ -5382,7 +5418,7 @@
         }
     }
 
-    impl<D: FakeFilterDeviceId<()>, I: DatagramIpExt<D> + IpLayerIpExt>
+    impl<D: FakeStrongDeviceId, I: DatagramIpExt<D> + IpLayerIpExt>
         DatagramStateContext<I, FakeBindingsCtx<(), (), (), ()>, FakeStateSpec>
         for FakeCoreCtx<I, D>
     {
@@ -5481,7 +5517,7 @@
         ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext>;
     }
 
-    impl<D: FakeFilterDeviceId<()>> DualStackContextsIpExt<D> for Ipv4 {
+    impl<D: FakeStrongDeviceId> DualStackContextsIpExt<D> for Ipv4 {
         type DualStackContext =
             UninstantiableWrapper<Wrapped<FakeBoundSockets<D>, FakeInnerCoreCtx<D>>>;
         type NonDualStackContext = Wrapped<FakeBoundSockets<D>, FakeInnerCoreCtx<D>>;
@@ -5492,7 +5528,7 @@
         }
     }
 
-    impl<D: FakeFilterDeviceId<()>> DualStackContextsIpExt<D> for Ipv6 {
+    impl<D: FakeStrongDeviceId> DualStackContextsIpExt<D> for Ipv6 {
         type DualStackContext = Wrapped<FakeBoundSockets<D>, FakeInnerCoreCtx<D>>;
         type NonDualStackContext =
             UninstantiableWrapper<Wrapped<FakeBoundSockets<D>, FakeInnerCoreCtx<D>>>;
@@ -5503,10 +5539,8 @@
         }
     }
 
-    impl<
-            D: FakeFilterDeviceId<()>,
-            I: Ip + IpExt + IpDeviceStateIpExt + DualStackContextsIpExt<D>,
-        > DatagramBoundStateContext<I, FakeBindingsCtx<(), (), (), ()>, FakeStateSpec>
+    impl<D: FakeStrongDeviceId, I: Ip + IpExt + IpDeviceStateIpExt + DualStackContextsIpExt<D>>
+        DatagramBoundStateContext<I, FakeBindingsCtx<(), (), (), ()>, FakeStateSpec>
         for Wrapped<FakeBoundSockets<D>, FakeInnerCoreCtx<D>>
     {
         type IpSocketsCtx<'a> = FakeInnerCoreCtx<D>;
@@ -5575,7 +5609,7 @@
         }
     }
 
-    impl<D: FakeFilterDeviceId<()>>
+    impl<D: FakeStrongDeviceId>
         DualStackDatagramBoundStateContext<Ipv6, FakeBindingsCtx<(), (), (), ()>, FakeStateSpec>
         for Wrapped<FakeBoundSockets<D>, FakeInnerCoreCtx<D>>
     {
@@ -5590,12 +5624,13 @@
             true
         }
 
+        type OtherSendOptions = OtherStackSocketState<Ipv4>;
+
         fn to_other_send_options<'a>(
             &self,
             state: &'a IpOptions<Ipv6, Self::WeakDeviceId, FakeStateSpec>,
-        ) -> &'a SocketHopLimits<Ipv4> {
-            let IpOptions { multicast_memberships: _, hop_limits: _, other_stack, transparent: _ } =
-                state;
+        ) -> &'a Self::OtherSendOptions {
+            let IpOptions { other_stack, .. } = state;
             other_stack
         }
 
@@ -5697,12 +5732,13 @@
     }
 
     #[ip_test]
-    fn set_get_device_hop_limits<I: Ip + DatagramIpExt<FakeDeviceId> + IpLayerIpExt>() {
+    fn set_get_device_hop_limits<I: Ip + DatagramIpExt<FakeReferencyDeviceId> + IpLayerIpExt>() {
+        let device = FakeReferencyDeviceId::default();
         let mut core_ctx = FakeCoreCtx::<I, _> {
             outer: FakeSocketsState::default(),
             inner: WrappedFakeCoreCtx::with_inner_and_outer_state(
                 FakeDualStackIpSocketCtx::new([FakeDeviceConfig::<_, SpecifiedAddr<I::Addr>> {
-                    device: FakeDeviceId,
+                    device: device.clone(),
                     local_ips: Default::default(),
                     remote_ips: Default::default(),
                 }]),
@@ -5712,18 +5748,15 @@
         let mut bindings_ctx = FakeBindingsCtx::default();
 
         let unbound = create(&mut core_ctx, ());
-        set_device(&mut core_ctx, &mut bindings_ctx, &unbound, Some(&FakeDeviceId)).unwrap();
+        set_device(&mut core_ctx, &mut bindings_ctx, &unbound, Some(&device)).unwrap();
 
         let HopLimits { mut unicast, multicast } = DEFAULT_HOP_LIMITS;
         unicast = unicast.checked_add(1).unwrap();
         {
-            let ip_socket_ctx = core_ctx.inner.inner.get_ref();
-            let device_state: &IpDeviceState<_, I> =
-                ip_socket_ctx.get_device_state(&FakeDeviceId).as_ref();
-            let mut default_hop_limit = device_state.default_hop_limit.write();
-            let default_hop_limit = default_hop_limit.deref_mut();
-            assert_ne!(*default_hop_limit, unicast);
-            *default_hop_limit = unicast;
+            let ip_socket_ctx = core_ctx.inner.inner.get_mut();
+            let device_state = ip_socket_ctx.get_device_state_mut::<I>(&device);
+            assert_ne!(device_state.default_hop_limit, unicast);
+            device_state.default_hop_limit = unicast;
         }
         assert_eq!(
             get_ip_hop_limits(&mut core_ctx, &bindings_ctx, &unbound),
@@ -5731,8 +5764,7 @@
         );
 
         // If the device is removed, use default hop limits.
-        AsMut::<FakeIpDeviceIdCtx<_>>::as_mut(&mut core_ctx.inner.inner.get_mut())
-            .set_device_removed(FakeDeviceId, true);
+        device.mark_removed();
         assert_eq!(get_ip_hop_limits(&mut core_ctx, &bindings_ctx, &unbound), DEFAULT_HOP_LIMITS);
     }
 
@@ -5856,11 +5888,13 @@
     #[ip_test]
     #[test_case(true; "remove device b")]
     #[test_case(false; "dont remove device b")]
-    fn multicast_membership_changes<I: Ip + DatagramIpExt<MultipleDevicesId> + TestIpExt>(
+    fn multicast_membership_changes<I: Ip + DatagramIpExt<FakeReferencyDeviceId> + TestIpExt>(
         remove_device_b: bool,
     ) {
-        let mut core_ctx = FakeIpSocketCtx::<I, MultipleDevicesId>::new(
-            MultipleDevicesId::all().into_iter().map(|device| FakeDeviceConfig {
+        let device_a = FakeReferencyDeviceId::default();
+        let device_b = FakeReferencyDeviceId::default();
+        let mut core_ctx = FakeIpSocketCtx::<I, FakeReferencyDeviceId>::new(
+            [device_a.clone(), device_b.clone()].into_iter().map(|device| FakeDeviceConfig {
                 device,
                 local_ips: Default::default(),
                 remote_ips: Default::default(),
@@ -5873,32 +5907,32 @@
         assert_eq!(
             memberships.apply_membership_change(
                 multicast_addr1,
-                &FakeWeakDeviceId(MultipleDevicesId::A),
+                &FakeWeakDeviceId(device_a.clone()),
                 true /* want_membership */
             ),
             Some(MulticastMembershipChange::Join),
         );
-        core_ctx.join_multicast_group(&mut bindings_ctx, &MultipleDevicesId::A, multicast_addr1);
+        core_ctx.join_multicast_group(&mut bindings_ctx, &device_a, multicast_addr1);
 
         let multicast_addr2 = I::get_multicast_addr(2);
         assert_eq!(
             memberships.apply_membership_change(
                 multicast_addr2,
-                &FakeWeakDeviceId(MultipleDevicesId::B),
+                &FakeWeakDeviceId(device_b.clone()),
                 true /* want_membership */
             ),
             Some(MulticastMembershipChange::Join),
         );
-        core_ctx.join_multicast_group(&mut bindings_ctx, &MultipleDevicesId::B, multicast_addr2);
+        core_ctx.join_multicast_group(&mut bindings_ctx, &device_b, multicast_addr2);
 
         for (device, addr, expected) in [
-            (MultipleDevicesId::A, multicast_addr1, true),
-            (MultipleDevicesId::A, multicast_addr2, false),
-            (MultipleDevicesId::B, multicast_addr1, false),
-            (MultipleDevicesId::B, multicast_addr2, true),
+            (&device_a, multicast_addr1, true),
+            (&device_a, multicast_addr2, false),
+            (&device_b, multicast_addr1, false),
+            (&device_b, multicast_addr2, true),
         ] {
             assert_eq!(
-                core_ctx.get_device_state(&device).multicast_groups.read().contains(&addr),
+                core_ctx.get_device_state(device).is_in_multicast_group(&addr),
                 expected,
                 "device={:?}, addr={}",
                 device,
@@ -5907,23 +5941,22 @@
         }
 
         if remove_device_b {
-            AsMut::<FakeIpDeviceIdCtx<_>>::as_mut(&mut core_ctx)
-                .set_device_removed(MultipleDevicesId::B, true);
+            device_b.mark_removed();
         }
 
         leave_all_joined_groups(&mut core_ctx, &mut bindings_ctx, memberships);
         for (device, addr, expected) in [
-            (MultipleDevicesId::A, multicast_addr1, false),
-            (MultipleDevicesId::A, multicast_addr2, false),
-            (MultipleDevicesId::B, multicast_addr1, false),
+            (&device_a, multicast_addr1, false),
+            (&device_a, multicast_addr2, false),
+            (&device_b, multicast_addr1, false),
             // Should not attempt to leave the multicast group on the device if
             // the device looks like it was removed. Note that although we mark
             // the device as removed, we do not destroy its state so we can
             // inspect it here.
-            (MultipleDevicesId::B, multicast_addr2, remove_device_b),
+            (&device_b, multicast_addr2, remove_device_b),
         ] {
             assert_eq!(
-                core_ctx.get_device_state(&device).multicast_groups.read().contains(&addr),
+                core_ctx.get_device_state(device).is_in_multicast_group(&addr),
                 expected,
                 "device={:?}, addr={}",
                 device,
diff --git a/src/connectivity/network/netstack3/core/src/state.rs b/src/connectivity/network/netstack3/core/src/state.rs
index 3daa579..cd5f527 100644
--- a/src/connectivity/network/netstack3/core/src/state.rs
+++ b/src/connectivity/network/netstack3/core/src/state.rs
@@ -13,6 +13,7 @@
         arp::ArpCounters, DeviceCounters, DeviceId, DeviceLayerState, EthernetDeviceCounters,
         PureIpDeviceCounters, WeakDeviceId,
     },
+    filter::FilterBindingsTypes,
     ip::{
         self,
         device::nud::NudCounters,
@@ -94,11 +95,11 @@
 
     pub(crate) fn filter<I: packet_formats::ip::IpExt>(
         &self,
-    ) -> &RwLock<crate::filter::State<I, BT::DeviceClass>> {
+    ) -> &RwLock<crate::filter::State<I, BT>> {
         #[derive(GenericOverIp)]
         #[generic_over_ip(I, Ip)]
-        struct Wrap<'a, I: packet_formats::ip::IpExt, DeviceClass>(
-            &'a RwLock<crate::filter::State<I, DeviceClass>>,
+        struct Wrap<'a, I: packet_formats::ip::IpExt, BT: FilterBindingsTypes>(
+            &'a RwLock<crate::filter::State<I, BT>>,
         );
         let Wrap(state) = I::map_ip(
             IpInvariant(self),
diff --git a/src/connectivity/network/netstack3/core/src/testutil.rs b/src/connectivity/network/netstack3/core/src/testutil.rs
index 6015a3a..524cad0 100644
--- a/src/connectivity/network/netstack3/core/src/testutil.rs
+++ b/src/connectivity/network/netstack3/core/src/testutil.rs
@@ -1917,7 +1917,7 @@
                 None, // local_ip
                 SocketIpAddr::try_from(FAKE_CONFIG_V4.remote_ip).unwrap(),
                 Ipv4Proto::Icmp,
-                DefaultSendOptions,
+                &DefaultSendOptions,
                 |_| {
                     let req = IcmpEchoRequest::new(0, 0);
                     let req_body = &[1, 2, 3, 4];
diff --git a/src/connectivity/network/netstack3/core/src/transport/tcp/socket.rs b/src/connectivity/network/netstack3/core/src/transport/tcp/socket.rs
index 4f97fe5..f18323c 100644
--- a/src/connectivity/network/netstack3/core/src/transport/tcp/socket.rs
+++ b/src/connectivity/network/netstack3/core/src/transport/tcp/socket.rs
@@ -52,14 +52,13 @@
     },
     convert::{BidirectionalConverter as _, OwnedOrRefsBidirectionalConverter},
     data_structures::socketmap::{IterShadows as _, SocketMap},
-    device::{self, AnyDevice, DeviceIdContext, WeakId},
+    device::{self, AnyDevice, DeviceIdContext, StrongId as _, WeakId},
     error::{ExistsError, LocalAddressError, ZonedAddressError},
     inspect::{Inspector, InspectorDeviceExt},
     ip::{
         icmp::IcmpErrorCode,
         socket::{
-            DefaultSendOptions, DeviceIpSocketHandler, IpSock, IpSockCreationError,
-            IpSocketHandler, SendOptions,
+            DefaultSendOptions, DeviceIpSocketHandler, IpSock, IpSockCreationError, IpSocketHandler,
         },
         EitherDeviceId, IpExt, IpSockCreateAndSendError, TransportIpContext,
     },
@@ -1609,7 +1608,7 @@
         BT::SendBuffer,
         BT::ListenerNotifierOrProvidedBuffers,
     >,
-    ip_sock: IpSock<WireI, D, DefaultSendOptions>,
+    ip_sock: IpSock<WireI, D>,
     /// The user has indicated that this connection will never be used again, we
     /// keep the connection in the socketmap to perform the shutdown but it will
     /// be auto removed once the state reaches Closed.
@@ -1749,7 +1748,7 @@
 impl<I: DualStackIpExt, D: device::WeakId, BT: TcpBindingsTypes> Debug for TcpSocketId<I, D, BT> {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let Self(rc) = self;
-        f.debug_tuple("TcpSocketId").field(&StrongRc::ptr_debug(rc)).finish()
+        f.debug_tuple("TcpSocketId").field(&StrongRc::debug_id(rc)).finish()
     }
 }
 
@@ -1773,7 +1772,7 @@
 {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let Self(rc) = self;
-        f.debug_tuple("WeakTcpSocketId").field(&rc.ptr_debug()).finish()
+        f.debug_tuple("WeakTcpSocketId").field(&rc.debug_id()).finish()
     }
 }
 
@@ -1886,7 +1885,7 @@
         None => (None, bound_device.clone().map(EitherDeviceId::Weak)),
     };
 
-    let weak_device = device.map(|d| d.as_weak(core_ctx).into_owned());
+    let weak_device = device.map(|d| d.as_weak().into_owned());
     let port = match port {
         None => {
             match algorithm::simple_randomized_port_alloc(
@@ -3217,7 +3216,7 @@
         bindings_ctx: &mut C::BindingsContext,
         addr: &mut ConnAddr<ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>, CC::WeakDeviceId>,
         demux_id: &WireI::DemuxSocketId<CC::WeakDeviceId, C::BindingsContext>,
-        ip_sock: &mut IpSock<WireI, CC::WeakDeviceId, DefaultSendOptions>,
+        ip_sock: &mut IpSock<WireI, CC::WeakDeviceId>,
         new_device: Option<CC::DeviceId>,
     ) -> Result<(), SetDeviceError>
     where
@@ -3245,9 +3244,8 @@
                 Some(*local_ip),
                 *remote_ip,
                 IpProto::Tcp.into(),
-                Default::default(),
             )
-            .map_err(|_: (IpSockCreationError, DefaultSendOptions)| SetDeviceError::Unroutable)?;
+            .map_err(|_: IpSockCreationError| SetDeviceError::Unroutable)?;
         core_ctx.with_demux_mut(|DemuxState { socketmap }| {
             let entry = socketmap
                 .conns_mut()
@@ -3313,7 +3311,7 @@
         new_device: Option<<C::CoreContext as DeviceIdContext<AnyDevice>>::DeviceId>,
     ) -> Result<(), SetDeviceError> {
         let (core_ctx, bindings_ctx) = self.contexts();
-        let weak_device = new_device.as_ref().map(|d| core_ctx.downgrade_device_id(d));
+        let weak_device = new_device.as_ref().map(|d| d.downgrade());
         core_ctx.with_socket_mut_transport_demux(id, move |core_ctx, socket_state| {
             debug!("set device on {id:?} to {new_device:?}");
             let TcpSocketState { socket_state, ip_options: _ } = socket_state;
@@ -3443,9 +3441,7 @@
                                 } => {
                                     let other_demux_id =
                                         core_ctx.into_other_demux_socket_id(id.clone());
-                                    let old_device = device
-                                        .as_ref()
-                                        .and_then(|d| core_ctx.upgrade_weak_device_id(d));
+                                    let old_device = device.as_ref().and_then(|d| d.upgrade());
                                     let old_weak_device = device.clone();
                                     core_ctx.with_both_demux_mut(|demux, other_demux| {
                                         Self::set_device_listener(
@@ -4393,7 +4389,7 @@
         BC::SendBuffer,
         BC::ListenerNotifierOrProvidedBuffers,
     >,
-    ip_sock: &IpSock<WireI, DC::WeakDeviceId, DefaultSendOptions>,
+    ip_sock: &IpSock<WireI, DC::WeakDeviceId>,
     conn_addr: &ConnAddr<ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>, DC::WeakDeviceId>,
 ) where
     WireI: DualStackIpExt,
@@ -4736,9 +4732,8 @@
             local_ip,
             remote_ip,
             IpProto::Tcp.into(),
-            DefaultSendOptions,
         )
-        .map_err(|(err, DefaultSendOptions {})| match err {
+        .map_err(|err| match err {
             IpSockCreationError::Route(_) => ConnectError::NoRoute,
         })?;
 
@@ -4964,11 +4959,11 @@
 ///
 /// `socket_id` is used strictly for logging. `None` can be provided in cases
 /// where the segment is not associated with any particular socket.
-fn send_tcp_segment<'a, WireI, SockI, CC, BC, D, O>(
+fn send_tcp_segment<'a, WireI, SockI, CC, BC, D>(
     core_ctx: &mut CC,
     bindings_ctx: &mut BC,
     socket_id: Option<&TcpSocketId<SockI, D, BC>>,
-    ip_sock: Option<&IpSock<WireI, D, O>>,
+    ip_sock: Option<&IpSock<WireI, D>>,
     conn_addr: ConnIpAddr<WireI::Addr, NonZeroU16, NonZeroU16>,
     segment: Segment<SendPayload<'a>>,
 ) where
@@ -4978,30 +4973,27 @@
         + IpSocketHandler<WireI, BC, DeviceId = D::Strong, WeakDeviceId = D>,
     BC: TcpBindingsTypes,
     D: WeakId,
-    O: SendOptions<WireI>,
 {
     let control = segment.contents.control();
     let result = match ip_sock {
         Some(ip_sock) => {
             let body = tcp_serialize_segment(segment, conn_addr);
             core_ctx
-                .send_ip_packet(bindings_ctx, ip_sock, body, None)
+                .send_ip_packet(bindings_ctx, ip_sock, body, None, &DefaultSendOptions)
                 .map_err(|(_serializer, err)| IpSockCreateAndSendError::Send(err))
         }
         None => {
             let ConnIpAddr { local: (local_ip, _), remote: (remote_ip, _) } = conn_addr;
-            core_ctx
-                .send_oneshot_ip_packet(
-                    bindings_ctx,
-                    None,
-                    Some(local_ip),
-                    remote_ip,
-                    IpProto::Tcp.into(),
-                    DefaultSendOptions,
-                    |_addr| tcp_serialize_segment(segment, conn_addr),
-                    None,
-                )
-                .map_err(|(err, _options)| err)
+            core_ctx.send_oneshot_ip_packet(
+                bindings_ctx,
+                None,
+                Some(local_ip),
+                remote_ip,
+                IpProto::Tcp.into(),
+                &DefaultSendOptions,
+                |_addr| tcp_serialize_segment(segment, conn_addr),
+                None,
+            )
         }
     };
     match result {
@@ -5033,10 +5025,10 @@
     use ip_test_macro::ip_test;
     use net_declare::net_ip_v6;
     use net_types::{
-        ip::{AddrSubnet, Ip, Ipv4, Ipv6, Ipv6SourceAddr, Mtu},
-        LinkLocalAddr, Witness,
+        ip::{Ip, Ipv4, Ipv6, Ipv6SourceAddr, Mtu},
+        LinkLocalAddr,
     };
-    use packet::{Buf, BufferMut, ParseBuffer as _, Serializer};
+    use packet::{Buf, BufferMut, ParseBuffer as _};
     use packet_formats::{
         icmp::{Icmpv4DestUnreachableCode, Icmpv6DestUnreachableCode},
         tcp::{TcpParseArgs, TcpSegment},
@@ -5052,7 +5044,7 @@
                 FakeNetworkContext, FakeTimerCtx, InstantAndData, PendingFrameData, StepResult,
                 WithFakeFrameContext, WithFakeTimerContext, WrappedFakeCoreCtx,
             },
-            ContextProvider, InstantContext as _, SendFrameContext,
+            ContextProvider, InstantContext as _,
         },
         device::{
             link::LinkDevice,
@@ -5060,32 +5052,22 @@
             testutil::{FakeDeviceId, FakeStrongDeviceId, FakeWeakDeviceId, MultipleDevicesId},
             DeviceLayerStateTypes,
         },
-        filter::FilterBindingsTypes,
+        filter::{FilterBindingsTypes, TransportPacketSerializer},
         ip::{
-            device::{
-                nud::LinkResolutionContext,
-                state::{
-                    DualStackIpDeviceState, IpDeviceStateIpExt, Ipv4AddrConfig, Ipv4AddressEntry,
-                    Ipv4DeviceState, Ipv6AddrConfig, Ipv6AddressEntry, Ipv6DadState,
-                    Ipv6DeviceState,
-                },
-                IpDeviceAddr,
-            },
+            device::{nud::LinkResolutionContext, state::IpDeviceStateIpExt},
             icmp::{IcmpIpExt, Icmpv4ErrorCode, Icmpv6ErrorCode},
-            socket::testutil::FakeDualStackIpSocketCtx,
             socket::{
-                testutil::{FakeDeviceConfig, FakeFilterDeviceId},
-                IpSocketBindingsContext, IpSocketContext, MmsError,
+                testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx},
+                IpSockSendError, IpSocketBindingsContext, MmsError, SendOptions,
             },
             testutil::DualStackSendIpPacketMeta,
-            types::{ResolvedRoute, RoutableIpAddr},
-            HopLimits, IpTransportContext, ResolveRouteError, SendIpPacketMeta,
+            HopLimits, IpTransportContext,
         },
         sync::Mutex,
         testutil::ContextPair,
         testutil::{
             new_rng, run_with_many_seeds, set_logger_for_test, FakeCryptoRng, MonotonicIdentifier,
-            TestIpExt, DEFAULT_INTERFACE_METRIC,
+            TestIpExt,
         },
         transport::tcp::{
             buffer::{
@@ -5151,11 +5133,6 @@
         >;
         fn recv_src_addr(addr: Self::Addr) -> Self::RecvSrcAddr;
 
-        fn new_device_state(
-            addrs: impl IntoIterator<Item = Self::Addr>,
-            prefix: u8,
-        ) -> DualStackIpDeviceState<TcpBindingsCtx<FakeDeviceId>>;
-
         fn converter() -> MaybeDualStack<Self::DualStackConverter, Self::SingleStackConverter>;
     }
 
@@ -5221,7 +5198,7 @@
 
     type TcpCoreCtx<D, BT> = WrappedFakeCoreCtx<
         FakeDualStackTcpState<D, BT>,
-        FakeDualStackIpSocketCtx<D, BT>,
+        FakeDualStackIpSocketCtx<D>,
         DualStackSendIpPacketMeta<D>,
         D,
     >;
@@ -5241,7 +5218,7 @@
         }
     }
 
-    impl<D: FakeFilterDeviceId<()>> FakeNetworkContext for TcpCtx<D> {
+    impl<D: FakeStrongDeviceId> FakeNetworkContext for TcpCtx<D> {
         type TimerId = TimerId<D::Weak, TcpBindingsCtx<D>>;
         type SendMeta = DualStackSendIpPacketMeta<D>;
         type RecvMeta = DualStackSendIpPacketMeta<D>;
@@ -5424,10 +5401,10 @@
         D: FakeStrongDeviceId,
         BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext,
     {
-        fn get_mms<O: SendOptions<I>>(
+        fn get_mms(
             &mut self,
             _bindings_ctx: &mut BC,
-            _ip_sock: &IpSock<I, Self::WeakDeviceId, O>,
+            _ip_sock: &IpSock<I, Self::WeakDeviceId>,
         ) -> Result<Mms, MmsError> {
             Ok(Mms::from_mtu::<I>(Mtu::new(1500), 0).unwrap())
         }
@@ -5437,11 +5414,11 @@
     impl<I, D, BC> TransportIpContext<I, BC> for TcpCoreCtx<D, BC>
     where
         I: TcpTestIpExt,
-        D: FakeFilterDeviceId<BC::DeviceClass>,
+        D: FakeStrongDeviceId,
         BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext,
-        FakeDualStackIpSocketCtx<D, BC>: TransportIpContext<I, BC, DeviceId = Self::DeviceId>,
+        FakeDualStackIpSocketCtx<D>: TransportIpContext<I, BC, DeviceId = Self::DeviceId>,
     {
-        type DevicesWithAddrIter<'a> = <FakeDualStackIpSocketCtx<D, BC> as TransportIpContext<I, BC>>::DevicesWithAddrIter<'a>
+        type DevicesWithAddrIter<'a> = <FakeDualStackIpSocketCtx<D> as TransportIpContext<I, BC>>::DevicesWithAddrIter<'a>
             where Self: 'a;
 
         fn get_devices_with_assigned_addr(
@@ -5471,50 +5448,47 @@
     }
 
     /// Delegate implementation to inner context.
-    impl<
-            I: TcpTestIpExt,
-            D: FakeStrongDeviceId,
-            BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext,
-        > IpSocketContext<I, BC> for TcpCoreCtx<D, BC>
+    impl<I: TcpTestIpExt, D: FakeStrongDeviceId, BC: TcpTestBindingsTypes<D>> IpSocketHandler<I, BC>
+        for TcpCoreCtx<D, BC>
     {
-        fn lookup_route(
+        fn new_ip_socket(
             &mut self,
             bindings_ctx: &mut BC,
-            device: Option<&Self::DeviceId>,
-            local_ip: Option<IpDeviceAddr<I::Addr>>,
-            addr: RoutableIpAddr<I::Addr>,
-        ) -> Result<ResolvedRoute<I, Self::DeviceId>, ResolveRouteError> {
-            self.inner.get_mut().lookup_route(bindings_ctx, device, local_ip, addr)
+            device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
+            local_ip: Option<SocketIpAddr<I::Addr>>,
+            remote_ip: SocketIpAddr<I::Addr>,
+            proto: I::Proto,
+        ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError> {
+            IpSocketHandler::<I, BC>::new_ip_socket(
+                &mut self.inner,
+                bindings_ctx,
+                device,
+                local_ip,
+                remote_ip,
+                proto,
+            )
         }
 
-        fn send_ip_packet<SS>(
+        fn send_ip_packet<S, O>(
             &mut self,
             bindings_ctx: &mut BC,
-            SendIpPacketMeta {  device, src_ip, dst_ip, broadcast, next_hop, proto, ttl, mtu }: SendIpPacketMeta<I, &Self::DeviceId, SpecifiedAddr<I::Addr>>,
-            body: SS,
-        ) -> Result<(), SS>
+            socket: &IpSock<I, Self::WeakDeviceId>,
+            body: S,
+            mtu: Option<u32>,
+            options: &O,
+        ) -> Result<(), (S, IpSockSendError)>
         where
-            SS: Serializer,
-            SS::Buffer: BufferMut,
+            S: TransportPacketSerializer,
+            S::Buffer: BufferMut,
+            O: SendOptions<I, Self::WeakDeviceId>,
         {
-            let meta = SendIpPacketMeta::<I, _, _> {
-                device: device.clone(),
-                src_ip,
-                dst_ip,
-                broadcast,
-                next_hop,
-                proto,
-                ttl,
-                mtu,
-            }
-            .into();
-            self.inner.frames.send_frame(bindings_ctx, meta, body)
+            self.inner.send_ip_packet(bindings_ctx, socket, body, mtu, options)
         }
     }
 
     impl<D, BC> TcpDemuxContext<Ipv4, D::Weak, BC> for TcpCoreCtx<D, BC>
     where
-        D: FakeFilterDeviceId<BC::DeviceClass>,
+        D: FakeStrongDeviceId,
         BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext,
     {
         type IpTransportCtx<'a> = Self;
@@ -5544,7 +5518,7 @@
 
     impl<D, BC> TcpDemuxContext<Ipv6, D::Weak, BC> for TcpCoreCtx<D, BC>
     where
-        D: FakeFilterDeviceId<BC::DeviceClass>,
+        D: FakeStrongDeviceId,
         BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext,
     {
         type IpTransportCtx<'a> = Self;
@@ -5583,10 +5557,8 @@
         }
     }
 
-    impl<
-            D: FakeFilterDeviceId<BC::DeviceClass>,
-            BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext,
-        > TcpContext<Ipv6, BC> for TcpCoreCtx<D, BC>
+    impl<D: FakeStrongDeviceId, BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext>
+        TcpContext<Ipv6, BC> for TcpCoreCtx<D, BC>
     {
         type ThisStackIpTransportAndDemuxCtx<'a> = Self;
         type SingleStackIpTransportAndDemuxCtx<'a> = UninstantiableWrapper<Self>;
@@ -5663,10 +5635,8 @@
         }
     }
 
-    impl<
-            D: FakeFilterDeviceId<BC::DeviceClass>,
-            BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext,
-        > TcpContext<Ipv4, BC> for TcpCoreCtx<D, BC>
+    impl<D: FakeStrongDeviceId, BC: TcpTestBindingsTypes<D> + IpSocketBindingsContext>
+        TcpContext<Ipv4, BC> for TcpCoreCtx<D, BC>
     {
         type ThisStackIpTransportAndDemuxCtx<'a> = Self;
         type SingleStackIpTransportAndDemuxCtx<'a> = Self;
@@ -5744,10 +5714,8 @@
         }
     }
 
-    impl<
-            D: FakeFilterDeviceId<BT::DeviceClass>,
-            BT: TcpTestBindingsTypes<D> + IpSocketBindingsContext,
-        > TcpDualStackContext<Ipv6, FakeWeakDeviceId<D>, BT> for TcpCoreCtx<D, BT>
+    impl<D: FakeStrongDeviceId, BT: TcpTestBindingsTypes<D> + IpSocketBindingsContext>
+        TcpDualStackContext<Ipv6, FakeWeakDeviceId<D>, BT> for TcpCoreCtx<D, BT>
     {
         type Converter = Ipv6SocketIdToIpv4DemuxIdConverter;
         type DualStackIpTransportCtx<'a> = Self;
@@ -5843,29 +5811,6 @@
         fn recv_src_addr(addr: Self::Addr) -> Self::RecvSrcAddr {
             addr
         }
-
-        fn new_device_state(
-            addrs: impl IntoIterator<Item = Self::Addr>,
-            prefix: u8,
-        ) -> DualStackIpDeviceState<TcpBindingsCtx<FakeDeviceId>> {
-            let ipv4 = Ipv4DeviceState::default();
-            for addr in addrs {
-                let _addr_id = ipv4
-                    .ip_state
-                    .addrs
-                    .write()
-                    .add(Ipv4AddressEntry::new(
-                        AddrSubnet::new(addr, prefix).unwrap(),
-                        Ipv4AddrConfig::default(),
-                    ))
-                    .expect("failed to add address");
-            }
-            DualStackIpDeviceState {
-                ipv4,
-                ipv6: Default::default(),
-                metric: DEFAULT_INTERFACE_METRIC,
-            }
-        }
     }
 
     impl TcpTestIpExt for Ipv6 {
@@ -5877,30 +5822,6 @@
         fn recv_src_addr(addr: Self::Addr) -> Self::RecvSrcAddr {
             Ipv6SourceAddr::new(addr).unwrap()
         }
-
-        fn new_device_state(
-            addrs: impl IntoIterator<Item = Self::Addr>,
-            prefix: u8,
-        ) -> DualStackIpDeviceState<TcpBindingsCtx<FakeDeviceId>> {
-            let ipv6 = Ipv6DeviceState::default();
-            for addr in addrs {
-                let _addr_id = ipv6
-                    .ip_state
-                    .addrs
-                    .write()
-                    .add(Ipv6AddressEntry::new(
-                        AddrSubnet::new(addr, prefix).unwrap(),
-                        Ipv6DadState::Assigned,
-                        Ipv6AddrConfig::default(),
-                    ))
-                    .expect("failed to add address");
-            }
-            DualStackIpDeviceState {
-                ipv4: Default::default(),
-                ipv6,
-                metric: DEFAULT_INTERFACE_METRIC,
-            }
-        }
     }
 
     type TcpTestNetwork = FakeNetwork<
@@ -7551,15 +7472,11 @@
     {
         let addrs = [1, 2].map(|i| I::get_other_ip_address(i));
         let mut ctx = TcpCtx::with_core_ctx(TcpCoreCtx::with_inner_and_outer_state(
-            FakeDualStackIpSocketCtx::<_, _>::with_devices_state(core::iter::once::<(
-                _,
-                _,
-                Vec<SpecifiedAddr<IpAddr>>,
-            )>((
-                FakeDeviceId,
-                I::new_device_state(addrs.iter().map(Witness::get), I::FAKE_CONFIG.subnet.prefix()),
-                vec![],
-            ))),
+            FakeDualStackIpSocketCtx::new(core::iter::once(FakeDeviceConfig {
+                device: FakeDeviceId,
+                local_ips: addrs.iter().cloned().map(SpecifiedAddr::<IpAddr>::from).collect(),
+                remote_ips: Default::default(),
+            })),
             FakeDualStackTcpState::default(),
         ));
         let mut api = ctx.tcp_api::<I>();
diff --git a/src/connectivity/network/netstack3/core/src/transport/tcp/socket/demux.rs b/src/connectivity/network/netstack3/core/src/transport/tcp/socket/demux.rs
index ea4a22a..ce1b897 100644
--- a/src/connectivity/network/netstack3/core/src/transport/tcp/socket/demux.rs
+++ b/src/connectivity/network/netstack3/core/src/transport/tcp/socket/demux.rs
@@ -25,13 +25,12 @@
 use crate::{
     context::{CounterContext, CtxPair},
     convert::BidirectionalConverter as _,
-    device,
+    device::{self, StrongId as _, WeakId as _},
     error::NotFoundError,
     filter::TransportPacketSerializer,
     ip::{
-        socket::{DefaultSendOptions, MmsError},
-        EitherDeviceId, IpSockCreationError, IpTransportContext, TransportIpContext,
-        TransportReceiveError,
+        socket::MmsError, EitherDeviceId, IpSockCreationError, IpTransportContext,
+        TransportIpContext, TransportReceiveError,
     },
     socket::{
         address::{
@@ -222,7 +221,7 @@
 
     let mut addrs_to_search = AddrVecIter::<WireI, CC::WeakDeviceId, TcpPortSpec>::with_device(
         conn_addr.into(),
-        core_ctx.downgrade_device_id(incoming_device),
+        incoming_device.downgrade(),
     );
 
     let found_socket = loop {
@@ -384,7 +383,7 @@
         // there is no TCB, and therefore, no connection.
         if let Some(seg) = (Closed { reason: None::<Option<ConnectionError>> }.on_segment(incoming))
         {
-            tcp::socket::send_tcp_segment::<WireI, WireI, _, _, _, DefaultSendOptions>(
+            tcp::socket::send_tcp_segment::<WireI, WireI, _, _, _>(
                 core_ctx,
                 bindings_ctx,
                 None,
@@ -621,7 +620,7 @@
 
     let mut confirm_reachable = || {
         let remote_ip = *ip_sock.remote_ip();
-        let device = ip_sock.device().and_then(|weak| core_ctx.upgrade_weak_device_id(weak));
+        let device = ip_sock.device().and_then(|weak| weak.upgrade());
         <DC as TransportIpContext<WireI, _>>::confirm_reachable_with_destination(
             core_ctx,
             bindings_ctx,
@@ -747,7 +746,7 @@
             // conflicting connection was found.
             *addrs_to_search = AddrVecIter::<WireI, CC::WeakDeviceId, TcpPortSpec>::with_device(
                 conn_addr.into(),
-                core_ctx.downgrade_device_id(incoming_device),
+                incoming_device.downgrade(),
             );
             false
         }
@@ -891,10 +890,9 @@
         Some(local_ip),
         remote_ip,
         IpProto::Tcp.into(),
-        DefaultSendOptions,
     ) {
         Ok(ip_sock) => ip_sock,
-        err @ Err((IpSockCreationError::Route(_), DefaultSendOptions)) => {
+        err @ Err(IpSockCreationError::Route(_)) => {
             core_ctx.increment(|counters| &counters.passive_open_no_route_errors);
             core_ctx.increment(|counters| &counters.failed_connection_attempts);
             debug!("cannot construct an ip socket to the SYN originator: {:?}, ignoring", err);
diff --git a/src/connectivity/network/netstack3/core/src/transport/tcp/state.rs b/src/connectivity/network/netstack3/core/src/transport/tcp/state.rs
index df2f557..5fa5cd9 100644
--- a/src/connectivity/network/netstack3/core/src/transport/tcp/state.rs
+++ b/src/connectivity/network/netstack3/core/src/transport/tcp/state.rs
@@ -881,11 +881,11 @@
         buffer.target_capacity()
     }
 
-    fn poll_send(&mut self, snd_nxt: SeqNum, now: I) -> Option<Segment<()>> {
+    fn poll_send(&mut self, snd_max: SeqNum, now: I) -> Option<Segment<()>> {
         match self.timer {
             Some(ReceiveTimer::DelayedAck { at, received_bytes: _ }) => (at <= now).then(|| {
                 self.timer = None;
-                Segment::ack(snd_nxt, self.nxt(), self.select_window() >> self.wnd_scale)
+                Segment::ack(snd_max, self.nxt(), self.select_window() >> self.wnd_scale)
             }),
             None => None,
         }
@@ -1030,7 +1030,7 @@
                         // Per RFC 9293 Section 3.8.4:
                         //   Such a segment generally contains SEG.SEQ = SND.NXT-1
                         return Some(
-                            Segment::ack(*snd_nxt - 1, rcv_nxt, rcv_wnd >> *wnd_scale).into(),
+                            Segment::ack(*snd_max - 1, rcv_nxt, rcv_wnd >> *wnd_scale).into(),
                         );
                     }
                 } else {
@@ -1259,7 +1259,7 @@
             //   If the ACK acks something not yet sent (SEG.ACK >
             //   SND.NXT) then send an ACK, drop the segment, and
             //   return.
-            (Some(Segment::ack(*snd_nxt, rcv_nxt, rcv_wnd >> *wnd_scale)), DataAcked::No)
+            (Some(Segment::ack(*snd_max, rcv_nxt, rcv_wnd >> *wnd_scale)), DataAcked::No)
         } else if seg_ack.after(*snd_una) {
             // The unwrap is safe because the result must be positive.
             let acked = u32::try_from(seg_ack - *snd_una)
@@ -1709,7 +1709,7 @@
         let mut passive_open = None;
         let mut data_acked = DataAcked::No;
         let seg = (|| {
-            let (mut rcv_nxt, rcv_wnd, rcv_wnd_scale, snd_nxt) = match self {
+            let (mut rcv_nxt, rcv_wnd, rcv_wnd_scale, snd_max) = match self {
                 State::Closed(closed) => return closed.on_segment(incoming),
                 State::Listen(listen) => {
                     return match listen.on_segment(incoming, now) {
@@ -1769,7 +1769,7 @@
                                         rcv: established.rcv.with_buffer(rcv_buffer),
                                     };
                                     let ack = Some(Segment::ack(
-                                        established.snd.nxt,
+                                        established.snd.max,
                                         established.rcv.nxt(),
                                         established.rcv.select_window() >> rcv_wnd_scale,
                                     ));
@@ -1823,17 +1823,17 @@
                     )
                 }
                 State::Established(Established { rcv, snd }) => {
-                    (rcv.nxt(), rcv.select_window(), rcv.wnd_scale, snd.nxt)
+                    (rcv.nxt(), rcv.select_window(), rcv.wnd_scale, snd.max)
                 }
                 State::CloseWait(CloseWait { snd, last_ack, last_wnd }) => {
-                    (*last_ack, *last_wnd, WindowScale::default(), snd.nxt)
+                    (*last_ack, *last_wnd, WindowScale::default(), snd.max)
                 }
                 State::LastAck(LastAck { snd, last_ack, last_wnd })
                 | State::Closing(Closing { snd, last_ack, last_wnd, last_wnd_scale: _ }) => {
-                    (*last_ack, *last_wnd, WindowScale::default(), snd.nxt)
+                    (*last_ack, *last_wnd, WindowScale::default(), snd.max)
                 }
                 State::FinWait1(FinWait1 { rcv, snd }) => {
-                    (rcv.nxt(), rcv.select_window(), rcv.wnd_scale, snd.nxt)
+                    (rcv.nxt(), rcv.select_window(), rcv.wnd_scale, snd.max)
                 }
                 State::FinWait2(FinWait2 { last_seq, rcv, timeout_at: _ }) => {
                     (rcv.nxt(), rcv.select_window(), rcv.wnd_scale, *last_seq)
@@ -1869,7 +1869,7 @@
                         return if is_rst {
                             None
                         } else {
-                            Some(Segment::ack(snd_nxt, rcv_nxt, rcv_wnd >> rcv_wnd_scale))
+                            Some(Segment::ack(snd_max, rcv_nxt, rcv_wnd >> rcv_wnd_scale))
                         };
                     }
                 };
@@ -1902,7 +1902,7 @@
                     counters,
                     State::Closed(Closed { reason: Some(ConnectionError::ConnectionReset) }),
                 );
-                return Some(Segment::rst(snd_nxt));
+                return Some(Segment::rst(snd_max));
             }
             // Per RFC 793 (https://tools.ietf.org/html/rfc793#page-72):
             //   fifth check the ACK field
@@ -2155,7 +2155,7 @@
                             }
                         }
                         (!matches!(rcv.timer, Some(ReceiveTimer::DelayedAck { .. }))).then_some(
-                            Segment::ack(snd_nxt, rcv.nxt(), rcv.select_window() >> rcv.wnd_scale),
+                            Segment::ack(snd_max, rcv.nxt(), rcv.select_window() >> rcv.wnd_scale),
                         )
                     }
                     State::CloseWait(_)
@@ -2194,7 +2194,7 @@
                         let scaled_wnd = last_wnd >> rcv.wnd_scale;
                         let closewait = CloseWait { snd: snd.take(), last_ack, last_wnd };
                         self.transition_to_state(counters, State::CloseWait(closewait));
-                        Some(Segment::ack(snd_nxt, last_ack, scaled_wnd))
+                        Some(Segment::ack(snd_max, last_ack, scaled_wnd))
                     }
                     State::CloseWait(_) | State::LastAck(_) | State::Closing(_) => {
                         // Per RFC 793 (https://tools.ietf.org/html/rfc793#page-75):
@@ -2218,7 +2218,7 @@
                             last_wnd_scale: rcv.wnd_scale,
                         };
                         self.transition_to_state(counters, State::Closing(closing));
-                        Some(Segment::ack(snd_nxt, last_ack, scaled_wnd))
+                        Some(Segment::ack(snd_max, last_ack, scaled_wnd))
                     }
                     State::FinWait2(FinWait2 { last_seq, rcv, timeout_at: _ }) => {
                         let last_ack = rcv.nxt() + 1;
@@ -2233,7 +2233,7 @@
                             last_wnd_scale: rcv.wnd_scale,
                         };
                         self.transition_to_state(counters, State::TimeWait(timewait));
-                        Some(Segment::ack(snd_nxt, last_ack, scaled_window))
+                        Some(Segment::ack(snd_max, last_ack, scaled_window))
                     }
                     State::TimeWait(TimeWait {
                         last_seq,
@@ -2296,7 +2296,7 @@
             let rcv_nxt = rcv.nxt();
             let rcv_wnd = rcv.select_window();
             let seg = rcv
-                .poll_send(snd.nxt, now)
+                .poll_send(snd.max, now)
                 .map(Into::into)
                 .or_else(|| snd.poll_send(counters, rcv_nxt, rcv_wnd, limit, now, socket_options));
             // We must have piggybacked an ACK so we can cancel the timer now.
@@ -6480,4 +6480,100 @@
             ))
         );
     }
+
+    #[test]
+    // Regression test for https://fxbug.dev/334926865.
+    fn ack_uses_snd_max() {
+        let counters = TcpCountersInner::default();
+        let mss = Mss(NonZeroU16::new(u16::try_from(TEST_BYTES.len()).unwrap()).unwrap());
+
+        let mut clock = FakeInstantCtx::default();
+        let mut buffer = RingBuffer::new(BUFFER_SIZE);
+        assert_eq!(buffer.enqueue_data(TEST_BYTES), TEST_BYTES.len());
+        assert_eq!(buffer.enqueue_data(TEST_BYTES), TEST_BYTES.len());
+
+        // This connection has the same send and receive seqnum space.
+        let mut state: State<_, _, _, ()> = State::Established(Established {
+            snd: Send {
+                nxt: ISS_1 + 1,
+                max: ISS_1 + 1,
+                una: ISS_1 + 1,
+                wnd: WindowSize::DEFAULT,
+                wnd_max: WindowSize::DEFAULT,
+                buffer,
+                wl1: ISS_1,
+                wl2: ISS_1,
+                last_seq_ts: None,
+                rtt_estimator: Estimator::NoSample,
+                timer: None,
+                congestion_control: CongestionControl::cubic_with_mss(mss),
+                wnd_scale: WindowScale::default(),
+            },
+            rcv: Recv {
+                buffer: RingBuffer::new(BUFFER_SIZE),
+                assembler: Assembler::new(ISS_1 + 1),
+                timer: None,
+                mss,
+                wnd_scale: WindowScale::default(),
+                last_window_update: (ISS_1 + 1, WindowSize::new(BUFFER_SIZE).unwrap()),
+            },
+        });
+
+        // Send the first two data segments.
+        assert_eq!(
+            state.poll_send_with_default_options(u32::MAX, clock.now(), &counters),
+            Some(Segment::data(
+                ISS_1 + 1,
+                ISS_1 + 1,
+                UnscaledWindowSize::from(u16::try_from(BUFFER_SIZE).unwrap()),
+                SendPayload::Contiguous(TEST_BYTES),
+            )),
+        );
+        assert_eq!(
+            state.poll_send_with_default_options(u32::MAX, clock.now(), &counters),
+            Some(Segment::data(
+                ISS_1 + 1 + TEST_BYTES.len(),
+                ISS_1 + 1,
+                UnscaledWindowSize::from(u16::try_from(BUFFER_SIZE).unwrap()),
+                SendPayload::Contiguous(TEST_BYTES),
+            )),
+        );
+
+        // Retransmit, now snd.nxt = TEST.BYTES.len() + 1.
+        clock.sleep(Estimator::RTO_INIT);
+        assert_eq!(
+            state.poll_send_with_default_options(u32::MAX, clock.now(), &counters),
+            Some(Segment::data(
+                ISS_1 + 1,
+                ISS_1 + 1,
+                UnscaledWindowSize::from(u16::try_from(BUFFER_SIZE).unwrap()),
+                SendPayload::Contiguous(TEST_BYTES),
+            )),
+        );
+
+        // the ACK sent should have seq = snd.max (2 * TEST_BYTES.len() + 1) to
+        // avoid getting stuck in an ACK cycle.
+        assert_eq!(
+            state.on_segment_with_default_options::<_, ClientlessBufferProvider>(
+                Segment::data(
+                    ISS_1 + 1,
+                    ISS_1 + 1,
+                    UnscaledWindowSize::from(u16::try_from(BUFFER_SIZE).unwrap()),
+                    SendPayload::Contiguous(TEST_BYTES),
+                ),
+                clock.now(),
+                &counters,
+            ),
+            (
+                Some(Segment::ack(
+                    ISS_1 + 1 + 2 * TEST_BYTES.len(),
+                    ISS_1 + 1 + TEST_BYTES.len(),
+                    UnscaledWindowSize::from(
+                        u16::try_from(BUFFER_SIZE - TEST_BYTES.len()).unwrap()
+                    ),
+                )),
+                None,
+            )
+        );
+    }
 }
diff --git a/src/connectivity/network/netstack3/core/src/transport/udp.rs b/src/connectivity/network/netstack3/core/src/transport/udp.rs
index f61816e..d6fc894 100644
--- a/src/connectivity/network/netstack3/core/src/transport/udp.rs
+++ b/src/connectivity/network/netstack3/core/src/transport/udp.rs
@@ -20,9 +20,10 @@
 use either::Either;
 use net_types::{
     ip::{
-        GenericOverIp, Ip, IpAddress, IpInvariant, IpMarked, IpVersion, IpVersionMarker, Ipv4, Ipv6,
+        GenericOverIp, Ip, IpAddress, IpInvariant, IpMarked, IpVersion, IpVersionMarker, Ipv4,
+        Ipv4Addr, Ipv6,
     },
-    MulticastAddr, SpecifiedAddr, Witness, ZonedAddr,
+    MulticastAddr, MulticastAddress, SpecifiedAddr, Witness, ZonedAddr,
 };
 use packet::{BufferMut, Nested, ParsablePacket, Serializer};
 use packet_formats::{
@@ -41,11 +42,11 @@
     convert::BidirectionalConverter,
     counters::Counter,
     data_structures::socketmap::{IterShadows as _, SocketMap, Tagged},
-    device::{self, AnyDevice, DeviceIdContext},
+    device::{self, AnyDevice, DeviceIdContext, StrongId as _},
     error::{LocalAddressError, SocketError, ZonedAddressError},
     inspect::{Inspector, InspectorDeviceExt},
     ip::{
-        socket::{IpSockCreateAndSendError, IpSockCreationError, IpSockSendError},
+        socket::{IpSockCreateAndSendError, IpSockCreationError, IpSockSendError, SendOptions},
         HopLimits, IpTransportContext, MulticastMembershipHandler, TransportIpContext,
         TransportReceiveError,
     },
@@ -536,9 +537,9 @@
 }
 
 /// State held for IPv6 sockets related to dual-stack operation.
-#[derive(Clone, Debug, Derivative)]
-#[derivative(Default)]
-pub struct DualStackSocketState {
+#[derive(Clone, Derivative)]
+#[derivative(Default(bound = ""), Debug(bound = ""))]
+pub struct DualStackSocketState<D: device::WeakId> {
     /// Whether dualstack operations are enabled on this socket.
     /// Match Linux's behavior by enabling dualstack operations by default.
     #[derivative(Default(value = "true"))]
@@ -546,6 +547,25 @@
     /// The IPv4 hop limits (e.g. TTL) to be used when sending packets in the
     /// IPv4 stack.
     hop_limits: SocketHopLimits<Ipv4>,
+
+    /// The multicast interface which can be set for IPv4 independently from
+    /// the interface selected for IPv6.
+    multicast_interface: Option<D>,
+}
+
+impl<D: device::WeakId> SendOptions<Ipv4, D> for DualStackSocketState<D> {
+    fn hop_limit(&self, destination: &SpecifiedAddr<Ipv4Addr>) -> Option<NonZeroU8> {
+        let Self { hop_limits: SocketHopLimits { unicast, multicast, version: _ }, .. } = self;
+        if destination.is_multicast() {
+            *multicast
+        } else {
+            *unicast
+        }
+    }
+
+    fn multicast_interface(&self) -> Option<&D> {
+        self.multicast_interface.as_ref()
+    }
 }
 
 /// Serialization errors for Udp Packets.
@@ -559,11 +579,12 @@
     const NAME: &'static str = "UDP";
     type AddrSpec = UdpAddrSpec;
     type SocketId<I: IpExt, D: device::WeakId> = UdpSocketId<I, D, BT>;
-    type OtherStackIpOptions<I: IpExt> = I::OtherStackIpOptions<DualStackSocketState>;
+    type OtherStackIpOptions<I: IpExt, D: device::WeakId> =
+        I::OtherStackIpOptions<DualStackSocketState<D>>;
     type ListenerIpAddr<I: IpExt> = I::DualStackListenerIpAddr<NonZeroU16>;
     type ConnIpAddr<I: IpExt> = I::DualStackConnIpAddr<Self>;
     type ConnStateExtra = ();
-    type ConnState<I: IpExt, D: Debug + Eq + Hash + Send + Sync> = I::DualStackConnState<D, Self>;
+    type ConnState<I: IpExt, D: device::WeakId> = I::DualStackConnState<D, Self>;
     type SocketMapSpec<I: IpExt, D: device::WeakId> = (Self, I, D);
     type SharingState = Sharing;
 
@@ -606,7 +627,7 @@
         try_alloc_listen_port::<I, D, BT>(rng, is_available)
     }
 
-    fn conn_info_from_state<I: IpExt, D: Clone + Debug + Eq + Hash + Send + Sync>(
+    fn conn_info_from_state<I: IpExt, D: device::WeakId>(
         state: &Self::ConnState<I, D>,
     ) -> datagram::ConnInfo<I::Addr, D> {
         let ConnAddr { ip, device } = I::conn_addr_from_state(state);
@@ -974,7 +995,7 @@
 impl<I: IpExt, D: device::WeakId, BT: UdpBindingsTypes> Debug for UdpSocketId<I, D, BT> {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let Self(rc) = self;
-        f.debug_tuple("UdpSocketId").field(&StrongRc::ptr_debug(rc)).finish()
+        f.debug_tuple("UdpSocketId").field(&StrongRc::debug_id(rc)).finish()
     }
 }
 
@@ -1024,7 +1045,7 @@
 impl<I: IpExt, D: device::WeakId, BT: UdpBindingsTypes> Debug for WeakUdpSocketId<I, D, BT> {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         let Self(rc) = self;
-        f.debug_tuple("WeakUdpSocketId").field(&rc.ptr_debug()).finish()
+        f.debug_tuple("WeakUdpSocketId").field(&rc.debug_id()).finish()
     }
 }
 
@@ -1342,7 +1363,7 @@
 
     let dst_port = packet.dst_port();
     let recipients = StateContext::<I, _>::with_bound_state_context(core_ctx, |core_ctx| {
-        let device_weak = core_ctx.downgrade_device_id(device);
+        let device_weak = device.downgrade();
         DatagramBoundStateContext::with_bound_sockets(core_ctx, |_core_ctx, bound_sockets| {
             lookup(bound_sockets, (src_ip, src_port), (dst_ip, dst_port), device_weak)
                 .map(|result| match result {
@@ -1716,8 +1737,7 @@
                     (enabled, WrapOtherStackIpOptionsMut(other_stack)),
                     |(_enabled, _v4)| Err(SetDualStackEnabledError::NotCapable),
                     |(enabled, WrapOtherStackIpOptionsMut(other_stack))| {
-                        let DualStackSocketState { dual_stack_enabled, hop_limits: _ } =
-                            other_stack;
+                        let DualStackSocketState { dual_stack_enabled, .. } = other_stack;
                         *dual_stack_enabled = enabled;
                         Ok(())
                     },
@@ -1756,7 +1776,7 @@
                 WrapOtherStackIpOptions(other_stack),
                 |_v4| Err(NotDualStackCapableError),
                 |WrapOtherStackIpOptions(other_stack)| {
-                    let DualStackSocketState { dual_stack_enabled, hop_limits: _ } = other_stack;
+                    let DualStackSocketState { dual_stack_enabled, .. } = other_stack;
                     Ok(*dual_stack_enabled)
                 },
             )
@@ -1851,8 +1871,8 @@
                 |(IpInvariant(_unicast_hop_limit), _v4)| Err(NotDualStackCapableError),
                 |(IpInvariant(unicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack))| {
                     let DualStackSocketState {
-                        dual_stack_enabled: _,
                         hop_limits: SocketHopLimits { unicast, multicast: _, version: _ },
+                        ..
                     } = other_stack;
                     *unicast = unicast_hop_limit;
                     Ok(())
@@ -1890,8 +1910,8 @@
                 |(IpInvariant(_multicast_hop_limit), _v4)| Err(NotDualStackCapableError),
                 |(IpInvariant(multicast_hop_limit), WrapOtherStackIpOptionsMut(other_stack))| {
                     let DualStackSocketState {
-                        dual_stack_enabled: _,
                         hop_limits: SocketHopLimits { unicast: _, multicast, version: _ },
+                        ..
                     } = other_stack;
                     *multicast = multicast_hop_limit;
                     Ok(())
@@ -1932,8 +1952,8 @@
                         IpInvariant(HopLimits { unicast: default_unicast, multicast: _ }),
                     )| {
                         let DualStackSocketState {
-                            dual_stack_enabled: _,
                             hop_limits: SocketHopLimits { unicast, multicast: _, version: _ },
+                            ..
                         } = other_stack;
                         Ok(IpInvariant(unicast.unwrap_or(default_unicast)))
                     },
@@ -1975,8 +1995,8 @@
                         IpInvariant(HopLimits { unicast: _, multicast: default_multicast }),
                     )| {
                         let DualStackSocketState {
-                            dual_stack_enabled: _,
                             hop_limits: SocketHopLimits { unicast: _, multicast, version: _ },
+                            ..
                         } = other_stack;
                         Ok(IpInvariant(multicast.unwrap_or(default_multicast)))
                     },
@@ -2366,17 +2386,17 @@
         &self,
         state: &impl AsRef<IpOptions<Ipv6, Self::WeakDeviceId, Udp<BC>>>,
     ) -> bool {
-        let DualStackSocketState { dual_stack_enabled, hop_limits: _ } =
-            state.as_ref().other_stack();
+        let DualStackSocketState { dual_stack_enabled, .. } = state.as_ref().other_stack();
         *dual_stack_enabled
     }
 
+    type OtherSendOptions = DualStackSocketState<CC::WeakDeviceId>;
+
     fn to_other_send_options<'a>(
         &self,
         state: &'a IpOptions<Ipv6, Self::WeakDeviceId, Udp<BC>>,
-    ) -> &'a SocketHopLimits<Ipv4> {
-        let DualStackSocketState { dual_stack_enabled: _, hop_limits } = state.other_stack();
-        hop_limits
+    ) -> &'a Self::OtherSendOptions {
+        state.other_stack()
     }
 
     type Converter = ();
@@ -2466,7 +2486,7 @@
     use net_declare::net_ip_v4 as ip_v4;
     use net_declare::net_ip_v6;
     use net_types::{
-        ip::{IpAddr, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr},
+        ip::{IpAddr, Ipv4, Ipv6, Ipv6Addr, Ipv6SourceAddr},
         AddrAndZone, LinkLocalAddr, MulticastAddr, Scope as _, ScopeableAddress as _, ZonedAddr,
     };
     use packet::Buf;
@@ -2480,14 +2500,17 @@
         },
         device::{
             loopback::{LoopbackCreationProperties, LoopbackDevice},
-            testutil::{FakeDeviceId, FakeStrongDeviceId, FakeWeakDeviceId, MultipleDevicesId},
+            testutil::{
+                FakeDeviceId, FakeReferencyDeviceId, FakeStrongDeviceId, FakeWeakDeviceId,
+                MultipleDevicesId,
+            },
             DeviceId,
         },
         error::RemoteAddressError,
         ip::{
             device::state::IpDeviceStateIpExt,
-            socket::testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx, FakeFilterDeviceId},
-            testutil::{DualStackSendIpPacketMeta, FakeIpDeviceIdCtx},
+            socket::testutil::{FakeDeviceConfig, FakeDualStackIpSocketCtx},
+            testutil::DualStackSendIpPacketMeta,
             ResolveRouteError, SendIpPacketMeta,
         },
         socket::{self, datagram::MulticastInterfaceSelector, StrictlyZonedAddr},
@@ -2515,9 +2538,33 @@
         src_port: Option<NonZeroU16>,
     }
 
+    impl<D: FakeStrongDeviceId> FakeUdpCoreCtx<D> {
+        fn new_with_device<I: TestIpExt>(device: D) -> Self {
+            Self::with_local_remote_ip_addrs_and_device(
+                vec![local_ip::<I>()],
+                vec![remote_ip::<I>()],
+                device,
+            )
+        }
+    }
+
     impl FakeUdpCoreCtx<FakeDeviceId> {
         fn new_fake_device<I: TestIpExt>() -> Self {
-            Self::with_local_remote_ip_addrs(vec![local_ip::<I>()], vec![remote_ip::<I>()])
+            Self::new_with_device::<I>(FakeDeviceId)
+        }
+    }
+
+    impl<Outer: Default, D: FakeStrongDeviceId> Wrapped<Outer, FakeUdpInnerCoreCtx<D>> {
+        fn with_local_remote_ip_addrs_and_device<A: Into<SpecifiedAddr<IpAddr>>>(
+            local_ips: Vec<A>,
+            remote_ips: Vec<A>,
+            device: D,
+        ) -> Self {
+            Self::with_state(FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
+                device,
+                local_ips,
+                remote_ips,
+            }]))
         }
     }
 
@@ -2526,16 +2573,12 @@
             local_ips: Vec<A>,
             remote_ips: Vec<A>,
         ) -> Self {
-            Self::with_state(FakeDualStackIpSocketCtx::new([FakeDeviceConfig {
-                device: FakeDeviceId,
-                local_ips,
-                remote_ips,
-            }]))
+            Self::with_local_remote_ip_addrs_and_device(local_ips, remote_ips, FakeDeviceId)
         }
     }
 
     impl<Outer: Default, D: FakeStrongDeviceId> Wrapped<Outer, FakeUdpInnerCoreCtx<D>> {
-        fn with_state(state: FakeDualStackIpSocketCtx<D, FakeUdpBindingsCtx<D>>) -> Self {
+        fn with_state(state: FakeDualStackIpSocketCtx<D>) -> Self {
             Wrapped {
                 outer: Outer::default(),
                 inner: WrappedFakeCoreCtx::with_inner_and_outer_state(state, Default::default()),
@@ -2584,11 +2627,8 @@
 
     /// The FakeCoreCtx held as the inner state of the [`WrappedFakeCoreCtx`] that
     /// is [`FakeUdpCoreCtx`].
-    type FakeBufferCoreCtx<D> = FakeCoreCtx<
-        FakeDualStackIpSocketCtx<D, FakeUdpBindingsCtx<D>>,
-        DualStackSendIpPacketMeta<D>,
-        D,
-    >;
+    type FakeBufferCoreCtx<D> =
+        FakeCoreCtx<FakeDualStackIpSocketCtx<D>, DualStackSendIpPacketMeta<D>, D>;
 
     type UdpFakeDeviceCtx = FakeUdpCtx<FakeDeviceId>;
     type UdpFakeDeviceCoreCtx = FakeUdpCoreCtx<FakeDeviceId>;
@@ -2687,7 +2727,7 @@
 
     impl<
             I: TestIpExt,
-            D: FakeFilterDeviceId<()>,
+            D: FakeStrongDeviceId,
             Outer: Borrow<UdpSocketSet<I, FakeWeakDeviceId<D>, FakeUdpBindingsCtx<D>>>
                 + BorrowMut<UdpSocketSet<I, FakeWeakDeviceId<D>, FakeUdpBindingsCtx<D>>>,
         > StateContext<I, FakeUdpBindingsCtx<D>> for Wrapped<Outer, FakeUdpInnerCoreCtx<D>>
@@ -2771,7 +2811,7 @@
         }
     }
 
-    impl<I: TestIpExt, D: FakeFilterDeviceId<()>> BoundStateContext<I, FakeUdpBindingsCtx<D>>
+    impl<I: TestIpExt, D: FakeStrongDeviceId> BoundStateContext<I, FakeUdpBindingsCtx<D>>
         for FakeUdpInnerCoreCtx<D>
     {
         type IpSocketsCtx<'a> = FakeBufferCoreCtx<D>;
@@ -2817,14 +2857,14 @@
         fn dual_stack_context(
             &mut self,
         ) -> MaybeDualStack<&mut Self::DualStackContext, &mut Self::NonDualStackContext> {
-            struct Wrap<'a, I: Ip + TestIpExt, D: FakeFilterDeviceId<()> + 'static>(
+            struct Wrap<'a, I: Ip + TestIpExt, D: FakeStrongDeviceId + 'static>(
                 MaybeDualStack<
                     &'a mut I::UdpDualStackBoundStateContext<D>,
                     &'a mut I::UdpNonDualStackBoundStateContext<D>,
                 >,
             );
             // TODO(https://fxbug.dev/42082123): Replace this with a derived impl.
-            impl<'a, I: TestIpExt, NewIp: TestIpExt, D: FakeFilterDeviceId<()> + 'static>
+            impl<'a, I: TestIpExt, NewIp: TestIpExt, D: FakeStrongDeviceId + 'static>
                 GenericOverIp<NewIp> for Wrap<'a, I, D>
             {
                 type Type = Wrap<'a, NewIp, D>;
@@ -2846,7 +2886,7 @@
     {
     }
 
-    impl<D: FakeFilterDeviceId<()>> DualStackBoundStateContext<Ipv6, FakeUdpBindingsCtx<D>>
+    impl<D: FakeStrongDeviceId> DualStackBoundStateContext<Ipv6, FakeUdpBindingsCtx<D>>
         for FakeUdpInnerCoreCtx<D>
     {
         type IpSocketsCtx<'a> = FakeBufferCoreCtx<D>;
@@ -2892,7 +2932,7 @@
     }
 
     /// Ip packet delivery for the [`FakeUdpCoreCtx`].
-    impl<I: IpExt + IpDeviceStateIpExt + TestIpExt, D: FakeFilterDeviceId<()>>
+    impl<I: IpExt + IpDeviceStateIpExt + TestIpExt, D: FakeStrongDeviceId>
         IpTransportContext<I, FakeUdpBindingsCtx<D>, FakeUdpCoreCtx<D>> for UdpIpTransportContext
     {
         fn receive_icmp_error(
@@ -2999,18 +3039,18 @@
     }
 
     trait TestIpExt: crate::testutil::TestIpExt + IpExt + IpDeviceStateIpExt {
-        type UdpDualStackBoundStateContext<D: FakeFilterDeviceId<()> + 'static>:
+        type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static>:
             DualStackDatagramBoundStateContext<Self, FakeUdpBindingsCtx<D>, Udp<FakeUdpBindingsCtx<D>>, DeviceId=D, WeakDeviceId=D::Weak>;
-        type UdpNonDualStackBoundStateContext<D: FakeFilterDeviceId<()> + 'static>:
+        type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static>:
             NonDualStackDatagramBoundStateContext<Self, FakeUdpBindingsCtx<D>, Udp<FakeUdpBindingsCtx<D>>, DeviceId=D, WeakDeviceId=D::Weak>;
         fn try_into_recv_src_addr(addr: Self::Addr) -> Option<Self::RecvSrcAddr>;
     }
 
     impl TestIpExt for Ipv4 {
-        type UdpDualStackBoundStateContext<D: FakeFilterDeviceId<()> + 'static> =
+        type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
             UninstantiableWrapper<FakeUdpInnerCoreCtx<D>>;
 
-        type UdpNonDualStackBoundStateContext<D: FakeFilterDeviceId<()> + 'static> =
+        type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
             FakeUdpInnerCoreCtx<D>;
 
         fn try_into_recv_src_addr(addr: Ipv4Addr) -> Option<Ipv4Addr> {
@@ -3019,9 +3059,9 @@
     }
 
     impl TestIpExt for Ipv6 {
-        type UdpDualStackBoundStateContext<D: FakeFilterDeviceId<()> + 'static> =
+        type UdpDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
             FakeUdpInnerCoreCtx<D>;
-        type UdpNonDualStackBoundStateContext<D: FakeFilterDeviceId<()> + 'static> =
+        type UdpNonDualStackBoundStateContext<D: FakeStrongDeviceId + 'static> =
             UninstantiableWrapper<FakeUdpInnerCoreCtx<D>>;
 
         fn try_into_recv_src_addr(addr: Ipv6Addr) -> Option<Ipv6SourceAddr> {
@@ -3413,12 +3453,6 @@
         );
     }
 
-    fn set_device_removed<I: TestIpExt>(core_ctx: &mut UdpFakeDeviceCoreCtx, device_removed: bool) {
-        let core_ctx: &mut FakeCoreCtx<_, _, _> = core_ctx.as_mut();
-        let core_ctx: &mut FakeIpDeviceIdCtx<_> = core_ctx.get_mut().as_mut();
-        core_ctx.set_device_removed(FakeDeviceId, device_removed);
-    }
-
     #[ip_test]
     #[test_case(
         true,
@@ -3429,14 +3463,16 @@
         expected: Result<(), ConnectError>,
     ) {
         set_logger_for_test();
-        let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
+        let device = FakeReferencyDeviceId::default();
+        let mut ctx =
+            FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
         let mut api = UdpApi::<I, _>::new(ctx.as_mut());
 
         let unbound = api.create();
-        api.set_device(&unbound, Some(&FakeDeviceId)).unwrap();
+        api.set_device(&unbound, Some(&device)).unwrap();
 
         if remove_device {
-            set_device_removed::<I>(api.core_ctx(), remove_device);
+            device.mark_removed();
         }
 
         let remote_ip = remote_ip::<I>();
@@ -3727,11 +3763,13 @@
     #[ip_test]
     fn test_send_udp_conn_device_removed<I: Ip + TestIpExt>() {
         set_logger_for_test();
-        let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
+        let device = FakeReferencyDeviceId::default();
+        let mut ctx =
+            FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
         let mut api = UdpApi::<I, _>::new(ctx.as_mut());
         let remote_ip = remote_ip::<I>();
         let socket = api.create();
-        api.set_device(&socket, Some(&FakeDeviceId)).unwrap();
+        api.set_device(&socket, Some(&device)).unwrap();
         api.connect(&socket, Some(ZonedAddr::Unzoned(remote_ip)), REMOTE_PORT.into())
             .expect("connect failed");
 
@@ -3744,7 +3782,9 @@
                 )))),
             ),
         ] {
-            set_device_removed::<I>(api.core_ctx(), device_removed);
+            if device_removed {
+                device.mark_removed();
+            }
 
             assert_eq!(api.send(&socket, Buf::new(Vec::new(), ..)), expected_res)
         }
@@ -5019,13 +5059,15 @@
 
     #[ip_test]
     fn test_multicast_membership_with_removed_device<I: Ip + TestIpExt>() {
-        let mut ctx = UdpFakeDeviceCtx::with_core_ctx(UdpFakeDeviceCoreCtx::new_fake_device::<I>());
+        let device = FakeReferencyDeviceId::default();
+        let mut ctx =
+            FakeUdpCtx::with_core_ctx(FakeUdpCoreCtx::new_with_device::<I>(device.clone()));
         let mut api = UdpApi::<I, _>::new(ctx.as_mut());
 
         let unbound = api.create();
-        api.set_device(&unbound, Some(&FakeDeviceId)).unwrap();
+        api.set_device(&unbound, Some(&device)).unwrap();
 
-        set_device_removed::<I>(api.core_ctx(), true);
+        device.mark_removed();
 
         let group = I::get_multicast_addr(4);
         assert_eq!(
diff --git a/src/connectivity/network/netstack3/core/src/uninstantiable.rs b/src/connectivity/network/netstack3/core/src/uninstantiable.rs
index b695756..07f5bdf 100644
--- a/src/connectivity/network/netstack3/core/src/uninstantiable.rs
+++ b/src/connectivity/network/netstack3/core/src/uninstantiable.rs
@@ -21,7 +21,10 @@
     convert::BidirectionalConverter,
     device::{self, Device, DeviceIdContext},
     ip::{
-        socket::{DeviceIpSocketHandler, IpSock, IpSocketHandler, Mms, MmsError, SendOptions},
+        socket::{
+            DefaultSendOptions, DeviceIpSocketHandler, IpSock, IpSocketHandler, Mms, MmsError,
+            SendOptions,
+        },
         EitherDeviceId, HopLimits, IpExt, IpLayerIpExt, IpSockCreationError, IpSockSendError,
         TransportIpContext,
     },
@@ -76,15 +79,6 @@
 impl<D: Device, C: DeviceIdContext<D>> DeviceIdContext<D> for UninstantiableWrapper<C> {
     type DeviceId = C::DeviceId;
     type WeakDeviceId = C::WeakDeviceId;
-    fn downgrade_device_id(&self, _device_id: &Self::DeviceId) -> Self::WeakDeviceId {
-        self.uninstantiable_unreachable()
-    }
-    fn upgrade_weak_device_id(
-        &self,
-        _weak_device_id: &Self::WeakDeviceId,
-    ) -> Option<Self::DeviceId> {
-        self.uninstantiable_unreachable()
-    }
 }
 
 impl<T, BT, C> CoreTimerContext<T, BT> for UninstantiableWrapper<C>
@@ -173,10 +167,12 @@
         self.uninstantiable_unreachable()
     }
 
+    type OtherSendOptions = DefaultSendOptions;
+
     fn to_other_send_options<'a>(
         &self,
         _state: &'a datagram::IpOptions<I, Self::WeakDeviceId, S>,
-    ) -> &'a datagram::SocketHopLimits<I::OtherVersion> {
+    ) -> &'a Self::OtherSendOptions {
         self.uninstantiable_unreachable()
     }
 
@@ -277,10 +273,10 @@
 impl<I: IpLayerIpExt, C, P: DeviceIpSocketHandler<I, C>> DeviceIpSocketHandler<I, C>
     for UninstantiableWrapper<P>
 {
-    fn get_mms<O: SendOptions<I>>(
+    fn get_mms(
         &mut self,
         _ctx: &mut C,
-        _ip_sock: &IpSock<I, Self::WeakDeviceId, O>,
+        _ip_sock: &IpSock<I, Self::WeakDeviceId>,
     ) -> Result<Mms, MmsError> {
         self.uninstantiable_unreachable()
     }
@@ -310,28 +306,28 @@
 }
 
 impl<I: IpExt, C, P: IpSocketHandler<I, C>> IpSocketHandler<I, C> for UninstantiableWrapper<P> {
-    fn new_ip_socket<O>(
+    fn new_ip_socket(
         &mut self,
         _ctx: &mut C,
         _device: Option<EitherDeviceId<&Self::DeviceId, &Self::WeakDeviceId>>,
         _local_ip: Option<SocketIpAddr<I::Addr>>,
         _remote_ip: SocketIpAddr<I::Addr>,
         _proto: I::Proto,
-        _options: O,
-    ) -> Result<IpSock<I, Self::WeakDeviceId, O>, (IpSockCreationError, O)> {
+    ) -> Result<IpSock<I, Self::WeakDeviceId>, IpSockCreationError> {
         self.uninstantiable_unreachable()
     }
     fn send_ip_packet<S, O>(
         &mut self,
         _ctx: &mut C,
-        _socket: &IpSock<I, Self::WeakDeviceId, O>,
+        _socket: &IpSock<I, Self::WeakDeviceId>,
         _body: S,
         _mtu: Option<u32>,
+        _options: &O,
     ) -> Result<(), (S, IpSockSendError)>
     where
         S: Serializer,
         S::Buffer: BufferMut,
-        O: SendOptions<I>,
+        O: SendOptions<I, Self::WeakDeviceId>,
     {
         self.uninstantiable_unreachable()
     }
diff --git a/src/connectivity/network/netstack3/core/sync/src/rc.rs b/src/connectivity/network/netstack3/core/sync/src/rc.rs
index 3fe9527..83ad94a 100644
--- a/src/connectivity/network/netstack3/core/sync/src/rc.rs
+++ b/src/connectivity/network/netstack3/core/sync/src/rc.rs
@@ -116,6 +116,62 @@
     }
 }
 
+mod debug_id {
+    use core::sync::atomic::{AtomicU64, Ordering};
+
+    /// An opaque token to be used for debugging.
+    ///
+    /// The [`Debug`] implementation is guaranteed to produce a unique
+    /// representation for all instances of [`DebugToken`]. When paired with the
+    /// various RC types exposed in the parent module, this ensures that each
+    /// underlying value can be differentiated from one another. This is an
+    /// improvement over, say, using the underlying value's address, which may
+    /// be reused when the underlying value has been dropped.
+    #[derive(Clone)]
+    pub(super) struct DebugToken(u64);
+
+    impl core::fmt::Debug for DebugToken {
+        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
+            let DebugToken(inner) = self;
+            write!(f, "{}", inner)
+        }
+    }
+
+    impl Default for DebugToken {
+        fn default() -> Self {
+            static NEXT_TOKEN: AtomicU64 = AtomicU64::new(0);
+            // NB: Fetch add will cause the counter to rollback to 0 if we
+            // happen to exceed `u64::MAX` instantiations. In practice, that's
+            // an impossibility (at 1 billion instantiations per second, the
+            // counter is valid for > 500 years). Spare the CPU cycles and don't
+            // bother attempting to detect/handle overflow.
+            DebugToken(NEXT_TOKEN.fetch_add(1, Ordering::Relaxed))
+        }
+    }
+
+    /// A debug identifier for the RC types exposed in the parent module.
+    ///
+    /// Encompasses the underlying pointer for the RC type, as well as
+    /// (optionally) the globally unique [`DebugToken`].
+    pub(super) enum DebugId<T> {
+        /// Used in contexts that have access to the [`DebugToken`], e.g.
+        /// [`Primary`], [`Strong`], and sometimes [`Weak`] RC types.
+        WithToken { ptr: *const T, token: DebugToken },
+        /// Used in contexts that don't have access to the [`DebugToken`], e.g.
+        /// [`Weak`] RC types that cannot be upgraded.
+        WithoutToken { ptr: *const T },
+    }
+
+    impl<T> core::fmt::Debug for DebugId<T> {
+        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
+            match self {
+                DebugId::WithToken { ptr, token } => write!(f, "{:?}:{:?}", token, ptr),
+                DebugId::WithoutToken { ptr } => write!(f, "?:{:?}", ptr),
+            }
+        }
+    }
+}
+
 #[derive(Derivative)]
 #[derivative(Debug)]
 struct Inner<T> {
@@ -127,6 +183,7 @@
     // (i.e. atomicbox) or write unsafe code.
     #[derivative(Debug = "ignore")]
     notifier: crate::Mutex<Option<Box<dyn Notifier<T>>>>,
+    debug_token: debug_id::DebugToken,
 }
 
 impl<T> Inner<T> {
@@ -142,7 +199,8 @@
         // We cannot destructure `self` by value since `Inner` implements
         // `Drop`. So we must manually drop all the fields but data and then
         // forget self.
-        let Inner { marked_for_destruction, data, callers: holders, notifier } = &mut self;
+        let Inner { marked_for_destruction, data, callers: holders, notifier, debug_token } =
+            &mut self;
 
         // Make sure that `inner` is in a valid state for destruction.
         //
@@ -159,6 +217,7 @@
             core::ptr::drop_in_place(marked_for_destruction);
             core::ptr::drop_in_place(holders);
             core::ptr::drop_in_place(notifier);
+            core::ptr::drop_in_place(debug_token);
 
             core::mem::ManuallyDrop::take(data)
         };
@@ -174,7 +233,7 @@
     ///
     /// Panics if notifier is already set.
     fn set_notifier<N: Notifier<T> + 'static>(&self, notifier: N) {
-        let Self { marked_for_destruction: _, callers: _, data: _, notifier: slot } = self;
+        let Self { notifier: slot, .. } = self;
 
         // Using dynamic dispatch to notify allows us to not have to know the
         // notifier that will be used from creation and spread the type on all
@@ -190,7 +249,7 @@
 
 impl<T> Drop for Inner<T> {
     fn drop(&mut self) {
-        let Inner { marked_for_destruction, data, callers: _, notifier } = self;
+        let Inner { marked_for_destruction, data, callers: _, notifier, debug_token: _ } = self;
         // Take data out of ManuallyDrop in case we panic in pre_drop_check.
         // That'll ensure data is dropped if we hit the panic.
         //
@@ -234,7 +293,8 @@
         if !std::thread::panicking() {
             assert_eq!(was_marked, false, "Must not be marked for destruction yet");
 
-            let Inner { marked_for_destruction: _, callers, data: _, notifier: _ } = &*inner;
+            let Inner { marked_for_destruction: _, callers, data: _, notifier: _, debug_token: _ } =
+                &*inner;
 
             // Make sure that this `Primary` is the last thing to hold a strong
             // reference to the underlying data when it is being dropped.
@@ -259,7 +319,8 @@
 
     fn deref(&self) -> &T {
         let Self { inner } = self;
-        let Inner { marked_for_destruction: _, data, callers: _, notifier: _ } = &***inner;
+        let Inner { marked_for_destruction: _, data, callers: _, notifier: _, debug_token: _ } =
+            &***inner;
         data
     }
 }
@@ -285,6 +346,7 @@
                 callers: caller::Callers::default(),
                 data: core::mem::ManuallyDrop::new(data),
                 notifier: crate::Mutex::new(None),
+                debug_token: debug_id::DebugToken::default(),
             })),
         }
     }
@@ -302,6 +364,7 @@
                 callers: caller::Callers::default(),
                 data: core::mem::ManuallyDrop::new(data_fn(Weak(weak.clone()))),
                 notifier: crate::Mutex::new(None),
+                debug_token: debug_id::DebugToken::default(),
             })),
         }
     }
@@ -309,7 +372,8 @@
     /// Clones a strongly-held reference.
     #[cfg_attr(feature = "rc-debug-names", track_caller)]
     pub fn clone_strong(Self { inner }: &Self) -> Strong<T> {
-        let Inner { data: _, callers, marked_for_destruction: _, notifier: _ } = &***inner;
+        let Inner { data: _, callers, marked_for_destruction: _, notifier: _, debug_token: _ } =
+            &***inner;
         let caller = callers.insert(Location::caller());
         Strong { inner: alloc::sync::Arc::clone(inner), caller }
     }
@@ -327,10 +391,14 @@
         alloc::sync::Arc::ptr_eq(this, other)
     }
 
-    /// Returns [`core::fmt::Debug`] implementation that prints the pointer
-    /// address of this [`Primary`].
-    pub fn ptr_debug(Self { inner }: &Self) -> impl core::fmt::Debug {
-        alloc::sync::Arc::as_ptr(inner)
+    /// Returns [`core::fmt::Debug`] implementation that is stable and unique
+    /// for the data held behind this [`Primary`].
+    pub fn debug_id(&self) -> impl core::fmt::Debug {
+        let Self { inner } = self;
+        debug_id::DebugId::WithToken {
+            ptr: alloc::sync::Arc::as_ptr(inner),
+            token: inner.debug_token.clone(),
+        }
     }
 
     fn mark_for_destruction_and_take_inner(mut this: Self) -> alloc::sync::Arc<Inner<T>> {
@@ -415,7 +483,8 @@
 impl<T> Drop for Strong<T> {
     fn drop(&mut self) {
         let Self { inner, caller } = self;
-        let Inner { marked_for_destruction: _, callers, data: _, notifier: _ } = &**inner;
+        let Inner { marked_for_destruction: _, callers, data: _, notifier: _, debug_token: _ } =
+            &**inner;
         caller.release(callers);
     }
 }
@@ -431,7 +500,8 @@
 
     fn deref(&self) -> &T {
         let Self { inner, caller: _ } = self;
-        let Inner { marked_for_destruction: _, data, callers: _, notifier: _ } = inner.deref();
+        let Inner { marked_for_destruction: _, data, callers: _, notifier: _, debug_token: _ } =
+            inner.deref();
         data
     }
 }
@@ -455,7 +525,8 @@
     #[cfg_attr(feature = "rc-debug-names", track_caller)]
     fn clone(&self) -> Self {
         let Self { inner, caller: _ } = self;
-        let Inner { data: _, marked_for_destruction: _, callers, notifier: _ } = &**inner;
+        let Inner { data: _, marked_for_destruction: _, callers, notifier: _, debug_token: _ } =
+            &**inner;
         let caller = callers.insert(Location::caller());
         Self { inner: alloc::sync::Arc::clone(inner), caller }
     }
@@ -467,15 +538,20 @@
         Weak(alloc::sync::Arc::downgrade(inner))
     }
 
-    /// Returns [`core::fmt::Debug`] implementation that prints the pointer
-    /// address of this [`Strong`].
-    pub fn ptr_debug(Self { inner, caller: _ }: &Self) -> impl core::fmt::Debug {
-        alloc::sync::Arc::as_ptr(inner)
+    /// Returns [`core::fmt::Debug`] implementation that is stable and unique
+    /// for the data held behind this [`Strong`].
+    pub fn debug_id(&self) -> impl core::fmt::Debug {
+        let Self { inner, caller: _ } = self;
+        debug_id::DebugId::WithToken {
+            ptr: alloc::sync::Arc::as_ptr(inner),
+            token: inner.debug_token.clone(),
+        }
     }
 
     /// Returns true if the inner value has since been marked for destruction.
     pub fn marked_for_destruction(Self { inner, caller: _ }: &Self) -> bool {
-        let Inner { marked_for_destruction, data: _, callers: _, notifier: _ } = inner.as_ref();
+        let Inner { marked_for_destruction, data: _, callers: _, notifier: _, debug_token: _ } =
+            inner.as_ref();
         // `Ordering::Acquire` because we want to synchronize with with the
         // `Ordering::Release` write to `marked_for_destruction` so that all
         // memory writes before the reference was marked for destruction is
@@ -555,11 +631,23 @@
         this.ptr_eq(other)
     }
 
-    /// Returns [`core::fmt::Debug`] implementation that prints the pointer
-    /// address of this [`Weak`].
-    pub fn ptr_debug(&self) -> impl core::fmt::Debug {
-        let Self(this) = self;
-        this.as_ptr()
+    /// Returns [`core::fmt::Debug`] implementation that is stable and unique
+    /// for the data held behind this [`Weak`].
+    pub fn debug_id(&self) -> impl core::fmt::Debug {
+        match self.upgrade() {
+            Some(strong) => {
+                let Strong { inner, caller: _ } = &strong;
+                debug_id::DebugId::WithToken {
+                    ptr: alloc::sync::Arc::as_ptr(&inner),
+                    token: inner.debug_token.clone(),
+                }
+            }
+            None => {
+                let Self(this) = self;
+                // NB: If we can't upgrade the socket, we can't know the token.
+                debug_id::DebugId::WithoutToken { ptr: this.as_ptr() }
+            }
+        }
     }
 
     /// Attempts to upgrade to a [`Strong`].
@@ -569,7 +657,8 @@
     pub fn upgrade(&self) -> Option<Strong<T>> {
         let Self(weak) = self;
         let arc = weak.upgrade()?;
-        let Inner { marked_for_destruction, data: _, callers, notifier: _ } = arc.deref();
+        let Inner { marked_for_destruction, data: _, callers, notifier: _, debug_token: _ } =
+            arc.deref();
 
         // `Ordering::Acquire` because we want to synchronize with with the
         // `Ordering::Release` write to `marked_for_destruction` so that all
@@ -600,7 +689,8 @@
         let mut f = f.debug_struct("DebugReferences");
         if let Some(inner) = inner.upgrade() {
             let strong_count = alloc::sync::Arc::strong_count(&inner);
-            let Inner { marked_for_destruction, callers, data: _, notifier: _ } = &*inner;
+            let Inner { marked_for_destruction, callers, data: _, notifier: _, debug_token: _ } =
+                &*inner;
             f.field("strong_count", &strong_count)
                 .field("marked_for_destruction", marked_for_destruction)
                 .field("callers", callers)
@@ -764,7 +854,8 @@
         let strong3 = weak.upgrade().unwrap();
 
         let Primary { inner } = &primary;
-        let Inner { marked_for_destruction: _, callers, data: _, notifier: _ } = &***inner;
+        let Inner { marked_for_destruction: _, callers, data: _, notifier: _, debug_token: _ } =
+            &***inner;
 
         let strongs = [strong1, strong2, strong3];
         let _: &Location<'_> = strongs.iter().enumerate().fold(here, |prev, (i, cur)| {
@@ -800,7 +891,8 @@
         assert_eq!(strong1.caller.location, strong2.caller.location);
 
         let Primary { inner } = &primary;
-        let Inner { marked_for_destruction: _, callers, data: _, notifier: _ } = &***inner;
+        let Inner { marked_for_destruction: _, callers, data: _, notifier: _, debug_token: _ } =
+            &***inner;
 
         {
             let callers = callers.callers.lock();
@@ -884,4 +976,43 @@
         assert_eq!(strong.value, 2);
         assert!(Primary::ptr_eq(&primary, &strong));
     }
+
+    macro_rules! assert_debug_id_eq {
+        ($id1:expr, $id2:expr) => {
+            assert_eq!(alloc::format!("{:?}", $id1), alloc::format!("{:?}", $id2))
+        };
+    }
+    macro_rules! assert_debug_id_ne {
+        ($id1:expr, $id2:expr) => {
+            assert_ne!(alloc::format!("{:?}", $id1), alloc::format!("{:?}", $id2))
+        };
+    }
+
+    #[test]
+    fn debug_ids_are_stable() {
+        // Verify that transforming a given RC doesn't change it's debug_id.
+        let primary = Primary::new(1);
+        let strong = Primary::clone_strong(&primary);
+        let weak_p = Primary::downgrade(&primary);
+        let weak_s = Strong::downgrade(&strong);
+        let weak_c = weak_p.clone();
+        assert_debug_id_eq!(&primary.debug_id(), &strong.debug_id());
+        assert_debug_id_eq!(&primary.debug_id(), &weak_p.debug_id());
+        assert_debug_id_eq!(&primary.debug_id(), &weak_s.debug_id());
+        assert_debug_id_eq!(&primary.debug_id(), &weak_c.debug_id());
+    }
+
+    #[test]
+    fn debug_ids_are_unique() {
+        // Verify that RCs to different data have different debug_ids.
+        let primary1 = Primary::new(1);
+        let primary2 = Primary::new(1);
+        assert_debug_id_ne!(&primary1.debug_id(), &primary2.debug_id());
+
+        // Verify that dropping an RC does not allow it's debug_id to be reused.
+        let id1 = primary1.debug_id();
+        std::mem::drop(primary1);
+        let primary3 = Primary::new(1);
+        assert_debug_id_ne!(&id1, &primary3.debug_id());
+    }
 }
diff --git a/src/connectivity/network/netstack3/core/tests/BUILD.gn b/src/connectivity/network/netstack3/core/tests/BUILD.gn
index b1fb41b..684e2a8 100644
--- a/src/connectivity/network/netstack3/core/tests/BUILD.gn
+++ b/src/connectivity/network/netstack3/core/tests/BUILD.gn
@@ -30,16 +30,15 @@
   # The loom crate documentation recommends compiling with optimizations since
   # the number of iterations can be large enough to make tests unreasonably
   # slow otherwise.
-  configs += [
-    "//build/config/rust:lto_thin",
-    "//build/config:optimize_default",
-  ]
+  configs += [ "//build/config:optimize_default" ]
+
+  # Add thinlto config if lto variants are not used.
+  if (!is_lto_variant) {
+    configs += [ "//build/config/lto:thinlto" ]
+  }
 }
 
 group("tests") {
   testonly = true
-  deps = []
-  if (!is_coverage) {
-    deps += [ ":netstack3_core_threading_test" ]
-  }
+  deps = [ ":netstack3_core_threading_test" ]
 }
diff --git a/src/connectivity/network/netstack3/core/tests/threading/lib.rs b/src/connectivity/network/netstack3/core/tests/threading/lib.rs
index 3c5bd8b..ae21248 100644
--- a/src/connectivity/network/netstack3/core/tests/threading/lib.rs
+++ b/src/connectivity/network/netstack3/core/tests/threading/lib.rs
@@ -35,6 +35,34 @@
     udp::{UdpPacket, UdpParseArgs},
 };
 
+/// Spawns a loom thread with a safe stack size.
+#[track_caller]
+fn loom_spawn<F, T>(f: F) -> loom::thread::JoinHandle<T>
+where
+    F: FnOnce() -> T + Send + 'static,
+    T: Send + 'static,
+{
+    // Picked to allow all the tests in this file to run safely. We've had
+    // problems in the past with coverage builders using too much stack.
+    const THREAD_STACK_SIZE: usize = 0x10000;
+    loom::thread::Builder::new().stack_size(THREAD_STACK_SIZE).spawn(f).unwrap()
+}
+
+/// A wrapper around loom's base modelling calls.
+///
+/// We use this function directly because it allows us to specify the stack size
+/// of the "main" thread that we're running on by using `loom_spawn`. Otherwise,
+/// loom uses a default value that causes segfaults in some of our tests.
+///
+/// TODO(https://github.com/tokio-rs/loom/issues/345): Remove this when we can
+/// just set our stack size from the model builder.
+fn loom_model<F>(model: loom::model::Builder, f: F)
+where
+    F: Fn() + Copy + Sync + Send + 'static,
+{
+    model.check(move || loom_spawn(f).join().unwrap())
+}
+
 #[test]
 fn packet_socket_change_device_and_protocol_atomic() {
     const DEVICE_MAC: Mac = net_mac!("22:33:44:55:66:77");
@@ -50,7 +78,7 @@
     let first_proto: NonZeroU16 = NonZeroU16::new(EtherType::Ipv4.into()).unwrap();
     let second_proto: NonZeroU16 = NonZeroU16::new(EtherType::Ipv6.into()).unwrap();
 
-    loom::model(move || {
+    loom_model(Default::default(), move || {
         let mut builder = FakeEventDispatcherBuilder::default();
         let dev_indexes =
             [(); 2].map(|()| builder.add_device(UnicastAddr::new(DEVICE_MAC).unwrap()));
@@ -68,7 +96,7 @@
         );
 
         let thread_vars = (ctx.clone(), devs.clone());
-        let deliver = loom::thread::spawn(move || {
+        let deliver = loom_spawn(move || {
             let (mut ctx, devs) = thread_vars;
             let [dev_a, dev_b] = devs;
             for (device_id, ethertype) in [
@@ -86,7 +114,7 @@
 
         let thread_vars = (ctx.clone(), devs[1].clone(), socket.clone());
 
-        let change_device = loom::thread::spawn(move || {
+        let change_device = loom_spawn(move || {
             let (mut ctx, dev, socket) = thread_vars;
             ctx.core_api().device_socket().set_device_and_protocol(
                 &socket,
@@ -246,7 +274,7 @@
     let mut model = loom::model::Builder::new();
     model.preemption_bound = Some(3);
 
-    model.check(move || {
+    loom_model(model, move || {
         let mut builder = FakeEventDispatcherBuilder::default();
         let dev_index = builder.add_device_with_ip(
             UnicastAddr::new(DEVICE_MAC).unwrap(),
@@ -309,7 +337,7 @@
         //  - Queueing of another packet to that neighbor.
 
         let thread_vars = (ctx.clone(), device.clone());
-        let resolve_neighbor = loom::thread::spawn(move || {
+        let resolve_neighbor = loom_spawn(move || {
             let (mut ctx, device_id) = thread_vars;
             ctx.core_api().device::<EthernetLinkDevice>().receive_frame(
                 RecvEthernetFrameMeta { device_id },
@@ -318,7 +346,7 @@
         });
 
         let thread_vars = (ctx.clone(), socket.clone());
-        let queue_packet = loom::thread::spawn(move || {
+        let queue_packet = loom_spawn(move || {
             let (mut ctx, socket) = thread_vars;
             ctx.core_api()
                 .udp()
@@ -366,7 +394,7 @@
 #[ip_test]
 #[netstack3_core::context_ip_bounds(I, FakeBindingsCtx)]
 fn new_incomplete_neighbor_schedule_timer_atomic<I: Ip + TestIpExt>() {
-    loom::model(move || {
+    loom_model(Default::default(), move || {
         let mut builder = FakeEventDispatcherBuilder::default();
         let dev_index = builder.add_device_with_ip(
             UnicastAddr::new(DEVICE_MAC).unwrap(),
@@ -416,7 +444,7 @@
         // will cause a panic.
 
         let thread_vars = (ctx.clone(), socket.clone());
-        let create_incomplete_neighbor = loom::thread::spawn(move || {
+        let create_incomplete_neighbor = loom_spawn(move || {
             let (mut ctx, socket) = thread_vars;
             ctx.core_api()
                 .udp()
@@ -430,7 +458,7 @@
         });
 
         let thread_vars = (ctx.clone(), device.clone());
-        let set_static_neighbor = loom::thread::spawn(move || {
+        let set_static_neighbor = loom_spawn(move || {
             let (mut ctx, device) = thread_vars;
             ctx.core_api()
                 .neighbor::<I, EthernetLinkDevice>()
diff --git a/src/connectivity/network/netstack3/meta/netstack3.shard.cml b/src/connectivity/network/netstack3/meta/netstack3.shard.cml
index e4f41c7..7e1d468 100644
--- a/src/connectivity/network/netstack3/meta/netstack3.shard.cml
+++ b/src/connectivity/network/netstack3/meta/netstack3.shard.cml
@@ -13,12 +13,18 @@
     },
     capabilities: [
         {
-            protocol: [ "fuchsia.net.filter.State" ],
+            protocol: [
+                "fuchsia.net.filter.Control",
+                "fuchsia.net.filter.State",
+            ],
         },
     ],
     expose: [
         {
-            protocol: [ "fuchsia.net.filter.State" ],
+            protocol: [
+                "fuchsia.net.filter.Control",
+                "fuchsia.net.filter.State",
+            ],
             from: "self",
         },
     ],
diff --git a/src/connectivity/network/netstack3/src/bindings.rs b/src/connectivity/network/netstack3/src/bindings.rs
index b73856d..2fd72e1 100644
--- a/src/connectivity/network/netstack3/src/bindings.rs
+++ b/src/connectivity/network/netstack3/src/bindings.rs
@@ -66,13 +66,9 @@
 use interfaces_watcher::{InterfaceEventProducer, InterfaceProperties, InterfaceUpdate};
 use timers::TimerDispatcher;
 
-use net_declare::net_subnet_v4;
 use net_types::{
     ethernet::Mac,
-    ip::{
-        AddrSubnet, AddrSubnetEither, Ip, IpAddr, IpAddress, IpVersion, Ipv4, Ipv4Addr, Ipv6, Mtu,
-        Subnet,
-    },
+    ip::{AddrSubnet, AddrSubnetEither, Ip, IpAddr, IpAddress, IpVersion, Ipv4, Ipv6, Mtu},
     SpecifiedAddr,
 };
 use netstack3_core::{
@@ -263,14 +259,6 @@
 /// ```
 const DEFAULT_LOOPBACK_MTU: Mtu = Mtu::new(65536);
 
-/// Subnet for the IPv4 Limited Broadcast Address.
-const IPV4_LIMITED_BROADCAST_SUBNET: Subnet<Ipv4Addr> = net_subnet_v4!("255.255.255.255/32");
-
-/// The default "Low Priority" metric to use for default routes.
-///
-/// The value is currently kept in sync with the Netstack2 implementation.
-const DEFAULT_LOW_PRIORITY_METRIC: u32 = 99999;
-
 /// Default routing metric for newly created interfaces, if unspecified.
 ///
 /// The value is currently kept in sync with the Netstack2 implementation.
@@ -885,11 +873,6 @@
             loopback.downgrade(),
             AddableMetric::MetricTracksInterface,
         ),
-        AddableEntry::without_gateway(
-            IPV4_LIMITED_BROADCAST_SUBNET,
-            loopback.downgrade(),
-            AddableMetric::ExplicitMetric(RawMetric(DEFAULT_LOW_PRIORITY_METRIC)),
-        ),
     ]
     .into_iter()
     .map(|entry| {
@@ -1082,7 +1065,6 @@
     DebugInterfaces(fidl_fuchsia_net_debug::InterfacesRequestStream),
     FilterControl(fidl_fuchsia_net_filter::ControlRequestStream),
     FilterState(fidl_fuchsia_net_filter::StateRequestStream),
-    FilterDeprecated(fidl_fuchsia_net_filter_deprecated::FilterRequestStream),
     Interfaces(fidl_fuchsia_net_interfaces::StateRequestStream),
     InterfacesAdmin(fidl_fuchsia_net_interfaces_admin::InstallerRequestStream),
     NeighborController(fidl_fuchsia_net_neighbor::ControllerRequestStream),
@@ -1272,7 +1254,12 @@
             let counters = inspector.root().create_lazy_child("Counters", move || {
                 futures::future::ok(inspect::counters(&mut counters_ctx.clone())).boxed()
             });
-            (health, sockets, routes, devices, neighbors, counters)
+            let filter_ctx = netstack.ctx.clone();
+            let filtering_state =
+                inspector.root().create_lazy_child("Filtering State", move || {
+                    futures::future::ok(inspect::filtering_state(&mut filter_ctx.clone())).boxed()
+                });
+            (health, sockets, routes, devices, neighbors, counters, filtering_state)
         };
 
         let diagnostics_handler = debug_fidl_worker::DiagnosticsHandler::default();
@@ -1465,9 +1452,6 @@
                                 })
                                 .await
                         }
-                        Service::FilterDeprecated(filter) => {
-                            filter.serve_with(|rs| filter::serve_deprecated(rs)).await
-                        }
                         Service::Neighbor(neighbor) => {
                             neighbor
                                 .serve_with(|rs| {
diff --git a/src/connectivity/network/netstack3/src/bindings/filter.rs b/src/connectivity/network/netstack3/src/bindings/filter.rs
index 2b116a0..0301468 100644
--- a/src/connectivity/network/netstack3/src/bindings/filter.rs
+++ b/src/connectivity/network/netstack3/src/bindings/filter.rs
@@ -510,66 +510,3 @@
     }
     Ok(())
 }
-
-// TODO(https://fxbug.dev/42182576): remove this once NetCfg interacts with
-// fuchsia.net.filter for Netstack3.
-pub(crate) async fn serve_deprecated(
-    stream: fidl_fuchsia_net_filter_deprecated::FilterRequestStream,
-) -> Result<(), fidl::Error> {
-    use fidl_fuchsia_net_filter_deprecated::FilterRequest;
-
-    stream
-        .try_for_each(|request: FilterRequest| async move {
-            match request {
-                FilterRequest::DisableInterface { responder, .. } => {
-                    error!(
-                        "fuchsia.net.filter.deprecated.Filter is not implemented \
-                           (https://fxbug.dev/42182576); ignoring DisableInterface"
-                    );
-                    responder.send(Ok(())).unwrap_or_else(|e| error!("failed to respond: {e:?}"));
-                }
-                FilterRequest::EnableInterface { responder, .. } => {
-                    error!(
-                        "fuchsia.net.filter.deprecated.Filter is not implemented \
-                           (https://fxbug.dev/42182576); ignoring EnableInterface"
-                    );
-                    responder.send(Ok(())).unwrap_or_else(|e| error!("failed to respond: {e:?}"));
-                }
-                FilterRequest::GetRules { responder } => {
-                    error!(
-                        "fuchsia.net.filter.deprecated.Filter is not implemented \
-                           (https://fxbug.dev/42182576); ignoring GetRules"
-                    );
-                    responder
-                        .send(&[], 0)
-                        .unwrap_or_else(|e| error!("Responder send error: {:?}", e))
-                }
-                FilterRequest::UpdateRules { rules, generation, responder } => {
-                    error!(
-                        "fuchsia.net.filter.deprecated.Filter is not implemented \
-                            (https://fxbug.dev/42182576); ignoring UpdateRules \
-                            {{ generation: {:?}, rules: {:?} }}",
-                        generation, rules
-                    );
-                    responder.send(Ok(())).unwrap_or_else(|e| error!("failed to respond: {e:?}"));
-                }
-                FilterRequest::GetNatRules { .. } => {
-                    todo!("https://fxbug.dev/42182576: implement filtering support");
-                }
-                FilterRequest::UpdateNatRules { .. } => {
-                    todo!("https://fxbug.dev/42182576: implement filtering support");
-                }
-                FilterRequest::GetRdrRules { .. } => {
-                    todo!("https://fxbug.dev/42182576: implement filtering support");
-                }
-                FilterRequest::UpdateRdrRules { .. } => {
-                    todo!("https://fxbug.dev/42182576: implement filtering support");
-                }
-                FilterRequest::CheckPresence { responder } => {
-                    responder.send().unwrap_or_else(|e| error!("failed to respond: {e:?}"));
-                }
-            };
-            Ok(())
-        })
-        .await
-}
diff --git a/src/connectivity/network/netstack3/src/bindings/filter/controller.rs b/src/connectivity/network/netstack3/src/bindings/filter/controller.rs
index f02edfd..6c644ca 100644
--- a/src/connectivity/network/netstack3/src/bindings/filter/controller.rs
+++ b/src/connectivity/network/netstack3/src/bindings/filter/controller.rs
@@ -24,7 +24,8 @@
 /// same priority, the routine that was installed earlier will be evaluated
 /// first. This atomic counter is incremented on addition of each routine,
 /// giving us a monotonically increasing value we can use to sort routines in
-/// order of installation.
+/// order of installation. It's also useful for providing a unique ID to Core
+/// for each uninstalled routine.
 static ROUTINE_COUNTER: AtomicUsize = AtomicUsize::new(0);
 
 #[derive(Debug, Clone, Derivative)]
@@ -46,9 +47,21 @@
 }
 
 #[derive(Debug, Clone, PartialEq)]
+pub(super) enum IpRoutineType {
+    Installed(InstalledIpRoutine),
+    Uninstalled(usize),
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub(super) enum NatRoutineType {
+    Installed(InstalledNatRoutine),
+    Uninstalled(usize),
+}
+
+#[derive(Debug, Clone, PartialEq)]
 pub(super) enum RoutineType {
-    Ip(Option<InstalledIpRoutine>),
-    Nat(Option<InstalledNatRoutine>),
+    Ip(IpRoutineType),
+    Nat(NatRoutineType),
 }
 
 impl RoutineType {
@@ -56,8 +69,10 @@
         // The `InstalledIpRoutine` or `InstalledNatRoutine` configuration is
         // optional, and when omitted, signifies an uninstalled routine.
         match self {
-            Self::Ip(Some(_)) | Self::Nat(Some(_)) => true,
-            Self::Ip(None) | Self::Nat(None) => false,
+            Self::Ip(IpRoutineType::Installed(_)) | Self::Nat(NatRoutineType::Installed(_)) => true,
+            Self::Ip(IpRoutineType::Uninstalled(_)) | Self::Nat(NatRoutineType::Uninstalled(_)) => {
+                false
+            }
         }
     }
 }
@@ -65,18 +80,24 @@
 impl From<fnet_filter_ext::RoutineType> for RoutineType {
     fn from(routine_type: fnet_filter_ext::RoutineType) -> Self {
         match routine_type {
-            fnet_filter_ext::RoutineType::Ip(installation) => Self::Ip(installation.map(
-                |fnet_filter_ext::InstalledIpRoutine { hook, priority }| InstalledIpRoutine {
-                    hook,
-                    priority,
-                    installation_order: ROUTINE_COUNTER.fetch_add(1, Ordering::SeqCst),
+            fnet_filter_ext::RoutineType::Ip(installation) => Self::Ip(installation.map_or(
+                IpRoutineType::Uninstalled(ROUTINE_COUNTER.fetch_add(1, Ordering::Relaxed)),
+                |fnet_filter_ext::InstalledIpRoutine { hook, priority }| {
+                    IpRoutineType::Installed(InstalledIpRoutine {
+                        hook,
+                        priority,
+                        installation_order: ROUTINE_COUNTER.fetch_add(1, Ordering::Relaxed),
+                    })
                 },
             )),
-            fnet_filter_ext::RoutineType::Nat(installation) => Self::Nat(installation.map(
-                |fnet_filter_ext::InstalledNatRoutine { hook, priority }| InstalledNatRoutine {
-                    hook,
-                    priority,
-                    installation_order: ROUTINE_COUNTER.fetch_add(1, Ordering::SeqCst),
+            fnet_filter_ext::RoutineType::Nat(installation) => Self::Nat(installation.map_or(
+                NatRoutineType::Uninstalled(ROUTINE_COUNTER.fetch_add(1, Ordering::Relaxed)),
+                |fnet_filter_ext::InstalledNatRoutine { hook, priority }| {
+                    NatRoutineType::Installed(InstalledNatRoutine {
+                        hook,
+                        priority,
+                        installation_order: ROUTINE_COUNTER.fetch_add(1, Ordering::Relaxed),
+                    })
                 },
             )),
         }
@@ -86,16 +107,26 @@
 impl From<&RoutineType> for fnet_filter_ext::RoutineType {
     fn from(routine_type: &RoutineType) -> Self {
         match routine_type {
-            RoutineType::Ip(installation) => Self::Ip(installation.as_ref().map(
-                |InstalledIpRoutine { hook, priority, installation_order: _ }| {
-                    fnet_filter_ext::InstalledIpRoutine { hook: *hook, priority: *priority }
-                },
-            )),
-            RoutineType::Nat(installation) => Self::Nat(installation.as_ref().map(
-                |InstalledNatRoutine { hook, priority, installation_order: _ }| {
-                    fnet_filter_ext::InstalledNatRoutine { hook: *hook, priority: *priority }
-                },
-            )),
+            RoutineType::Ip(routine_type) => Self::Ip(match routine_type {
+                IpRoutineType::Uninstalled(_) => None,
+                IpRoutineType::Installed(InstalledIpRoutine {
+                    hook,
+                    priority,
+                    installation_order: _,
+                }) => {
+                    Some(fnet_filter_ext::InstalledIpRoutine { hook: *hook, priority: *priority })
+                }
+            }),
+            RoutineType::Nat(routine_type) => Self::Nat(match routine_type {
+                NatRoutineType::Uninstalled(_) => None,
+                NatRoutineType::Installed(InstalledNatRoutine {
+                    hook,
+                    priority,
+                    installation_order: _,
+                }) => {
+                    Some(fnet_filter_ext::InstalledNatRoutine { hook: *hook, priority: *priority })
+                }
+            }),
         }
     }
 }
diff --git a/src/connectivity/network/netstack3/src/bindings/filter/conversion.rs b/src/connectivity/network/netstack3/src/bindings/filter/conversion.rs
index b8c6bbd..08cb62d 100644
--- a/src/connectivity/network/netstack3/src/bindings/filter/conversion.rs
+++ b/src/connectivity/network/netstack3/src/bindings/filter/conversion.rs
@@ -13,7 +13,10 @@
 use packet_formats::ip::IpExt;
 
 use crate::bindings::filter::{
-    controller::{InstalledIpRoutine, InstalledNatRoutine, Namespace, Routine, Rule},
+    controller::{
+        InstalledIpRoutine, InstalledNatRoutine, IpRoutineType, Namespace, NatRoutineType, Routine,
+        Rule,
+    },
     CommitError,
 };
 use matchers::{ConversionResult, IpVersionMismatchError, TryConvertToCoreState as _};
@@ -317,7 +320,7 @@
         //
         // (NB: by this point, `Jump` targets have already been validated to refer
         // to existing uninstalled routines.)
-        let UninstalledRoutine { routine_type, rules } =
+        let UninstalledRoutine { routine_type, rules, id } =
             uninstalled_routines.remove(name).ok_or_else(|| {
                 CommitError::CyclicalRoutineGraph(fnet_filter_ext::RoutineId {
                     namespace: namespace.to_owned(),
@@ -348,7 +351,7 @@
         )?;
 
         // Insert the resulting converted routine in the `core_uninstalled` state.
-        let target = CoreUninstalledRoutine::new(rules);
+        let target = CoreUninstalledRoutine::new(rules, id);
         let uninstalled = match routine_type {
             RoutineType::Ip => &mut self.ip,
             RoutineType::Nat => &mut self.nat,
@@ -410,6 +413,7 @@
 struct UninstalledRoutine {
     routine_type: RoutineType,
     rules: BTreeMap<u32, Rule>,
+    id: usize,
 }
 
 /// Converts a controller's state to the equivalent `netstack3_core` state.
@@ -430,38 +434,38 @@
             |(mut installed, mut uninstalled), (name, routine)| {
                 let Routine { routine_type, rules } = routine;
                 match routine_type {
-                    super::controller::RoutineType::Ip(None) => {
+                    super::controller::RoutineType::Ip(IpRoutineType::Uninstalled(id)) => {
                         assert_matches!(
                             uninstalled.insert(
                                 name,
-                                UninstalledRoutine { routine_type: RoutineType::Ip, rules },
+                                UninstalledRoutine { routine_type: RoutineType::Ip, rules, id },
                             ),
                             None
                         );
                     }
-                    super::controller::RoutineType::Nat(None) => {
+                    super::controller::RoutineType::Nat(NatRoutineType::Uninstalled(id)) => {
                         assert_matches!(
                             uninstalled.insert(
                                 name,
-                                UninstalledRoutine { routine_type: RoutineType::Nat, rules },
+                                UninstalledRoutine { routine_type: RoutineType::Nat, rules, id },
                             ),
                             None
                         );
                     }
-                    super::controller::RoutineType::Ip(Some(installation)) => {
+                    super::controller::RoutineType::Ip(IpRoutineType::Installed(installation)) => {
                         installed.push(InstalledRoutine {
                             name,
                             routine_type: InstalledRoutineType::Ip(installation),
                             rules,
                         })
                     }
-                    super::controller::RoutineType::Nat(Some(installation)) => {
-                        installed.push(InstalledRoutine {
-                            name,
-                            routine_type: InstalledRoutineType::Nat(installation),
-                            rules,
-                        })
-                    }
+                    super::controller::RoutineType::Nat(NatRoutineType::Installed(
+                        installation,
+                    )) => installed.push(InstalledRoutine {
+                        name,
+                        routine_type: InstalledRoutineType::Nat(installation),
+                        rules,
+                    }),
                 }
                 (installed, uninstalled)
             },
diff --git a/src/connectivity/network/netstack3/src/bindings/inspect.rs b/src/connectivity/network/netstack3/src/bindings/inspect.rs
index a95f0cc..c3880de 100644
--- a/src/connectivity/network/netstack3/src/bindings/inspect.rs
+++ b/src/connectivity/network/netstack3/src/bindings/inspect.rs
@@ -236,3 +236,9 @@
     ctx.api().counters().inspect_stack_counters(&mut BindingsInspector::new(inspector.root()));
     inspector
 }
+
+pub(crate) fn filtering_state(ctx: &mut Ctx) -> fuchsia_inspect::Inspector {
+    let inspector = fuchsia_inspect::Inspector::new(Default::default());
+    ctx.api().filter().inspect_state(&mut BindingsInspector::new(inspector.root()));
+    inspector
+}
diff --git a/src/connectivity/network/netstack3/src/bindings/integration_tests.rs b/src/connectivity/network/netstack3/src/bindings/integration_tests.rs
index e2daa74..8cf65c2 100644
--- a/src/connectivity/network/netstack3/src/bindings/integration_tests.rs
+++ b/src/connectivity/network/netstack3/src/bindings/integration_tests.rs
@@ -139,7 +139,6 @@
 
 impl_service_marker!(fidl_fuchsia_net_debug::DiagnosticsMarker, DebugDiagnostics, server_end);
 impl_service_marker!(fidl_fuchsia_net_debug::InterfacesMarker, DebugInterfaces);
-impl_service_marker!(fidl_fuchsia_net_filter_deprecated::FilterMarker, FilterDeprecated);
 impl_service_marker!(fidl_fuchsia_net_interfaces::StateMarker, Interfaces);
 impl_service_marker!(fidl_fuchsia_net_interfaces_admin::InstallerMarker, InterfacesAdmin);
 impl_service_marker!(fidl_fuchsia_net_neighbor::ViewMarker, Neighbor);
@@ -776,19 +775,6 @@
     };
 
     let expected_routes = [
-        // Automatically installed routes
-        fidl_net_stack::ForwardingEntry {
-            subnet: crate::bindings::IPV4_LIMITED_BROADCAST_SUBNET.into_ext(),
-            device_id: loopback_id.get(),
-            next_hop: None,
-            metric: crate::bindings::DEFAULT_LOW_PRIORITY_METRIC,
-        },
-        fidl_net_stack::ForwardingEntry {
-            subnet: crate::bindings::IPV4_LIMITED_BROADCAST_SUBNET.into_ext(),
-            device_id: if_id.get(),
-            next_hop: None,
-            metric: crate::bindings::DEFAULT_LOW_PRIORITY_METRIC,
-        },
         // route1
         route1_fwd_entry.clone(),
         // route2
diff --git a/src/connectivity/network/netstack3/src/bindings/netdevice_worker.rs b/src/connectivity/network/netstack3/src/bindings/netdevice_worker.rs
index 2ff6bd1..b93b559 100644
--- a/src/connectivity/network/netstack3/src/bindings/netdevice_worker.rs
+++ b/src/connectivity/network/netstack3/src/bindings/netdevice_worker.rs
@@ -708,8 +708,8 @@
     Ok((mac_addr, mac_proxy))
 }
 
-/// Adds the IPv4 and IPv6 multicast subnet routes, the IPv6 link-local subnet
-/// route, and the IPv4 limited broadcast subnet route.
+/// Adds the IPv4 and IPv6 multicast subnet routes and the IPv6 link-local
+/// subnet route.
 ///
 /// Note that if an error is encountered while installing a route, any routes
 /// that were successfully installed prior to the error will not be removed.
@@ -717,19 +717,11 @@
     use netstack3_core::routes::{AddableEntry, AddableMetric};
     const LINK_LOCAL_SUBNET: Subnet<Ipv6Addr> = net_declare::net_subnet_v6!("fe80::/64");
 
-    let v4_changes = [
-        AddableEntry::without_gateway(
-            Ipv4::MULTICAST_SUBNET,
-            device.downgrade(),
-            AddableMetric::MetricTracksInterface,
-        ),
-        AddableEntry::without_gateway(
-            crate::bindings::IPV4_LIMITED_BROADCAST_SUBNET,
-            device.downgrade(),
-            AddableMetric::ExplicitMetric(RawMetric(crate::bindings::DEFAULT_LOW_PRIORITY_METRIC)),
-        ),
-    ]
-    .into_iter()
+    let v4_changes = std::iter::once(AddableEntry::without_gateway(
+        Ipv4::MULTICAST_SUBNET,
+        device.downgrade(),
+        AddableMetric::MetricTracksInterface,
+    ))
     .map(|entry| {
         routes::Change::RouteOp(
             routes::RouteOp::Add(entry),
diff --git a/src/connectivity/network/netstack3/src/main.rs b/src/connectivity/network/netstack3/src/main.rs
index 65a8c60..1f538d7 100644
--- a/src/connectivity/network/netstack3/src/main.rs
+++ b/src/connectivity/network/netstack3/src/main.rs
@@ -69,7 +69,6 @@
         .add_fidl_service(Service::InterfacesAdmin)
         .add_fidl_service(Service::FilterState)
         .add_fidl_service(Service::FilterControl)
-        .add_fidl_service(Service::FilterDeprecated)
         .add_fidl_service(Service::Neighbor)
         .add_fidl_service(Service::NeighborController)
         .add_fidl_service(Service::Verifier);
diff --git a/src/connectivity/network/testing/conformance/BUILD.gn b/src/connectivity/network/testing/conformance/BUILD.gn
index c1777a3..5d7765f 100644
--- a/src/connectivity/network/testing/conformance/BUILD.gn
+++ b/src/connectivity/network/testing/conformance/BUILD.gn
@@ -5,7 +5,6 @@
 group("tests") {
   testonly = true
   deps = [
-    "emulator:tests",
     "expect:tests",
     "expectation:tests",
     "parseoutput:tests",
diff --git a/src/connectivity/network/testing/conformance/emulator/BUILD.gn b/src/connectivity/network/testing/conformance/emulator/BUILD.gn
index fe77f71..280bd27 100644
--- a/src/connectivity/network/testing/conformance/emulator/BUILD.gn
+++ b/src/connectivity/network/testing/conformance/emulator/BUILD.gn
@@ -59,7 +59,7 @@
   }
 }
 
-group("tests") {
+group("e2e_tests") {
   if (host_os == "linux" && has_board) {
     deps = [ ":conformance_emulator_test($host_toolchain)" ]
   }
diff --git a/src/connectivity/network/testing/conformance/expectation/tcpcore.go b/src/connectivity/network/testing/conformance/expectation/tcpcore.go
index e8ccefc..925f40f 100644
--- a/src/connectivity/network/testing/conformance/expectation/tcpcore.go
+++ b/src/connectivity/network/testing/conformance/expectation/tcpcore.go
@@ -349,7 +349,7 @@
 	{20, 19}: Pass,
 	{20, 20}: Pass,
 	{23, 1}:  Pass,
-	{23, 2}:  Fail,
+	{23, 2}:  Pass,
 	{23, 3}:  Pass,
 	{23, 4}:  Pass,
 	{23, 5}:  Pass,
diff --git a/src/connectivity/network/testing/netemul/rust/BUILD.gn b/src/connectivity/network/testing/netemul/rust/BUILD.gn
index 73a821c..5e73a72 100644
--- a/src/connectivity/network/testing/netemul/rust/BUILD.gn
+++ b/src/connectivity/network/testing/netemul/rust/BUILD.gn
@@ -19,6 +19,7 @@
     "//sdk/fidl/fuchsia.net.interfaces:fuchsia.net.interfaces_rust",
     "//sdk/fidl/fuchsia.net.interfaces.admin:fuchsia.net.interfaces.admin_rust",
     "//sdk/fidl/fuchsia.net.neighbor:fuchsia.net.neighbor_rust",
+    "//sdk/fidl/fuchsia.net.root:fuchsia.net.root_rust",
     "//sdk/fidl/fuchsia.net.routes.admin:fuchsia.net.routes.admin_rust",
     "//sdk/fidl/fuchsia.net.stack:fuchsia.net.stack_rust",
     "//sdk/fidl/fuchsia.posix.socket:fuchsia.posix.socket_rust",
@@ -38,6 +39,7 @@
     "//src/lib/network/fidl_fuchsia_net_dhcp_ext",
     "//src/lib/network/fidl_fuchsia_net_ext",
     "//src/lib/network/fidl_fuchsia_net_interfaces_ext",
+    "//src/lib/network/fidl_fuchsia_net_routes_ext",
     "//src/lib/network/fidl_fuchsia_posix_socket_ext",
     "//src/lib/zircon/rust:fuchsia-zircon",
     "//src/virtualization/lib/guest_interaction:fuchsia.virtualization.guest.interaction_rust",
diff --git a/src/connectivity/network/testing/netemul/rust/src/lib.rs b/src/connectivity/network/testing/netemul/rust/src/lib.rs
index 23da183..939c66b 100644
--- a/src/connectivity/network/testing/netemul/rust/src/lib.rs
+++ b/src/connectivity/network/testing/netemul/rust/src/lib.rs
@@ -11,6 +11,7 @@
 
 use std::{borrow::Cow, num::NonZeroU64, ops::DerefMut as _, path::Path, pin::pin};
 
+use fidl::endpoints::ProtocolMarker;
 use fidl_fuchsia_hardware_network as fnetwork;
 use fidl_fuchsia_io as fio;
 use fidl_fuchsia_net as fnet;
@@ -21,7 +22,9 @@
 use fidl_fuchsia_net_interfaces_admin as fnet_interfaces_admin;
 use fidl_fuchsia_net_interfaces_ext as fnet_interfaces_ext;
 use fidl_fuchsia_net_neighbor as fnet_neighbor;
+use fidl_fuchsia_net_root as fnet_root;
 use fidl_fuchsia_net_routes_admin as fnet_routes_admin;
+use fidl_fuchsia_net_routes_ext as fnet_routes_ext;
 use fidl_fuchsia_net_stack as fnet_stack;
 use fidl_fuchsia_net_stack_ext::FidlReturn as _;
 use fidl_fuchsia_netemul as fnetemul;
@@ -35,10 +38,11 @@
 
 use anyhow::{anyhow, Context as _};
 use futures::{
-    future::{FutureExt as _, TryFutureExt as _},
+    future::{FutureExt as _, LocalBoxFuture, TryFutureExt as _},
     SinkExt as _, StreamExt as _, TryStreamExt as _,
 };
 use net_declare::fidl_subnet;
+use net_types::ip::{GenericOverIp, Ip, IpInvariant};
 
 type Result<T = ()> = std::result::Result<T, anyhow::Error>;
 
@@ -1104,6 +1108,71 @@
             })
     }
 
+    /// Create a root route set authenticated to manage routes through this interface.
+    pub async fn create_authenticated_global_route_set<
+        I: fnet_routes_ext::FidlRouteIpExt + fnet_routes_ext::admin::FidlRouteAdminIpExt,
+    >(
+        &self,
+    ) -> Result<<I::RouteSetMarker as ProtocolMarker>::Proxy> {
+        #[derive(GenericOverIp)]
+        #[generic_over_ip(I, Ip)]
+        struct Out<'a, I: fnet_routes_ext::admin::FidlRouteAdminIpExt>(
+            LocalBoxFuture<'a, <I::RouteSetMarker as ProtocolMarker>::Proxy>,
+        );
+
+        let Out(proxy_fut) = I::map_ip::<_, Out<'_, _>>(
+            IpInvariant(self),
+            |IpInvariant(this)| {
+                Out(this
+                    .get_global_route_set_v4()
+                    .map(|result| result.expect("get global route set"))
+                    .boxed_local())
+            },
+            |IpInvariant(this)| {
+                Out(this
+                    .get_global_route_set_v6()
+                    .map(|result| result.expect("get global route set"))
+                    .boxed_local())
+            },
+        );
+
+        let route_set = proxy_fut.await;
+        let fnet_interfaces_admin::GrantForInterfaceAuthorization { interface_id, token } =
+            self.get_authorization().await.expect("get interface grant");
+        fnet_routes_ext::admin::authenticate_for_interface::<I>(
+            &route_set,
+            fnet_interfaces_admin::ProofOfInterfaceAuthorization { interface_id, token },
+        )
+        .await
+        .expect("authentication should not have FIDL error")
+        .expect("authentication should succeed");
+        Ok(route_set)
+    }
+
+    async fn get_global_route_set_v4(&self) -> Result<fnet_routes_admin::RouteSetV4Proxy> {
+        let root_routes = self
+            .realm
+            .connect_to_protocol::<fnet_root::RoutesV4Marker>()
+            .expect("get fuchsia.net.root.RoutesV4");
+        let (route_set, server_end) =
+            fidl::endpoints::create_proxy::<fnet_routes_admin::RouteSetV4Marker>()
+                .expect("creating route set proxy should succeed");
+        root_routes.global_route_set(server_end).expect("calling global_route_set should succeed");
+        Ok(route_set)
+    }
+
+    async fn get_global_route_set_v6(&self) -> Result<fnet_routes_admin::RouteSetV6Proxy> {
+        let root_routes = self
+            .realm
+            .connect_to_protocol::<fnet_root::RoutesV6Marker>()
+            .expect("get fuchsia.net.root.RoutesV6");
+        let (route_set, server_end) =
+            fidl::endpoints::create_proxy::<fnet_routes_admin::RouteSetV6Marker>()
+                .expect("creating route set proxy should succeed");
+        root_routes.global_route_set(server_end).expect("calling global_route_set should succeed");
+        Ok(route_set)
+    }
+
     /// Gets the interface's properties with assigned addresses.
     async fn get_properties(
         &self,
diff --git a/src/connectivity/network/tests/delegated-provisioning/src/bootstrap_dhcpd.rs b/src/connectivity/network/tests/delegated-provisioning/src/bootstrap_dhcpd.rs
index 89cff2a..d2efa2e 100644
--- a/src/connectivity/network/tests/delegated-provisioning/src/bootstrap_dhcpd.rs
+++ b/src/connectivity/network/tests/delegated-provisioning/src/bootstrap_dhcpd.rs
@@ -50,6 +50,12 @@
     }
 
     dhcp_server
+        .set_option(&fnet_dhcp::Option_::Router(vec![constants::SERVER_STATIC_IP]))
+        .await
+        .expect("failed to call fnet_dhcp::Server::set_option")
+        .expect("failed to set option");
+
+    dhcp_server
         .start_serving()
         .await
         .expect("failed to call fnet_dhcp::Server::start")
diff --git a/src/connectivity/network/tests/fidl/routes/src/lib.rs b/src/connectivity/network/tests/fidl/routes/src/lib.rs
index d86621fa3..4d4c5bf 100644
--- a/src/connectivity/network/tests/fidl/routes/src/lib.rs
+++ b/src/connectivity/network/tests/fidl/routes/src/lib.rs
@@ -414,6 +414,7 @@
 }
 
 // Asserts that two vectors contain the same entries, order independent.
+#[track_caller]
 fn assert_eq_unordered<T: Debug + Eq + Hash + PartialEq>(a: Vec<T>, b: Vec<T>) {
     // Converts a `Vec<T>` into a `HashMap` where the key is `T` and the value
     // is the count of occurrences of `T` in the vec.
@@ -429,26 +430,17 @@
 // Default metric values used by the netstack when creating implicit routes.
 // See `src/connectivity/network/netstack/netstack.go`.
 const DEFAULT_INTERFACE_METRIC: u32 = 100;
-const DEFAULT_LOW_PRIORITY_METRIC: u32 = 99999;
 
 // The initial IPv4 routes that are installed on the loopback interface.
 fn initial_loopback_routes_v4<N: Netstack>(
     loopback_id: u64,
 ) -> impl Iterator<Item = fnet_routes_ext::InstalledRoute<Ipv4>> {
-    [
-        new_installed_route(
-            net_subnet_v4!("127.0.0.0/8"),
-            loopback_id,
-            DEFAULT_INTERFACE_METRIC,
-            true,
-        ),
-        new_installed_route(
-            net_subnet_v4!("255.255.255.255/32"),
-            loopback_id,
-            DEFAULT_LOW_PRIORITY_METRIC,
-            false,
-        ),
-    ]
+    [new_installed_route(
+        net_subnet_v4!("127.0.0.0/8"),
+        loopback_id,
+        DEFAULT_INTERFACE_METRIC,
+        true,
+    )]
     .into_iter()
     // TODO(https://fxbug.dev/42074061) Unify the loopback routes between
     // Netstack2 and Netstack3
@@ -493,20 +485,12 @@
 fn initial_ethernet_routes_v4(
     ethernet_id: u64,
 ) -> impl Iterator<Item = fnet_routes_ext::InstalledRoute<Ipv4>> {
-    [
-        new_installed_route(
-            net_subnet_v4!("255.255.255.255/32"),
-            ethernet_id,
-            DEFAULT_LOW_PRIORITY_METRIC,
-            false,
-        ),
-        new_installed_route(
-            net_subnet_v4!("224.0.0.0/4"),
-            ethernet_id,
-            DEFAULT_INTERFACE_METRIC,
-            true,
-        ),
-    ]
+    [new_installed_route(
+        net_subnet_v4!("224.0.0.0/4"),
+        ethernet_id,
+        DEFAULT_INTERFACE_METRIC,
+        true,
+    )]
     .into_iter()
 }
 
diff --git a/src/connectivity/network/tests/integration/BUILD.gn b/src/connectivity/network/tests/integration/BUILD.gn
index f84d020..e4d300e 100644
--- a/src/connectivity/network/tests/integration/BUILD.gn
+++ b/src/connectivity/network/tests/integration/BUILD.gn
@@ -37,15 +37,9 @@
     label = "ipv6"
   },
   {
-    label = "management"
-  },
-  {
     label = "product-flow"
   },
   {
-    label = "reachability"
-  },
-  {
     label = "socket"
   },
 ]
@@ -104,16 +98,9 @@
   "//src/lib/fake-clock/svc",
 
   # netcfg integration with netstack is tested.
-  ":netcfg-netemul-config",
-  ":netcfg-with-dhcpv6-netemul-config",
-  ":netcfg-with-duplicate-names",
-  ":netcfg-with-forwarding-netemul-config",
-  ":netcfg-with-iface-name-prefix",
-  ":netcfg-with-packet-filter-ethernet",
-  ":netcfg-with-packet-filter-wlan",
-  ":netcfg-without-provisioning-netemul-config",
   "//src/connectivity/policy/netcfg:component-advanced",
   "//src/connectivity/policy/netcfg:component-basic",
+  "//src/connectivity/policy/tests/integration:netcfg-netemul-configs",
 ]
 
 # RISC-V on Fuchsia does not support Golang.
@@ -182,54 +169,6 @@
   }
 }
 
-resource("netcfg-netemul-config") {
-  testonly = true
-  sources = [ "management/config/empty.json" ]
-  outputs = [ "netcfg/empty.json" ]
-}
-
-resource("netcfg-with-dhcpv6-netemul-config") {
-  testonly = true
-  sources = [ "management/config/dhcpv6.json" ]
-  outputs = [ "netcfg/dhcpv6.json" ]
-}
-
-resource("netcfg-with-forwarding-netemul-config") {
-  testonly = true
-  sources = [ "management/config/forwarding.json" ]
-  outputs = [ "netcfg/forwarding.json" ]
-}
-
-resource("netcfg-without-provisioning-netemul-config") {
-  testonly = true
-  sources = [ "management/config/all_delegated.json" ]
-  outputs = [ "netcfg/all_delegated.json" ]
-}
-
-resource("netcfg-with-iface-name-prefix") {
-  testonly = true
-  sources = [ "management/config/iface_prefix.json" ]
-  outputs = [ "netcfg/iface_prefix.json" ]
-}
-
-resource("netcfg-with-duplicate-names") {
-  testonly = true
-  sources = [ "management/config/duplicate_names.json" ]
-  outputs = [ "netcfg/duplicate_names.json" ]
-}
-
-resource("netcfg-with-packet-filter-ethernet") {
-  testonly = true
-  sources = [ "management/config/packet_filter_ethernet.json" ]
-  outputs = [ "netcfg/packet_filter_ethernet.json" ]
-}
-
-resource("netcfg-with-packet-filter-wlan") {
-  testonly = true
-  sources = [ "management/config/packet_filter_wlan.json" ]
-  outputs = [ "netcfg/packet_filter_wlan.json" ]
-}
-
 # We keep tests that involve the virtualization stack (and especially guest
 # images) restricted to a separate builder.  See https://fxbug.dev/42073933 for
 # more details.
diff --git a/src/connectivity/network/tests/integration/common/src/ndp.rs b/src/connectivity/network/tests/integration/common/src/ndp.rs
index a1161d6..86f8b11 100644
--- a/src/connectivity/network/tests/integration/common/src/ndp.rs
+++ b/src/connectivity/network/tests/integration/common/src/ndp.rs
@@ -124,7 +124,7 @@
                     _,
                     NeighborSolicitation,
                     _,
-                >(&data, EthernetFrameLengthCheck::Check, |p| {
+                >(&data, EthernetFrameLengthCheck::NoCheck, |p| {
                     assert_eq!(p.body().iter().count(), 0)
                 })
                 .map_or(
diff --git a/src/connectivity/network/tests/integration/common/src/realms.rs b/src/connectivity/network/tests/integration/common/src/realms.rs
index 5aaa4b1..dc6ebd0 100644
--- a/src/connectivity/network/tests/integration/common/src/realms.rs
+++ b/src/connectivity/network/tests/integration/common/src/realms.rs
@@ -71,7 +71,6 @@
         macro_rules! common_services_and {
             ($($name:expr),*) => {[
                 fnet_debug::InterfacesMarker::PROTOCOL_NAME,
-                fnet_filter_deprecated::FilterMarker::PROTOCOL_NAME,
                 fnet_interfaces_admin::InstallerMarker::PROTOCOL_NAME,
                 fnet_interfaces::StateMarker::PROTOCOL_NAME,
                 fnet_name::DnsServerWatcherMarker::PROTOCOL_NAME,
@@ -99,6 +98,7 @@
         match self {
             NetstackVersion::Netstack2 { tracing: _, fast_udp: _ }
             | NetstackVersion::ProdNetstack2 => &common_services_and!(
+                fnet_filter_deprecated::FilterMarker::PROTOCOL_NAME,
                 fnet_multicast_admin::Ipv4RoutingTableControllerMarker::PROTOCOL_NAME,
                 fnet_multicast_admin::Ipv6RoutingTableControllerMarker::PROTOCOL_NAME,
                 fnet_stack::LogMarker::PROTOCOL_NAME,
@@ -401,6 +401,11 @@
                                 [
                                     fnetemul::Capability::LogSink(fnetemul::Empty {}),
                                     fnetemul::Capability::ChildDep(protocol_dep::<
+                                        fnet_filter::ControlMarker,
+                                    >(
+                                        constants::netstack::COMPONENT_NAME,
+                                    )),
+                                    fnetemul::Capability::ChildDep(protocol_dep::<
                                         fnet_filter_deprecated::FilterMarker,
                                     >(
                                         constants::netstack::COMPONENT_NAME,
diff --git a/src/connectivity/network/tests/integration/expects/netstack-reachability-integration-test.json5 b/src/connectivity/network/tests/integration/expects/netstack-reachability-integration-test.json5
deleted file mode 100644
index 004ffc9..0000000
--- a/src/connectivity/network/tests/integration/expects/netstack-reachability-integration-test.json5
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    actions: [
-        {
-            type: "expect_pass",
-            matchers: [
-                "*",
-            ],
-        },
-        {
-            type: "expect_failure_with_err_logs",
-            matchers: [
-                "test_gateway_goes_down_ns3*",
-                "test_internet_available_ns3*",
-                "test_internet_comes_up_ns3*",
-                "test_internet_goes_down_ns3*",
-                "test_internet_to_gateway_state_ns3",
-                "test_state_ns3*",
-            ],
-        },
-    ],
-}
diff --git a/src/connectivity/network/tests/integration/expects/netstack-socket-integration-test.json5 b/src/connectivity/network/tests/integration/expects/netstack-socket-integration-test.json5
index fc8d2ac..b23d6ba 100644
--- a/src/connectivity/network/tests/integration/expects/netstack-socket-integration-test.json5
+++ b/src/connectivity/network/tests/integration/expects/netstack-socket-integration-test.json5
@@ -17,15 +17,16 @@
                 "tcp_socket_shutdown_listener_v6_ns2",
                 "udp_recv_msg_postflight_fidl_ns3*",
                 "udp_send_msg_preflight*ns3*",
-            ],
-        },
-        {
-            type: "expect_failure",
-            matchers: [
+
                 // TODO(https://fxbug.dev/321240038): remove when Netstack3's
                 // SocketMap correctly takes bound devices into account.
                 "tcp_connect_bound_to_device_ns3",
                 "tcp_bind_with_zone_connect_unzoned_ns3",
+
+                // TODO(https://fxbug.dev/42051633): Support Pure IP devices in
+                // Netstack3.
+                "ip_endpoints_socket_ns3_v4::packet_socket",
+                "ip_endpoints_socket_ns3_v6::packet_socket",
             ],
         },
         {
diff --git a/src/connectivity/network/tests/integration/inspect/BUILD.gn b/src/connectivity/network/tests/integration/inspect/BUILD.gn
index 9a65137..0207f44 100644
--- a/src/connectivity/network/tests/integration/inspect/BUILD.gn
+++ b/src/connectivity/network/tests/integration/inspect/BUILD.gn
@@ -50,6 +50,7 @@
   edition = "2021"
   deps = [
     "//sdk/fidl/fuchsia.net:fuchsia.net_rust",
+    "//sdk/fidl/fuchsia.net.filter:fuchsia.net.filter_rust",
     "//sdk/fidl/fuchsia.net.interfaces:fuchsia.net.interfaces_rust",
     "//sdk/fidl/fuchsia.posix.socket:fuchsia.posix.socket_rust",
     "//src/connectivity/lib/net-declare",
@@ -59,6 +60,7 @@
     "//src/connectivity/network/tests/integration/common:netstack_testing_common",
     "//src/connectivity/network/tests/integration/macros:netstack_testing_macros",
     "//src/lib/fuchsia-async",
+    "//src/lib/network/fidl_fuchsia_net_filter_ext",
     "//src/lib/network/fidl_fuchsia_net_interfaces_ext",
     "//third_party/rust_crates:assert_matches",
     "//third_party/rust_crates:libc",
diff --git a/src/connectivity/network/tests/integration/inspect/src/ns2.rs b/src/connectivity/network/tests/integration/inspect/src/ns2.rs
index df3d854..97637d5 100644
--- a/src/connectivity/network/tests/integration/inspect/src/ns2.rs
+++ b/src/connectivity/network/tests/integration/inspect/src/ns2.rs
@@ -393,15 +393,6 @@
         "Dynamic": AnyProperty,
         "Enabled": AnyProperty,
     }));
-    routing_table_assertion.add_child_assertion(tree_assertion!("2": {
-        "Destination": "255.255.255.255/32",
-        "Gateway": "",
-        "NIC": "1",
-        "Metric": "99999",
-        "MetricTracksInterface": "false",
-        "Dynamic": AnyProperty,
-        "Enabled": AnyProperty,
-    }));
 
     let data = get_inspect_data(&diagnostics_dir, "Routes", "routes").await;
     let () = routing_table_assertion
diff --git a/src/connectivity/network/tests/integration/inspect/src/ns3.rs b/src/connectivity/network/tests/integration/inspect/src/ns3.rs
index fef741f..46da6d5 100644
--- a/src/connectivity/network/tests/integration/inspect/src/ns3.rs
+++ b/src/connectivity/network/tests/integration/inspect/src/ns3.rs
@@ -6,9 +6,11 @@
 // Needed for invocations of the `assert_data_tree` macro.
 #![recursion_limit = "256"]
 
-use std::{collections::HashMap, convert::TryFrom as _, time::Duration};
+use std::{collections::HashMap, convert::TryFrom as _, num::NonZeroU64, time::Duration};
 
 use assert_matches::assert_matches;
+use fidl_fuchsia_net_filter as fnet_filter;
+use fidl_fuchsia_net_filter_ext as fnet_filter_ext;
 use fidl_fuchsia_posix_socket as fposix_socket;
 
 use net_declare::{fidl_mac, fidl_subnet, std_ip_v4, std_ip_v6};
@@ -16,7 +18,10 @@
     ip::{IpAddress, IpInvariant, IpVersion, Ipv4, Ipv6},
     AddrAndPortFormatter, Witness as _,
 };
-use netstack_testing_common::{constants, get_inspect_data, realms::TestSandboxExt as _};
+use netstack_testing_common::{
+    constants, get_inspect_data,
+    realms::{Netstack3, TestSandboxExt as _},
+};
 use netstack_testing_macros::netstack_test;
 use packet_formats::ethernet::testutil::ETHERNET_HDR_LEN_NO_TAG;
 use test_case::test_case;
@@ -34,9 +39,9 @@
 #[test_case(TcpSocketState::Listener; "listener")]
 #[test_case(TcpSocketState::Connected; "connected")]
 async fn inspect_tcp_sockets<I: net_types::ip::Ip>(name: &str, socket_state: TcpSocketState) {
-    type N = netstack_testing_common::realms::Netstack3;
     let sandbox = netemul::TestSandbox::new().expect("failed to create sandbox");
-    let realm = sandbox.create_netstack_realm::<N, _>(name).expect("failed to create realm");
+    let realm =
+        sandbox.create_netstack_realm::<Netstack3, _>(name).expect("failed to create realm");
     let network = sandbox.create_network("net").await.expect("failed to create network");
 
     let interfaces_state = realm
@@ -305,9 +310,9 @@
     proto: fposix_socket::DatagramSocketProtocol,
     socket_state: SocketState,
 ) {
-    type N = netstack_testing_common::realms::Netstack3;
     let sandbox = netemul::TestSandbox::new().expect("failed to create sandbox");
-    let realm = sandbox.create_netstack_realm::<N, _>(name).expect("failed to create realm");
+    let realm =
+        sandbox.create_netstack_realm::<Netstack3, _>(name).expect("failed to create realm");
 
     // Ensure ns3 has started and that there is a Socket to collect inspect data about.
     let socket = realm.datagram_socket(I::DOMAIN, proto).await.expect("create datagram socket");
@@ -364,9 +369,9 @@
 
 #[netstack_test]
 async fn inspect_routes(name: &str) {
-    type N = netstack_testing_common::realms::Netstack3;
     let sandbox = netemul::TestSandbox::new().expect("failed to create sandbox");
-    let realm = sandbox.create_netstack_realm::<N, _>(name).expect("failed to create realm");
+    let realm =
+        sandbox.create_netstack_realm::<Netstack3, _>(name).expect("failed to create realm");
 
     let interfaces_state = realm
         .connect_to_protocol::<fidl_fuchsia_net_interfaces::StateMarker>()
@@ -408,34 +413,27 @@
     diagnostics_assertions::assert_data_tree!(data, "root": contains {
         "Routes": {
             "0": {
-                Destination: "255.255.255.255/32",
-                InterfaceId: loopback_id,
-                Gateway: "[NONE]",
-                Metric: 99999u64,
-                MetricTracksInterface: false,
-            },
-            "1": {
                 Destination: "127.0.0.0/8",
                 InterfaceId: loopback_id,
                 Gateway: "[NONE]",
                 Metric: 100u64,
                 MetricTracksInterface: true,
             },
-            "2": {
+            "1": {
                 Destination: "224.0.0.0/4",
                 InterfaceId: loopback_id,
                 Gateway: "[NONE]",
                 Metric: 100u64,
                 MetricTracksInterface: true,
             },
-            "3": {
+            "2": {
                 Destination: "::1/128",
                 InterfaceId: loopback_id,
                 Gateway: "[NONE]",
                 Metric: 100u64,
                 MetricTracksInterface: true,
             },
-            "4": {
+            "3": {
                 Destination: "ff00::/8",
                 InterfaceId: loopback_id,
                 Gateway: "[NONE]",
@@ -448,10 +446,10 @@
 
 #[netstack_test]
 async fn inspect_devices(name: &str) {
-    type N = netstack_testing_common::realms::Netstack3;
     let sandbox = netemul::TestSandbox::new().expect("failed to create sandbox");
     let network = sandbox.create_network("net").await.expect("failed to create network");
-    let realm = sandbox.create_netstack_realm::<N, _>(name).expect("failed to create realm");
+    let realm =
+        sandbox.create_netstack_realm::<Netstack3, _>(name).expect("failed to create realm");
 
     // Install netdevice device so that non-Loopback device Inspect properties can be asserted upon.
     const NETDEV_NAME: &str = "test-eth";
@@ -594,10 +592,9 @@
 
 #[netstack_test]
 async fn inspect_counters(name: &str) {
-    type N = netstack_testing_common::realms::Netstack3;
     let sandbox = netemul::TestSandbox::new().expect("failed to create sandbox");
-    let _network = sandbox.create_network("net").await.expect("failed to create network");
-    let realm = sandbox.create_netstack_realm::<N, _>(name).expect("failed to create realm");
+    let realm =
+        sandbox.create_netstack_realm::<Netstack3, _>(name).expect("failed to create realm");
 
     // Send a packet over loopback to increment Tx and Rx count by 1.
     let sender = realm
@@ -905,3 +902,253 @@
         }
     })
 }
+
+#[netstack_test]
+async fn inspect_filtering_state(name: &str) {
+    use fnet_filter_ext::{
+        Action, AddressMatcher, AddressMatcherType, Change, Controller, ControllerId, Domain,
+        InstalledIpRoutine, InterfaceMatcher, IpHook, Matchers, Namespace, NamespaceId,
+        PortMatcher, Resource, Routine, RoutineId, RoutineType, Rule, RuleId,
+        TransportProtocolMatcher,
+    };
+
+    let sandbox = netemul::TestSandbox::new().expect("create sandbox");
+    let realm = sandbox.create_netstack_realm::<Netstack3, _>(name).expect("create realm");
+
+    let control = realm
+        .connect_to_protocol::<fnet_filter::ControlMarker>()
+        .expect("connect to filter control");
+    let id = ControllerId(String::from("inspect"));
+    let mut controller = Controller::new(&control, &id).await.expect("open filter controller");
+
+    // By default, the netstack should report all the filtering hooks for both
+    // IP versions, but have no filtering state configured.
+    let data =
+        get_inspect_data(&realm, "netstack", "root", constants::inspect::DEFAULT_INSPECT_TREE_NAME)
+            .await
+            .expect("inspect data should be present");
+    // Debug print the tree to make debugging easier in case of failures.
+    println!("got inspect data: {:#?}", data);
+    diagnostics_assertions::assert_data_tree!(data, "root": contains {
+        "Filtering State": {
+            "IPv4": {
+                "ingress": {
+                    "routines": 0u64,
+                },
+                "local_ingress": {
+                    "routines": 0u64,
+                },
+                "forwarding": {
+                    "routines": 0u64,
+                },
+                "local_egress": {
+                    "routines": 0u64,
+                },
+                "egress": {
+                    "routines": 0u64,
+                },
+                "uninstalled": {
+                    "routines": 0u64,
+                },
+            },
+            "IPv6": {
+                "ingress": {
+                    "routines": 0u64,
+                },
+                "local_ingress": {
+                    "routines": 0u64,
+                },
+                "forwarding": {
+                    "routines": 0u64,
+                },
+                "local_egress": {
+                    "routines": 0u64,
+                },
+                "egress": {
+                    "routines": 0u64,
+                },
+                "uninstalled": {
+                    "routines": 0u64,
+                },
+            },
+        }
+    });
+
+    let namespace = NamespaceId(String::from("test-namespace"));
+    let ingress_routine = RoutineId { namespace: namespace.clone(), name: String::from("ingress") };
+    let egress_routine = RoutineId { namespace: namespace.clone(), name: String::from("egress") };
+    let target_routine_name = String::from("target");
+    controller
+        .push_changes(
+            [
+                Resource::Namespace(Namespace { id: namespace.clone(), domain: Domain::AllIp }),
+                Resource::Routine(Routine {
+                    id: ingress_routine.clone(),
+                    routine_type: RoutineType::Ip(Some(InstalledIpRoutine {
+                        hook: IpHook::Ingress,
+                        priority: -10,
+                    })),
+                }),
+                Resource::Rule(Rule {
+                    id: RuleId { routine: ingress_routine.clone(), index: 20 },
+                    matchers: Matchers {
+                        in_interface: Some(InterfaceMatcher::Id(NonZeroU64::new(1).unwrap())),
+                        ..Default::default()
+                    },
+                    action: Action::Drop,
+                }),
+                Resource::Rule(Rule {
+                    id: RuleId { routine: ingress_routine, index: 10 },
+                    matchers: Matchers {
+                        transport_protocol: Some(TransportProtocolMatcher::Tcp {
+                            src_port: None,
+                            dst_port: Some(PortMatcher::new(22, 22, /* invert */ false).unwrap()),
+                        }),
+                        ..Default::default()
+                    },
+                    action: Action::Drop,
+                }),
+                Resource::Routine(Routine {
+                    id: RoutineId { namespace, name: target_routine_name.clone() },
+                    routine_type: RoutineType::Ip(None),
+                }),
+                Resource::Routine(Routine {
+                    id: egress_routine.clone(),
+                    routine_type: RoutineType::Ip(Some(InstalledIpRoutine {
+                        hook: IpHook::Egress,
+                        priority: -10,
+                    })),
+                }),
+                Resource::Rule(Rule {
+                    id: RuleId { routine: egress_routine, index: 0 },
+                    matchers: Matchers {
+                        dst_addr: Some(AddressMatcher {
+                            matcher: AddressMatcherType::Subnet(
+                                fidl_subnet!("127.0.0.0/8").try_into().unwrap(),
+                            ),
+                            invert: false,
+                        }),
+                        ..Default::default()
+                    },
+                    action: Action::Jump(target_routine_name),
+                }),
+            ]
+            .into_iter()
+            .map(Change::Create)
+            .collect(),
+        )
+        .await
+        .expect("push filter changes");
+    controller.commit().await.expect("commit filter changes");
+
+    let data =
+        get_inspect_data(&realm, "netstack", "root", constants::inspect::DEFAULT_INSPECT_TREE_NAME)
+            .await
+            .expect("inspect data should be present");
+    // Debug print the tree to make debugging easier in case of failures.
+    println!("got inspect data: {:#?}", data);
+    diagnostics_assertions::assert_data_tree!(data, "root": contains {
+        "Filtering State": {
+            "IPv4": {
+                "ingress": {
+                    "routines": 1u64,
+                    "0": {
+                        "rules": 2u64,
+                        "0": {
+                            "matchers": {
+                                "transport_protocol": "TransportProtocolMatcher { \
+                                    proto: TCP, \
+                                    src_port: None, \
+                                    dst_port: Some(PortMatcher { range: 22..=22, invert: false }) \
+                                }",
+                            },
+                            "action": "Drop",
+                        },
+                        "1": {
+                            "matchers": {
+                                "in_interface": "Id(1)",
+                            },
+                            "action": "Drop",
+                        },
+                    },
+                },
+                "local_ingress": {
+                    "routines": 0u64,
+                },
+                "forwarding": {
+                    "routines": 0u64,
+                },
+                "local_egress": {
+                    "routines": 0u64,
+                },
+                "egress": {
+                    "routines": 1u64,
+                    "0": {
+                        "rules": 1u64,
+                        "0": {
+                            // Note that this rule is only included in the IPv4 filtering state
+                            // because it has an address matcher with an IPv4 subnet.
+                            "matchers": {
+                                "dst_address": "AddressMatcher { \
+                                    matcher: Subnet(127.0.0.0/8), \
+                                    invert: false \
+                                }",
+                            },
+                            "action": "Jump(UninstalledRoutine(2))",
+                        },
+                    },
+                },
+                // Because the uninstalled routine is only jumped to from an IPv4 routine, it
+                // only exists in the IPv4 filtering state.
+                "uninstalled": {
+                    "routines": 1u64,
+                    "2": {
+                        "rules": 0u64,
+                    },
+                },
+            },
+            "IPv6": {
+                "ingress": {
+                    "routines": 1u64,
+                    "0": {
+                        "rules": 2u64,
+                        "0": {
+                            "matchers": {
+                                "transport_protocol": "TransportProtocolMatcher { \
+                                    proto: TCP, \
+                                    src_port: None, \
+                                    dst_port: Some(PortMatcher { range: 22..=22, invert: false }) \
+                                }",
+                            },
+                            "action": "Drop",
+                        },
+                        "1": {
+                            "matchers": {
+                                "in_interface": "Id(1)",
+                            },
+                            "action": "Drop",
+                        },
+                    },
+                },
+                "local_ingress": {
+                    "routines": 0u64,
+                },
+                "forwarding": {
+                    "routines": 0u64,
+                },
+                "local_egress": {
+                    "routines": 0u64,
+                },
+                "egress": {
+                    "routines": 1u64,
+                    "0": {
+                        "rules": 0u64,
+                    },
+                },
+                "uninstalled": {
+                    "routines": 0u64,
+                },
+            },
+        }
+    });
+}
diff --git a/src/connectivity/network/tests/integration/ipv4/BUILD.gn b/src/connectivity/network/tests/integration/ipv4/BUILD.gn
index a70230e..cd0fefe 100644
--- a/src/connectivity/network/tests/integration/ipv4/BUILD.gn
+++ b/src/connectivity/network/tests/integration/ipv4/BUILD.gn
@@ -10,6 +10,7 @@
   deps = [
     "//sdk/fidl/fuchsia.net:fuchsia.net_rust",
     "//sdk/fidl/fuchsia.net.interfaces.admin:fuchsia.net.interfaces.admin_rust",
+    "//sdk/fidl/fuchsia.net.routes:fuchsia.net.routes_rust",
     "//src/connectivity/lib/net-declare",
     "//src/connectivity/lib/net-types",
     "//src/connectivity/lib/packet-formats",
@@ -17,6 +18,7 @@
     "//src/connectivity/network/tests/integration/common:netstack_testing_common",
     "//src/connectivity/network/tests/integration/macros:netstack_testing_macros",
     "//src/lib/fuchsia-async",
+    "//src/lib/network/fidl_fuchsia_net_routes_ext",
     "//src/lib/network/packet",
     "//third_party/rust_crates:assert_matches",
     "//third_party/rust_crates:futures",
diff --git a/src/connectivity/network/tests/integration/ipv4/src/lib.rs b/src/connectivity/network/tests/integration/ipv4/src/lib.rs
index c6ea99f..8321920 100644
--- a/src/connectivity/network/tests/integration/ipv4/src/lib.rs
+++ b/src/connectivity/network/tests/integration/ipv4/src/lib.rs
@@ -4,17 +4,22 @@
 
 #![cfg(test)]
 
-use fidl_fuchsia_net as net;
+use fidl_fuchsia_net as fnet;
 use fidl_fuchsia_net_interfaces_admin as fnet_interfaces_admin;
+use fidl_fuchsia_net_routes as fnet_routes;
+use fidl_fuchsia_net_routes_ext as fnet_routes_ext;
 use fuchsia_async::{DurationExt as _, TimeoutExt as _};
 
-use futures::StreamExt as _;
+use futures::{FutureExt as _, StreamExt as _};
 use net_declare::{net_ip_v4, std_ip_v4};
-use net_types::{ip as net_types_ip, MulticastAddress as _};
-use netemul::RealmUdpSocket as _;
+use net_types::{
+    ip::{self as net_types_ip, Ipv4, Ipv4Addr},
+    MulticastAddress as _,
+};
+use netemul::RealmUdpSocket;
 use netstack_testing_common::{
-    interfaces,
-    realms::{Netstack, NetstackVersion},
+    interfaces::{self, TestInterfaceExt},
+    realms::{Netstack, NetstackVersion, TestSandboxExt},
     setup_network, ASYNC_EVENT_POSITIVE_CHECK_TIMEOUT,
 };
 use netstack_testing_macros::netstack_test;
@@ -216,10 +221,10 @@
         );
     }
 
-    let addr = net::Ipv4Address { addr: INTERFACE_ADDR.octets() };
+    let addr = fnet::Ipv4Address { addr: INTERFACE_ADDR.octets() };
     let _address_state_provider = interfaces::add_subnet_address_and_route_wait_assigned(
         &iface,
-        net::Subnet { addr: net::IpAddress::Ipv4(addr), prefix_len: 24 },
+        fnet::Subnet { addr: fnet::IpAddress::Ipv4(addr), prefix_len: 24 },
         fidl_fuchsia_net_interfaces_admin::AddressParameters::default(),
     )
     .await
@@ -301,3 +306,118 @@
         .await
         .expect("error getting our expected IGMP report");
 }
+
+#[netstack_test]
+async fn all_ones_broadcast<N: Netstack>(name: &str) {
+    let sandbox = netemul::TestSandbox::new().expect("error creating sandbox");
+
+    let name_suffixes = ["a", "b", "c"];
+    let realms = name_suffixes.map(|suffix| {
+        sandbox
+            .create_netstack_realm::<N, _>(format!("{name}_{suffix}"))
+            .unwrap_or_else(|e| panic!("create realm {suffix}: {e:?}"))
+    });
+    let network = sandbox.create_network(name).await.expect("create network");
+
+    let addr_subnets = [
+        net_declare::fidl_subnet!("192.168.0.1/24"),
+        net_declare::fidl_subnet!("192.168.0.2/24"),
+        net_declare::fidl_subnet!("192.168.0.3/24"),
+    ];
+
+    // Keep same as first `addr_subnet`.
+    const SENDER_IP: std::net::IpAddr = net_declare::std_ip!("192.168.0.1");
+
+    const DEFAULT_SUBNET: net_types::ip::Subnet<Ipv4Addr> =
+        net_declare::net_subnet_v4!("0.0.0.0/0");
+
+    let mut ifaces = Vec::new();
+    for (i, realm) in realms.iter().enumerate() {
+        let iface = realm
+            .join_network(&network, format!("{name}_{}", name_suffixes[i]))
+            .await
+            .expect("join network");
+        iface.add_address(addr_subnets[i]).await.expect("add address");
+        iface.apply_nud_flake_workaround().await.expect("apply nud flake workaround");
+        let global_route_set = iface
+            .create_authenticated_global_route_set::<Ipv4>()
+            .await
+            .expect("create authenticated route set");
+
+        // Add an on-link default route so that the netstacks should each be
+        // able to receive broadcasts from each other.
+        let default_route = fnet_routes_ext::Route::<Ipv4> {
+            action: fnet_routes_ext::RouteAction::Forward(fnet_routes_ext::RouteTarget {
+                outbound_interface: iface.id(),
+                next_hop: None,
+            }),
+            destination: DEFAULT_SUBNET,
+            properties: fnet_routes_ext::RouteProperties {
+                specified_properties: fnet_routes_ext::SpecifiedRouteProperties {
+                    metric: fnet_routes::SpecifiedMetric::InheritedFromInterface(
+                        fnet_routes::Empty,
+                    ),
+                },
+            },
+        };
+        assert!(
+            global_route_set
+                .add_route(&default_route.try_into().expect("convert to FIDL route"))
+                .await
+                .expect("adding default route should not get FIDL error")
+                .expect("adding default route should succeed"),
+            "should have newly-added default route"
+        );
+        ifaces.push(iface);
+    }
+
+    let sending_realm = &realms[0];
+
+    // Using 1024 as arbitrary port for sending/receiving.
+    const PORT: u16 = 1024;
+
+    let make_socket = |realm| async move {
+        let socket = fuchsia_async::net::UdpSocket::bind_in_realm(
+            realm,
+            std::net::SocketAddr::new(std::net::Ipv4Addr::UNSPECIFIED.into(), PORT),
+        )
+        .await
+        .expect("bind in realm");
+        socket.set_broadcast(true).expect("set broadcast");
+        socket
+    };
+
+    let sending_socket = make_socket(sending_realm).await;
+
+    let mut receiving_sockets = Vec::new();
+    for receiving_realm in &realms[1..] {
+        receiving_sockets.push(make_socket(receiving_realm).await);
+    }
+
+    const PAYLOAD: &str = "hello";
+    assert_eq!(
+        sending_socket
+            .send_to(
+                PAYLOAD.as_bytes(),
+                std::net::SocketAddr::new(std::net::Ipv4Addr::BROADCAST.into(), PORT),
+            )
+            .await
+            .expect("send should succeed"),
+        PAYLOAD.len()
+    );
+
+    let mut buf = [0u8; 16];
+
+    for receiving_socket in receiving_sockets {
+        let (n, received_from) = receiving_socket
+            .recv_from(&mut buf)
+            .map(Some)
+            .on_timeout(ASYNC_EVENT_POSITIVE_CHECK_TIMEOUT, || None)
+            .await
+            .expect("should not have timed out")
+            .expect("recv_from");
+        assert_eq!(n, PAYLOAD.len());
+        assert_eq!(&buf[..n], PAYLOAD.as_bytes());
+        assert_eq!(received_from, std::net::SocketAddr::new(SENDER_IP, PORT));
+    }
+}
diff --git a/src/connectivity/network/tests/integration/ipv6/src/lib.rs b/src/connectivity/network/tests/integration/ipv6/src/lib.rs
index 62b540f..25cc9a2 100644
--- a/src/connectivity/network/tests/integration/ipv6/src/lib.rs
+++ b/src/connectivity/network/tests/integration/ipv6/src/lib.rs
@@ -247,7 +247,7 @@
                         _,
                         RouterSolicitation,
                         _,
-                    >(&data, EthernetFrameLengthCheck::Check, |p| {
+                    >(&data, EthernetFrameLengthCheck::NoCheck, |p| {
                         for option in p.body().iter() {
                             if let NdpOption::SourceLinkLayerAddress(a) = option {
                                 let mut mac_bytes = [0; 6];
@@ -355,7 +355,7 @@
                     _,
                     RouterSolicitation,
                     _,
-                >(&data, EthernetFrameLengthCheck::Check, |_| {})
+                >(&data, EthernetFrameLengthCheck::NoCheck, |_| {})
                 .map_or(None, |_| Some(())),
             )
         })
@@ -815,7 +815,7 @@
                         _,
                         NeighborSolicitation,
                         _,
-                    >(&data, EthernetFrameLengthCheck::Check, |p| assert_eq!(p.body().iter().count(), 0))
+                    >(&data, EthernetFrameLengthCheck::NoCheck, |p| assert_eq!(p.body().iter().count(), 0))
                         .map_or(None, |(_src_mac, _dst_mac, _src_ip, _dst_ip, _ttl, message, _code)| {
                             // If the NS target_address does not have the prefix we have advertised,
                             // this is for some other address. We ignore it as it is not relevant to
diff --git a/src/connectivity/network/tests/integration/socket/BUILD.gn b/src/connectivity/network/tests/integration/socket/BUILD.gn
index b658e50..dc38d73 100644
--- a/src/connectivity/network/tests/integration/socket/BUILD.gn
+++ b/src/connectivity/network/tests/integration/socket/BUILD.gn
@@ -17,10 +17,12 @@
     "//sdk/fidl/fuchsia.net.tun:fuchsia.net.tun_rust",
     "//sdk/fidl/fuchsia.posix:fuchsia.posix_rust",
     "//sdk/fidl/fuchsia.posix.socket:fuchsia.posix.socket_rust",
+    "//sdk/fidl/fuchsia.posix.socket.packet:fuchsia.posix.socket.packet_rust",
     "//src/connectivity/lib/fidl_fuchsia_net_stack_ext",
     "//src/connectivity/lib/net-declare",
     "//src/connectivity/lib/net-types",
     "//src/connectivity/lib/packet-formats",
+    "//src/connectivity/network/lib/sockaddr",
     "//src/connectivity/network/testing/netemul/rust:lib",
     "//src/connectivity/network/tests/integration/common:netstack_testing_common",
     "//src/connectivity/network/tests/integration/macros:netstack_testing_macros",
diff --git a/src/connectivity/network/tests/integration/socket/src/lib.rs b/src/connectivity/network/tests/integration/socket/src/lib.rs
index e13b4f4..0df499a 100644
--- a/src/connectivity/network/tests/integration/socket/src/lib.rs
+++ b/src/connectivity/network/tests/integration/socket/src/lib.rs
@@ -20,6 +20,7 @@
 use fidl_fuchsia_net_tun as fnet_tun;
 use fidl_fuchsia_posix as fposix;
 use fidl_fuchsia_posix_socket as fposix_socket;
+use fidl_fuchsia_posix_socket_packet as fpacket;
 use fuchsia_async::{
     self as fasync,
     net::{DatagramSocket, UdpSocket},
@@ -38,7 +39,10 @@
 };
 use net_types::{
     ethernet::Mac,
-    ip::{AddrSubnetEither, Ip, IpAddress as _, IpInvariant, Ipv4, Ipv4Addr, Ipv6},
+    ip::{
+        AddrSubnetEither, Ip, IpAddress as _, IpInvariant, IpVersion, Ipv4, Ipv4Addr, Ipv6,
+        Ipv6Addr,
+    },
     Witness as _,
 };
 use netemul::{
@@ -52,6 +56,7 @@
     realms::{KnownServiceProvider, Netstack, NetstackVersion, TestSandboxExt as _},
     Result,
 };
+
 use netstack_testing_macros::netstack_test;
 use packet::{InnerPacketBuilder as _, ParsablePacket as _, Serializer as _};
 use packet_formats::{
@@ -62,15 +67,18 @@
             options::{NdpOptionBuilder, PrefixInformation},
             NeighborAdvertisement,
         },
-        IcmpDestUnreachable, IcmpPacketBuilder, Icmpv4DestUnreachableCode,
-        Icmpv6DestUnreachableCode,
+        IcmpDestUnreachable, IcmpEchoRequest, IcmpPacketBuilder, IcmpUnusedCode,
+        Icmpv4DestUnreachableCode, Icmpv4Packet, Icmpv6DestUnreachableCode, Icmpv6Packet,
+        MessageBody,
     },
+    igmp::messages::IgmpPacket,
     ip::{IpProto, Ipv4Proto, Ipv6Proto},
     ipv4::{Ipv4Header as _, Ipv4Packet, Ipv4PacketBuilder},
-    ipv6::{Ipv6Header as _, Ipv6Packet},
+    ipv6::{Ipv6Header, Ipv6Packet, Ipv6PacketBuilder},
 };
+use sockaddr::{IntoSockAddr as _, PureIpSockaddr};
 use socket2::SockRef;
-use std::pin::pin;
+use std::{num::NonZeroU64, pin::pin};
 use test_case::test_case;
 
 async fn run_udp_socket_test(
@@ -115,6 +123,72 @@
     let ((), ()) = futures::future::join(client_fut, server_fut).await;
 }
 
+async fn run_ip_endpoint_packet_socket_test(
+    server: &netemul::TestRealm<'_>,
+    server_iface_id: u64,
+    client: &netemul::TestRealm<'_>,
+    client_iface_id: u64,
+    ip_version: IpVersion,
+) {
+    async fn new_packet_socket_in_realm(
+        realm: &netemul::TestRealm<'_>,
+        addr: PureIpSockaddr,
+    ) -> Result<fasync::net::DatagramSocket> {
+        let socket =
+            realm.packet_socket(fpacket::Kind::Network).await.context("creating packet socket")?;
+        let sockaddr = libc::sockaddr_ll::from(addr).into_sockaddr();
+        let () = socket.bind(&sockaddr).context("binding packet_socket")?;
+        let socket = fasync::net::DatagramSocket::new_from_socket(socket)
+            .context("wrapping packet socket in fuchsia-async DatagramSocket")?;
+        Ok(socket)
+    }
+
+    let client_iface_id = NonZeroU64::new(client_iface_id).expect("client iface id is 0");
+    let server_iface_id = NonZeroU64::new(server_iface_id).expect("server iface id is 0");
+
+    let client_sock = new_packet_socket_in_realm(
+        client,
+        PureIpSockaddr { interface_id: Some(client_iface_id), protocol: ip_version },
+    )
+    .await
+    .expect("failed to create client socket");
+
+    let server_sock = new_packet_socket_in_realm(
+        server,
+        PureIpSockaddr { interface_id: Some(server_iface_id), protocol: ip_version },
+    )
+    .await
+    .expect("failed to create server socket");
+
+    const PAYLOAD: &'static str = "Hello World";
+    let send_to_addr = libc::sockaddr_ll::from(PureIpSockaddr {
+        interface_id: Some(client_iface_id),
+        protocol: ip_version,
+    })
+    .into_sockaddr();
+    let r = client_sock.send_to(PAYLOAD.as_bytes(), send_to_addr).await.expect("sendto failed");
+    assert_eq!(r, PAYLOAD.as_bytes().len());
+
+    let mut buf = [0u8; 1024];
+    // Receive from the socket, ignoring all spurious data that may be observed
+    // from the network.
+    let (recv_len, from) = {
+        loop {
+            let (recv_len, from) =
+                server_sock.recv_from(&mut buf[..]).await.expect("failed to receive");
+            match is_packet_spurious(ip_version, &buf[..recv_len]) {
+                // NB: IPv4/IPv6 Parse errors are expected, since we're sending
+                // "Hello World" and not a valid packet.
+                Err(_) | Ok(false) => break (recv_len, from),
+                Ok(true) => continue,
+            }
+        }
+    };
+    assert_eq!(recv_len, PAYLOAD.as_bytes().len());
+    assert_eq!(&buf[..recv_len], PAYLOAD.as_bytes());
+    assert_eq!(i32::from(from.family()), libc::AF_PACKET);
+}
+
 const CLIENT_SUBNET: fnet::Subnet = fidl_subnet!("192.168.0.2/24");
 const SERVER_SUBNET: fnet::Subnet = fidl_subnet!("192.168.0.1/24");
 const CLIENT_MAC: fnet::MacAddress = fidl_mac!("02:00:00:00:00:02");
@@ -1935,8 +2009,20 @@
     }
 }
 
+enum IpEndpointsSocketTestCase {
+    Udp,
+    Tcp,
+    Packet,
+}
+
 #[netstack_test]
-async fn ip_endpoints_socket<N: Netstack>(name: &str) {
+#[test_case(IpEndpointsSocketTestCase::Udp; "udp_socket")]
+#[test_case(IpEndpointsSocketTestCase::Tcp; "tcp_socket")]
+#[test_case(IpEndpointsSocketTestCase::Packet; "packet_socket")]
+async fn ip_endpoints_socket<N: Netstack, I: net_types::ip::Ip>(
+    name: &str,
+    socket_type: IpEndpointsSocketTestCase,
+) {
     let sandbox = netemul::TestSandbox::new().expect("failed to create sandbox");
     let client = sandbox
         .create_netstack_realm::<N, _>(format!("{}_client", name))
@@ -1958,27 +2044,87 @@
     .await;
 
     // Addresses must be in the same subnet.
-    const SERVER_ADDR_V4: fnet::Subnet = fidl_subnet!("192.168.0.1/24");
-    const SERVER_ADDR_V6: fnet::Subnet = fidl_subnet!("2001::1/120");
-    const CLIENT_ADDR_V4: fnet::Subnet = fidl_subnet!("192.168.0.2/24");
-    const CLIENT_ADDR_V6: fnet::Subnet = fidl_subnet!("2001::2/120");
+    let (client_addr, server_addr) = match I::VERSION {
+        IpVersion::V4 => (fidl_subnet!("192.168.0.1/24"), fidl_subnet!("192.168.0.2/24")),
+        IpVersion::V6 => (fidl_subnet!("2001::1/120"), fidl_subnet!("2001::2/120")),
+    };
 
     // We install both devices in parallel because a DevicePair will only have
     // its link signal set to up once both sides have sessions attached. This
     // way both devices will be configured "at the same time" and DAD will be
     // able to complete for IPv6 addresses.
     let (
-        (_client_id, _client_control, _client_device_control),
-        (_server_id, _server_control, _server_device_control),
+        (client_id, _client_control, _client_device_control),
+        (server_id, _server_control, _server_device_control),
     ) = futures::future::join(
-        install_ip_device(&client, client_port, [CLIENT_ADDR_V4, CLIENT_ADDR_V6]),
-        install_ip_device(&server, server_port, [SERVER_ADDR_V4, SERVER_ADDR_V6]),
+        install_ip_device(&client, client_port, [client_addr]),
+        install_ip_device(&server, server_port, [server_addr]),
     )
     .await;
 
-    // Run socket test for both IPv4 and IPv6.
-    let () = run_udp_socket_test(&server, SERVER_ADDR_V4.addr, &client, CLIENT_ADDR_V4.addr).await;
-    let () = run_udp_socket_test(&server, SERVER_ADDR_V6.addr, &client, CLIENT_ADDR_V6.addr).await;
+    match socket_type {
+        IpEndpointsSocketTestCase::Udp => {
+            run_udp_socket_test(&server, server_addr.addr, &client, client_addr.addr).await
+        }
+        IpEndpointsSocketTestCase::Tcp => {
+            run_tcp_socket_test(&server, server_addr.addr, &client, client_addr.addr).await
+        }
+        IpEndpointsSocketTestCase::Packet => {
+            run_ip_endpoint_packet_socket_test(&server, server_id, &client, client_id, I::VERSION)
+                .await
+        }
+    }
+}
+
+/// Returns true if the packet is one of is IGMP, MLD, or NDP.
+
+/// This traffic implicitly exists on the network, and may be unexpectedly
+/// received during tests who interact directly with the underlying device (e.g.
+/// via packet sockets, or via the netdevice APIs).
+///
+/// Returns `Err` if the packet cannot be parsed.
+fn is_packet_spurious(ip_version: IpVersion, mut body: &[u8]) -> Result<bool> {
+    match ip_version {
+        IpVersion::V6 => {
+            let ipv6 = Ipv6Packet::parse(&mut body, ())
+                .with_context(|| format!("failed to parse IPv6 packet {:?}", body))?;
+            if ipv6.proto() == Ipv6Proto::Icmpv6 {
+                let parse_args =
+                    packet_formats::icmp::IcmpParseArgs::new(ipv6.src_ip(), ipv6.dst_ip());
+                match Icmpv6Packet::parse(&mut body, parse_args)
+                    .context("failed to parse ICMP packet")?
+                {
+                    Icmpv6Packet::Ndp(p) => {
+                        println!("ignoring NDP packet {:?}", p);
+                        Ok(true)
+                    }
+                    Icmpv6Packet::Mld(p) => {
+                        println!("ignoring MLD packet {:?}", p);
+                        Ok(true)
+                    }
+                    Icmpv6Packet::DestUnreachable(_)
+                    | Icmpv6Packet::PacketTooBig(_)
+                    | Icmpv6Packet::TimeExceeded(_)
+                    | Icmpv6Packet::ParameterProblem(_)
+                    | Icmpv6Packet::EchoRequest(_)
+                    | Icmpv6Packet::EchoReply(_) => Ok(false),
+                }
+            } else {
+                Ok(false)
+            }
+        }
+        IpVersion::V4 => {
+            let ipv4 = Ipv4Packet::parse(&mut body, ())
+                .with_context(|| format!("failed to parse IPv4 packet {:?}", body))?;
+            if ipv4.proto() == Ipv4Proto::Igmp {
+                let p = IgmpPacket::parse(&mut body, ()).context("failed to parse IGMP packet")?;
+                println!("ignoring IGMP packet {:?}", p);
+                Ok(true)
+            } else {
+                Ok(false)
+            }
+        }
+    }
 }
 
 #[netstack_test]
@@ -2039,18 +2185,6 @@
     )
     .await;
 
-    use net_types::ip::{Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
-    use packet::ParsablePacket;
-    use packet_formats::{
-        icmp::{
-            IcmpEchoRequest, IcmpPacketBuilder, IcmpUnusedCode, Icmpv4Packet, Icmpv6Packet,
-            MessageBody,
-        },
-        igmp::messages::IgmpPacket,
-        ipv4::{Ipv4Packet, Ipv4PacketBuilder},
-        ipv6::{Ipv6Header, Ipv6Packet, Ipv6PacketBuilder},
-    };
-
     let read_frame = futures::stream::try_unfold(tun_dev.clone(), |tun_dev| async move {
         let frame = tun_dev
             .read_frame()
@@ -2063,50 +2197,16 @@
     .try_filter_map(|frame| async move {
         let frame_type = frame.frame_type.context("missing frame type in frame")?;
         let frame_data = frame.data.context("missing data in frame")?;
-        match frame_type {
+        let is_spurious = match frame_type {
             fhardware_network::FrameType::Ipv6 => {
-                // Ignore all NDP and MLD IPv6 frames.
-                let mut bv = &frame_data[..];
-                let ipv6 = Ipv6Packet::parse(&mut bv, ())
-                    .with_context(|| format!("failed to parse IPv6 packet {:?}", frame_data))?;
-                if ipv6.proto() == Ipv6Proto::Icmpv6 {
-                    let parse_args =
-                        packet_formats::icmp::IcmpParseArgs::new(ipv6.src_ip(), ipv6.dst_ip());
-                    match Icmpv6Packet::parse(&mut bv, parse_args)
-                        .context("failed to parse ICMP packet")?
-                    {
-                        Icmpv6Packet::Ndp(p) => {
-                            println!("ignoring NDP packet {:?}", p);
-                            return Ok(None);
-                        }
-                        Icmpv6Packet::Mld(p) => {
-                            println!("ignoring MLD packet {:?}", p);
-                            return Ok(None);
-                        }
-                        Icmpv6Packet::DestUnreachable(_)
-                        | Icmpv6Packet::PacketTooBig(_)
-                        | Icmpv6Packet::TimeExceeded(_)
-                        | Icmpv6Packet::ParameterProblem(_)
-                        | Icmpv6Packet::EchoRequest(_)
-                        | Icmpv6Packet::EchoReply(_) => {}
-                    }
-                }
+                is_packet_spurious(IpVersion::V6, &frame_data[..])
             }
             fhardware_network::FrameType::Ipv4 => {
-                // Ignore all IGMP frames.
-                let mut bv = &frame_data[..];
-                let ipv4 = Ipv4Packet::parse(&mut bv, ())
-                    .with_context(|| format!("failed to parse IPv4 packet {:?}", frame_data))?;
-                if ipv4.proto() == Ipv4Proto::Igmp {
-                    let p =
-                        IgmpPacket::parse(&mut bv, ()).context("failed to parse IGMP packet")?;
-                    println!("ignoring IGMP packet {:?}", p);
-                    return Ok(None);
-                }
+                is_packet_spurious(IpVersion::V4, &frame_data[..])
             }
-            fhardware_network::FrameType::Ethernet => {}
-        }
-        Ok(Some((frame_type, frame_data)))
+            fhardware_network::FrameType::Ethernet => Ok(false),
+        }?;
+        Ok((!is_spurious).then_some((frame_type, frame_data)))
     });
     let mut read_frame = pin!(read_frame);
 
diff --git a/src/connectivity/network/tests/socket/dgramsocket_test.cc b/src/connectivity/network/tests/socket/dgramsocket_test.cc
index a0043bf..7f33e76 100644
--- a/src/connectivity/network/tests/socket/dgramsocket_test.cc
+++ b/src/connectivity/network/tests/socket/dgramsocket_test.cc
@@ -4058,7 +4058,7 @@
 
 class DatagramSendSemanticsSoBroadcastInstance : public DatagramSendSemanticsTestInstance {
  public:
-  DatagramSendSemanticsSoBroadcastInstance(const SocketDomain& domain)
+  explicit DatagramSendSemanticsSoBroadcastInstance(const SocketDomain& domain)
       : DatagramSendSemanticsTestInstance(domain) {}
 
   void SetUpInstance() override {
@@ -4082,6 +4082,14 @@
     ASSERT_EQ(addrlen, sizeof(recv_addr_));
 
     ASSERT_TRUE(send_fd_ = fbl::unique_fd(socket(domain_.Get(), SOCK_DGRAM, 0))) << strerror(errno);
+
+    // Bind the sending socket to a device to ensure that the test does not rely
+    // on a default route being installed.
+    const char loopback_name[3] = "lo";
+    EXPECT_EQ(setsockopt(send_fd_.get(), SOL_SOCKET, SO_BINDTODEVICE, &loopback_name,
+                         sizeof(loopback_name)),
+              0)
+        << strerror(errno);
   }
 
   void ToggleOn() {
diff --git a/src/connectivity/network/tools/sockscripter/BUILD.gn b/src/connectivity/network/tools/sockscripter/BUILD.gn
index aa8c537..cd9e319 100644
--- a/src/connectivity/network/tools/sockscripter/BUILD.gn
+++ b/src/connectivity/network/tools/sockscripter/BUILD.gn
@@ -34,6 +34,7 @@
   sources = [
     "addr_test.cc",
     "sockscripter_test.cc",
+    "testutil.h",
   ]
   deps = [
     ":src",
diff --git a/src/connectivity/network/tools/sockscripter/addr.cc b/src/connectivity/network/tools/sockscripter/addr.cc
index aa80cd1..0a2fbf0 100644
--- a/src/connectivity/network/tools/sockscripter/addr.cc
+++ b/src/connectivity/network/tools/sockscripter/addr.cc
@@ -18,6 +18,8 @@
 
 #if PACKET_SOCKETS
 #include <netpacket/packet.h>
+
+#include "api_abstraction.h"
 #endif
 
 struct PrintInterface {
@@ -231,3 +233,40 @@
     }
   }
 }
+
+#if PACKET_SOCKETS
+std::optional<sockaddr_ll> ParseSockAddrLlFromArg(const std::string& argstr, ApiAbstraction* api) {
+  size_t col_pos = argstr.find_first_of(':');
+  if (col_pos == std::string::npos) {
+    LOG(ERROR) << "Error-Cannot parse packet socket addr='" << argstr
+               << "' for <protocol>:<ifname> - missing separating colon ':'!";
+    return std::nullopt;
+  }
+
+  std::string protocol_str = argstr.substr(0, col_pos);
+  std::string ifname_str = argstr.substr(col_pos + 1);
+
+  int protocol;
+  if (!str2int(protocol_str, &protocol)) {
+    LOG(ERROR) << "Error-Cannot parse protocol number='" << protocol_str << "'!";
+    return std::nullopt;
+  }
+
+  unsigned int if_index = 0;
+  if (!ifname_str.empty()) {
+    if_index = api->if_nametoindex(ifname_str.c_str());
+    if (!if_index) {
+      LOG(ERROR) << "Error-if_nametoindex(" << ifname_str << ") failed -" << "[" << errno << "]"
+                 << strerror(errno);
+      return std::nullopt;
+    }
+  }
+
+  const struct sockaddr_ll sll = {
+      .sll_family = AF_PACKET,
+      .sll_protocol = htons(static_cast<uint16_t>(protocol)),
+      .sll_ifindex = static_cast<int>(if_index),
+  };
+  return std::make_optional(sll);
+}
+#endif  // PACKET_SOCKETS
diff --git a/src/connectivity/network/tools/sockscripter/addr.h b/src/connectivity/network/tools/sockscripter/addr.h
index ff0469a..8c5d6a1 100644
--- a/src/connectivity/network/tools/sockscripter/addr.h
+++ b/src/connectivity/network/tools/sockscripter/addr.h
@@ -7,6 +7,13 @@
 
 #include <netinet/in.h>
 
+#include "packet.h"
+#if PACKET_SOCKETS
+#include <netpacket/packet.h>
+
+#include "api_abstraction.h"
+#endif  // PACKET_SOCKETS
+
 #include <optional>
 #include <string>
 
@@ -28,4 +35,11 @@
 /// Returns the length of the provided address based on its family.
 socklen_t AddrLen(const sockaddr_storage& addr);
 
+#if PACKET_SOCKETS
+/// Parses the `argstr` into a packet socket address (`sockaddr_ll`).
+///
+/// The expected format for `argstr` is "<protocol>:<ifname>".
+std::optional<sockaddr_ll> ParseSockAddrLlFromArg(const std::string& argstr, ApiAbstraction* api);
+#endif  // PACKET_SOCKETS
+
 #endif  // SRC_CONNECTIVITY_NETWORK_TOOLS_SOCKSCRIPTER_ADDR_H_
diff --git a/src/connectivity/network/tools/sockscripter/addr_test.cc b/src/connectivity/network/tools/sockscripter/addr_test.cc
index d62aeed..9176b7b 100644
--- a/src/connectivity/network/tools/sockscripter/addr_test.cc
+++ b/src/connectivity/network/tools/sockscripter/addr_test.cc
@@ -8,6 +8,13 @@
 
 #include <gtest/gtest.h>
 
+#if PACKET_SOCKETS
+#include <netpacket/packet.h>
+
+#include "api_abstraction.h"
+#include "testutil.h"
+#endif  // PACKET_SOCKETS
+
 #define EXPECT_NO_VALUE(expr)                     \
   do {                                            \
     const std::optional val = expr;               \
@@ -128,3 +135,26 @@
   ASSERT_EQ(addr_v6.value().ss_family, AF_INET6);
   EXPECT_EQ(AddrLen(addr_v6.value()), sizeof(sockaddr_in6));
 }
+
+#if PACKET_SOCKETS
+TEST(AddrTest, TestParseSockAddrLl) {
+  constexpr unsigned int kIfIndex = 5;
+  constexpr uint16_t kIpv4Protocol = 2048;
+  TestApi api;
+  EXPECT_CALL(api, if_nametoindex(testing::_)).WillOnce([](const char* ifname) {
+    EXPECT_EQ(std::string(ifname), "myinterfacename");
+    return kIfIndex;
+  });
+
+  std::optional actual_addr = ParseSockAddrLlFromArg("2048:myinterfacename", &api);
+  const struct sockaddr_ll expected_addr = {
+      .sll_family = AF_PACKET,
+      .sll_protocol = htons(kIpv4Protocol),
+      .sll_ifindex = kIfIndex,
+  };
+  ASSERT_TRUE(actual_addr.has_value());
+  EXPECT_EQ(actual_addr->sll_family, expected_addr.sll_family);
+  EXPECT_EQ(actual_addr->sll_protocol, expected_addr.sll_protocol);
+  EXPECT_EQ(actual_addr->sll_ifindex, expected_addr.sll_ifindex);
+}
+#endif  // PACKET_SOCKETS
diff --git a/src/connectivity/network/tools/sockscripter/sockscripter.cc b/src/connectivity/network/tools/sockscripter/sockscripter.cc
index c055f6a..69841f0 100644
--- a/src/connectivity/network/tools/sockscripter/sockscripter.cc
+++ b/src/connectivity/network/tools/sockscripter/sockscripter.cc
@@ -208,6 +208,10 @@
 #if PACKET_SOCKETS
     {"packet-bind", "<protocol>:<if-name-string>",
      "bind a packet socket to the given protocol and interface", &SockScripter::PacketBind},
+    {"packet-send-to", "<protocol>:<if-name-string>",
+     "send send_buf on a packet socket with the given protocol out the given interface.",
+     &SockScripter::PacketSendTo},
+
 #endif
 };
 
@@ -785,42 +789,37 @@
 }
 
 #if PACKET_SOCKETS
+bool SockScripter::PacketSendTo(char* arg) {
+  std::string argstr = arg;
+  std::optional<sockaddr_ll> sll = ParseSockAddrLlFromArg(argstr, api_);
+  if (!sll.has_value()) {
+    return false;
+  }
+  auto snd_buf = snd_buf_gen_.GetSndStr();
+  LOG(INFO) << "PacketSendTo(data:\"" << Escaped(snd_buf) << "\", len:" << snd_buf.length()
+            << ", fd" << sockfd_ << ", protocol:" << ntohs(sll->sll_protocol)
+            << ", if_index:" << sll->sll_ifindex << ")";
+
+  ssize_t sent = api_->sendto(sockfd_, snd_buf.c_str(), snd_buf.length(), snd_flags_,
+                              reinterpret_cast<const struct sockaddr*>(&sll), sizeof(sll));
+  if (sent < 0) {
+    LOG(ERROR) << "Error-PacketSendTo(fd:" << sockfd_ << ") failed-" << "[" << errno << "]"
+               << strerror(errno);
+    return false;
+  }
+
+  LOG(INFO) << "Sent [" << sent << "] on fd:" << sockfd_;
+  return true;
+}
 bool SockScripter::PacketBind(char* arg) {
   std::string argstr = arg;
-  size_t col_pos = argstr.find_first_of(':');
-  if (col_pos == std::string::npos) {
-    LOG(ERROR) << "Error-Cannot parse packet-bind arg='" << argstr
-               << "' for <protocol>:<ifname> - missing separating colon ':'!";
+  std::optional<sockaddr_ll> sll = ParseSockAddrLlFromArg(argstr, api_);
+  if (!sll.has_value()) {
     return false;
   }
+  LOG(INFO) << "PacketBind(fd:" << sockfd_ << ", protocol:" << ntohs(sll->sll_protocol)
+            << ", if_index:" << sll->sll_ifindex << ")";
 
-  std::string protocol_str = argstr.substr(0, col_pos);
-  std::string ifname_str = argstr.substr(col_pos + 1);
-
-  int protocol;
-  if (!str2int(protocol_str, &protocol)) {
-    LOG(ERROR) << "Error-Cannot parse protocol number='" << protocol_str << "'!";
-    return false;
-  }
-
-  unsigned int if_index = 0;
-  if (!ifname_str.empty()) {
-    if_index = api_->if_nametoindex(ifname_str.c_str());
-    if (!if_index) {
-      LOG(ERROR) << "Error-if_nametoindex(" << ifname_str << ") failed -" << "[" << errno << "]"
-                 << strerror(errno);
-      return false;
-    }
-  }
-
-  const struct sockaddr_ll sll = {
-      .sll_family = AF_PACKET,
-      .sll_protocol = htons(static_cast<uint16_t>(protocol)),
-      .sll_ifindex = static_cast<int>(if_index),
-  };
-
-  LOG(INFO) << "PacketBind(fd:" << sockfd_ << ", protocol:" << protocol << ", if_index:" << if_index
-            << ")";
   if (api_->bind(sockfd_, reinterpret_cast<const struct sockaddr*>(&sll), sizeof(sll)) < 0) {
     LOG(ERROR) << "Error-PacketBind(fd:" << sockfd_ << ") failed-" << "[" << errno << "]"
                << strerror(errno);
@@ -829,7 +828,7 @@
 
   return true;
 }
-#endif
+#endif  // PACKET_SOCKETS
 
 bool SockScripter::Shutdown(char* arg) {
   std::string howStr(arg);
diff --git a/src/connectivity/network/tools/sockscripter/sockscripter.h b/src/connectivity/network/tools/sockscripter/sockscripter.h
index 52b9857d..d40cf66 100644
--- a/src/connectivity/network/tools/sockscripter/sockscripter.h
+++ b/src/connectivity/network/tools/sockscripter/sockscripter.h
@@ -104,6 +104,7 @@
 
 #if PACKET_SOCKETS
   bool PacketBind(char* arg);
+  bool PacketSendTo(char* arg);
 #endif
 
  private:
diff --git a/src/connectivity/network/tools/sockscripter/sockscripter_test.cc b/src/connectivity/network/tools/sockscripter/sockscripter_test.cc
index 78107ca..bb6d03a 100644
--- a/src/connectivity/network/tools/sockscripter/sockscripter_test.cc
+++ b/src/connectivity/network/tools/sockscripter/sockscripter_test.cc
@@ -9,6 +9,8 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include "testutil.h"
+
 #if PACKET_SOCKETS
 #include <netpacket/packet.h>
 #endif
@@ -38,79 +40,6 @@
   EXPECT_EQ(gen.GetSndStr(), "Packet number 10.");
 }
 
-class TestApi : ApiAbstraction {
- public:
-  MOCK_METHOD(int, socket, (int domain, int type, int protocol), (override));
-
-  MOCK_METHOD(int, close, (int fd), (override));
-
-  MOCK_METHOD(int, setsockopt,
-              (int fd, int level, int optname, const void* optval, socklen_t optlen), (override));
-
-  MOCK_METHOD(int, getsockopt, (int fd, int level, int optname, void* optval, socklen_t* optlen),
-              (override));
-
-  MOCK_METHOD(int, bind, (int fd, const struct sockaddr* addr, socklen_t len), (override));
-
-  MOCK_METHOD(int, shutdown, (int fd, int how), (override));
-
-  MOCK_METHOD(int, connect, (int fd, const struct sockaddr* addr, socklen_t len), (override));
-
-  MOCK_METHOD(int, accept, (int fd, struct sockaddr* addr, socklen_t* len), (override));
-
-  MOCK_METHOD(int, listen, (int fd, int backlog), (override));
-
-  MOCK_METHOD(ssize_t, send, (int fd, const void* buf, size_t len, int flags), (override));
-
-  MOCK_METHOD(ssize_t, sendto,
-              (int fd, const void* buf, size_t buflen, int flags, const struct sockaddr* addr,
-               socklen_t addrlen),
-              (override));
-
-  MOCK_METHOD(ssize_t, recv, (int fd, void* buf, size_t len, int flags), (override));
-
-  MOCK_METHOD(ssize_t, recvfrom,
-              (int fd, void* buf, size_t buflen, int flags, struct sockaddr* addr,
-               socklen_t* addrlen),
-              (override));
-
-  MOCK_METHOD(int, getsockname, (int fd, struct sockaddr* addr, socklen_t* len), (override));
-
-  MOCK_METHOD(int, getpeername, (int fd, struct sockaddr* addr, socklen_t* len), (override));
-
-  MOCK_METHOD(unsigned int, if_nametoindex, (const char* ifname), (override));
-
-  int RunCommandLine(const std::string& line) {
-    SockScripter scripter(this);
-
-    std::unique_ptr<char[]> parsing(new char[line.length() + 1]);
-    strcpy(parsing.get(), line.c_str());
-    auto* p = parsing.get();
-    char* start = nullptr;
-    char program[] = "sockscripter";
-    std::vector<char*> args;
-    args.push_back(program);
-
-    while (*p) {
-      if (!start) {
-        start = p;
-      }
-      if (*p == ' ') {
-        if (strlen(start)) {
-          args.push_back(start);
-          start = nullptr;
-        }
-        *p = '\0';
-      }
-      p++;
-    }
-    if (start && strlen(start)) {
-      args.push_back(start);
-    }
-    return scripter.Execute(static_cast<int>(args.size()), args.data());
-  }
-};
-
 std::string TestPacketNumber(int c) {
   std::stringstream ss;
   ss << "Packet number " << c << ".";
@@ -513,7 +442,37 @@
       .WillOnce(testing::Return(0));
   EXPECT_EQ(test.RunCommandLine("packet packet-bind 2048: recvfrom"), 0);
 }
-#endif
+
+TEST(CommandLine, PacketSendTo) {
+  constexpr unsigned int kIfIndex = 5;
+  constexpr uint16_t kIpv4Protocol = 2048;
+  testing::StrictMock<TestApi> test;
+  testing::InSequence s;
+  EXPECT_CALL(test, socket(AF_PACKET, SOCK_DGRAM, 0)).WillOnce(testing::Return(kSockFd));
+  EXPECT_CALL(test, if_nametoindex(testing::_)).WillOnce([](const char* ifname) {
+    EXPECT_EQ(std::string(ifname), "myinterfacename");
+    return kIfIndex;
+  });
+  EXPECT_CALL(test, sendto(kSockFd, testing::_, testing::_, testing::_, testing::_, testing::_))
+      .WillOnce([](testing::Unused, const void* buf, size_t len, testing::Unused,
+                   const struct sockaddr* addr, socklen_t addrlen) {
+        EXPECT_EQ(std::string(static_cast<const char*>(buf), len), TestPacketNumber(0));
+        const struct sockaddr_ll expected_addr = {
+            .sll_family = AF_PACKET,
+            .sll_protocol = htons(kIpv4Protocol),
+            .sll_ifindex = kIfIndex,
+        };
+        EXPECT_GE(addrlen, sizeof(expected_addr));
+        const auto& addr_ll = *reinterpret_cast<const struct sockaddr_ll*>(addr);
+        EXPECT_EQ(addr_ll.sll_family, expected_addr.sll_family);
+        EXPECT_EQ(addr_ll.sll_protocol, expected_addr.sll_protocol);
+        EXPECT_EQ(addr_ll.sll_ifindex, expected_addr.sll_ifindex);
+        return 0;
+      });
+  EXPECT_EQ(test.RunCommandLine("packet packet-send-to 2048:myinterfacename"), 0);
+}
+
+#endif  // PACKET_SOCKETS
 
 struct SockOptParam {
   SockOptParam(std::string name, std::string arg, int level, int optname,
diff --git a/src/connectivity/network/tools/sockscripter/testutil.h b/src/connectivity/network/tools/sockscripter/testutil.h
new file mode 100644
index 0000000..300ff7b
--- /dev/null
+++ b/src/connectivity/network/tools/sockscripter/testutil.h
@@ -0,0 +1,88 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_CONNECTIVITY_NETWORK_TOOLS_SOCKSCRIPTER_TESTUTIL_H_
+#define SRC_CONNECTIVITY_NETWORK_TOOLS_SOCKSCRIPTER_TESTUTIL_H_
+
+#include <string>
+
+#include <gmock/gmock.h>
+
+#include "api_abstraction.h"
+#include "sockscripter.h"
+
+class TestApi : public ApiAbstraction {
+ public:
+  MOCK_METHOD(int, socket, (int domain, int type, int protocol), (override));
+
+  MOCK_METHOD(int, close, (int fd), (override));
+
+  MOCK_METHOD(int, setsockopt,
+              (int fd, int level, int optname, const void* optval, socklen_t optlen), (override));
+
+  MOCK_METHOD(int, getsockopt, (int fd, int level, int optname, void* optval, socklen_t* optlen),
+              (override));
+
+  MOCK_METHOD(int, bind, (int fd, const struct sockaddr* addr, socklen_t len), (override));
+
+  MOCK_METHOD(int, shutdown, (int fd, int how), (override));
+
+  MOCK_METHOD(int, connect, (int fd, const struct sockaddr* addr, socklen_t len), (override));
+
+  MOCK_METHOD(int, accept, (int fd, struct sockaddr* addr, socklen_t* len), (override));
+
+  MOCK_METHOD(int, listen, (int fd, int backlog), (override));
+
+  MOCK_METHOD(ssize_t, send, (int fd, const void* buf, size_t len, int flags), (override));
+
+  MOCK_METHOD(ssize_t, sendto,
+              (int fd, const void* buf, size_t buflen, int flags, const struct sockaddr* addr,
+               socklen_t addrlen),
+              (override));
+
+  MOCK_METHOD(ssize_t, recv, (int fd, void* buf, size_t len, int flags), (override));
+
+  MOCK_METHOD(ssize_t, recvfrom,
+              (int fd, void* buf, size_t buflen, int flags, struct sockaddr* addr,
+               socklen_t* addrlen),
+              (override));
+
+  MOCK_METHOD(int, getsockname, (int fd, struct sockaddr* addr, socklen_t* len), (override));
+
+  MOCK_METHOD(int, getpeername, (int fd, struct sockaddr* addr, socklen_t* len), (override));
+
+  MOCK_METHOD(unsigned int, if_nametoindex, (const char* ifname), (override));
+
+  int RunCommandLine(const std::string& line) {
+    SockScripter scripter(this);
+
+    std::unique_ptr<char[]> parsing(new char[line.length() + 1]);
+    strcpy(parsing.get(), line.c_str());
+    auto* p = parsing.get();
+    char* start = nullptr;
+    char program[] = "sockscripter";
+    std::vector<char*> args;
+    args.push_back(program);
+
+    while (*p) {
+      if (!start) {
+        start = p;
+      }
+      if (*p == ' ') {
+        if (strlen(start)) {
+          args.push_back(start);
+          start = nullptr;
+        }
+        *p = '\0';
+      }
+      p++;
+    }
+    if (start && strlen(start)) {
+      args.push_back(start);
+    }
+    return scripter.Execute(static_cast<int>(args.size()), args.data());
+  }
+};
+
+#endif  // SRC_CONNECTIVITY_NETWORK_TOOLS_SOCKSCRIPTER_TESTUTIL_H_
diff --git a/src/connectivity/network/unified_binary/BUILD.gn b/src/connectivity/network/unified_binary/BUILD.gn
index 4a2911d..0c4d522 100644
--- a/src/connectivity/network/unified_binary/BUILD.gn
+++ b/src/connectivity/network/unified_binary/BUILD.gn
@@ -34,9 +34,12 @@
 
 config("config") {
   if (!is_debug) {
-    # Allow cross-crate optimization since each binary that is unified here is a
-    # different crate.
-    configs = [ "//build/config/lto:thinlto" ]
+    # Add thinlto config if lto variants are not used.
+    if (!is_lto_variant) {
+      # Allow cross-crate optimization since each binary that is unified here is a
+      # different crate.
+      configs = [ "//build/config/lto:thinlto" ]
+    }
   }
 
   visibility = [ ":*" ]
diff --git a/src/connectivity/policy/BUILD.gn b/src/connectivity/policy/BUILD.gn
index c81079e..abf9280 100644
--- a/src/connectivity/policy/BUILD.gn
+++ b/src/connectivity/policy/BUILD.gn
@@ -10,5 +10,6 @@
     "http-client:tests",
     "netcfg:tests",
     "reachability:tests",
+    "tests/integration:tests",
   ]
 }
diff --git a/src/connectivity/policy/tests/integration/BUILD.gn b/src/connectivity/policy/tests/integration/BUILD.gn
new file mode 100644
index 0000000..c4ed0ee
--- /dev/null
+++ b/src/connectivity/policy/tests/integration/BUILD.gn
@@ -0,0 +1,143 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/components.gni")
+import("//build/config.gni")
+import(
+    "//src/lib/testing/expectation/fuchsia_test_component_with_expectations.gni")
+import(
+    "//src/lib/testing/expectation/fuchsia_test_with_expectations_package.gni")
+
+tests = [ "reachability" ]
+
+tests_with_err_logs = [
+  {
+    label = "management"
+  },
+]
+
+foreach(test, tests) {
+  name = "policy-${test}-integration-test"
+  fuchsia_test_component_with_expectations(name) {
+    expectations = "expects/${name}.json5"
+    manifest = "meta/${name}.cml"
+    deps = [ test ]
+  }
+}
+
+foreach(test, tests_with_err_logs) {
+  name = "policy-${test.label}-integration-test"
+  fuchsia_test_component(name) {
+    manifest = "meta/${name}.cml"
+    deps = [ test.label ]
+  }
+}
+
+package_deps = [
+  # netemul-sandbox is used to create hermetic test realms.
+  "//src/connectivity/network/testing/netemul/service:netemul-sandbox",
+
+  # netstack3 is under test.
+  "//src/connectivity/network/netstack3:component",
+  "//src/connectivity/network/netstack3:component-debug",
+
+  # reachability monitor is under test.
+  "//src/connectivity/policy/reachability:component_with_fake_time",
+
+  # stash_secure is used by dhcpd and netstack.
+  "//src/sys/stash:stash_secure_v2",
+
+  # DHCPv4 Server is used to test DHCP address acquisition.
+  "//src/connectivity/network/dhcpv4/server:component",
+
+  # DHCP(v4) client is under test.
+  "//src/connectivity/network/dhcpv4/client/bindings:component",
+
+  # DHCPv6 client is under test.
+  "//src/connectivity/network/dhcpv6/client:component",
+
+  # dns_resolver integration with netstack is tested.
+  "//src/connectivity/network/dns:component_with_fake_time",
+
+  # the DNS resolver under test uses the fake clock.
+  "//src/lib/fake-clock/svc",
+
+  # netcfg integration with netstack is tested.
+  ":netcfg-netemul-configs",
+  "//src/connectivity/policy/netcfg:component-advanced",
+  "//src/connectivity/policy/netcfg:component-basic",
+]
+
+# RISC-V on Fuchsia does not support Golang.
+if (target_cpu != "riscv64") {
+  package_deps += [
+    "//src/connectivity/network/netstack:component",
+    "//src/connectivity/network/netstack:component-debug",
+    "//src/connectivity/network/netstack:component-with-fast-udp-debug",
+  ]
+}
+
+fuchsia_test_package("policy-integration-tests") {
+  test_components = []
+  foreach(test, tests) {
+    test_components += [ ":policy-${test}-integration-test" ]
+  }
+
+  deps = package_deps + [ "//src/lib/testing/expectation:expectation_comparer" ]
+}
+
+err_log_package_deps = []
+foreach(test, tests_with_err_logs) {
+  name = "policy-${test.label}-integration-test"
+  no_err_logs_package_name = "${name}-no-err-logs"
+  fuchsia_test_with_expectations_package(no_err_logs_package_name) {
+    test_components = [ ":${name}" ]
+    expectations = "expects/${name}.json5"
+    treatment_of_cases_with_error_logs = "SKIP_CASES_WITH_ERROR_LOGS"
+    deps =
+        package_deps + [ "//src/lib/testing/expectation:expectation_comparer" ]
+  }
+  with_err_logs_package_name = "${name}-with-err-logs"
+  fuchsia_test_with_expectations_package(with_err_logs_package_name) {
+    test_components = [ ":${name}" ]
+    expectations = "expects/${name}.json5"
+    treatment_of_cases_with_error_logs = "RUN_ONLY_CASES_WITH_ERROR_LOGS"
+    deps =
+        package_deps + [ "//src/lib/testing/expectation:expectation_comparer" ]
+    test_specs = {
+      log_settings = {
+        max_severity = "ERROR"
+      }
+    }
+  }
+  err_log_package_deps += [
+    ":${no_err_logs_package_name}",
+    ":${with_err_logs_package_name}",
+  ]
+}
+
+# Note: using configs in tests requires for this path to be added to
+# network/tests/integration/common/src/realms.rs with an enum type.
+resource("netcfg-netemul-configs") {
+  testonly = true
+
+  sources = [
+    "management/config/all_delegated.json",
+    "management/config/dhcpv6.json",
+    "management/config/duplicate_names.json",
+    "management/config/empty.json",
+    "management/config/forwarding.json",
+    "management/config/iface_prefix.json",
+    "management/config/packet_filter_ethernet.json",
+    "management/config/packet_filter_wlan.json",
+  ]
+
+  outputs = [ "netcfg/{{source_file_part}}" ]
+}
+
+group("tests") {
+  testonly = true
+
+  deps = [ ":policy-integration-tests" ] + err_log_package_deps
+}
diff --git a/src/connectivity/network/tests/integration/expects/netstack-management-integration-test.json5 b/src/connectivity/policy/tests/integration/expects/policy-management-integration-test.json5
similarity index 78%
rename from src/connectivity/network/tests/integration/expects/netstack-management-integration-test.json5
rename to src/connectivity/policy/tests/integration/expects/policy-management-integration-test.json5
index ea56803..21b82a1 100644
--- a/src/connectivity/network/tests/integration/expects/netstack-management-integration-test.json5
+++ b/src/connectivity/policy/tests/integration/expects/policy-management-integration-test.json5
@@ -17,10 +17,7 @@
                 // TODO(https://fxbug.dev/333528428): Remove filtering
                 // tests once `use_out_of_stack_dhcp_client` is aligned
                 // with NS2/NS3.
-                "test_filtering_udp_netcfg_advanced_ns3::both_no_filter",
-                "test_filtering_udp_netcfg_basic_ns3::both_no_filter",
-                "test_filtering_udp_netcfg_advanced_ns3::both_wlan_enabled",
-                "test_filtering_udp_netcfg_basic_ns3::both_wlan_enabled",
+                "test_filtering_udp_netcfg_*_ns3::*",
                 "test_oir_interface_name_conflict_uninstall_existing_netcfg_advanced_ns3",
                 "test_oir_interface_name_conflict_uninstall_existing_netcfg_basic_ns3",
                 "test_oir_interface_name_conflict_reject_netcfg_basic_ns2::*",
@@ -48,15 +45,6 @@
         {
             type: "expect_failure_with_err_logs",
             matchers: [
-                // TODO(https://fxbug.dev/42182576): Remove once NS3 stops
-                // serving a stub of filter.deprecated.
-                "test_filtering_udp_netcfg_advanced_ns3::receiver_eth_enabled",
-                "test_filtering_udp_netcfg_basic_ns3::receiver_eth_enabled",
-                "test_filtering_udp_netcfg_advanced_ns3::sender_eth_enabled",
-                "test_filtering_udp_netcfg_basic_ns3::sender_eth_enabled",
-                "test_filtering_udp_netcfg_advanced_ns3::both_eth_enabled",
-                "test_filtering_udp_netcfg_basic_ns3::both_eth_enabled",
-
                 // TODO(https://fxbug.dev/323052525): Remove once multicast
                 // forwarding is supported in interface configurations.
                 "test_forwarding_netcfg_advanced_ns3",
diff --git a/src/connectivity/policy/tests/integration/expects/policy-reachability-integration-test.json5 b/src/connectivity/policy/tests/integration/expects/policy-reachability-integration-test.json5
new file mode 100644
index 0000000..7f8aba6
--- /dev/null
+++ b/src/connectivity/policy/tests/integration/expects/policy-reachability-integration-test.json5
@@ -0,0 +1,13 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    actions: [
+        {
+            type: "expect_pass",
+            matchers: [
+                "*",
+            ],
+        },
+    ],
+}
diff --git a/src/connectivity/network/tests/integration/management/BUILD.gn b/src/connectivity/policy/tests/integration/management/BUILD.gn
similarity index 97%
rename from src/connectivity/network/tests/integration/management/BUILD.gn
rename to src/connectivity/policy/tests/integration/management/BUILD.gn
index 076bd1d..441b543 100644
--- a/src/connectivity/network/tests/integration/management/BUILD.gn
+++ b/src/connectivity/policy/tests/integration/management/BUILD.gn
@@ -6,7 +6,7 @@
 
 rustc_test("management") {
   edition = "2021"
-  output_name = "netstack_management_integration_test"
+  output_name = "policy_management_integration_test"
   deps = [
     "//sdk/fidl/fuchsia.hardware.network:fuchsia.hardware.network_rust",
     "//sdk/fidl/fuchsia.net:fuchsia.net_rust",
diff --git a/src/connectivity/network/tests/integration/management/config/all_delegated.json b/src/connectivity/policy/tests/integration/management/config/all_delegated.json
similarity index 100%
rename from src/connectivity/network/tests/integration/management/config/all_delegated.json
rename to src/connectivity/policy/tests/integration/management/config/all_delegated.json
diff --git a/src/connectivity/network/tests/integration/management/config/dhcpv6.json b/src/connectivity/policy/tests/integration/management/config/dhcpv6.json
similarity index 100%
rename from src/connectivity/network/tests/integration/management/config/dhcpv6.json
rename to src/connectivity/policy/tests/integration/management/config/dhcpv6.json
diff --git a/src/connectivity/network/tests/integration/management/config/duplicate_names.json b/src/connectivity/policy/tests/integration/management/config/duplicate_names.json
similarity index 100%
rename from src/connectivity/network/tests/integration/management/config/duplicate_names.json
rename to src/connectivity/policy/tests/integration/management/config/duplicate_names.json
diff --git a/src/connectivity/network/tests/integration/management/config/empty.json b/src/connectivity/policy/tests/integration/management/config/empty.json
similarity index 100%
rename from src/connectivity/network/tests/integration/management/config/empty.json
rename to src/connectivity/policy/tests/integration/management/config/empty.json
diff --git a/src/connectivity/network/tests/integration/management/config/forwarding.json b/src/connectivity/policy/tests/integration/management/config/forwarding.json
similarity index 100%
rename from src/connectivity/network/tests/integration/management/config/forwarding.json
rename to src/connectivity/policy/tests/integration/management/config/forwarding.json
diff --git a/src/connectivity/network/tests/integration/management/config/iface_prefix.json b/src/connectivity/policy/tests/integration/management/config/iface_prefix.json
similarity index 100%
rename from src/connectivity/network/tests/integration/management/config/iface_prefix.json
rename to src/connectivity/policy/tests/integration/management/config/iface_prefix.json
diff --git a/src/connectivity/network/tests/integration/management/config/packet_filter_ethernet.json b/src/connectivity/policy/tests/integration/management/config/packet_filter_ethernet.json
similarity index 100%
rename from src/connectivity/network/tests/integration/management/config/packet_filter_ethernet.json
rename to src/connectivity/policy/tests/integration/management/config/packet_filter_ethernet.json
diff --git a/src/connectivity/network/tests/integration/management/config/packet_filter_wlan.json b/src/connectivity/policy/tests/integration/management/config/packet_filter_wlan.json
similarity index 100%
rename from src/connectivity/network/tests/integration/management/config/packet_filter_wlan.json
rename to src/connectivity/policy/tests/integration/management/config/packet_filter_wlan.json
diff --git a/src/connectivity/network/tests/integration/management/src/lib.rs b/src/connectivity/policy/tests/integration/management/src/lib.rs
similarity index 98%
rename from src/connectivity/network/tests/integration/management/src/lib.rs
rename to src/connectivity/policy/tests/integration/management/src/lib.rs
index 5ed2433..958d9b8 100644
--- a/src/connectivity/network/tests/integration/management/src/lib.rs
+++ b/src/connectivity/policy/tests/integration/management/src/lib.rs
@@ -54,7 +54,7 @@
     nud::apply_nud_flake_workaround,
     realms::{
         KnownServiceProvider, ManagementAgent, Manager, ManagerConfig, NetCfgBasic, NetCfgVersion,
-        Netstack, Netstack3, NetstackVersion, TestRealmExt as _, TestSandboxExt,
+        Netstack, Netstack3, TestRealmExt as _, TestSandboxExt,
     },
     try_all, try_any, wait_for_component_stopped, ASYNC_EVENT_NEGATIVE_CHECK_TIMEOUT,
     ASYNC_EVENT_POSITIVE_CHECK_TIMEOUT,
@@ -349,23 +349,12 @@
         Some(())
     };
 
-    // TODO(https://fxbug.dev/42182576): Remove special case for NS3 once we
-    // stop serving filter.deprecated. Without this, there are spurious
-    // failures where the message is not received within the negative
-    // timeout window, causing the test to pass when it is expected to fail.
-    let timeout = match N::VERSION {
-        // Choose a timeout dependent on whether we are looking for a positive
-        // check (message was received) or negative check (message was dropped).
-        NetstackVersion::Netstack2 { .. } | NetstackVersion::ProdNetstack2 => {
-            if message_expected {
-                ASYNC_EVENT_POSITIVE_CHECK_TIMEOUT
-            } else {
-                ASYNC_EVENT_NEGATIVE_CHECK_TIMEOUT
-            }
-        }
-        NetstackVersion::Netstack3 | NetstackVersion::ProdNetstack3 => {
-            ASYNC_EVENT_POSITIVE_CHECK_TIMEOUT
-        }
+    // Choose a timeout dependent on whether we are looking for a positive
+    // check (message was received) or negative check (message was dropped).
+    let timeout = if message_expected {
+        ASYNC_EVENT_POSITIVE_CHECK_TIMEOUT
+    } else {
+        ASYNC_EVENT_NEGATIVE_CHECK_TIMEOUT
     };
 
     let ((), message_received) = futures::future::join(sender_fut, receiver_fut)
diff --git a/src/connectivity/network/tests/integration/management/src/virtualization.rs b/src/connectivity/policy/tests/integration/management/src/virtualization.rs
similarity index 99%
rename from src/connectivity/network/tests/integration/management/src/virtualization.rs
rename to src/connectivity/policy/tests/integration/management/src/virtualization.rs
index 25bd8ba..772629d 100644
--- a/src/connectivity/network/tests/integration/management/src/virtualization.rs
+++ b/src/connectivity/policy/tests/integration/management/src/virtualization.rs
@@ -574,7 +574,7 @@
             futures::future::ready(
                 match packet_formats::testutil::parse_ip_packet_in_ethernet_frame::<
                     net_types::ip::Ipv4,
-                >(&buf, EthernetFrameLengthCheck::Check)
+                >(&buf, EthernetFrameLengthCheck::NoCheck)
                 {
                     Ok((mut body, _src_mac, _dst_mac, src_ip, dst_ip, _proto, _ttl)) => {
                         match (&mut body).parse_with::<_, packet_formats::udp::UdpPacket<_>>(
diff --git a/src/connectivity/network/tests/integration/meta/netstack-management-integration-test.cml b/src/connectivity/policy/tests/integration/meta/policy-management-integration-test.cml
similarity index 91%
rename from src/connectivity/network/tests/integration/meta/netstack-management-integration-test.cml
rename to src/connectivity/policy/tests/integration/meta/policy-management-integration-test.cml
index 3d4bc6e..e2d986e 100644
--- a/src/connectivity/network/tests/integration/meta/netstack-management-integration-test.cml
+++ b/src/connectivity/policy/tests/integration/meta/policy-management-integration-test.cml
@@ -9,7 +9,7 @@
     ],
     program: {
         runner: "rust_test_runner",
-        binary: "bin/netstack_management_integration_test",
+        binary: "bin/policy_management_integration_test",
     },
     use: [
         {
diff --git a/src/connectivity/network/tests/integration/meta/netstack-reachability-integration-test.cml b/src/connectivity/policy/tests/integration/meta/policy-reachability-integration-test.cml
similarity index 87%
rename from src/connectivity/network/tests/integration/meta/netstack-reachability-integration-test.cml
rename to src/connectivity/policy/tests/integration/meta/policy-reachability-integration-test.cml
index 8d28b01..e7d74a0 100644
--- a/src/connectivity/network/tests/integration/meta/netstack-reachability-integration-test.cml
+++ b/src/connectivity/policy/tests/integration/meta/policy-reachability-integration-test.cml
@@ -9,6 +9,6 @@
     ],
     program: {
         runner: "rust_test_runner",
-        binary: "bin/netstack_reachability_integration_test",
+        binary: "bin/policy_reachability_integration_test",
     },
 }
diff --git a/src/connectivity/network/tests/integration/reachability/BUILD.gn b/src/connectivity/policy/tests/integration/reachability/BUILD.gn
similarity index 96%
rename from src/connectivity/network/tests/integration/reachability/BUILD.gn
rename to src/connectivity/policy/tests/integration/reachability/BUILD.gn
index 6eb36de..dae38d3 100644
--- a/src/connectivity/network/tests/integration/reachability/BUILD.gn
+++ b/src/connectivity/policy/tests/integration/reachability/BUILD.gn
@@ -6,7 +6,7 @@
 
 rustc_test("reachability") {
   edition = "2021"
-  output_name = "netstack_reachability_integration_test"
+  output_name = "policy_reachability_integration_test"
   deps = [
     "//sdk/fidl/fuchsia.net:fuchsia.net_rust",
     "//sdk/fidl/fuchsia.net.interfaces.admin:fuchsia.net.interfaces.admin_rust",
diff --git a/src/connectivity/network/tests/integration/reachability/src/lib.rs b/src/connectivity/policy/tests/integration/reachability/src/lib.rs
similarity index 99%
rename from src/connectivity/network/tests/integration/reachability/src/lib.rs
rename to src/connectivity/policy/tests/integration/reachability/src/lib.rs
index 7f61c65..3884b85 100644
--- a/src/connectivity/network/tests/integration/reachability/src/lib.rs
+++ b/src/connectivity/policy/tests/integration/reachability/src/lib.rs
@@ -104,7 +104,7 @@
         _,
         IcmpEchoRequest,
         _,
-    >(&frame, EthernetFrameLengthCheck::Check, |p| {
+    >(&frame, EthernetFrameLengthCheck::NoCheck, |p| {
         icmp_body.extend(p.body().bytes());
     });
     match r {
@@ -154,7 +154,7 @@
         _,
         IcmpEchoRequest,
         _,
-    >(&frame, EthernetFrameLengthCheck::Check, |p| {
+    >(&frame, EthernetFrameLengthCheck::NoCheck, |p| {
         icmp_body.extend(p.body().bytes());
     });
     match r {
diff --git a/src/connectivity/wlan/drivers/wlansoftmac/rust_driver/src/lib.rs b/src/connectivity/wlan/drivers/wlansoftmac/rust_driver/src/lib.rs
index bcdd6009..af579c9 100644
--- a/src/connectivity/wlan/drivers/wlansoftmac/rust_driver/src/lib.rs
+++ b/src/connectivity/wlan/drivers/wlansoftmac/rust_driver/src/lib.rs
@@ -345,7 +345,7 @@
                     Err(e) => {
                         error!("mlme_init_receiver interrupted: {}", e);
                         let status = zx::Status::INTERNAL;
-                    bridge.cancel().await;
+                        std::mem::drop(bridge);
                         init_completer.complete(Err(status));
                         return Err(status);
                     }
@@ -355,7 +355,7 @@
                         init_completer.complete(Ok(())),
                     Err(status) => {
                         error!("Failed to initialize MLME: {}", status);
-                    bridge.cancel().await;
+                        std::mem::drop(bridge);
                         init_completer.complete(Err(status));
                         return Err(status);
                     }
@@ -364,7 +364,7 @@
             mlme_result = mlme => {
                 error!("MLME future completed before signaling init_sender: {:?}", mlme_result);
                 let status = zx::Status::INTERNAL;
-                bridge.cancel().await;
+                std::mem::drop(bridge);
                 init_completer.complete(Err(status));
                 return Err(status);
             }
@@ -403,10 +403,7 @@
 
     // At this point, the `bridge` Task should not report a result because the WlanSoftmacIfcBridge
     // server is still running. This cancellation should cause `bridge_exit_receiver` to be dropped.
-    bridge
-        .cancel()
-        .await
-        .map(|()| warn!("SoftmacIfcBridge server task completed before cancelation."));
+    bridge.cancel().map(|()| warn!("SoftmacIfcBridge server task completed before cancelation."));
     let bridge_result: Result<(), ()> = match bridge_exit_receiver.await {
         Err(Canceled) => {
             // This is the expected case because when MLME shuts down, the SoftmacIfcBridge server
diff --git a/src/connectivity/wlan/lib/stash/src/policy.rs b/src/connectivity/wlan/lib/stash/src/policy.rs
index 61dbf6d..984a775 100644
--- a/src/connectivity/wlan/lib/stash/src/policy.rs
+++ b/src/connectivity/wlan/lib/stash/src/policy.rs
@@ -440,7 +440,7 @@
                         SecureStoreRequest::Identify { .. } => {}
                         SecureStoreRequest::CreateAccessor { accessor_request, .. } => {
                             let read_from_stash = read_from_stash.clone();
-                            fuchsia_async::EHandle::local().spawn_detached(async move {
+                            fuchsia_async::Task::spawn(async move {
                                 let mut request_stream = accessor_request.into_stream().unwrap();
                                 while let Some(request) = request_stream.next().await {
                                     match request.unwrap() {
@@ -452,7 +452,8 @@
                                         _ => unreachable!(),
                                     }
                                 }
-                            });
+                            })
+                            .detach();
                         }
                     }
                 }
diff --git a/src/connectivity/wlan/testing/wlan-service-util/BUILD.gn b/src/connectivity/wlan/testing/wlan-service-util/BUILD.gn
index 3134fd2..20baa0f 100644
--- a/src/connectivity/wlan/testing/wlan-service-util/BUILD.gn
+++ b/src/connectivity/wlan/testing/wlan-service-util/BUILD.gn
@@ -27,7 +27,6 @@
 
   test_deps = [
     "//src/lib/fuchsia-async",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:rand",
   ]
 
diff --git a/src/connectivity/wlan/tests/drivers-only/fullmac-tests/BUILD.gn b/src/connectivity/wlan/tests/drivers-only/fullmac-tests/BUILD.gn
index 3cca5a4..d054aa9 100644
--- a/src/connectivity/wlan/tests/drivers-only/fullmac-tests/BUILD.gn
+++ b/src/connectivity/wlan/tests/drivers-only/fullmac-tests/BUILD.gn
@@ -9,10 +9,13 @@
   binary_deps = [
     "//sdk/fidl/fuchsia.wlan.common:fuchsia.wlan.common_rust",
     "//sdk/fidl/fuchsia.wlan.fullmac:fuchsia.wlan.fullmac_rust",
+    "//sdk/fidl/fuchsia.wlan.sme:fuchsia.wlan.sme_rust",
     "//src/connectivity/wlan/lib/common/rust/:wlan-common",
     "//src/connectivity/wlan/tests/drivers-only/common",
     "//src/connectivity/wlan/tests/helpers/fullmac-helpers",
+    "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia",
+    "//src/lib/zircon/rust:fuchsia-zircon",
     "//third_party/rust_crates:futures",
     "//third_party/rust_crates:rand",
   ]
diff --git a/src/connectivity/wlan/tests/drivers-only/fullmac-tests/src/lib.rs b/src/connectivity/wlan/tests/drivers-only/fullmac-tests/src/lib.rs
index 2e12b92..2b75688 100644
--- a/src/connectivity/wlan/tests/drivers-only/fullmac-tests/src/lib.rs
+++ b/src/connectivity/wlan/tests/drivers-only/fullmac-tests/src/lib.rs
@@ -5,10 +5,11 @@
 use {
     drivers_only_common::DriversOnlyTestRealm,
     fidl_fuchsia_wlan_common as fidl_common, fidl_fuchsia_wlan_fullmac as fidl_fullmac,
+    fidl_fuchsia_wlan_sme as fidl_sme, fuchsia_zircon as zx,
     fullmac_helpers::config::{default_fullmac_query_info, FullmacDriverConfig},
     futures::StreamExt,
-    rand::seq::SliceRandom,
-    wlan_common::assert_variant,
+    rand::{seq::SliceRandom, Rng},
+    wlan_common::{assert_variant, random_fidl_bss_description},
 };
 
 #[fuchsia::test]
@@ -45,3 +46,138 @@
     assert_eq!(query_resp.role, config.query_info.role);
     assert_eq!(query_resp.sta_addr, config.query_info.sta_addr);
 }
+
+#[fuchsia::test]
+async fn test_scan_request_success() {
+    let realm = DriversOnlyTestRealm::new().await;
+
+    let config = FullmacDriverConfig { ..Default::default() };
+
+    let (mut fullmac_req_stream, fullmac_ifc_proxy, generic_sme_proxy) =
+        fullmac_helpers::create_fullmac_driver(&realm.testcontroller_proxy, &config).await;
+
+    let (client_sme_proxy, client_sme_server) =
+        fidl::endpoints::create_proxy().expect("Failed to create client SME proxy");
+    async {
+        generic_sme_proxy
+            .get_client_sme(client_sme_server)
+            .await
+            .expect("FIDL error")
+            .expect("GetClientSme Error")
+    }
+    .await;
+
+    let client_fut = async {
+        client_sme_proxy
+            .scan(&fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {}))
+            .await
+            .expect("FIDL error")
+            .expect("ScanRequest error")
+    };
+
+    let driver_fut = async {
+        let txn_id = assert_variant!(fullmac_req_stream.next().await,
+        Some(Ok(fidl_fullmac::WlanFullmacImplBridgeRequest::StartScan { payload, responder })) => {
+            assert_eq!(payload.scan_type.unwrap(), fidl_fullmac::WlanScanType::Passive);
+            responder
+                .send()
+                .expect("Failed to respond to StartScan");
+            payload.txn_id.expect("No txn_id found")
+        });
+
+        let scan_result_list = vec![
+            fidl_fullmac::WlanFullmacScanResult {
+                txn_id,
+                timestamp_nanos: zx::Time::get_monotonic().into_nanos(),
+                bss: random_fidl_bss_description!(),
+            },
+            fidl_fullmac::WlanFullmacScanResult {
+                txn_id,
+                timestamp_nanos: zx::Time::get_monotonic().into_nanos() + 1,
+                bss: random_fidl_bss_description!(),
+            },
+        ];
+
+        for scan_result in &scan_result_list {
+            fullmac_ifc_proxy
+                .on_scan_result(&scan_result)
+                .await
+                .expect("Failed to send on_scan_result");
+        }
+
+        fullmac_ifc_proxy
+            .on_scan_end(&fidl_fullmac::WlanFullmacScanEnd {
+                txn_id,
+                code: fidl_fullmac::WlanScanResult::Success,
+            })
+            .await
+            .expect("Failed to send on_scan_end");
+
+        scan_result_list
+    };
+
+    let (scan_result_vmo, expected_scan_result_list) = futures::join!(client_fut, driver_fut);
+    let scan_result_list =
+        wlan_common::scan::read_vmo(scan_result_vmo).expect("Could not read scan result VMO");
+
+    assert_eq!(scan_result_list.len(), expected_scan_result_list.len());
+    let expected_bss_descriptions: Vec<_> =
+        expected_scan_result_list.iter().map(|scan_result| scan_result.bss.clone()).collect();
+
+    for actual in scan_result_list {
+        // TODO(https://g-issues.fuchsia.dev/issues/42164608):  SME ignores timestamps so they
+        // aren't checked here.
+        // NOTE: order of returned scans is not guaranteed.
+        assert!(expected_bss_descriptions.contains(&actual.bss_description));
+    }
+}
+
+#[fuchsia::test]
+async fn test_scan_request_error() {
+    let realm = DriversOnlyTestRealm::new().await;
+
+    let config = FullmacDriverConfig { ..Default::default() };
+
+    let (mut fullmac_req_stream, fullmac_ifc_proxy, generic_sme_proxy) =
+        fullmac_helpers::create_fullmac_driver(&realm.testcontroller_proxy, &config).await;
+
+    let (client_sme_proxy, client_sme_server) =
+        fidl::endpoints::create_proxy().expect("Failed to create client SME proxy");
+    async {
+        generic_sme_proxy
+            .get_client_sme(client_sme_server)
+            .await
+            .expect("FIDL error")
+            .expect("GetClientSme Error")
+    }
+    .await;
+
+    let client_fut = async {
+        client_sme_proxy
+            .scan(&fidl_sme::ScanRequest::Passive(fidl_sme::PassiveScanRequest {}))
+            .await
+            .expect("FIDL error")
+    };
+
+    let driver_fut = async {
+        let txn_id = assert_variant!(fullmac_req_stream.next().await,
+        Some(Ok(fidl_fullmac::WlanFullmacImplBridgeRequest::StartScan { payload, responder })) => {
+            assert_eq!(payload.scan_type.unwrap(), fidl_fullmac::WlanScanType::Passive);
+            responder
+                .send()
+                .expect("Failed to respond to StartScan");
+            payload.txn_id.expect("No txn_id found")
+        });
+
+        fullmac_ifc_proxy
+            .on_scan_end(&fidl_fullmac::WlanFullmacScanEnd {
+                txn_id,
+                code: fidl_fullmac::WlanScanResult::NotSupported,
+            })
+            .await
+            .expect("Failed to send on_scan_end");
+    };
+
+    let (scan_result, _) = futures::join!(client_fut, driver_fut);
+    assert_eq!(scan_result.unwrap_err(), fidl_sme::ScanErrorCode::NotSupported);
+}
diff --git a/src/connectivity/wlan/tests/helpers/testcontroller-driver/driver.cc b/src/connectivity/wlan/tests/helpers/testcontroller-driver/driver.cc
index 30d396f..2745e4a 100644
--- a/src/connectivity/wlan/tests/helpers/testcontroller-driver/driver.cc
+++ b/src/connectivity/wlan/tests/helpers/testcontroller-driver/driver.cc
@@ -78,8 +78,15 @@
   }
 
   void OnScanResult(OnScanResultRequest& request, OnScanResultCompleter::Sync& completer) override {
+    WLAN_TRACE_DURATION();
+    bridge_client_->OnScanResult(request).ThenExactlyOnce(
+        ForwardResult<WlanFullmacImplIfc::OnScanResult>(completer.ToAsync()));
   }
-  void OnScanEnd(OnScanEndRequest& request, OnScanEndCompleter::Sync& completer) override {}
+  void OnScanEnd(OnScanEndRequest& request, OnScanEndCompleter::Sync& completer) override {
+    WLAN_TRACE_DURATION();
+    bridge_client_->OnScanEnd(request).ThenExactlyOnce(
+        ForwardResult<WlanFullmacImplIfc::OnScanEnd>(completer.ToAsync()));
+  }
   void ConnectConf(ConnectConfRequest& request, ConnectConfCompleter::Sync& completer) override {}
   void RoamConf(RoamConfRequest& request, RoamConfCompleter::Sync& completer) override {}
   void AuthInd(AuthIndRequest& request, AuthIndCompleter::Sync& completer) override {}
@@ -107,7 +114,7 @@
 
  private:
   fidl::ServerBinding<fuchsia_wlan_fullmac::WlanFullmacImplIfcBridge> binding_;
-  fdf::WireClient<fuchsia_wlan_fullmac::WlanFullmacImplIfc> bridge_client_;
+  fdf::Client<fuchsia_wlan_fullmac::WlanFullmacImplIfc> bridge_client_;
 };
 
 // Server that forwards calls from WlanFullmacImpl to WlanFullmacImplBridge.
@@ -185,7 +192,11 @@
     bridge_client_->QuerySpectrumManagementSupport().ThenExactlyOnce(
         ForwardResult<WlanFullmacImplBridge::QuerySpectrumManagementSupport>(completer.ToAsync()));
   }
-  void StartScan(StartScanRequest& request, StartScanCompleter::Sync& completer) override {}
+  void StartScan(StartScanRequest& request, StartScanCompleter::Sync& completer) override {
+    WLAN_TRACE_DURATION();
+    bridge_client_->StartScan(request).ThenExactlyOnce(
+        ForwardResult<WlanFullmacImplBridge::StartScan>(completer.ToAsync()));
+  }
   void Connect(ConnectRequest& request, ConnectCompleter::Sync& completer) override {
     WLAN_TRACE_DURATION();
     bridge_client_->Connect(request).ThenExactlyOnce(
diff --git a/src/connectivity/wlan/tools/wlantool/wlan_dev/src/lib.rs b/src/connectivity/wlan/tools/wlantool/wlan_dev/src/lib.rs
index 4b57ace..8d172b5 100644
--- a/src/connectivity/wlan/tools/wlantool/wlan_dev/src/lib.rs
+++ b/src/connectivity/wlan/tools/wlantool/wlan_dev/src/lib.rs
@@ -5,7 +5,6 @@
 use {
     anyhow::{format_err, Context as _, Error},
     fidl::endpoints,
-    fidl_fuchsia_wlan_common::PowerSaveType,
     fidl_fuchsia_wlan_common::{self as fidl_common, WlanMacRole},
     fidl_fuchsia_wlan_common_security as fidl_security,
     fidl_fuchsia_wlan_device_service::{
@@ -243,39 +242,6 @@
                 monitor_proxy.clear_country(&req).await.context("error clearing country")?;
             println!("response: {:?}", zx_status::Status::from_raw(response));
         }
-        opts::PhyCmd::SetPowerSaveMode { phy_id, mode } => {
-            println!("SetPSMode: phy_id {:?} ps_mode {:?}", phy_id, mode);
-            let req = wlan_service::SetPowerSaveModeRequest { phy_id, ps_mode: mode.into() };
-            let response =
-                monitor_proxy.set_power_save_mode(&req).await.context("error setting ps mode")?;
-            println!("response: {:?}", zx_status::Status::from_raw(response));
-        }
-        opts::PhyCmd::GetPowerSaveMode { phy_id } => {
-            let result =
-                monitor_proxy.get_power_save_mode(phy_id).await.context("error getting ps mode")?;
-            match result {
-                Ok(resp) => match resp.ps_mode {
-                    PowerSaveType::PsModePerformance => {
-                        println!("PS Mode Off");
-                    }
-                    PowerSaveType::PsModeBalanced => {
-                        println!("Medium PS Mode");
-                    }
-                    PowerSaveType::PsModeLowPower => {
-                        println!("Low Ps Mode");
-                    }
-                    PowerSaveType::PsModeUltraLowPower => {
-                        println!("Ultra low Ps Mode");
-                    }
-                },
-                Err(status) => {
-                    println!(
-                        "response: Failed with status {:?}",
-                        zx_status::Status::from_raw(status)
-                    );
-                }
-            }
-        }
     }
     Ok(())
 }
@@ -968,58 +934,6 @@
     }
 
     #[fuchsia::test]
-    fn test_get_power_save_mode() {
-        let mut exec = fasync::TestExecutor::new();
-        let (monitor_svc_local, monitor_svc_remote) =
-            create_proxy::<DeviceMonitorMarker>().expect("failed to create DeviceMonitor service");
-        let mut monitor_svc_stream =
-            monitor_svc_remote.into_stream().expect("failed to create stream");
-        let fut = do_phy(PhyCmd::GetPowerSaveMode { phy_id: 45 }, monitor_svc_local);
-        let mut fut = pin!(fut);
-
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-        assert_variant!(
-            exec.run_until_stalled(&mut monitor_svc_stream.next()),
-            Poll::Ready(Some(Ok(wlan_service::DeviceMonitorRequest::GetPowerSaveMode {
-                phy_id, responder,
-            }))) => {
-                assert_eq!(phy_id, 45);
-                responder.send(
-                     Ok(&fidl_fuchsia_wlan_device_service::GetPowerSaveModeResponse {
-                        ps_mode: PowerSaveType::PsModePerformance,
-                    })).expect("failed to send response");
-            }
-        );
-
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Ready(Ok(())));
-    }
-
-    #[fuchsia::test]
-    fn test_set_power_save_mode() {
-        let mut exec = fasync::TestExecutor::new();
-        let (monitor_svc_local, monitor_svc_remote) =
-            create_proxy::<DeviceMonitorMarker>().expect("failed to create DeviceMonitor service");
-        let mut monitor_svc_stream =
-            monitor_svc_remote.into_stream().expect("failed to create stream");
-        let fut = do_phy(
-            PhyCmd::SetPowerSaveMode { phy_id: 45, mode: PsModeArg::PsModeBalanced },
-            monitor_svc_local,
-        );
-        let mut fut = pin!(fut);
-
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-        assert_variant!(
-            exec.run_until_stalled(&mut monitor_svc_stream.next()),
-            Poll::Ready(Some(Ok(wlan_service::DeviceMonitorRequest::SetPowerSaveMode {
-                req, responder,
-            }))) => {
-                assert_eq!(req.phy_id, 45);
-                assert_eq!(req.ps_mode, PowerSaveType::PsModeBalanced);
-                responder.send(zx_status::Status::OK.into_raw()).expect("failed to send response");
-            }
-        );
-    }
-    #[fuchsia::test]
     fn test_generate_psk() {
         assert_eq!(
             generate_psk("12345678", "coolnet").unwrap(),
diff --git a/src/connectivity/wlan/tools/wlantool/wlan_dev/src/opts.rs b/src/connectivity/wlan/tools/wlantool/wlan_dev/src/opts.rs
index 5848210..cd8bb68 100644
--- a/src/connectivity/wlan/tools/wlantool/wlan_dev/src/opts.rs
+++ b/src/connectivity/wlan/tools/wlantool/wlan_dev/src/opts.rs
@@ -171,28 +171,6 @@
         /// id of the phy to query
         phy_id: u16,
     },
-    #[structopt(name = "set-ps-mode")]
-    /// sets the phy's power save mode
-    SetPowerSaveMode {
-        #[structopt(raw(required = "true"))]
-        /// id of the phy to query
-        phy_id: u16,
-        #[structopt(raw(required = "true"))]
-        #[structopt(
-            raw(possible_values = "&PsModeArg::variants()"),
-            raw(case_insensitive = "true"),
-            help = "Specify PS Mode"
-        )]
-        mode: PsModeArg,
-    },
-
-    #[structopt(name = "get-ps-mode")]
-    /// gets the phy's power save mode
-    GetPowerSaveMode {
-        #[structopt(raw(required = "true"))]
-        /// id of the phy to query
-        phy_id: u16,
-    },
 }
 
 #[derive(StructOpt, Clone, Debug, PartialEq)]
diff --git a/src/connectivity/wlan/wlancfg/BUILD.gn b/src/connectivity/wlan/wlancfg/BUILD.gn
index dfd81bd..bdead9c 100644
--- a/src/connectivity/wlan/wlancfg/BUILD.gn
+++ b/src/connectivity/wlan/wlancfg/BUILD.gn
@@ -29,7 +29,6 @@
     "//sdk/fidl/fuchsia.location.namedplace:fuchsia.location.namedplace_rust",
     "//sdk/fidl/fuchsia.location.sensor:fuchsia.location.sensor_rust",
     "//sdk/fidl/fuchsia.metrics:fuchsia.metrics_rust",
-    "//sdk/fidl/fuchsia.power.clientlevel:fuchsia.power.clientlevel_rust",
     "//sdk/fidl/fuchsia.wlan.common:fuchsia.wlan.common_rust",
     "//sdk/fidl/fuchsia.wlan.device.service:fuchsia.wlan.device.service_rust",
     "//sdk/fidl/fuchsia.wlan.ieee80211:fuchsia.wlan.ieee80211_rust",
@@ -109,7 +108,6 @@
     "src/mode_management/iface_manager.rs",
     "src/mode_management/iface_manager_api.rs",
     "src/mode_management/iface_manager_types.rs",
-    "src/mode_management/low_power_manager.rs",
     "src/mode_management/mod.rs",
     "src/mode_management/phy_manager.rs",
     "src/mode_management/recovery.rs",
@@ -151,8 +149,6 @@
     ":wlancfg-config",
     "//sdk/fidl/fuchsia.location.namedplace:fuchsia.location.namedplace_rust",
     "//sdk/fidl/fuchsia.metrics:fuchsia.metrics_rust",
-    "//sdk/fidl/fuchsia.power.clientlevel:fuchsia.power.clientlevel_rust",
-    "//sdk/fidl/fuchsia.wlan.common:fuchsia.wlan.common_rust",
     "//sdk/fidl/fuchsia.wlan.device.service:fuchsia.wlan.device.service_rust",
     "//sdk/fidl/fuchsia.wlan.policy:fuchsia.wlan.policy_rust",
     "//src/connectivity/wlan/lib/trace:wlan-trace",
diff --git a/src/connectivity/wlan/wlancfg/meta/wlancfg.cml b/src/connectivity/wlan/wlancfg/meta/wlancfg.cml
index faba745..4c84e76 100644
--- a/src/connectivity/wlan/wlancfg/meta/wlancfg.cml
+++ b/src/connectivity/wlan/wlancfg/meta/wlancfg.cml
@@ -39,7 +39,6 @@
                 "fuchsia.diagnostics.persist.DataPersistence-wlan",
                 "fuchsia.location.namedplace.RegulatoryRegionWatcher",
                 "fuchsia.metrics.MetricEventLoggerFactory",
-                "fuchsia.power.clientlevel.Connector",
                 "fuchsia.stash.SecureStore",
                 "fuchsia.wlan.device.service.DeviceMonitor",
             ],
diff --git a/src/connectivity/wlan/wlancfg/meta/wlancfg.core_shard.cml b/src/connectivity/wlan/wlancfg/meta/wlancfg.core_shard.cml
index 98e5e4c9..9d377ca 100644
--- a/src/connectivity/wlan/wlancfg/meta/wlancfg.core_shard.cml
+++ b/src/connectivity/wlan/wlancfg/meta/wlancfg.core_shard.cml
@@ -45,11 +45,6 @@
             to: "#wlancfg",
         },
         {
-            protocol: "fuchsia.power.clientlevel.Connector",
-            from: "parent",
-            to: "#wlancfg",
-        },
-        {
             storage: "data",
             from: "self",
             to: "#wlancfg",
diff --git a/src/connectivity/wlan/wlancfg/src/legacy/deprecated_configuration.rs b/src/connectivity/wlan/wlancfg/src/legacy/deprecated_configuration.rs
index c5856de..b33a8de 100644
--- a/src/connectivity/wlan/wlancfg/src/legacy/deprecated_configuration.rs
+++ b/src/connectivity/wlan/wlancfg/src/legacy/deprecated_configuration.rs
@@ -65,7 +65,7 @@
         },
         async_trait::async_trait,
         fidl::endpoints::create_proxy,
-        fidl_fuchsia_wlan_common as fidl_common, fuchsia_async as fasync, fuchsia_zircon as zx,
+        fuchsia_async as fasync,
         futures::task::Poll,
         std::pin::pin,
         std::unimplemented,
@@ -157,13 +157,6 @@
             unimplemented!();
         }
 
-        async fn set_power_state(
-            &mut self,
-            _low_power_enabled: fidl_common::PowerSaveType,
-        ) -> Result<zx::Status, anyhow::Error> {
-            unimplemented!();
-        }
-
         fn record_defect(&mut self, _defect: Defect) {
             unimplemented!();
         }
diff --git a/src/connectivity/wlan/wlancfg/src/main.rs b/src/connectivity/wlan/wlancfg/src/main.rs
index 4a8329d..ba549d24 100644
--- a/src/connectivity/wlan/wlancfg/src/main.rs
+++ b/src/connectivity/wlan/wlancfg/src/main.rs
@@ -10,7 +10,6 @@
     anyhow::{format_err, Context as _, Error},
     diagnostics_log::PublishOptions,
     fidl_fuchsia_location_namedplace::RegulatoryRegionWatcherMarker,
-    fidl_fuchsia_power_clientlevel as fidl_lp, fidl_fuchsia_wlan_common as fidl_common,
     fidl_fuchsia_wlan_device_service::DeviceMonitorMarker,
     fidl_fuchsia_wlan_policy as fidl_policy, fuchsia_async as fasync,
     fuchsia_async::DurationExt,
@@ -36,11 +35,8 @@
         config_management::{SavedNetworksManager, SavedNetworksManagerApi},
         legacy::{self, IfaceRef},
         mode_management::{
-            create_iface_manager, device_monitor,
-            iface_manager_api::IfaceManagerApi,
-            low_power_manager::PowerModeManager,
-            phy_manager::{PhyManager, PhyManagerApi},
-            recovery,
+            create_iface_manager, device_monitor, iface_manager_api::IfaceManagerApi,
+            phy_manager::PhyManager, recovery,
         },
         regulatory_manager::RegulatoryManager,
         telemetry::{
@@ -224,57 +220,6 @@
     Ok(())
 }
 
-// wlancfg can respond to low power services updates provided the service is available.  If the
-// service is not available, wlancfg will simply disable power save.  If the service is available,
-// wlancfg will listen for updates to WLAN power level and apply the desired power configuration
-// to all PHYs.
-async fn run_low_power_manager(
-    phy_manager: Arc<Mutex<PhyManager>>,
-    telemetry_sender: TelemetrySender,
-) -> Result<(), Error> {
-    // Check if the low power service is offered to wlancfg.
-    let req = match fuchsia_component::client::new_protocol_connector::<fidl_lp::ConnectorMarker>()
-    {
-        Ok(req) => req,
-        Err(e) => {
-            warn!("error probing low power client connector service: {:?}", e);
-            return Ok(());
-        }
-    };
-
-    // Only proceed with monitoring for updates if the Connector service exists and if we can
-    // connect to it.
-    if !req.exists().await.context("error checking for low power Connector existence")? {
-        warn!("Low power Connector is not available");
-        return Ok(());
-    }
-
-    // To ensure that the policy layer starts off in a known power state, set the PHYs to
-    // performance mode.
-    let mut phy_manager_lock = phy_manager.lock().await;
-    if let Err(e) =
-        phy_manager_lock.set_power_state(fidl_common::PowerSaveType::PsModePerformance).await
-    {
-        warn!("Failed to initialize PHYs to performance mode: {:?}", e);
-    }
-    drop(phy_manager_lock);
-
-    // At this point, the low power service is known to exist and wlancfg will attempt to monitor
-    // for low power updates and to apply the low power settings to all PHYs as new updates and
-    // new PHYs are discovered.  Any error in this process should be considered fatal.
-    let lp_connector = req.connect().context("Unable to connect to low power Connector service")?;
-    let (watcher_proxy, watcher_service) =
-        fidl::endpoints::create_proxy::<fidl_lp::WatcherMarker>()?;
-    if let Err(e) = lp_connector.connect(fidl_lp::ClientType::Wlan, watcher_service) {
-        warn!("Client level connector is unavailable: {:?}", e);
-        return Ok(());
-    }
-
-    let lp_manager = PowerModeManager::new(watcher_proxy, phy_manager, telemetry_sender);
-    lp_manager.run().await;
-    Ok(())
-}
-
 async fn run_all_futures() -> Result<(), Error> {
     let monitor_svc = fuchsia_component::client::connect_to_protocol::<DeviceMonitorMarker>()
         .context("failed to connect to device monitor")?;
@@ -446,7 +391,6 @@
 
     let saved_networks_metrics_fut = saved_networks_manager_metrics_loop(saved_networks.clone());
     let regulatory_fut = run_regulatory_manager(iface_manager.clone(), regulatory_sender);
-    let low_power_fut = run_low_power_manager(phy_manager.clone(), telemetry_sender);
 
     let _ = futures::try_join!(
         fidl_fut,
@@ -455,7 +399,6 @@
         saved_networks_metrics_fut.map(Ok),
         scanning_service,
         regulatory_fut,
-        low_power_fut,
         telemetry_fut.map(Ok),
         persistence_req_forwarder_fut.map(Ok),
         roam_manager_service_fut.map(Ok),
diff --git a/src/connectivity/wlan/wlancfg/src/mode_management/device_monitor.rs b/src/connectivity/wlan/wlancfg/src/mode_management/device_monitor.rs
index 3df15a1..f1d970e 100644
--- a/src/connectivity/wlan/wlancfg/src/mode_management/device_monitor.rs
+++ b/src/connectivity/wlan/wlancfg/src/mode_management/device_monitor.rs
@@ -858,13 +858,6 @@
             unimplemented!();
         }
 
-        async fn set_power_state(
-            &mut self,
-            _low_power_enabled: fidl_fuchsia_wlan_common::PowerSaveType,
-        ) -> Result<fuchsia_zircon::Status, anyhow::Error> {
-            unimplemented!();
-        }
-
         fn record_defect(&mut self, _defect: Defect) {
             unimplemented!();
         }
diff --git a/src/connectivity/wlan/wlancfg/src/mode_management/iface_manager.rs b/src/connectivity/wlan/wlancfg/src/mode_management/iface_manager.rs
index b55dc2b..32fcc59 100644
--- a/src/connectivity/wlan/wlancfg/src/mode_management/iface_manager.rs
+++ b/src/connectivity/wlan/wlancfg/src/mode_management/iface_manager.rs
@@ -1655,13 +1655,6 @@
             self.wpa3_iface.is_some()
         }
 
-        async fn set_power_state(
-            &mut self,
-            _low_power_enabled: fidl_fuchsia_wlan_common::PowerSaveType,
-        ) -> Result<fuchsia_zircon::Status, anyhow::Error> {
-            unimplemented!();
-        }
-
         fn record_defect(&mut self, defect: Defect) {
             self.defects.push(defect);
         }
diff --git a/src/connectivity/wlan/wlancfg/src/mode_management/low_power_manager.rs b/src/connectivity/wlan/wlancfg/src/mode_management/low_power_manager.rs
deleted file mode 100644
index 7de3a27..0000000
--- a/src/connectivity/wlan/wlancfg/src/mode_management/low_power_manager.rs
+++ /dev/null
@@ -1,399 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use {
-    crate::{mode_management::phy_manager::PhyManagerApi, telemetry},
-    fidl_fuchsia_power_clientlevel as fidl_power, fidl_fuchsia_wlan_common as fidl_common,
-    futures::lock::Mutex,
-    std::sync::Arc,
-    tracing::{info, warn},
-};
-
-fn power_level_to_mode(level: u64) -> fidl_common::PowerSaveType {
-    match level {
-        0 => fidl_common::PowerSaveType::PsModeUltraLowPower,
-        1 => fidl_common::PowerSaveType::PsModeLowPower,
-        2 => fidl_common::PowerSaveType::PsModeBalanced,
-        3 => fidl_common::PowerSaveType::PsModePerformance,
-        // Any power level that is implied to be higher than performance mode will be mapped to
-        // performance mode.
-        _ => fidl_common::PowerSaveType::PsModePerformance,
-    }
-}
-
-pub struct PowerModeManager<P: PhyManagerApi + ?Sized> {
-    power_watcher: fidl_power::WatcherProxy,
-    phy_manager: Arc<Mutex<P>>,
-    telemetry_sender: telemetry::TelemetrySender,
-}
-
-impl<P: PhyManagerApi + ?Sized> PowerModeManager<P> {
-    pub fn new(
-        power_watcher: fidl_power::WatcherProxy,
-        phy_manager: Arc<Mutex<P>>,
-        telemetry_sender: telemetry::TelemetrySender,
-    ) -> Self {
-        PowerModeManager { power_watcher, phy_manager, telemetry_sender }
-    }
-
-    pub async fn run(&self) {
-        let mut current_power_mode = None;
-
-        loop {
-            // Per the API specification, if a system does not have a WLAN power mode
-            // configuration, it will simply drop the channel.
-            let power_level = match self.power_watcher.watch().await {
-                Ok(level) => level,
-                Err(e) => {
-                    warn!("Error while waiting for low power state updates: {:?}", e);
-                    return;
-                }
-            };
-
-            let power_mode = power_level_to_mode(power_level);
-
-            info!("Received power level {}, setting power mode {:?}", power_level, power_mode);
-
-            let mut phy_manager = self.phy_manager.lock().await;
-            if let Err(e) = phy_manager.set_power_state(power_mode).await {
-                warn!("Failed to apply power mode {:?}: {:?}", power_mode, e);
-                continue;
-            }
-
-            if Some(power_mode) != current_power_mode {
-                self.telemetry_sender.send(telemetry::TelemetryEvent::UpdateExperiment {
-                    experiment: telemetry::experiment::ExperimentUpdate::Power(power_mode),
-                });
-                current_power_mode = Some(power_mode);
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use {
-        super::*,
-        crate::{
-            mode_management::{
-                phy_manager::{CreateClientIfacesReason, PhyManagerError},
-                recovery::RecoverySummary,
-                Defect,
-            },
-            regulatory_manager::REGION_CODE_LEN,
-        },
-        anyhow::format_err,
-        async_trait::async_trait,
-        fuchsia_zircon as zx,
-        futures::{channel::mpsc, task::Poll, StreamExt},
-        ieee80211::MacAddr,
-        std::pin::pin,
-        std::unimplemented,
-        test_case::test_case,
-        wlan_common::assert_variant,
-    };
-
-    #[test_case(0, fidl_common::PowerSaveType::PsModeUltraLowPower; "ps mode ultra low")]
-    #[test_case(1, fidl_common::PowerSaveType::PsModeLowPower; "ps mode low")]
-    #[test_case(2, fidl_common::PowerSaveType::PsModeBalanced; "ps mode medium")]
-    #[test_case(3, fidl_common::PowerSaveType::PsModePerformance; "ps mode high")]
-    #[test_case(9999, fidl_common::PowerSaveType::PsModePerformance; "ps mode higher than expected")]
-    fn test_power_level_conversion(level: u64, expected_mode: fidl_common::PowerSaveType) {
-        assert_eq!(power_level_to_mode(level), expected_mode)
-    }
-
-    struct TestValues {
-        phy_manager: FakePhyManager,
-        telemetry_sender: telemetry::TelemetrySender,
-        telemetry_receiver: mpsc::Receiver<telemetry::TelemetryEvent>,
-        watcher_proxy: fidl_power::WatcherProxy,
-        watcher_svc: fidl_power::WatcherRequestStream,
-    }
-
-    fn test_setup() -> TestValues {
-        let (watcher_proxy, watcher_svc) =
-            fidl::endpoints::create_proxy::<fidl_power::WatcherMarker>()
-                .expect("failed to create watcher.");
-        let watcher_svc = watcher_svc.into_stream().expect("failed to create watcher stream.");
-        let phy_manager = FakePhyManager::new();
-        let (mpsc_sender, telemetry_receiver) = mpsc::channel(10);
-        let telemetry_sender = telemetry::TelemetrySender::new(mpsc_sender);
-
-        TestValues { phy_manager, telemetry_sender, telemetry_receiver, watcher_proxy, watcher_svc }
-    }
-
-    #[fuchsia::test]
-    fn test_no_wlan_power_config() {
-        let mut exec = fuchsia_async::TestExecutor::new();
-        let test_vals = test_setup();
-
-        // Drop the watcher service end so that watcher update requests fail.
-        drop(test_vals.watcher_svc);
-
-        // Create a PowerModeManager and run it.
-        let lpm = PowerModeManager::new(
-            test_vals.watcher_proxy,
-            Arc::new(Mutex::new(test_vals.phy_manager)),
-            test_vals.telemetry_sender,
-        );
-        let fut = lpm.run();
-        let mut fut = pin!(fut);
-
-        // The future should exit immediately with an error since the low power state could not
-        // be queried.
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Ready(()))
-    }
-
-    #[fuchsia::test]
-    fn test_power_watcher_drops() {
-        let mut exec = fuchsia_async::TestExecutor::new();
-        let mut test_vals = test_setup();
-
-        // Create a PowerModeManager and run it.
-        let lpm = PowerModeManager::new(
-            test_vals.watcher_proxy,
-            Arc::new(Mutex::new(test_vals.phy_manager)),
-            test_vals.telemetry_sender,
-        );
-        let fut = lpm.run();
-        let mut fut = pin!(fut);
-
-        // The future should stall waiting for an update.
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-
-        // Read the watcher request and reply.
-        assert_variant!(
-            exec.run_until_stalled(&mut test_vals.watcher_svc.next()),
-            Poll::Ready(Some(Ok(fidl_power::WatcherRequest::Watch { responder }))) => {
-                responder
-                    .send(4_u64)
-                    .expect("failed to send power state");
-            }
-        );
-
-        // Drop the watcher service end so that the subsequent watcher update requests fail.
-        drop(test_vals.watcher_svc);
-
-        // The future should exit since this is presumed to be a platform for which WLAN power
-        // updates are available.
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Ready(()));
-
-        // Make sure the update to performance mode came through.
-        assert_variant!(
-            exec.run_until_stalled(&mut test_vals.telemetry_receiver.next()),
-            Poll::Ready(Some(telemetry::TelemetryEvent::UpdateExperiment {
-                experiment: telemetry::experiment::ExperimentUpdate::Power(
-                    fidl_common::PowerSaveType::PsModePerformance,
-                )
-            }))
-        );
-    }
-
-    #[fuchsia::test]
-    fn test_applying_power_setting_fails() {
-        let mut exec = fuchsia_async::TestExecutor::new();
-        let mut test_vals = test_setup();
-
-        // Configure the FakePhyManager so that setting the power state fails.
-        test_vals.phy_manager.set_power_succeeds = false;
-        let phy_manager = Arc::new(Mutex::new(test_vals.phy_manager));
-        let desired_power_state = fidl_common::PowerSaveType::PsModePerformance;
-
-        // Create a PowerModeManager and run it.
-        let lpm = PowerModeManager::new(
-            test_vals.watcher_proxy,
-            phy_manager.clone(),
-            test_vals.telemetry_sender,
-        );
-        let fut = lpm.run();
-        let mut fut = pin!(fut);
-
-        // The future should stall waiting for an update.
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-
-        // Read the watcher request and reply.
-        assert_variant!(
-            exec.run_until_stalled(&mut test_vals.watcher_svc.next()),
-            Poll::Ready(Some(Ok(fidl_power::WatcherRequest::Watch { responder }))) => {
-                responder
-                    .send(desired_power_state as u64)
-                    .expect("failed to send power state");
-            }
-        );
-
-        // The future should process the reply, fail to apply the change, and continue running.
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-
-        // There should not be a power state update since setting the power state failed.
-        assert_variant!(
-            exec.run_until_stalled(&mut test_vals.telemetry_receiver.next()),
-            Poll::Pending
-        );
-    }
-
-    #[test_case(fidl_common::PowerSaveType::PsModePerformance)]
-    #[test_case(fidl_common::PowerSaveType::PsModeBalanced)]
-    #[test_case(fidl_common::PowerSaveType::PsModeLowPower)]
-    #[test_case(fidl_common::PowerSaveType::PsModeUltraLowPower)]
-    fn test_applying_power_setting_succeeds(desired_power_state: fidl_common::PowerSaveType) {
-        let mut exec = fuchsia_async::TestExecutor::new();
-        let mut test_vals = test_setup();
-        let phy_manager = Arc::new(Mutex::new(test_vals.phy_manager));
-
-        // Create a PowerModeManager and run it.
-        let lpm = PowerModeManager::new(
-            test_vals.watcher_proxy,
-            phy_manager.clone(),
-            test_vals.telemetry_sender,
-        );
-        let fut = lpm.run();
-        let mut fut = pin!(fut);
-
-        // The future should stall waiting for an update.
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-
-        // Read the watcher request and reply.
-        assert_variant!(
-            exec.run_until_stalled(&mut test_vals.watcher_svc.next()),
-            Poll::Ready(Some(Ok(fidl_power::WatcherRequest::Watch { responder }))) => {
-                responder
-                    .send(desired_power_state as u64)
-                    .expect("failed to send power state");
-            }
-        );
-
-        // The future should process the reply, apply the change, and then wait for the next
-        // update.
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-
-        let phy_manager_fut = phy_manager.lock();
-        let mut phy_manager_fut = pin!(phy_manager_fut);
-        assert_variant!(
-            exec.run_until_stalled(&mut phy_manager_fut),
-            Poll::Ready(phy_manager) => {
-                assert_eq!(phy_manager.power_state, Some(desired_power_state))
-            }
-        );
-
-        // There should be a power state update indicating that the power mode has been changed.
-        assert_variant!(
-            exec.run_until_stalled(&mut test_vals.telemetry_receiver.next()),
-            Poll::Ready(Some(telemetry::TelemetryEvent::UpdateExperiment { experiment })) => {
-                assert_eq!(
-                    telemetry::experiment::ExperimentUpdate::Power(desired_power_state),
-                    experiment
-                );
-            }
-        );
-    }
-
-    #[derive(Debug)]
-    struct FakePhyManager {
-        power_state: Option<fidl_common::PowerSaveType>,
-        set_power_succeeds: bool,
-    }
-
-    impl FakePhyManager {
-        fn new() -> Self {
-            FakePhyManager { power_state: None, set_power_succeeds: true }
-        }
-    }
-
-    #[async_trait]
-    impl PhyManagerApi for FakePhyManager {
-        async fn add_phy(&mut self, _phy_id: u16) -> Result<(), PhyManagerError> {
-            unimplemented!();
-        }
-
-        fn remove_phy(&mut self, _phy_id: u16) {
-            unimplemented!();
-        }
-
-        async fn on_iface_added(&mut self, _iface_id: u16) -> Result<(), PhyManagerError> {
-            unimplemented!();
-        }
-
-        fn on_iface_removed(&mut self, _iface_id: u16) {
-            unimplemented!();
-        }
-
-        async fn create_all_client_ifaces(
-            &mut self,
-            _reason: CreateClientIfacesReason,
-        ) -> Result<Vec<u16>, (Vec<u16>, PhyManagerError)> {
-            unimplemented!();
-        }
-
-        fn client_connections_enabled(&self) -> bool {
-            unimplemented!();
-        }
-
-        async fn destroy_all_client_ifaces(&mut self) -> Result<(), PhyManagerError> {
-            unimplemented!();
-        }
-
-        fn get_client(&mut self) -> Option<u16> {
-            unimplemented!();
-        }
-
-        fn get_wpa3_capable_client(&mut self) -> Option<u16> {
-            unimplemented!();
-        }
-
-        async fn create_or_get_ap_iface(&mut self) -> Result<Option<u16>, PhyManagerError> {
-            unimplemented!();
-        }
-
-        async fn destroy_ap_iface(&mut self, _iface_id: u16) -> Result<(), PhyManagerError> {
-            unimplemented!();
-        }
-
-        async fn destroy_all_ap_ifaces(&mut self) -> Result<(), PhyManagerError> {
-            unimplemented!();
-        }
-
-        fn suggest_ap_mac(&mut self, _mac: MacAddr) {
-            unimplemented!();
-        }
-
-        fn get_phy_ids(&self) -> Vec<u16> {
-            unimplemented!();
-        }
-
-        fn log_phy_add_failure(&mut self) {
-            unimplemented!();
-        }
-
-        async fn set_country_code(
-            &mut self,
-            _country_code: Option<[u8; REGION_CODE_LEN]>,
-        ) -> Result<(), PhyManagerError> {
-            unimplemented!();
-        }
-
-        fn has_wpa3_client_iface(&self) -> bool {
-            unimplemented!();
-        }
-
-        async fn set_power_state(
-            &mut self,
-            power_state: fidl_common::PowerSaveType,
-        ) -> Result<fuchsia_zircon::Status, anyhow::Error> {
-            if self.set_power_succeeds {
-                self.power_state = Some(power_state);
-                Ok(zx::Status::OK)
-            } else {
-                Err(format_err!("failed to set power state"))
-            }
-        }
-
-        fn record_defect(&mut self, _defect: Defect) {
-            unimplemented!();
-        }
-
-        async fn perform_recovery(&mut self, _summary: RecoverySummary) {
-            unimplemented!();
-        }
-    }
-}
diff --git a/src/connectivity/wlan/wlancfg/src/mode_management/mod.rs b/src/connectivity/wlan/wlancfg/src/mode_management/mod.rs
index 6ed8fff..f5e2a55 100644
--- a/src/connectivity/wlan/wlancfg/src/mode_management/mod.rs
+++ b/src/connectivity/wlan/wlancfg/src/mode_management/mod.rs
@@ -22,7 +22,6 @@
 mod iface_manager;
 pub mod iface_manager_api;
 mod iface_manager_types;
-pub mod low_power_manager;
 pub mod phy_manager;
 pub mod recovery;
 
diff --git a/src/connectivity/wlan/wlancfg/src/mode_management/phy_manager.rs b/src/connectivity/wlan/wlancfg/src/mode_management/phy_manager.rs
index 693aa7b..20cbc5c 100644
--- a/src/connectivity/wlan/wlancfg/src/mode_management/phy_manager.rs
+++ b/src/connectivity/wlan/wlancfg/src/mode_management/phy_manager.rs
@@ -34,8 +34,6 @@
     PhyQueryFailure,
     #[error("failed to set country for new PHY")]
     PhySetCountryFailure,
-    #[error("unable to apply power setting")]
-    PhySetLowPowerFailure,
     #[error("unable to query iface information")]
     IfaceQueryFailure,
     #[error("unable to create iface")]
@@ -143,13 +141,6 @@
     /// Returns whether any PHY has a client interface that supports WPA3.
     fn has_wpa3_client_iface(&self) -> bool;
 
-    /// Sets the low power state for all PHYs.  PHYs discovered in the future will have the low
-    /// power setting applied to them as well.
-    async fn set_power_state(
-        &mut self,
-        power_state: fidl_common::PowerSaveType,
-    ) -> Result<fuchsia_zircon::Status, anyhow::Error>;
-
     /// Store a record for the provided defect.
     fn record_defect(&mut self, defect: Defect);
 
@@ -164,7 +155,6 @@
     recovery_enabled: bool,
     device_monitor: fidl_service::DeviceMonitorProxy,
     client_connections_enabled: bool,
-    power_state: fidl_common::PowerSaveType,
     suggested_ap_mac: Option<MacAddr>,
     saved_country_code: Option<[u8; REGION_CODE_LEN]>,
     _node: inspect::Node,
@@ -208,7 +198,6 @@
             recovery_enabled,
             device_monitor,
             client_connections_enabled: false,
-            power_state: fidl_common::PowerSaveType::PsModePerformance,
             suggested_ap_mac: None,
             saved_country_code: None,
             _node: node,
@@ -346,13 +335,6 @@
             };
         }
 
-        if self.power_state != fidl_common::PowerSaveType::PsModePerformance {
-            let ps_result = set_power_save_mode(&self.device_monitor, phy_id, self.power_state)
-                .await
-                .map_err(|_| PhyManagerError::PhySetLowPowerFailure)?;
-            fuchsia_zircon::ok(ps_result).map_err(|_| PhyManagerError::PhySetLowPowerFailure)?
-        }
-
         if self.phys.insert(phy_id, phy_container).is_some() {
             warn!("Unexpectedly replaced existing phy information for id {}", phy_id);
         };
@@ -719,23 +701,6 @@
         false
     }
 
-    async fn set_power_state(
-        &mut self,
-        power_state: fidl_common::PowerSaveType,
-    ) -> Result<fuchsia_zircon::Status, anyhow::Error> {
-        self.power_state = power_state;
-        let mut final_status = fuchsia_zircon::Status::OK;
-
-        for phy_id in self.phys.keys() {
-            let result = set_power_save_mode(&self.device_monitor, *phy_id, power_state).await?;
-            if let Err(status) = fuchsia_zircon::ok(result) {
-                final_status = status;
-            }
-        }
-
-        Ok(final_status)
-    }
-
     fn record_defect(&mut self, defect: Defect) {
         let mut recovery_action = None;
 
@@ -948,15 +913,6 @@
     })
 }
 
-async fn set_power_save_mode(
-    proxy: &fidl_service::DeviceMonitorProxy,
-    phy_id: u16,
-    state: fidl_common::PowerSaveType,
-) -> Result<i32, anyhow::Error> {
-    let req = fidl_service::SetPowerSaveModeRequest { phy_id, ps_mode: state };
-    proxy.set_power_save_mode(&req).await.map_err(|e| e.into())
-}
-
 #[cfg(test)]
 mod tests {
     use {
@@ -3613,234 +3569,6 @@
         assert!(!phy_manager.client_connections_enabled());
     }
 
-    /// Tests the case where setting low power state succeeds.
-    #[fuchsia::test]
-    fn test_succeed_in_setting_power_state() {
-        let mut exec = TestExecutor::new();
-        let mut test_values = test_setup();
-        let mut phy_manager = PhyManager::new(
-            test_values.monitor_proxy,
-            recovery::lookup_recovery_profile(""),
-            false,
-            test_values.node,
-            test_values.telemetry_sender,
-            test_values.recovery_sender,
-        );
-
-        assert_eq!(phy_manager.power_state, fidl_common::PowerSaveType::PsModePerformance);
-
-        // Add a couple of PHYs.
-        let mut phy_ids = HashSet::<u16>::new();
-        let _ = phy_ids.insert(0);
-        let _ = phy_ids.insert(1);
-        for id in phy_ids.iter() {
-            let phy_container = PhyContainer::new(vec![]);
-            let _ = phy_manager.phys.insert(*id, phy_container);
-        }
-
-        {
-            // Set low power state on the PHYs.
-            let fut = phy_manager.set_power_state(fidl_common::PowerSaveType::PsModeLowPower);
-
-            // The future should run until it stalls out requesting that one of the PHYs set its low
-            // power mode.
-            let mut fut = pin!(fut);
-
-            for _ in 0..phy_ids.len() {
-                assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-                assert_variant!(
-                    exec.run_until_stalled(&mut test_values.monitor_stream.next()),
-                    Poll::Ready(Some(Ok(
-                        fidl_service::DeviceMonitorRequest::SetPowerSaveMode {
-                            req: fidl_service::SetPowerSaveModeRequest { phy_id, ps_mode },
-                            responder,
-                        }
-                    ))) => {
-                        assert!(phy_ids.remove(&phy_id));
-                        assert_eq!(ps_mode, fidl_common::PowerSaveType::PsModeLowPower);
-                        responder.send(ZX_OK).expect("sending fake set PS mode response");
-                    }
-                )
-            }
-
-            assert_variant!(
-                exec.run_until_stalled(&mut fut),
-                Poll::Ready(Ok(fuchsia_zircon::Status::OK))
-            );
-        }
-        assert_eq!(phy_manager.power_state, fidl_common::PowerSaveType::PsModeLowPower);
-    }
-
-    /// Tests the case where setting low power state fails.
-    #[fuchsia::test]
-    fn test_fail_to_set_power_state() {
-        let mut exec = TestExecutor::new();
-        let mut test_values = test_setup();
-        let mut phy_manager = PhyManager::new(
-            test_values.monitor_proxy,
-            recovery::lookup_recovery_profile(""),
-            false,
-            test_values.node,
-            test_values.telemetry_sender,
-            test_values.recovery_sender,
-        );
-
-        assert_eq!(phy_manager.power_state, fidl_common::PowerSaveType::PsModePerformance);
-
-        // Add a couple of PHYs.
-        let mut phy_ids = HashSet::<u16>::new();
-        let _ = phy_ids.insert(0);
-        let _ = phy_ids.insert(1);
-        for id in phy_ids.iter() {
-            let phy_container = PhyContainer::new(vec![]);
-            let _ = phy_manager.phys.insert(*id, phy_container);
-        }
-
-        {
-            // Set low power state on the PHYs.
-            let fut = phy_manager.set_power_state(fidl_common::PowerSaveType::PsModeLowPower);
-
-            // The future should run until it stalls out requesting that one of the PHYs set its low
-            // power mode.
-            let mut fut = pin!(fut);
-
-            for _ in 0..phy_ids.len() {
-                assert_variant!(exec.run_until_stalled(&mut fut), Poll::Pending);
-                assert_variant!(
-                    exec.run_until_stalled(&mut test_values.monitor_stream.next()),
-                    Poll::Ready(Some(Ok(
-                        fidl_service::DeviceMonitorRequest::SetPowerSaveMode {
-                            req: fidl_service::SetPowerSaveModeRequest { phy_id, ps_mode },
-                            responder,
-                        }
-                    ))) => {
-                        assert!(phy_ids.remove(&phy_id));
-                        assert_eq!(ps_mode, fidl_common::PowerSaveType::PsModeLowPower);
-
-                        // Send back a failure for one of the PHYs
-                        if phy_id == 0 {
-                            responder.send(ZX_OK).expect("sending fake set PS mode response");
-                        } else {
-                            responder
-                                .send(ZX_ERR_NOT_FOUND)
-                                .expect("sending negativefake set PS mode response");
-                        }
-                    }
-                )
-            }
-
-            // An error should be reported due to the failure to set the power mode on one of the
-            // PHYs.
-            assert_variant!(
-                exec.run_until_stalled(&mut fut),
-                Poll::Ready(Ok(fuchsia_zircon::Status::NOT_FOUND))
-            );
-        }
-        assert_eq!(phy_manager.power_state, fidl_common::PowerSaveType::PsModeLowPower);
-    }
-
-    /// Tests the case where the request cannot be made to configure low power mode for a PHY.
-    #[fuchsia::test]
-    fn test_fail_to_request_low_power_mode() {
-        let mut exec = TestExecutor::new();
-        let test_values = test_setup();
-        let mut phy_manager = PhyManager::new(
-            test_values.monitor_proxy,
-            recovery::lookup_recovery_profile(""),
-            false,
-            test_values.node,
-            test_values.telemetry_sender,
-            test_values.recovery_sender,
-        );
-
-        // Drop the receiving end of the device monitor channel.
-        drop(test_values.monitor_stream);
-
-        // Add a couple of PHYs.
-        let mut phy_ids = HashSet::<u16>::new();
-        let _ = phy_ids.insert(0);
-        let _ = phy_ids.insert(1);
-        for id in phy_ids.iter() {
-            let phy_container = PhyContainer::new(vec![]);
-            let _ = phy_manager.phys.insert(*id, phy_container);
-        }
-
-        // Set low power state on the PHYs.
-        let fut = phy_manager.set_power_state(fidl_common::PowerSaveType::PsModePerformance);
-
-        // The future should run until it stalls out requesting that one of the PHYs set its low
-        // power mode.
-        let mut fut = pin!(fut);
-        assert_variant!(exec.run_until_stalled(&mut fut), Poll::Ready(Err(_)));
-    }
-
-    /// Tests the case where a PHY is added after the low power state has been enabled.
-    #[fuchsia::test]
-    fn test_add_phy_after_low_power_enabled() {
-        let mut exec = TestExecutor::new();
-        let mut test_values = test_setup();
-        let mut phy_manager = PhyManager::new(
-            test_values.monitor_proxy,
-            recovery::lookup_recovery_profile(""),
-            false,
-            test_values.node,
-            test_values.telemetry_sender,
-            test_values.recovery_sender,
-        );
-
-        assert_eq!(phy_manager.power_state, fidl_common::PowerSaveType::PsModePerformance);
-
-        // Enable low power mode which should complete immediately.
-        {
-            let fut = phy_manager.set_power_state(fidl_common::PowerSaveType::PsModeBalanced);
-            let mut fut = pin!(fut);
-            assert_variant!(
-                exec.run_until_stalled(&mut fut),
-                Poll::Ready(Ok(fuchsia_zircon::Status::OK))
-            );
-        }
-
-        assert_eq!(phy_manager.power_state, fidl_common::PowerSaveType::PsModeBalanced);
-
-        // Add a new PHY and ensure that the low power mode is set
-        {
-            let add_phy_fut = phy_manager.add_phy(0);
-            let mut add_phy_fut = pin!(add_phy_fut);
-            assert!(exec.run_until_stalled(&mut add_phy_fut).is_pending());
-
-            send_get_supported_mac_roles_response(
-                &mut exec,
-                &mut test_values.monitor_stream,
-                Ok(&[]),
-            );
-
-            // There should be a stall as the low power mode is requested.
-            assert_variant!(exec.run_until_stalled(&mut add_phy_fut), Poll::Pending);
-            assert_variant!(
-                exec.run_until_stalled(&mut test_values.monitor_stream.next()),
-                Poll::Ready(Some(Ok(
-                    fidl_service::DeviceMonitorRequest::SetPowerSaveMode {
-                        req: fidl_service::SetPowerSaveModeRequest { phy_id, ps_mode },
-                        responder,
-                    }
-                ))) => {
-                    assert_eq!(ps_mode, fidl_common::PowerSaveType::PsModeBalanced);
-
-                    // Send back a failure for one of the PHYs
-                    if phy_id == 0 {
-                        responder.send(ZX_OK).expect("sending fake set PS mode response");
-                    } else {
-                        responder
-                            .send(ZX_ERR_NOT_FOUND)
-                            .expect("sending negativefake set PS mode response");
-                    }
-                }
-            );
-
-            assert!(exec.run_until_stalled(&mut add_phy_fut).is_ready());
-        }
-    }
-
     #[fuchsia::test]
     fn test_create_iface_succeeds() {
         let mut exec = TestExecutor::new();
diff --git a/src/connectivity/wlan/wlancfg/tool/BUILD.gn b/src/connectivity/wlan/wlancfg/tool/BUILD.gn
index b5c7234..9ce5d49 100644
--- a/src/connectivity/wlan/wlancfg/tool/BUILD.gn
+++ b/src/connectivity/wlan/wlancfg/tool/BUILD.gn
@@ -10,12 +10,6 @@
   deps = [ "policy:donut-lib-tests" ]
 }
 
-# Enabling a soft-transition, remove when complete
-# TODO(122864) Remove transitional labels
-group("for_transition") {
-  public_deps = [ ":donut" ]
-}
-
 fuchsia_package("donut") {
   deps = [ "cli:bin" ]
 }
diff --git a/src/developer/adb/bin/adb-file-sync/adb-file-sync-test.cc b/src/developer/adb/bin/adb-file-sync/adb-file-sync-test.cc
index d9de438..9951e57 100644
--- a/src/developer/adb/bin/adb-file-sync/adb-file-sync-test.cc
+++ b/src/developer/adb/bin/adb-file-sync/adb-file-sync-test.cc
@@ -79,11 +79,10 @@
   }
 
   zx::channel BindServer() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     binding_ref_ = std::make_unique<fidl::ServerBindingRef<fuchsia_io::Directory>>(
-        fidl::BindServer(dispatcher_, std::move(endpoints->server), this));
-    return endpoints->client.TakeChannel();
+        fidl::BindServer(dispatcher_, std::move(endpoints.server), this));
+    return endpoints.client.TakeChannel();
   }
 
   void TearDown() {
diff --git a/src/developer/adb/bin/adb-shell/adb-shell-test.cc b/src/developer/adb/bin/adb-shell/adb-shell-test.cc
index 7768741..56212c3 100644
--- a/src/developer/adb/bin/adb-shell/adb-shell-test.cc
+++ b/src/developer/adb/bin/adb-shell/adb-shell-test.cc
@@ -101,18 +101,15 @@
   void SetUp() override {
     shell_loop_.StartThread("adb-shell-test-shell");
     incoming_ = std::make_unique<component::OutgoingDirectory>(dispatcher());
-    auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_TRUE(svc_endpoints.is_ok());
-    SetupIncomingServices(std::move(svc_endpoints->server));
+    auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    SetupIncomingServices(std::move(svc_endpoints.server));
     adb_ = std::make_unique<adb_shell::AdbShell>(
-        std::move(svc_endpoints->client), shell_loop_.dispatcher(), adb_shell_config::Config());
+        std::move(svc_endpoints.client), shell_loop_.dispatcher(), adb_shell_config::Config());
     ASSERT_NO_FAILURES();
   }
 
   void SetupIncomingServices(fidl::ServerEnd<fuchsia_io::Directory> svc) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_io::Directory>::Create();
     ASSERT_OK(incoming_->AddUnmanagedProtocol<fuchsia_dash::Launcher>(
         [this](fidl::ServerEnd<fuchsia_dash::Launcher> server_end) {
           fake_dash_launcher_.BindServer(dispatcher(), std::move(server_end));
diff --git a/src/developer/adb/drivers/usb-adb-function/adb-function-test.cc b/src/developer/adb/drivers/usb-adb-function/adb-function-test.cc
index 738c4db..fdcf2ac 100644
--- a/src/developer/adb/drivers/usb-adb-function/adb-function-test.cc
+++ b/src/developer/adb/drivers/usb-adb-function/adb-function-test.cc
@@ -155,9 +155,8 @@
 
     parent_->AddProtocol(ZX_PROTOCOL_USB_FUNCTION, mock_usb_.GetProto()->ops,
                          mock_usb_.GetProto()->ctx);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
-    incoming_.SyncCall([server = std::move(endpoints->server)](IncomingNamespace* infra) mutable {
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    incoming_.SyncCall([server = std::move(endpoints.server)](IncomingNamespace* infra) mutable {
       ASSERT_OK(
           infra->outgoing.template AddService<fuchsia_hardware_usb_function::UsbFunctionService>(
               fuchsia_hardware_usb_function::UsbFunctionService::InstanceHandler({
@@ -169,7 +168,7 @@
       ASSERT_OK(infra->outgoing.Serve(std::move(server)));
     });
     parent_->AddFidlService(fuchsia_hardware_usb_function::UsbFunctionService::Name,
-                            std::move(endpoints->client));
+                            std::move(endpoints.client));
 
     // Expect calls from UsbAdbDevice initialization
     mock_usb_.ExpectAllocInterface(ZX_OK, 1);
diff --git a/src/developer/debug/debug_agent/launcher.cc b/src/developer/debug/debug_agent/launcher.cc
index 2abdae2..fb761f0 100644
--- a/src/developer/debug/debug_agent/launcher.cc
+++ b/src/developer/debug/debug_agent/launcher.cc
@@ -66,7 +66,7 @@
 
   fuchsia_component_decl::ChildRef child_ref(name, kCollectionName);
 
-  auto [dir_client_end, dir_server_end] = *fidl::CreateEndpoints<fuchsia_io::Directory>();
+  auto [dir_client_end, dir_server_end] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   realm->OpenExposedDir({{.child = child_ref, .exposed_dir = std::move(dir_server_end)}})
       .Then([name, server_end = std::move(server_end), dir_client_end = std::move(dir_client_end),
@@ -97,7 +97,7 @@
                                                    async_get_default_dispatcher());
 
       fuchsia_component_decl::CollectionRef collection(kCollectionName);
-      auto [client_end, server_end] = *fidl::CreateEndpoints<fuchsia_component::ChildIterator>();
+      auto [client_end, server_end] = fidl::Endpoints<fuchsia_component::ChildIterator>::Create();
 
       child_iterator_ = fidl::Client(std::move(client_end), async_get_default_dispatcher());
 
@@ -154,7 +154,7 @@
     bool completer_called = false;
 
     for (auto it = children.begin(); it != children.end(); ++it) {
-      auto [client_end, server_end] = *fidl::CreateEndpoints<fuchsia_debugger::DebugAgent>();
+      auto [client_end, server_end] = fidl::Endpoints<fuchsia_debugger::DebugAgent>::Create();
 
       if (!completer_called) {
         batch.emplace_back(it->name(), std::move(client_end));
@@ -208,7 +208,7 @@
                                                async_get_default_dispatcher());
 
   auto [controller_client_end, controller_server_end] =
-      *fidl::CreateEndpoints<fuchsia_component::Controller>();
+      fidl::Endpoints<fuchsia_component::Controller>::Create();
 
   fidl::Client<fuchsia_component::Controller> controller(std::move(controller_client_end),
                                                          async_get_default_dispatcher());
@@ -251,7 +251,7 @@
 
               // Otherwise, we need to explicitly start the child.
               auto [exec_controller_client, exec_controller_server] =
-                  *fidl::CreateEndpoints<fuchsia_component::ExecutionController>();
+                  fidl::Endpoints<fuchsia_component::ExecutionController>::Create();
               fidl::Client<fuchsia_component::ExecutionController> execution_controller(
                   std::move(exec_controller_client), async_get_default_dispatcher());
 
diff --git a/src/developer/debug/debug_agent/test_data/BUILD.gn b/src/developer/debug/debug_agent/test_data/BUILD.gn
index 5ae69c7..7b321d0 100644
--- a/src/developer/debug/debug_agent/test_data/BUILD.gn
+++ b/src/developer/debug/debug_agent/test_data/BUILD.gn
@@ -119,8 +119,6 @@
     ":limbo_caller",
     ":multi_threaded",
     ":printer",
-    ":process_loop",
-    ":process_spawner",
     ":test_suite",
     ":thread_signals",
   ]
@@ -190,24 +188,6 @@
   sources = [ "printer.cc" ]
 }
 
-executable("process_loop") {
-  output_name = "process_loop"
-
-  sources = [ "process_loop.cc" ]
-}
-
-executable("process_spawner") {
-  output_name = "process_spawner"
-
-  sources = [ "process_spawner.cc" ]
-
-  deps = [
-    "//sdk/lib/fdio",
-    "//src/lib/fxl",
-    "//zircon/system/ulib/zx",
-  ]
-}
-
 executable("thread_signals") {
   output_name = "thread_signals"
 
diff --git a/src/developer/debug/debug_agent/test_data/process_loop.cc b/src/developer/debug/debug_agent/test_data/process_loop.cc
deleted file mode 100644
index e000680..0000000
--- a/src/developer/debug/debug_agent/test_data/process_loop.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdio.h>
-#include <unistd.h>
-
-#include <string>
-
-constexpr int kLimit = 20;
-
-void Print(int i) {
-  printf("Iteration %d/%d\n", i + 1, kLimit);
-  fflush(stdout);
-}
-
-int main(int argc, char* argv[]) {
-  int iterations = kLimit;
-  if (argc == 2)
-    iterations = std::stoi(argv[1]);
-
-  // Run for 20 seconds and then end.
-  for (int i = 0; i < iterations; i++) {
-    Print(i);
-    sleep(1);
-  }
-}
diff --git a/src/developer/debug/debug_agent/test_data/process_spawner.cc b/src/developer/debug/debug_agent/test_data/process_spawner.cc
deleted file mode 100644
index 51505e6..0000000
--- a/src/developer/debug/debug_agent/test_data/process_spawner.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <lib/fdio/spawn.h>
-#include <lib/syslog/cpp/macros.h>
-#include <lib/zx/job.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <zircon/processargs.h>
-#include <zircon/status.h>
-#include <zircon/syscalls.h>
-#include <zircon/syscalls/object.h>
-
-#include <iostream>
-#include <iterator>
-#include <vector>
-
-#include "src/lib/fxl/strings/string_printf.h"
-
-// ProcessSpawner is a simple utility that waits for user input on stdin and
-// creates a new process when anything that doens't say "exit" in it is entered.
-//
-// This is useful for debugging process attaching and similar functionality.
-
-namespace {
-
-uint64_t GetKoidForHandle(zx_handle_t handle) {
-  zx_info_handle_basic_t info;
-  zx_status_t res =
-      zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL, NULL);
-  if (res != ZX_OK)
-    return 0;
-  return static_cast<uint64_t>(info.koid);
-}
-
-zx_status_t LaunchProcess(zx_handle_t job, const std::vector<const char*>& argv, const char* name,
-                          int outfd, zx_handle_t* proc) {
-  std::vector<const char*> normalized_argv = argv;
-  normalized_argv.push_back(nullptr);
-
-  fdio_spawn_action_t actions[] = {
-      {.action = FDIO_SPAWN_ACTION_CLONE_FD, .fd = {.local_fd = outfd, .target_fd = STDOUT_FILENO}},
-      {.action = FDIO_SPAWN_ACTION_CLONE_FD,
-       .fd = {.local_fd = STDIN_FILENO, .target_fd = STDIN_FILENO}},
-      {.action = FDIO_SPAWN_ACTION_CLONE_FD,
-       .fd = {.local_fd = STDERR_FILENO, .target_fd = STDERR_FILENO}},
-      {.action = FDIO_SPAWN_ACTION_SET_NAME, .name = {.data = name}}};
-  char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
-  zx_status_t status =
-      fdio_spawn_etc(job, FDIO_SPAWN_CLONE_ALL, normalized_argv.front(), normalized_argv.data(),
-                     nullptr, std::size(actions), actions, proc, err_msg);
-  return status;
-}
-
-}  // namespace
-
-const char kBinaryPath[] = "/pkgfs/packages/debug_agent_helpers/0/bin/process_loop";
-
-int main() {
-  zx_handle_t default_job = zx_job_default();
-  zx_handle_t child_job;
-  if (zx_status_t status = zx_job_create(default_job, 0u, &child_job); status != ZX_OK) {
-    FX_LOGS(ERROR) << "Could not create a child job.";
-    exit(1);
-  }
-
-  FX_LOGS(INFO) << "Parent job: " << GetKoidForHandle(default_job)
-                << ", Created job: " << GetKoidForHandle(child_job);
-
-  // We're going to keep a list of the created processes.
-  struct Process {
-    std::string name;
-    zx_handle_t proc_handle;
-  };
-  std::vector<Process> processes;
-
-  FX_LOGS(INFO) << "Waiting for output.";
-  std::vector<char> current_line;
-  while (true) {
-    int i = getc(stdin);
-    if (i < 0)
-      break;
-    char c = static_cast<char>(i);
-    printf("%c", c);
-    fflush(stdout);
-
-    // We acumulate characters to that the user can write exit if they want to
-    // exit. Not a very good UI, but works for the testing purposes.
-    if (c >= 'a' && c <= 'z') {
-      current_line.push_back(c);
-      continue;
-    }
-    current_line.push_back(0);
-
-    // If the user wrote exit somewhere, we exit.
-    std::string cmd(current_line.data());
-    if (cmd.find("exit") != std::string::npos) {
-      FX_LOGS(INFO) << "Found \"exit\" in the input. Exiting.";
-      exit(0);
-    }
-
-    // Spawn a process the fdio way.
-    int pipe_fds[2];
-    if (pipe(pipe_fds) != 0) {
-      FX_LOGS(ERROR) << "Could not create pipes!";
-      exit(1);
-    }
-
-    FX_LOGS(INFO) << "Creating process.";
-    Process process;
-    process.name = fxl::StringPrintf("process-%lu", processes.size());
-    zx_status_t status = LaunchProcess(child_job, {kBinaryPath}, process.name.data(), pipe_fds[0],
-                                       &process.proc_handle);
-    if (status != ZX_OK) {
-      FX_LOGS(ERROR) << "Could not create process " << process.name << ": "
-                     << zx_status_get_string(status);
-      exit(1);
-    }
-
-    FX_LOGS(INFO) << "Created process " << process.name
-                  << " with KOID: " << GetKoidForHandle(process.proc_handle);
-    processes.push_back(std::move(process));
-    current_line.clear();
-  }
-
-  return 0;
-}
diff --git a/src/developer/debug/debug_agent/test_realm.cc b/src/developer/debug/debug_agent/test_realm.cc
index 8b19842..2c73cc8 100644
--- a/src/developer/debug/debug_agent/test_realm.cc
+++ b/src/developer/debug/debug_agent/test_realm.cc
@@ -27,7 +27,7 @@
 // Helper to simplify request pipelining.
 template <typename Protocol>
 fidl::ServerEnd<Protocol> CreateEndpointsAndBind(fidl::SyncClient<Protocol>& client) {
-  auto [client_end, server_end] = *fidl::CreateEndpoints<Protocol>();
+  auto [client_end, server_end] = fidl::Endpoints<Protocol>::Create();
   client.Bind(std::move(client_end));
   return std::move(server_end);
 }
@@ -206,7 +206,7 @@
     return fit::error(ErrorToStatus(exposed_dir_open_res.error_value()));
   }
 
-  auto [realm_client_end, realm_server_end] = *fidl::CreateEndpoints<fuchsia_component::Realm>();
+  auto [realm_client_end, realm_server_end] = fidl::Endpoints<fuchsia_component::Realm>::Create();
   auto realm_open_res =
       directory->Open({fuchsia_io::OpenFlags(0), fuchsia_io::ModeType(0),
                        fidl::DiscoverableProtocolName<fuchsia_component::Realm>,
diff --git a/src/developer/debug/debug_agent/zircon_component_manager.cc b/src/developer/debug/debug_agent/zircon_component_manager.cc
index 9669e5f..f52edab 100644
--- a/src/developer/debug/debug_agent/zircon_component_manager.cc
+++ b/src/developer/debug/debug_agent/zircon_component_manager.cc
@@ -47,7 +47,7 @@
 // Helper to simplify request pipelining.
 template <typename Protocol>
 fidl::ServerEnd<Protocol> CreateEndpointsAndBind(fidl::Client<Protocol>& client) {
-  auto [client_end, server_end] = *fidl::CreateEndpoints<Protocol>();
+  auto [client_end, server_end] = fidl::Endpoints<Protocol>::Create();
   client.Bind(std::move(client_end), async_get_default_dispatcher());
   return std::move(server_end);
 }
diff --git a/src/developer/debug/debug_agent/zircon_limbo_provider_unittest.cc b/src/developer/debug/debug_agent/zircon_limbo_provider_unittest.cc
index dc95a15..fb6b54d 100644
--- a/src/developer/debug/debug_agent/zircon_limbo_provider_unittest.cc
+++ b/src/developer/debug/debug_agent/zircon_limbo_provider_unittest.cc
@@ -186,7 +186,7 @@
 template <typename Protocol, typename ServerImpl>
 fidl::ClientEnd<fuchsia_io::Directory> SetupServiceRoot(std::unique_ptr<ServerImpl> impl,
                                                         async_dispatcher_t* dispatcher) {
-  auto [root_client_end, root_server_end] = *fidl::CreateEndpoints<fuchsia_io::Directory>();
+  auto [root_client_end, root_server_end] = fidl::Endpoints<fuchsia_io::Directory>::Create();
   async::PostTask(dispatcher, [dispatcher, impl = std::move(impl),
                                server_end = std::move(root_server_end)]() mutable {
     // |component::OutgoingDirectory| is not thread-safe, so we have to construct and destruct in
@@ -195,10 +195,9 @@
     ASSERT_TRUE(outgoing_dir->AddProtocol<Protocol>(std::move(impl)).is_ok());
     ASSERT_TRUE(outgoing_dir->Serve(std::move(server_end)).is_ok());
     // Defer the destructing until the loop destructs.
-    async::PostTaskForTime(
-        dispatcher, [dir = std::move(outgoing_dir)]() {}, zx::time::infinite());
+    async::PostTaskForTime(dispatcher, [dir = std::move(outgoing_dir)]() {}, zx::time::infinite());
   });
-  auto [svc_client_end, svc_server_end] = *fidl::CreateEndpoints<fuchsia_io::Directory>();
+  auto [svc_client_end, svc_server_end] = fidl::Endpoints<fuchsia_io::Directory>::Create();
   EXPECT_ZX_EQ(fdio_open_at(root_client_end.channel().release(), "svc",
                             static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
                             svc_server_end.channel().release()),
diff --git a/src/developer/debug/e2e_tests/inferiors/async_rust.rs b/src/developer/debug/e2e_tests/inferiors/async_rust.rs
index 811b706..c1daca9 100644
--- a/src/developer/debug/e2e_tests/inferiors/async_rust.rs
+++ b/src/developer/debug/e2e_tests/inferiors/async_rust.rs
@@ -6,6 +6,7 @@
 
 #[fasync::run_singlethreaded]
 async fn main() {
+    let _task = fasync::Task::spawn(async {});
     let block = async {
         fasync::Task::spawn(baz(20)).detach();
         let task = fasync::Task::spawn(baz(21));
diff --git a/src/developer/debug/e2e_tests/scripts/async_backtrace.script b/src/developer/debug/e2e_tests/scripts/async_backtrace.script
index 5311e1b..f3a1ffd 100644
--- a/src/developer/debug/e2e_tests/scripts/async_backtrace.script
+++ b/src/developer/debug/e2e_tests/scripts/async_backtrace.script
@@ -1,4 +1,5 @@
 ## require is_lto=false
+## require optimize=none
 
 [zxdb] run-component fuchsia-pkg://fuchsia.com/zxdb_e2e_inferiors#meta/async_rust.cm
 Launched Process 1 state=Running koid=?? name=async_rust.cm component=async_rust.cm
@@ -20,9 +21,11 @@
       └─ async_rust::main::func::λ • async_rust.rs:??
          └─ fuchsia_async::runtime::fuchsia::task::Task
 Task(id = 1)
+└─ Finished
+Task(id = 2)
 └─ async_rust::baz • async_rust.rs:??
    └─ fuchsia_async::runtime::fuchsia::timer::Timer
-Task(id = 2)
+Task(id = 3)
 └─ async_rust::baz (Unresumed) • async_rust.rs:??
 
 [zxdb] kill
diff --git a/src/developer/debug/e2e_tests/scripts/bitfield.script b/src/developer/debug/e2e_tests/scripts/bitfield.script
index 8965764..cd3cb21 100644
--- a/src/developer/debug/e2e_tests/scripts/bitfield.script
+++ b/src/developer/debug/e2e_tests/scripts/bitfield.script
@@ -1,6 +1,7 @@
 # LTO or ThinLTO+release will cause p to be optimized out.
 ## require is_lto=false
 ## require is_thinlto=false
+## require optimize=none
 
 [zxdb] b main
 Created Breakpoint 1 @ main
diff --git a/src/developer/debug/e2e_tests/scripts/unwind_plt.script b/src/developer/debug/e2e_tests/scripts/unwind_plt.script
index fe3292a..7b8fe57 100644
--- a/src/developer/debug/e2e_tests/scripts/unwind_plt.script
+++ b/src/developer/debug/e2e_tests/scripts/unwind_plt.script
@@ -1,6 +1,7 @@
 # When LTO is enabled, puts will go though GOT directly rather than PLT stubs, similar to -fno-plt.
 # There won't be $plt(puts) symbol.
 ## require is_lto=false
+## require optimize=none
 
 [zxdb] break $plt(puts)
 Created Breakpoint 1 @ $plt(puts)
diff --git a/src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc b/src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc
index b1bccd6..0967a11 100644
--- a/src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc
+++ b/src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc
@@ -37,6 +37,7 @@
 #include "src/developer/debug/zxdb/symbols/collection.h"
 #include "src/developer/debug/zxdb/symbols/data_member.h"
 #include "src/developer/debug/zxdb/symbols/identifier.h"
+#include "src/developer/debug/zxdb/symbols/modified_type.h"
 #include "src/developer/debug/zxdb/symbols/process_symbols.h"
 #include "src/developer/debug/zxdb/symbols/symbol.h"
 #include "src/developer/debug/zxdb/symbols/template_parameter.h"
@@ -415,16 +416,73 @@
         auto out = fxl::MakeRefCounted<AsyncOutputBuffer>();
         out->Append("Task(id = " + std::to_string(task_id) + ")\n", TextForegroundColor::kGreen);
         out->Append(kAwaiteeMarker);
-        // Arc -> Task -> AtomicFuture -> UnsafeCell -> ManuallyDrop -> FutureObj -> LocalFutureObj
-        ErrOrValue future =
-            ResolveNonstaticMember(context, arc_inner.value(),
-                                   {"data", "future", "future", "value", "value", "__0", "future"});
-        if (future.has_error())
-          return cb(task_id, FormatError("Invalid HashMap tuple (6)", future.err()));
+        // Arc -> Task -> AtomicFuture
+        ErrOrValue atomic_future =
+            ResolveNonstaticMember(context, arc_inner.value(), {"data", "future"});
+        if (atomic_future.has_error())
+          return cb(task_id, FormatError("Invalid HashMap tuple (4)", atomic_future.err()));
 
-        // |future| is a $(*mut dyn core::future::future::Future<Output=()>).
-        out->Complete(FormatFuture(future.value(), options, context, 3));
-        cb(task_id, out);
+        ErrOrValue state = ResolveNonstaticMember(context, atomic_future.value(), {"state"});
+        if (state.has_error())
+          return cb(task_id, FormatError("Invalid HashMap tuple (5)", state.err()));
+
+        // Read the state of the future.
+        uint64_t state_value;
+        if (auto result = state.value().PromoteTo64(&state_value); result.has_error())
+          return cb(task_id, FormatError("Invalid HashMap tuple (6)", result));
+
+        // See if the future is DONE.
+        if (state_value & (1 << 2)) {
+          out->Complete("Finished\n");
+          return cb(task_id, out);
+        }
+
+        // AtomicFuture -> UnsafeCell -> Box<dyn FutureOrResult>
+        ErrOrValue value =
+            ResolveNonstaticMember(context, atomic_future.value(), {"future", "value"});
+
+        // Now we have `Box<dyn FutureOrResult>`.  To determine the concrete type of the future we
+        // need to find the future's drop function.  We can't use FutureOrResult's drop because it
+        // doesn't have a drop method (it uses ManuallyDrop), so we have to find the `drop_future`
+        // method from the `FutureOrResult` trait.
+
+        // Extract pointer and vtable from the fat pointer.
+        ErrOrValue pointer_val = ResolveNonstaticMember(context, value.value(), {"pointer"});
+        ErrOrValue vtable_val = ResolveNonstaticMember(context, value.value(), {"vtable"});
+        TargetPointer vtable = 0;
+        if (pointer_val.has_error() || vtable_val.has_error() ||
+            vtable_val.value().PromoteTo64(&vtable).has_error())
+          return cb(task_id, FormatMessage(Syntax::kError, "Invalid HashMap tuple (7)"));
+
+        // We want to get to the `drop_future` method which is the first method in the trait.  The
+        // vtable should be <drop, size, align, trait methods...>, so it's the fourth pointer.
+        context->GetDataProvider()->GetMemoryAsync(
+            vtable + 3 * sizeof(TargetPointer), sizeof(TargetPointer),
+            [=, cb = std::move(cb), pointer = pointer_val.value()](
+                const Err& err, std::vector<uint8_t> data) mutable {
+              if (err.has_error() || data.size() != sizeof(TargetPointer))
+                return cb(task_id, FormatMessage(Syntax::kError, "Invalid HashMap tuple (8)"));
+
+              // Assume the same endian.
+              TargetPointer drop_in_place_addr = *reinterpret_cast<TargetPointer*>(data.data());
+              Location loc = context->GetLocationForAddress(drop_in_place_addr);
+              if (!loc.symbol())
+                return cb(task_id, FormatMessage(Syntax::kError, "Invalid HashMap tuple (9)"));
+
+              const Function* func = loc.symbol().Get()->As<Function>();
+              if (!func || func->template_params().empty())
+                return cb(task_id, FormatMessage(Syntax::kError, "Invalid HashMap tuple (10)"));
+
+              // Get the templated parameter and create a ModifiedType to that type.
+              LazySymbol pointed_to =
+                  func->template_params()[0].Get()->As<TemplateParameter>()->type();
+              auto derived = fxl::MakeRefCounted<ModifiedType>(DwarfTag::kPointerType, pointed_to);
+
+              out->Complete(FormatFuture(ExprValue(derived, pointer.data(), pointer.source()),
+                                         options, context, 3));
+
+              cb(task_id, out);
+            });
       });
 }
 
@@ -433,7 +491,7 @@
                                                         const FormatFutureOptions& options,
                                                         const fxl::RefPtr<EvalContext>& context) {
   if (hashmap.has_error()) {
-    return FormatError("Cannot locate active_tasks", hashmap.err());
+    return FormatError("Cannot locate all_tasks", hashmap.err());
   }
   if (StripTemplate(hashmap.value().type()->GetFullName()) !=
       "std::collections::hash::map::HashMap") {
@@ -534,17 +592,22 @@
     if (!stack[i]->GetLocation().has_symbols())
       continue;
     std::string func_name(StripTemplate(stack[i]->GetLocation().symbol().Get()->GetFullName()));
-    if (func_name == "fuchsia_async::runtime::fuchsia::executor::local::LocalExecutor::run" ||
-        func_name == "fuchsia_async::runtime::fuchsia::executor::send::SendExecutor::run") {
-      auto out = fxl::MakeRefCounted<AsyncOutputBuffer>();
-      auto context = stack[i]->GetEvalContext();
-      EvalExpression("self.inner->data.active_tasks.data.value", context, false,
-                     [out, options, context](const ErrOrValue& value) {
-                       out->Complete(FormatActiveTasksHashMap(value, options, context));
-                     });
-      cmd_context->Output(out);
-      return;
+    std::string expr;
+    if (func_name == "fuchsia_async::runtime::fuchsia::executor::local::LocalExecutor::run") {
+      expr = "self.ehandle.inner->data.task_state.data.value.all_tasks";
+    } else if (func_name == "fuchsia_async::runtime::fuchsia::executor::send::SendExecutor::run") {
+      expr = "self.inner->data.task_state.data.value.all_tasks";
+    } else {
+      continue;
     }
+
+    auto out = fxl::MakeRefCounted<AsyncOutputBuffer>();
+    auto context = stack[i]->GetEvalContext();
+    EvalExpression(expr, context, false, [out, options, context](const ErrOrValue& value) {
+      out->Complete(FormatActiveTasksHashMap(value, options, context));
+    });
+    cmd_context->Output(out);
+    return;
   }
   cmd_context->ReportError(Err("Cannot locate the async executor on the stack."));
 }
diff --git a/src/developer/debug/zxdb/debug_adapter/handlers/request_attach.cc b/src/developer/debug/zxdb/debug_adapter/handlers/request_attach.cc
index f416ecb..e70f79a 100644
--- a/src/developer/debug/zxdb/debug_adapter/handlers/request_attach.cc
+++ b/src/developer/debug/zxdb/debug_adapter/handlers/request_attach.cc
@@ -13,7 +13,7 @@
 
 DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(AttachRequestZxdb, AttachRequest, "attach",
                                   DAP_FIELD(process, "process"), DAP_FIELD(command, "command"),
-                                  DAP_FIELD(cwd, "cwd"))
+                                  DAP_FIELD(recursive, "recursive"), DAP_FIELD(cwd, "cwd"))
 
 }  // namespace dap
 
@@ -22,7 +22,8 @@
 dap::ResponseOrError<dap::AttachResponse> OnRequestAttach(DebugAdapterContext* context,
                                                           const dap::AttachRequestZxdb& req) {
   dap::AttachResponse response;
-  context->console()->ProcessInputLine("attach " + req.process);
+  std::string attach = req.recursive && *req.recursive ? "attach --recursive " : "attach ";
+  context->console()->ProcessInputLine(attach + req.process);
 
   // If specified run the provided command (an event) every time we start debugging
   // or after clicking the restart button.
diff --git a/src/developer/debug/zxdb/debug_adapter/handlers/request_attach.h b/src/developer/debug/zxdb/debug_adapter/handlers/request_attach.h
index eea7c91..4a02195 100644
--- a/src/developer/debug/zxdb/debug_adapter/handlers/request_attach.h
+++ b/src/developer/debug/zxdb/debug_adapter/handlers/request_attach.h
@@ -14,6 +14,7 @@
  public:
   dap::string process;
   optional<dap::string> command;
+  optional<dap::boolean> recursive;
   // Current working directory for running the shell command.
   optional<string> cwd;
 };
diff --git a/src/developer/fastboot/BUILD.gn b/src/developer/fastboot/BUILD.gn
index 61ce560..6b47d6a 100644
--- a/src/developer/fastboot/BUILD.gn
+++ b/src/developer/fastboot/BUILD.gn
@@ -11,7 +11,6 @@
     name = "fastboot"
     edition = "2021"
 
-    # TODO(https://fxbug.dev/42158564): this library contains unit tests, but they don't build
     with_unit_tests = true
 
     deps = [
diff --git a/src/developer/ffx/BUILD.gn b/src/developer/ffx/BUILD.gn
index 34a4fd3..799194b3 100644
--- a/src/developer/ffx/BUILD.gn
+++ b/src/developer/ffx/BUILD.gn
@@ -158,6 +158,8 @@
       "//src/developer/ffx/frontends/ffx:config.json($host_toolchain)",
 
       # These are separate subtools with plugin-generated config.json
+      "//src/developer/ffx/plugins/emulator:config.json($host_toolchain)",
+      "//src/developer/ffx/plugins/log:config.json($host_toolchain)",
       "//src/developer/ffx/plugins/trace:config.json($host_toolchain)",
     ]
 
diff --git a/src/developer/ffx/build/ffx.gni b/src/developer/ffx/build/ffx.gni
index 36b809e..7900961 100644
--- a/src/developer/ffx/build/ffx.gni
+++ b/src/developer/ffx/build/ffx.gni
@@ -58,13 +58,16 @@
       if (is_debug) {
         # Disable lto for debug builds, as the additional codegen units imply the
         # use of thin-local lto
-        configs += [ "//build/config/rust:lto_disabled" ]
+        configs += [ "//build/config/lto:no-lto" ]
       } else {
         # Use thin lto (instead of implied thin-local), to run (thin) lto across
         # the entire set of dependency crates, to minimize final binary size
         # without spending an undue amount of time (this is still faster than
         # using codegen_units=1)
-        configs += [ "//build/config/rust:lto_thin" ]
+        # Add thinlto config if lto variants are not used.
+        if (!is_lto_variant) {
+          configs += [ "//build/config/lto:thinlto" ]
+        }
       }
     }
 
diff --git a/src/developer/ffx/config.gni b/src/developer/ffx/config.gni
index ce8959e..dcaaac34 100644
--- a/src/developer/ffx/config.gni
+++ b/src/developer/ffx/config.gni
@@ -52,8 +52,6 @@
 dual_mode_plugins = [
   "//src/developer/ffx/plugins/component:ffx_component",
   "//src/developer/ffx/plugins/debug:ffx_debug_plugin",
-  "//src/developer/ffx/plugins/emulator:ffx_emulator",
-  "//src/developer/ffx/plugins/log:ffx_log",
   "//src/developer/ffx/plugins/package:ffx_package",
   "//src/developer/ffx/plugins/product:ffx_product",
   "//src/developer/ffx/plugins/repository:ffx_repository",
@@ -67,8 +65,6 @@
 # Config default files from tools listed above so they can be included in
 # the build.
 dual_mode_defaults = [
-  "//src/developer/ffx/plugins/emulator/data/config.json",
-  "//src/developer/ffx/plugins/log/data/config.json",
   "//src/developer/ffx/plugins/product/data/config.json",
   "//src/developer/ffx/plugins/repository/data/config.json",
   "//src/developer/ffx/plugins/test/data/config.json",
diff --git a/src/developer/ffx/core/BUILD.gn b/src/developer/ffx/core/BUILD.gn
index e3caea1..6c82d7b 100644
--- a/src/developer/ffx/core/BUILD.gn
+++ b/src/developer/ffx/core/BUILD.gn
@@ -23,8 +23,11 @@
       "//third_party/rust_crates:anyhow",
       "//third_party/rust_crates:async-trait",
       "//third_party/rust_crates:futures",
+      "//third_party/rust_crates:thiserror",
     ]
 
+    test_deps = [ "//third_party/rust_crates:assert_matches" ]
+
     sources = [ "src/lib.rs" ]
   }
 }
diff --git a/src/developer/ffx/core/src/lib.rs b/src/developer/ffx/core/src/lib.rs
index d9cb524..a284d81 100644
--- a/src/developer/ffx/core/src/lib.rs
+++ b/src/developer/ffx/core/src/lib.rs
@@ -9,6 +9,7 @@
 use ffx_writer::Writer;
 use fidl_fuchsia_developer_ffx::{DaemonProxy, TargetProxy, VersionInfo};
 use fidl_fuchsia_developer_remotecontrol::RemoteControlProxy;
+use thiserror::Error;
 
 /// Exports used in macros
 #[doc(hidden)]
@@ -22,9 +23,30 @@
     pub use rcs;
 }
 
+#[derive(Error, Debug)]
+pub enum FfxInjectorError {
+    // This error message must stay the same as it's load-bearing to infra.
+    // LINT.IfChange
+    #[error("FFX Daemon was told not to autostart and no existing Daemon instance was found")]
+    DaemonAutostartDisabled,
+    // LINT.ThenChange(//tools/testing/tefmocheck/string_in_log_check.go)
+    #[error(transparent)]
+    UnknownError(#[from] anyhow::Error),
+}
+
+/// Downcasts an anyhow::Error to a structured error.
+/// Used for compatibility purposes until all of ffx
+/// is structured.
+pub fn downcast_injector_error<T>(res: Result<T, anyhow::Error>) -> Result<T, FfxInjectorError> {
+    res.map_err(|err| match err.downcast() {
+        Ok(value) => value,
+        Err(value) => value.into(),
+    })
+}
+
 #[async_trait(?Send)]
 pub trait Injector {
-    async fn daemon_factory(&self) -> Result<DaemonProxy>;
+    async fn daemon_factory(&self) -> Result<DaemonProxy, FfxInjectorError>;
     /// Attempts to get a handle to the ffx daemon.
     async fn try_daemon(&self) -> Result<Option<DaemonProxy>>;
     async fn remote_factory(&self) -> Result<RemoteControlProxy>;
@@ -33,3 +55,22 @@
     async fn build_info(&self) -> Result<VersionInfo>;
     async fn writer(&self) -> Result<Writer>;
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use assert_matches::assert_matches;
+    use errors::ffx_error;
+
+    #[fuchsia_async::run_singlethreaded(test)]
+    async fn test_downcast_injector_error() {
+        assert_matches!(
+            downcast_injector_error::<()>(Err(ffx_error!("test error").into())),
+            Err(FfxInjectorError::UnknownError(_))
+        );
+        assert_matches!(
+            downcast_injector_error::<()>(Err(FfxInjectorError::DaemonAutostartDisabled.into())),
+            Err(FfxInjectorError::DaemonAutostartDisabled)
+        );
+    }
+}
diff --git a/src/developer/ffx/daemon/data/config.json b/src/developer/ffx/daemon/data/config.json
index 6f59f0e..b08e5b3 100644
--- a/src/developer/ffx/daemon/data/config.json
+++ b/src/developer/ffx/daemon/data/config.json
@@ -11,12 +11,6 @@
         },
         "timeout": 500
     },
-    "fastboot": {
-        "flash": {
-            "min_timeout_secs": 60,
-            "timeout_rate": 5
-        }
-    },
     "ssh": {
         "auth-sock": [
             "$SSH_AUTH_SOCK"
diff --git a/src/developer/ffx/daemon/protocols/agis/src/lib.rs b/src/developer/ffx/daemon/protocols/agis/src/lib.rs
index d447719..ad735ba 100644
--- a/src/developer/ffx/daemon/protocols/agis/src/lib.rs
+++ b/src/developer/ffx/daemon/protocols/agis/src/lib.rs
@@ -121,7 +121,6 @@
                 let tasks = self.task_manager.drain();
                 for t in tasks {
                     tracing::info!("cancelling task {:?}", t);
-                    t.cancel().await;
                 }
                 responder.send(Ok(()))?;
                 Ok(())
diff --git a/src/developer/ffx/daemon/protocols/mdns/src/lib.rs b/src/developer/ffx/daemon/protocols/mdns/src/lib.rs
index 86aedcd..67743da 100644
--- a/src/developer/ffx/daemon/protocols/mdns/src/lib.rs
+++ b/src/developer/ffx/daemon/protocols/mdns/src/lib.rs
@@ -87,7 +87,7 @@
     }
 
     async fn stop(&mut self, _cx: &Context) -> Result<()> {
-        self.mdns_task.take().ok_or(anyhow!("mdns_task never started"))?.cancel().await;
+        self.mdns_task.take().ok_or(anyhow!("mdns_task never started"))?;
         Ok(())
     }
 
diff --git a/src/developer/ffx/daemon/proxy/src/lib.rs b/src/developer/ffx/daemon/proxy/src/lib.rs
index bb6e7ef..a83762c 100644
--- a/src/developer/ffx/daemon/proxy/src/lib.rs
+++ b/src/developer/ffx/daemon/proxy/src/lib.rs
@@ -9,7 +9,7 @@
 use errors::{ffx_bail, ffx_error, FfxError};
 use ffx_command_error::FfxContext;
 use ffx_config::EnvironmentContext;
-use ffx_core::Injector;
+use ffx_core::{downcast_injector_error, FfxInjectorError, Injector};
 use ffx_daemon::{get_daemon_proxy_single_link, is_daemon_running_at_path, DaemonConfig};
 use ffx_metrics::add_ffx_rcs_protocol_event;
 use ffx_target::{get_remote_proxy, open_target_with_fut};
@@ -180,21 +180,26 @@
     // This could get called multiple times by the plugin system via multiple threads - so make sure
     // the spawning only happens one thread at a time.
     #[tracing::instrument]
-    async fn daemon_factory(&self) -> Result<DaemonProxy> {
+    async fn daemon_factory(&self) -> Result<DaemonProxy, FfxInjectorError> {
         let autostart = self.env_context.query(CONFIG_DAEMON_AUTOSTART).get().await.unwrap_or(true);
-        self.daemon_once
-            .get_or_try_init(|first_connection| {
-                let start_mode =
-                    if autostart { DaemonStart::AutoStart } else { DaemonStart::DoNotAutoStart };
-                init_daemon_proxy(
-                    start_mode,
-                    Arc::clone(&self.node),
-                    self.env_context.clone(),
-                    self.daemon_check.clone(),
-                    first_connection,
-                )
-            })
-            .await
+        downcast_injector_error(
+            self.daemon_once
+                .get_or_try_init(|first_connection| {
+                    let start_mode = if autostart {
+                        DaemonStart::AutoStart
+                    } else {
+                        DaemonStart::DoNotAutoStart
+                    };
+                    init_daemon_proxy(
+                        start_mode,
+                        Arc::clone(&self.node),
+                        self.env_context.clone(),
+                        self.daemon_check.clone(),
+                        first_connection,
+                    )
+                })
+                .await,
+        )
     }
 
     #[tracing::instrument]
@@ -303,10 +308,7 @@
 
     if cfg!(not(test)) && !is_daemon_running_at_path(&ascendd_path) {
         if autostart == DaemonStart::DoNotAutoStart {
-            return Err(ffx_error!(
-                "FFX Daemon was told not to autostart and no existing Daemon instance was found"
-            )
-            .into());
+            return Err(FfxInjectorError::DaemonAutostartDisabled.into());
         }
         ffx_daemon::spawn_daemon(&context).await?;
     }
diff --git a/src/developer/ffx/daemon/target/src/overnet/host_pipe.rs b/src/developer/ffx/daemon/target/src/overnet/host_pipe.rs
index 52264d6..c67d01e 100644
--- a/src/developer/ffx/daemon/target/src/overnet/host_pipe.rs
+++ b/src/developer/ffx/daemon/target/src/overnet/host_pipe.rs
@@ -353,6 +353,7 @@
                     ssh.kill().await?;
                     // Flush any remaining lines, but let's not wait more than one second
                     let mut lb = ffx_ssh::parse::LineBuffer::new();
+                    let mut last_line = "".to_string();
                     while let Ok(line) = read_ssh_line(&mut lb, &mut stderr)
                         .on_timeout(Duration::from_secs(1), || {
                             Err(ParseSshConnectionError::Timeout)
@@ -363,6 +364,7 @@
                             write_ssh_log("E", &line).await;
                         }
                         tracing::error!("SSH stderr: {line}");
+                        last_line = line;
                     }
 
                     if let Some(status) = ssh.try_wait()? {
@@ -380,6 +382,11 @@
                         fuchsia_async::Timer::new(std::time::Duration::from_secs(2)).await;
                         tracing::error!("ssh child status is {:?}", ssh.try_wait());
                     }
+                    event_queue
+                        .push(TargetEvent::SshHostPipeErr(HostPipeErr::from(last_line)))
+                        .unwrap_or_else(|e| {
+                            tracing::warn!("queueing host pipe err event: {:?}", e)
+                        });
                     return Err(e);
                 }
             };
diff --git a/src/developer/ffx/data/config.json b/src/developer/ffx/data/config.json
index d4cfdc1..1a0a347 100644
--- a/src/developer/ffx/data/config.json
+++ b/src/developer/ffx/data/config.json
@@ -16,6 +16,12 @@
         "rotations": 5,
         "rotate_size": 104857600
     },
+    "fastboot": {
+        "flash": {
+            "min_timeout_secs": 60,
+            "timeout_rate": 2
+        }
+    },
     "proxy": {
         "timeout_secs": 10.0
     },
diff --git a/src/developer/ffx/docs/configuration.md b/src/developer/ffx/docs/configuration.md
index 55e0459..ccf6fea 100644
--- a/src/developer/ffx/docs/configuration.md
+++ b/src/developer/ffx/docs/configuration.md
@@ -75,7 +75,7 @@
 :                                         : device. Defaults to `60` seconds   :
 | `fastboot.flash.timeout_rate`           | The timeout rate in mb/s when      |
 :                                         : communicating with the target      :
-:                                         : device. Defaults to `5` MB/sec     :
+:                                         : device. Defaults to `2` MB/sec     :
 | `fastboot.reboot.reconnect_timeout`     | Timeout in seconds to wait for     |
 :                                         : target after a reboot to fastboot  :
 :                                         : mode. Defaults to `10` seconds     :
diff --git a/src/developer/ffx/lib/fho/src/from_env/helpers.rs b/src/developer/ffx/lib/fho/src/from_env/helpers.rs
index 3e9c9f6..f0c60ec 100644
--- a/src/developer/ffx/lib/fho/src/from_env/helpers.rs
+++ b/src/developer/ffx/lib/fho/src/from_env/helpers.rs
@@ -67,7 +67,7 @@
     P::Protocol: DiscoverableProtocolMarker,
 {
     let svc_name = <P::Protocol as DiscoverableProtocolMarker>::PROTOCOL_NAME;
-    let daemon = env.injector.daemon_factory().await?;
+    let daemon = env.injector.daemon_factory().await.map_err(|err| anyhow::Error::from(err))?;
     let (proxy, server_end) = create_proxy()?;
 
     daemon
diff --git a/src/developer/ffx/lib/fho/src/testing.rs b/src/developer/ffx/lib/fho/src/testing.rs
index e1f536d..bf17bf5 100644
--- a/src/developer/ffx/lib/fho/src/testing.rs
+++ b/src/developer/ffx/lib/fho/src/testing.rs
@@ -10,7 +10,7 @@
 use async_trait::async_trait;
 use ffx_command::{FfxCommandLine, Result};
 use ffx_config::EnvironmentContext;
-use ffx_core::Injector;
+use ffx_core::{downcast_injector_error, FfxInjectorError, Injector};
 use ffx_writer::Writer;
 use fidl_fuchsia_developer_ffx::{DaemonProxy, TargetProxy, VersionInfo};
 use fidl_fuchsia_developer_remotecontrol::RemoteControlProxy;
@@ -129,8 +129,8 @@
 
 #[async_trait(?Send)]
 impl Injector for FakeInjector {
-    async fn daemon_factory(&self) -> anyhow::Result<DaemonProxy> {
-        (self.daemon_factory_closure)().await
+    async fn daemon_factory(&self) -> anyhow::Result<DaemonProxy, FfxInjectorError> {
+        downcast_injector_error((self.daemon_factory_closure)().await)
     }
 
     async fn try_daemon(&self) -> anyhow::Result<Option<DaemonProxy>> {
diff --git a/src/developer/ffx/lib/fuchsia-controller/src/lib_context.rs b/src/developer/ffx/lib/fuchsia-controller/src/lib_context.rs
index 8424894..7acdaee 100644
--- a/src/developer/ffx/lib/fuchsia-controller/src/lib_context.rs
+++ b/src/developer/ffx/lib/fuchsia-controller/src/lib_context.rs
@@ -86,9 +86,8 @@
         executor.run_singlethreaded(async move {
             while let Ok(cmd) = receiver.recv().await {
                 if let LibraryCommand::ShutdownLib = cmd {
-                    if let Some(n) = notifier.lock().await.take() {
-                        n.close().await;
-                    }
+                    // Dropping the notifier will cause spawned tasks to be dropped.
+                    *notifier.lock().await = None;
                     break;
                 }
                 cmd.run().await;
@@ -98,7 +97,7 @@
 }
 
 pub(crate) struct LibNotifier {
-    pipe_reader_task: Task<()>,
+    _pipe_reader_task: Task<()>,
     handle_notification_sender: async_channel::Sender<zx_types::zx_handle_t>,
     pipe_rx: RawFd,
 }
@@ -128,7 +127,7 @@
                 }
             }
         });
-        Ok(Self { handle_notification_sender: tx, pipe_reader_task, pipe_rx })
+        Ok(Self { handle_notification_sender: tx, _pipe_reader_task: pipe_reader_task, pipe_rx })
     }
 
     fn receiver(&self) -> RawFd {
@@ -138,9 +137,4 @@
     fn sender(&self) -> async_channel::Sender<zx_types::zx_handle_t> {
         self.handle_notification_sender.clone()
     }
-
-    /// Cancels and destroys the internal reader that handles notifications.
-    async fn close(self) {
-        let _ = self.pipe_reader_task.cancel().await;
-    }
 }
diff --git a/src/developer/ffx/lib/mdns_discovery/src/lib.rs b/src/developer/ffx/lib/mdns_discovery/src/lib.rs
index 4542309..8ad8dcc 100644
--- a/src/developer/ffx/lib/mdns_discovery/src/lib.rs
+++ b/src/developer/ffx/lib/mdns_discovery/src/lib.rs
@@ -539,9 +539,7 @@
         {
             let mut tasks = socket_tasks.lock().await;
             for ip in to_delete {
-                if let Some(handle) = tasks.remove(&ip) {
-                    handle.cancel().await;
-                }
+                tasks.remove(&ip);
             }
         }
 
diff --git a/src/developer/ffx/lib/target/BUILD.gn b/src/developer/ffx/lib/target/BUILD.gn
index c1085cfb..6db03ae 100644
--- a/src/developer/ffx/lib/target/BUILD.gn
+++ b/src/developer/ffx/lib/target/BUILD.gn
@@ -32,6 +32,7 @@
       "//src/lib/versioning/version-history/rust:version-history",
       "//third_party/rust_crates:anyhow",
       "//third_party/rust_crates:async-channel",
+      "//third_party/rust_crates:async-lock",
       "//third_party/rust_crates:futures",
       "//third_party/rust_crates:futures-lite",
       "//third_party/rust_crates:itertools",
diff --git a/src/developer/ffx/lib/target/src/fidl_pipe.rs b/src/developer/ffx/lib/target/src/fidl_pipe.rs
index 4a9eb11..b62deb3 100644
--- a/src/developer/ffx/lib/target/src/fidl_pipe.rs
+++ b/src/developer/ffx/lib/target/src/fidl_pipe.rs
@@ -139,6 +139,17 @@
     pub fn target_address(&self) -> SocketAddr {
         self.address
     }
+
+    pub fn try_drain_errors(&self) -> Option<Vec<anyhow::Error>> {
+        let mut pipe_errors = Vec::new();
+        while let Ok(err) = self.error_queue.try_recv() {
+            pipe_errors.push(err)
+        }
+        if pipe_errors.is_empty() {
+            return None;
+        }
+        Some(pipe_errors)
+    }
 }
 
 impl Drop for FidlPipe {
@@ -177,6 +188,26 @@
         }
     }
 
+    #[derive(Debug)]
+    struct DoNothingConnector;
+
+    impl OvernetConnector for DoNothingConnector {
+        async fn connect(&mut self) -> Result<OvernetConnection> {
+            let (sock1, sock2) = fidl::Socket::create_stream();
+            let sock1 = fidl::AsyncSocket::from_socket(sock1);
+            let sock2 = fidl::AsyncSocket::from_socket(sock2);
+            let (_error_tx, error_rx) = async_channel::unbounded();
+            let error_task = Task::local(async move {});
+            Ok(OvernetConnection {
+                output: Box::new(BufReader::new(sock1)),
+                input: Box::new(sock2),
+                errors: error_rx,
+                compat: None,
+                main_task: Some(error_task),
+            })
+        }
+    }
+
     #[fuchsia_async::run_singlethreaded(test)]
     async fn test_error_queue() {
         // These sockets will do nothing of import.
@@ -195,4 +226,25 @@
         let err = errors.next().await.unwrap();
         assert_eq!(anyhow::anyhow!("boom").to_string(), err.to_string());
     }
+
+    #[fuchsia_async::run_singlethreaded(test)]
+    async fn test_empty_error_queue() {
+        let (local_socket, _remote_socket) = fidl::Socket::create_stream();
+        let local_socket = fidl::AsyncSocket::from_socket(local_socket);
+        let (reader, writer) = tokio::io::split(local_socket);
+        let fidl_pipe = FidlPipe::start_internal(
+            "127.0.0.1:22".parse().unwrap(),
+            reader,
+            writer,
+            DoNothingConnector,
+        )
+        .await
+        .unwrap();
+        // So, this DoNothingConnector is going to ensure no errors are placed onto the queue,
+        // however, even if AutoFailConnector was used here it still wouldn't work, since there is
+        // no polling happening between the creation of FidlPipe and the attempt to drain errors
+        // off of the queue.
+        let errs = fidl_pipe.try_drain_errors();
+        assert!(errs.is_none());
+    }
 }
diff --git a/src/developer/ffx/lib/target/src/lib.rs b/src/developer/ffx/lib/target/src/lib.rs
index 7431162..67aa73d 100644
--- a/src/developer/ffx/lib/target/src/lib.rs
+++ b/src/developer/ffx/lib/target/src/lib.rs
@@ -4,6 +4,7 @@
 
 use addr::TargetAddr;
 use anyhow::{Context as _, Result};
+use async_lock::Mutex;
 use compat_info::CompatibilityInfo;
 use discovery::{DiscoverySources, TargetEvent, TargetHandle, TargetState};
 use errors::{ffx_bail, FfxError};
@@ -474,53 +475,84 @@
     }
 }
 
-/// Identical to the above "knock" but does not use the daemon.
+/// Represents a direct (no daemon) connection to a Fuchsia target.
+pub struct DirectConnection {
+    overnet: OvernetClient,
+    fidl_pipe: FidlPipe,
+    rcs_proxy: Mutex<Option<RemoteControlProxy>>,
+}
+
+impl DirectConnection {
+    pub async fn new(target_spec: String, context: EnvironmentContext) -> Result<Self> {
+        let addr = resolve_target_address(Some(target_spec.clone()), &context)
+            .await?
+            .ok_or_else(|| anyhow::anyhow!("Unable to resolve address of target '{target_spec}'"))
+            .context("resolving target address")?;
+        let node = overnet_core::Router::new(None)?;
+        let fidl_pipe = FidlPipe::new(context.clone(), addr, node.clone())
+            .await
+            .context("starting fidl pipe")?;
+        Ok(Self { overnet: OvernetClient { node }, fidl_pipe, rcs_proxy: Default::default() })
+    }
+
+    pub async fn rcs_proxy(&self) -> Result<RemoteControlProxy> {
+        let mut rcs = self.rcs_proxy.lock().await;
+        if rcs.is_none() {
+            *rcs = Some(
+                self.overnet
+                    .connect_remote_control()
+                    .await
+                    .map_err(|e| self.wrap_connection_errors(e).context("getting RCS proxy"))?,
+            );
+        }
+        Ok(rcs.as_ref().unwrap().clone())
+    }
+
+    pub async fn knock_rcs(&self) -> Result<Option<CompatibilityInfo>, KnockError> {
+        let mut rcs = self.rcs_proxy.lock().await;
+        // These are the two places where errors can propagate to the user. For other code using
+        // the FIDL pipe it might be trickier to ensure that errors from the pipe are caught.
+        // For things like FHO integration these errors will probably just be handled outside of
+        // the main subtool.
+        if rcs.is_none() {
+            *rcs = Some(self.overnet.connect_remote_control().await.map_err(|e| {
+                KnockError::CriticalError(
+                    self.wrap_connection_errors(e).context("finding RCS proxy"),
+                )
+            })?);
+        }
+        let res = rcs::knock_rcs(rcs.as_ref().unwrap()).await.map_err(|e| anyhow::anyhow!("{e:?}"));
+        match res {
+            Ok(()) => Ok(self.fidl_pipe.compatibility_info()),
+            Err(e) => Err(KnockError::NonCriticalError(
+                self.wrap_connection_errors(e).context("getting RCS proxy"),
+            )),
+        }
+    }
+
+    /// Takes a given connection error and, if there have been underlying connection errors, adds
+    /// additional context to the passed error, else leaves the error the same.
+    ///
+    /// This function is used to overcome some of the shortcomings around FIDL errors, as on the
+    /// host they are being used to simulate what is essentially a networked connection, and not an
+    /// OS-backed operation (like when using FIDL on a Fuchsia device).
+    pub fn wrap_connection_errors(&self, e: anyhow::Error) -> anyhow::Error {
+        if let Some(pipe_errors) = self.fidl_pipe.try_drain_errors() {
+            return anyhow::anyhow!("{e:?}\n{pipe_errors:?}");
+        }
+        e
+    }
+}
+
+/// Identical to the above "knock_target" but does not use the daemon.
 ///
 /// Unlike other errors, this is not intended to be run in a tight loop.
 pub async fn knock_target_daemonless(
     target_spec: String,
     context: &EnvironmentContext,
 ) -> Result<Option<CompatibilityInfo>, KnockError> {
-    let addr = resolve_target_address(Some(target_spec.clone()), context)
-        .await?
-        .ok_or_else(|| anyhow::anyhow!("Unable to resolve address of target '{target_spec}'"))
-        .context("resolving target address")?;
-    let node = overnet_core::Router::new(None)?;
-    let fidl_pipe =
-        FidlPipe::new(context.clone(), addr, node.clone()).await.context("starting fidl pipe")?;
-    knock_target_daemonless_with(node, fidl_pipe).await
-}
-
-async fn knock_target_daemonless_with(
-    node: Arc<overnet_core::Router>,
-    fidl_pipe: FidlPipe,
-) -> Result<Option<CompatibilityInfo>, KnockError> {
-    let error_stream = fidl_pipe.error_stream();
-    let client = OvernetClient { node };
-    // These are the two places where errors can propagate to the user. For other code using the FIDL
-    // pipe it might be trickier to ensure that errors from the pipe are caught. For things like
-    // FHO integration these errors will probably just be handled outside of the main subtool.
-    let result = async move {
-        let rcs_proxy = client.connect_remote_control().await?;
-        rcs::knock_rcs(&rcs_proxy).await.map_err(|e| anyhow::anyhow!("{e:?}"))
-    }
-    .await;
-    match result {
-        Ok(()) => Ok(fidl_pipe.compatibility_info()),
-        Err(e) => {
-            let mut pipe_errors = Vec::new();
-            while let Ok(err) = error_stream.try_recv() {
-                pipe_errors.push(err);
-            }
-            if !pipe_errors.is_empty() {
-                return Err(KnockError::NonCriticalError(anyhow::anyhow!(
-                    "Error getting RCS proxy: {e:?}\n{:?}",
-                    pipe_errors
-                )));
-            }
-            Err(KnockError::NonCriticalError(anyhow::anyhow!("{:?}", e)).into())
-        }
-    }
+    let conn = DirectConnection::new(target_spec, context.clone()).await?;
+    conn.knock_rcs().await
 }
 
 /// Get the target specifier.  This uses the normal config mechanism which
@@ -733,10 +765,10 @@
                                 fidl::AsyncChannel::from_channel(server_channel),
                             );
                             // This task is here to ensure the channel stays open, but won't
-                            // necessarily do anything.
+                            // necessarily need do anything.
                             Task::spawn(async move {
                                 while let Ok(Some(req)) = stream.try_next().await {
-                                    eprintln!("Got a request: {req:?}");
+                                    eprintln!("Got a request: {req:?}")
                                 }
                             })
                             .detach();
@@ -747,6 +779,9 @@
                     }
                     responder.send(Ok(())).unwrap();
                 }
+                rcs::RemoteControlRequest::EchoString { value, responder } => {
+                    responder.send(&value).unwrap()
+                }
                 _ => panic!("Received an unexpected request: {req:?}"),
             }
         }
@@ -796,7 +831,7 @@
         let circuit_node = overnet_core::Router::new(None).unwrap();
         let (_sender, error_receiver) = async_channel::unbounded();
         let circuit = FakeOvernet {
-            circuit_node,
+            circuit_node: circuit_node.clone(),
             error_receiver,
             behavior: FakeOvernetBehavior::KeepRcsOpen,
         };
@@ -804,7 +839,12 @@
             FidlPipe::start_internal("127.0.0.1:22".parse().unwrap(), reader, writer, circuit)
                 .await
                 .unwrap();
-        assert!(knock_target_daemonless_with(node, fidl_pipe).await.is_ok());
+        let conn = DirectConnection {
+            overnet: OvernetClient { node },
+            fidl_pipe,
+            rcs_proxy: Default::default(),
+        };
+        assert!(conn.knock_rcs().await.is_ok());
     }
 
     #[fuchsia_async::run_singlethreaded(test)]
@@ -823,9 +863,46 @@
             FidlPipe::start_internal("[::1]:22".parse().unwrap(), reader, writer, circuit)
                 .await
                 .unwrap();
+        let conn = DirectConnection {
+            overnet: OvernetClient { node },
+            fidl_pipe,
+            rcs_proxy: Default::default(),
+        };
         error_sender.send(anyhow::anyhow!("kaboom")).await.unwrap();
-        let err = knock_target_daemonless_with(node, fidl_pipe).await;
+        let err = conn.knock_rcs().await;
         assert!(err.is_err());
-        assert!(err.unwrap_err().to_string().contains("kaboom"));
+        let err_string = err.unwrap_err().to_string();
+        assert!(err_string.contains("kaboom"));
+    }
+
+    #[fuchsia_async::run_singlethreaded(test)]
+    async fn test_overnet_rcs_echo_multiple_times() {
+        let node = overnet_core::Router::new(None).unwrap();
+        let overnet_socket = create_overnet_socket(node.clone()).unwrap();
+        let (reader, writer) = tokio::io::split(overnet_socket);
+        let circuit_node = overnet_core::Router::new(None).unwrap();
+        let (_sender, error_receiver) = async_channel::unbounded();
+        let circuit = FakeOvernet {
+            circuit_node: circuit_node.clone(),
+            error_receiver,
+            behavior: FakeOvernetBehavior::KeepRcsOpen,
+        };
+        let fidl_pipe =
+            FidlPipe::start_internal("127.0.0.1:22".parse().unwrap(), reader, writer, circuit)
+                .await
+                .unwrap();
+        let conn = DirectConnection {
+            overnet: OvernetClient { node },
+            fidl_pipe,
+            rcs_proxy: Default::default(),
+        };
+        let rcs = conn.rcs_proxy().await.unwrap();
+        assert_eq!(rcs.echo_string("foobart").await.unwrap(), "foobart".to_owned());
+        let rcs2 = conn.rcs_proxy().await.unwrap();
+        assert_eq!(rcs2.echo_string("foobarr").await.unwrap(), "foobarr".to_owned());
+        drop(rcs);
+        drop(rcs2);
+        let rcs3 = conn.rcs_proxy().await.unwrap();
+        assert_eq!(rcs3.echo_string("foobarz").await.unwrap(), "foobarz".to_owned());
     }
 }
diff --git a/src/developer/ffx/plugins/assembly/BUILD.gn b/src/developer/ffx/plugins/assembly/BUILD.gn
index ec9c4eb..b9256ac 100644
--- a/src/developer/ffx/plugins/assembly/BUILD.gn
+++ b/src/developer/ffx/plugins/assembly/BUILD.gn
@@ -108,6 +108,7 @@
     "//third_party/rust_crates:itertools",
     "//third_party/rust_crates:serde",
     "//third_party/rust_crates:serde_json",
+    "//third_party/rust_crates:serde_json5",
     "//third_party/rust_crates:textwrap",
     "//third_party/rust_crates:tracing",
     "//third_party/rust_crates:url",
diff --git a/src/developer/ffx/plugins/assembly/src/operations/product.rs b/src/developer/ffx/plugins/assembly/src/operations/product.rs
index 9c518dd..36d5ab4 100644
--- a/src/developer/ffx/plugins/assembly/src/operations/product.rs
+++ b/src/developer/ffx/plugins/assembly/src/operations/product.rs
@@ -5,9 +5,10 @@
 use crate::operations::product::assembly_builder::ImageAssemblyConfigBuilder;
 use anyhow::{bail, Context, Result};
 use assembly_config_schema::assembly_config::{
-    AdditionalPackageContents, CompiledPackageDefinition,
+    AdditionalPackageContents, AssemblyConfigWrapperForOverrides, CompiledPackageDefinition,
 };
 use assembly_config_schema::developer_overrides::DeveloperOverrides;
+use assembly_config_schema::platform_config::PlatformConfig;
 use assembly_config_schema::{
     AssemblyConfig, BoardInformation, BoardInputBundle, FeatureSupportLevel,
 };
@@ -37,19 +38,54 @@
         developer_overrides,
     } = args;
 
-    let developer_overrides = if let Some(overrides_path) = developer_overrides {
-        let developer_overrides =
-            read_config(&overrides_path).context("Reading developer overrides")?;
-        print_developer_overrides_banner(&developer_overrides, &overrides_path);
-        Some(developer_overrides)
-    } else {
-        None
-    };
-
     info!("Reading configuration files.");
     info!("  product: {}", product);
 
-    let config: AssemblyConfig = read_config(&product).context("Reading product configuration")?;
+    let (platform, product, developer_overrides) = if let Some(overrides_path) = developer_overrides
+    {
+        // If developer overrides are in use, parse to intermediate types so
+        // that overrides can be applied.
+        let AssemblyConfigWrapperForOverrides { platform, product } =
+            read_config(&product).context("Reading product configuration")?;
+
+        let developer_overrides =
+            read_config(&overrides_path).context("Reading developer overrides")?;
+        print_developer_overrides_banner(&developer_overrides, &overrides_path)
+            .context("Displaying developer overrides.")?;
+
+        // Extract the platform config overrides so that we can apply them to the platform config.
+        let platform_config_overrides = developer_overrides.platform;
+
+        // Merge the platform config with the overrides.
+        let merged_platform: serde_json::Value =
+            assembly_config_schema::try_merge_into(platform, platform_config_overrides)
+                .context("Merging developer overrides")?;
+
+        // Because serde_json and serde_json5 deserialize enums differently, we need to bounce the
+        // serde_json::Value of the platform config through a string so that we can re-parse it
+        // using serde_json5.
+        // TODO: Remove this after the following issue is fixed:
+        // https://github.com/google/serde_json5/issues/10
+        let merged_platform_json5 = serde_json::to_string_pretty(&merged_platform)
+            .context("Creating temporary json5 from merged config")?;
+
+        // Now deserialize the merged and serialized json5 of the platform configuration.  This
+        // works around the issue with enums.
+        let platform: PlatformConfig = serde_json5::from_str(&merged_platform_json5)
+            .context("Deserializing platform configuration merged with developer overrides.")?;
+
+        // Reconstitute the developer overrides struct, but with a null platform config, since it's
+        // been used to modify the platform configuration.
+        let developer_overrides =
+            DeveloperOverrides { platform: serde_json::Value::Null, ..developer_overrides };
+
+        (platform, product, Some(developer_overrides))
+    } else {
+        let AssemblyConfig { platform, product } =
+            read_config(&product).context("Reading product configuration")?;
+
+        (platform, product, None)
+    };
 
     let board_info_path = board_info;
     let board_info = read_config::<BoardInformation>(&board_info_path)
@@ -102,7 +138,8 @@
     let ramdisk_image = mode == PackageMode::DiskImageInZbi;
     let resource_dir = input_bundles_dir.join("resources");
     let configuration = assembly_platform_configuration::define_configuration(
-        &config,
+        &platform,
+        &product,
         &board_info,
         ramdisk_image,
         &outdir,
@@ -111,12 +148,15 @@
 
     // Now that all the configuration has been determined, create the builder
     // and start doing the work of creating the image assembly config.
-    let mut builder = ImageAssemblyConfigBuilder::new(config.platform.build_type.clone());
+    let mut builder = ImageAssemblyConfigBuilder::new(platform.build_type.clone());
 
     // Set the developer overrides, if any.
     if let Some(developer_overrides) = developer_overrides {
         builder
-            .add_developer_overrides(developer_overrides)
+            .add_developer_overrides(
+                developer_overrides.developer_only_options,
+                developer_overrides.kernel,
+            )
             .context("Setting developer overrides")?;
     }
 
@@ -156,7 +196,7 @@
         builder
             .add_board_input_bundle(
                 bundle,
-                config.platform.feature_set_level == FeatureSupportLevel::Bootstrap,
+                platform.feature_set_level == FeatureSupportLevel::Bootstrap,
             )
             .with_context(|| format!("Adding board input bundle from: {bundle_path}"))?;
     }
@@ -194,12 +234,10 @@
     builder.add_bootfs_files(&configuration.bootfs.files).context("Adding bootfs files")?;
 
     // Add product-specified packages and configuration
-    builder
-        .add_product_packages(config.product.packages)
-        .context("Adding product-provided packages")?;
+    builder.add_product_packages(product.packages).context("Adding product-provided packages")?;
 
     builder
-        .add_product_base_drivers(config.product.base_drivers)
+        .add_product_base_drivers(product.base_drivers)
         .context("Adding product-provided base-drivers")?;
 
     if let Some(package_config_path) = additional_packages_path {
@@ -245,7 +283,7 @@
     let mut image_assembly =
         builder.build(&outdir, &tools).context("Building Image Assembly config")?;
     let images = ImagesConfig::from_product_and_board(
-        &config.platform.storage.filesystems,
+        &platform.storage.filesystems,
         &board_info.filesystems,
     )
     .context("Constructing images config")?;
@@ -272,7 +310,10 @@
     bundles_dir.join(name).join("assembly_config.json")
 }
 
-fn print_developer_overrides_banner(overrides: &DeveloperOverrides, overrides_path: &Utf8PathBuf) {
+fn print_developer_overrides_banner(
+    overrides: &DeveloperOverrides,
+    overrides_path: &Utf8PathBuf,
+) -> Result<()> {
     let overrides_target = if let Some(target_name) = &overrides.target_name {
         target_name.as_str()
     } else {
@@ -286,6 +327,15 @@
         println!("  Options:");
         println!("    all_packages_in_base: enabled")
     }
+
+    if !overrides.platform.is_null() {
+        println!();
+        println!("  Platform Configuration Overrides / Additions:");
+        for line in serde_json::to_string_pretty(&overrides.platform)?.lines() {
+            println!("    {}", line);
+        }
+    }
+
     if !overrides.kernel.command_line_args.is_empty() {
         println!();
         println!("  Additional kernel command line arguments:");
@@ -294,4 +344,5 @@
         }
     }
     println!();
+    Ok(())
 }
diff --git a/src/developer/ffx/plugins/assembly/src/operations/product/assembly_builder.rs b/src/developer/ffx/plugins/assembly/src/operations/product/assembly_builder.rs
index 43ce93c..24f12c8c 100644
--- a/src/developer/ffx/plugins/assembly/src/operations/product/assembly_builder.rs
+++ b/src/developer/ffx/plugins/assembly/src/operations/product/assembly_builder.rs
@@ -9,7 +9,7 @@
     assembly_config::{AssemblyInputBundle, CompiledPackageDefinition, ShellCommands},
     board_config::{BoardInputBundle, HardwareInfo},
     common::PackagedDriverDetails,
-    developer_overrides::{DeveloperOnlyOptions, DeveloperOverrides},
+    developer_overrides::{DeveloperOnlyOptions, KernelOptions},
     image_assembly_config::{BoardDriverArguments, KernelConfig},
     platform_config::BuildType,
     product_config::{ProductConfigData, ProductPackageDetails, ProductPackagesConfig},
@@ -111,16 +111,14 @@
     /// Add developer overrides to the builder
     pub fn add_developer_overrides(
         &mut self,
-        developer_overrides: DeveloperOverrides,
+        developer_only_options: DeveloperOnlyOptions,
+        kernel_options: KernelOptions,
     ) -> Result<()> {
-        let DeveloperOverrides { developer_only_options, kernel, target_name: _ } =
-            developer_overrides;
-
         // Set the developer-only options for the buidler to use.
         self.developer_only_options = Some(developer_only_options);
 
         // Add the kernel command line args from the developer
-        self.kernel_args.extend(kernel.command_line_args.into_iter());
+        self.kernel_args.extend(kernel_options.command_line_args.into_iter());
 
         Ok(())
     }
@@ -841,6 +839,7 @@
             cache: packages.package_manifest_paths(PackageSet::Cache),
             system: packages.package_manifest_paths(PackageSet::System),
             bootfs_packages: packages.package_manifest_paths(PackageSet::Bootfs),
+            on_demand: packages.package_manifest_paths(PackageSet::OnDemand),
             kernel: KernelConfig {
                 path: kernel_path.context("A kernel path must be specified")?,
                 args: kernel_args.into_iter().collect(),
@@ -1640,6 +1639,7 @@
                     "args": [
                         "compile",
                         "--features=allow_long_names",
+                        "--features=dictionaries",
                         "--includeroot",
                         vars.outdir.join("bundle/compiled_packages/include").as_str(),
                         "--includepath",
@@ -1666,6 +1666,7 @@
                     "args": [
                         "compile",
                         "--features=allow_long_names",
+                        "--features=dictionaries",
                         "--includeroot",
                         vars.outdir.join("bundle/compiled_packages/include").as_str(),
                         "--includepath",
diff --git a/src/developer/ffx/plugins/audio/common/BUILD.gn b/src/developer/ffx/plugins/audio/common/BUILD.gn
index 4a7cf8ce..7dadc93 100644
--- a/src/developer/ffx/plugins/audio/common/BUILD.gn
+++ b/src/developer/ffx/plugins/audio/common/BUILD.gn
@@ -11,8 +11,6 @@
 
   deps = [
     "//sdk/fidl/fuchsia.audio.controller:fuchsia.audio.controller_rust",
-    "//sdk/fidl/fuchsia.audio.device:fuchsia.audio.device_rust",
-    "//sdk/fidl/fuchsia.hardware.audio:fuchsia.hardware.audio_rust",
     "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
     "//src/developer/ffx/command:lib",
     "//src/developer/ffx/lib/fho:lib",
diff --git a/src/developer/ffx/plugins/audio/common/src/lib.rs b/src/developer/ffx/plugins/audio/common/src/lib.rs
index a677f9a..2d14f2f 100644
--- a/src/developer/ffx/plugins/audio/common/src/lib.rs
+++ b/src/developer/ffx/plugins/audio/common/src/lib.rs
@@ -139,8 +139,6 @@
 
 pub mod tests {
     use super::*;
-    use fidl_fuchsia_audio_device as fadevice;
-    use fidl_fuchsia_hardware_audio as fhaudio;
     use fuchsia_audio::stop_listener;
     use futures::AsyncWriteExt;
     use timeout::timeout;
@@ -169,100 +167,6 @@
     \x26\x21\x1d\x18\x14\x10\x0d\x0a\x07\x05\x03\x02\x01\x00\x00\x00\
     \x01\x02\x04\x06\x08\x0b\x0e\x11\x15\x1a\x1e\x23";
 
-    pub fn fake_audio_daemon() -> fac::DeviceControlProxy {
-        let callback = |req| match req {
-            fac::DeviceControlRequest::GetDeviceInfo { payload, responder } => match payload.device
-            {
-                Some(device_selector) => {
-                    let fac::DeviceSelector::Devfs(devfs) = device_selector else {
-                        panic!("unknown selector type");
-                    };
-
-                    let result = match devfs.device_type {
-                        fadevice::DeviceType::Input | fadevice::DeviceType::Output => {
-                            let stream_device_info = fac::StreamConfigDeviceInfo {
-                                stream_properties: Some(fhaudio::StreamProperties {
-                                    unique_id: Some([
-                                        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
-                                        0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-                                    ]),
-                                    is_input: Some(true),
-                                    can_mute: Some(true),
-                                    can_agc: Some(true),
-                                    min_gain_db: Some(-32.0),
-                                    max_gain_db: Some(60.0),
-                                    gain_step_db: Some(0.5),
-                                    plug_detect_capabilities: None,
-                                    manufacturer: Some(format!("Spacely Sprockets")),
-                                    product: Some(format!("Test Microphone")),
-                                    clock_domain: Some(2),
-                                    ..Default::default()
-                                }),
-                                supported_formats: Some(vec![fhaudio::SupportedFormats {
-                                    pcm_supported_formats: Some(fhaudio::PcmSupportedFormats {
-                                        channel_sets: Some(vec![
-                                            fhaudio::ChannelSet {
-                                                attributes: Some(vec![
-                                                    fhaudio::ChannelAttributes::default(),
-                                                ]),
-                                                ..Default::default()
-                                            },
-                                            fhaudio::ChannelSet {
-                                                attributes: Some(vec![
-                                                    fhaudio::ChannelAttributes::default(),
-                                                    fhaudio::ChannelAttributes::default(),
-                                                ]),
-                                                ..Default::default()
-                                            },
-                                        ]),
-                                        sample_formats: Some(vec![
-                                            fhaudio::SampleFormat::PcmSigned,
-                                        ]),
-                                        bytes_per_sample: Some(vec![2]),
-                                        valid_bits_per_sample: Some(vec![16]),
-                                        frame_rates: Some(vec![
-                                            16000, 22050, 32000, 44100, 48000, 88200, 96000,
-                                        ]),
-                                        ..Default::default()
-                                    }),
-                                    ..Default::default()
-                                }]),
-                                gain_state: None,
-                                plug_state: None,
-                                ..Default::default()
-                            };
-                            fac::DeviceInfo::StreamConfig(stream_device_info)
-                        }
-                        fadevice::DeviceType::Composite => {
-                            let composite_device_info = fac::CompositeDeviceInfo {
-                                composite_properties: Some(fhaudio::CompositeProperties {
-                                    clock_domain: Some(0),
-                                    ..Default::default()
-                                }),
-                                supported_dai_formats: None,
-                                supported_ring_buffer_formats: None,
-                                ..Default::default()
-                            };
-
-                            fac::DeviceInfo::Composite(composite_device_info)
-                        }
-                        _ => unimplemented!(),
-                    };
-
-                    responder
-                        .send(Ok(fac::DeviceControlGetDeviceInfoResponse {
-                            device_info: Some(result),
-                            ..Default::default()
-                        }))
-                        .unwrap();
-                }
-                None => unimplemented!(),
-            },
-            _ => unimplemented!(),
-        };
-        fho::testing::fake_proxy(callback)
-    }
-
     pub fn fake_audio_player() -> fac::PlayerProxy {
         let callback = |req| match req {
             fac::PlayerRequest::Play { payload, responder } => {
diff --git a/src/developer/ffx/plugins/audio/device/BUILD.gn b/src/developer/ffx/plugins/audio/device/BUILD.gn
index f9bd3b96..8aa0714 100644
--- a/src/developer/ffx/plugins/audio/device/BUILD.gn
+++ b/src/developer/ffx/plugins/audio/device/BUILD.gn
@@ -11,10 +11,14 @@
   with_unit_tests = true
   args_with_unit_tests = true
 
-  args_deps = [ "//src/media/audio/lib/rust" ]
+  args_deps = [
+    "//sdk/fidl/fuchsia.audio.device:fuchsia.audio.device_rust",
+    "//src/media/audio/lib/rust",
+  ]
   args_sources = [ "src/args.rs" ]
 
   sources = [
+    "src/connect.rs",
     "src/info.rs",
     "src/lib.rs",
     "src/list.rs",
@@ -25,6 +29,7 @@
     "//sdk/fidl/fuchsia.audio.controller:fuchsia.audio.controller_rust",
     "//sdk/fidl/fuchsia.audio.device:fuchsia.audio.device_rust",
     "//sdk/fidl/fuchsia.hardware.audio:fuchsia.hardware.audio_rust",
+    "//sdk/fidl/fuchsia.hardware.audio.signalprocessing:fuchsia.hardware.audio.signalprocessing_rust",
     "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
     "//sdk/fidl/fuchsia.media:fuchsia.media_rust",
     "//src/developer/ffx/command:lib",
@@ -32,6 +37,7 @@
     "//src/developer/ffx/plugins/audio/common:ffx_audio_common",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/zircon/rust:fuchsia-zircon-status",
+    "//src/lib/zircon/rust:fuchsia-zircon-types",
     "//src/media/audio/lib/rust",
     "//third_party/rust_crates:async-trait",
     "//third_party/rust_crates:blocking",
@@ -49,6 +55,7 @@
     "//src/developer/ffx/lib/writer:lib",
     "//src/lib/fuchsia",
     "//src/media/audio/lib/rust",
+    "//third_party/rust_crates:serde_json",
     "//third_party/rust_crates:tempfile",
     "//third_party/rust_crates:test-case",
   ]
diff --git a/src/developer/ffx/plugins/audio/device/src/args.rs b/src/developer/ffx/plugins/audio/device/src/args.rs
index fec040d..941cbe57 100644
--- a/src/developer/ffx/plugins/audio/device/src/args.rs
+++ b/src/developer/ffx/plugins/audio/device/src/args.rs
@@ -4,6 +4,7 @@
 
 use argh::{ArgsInfo, FromArgs};
 use ffx_core::ffx_command;
+use fidl_fuchsia_audio_device as fadevice;
 use fuchsia_audio::{
     device::{Direction, HardwareType},
     Format,
@@ -73,12 +74,12 @@
 pub enum SubCommand {
     List(ListCommand),
     Info(InfoCommand),
-    Play(DevicePlayCommand),
-    Record(DeviceRecordCommand),
-    Gain(DeviceGainCommand),
-    Mute(DeviceMuteCommand),
-    Unmute(DeviceUnmuteCommand),
-    Agc(DeviceAgcCommand),
+    Play(PlayCommand),
+    Record(RecordCommand),
+    Gain(GainCommand),
+    Mute(MuteCommand),
+    Unmute(UnmuteCommmand),
+    Agc(AgcCommand),
 }
 
 #[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
@@ -101,18 +102,25 @@
 
 #[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
 #[argh(subcommand, name = "play", description = "Send audio data directly to device ring buffer.")]
-pub struct DevicePlayCommand {
+pub struct PlayCommand {
     #[argh(
         option,
         description = "file in WAV format containing audio signal. \
         If not specified, ffx command will read from stdin."
     )]
     pub file: Option<String>,
+
+    #[argh(
+        option,
+        description = "signal processing element ID, \
+        for an Endpoint element of type RingBuffer"
+    )]
+    pub element_id: Option<fadevice::ElementId>,
 }
 
 #[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
 #[argh(subcommand, name = "record", description = "Capture audio data directly from ring buffer.")]
-pub struct DeviceRecordCommand {
+pub struct RecordCommand {
     #[argh(
         option,
         description = "duration of output signal. Examples: 5ms or 3s. \
@@ -123,6 +131,13 @@
 
     #[argh(option, description = "output format (see 'ffx audio help' for more information).")]
     pub format: Format,
+
+    #[argh(
+        option,
+        description = "signal processing element ID, \
+        for an Endpoint element of type RingBuffer"
+    )]
+    pub element_id: Option<fadevice::ElementId>,
 }
 
 #[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
@@ -131,18 +146,18 @@
     name = "gain",
     description = "Request to set the gain of the stream, in decibels."
 )]
-pub struct DeviceGainCommand {
+pub struct GainCommand {
     #[argh(option, description = "gain, in decibels, to set the stream to.")]
     pub gain: f32,
 }
 
 #[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
 #[argh(subcommand, name = "mute", description = "Request to mute a stream.")]
-pub struct DeviceMuteCommand {}
+pub struct MuteCommand {}
 
 #[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
 #[argh(subcommand, name = "unmute", description = "Request to unmute a stream.")]
-pub struct DeviceUnmuteCommand {}
+pub struct UnmuteCommmand {}
 
 #[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
 #[argh(
@@ -150,7 +165,7 @@
     name = "agc",
     description = "Request to enable or disable automatic gain control for the stream."
 )]
-pub struct DeviceAgcCommand {
+pub struct AgcCommand {
     #[argh(
         positional,
         description = "enable or disable AGC. Accepted values: on, off",
diff --git a/src/developer/ffx/plugins/audio/device/src/connect.rs b/src/developer/ffx/plugins/audio/device/src/connect.rs
new file mode 100644
index 0000000..d2c3fdd
--- /dev/null
+++ b/src/developer/ffx/plugins/audio/device/src/connect.rs
@@ -0,0 +1,87 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use ffx_command::FfxContext;
+use fidl::endpoints::create_proxy;
+use fidl_fuchsia_hardware_audio as fhaudio;
+use fidl_fuchsia_io as fio;
+
+/// Connect to an instance of a FIDL protocol hosted in `directory` using the given `path`.
+// This is essentially the same as `fuchsia_component::client::connect_to_named_protocol_at_dir_root`.
+// We can't use the `fuchsia_component` library in ffx because it doesn't build on host.
+fn connect_to_named_protocol_at_dir_root<P: fidl::endpoints::ProtocolMarker>(
+    directory: &fio::DirectoryProxy,
+    path: &str,
+) -> fho::Result<P::Proxy> {
+    let (proxy, server_end) = create_proxy::<P>().unwrap();
+    directory
+        .open(
+            fio::OpenFlags::empty(),
+            fio::ModeType::empty(),
+            path,
+            server_end.into_channel().into(),
+        )
+        .bug_context("Failed to call Directory.Open")?;
+    Ok(proxy)
+}
+
+/// Connects to the `fuchsia.hardware.audio.Codec` protocol node in the `dev_class` directory
+/// at `path`.
+pub fn connect_hw_codec(
+    dev_class: &fio::DirectoryProxy,
+    path: &str,
+) -> fho::Result<fhaudio::CodecProxy> {
+    let connector_proxy =
+        connect_to_named_protocol_at_dir_root::<fhaudio::CodecConnectorMarker>(dev_class, path)
+            .bug_context("Failed to connect to CodecConnector")?;
+
+    let (proxy, server_end) = create_proxy::<fhaudio::CodecMarker>().unwrap();
+    connector_proxy.connect(server_end).bug_context("Failed to call Connect")?;
+
+    Ok(proxy)
+}
+
+/// Connects to the `fuchsia.hardware.audio.Dai` protocol node in the `dev_class` directory
+/// at `path`.
+pub fn connect_hw_dai(
+    dev_class: &fio::DirectoryProxy,
+    path: &str,
+) -> fho::Result<fhaudio::DaiProxy> {
+    let connector_proxy =
+        connect_to_named_protocol_at_dir_root::<fhaudio::DaiConnectorMarker>(dev_class, path)
+            .bug_context("Failed to connect to DaiConnector")?;
+
+    let (proxy, server_end) = create_proxy::<fhaudio::DaiMarker>().unwrap();
+    connector_proxy.connect(server_end).bug_context("Failed to call Connect")?;
+
+    Ok(proxy)
+}
+
+/// Connects to the `fuchsia.hardware.audio.Composite` protocol node in the `dev_class` directory
+/// at `path`.
+pub fn connect_hw_composite(
+    dev_class: &fio::DirectoryProxy,
+    path: &str,
+) -> fho::Result<fhaudio::CompositeProxy> {
+    // DFv2 Composite drivers do not use a connector/trampoline like Codec/Dai/StreamConfig.
+    connect_to_named_protocol_at_dir_root::<fhaudio::CompositeMarker>(dev_class, path)
+        .bug_context("Failed to connect to Composite")
+}
+
+/// Connects to the `fuchsia.hardware.audio.StreamConfig` protocol node in the `dev_class` directory
+/// at `path`.
+pub fn connect_hw_streamconfig(
+    dev_class: &fio::DirectoryProxy,
+    path: &str,
+) -> fho::Result<fhaudio::StreamConfigProxy> {
+    let connector_proxy = connect_to_named_protocol_at_dir_root::<
+        fhaudio::StreamConfigConnectorMarker,
+    >(dev_class, path)
+    .bug_context("Failed to connect to StreamConfigConnector")?;
+
+    let (proxy, server_end) = create_proxy::<fhaudio::StreamConfigMarker>().unwrap();
+    connector_proxy.connect(server_end).bug_context("Failed to call Connect")?;
+
+    Ok(proxy)
+}
diff --git a/src/developer/ffx/plugins/audio/device/src/info.rs b/src/developer/ffx/plugins/audio/device/src/info.rs
index e9e7fb8..17e8558 100644
--- a/src/developer/ffx/plugins/audio/device/src/info.rs
+++ b/src/developer/ffx/plugins/audio/device/src/info.rs
@@ -2,20 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use crate::serde_ext;
+use crate::{connect, serde_ext};
 use camino::Utf8PathBuf;
-use fidl_fuchsia_audio_controller as fac;
+use ffx_command::{bug, user_error, FfxContext};
+use fidl_fuchsia_audio_device as fadevice;
+use fidl_fuchsia_hardware_audio as fhaudio;
+use fidl_fuchsia_hardware_audio_signalprocessing as fhaudio_sigproc;
+use fidl_fuchsia_io as fio;
 use fuchsia_audio::{
+    dai::{DaiFormatSet, DaiFrameFormat, DaiFrameFormatClocking, DaiFrameFormatJustification},
     device::{
-        ClockDomain, GainCapabilities, GainState, PlugDetectCapabilities, PlugState, Selector,
-        UniqueInstanceId,
+        ClockDomain, DevfsSelector, GainCapabilities, GainState, Info as DeviceInfo,
+        PlugDetectCapabilities, PlugEvent, Selector, UniqueInstanceId,
     },
     format_set::{ChannelAttributes, ChannelSet, PcmFormatSet},
+    Registry,
 };
+use fuchsia_zircon_status::Status;
 use itertools::Itertools;
 use lazy_static::lazy_static;
 use prettytable::{cell, format, row, Table};
 use serde::Serialize;
+use std::collections::BTreeMap;
 use std::fmt::Display;
 
 lazy_static! {
@@ -37,9 +45,6 @@
         .build();
 }
 
-// The Zircon Rust library cannot be built on host, so we can't use `zx::Time`.
-type ZxTime = i64;
-
 /// Formatter for [GainState].
 struct GainStateText<'a>(&'a GainState);
 
@@ -114,6 +119,15 @@
     }
 }
 
+/// Formatter for [PlugEvent].
+struct PlugEventText<'a>(&'a PlugEvent);
+
+impl Display for PlugEventText<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{} at {}", self.0.state, self.0.time)
+    }
+}
+
 /// Formatter for a vector of [ChannelSet]s.
 struct ChannelSetsText<'a>(&'a Vec<ChannelSet>);
 
@@ -183,7 +197,7 @@
 }
 
 /// Formatter for a map of ring buffer element IDs to their supported formats.
-struct SupportedRingBufferFormatsText<'a>(&'a Vec<PcmFormatSet>);
+struct SupportedRingBufferFormatsText<'a>(&'a BTreeMap<fadevice::ElementId, Vec<PcmFormatSet>>);
 
 impl Display for SupportedRingBufferFormatsText<'_> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -195,10 +209,122 @@
             table.set_titles(row![format!(
                 "{} {} with format sets:",
                 self.0.len(),
-                if self.0.len() == 1 { "element" } else { "elements" }
+                if self.0.len() == 1 { "element" } else { "elements" },
             )]);
-            for format_set in self.0 {
-                table.add_row(row![PcmFormatSetText(format_set)]);
+            for (element_id, format_sets) in self.0 {
+                table.add_row(row![format!(
+                    "Element {} has {} format {}:",
+                    element_id,
+                    format_sets.len(),
+                    if format_sets.len() == 1 { "set" } else { "sets" }
+                )]);
+                for format_set in format_sets {
+                    table.add_row(row![PcmFormatSetText(format_set)]);
+                }
+            }
+        }
+        table.fmt(f)
+    }
+}
+
+/// Formatter for a vector of [DaiFrameFormat]s.
+struct DaiFrameFormatsText<'a>(&'a Vec<DaiFrameFormat>);
+
+impl Display for DaiFrameFormatsText<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut table = Table::new();
+        table.set_format(*TABLE_FORMAT_EMPTY);
+        for dai_frame_format in self.0 {
+            match dai_frame_format {
+                DaiFrameFormat::Standard(standard_format) => {
+                    table.add_row(row![standard_format.to_string()]);
+                }
+                DaiFrameFormat::Custom(custom_format) => {
+                    let mut format_table = Table::new();
+                    format_table.set_format(*TABLE_FORMAT_NORMAL);
+                    table.set_titles(row![format!("Custom format: {}", custom_format)]);
+                    format_table.add_row(row![
+                        r->"Justification:",
+                        match custom_format.justification {
+                            DaiFrameFormatJustification::Left => "Left",
+                            DaiFrameFormatJustification::Right => "Right",
+                        }
+                    ]);
+                    format_table.add_row(row![
+                        r->"Clocking:",
+                        match custom_format.clocking {
+                            DaiFrameFormatClocking::RaisingSclk => "Raising sclk",
+                            DaiFrameFormatClocking::FallingSclk => "Falling sclk",
+                        }
+                    ]);
+                    format_table.add_row(row![
+                        r->"Frame sync offset (sclks):",
+                        custom_format.frame_sync_sclks_offset
+                    ]);
+                    format_table.add_row(
+                        row![r->"Frame sync size (sclks):", custom_format.frame_sync_size],
+                    );
+                    table.add_row(row![format_table]);
+                }
+            }
+        }
+        table.fmt(f)
+    }
+}
+
+/// Formatter for [DaiFormatSet].
+struct DaiFormatSetText<'a>(&'a DaiFormatSet);
+
+impl Display for DaiFormatSetText<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let dai_format_set = self.0;
+        let number_of_channels =
+            dai_format_set.number_of_channels.iter().map(ToString::to_string).join(", ");
+        let sample_formats =
+            dai_format_set.sample_formats.iter().map(ToString::to_string).join(", ");
+        let frame_formats = DaiFrameFormatsText(&dai_format_set.frame_formats);
+        let frame_rates = dai_format_set.frame_rates.iter().map(ToString::to_string).join(", ");
+        let bits_per_slot = dai_format_set.bits_per_slot.iter().map(ToString::to_string).join(", ");
+        let bits_per_sample =
+            dai_format_set.bits_per_sample.iter().map(ToString::to_string).join(", ");
+
+        let mut table = Table::new();
+        table.set_format(*TABLE_FORMAT_NESTED);
+        table.add_row(row!(r->"Number of channels:", number_of_channels));
+        table.add_row(row!(r->"Sample formats:", sample_formats));
+        table.add_row(row!(r->"Frame formats:", frame_formats));
+        table.add_row(row!(r->"Frame rates (Hz):", frame_rates));
+        table.add_row(row!(r->"Bits per slot:", bits_per_slot));
+        table.add_row(row!(r->"Bits per sample:", bits_per_sample));
+        table.fmt(f)
+    }
+}
+
+/// Formatter for a map of DAI interconnect element IDs to their supported formats.
+struct SupportedDaiFormatsText<'a>(&'a BTreeMap<fadevice::ElementId, Vec<DaiFormatSet>>);
+
+impl Display for SupportedDaiFormatsText<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut table = Table::new();
+        table.set_format(*TABLE_FORMAT_EMPTY);
+        if self.0.is_empty() {
+            table.add_row(row!["No format sets available."]);
+        } else {
+            table.set_titles(row![format!(
+                "{} {} with DAI format sets:",
+                self.0.len(),
+                if self.0.len() == 1 { "element" } else { "elements" },
+            )]);
+            for (element_id, dai_format_sets) in self.0 {
+                table.add_row(row![format!(
+                    "Element {} has {} DAI format {}:",
+                    element_id,
+                    dai_format_sets.len(),
+                    if dai_format_sets.len() == 1 { "set" } else { "sets" }
+                )]);
+                for dai_format_set in dai_format_sets {
+                    table.add_row(row![DaiFormatSetText(dai_format_set)]);
+                }
             }
         }
         table.fmt(f)
@@ -222,10 +348,8 @@
     #[serde(serialize_with = "serde_ext::serialize_option_gaincapabilities")]
     pub gain_capabilities: Option<GainCapabilities>,
 
-    #[serde(serialize_with = "serde_ext::serialize_option_tostring")]
-    pub plug_state: Option<PlugState>,
-
-    pub plug_time: Option<ZxTime>,
+    #[serde(serialize_with = "serde_ext::serialize_option_plugevent")]
+    pub plug_event: Option<PlugEvent>,
 
     #[serde(serialize_with = "serde_ext::serialize_option_tostring")]
     pub plug_detect_capabilities: Option<PlugDetectCapabilities>,
@@ -233,8 +357,11 @@
     #[serde(serialize_with = "serde_ext::serialize_option_clockdomain")]
     pub clock_domain: Option<ClockDomain>,
 
-    #[serde(serialize_with = "serde_ext::serialize_option_vec_pcmformatset")]
-    pub supported_ring_buffer_formats: Option<Vec<PcmFormatSet>>,
+    #[serde(serialize_with = "serde_ext::serialize_option_map_daiformatset")]
+    pub supported_dai_formats: Option<BTreeMap<fadevice::ElementId, Vec<DaiFormatSet>>>,
+
+    #[serde(serialize_with = "serde_ext::serialize_option_map_pcmformatset")]
+    pub supported_ring_buffer_formats: Option<BTreeMap<fadevice::ElementId, Vec<PcmFormatSet>>>,
 }
 
 impl From<InfoResult> for Table {
@@ -245,17 +372,30 @@
         table.add_row(row!(r->"Unique ID:", or_unknown(&value.unique_id)));
         table.add_row(row!(r->"Manufacturer:", or_unknown(&value.manufacturer)));
         table.add_row(row!(r->"Product:", or_unknown(&value.product_name)));
-        table.add_row(
-            row!(r->"Current gain:", or_unknown(&value.gain_state.as_ref().map(GainStateText))),
-        );
-        table.add_row(
-            row!(r->"Gain capabilities:", or_unknown(&value.gain_capabilities.as_ref().map(GainCapabilitiesText))),
-        );
-        table.add_row(row!(r->"Plug state:", or_unknown(&value.plug_state)));
-        table.add_row(row!(r->"Plug time:", or_unknown(&value.plug_time)));
+        table.add_row(row!(
+            r->"Current gain:",
+            or_unknown(&value.gain_state.as_ref().map(GainStateText)),
+        ));
+        table.add_row(row!(
+            r->"Gain capabilities:",
+            or_unknown(&value.gain_capabilities.as_ref().map(GainCapabilitiesText)),
+        ));
+        table.add_row(row!(
+            r->"Plug state:",
+            or_unknown(&value.plug_event.as_ref().map(PlugEventText)),
+        ));
         table.add_row(row!(r->"Plug detection:", or_unknown(&value.plug_detect_capabilities)));
         table.add_row(row!(r->"Clock domain:", or_unknown(&value.clock_domain)));
-        table.add_row(row!(r->"Ring buffer formats:", or_unknown(&value.supported_ring_buffer_formats.as_ref().map(SupportedRingBufferFormatsText))));
+        table.add_row(row!(
+            r->"DAI formats:",
+            or_unknown(&value.supported_dai_formats.as_ref().map(SupportedDaiFormatsText)),
+        ));
+        table.add_row(row!(
+            r->"Ring buffer formats:",
+            or_unknown(
+                &value.supported_ring_buffer_formats.as_ref().map(SupportedRingBufferFormatsText),
+            ),
+        ));
         table
     }
 }
@@ -265,66 +405,471 @@
     value.as_ref().map_or("<unknown>".to_string(), |value| value.to_string())
 }
 
-impl From<(fac::DeviceInfo, Selector)> for InfoResult {
-    fn from(t: (fac::DeviceInfo, Selector)) -> Self {
-        let (device_info, selector) = t;
+impl From<(Info, Selector)> for InfoResult {
+    fn from(value: (Info, Selector)) -> Self {
+        let (info, selector) = value;
 
         let device_path = match selector {
             Selector::Devfs(devfs) => Some(devfs.path()),
             Selector::Registry(_) => None,
         };
 
-        match device_info {
-            fac::DeviceInfo::StreamConfig(stream_info) => {
-                let stream_properties = stream_info.stream_properties;
-                let gain_state = stream_info.gain_state;
-                let plug_state = stream_info.plug_state;
-                let pcm_supported_formats = stream_info.supported_formats;
+        Self {
+            device_path,
+            unique_id: info.unique_instance_id(),
+            manufacturer: info.manufacturer(),
+            product_name: info.product_name(),
+            gain_state: info.gain_state(),
+            gain_capabilities: info.gain_capabilities(),
+            plug_event: info.plug_event(),
+            plug_detect_capabilities: info.plug_detect_capabilities(),
+            clock_domain: info.clock_domain(),
+            supported_ring_buffer_formats: info.supported_ring_buffer_formats(),
+            supported_dai_formats: info.supported_dai_formats(),
+        }
+    }
+}
 
-                match stream_properties {
-                    Some(stream_properties) => Self {
-                        device_path,
-                        unique_id: stream_properties.unique_id.map(UniqueInstanceId::from),
-                        manufacturer: stream_properties.manufacturer.clone(),
-                        product_name: stream_properties.product.clone(),
-                        gain_state: gain_state
-                            .and_then(|gain_state| GainState::try_from(gain_state).ok()),
-                        gain_capabilities: GainCapabilities::try_from(&stream_properties).ok(),
-                        plug_state: plug_state
-                            .clone()
-                            .map(PlugState::try_from)
-                            .transpose()
-                            .unwrap_or_default(),
-                        plug_time: plug_state.clone().and_then(|p| p.plug_state_time),
-                        plug_detect_capabilities: stream_properties
-                            .plug_detect_capabilities
-                            .map(Into::into),
-                        clock_domain: None,
-                        supported_ring_buffer_formats: pcm_supported_formats.map(|formats| {
-                            formats
-                                .into_iter()
-                                .map(PcmFormatSet::try_from)
-                                .collect::<Result<Vec<_>, _>>()
-                                .unwrap()
-                        }),
-                    },
-                    None => Self { device_path, ..Default::default() },
-                }
+pub struct HardwareCompositeInfo {
+    properties: fhaudio::CompositeProperties,
+    dai_formats: BTreeMap<fhaudio_sigproc::ElementId, Vec<fhaudio::DaiSupportedFormats>>,
+    ring_buffer_formats: BTreeMap<fhaudio_sigproc::ElementId, Vec<fhaudio::SupportedFormats>>,
+}
+
+pub struct HardwareCodecInfo {
+    properties: fhaudio::CodecProperties,
+    dai_formats: Vec<fhaudio::DaiSupportedFormats>,
+    plug_state: fhaudio::PlugState,
+}
+
+pub struct HardwareDaiInfo {
+    properties: fhaudio::DaiProperties,
+    dai_formats: Vec<fhaudio::DaiSupportedFormats>,
+    ring_buffer_formats: Vec<fhaudio::SupportedFormats>,
+}
+
+pub struct HardwareStreamConfigInfo {
+    properties: fhaudio::StreamProperties,
+    supported_formats: Vec<fhaudio::SupportedFormats>,
+    gain_state: fhaudio::GainState,
+    plug_state: fhaudio::PlugState,
+}
+
+/// Information about a device from its hardware protocol.
+pub enum HardwareInfo {
+    Composite(HardwareCompositeInfo),
+    Codec(HardwareCodecInfo),
+    Dai(HardwareDaiInfo),
+    StreamConfig(HardwareStreamConfigInfo),
+}
+
+impl HardwareInfo {
+    pub fn unique_instance_id(&self) -> Option<UniqueInstanceId> {
+        let id = match self {
+            HardwareInfo::Composite(composite) => composite.properties.unique_id,
+            HardwareInfo::Codec(codec) => codec.properties.unique_id,
+            HardwareInfo::Dai(dai) => dai.properties.unique_id,
+            HardwareInfo::StreamConfig(stream_config) => stream_config.properties.unique_id,
+        };
+        id.map(UniqueInstanceId)
+    }
+
+    pub fn manufacturer(&self) -> Option<String> {
+        match self {
+            HardwareInfo::Composite(composite) => composite.properties.manufacturer.clone(),
+            HardwareInfo::Codec(codec) => codec.properties.manufacturer.clone(),
+            HardwareInfo::Dai(dai) => dai.properties.manufacturer.clone(),
+            HardwareInfo::StreamConfig(stream_config) => {
+                stream_config.properties.manufacturer.clone()
             }
-            fac::DeviceInfo::Composite(composite_info) => {
-                let composite_properties = composite_info.composite_properties;
-                match composite_properties {
-                    Some(composite_properties) => Self {
-                        device_path,
-                        manufacturer: composite_properties.manufacturer,
-                        product_name: composite_properties.product,
-                        clock_domain: composite_properties.clock_domain.map(ClockDomain::from),
-                        ..Default::default()
-                    },
-                    None => Self { device_path, ..Default::default() },
-                }
+        }
+    }
+
+    pub fn product_name(&self) -> Option<String> {
+        match self {
+            HardwareInfo::Composite(composite) => composite.properties.product.clone(),
+            HardwareInfo::Codec(codec) => codec.properties.product.clone(),
+            HardwareInfo::Dai(dai) => dai.properties.product_name.clone(),
+            HardwareInfo::StreamConfig(stream_config) => stream_config.properties.product.clone(),
+        }
+    }
+
+    pub fn gain_capabilities(&self) -> Option<GainCapabilities> {
+        match self {
+            HardwareInfo::StreamConfig(stream_config) => {
+                GainCapabilities::try_from(&stream_config.properties).ok()
             }
-            _ => panic!("Unsupported device type"),
+            // TODO(https://fxbug.dev/333120537): Support gain caps for hardware Composite/Codec/Dai
+            _ => None,
+        }
+    }
+
+    pub fn plug_detect_capabilities(&self) -> Option<PlugDetectCapabilities> {
+        match self {
+            HardwareInfo::Codec(codec) => {
+                codec.properties.plug_detect_capabilities.map(PlugDetectCapabilities::from)
+            }
+            HardwareInfo::StreamConfig(stream_config) => {
+                stream_config.properties.plug_detect_capabilities.map(PlugDetectCapabilities::from)
+            }
+            // TODO(https://fxbug.dev/333120537): Support plug detect caps for hardware Composite/Dai
+            _ => None,
+        }
+        .clone()
+    }
+
+    pub fn clock_domain(&self) -> Option<ClockDomain> {
+        match self {
+            HardwareInfo::Composite(composite) => {
+                composite.properties.clock_domain.map(ClockDomain::from)
+            }
+            HardwareInfo::StreamConfig(stream_config) => {
+                stream_config.properties.clock_domain.map(ClockDomain::from)
+            }
+            _ => None,
+        }
+    }
+
+    pub fn supported_ring_buffer_formats(
+        &self,
+    ) -> Option<BTreeMap<fadevice::ElementId, Vec<PcmFormatSet>>> {
+        fn supported_formats_to_pcm_format_sets(
+            supported_formats: &Vec<fhaudio::SupportedFormats>,
+        ) -> Vec<PcmFormatSet> {
+            supported_formats
+                .iter()
+                .filter_map(|supported_formats| {
+                    let pcm_supported_formats = supported_formats.pcm_supported_formats.clone()?;
+                    PcmFormatSet::try_from(pcm_supported_formats).ok()
+                })
+                .collect()
+        }
+
+        match self {
+            HardwareInfo::Composite(composite) => Some(
+                composite
+                    .ring_buffer_formats
+                    .iter()
+                    .map(|(element_id, supported_formats)| {
+                        (*element_id, supported_formats_to_pcm_format_sets(supported_formats))
+                    })
+                    .collect(),
+            ),
+            HardwareInfo::Codec(_) => None,
+            HardwareInfo::Dai(dai) => Some({
+                let pcm_format_sets =
+                    supported_formats_to_pcm_format_sets(&dai.ring_buffer_formats);
+                let mut map = BTreeMap::new();
+                map.insert(fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID, pcm_format_sets);
+                map
+            }),
+            HardwareInfo::StreamConfig(stream_config) => Some({
+                let pcm_format_sets =
+                    supported_formats_to_pcm_format_sets(&stream_config.supported_formats);
+                let mut map = BTreeMap::new();
+                map.insert(fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID, pcm_format_sets);
+                map
+            }),
+        }
+    }
+
+    pub fn supported_dai_formats(
+        &self,
+    ) -> Option<BTreeMap<fadevice::ElementId, Vec<DaiFormatSet>>> {
+        fn dai_supported_formats_to_dai_format_sets(
+            dai_supported_formats: &Vec<fhaudio::DaiSupportedFormats>,
+        ) -> Vec<DaiFormatSet> {
+            dai_supported_formats
+                .iter()
+                .map(|dai_supported_formats| DaiFormatSet::from(dai_supported_formats.clone()))
+                .collect()
+        }
+
+        match self {
+            HardwareInfo::Composite(composite) => Some(
+                composite
+                    .dai_formats
+                    .iter()
+                    .map(|(element_id, dai_supported_formats)| {
+                        (
+                            *element_id,
+                            dai_supported_formats_to_dai_format_sets(dai_supported_formats),
+                        )
+                    })
+                    .collect(),
+            ),
+            HardwareInfo::Codec(codec) => Some({
+                let dai_format_sets = dai_supported_formats_to_dai_format_sets(&codec.dai_formats);
+                let mut map = BTreeMap::new();
+                map.insert(fadevice::DEFAULT_DAI_INTERCONNECT_ELEMENT_ID, dai_format_sets);
+                map
+            }),
+            HardwareInfo::Dai(dai) => Some({
+                let dai_format_sets = dai_supported_formats_to_dai_format_sets(&dai.dai_formats);
+                let mut map = BTreeMap::new();
+                map.insert(fadevice::DEFAULT_DAI_INTERCONNECT_ELEMENT_ID, dai_format_sets);
+                map
+            }),
+            HardwareInfo::StreamConfig(_) => None,
+        }
+    }
+
+    pub fn gain_state(&self) -> Option<GainState> {
+        match self {
+            // TODO(https://fxbug.dev/334981374): Support gain state for hardware Composite
+            HardwareInfo::Composite(_) => None,
+            HardwareInfo::Codec(_) | HardwareInfo::Dai(_) => None,
+            HardwareInfo::StreamConfig(stream_config) => {
+                stream_config.gain_state.clone().try_into().ok()
+            }
+        }
+    }
+
+    pub fn plug_event(&self) -> Option<PlugEvent> {
+        match self {
+            // TODO(https://fxbug.dev/334980316): Support plug state for hardware Composite
+            HardwareInfo::Composite(_) => None,
+            HardwareInfo::Codec(codec) => codec.plug_state.clone().try_into().ok(),
+            HardwareInfo::Dai(_) => None,
+            HardwareInfo::StreamConfig(stream_config) => {
+                stream_config.plug_state.clone().try_into().ok()
+            }
+        }
+    }
+}
+
+/// Information about a device from `fuchsia.audio.device.Registry`.
+pub struct RegistryInfo {
+    device_info: DeviceInfo,
+    gain_state: Option<GainState>,
+    plug_event: Option<PlugEvent>,
+}
+
+pub enum Info {
+    Hardware(HardwareInfo),
+    Registry(RegistryInfo),
+}
+
+impl Info {
+    pub fn unique_instance_id(&self) -> Option<UniqueInstanceId> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.unique_instance_id(),
+            Info::Registry(registry_info) => registry_info.device_info.unique_instance_id(),
+        }
+    }
+
+    pub fn manufacturer(&self) -> Option<String> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.manufacturer(),
+            Info::Registry(registry_info) => registry_info.device_info.0.manufacturer.clone(),
+        }
+    }
+
+    pub fn product_name(&self) -> Option<String> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.product_name(),
+            Info::Registry(registry_info) => registry_info.device_info.0.product.clone(),
+        }
+    }
+
+    pub fn gain_state(&self) -> Option<GainState> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.gain_state(),
+            Info::Registry(registry_info) => registry_info.gain_state.clone(),
+        }
+    }
+
+    pub fn gain_capabilities(&self) -> Option<GainCapabilities> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.gain_capabilities(),
+            Info::Registry(registry_info) => registry_info.device_info.gain_capabilities(),
+        }
+    }
+
+    pub fn plug_event(&self) -> Option<PlugEvent> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.plug_event(),
+            Info::Registry(registry_info) => registry_info.plug_event.clone(),
+        }
+    }
+
+    pub fn plug_detect_capabilities(&self) -> Option<PlugDetectCapabilities> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.plug_detect_capabilities(),
+            Info::Registry(registry_info) => registry_info.device_info.plug_detect_capabilities(),
+        }
+    }
+
+    pub fn clock_domain(&self) -> Option<ClockDomain> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.clock_domain(),
+            Info::Registry(registry_info) => registry_info.device_info.clock_domain(),
+        }
+    }
+
+    pub fn supported_ring_buffer_formats(
+        &self,
+    ) -> Option<BTreeMap<fadevice::ElementId, Vec<PcmFormatSet>>> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.supported_ring_buffer_formats(),
+            Info::Registry(registry_info) => {
+                registry_info.device_info.supported_ring_buffer_formats().ok()
+            }
+        }
+    }
+
+    pub fn supported_dai_formats(
+        &self,
+    ) -> Option<BTreeMap<fadevice::ElementId, Vec<DaiFormatSet>>> {
+        match self {
+            Info::Hardware(hw_info) => hw_info.supported_dai_formats(),
+            Info::Registry(registry_info) => registry_info.device_info.supported_dai_formats().ok(),
+        }
+    }
+}
+
+/// Returns information about a Codec device from its hardware protocol.
+async fn get_hw_codec_info(codec: &fhaudio::CodecProxy) -> fho::Result<HardwareCodecInfo> {
+    let properties =
+        codec.get_properties().await.bug_context("Failed to call Codec.GetProperties")?;
+
+    let dai_formats = codec
+        .get_dai_formats()
+        .await
+        .bug_context("Failed to call Codec.GetDaiFormats")?
+        .map_err(|status| Status::from_raw(status))
+        .bug_context("Failed to get DAI formats")?;
+
+    let plug_state =
+        codec.watch_plug_state().await.bug_context("Failed to call Codec.WatchPlugState")?;
+
+    Ok(HardwareCodecInfo { properties, dai_formats, plug_state })
+}
+
+/// Returns information about a Dai device from its hardware protocol.
+async fn get_hw_dai_info(dai: &fhaudio::DaiProxy) -> fho::Result<HardwareDaiInfo> {
+    let properties = dai.get_properties().await.bug_context("Failed to call Dai.GetProperties")?;
+
+    let dai_formats = dai
+        .get_dai_formats()
+        .await
+        .bug_context("Failed to call Dai.GetDaiFormats")?
+        .map_err(|status| Status::from_raw(status))
+        .bug_context("Failed to get DAI formats")?;
+
+    let ring_buffer_formats = dai
+        .get_ring_buffer_formats()
+        .await
+        .bug_context("Failed to call Dai.GetRingBufferFormats")?
+        .map_err(|status| Status::from_raw(status))
+        .bug_context("Failed to get ring buffer formats")?;
+
+    Ok(HardwareDaiInfo { properties, dai_formats, ring_buffer_formats })
+}
+
+/// Returns information about a Composite device from its hardware protocol.
+async fn get_hw_composite_info(
+    composite: &fhaudio::CompositeProxy,
+) -> fho::Result<HardwareCompositeInfo> {
+    let properties =
+        composite.get_properties().await.bug_context("Failed to call Composite.GetProperties")?;
+
+    // TODO(https://fxbug.dev/333120537): Support fetching DAI formats for hardware Composite
+    let dai_formats = BTreeMap::new();
+
+    // TODO(https://fxbug.dev/333120537): Support fetching ring buffer formats for hardware Composite
+    let ring_buffer_formats = BTreeMap::new();
+
+    Ok(HardwareCompositeInfo { properties, dai_formats, ring_buffer_formats })
+}
+
+/// Returns information about a StreamConfig device from its hardware protocol.
+async fn get_hw_stream_config_info(
+    stream_config: &fhaudio::StreamConfigProxy,
+) -> fho::Result<HardwareStreamConfigInfo> {
+    let properties = stream_config
+        .get_properties()
+        .await
+        .bug_context("Failed to call StreamConfig.GetProperties")?;
+
+    let supported_formats = stream_config
+        .get_supported_formats()
+        .await
+        .bug_context("Failed to call StreamConfig.GetSupportedFormats")?;
+
+    let gain_state = stream_config
+        .watch_gain_state()
+        .await
+        .bug_context("Failed to call StreamConfig.WatchGainState")?;
+
+    let plug_state = stream_config
+        .watch_plug_state()
+        .await
+        .bug_context("Failed to call StreamConfig.WatchPlugState")?;
+
+    Ok(HardwareStreamConfigInfo { properties, supported_formats, gain_state, plug_state })
+}
+
+/// Returns information about a device from its hardware protocol in devfs.
+async fn get_hardware_info(
+    dev_class: &fio::DirectoryProxy,
+    selector: DevfsSelector,
+) -> fho::Result<HardwareInfo> {
+    let protocol_path = selector.relative_path();
+
+    match selector.device_type().0 {
+        fadevice::DeviceType::Codec => {
+            let codec = connect::connect_hw_codec(dev_class, protocol_path.as_str())?;
+            let codec_info = get_hw_codec_info(&codec).await?;
+            Ok(HardwareInfo::Codec(codec_info))
+        }
+        fadevice::DeviceType::Composite => {
+            let composite = connect::connect_hw_composite(dev_class, protocol_path.as_str())?;
+            let composite_info = get_hw_composite_info(&composite).await?;
+            Ok(HardwareInfo::Composite(composite_info))
+        }
+        fadevice::DeviceType::Dai => {
+            let dai = connect::connect_hw_dai(dev_class, protocol_path.as_str())?;
+            let dai_info = get_hw_dai_info(&dai).await?;
+            Ok(HardwareInfo::Dai(dai_info))
+        }
+        fadevice::DeviceType::Input | fadevice::DeviceType::Output => {
+            let stream_config =
+                connect::connect_hw_streamconfig(dev_class, protocol_path.as_str())?;
+            let stream_config_info = get_hw_stream_config_info(&stream_config).await?;
+            Ok(HardwareInfo::StreamConfig(stream_config_info))
+        }
+        _ => Err(bug!("Unsupported device type")),
+    }
+}
+
+/// Returns a device info from the target.
+///
+/// If the selector is a [RegistrySelector] for a registry device,
+/// `registry` must be Some.
+pub async fn get_info(
+    dev_class: &fio::DirectoryProxy,
+    registry: Option<&Registry>,
+    selector: Selector,
+) -> fho::Result<Info> {
+    match selector {
+        Selector::Devfs(devfs_selector) => {
+            let hw_info = get_hardware_info(dev_class, devfs_selector).await?;
+            Ok(Info::Hardware(hw_info))
+        }
+        Selector::Registry(registry_selector) => {
+            let device_info = registry
+                .ok_or_else(|| bug!("Registry not available"))?
+                .get(registry_selector.token_id())
+                .await
+                .ok_or_else(|| user_error!("No device with given ID exists in registry"))?;
+            let registry_info = RegistryInfo {
+                device_info,
+                // TODO(https://fxbug.dev/329150383): Supports gain_state/plug_state/plug_time for ADR devices
+                gain_state: None,
+                plug_event: None,
+            };
+            Ok(Info::Registry(registry_info))
         }
     }
 }
@@ -335,10 +880,10 @@
     use fidl_fuchsia_audio_device as fadevice;
     use fidl_fuchsia_hardware_audio as fhaudio;
     use fuchsia_audio::format::SampleType;
+    use serde_json::json;
 
-    #[test]
-    fn test_info_result_table() {
-        let info_result = InfoResult {
+    lazy_static! {
+        pub static ref TEST_INFO_RESULT: InfoResult = InfoResult {
             device_path: Some(Utf8PathBuf::from("/dev/class/audio-input/0c8301e0")),
             unique_id: Some(UniqueInstanceId([
                 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
@@ -358,34 +903,107 @@
                 can_mute: Some(true),
                 can_agc: Some(false),
             }),
-            plug_state: Some(fadevice::PlugState::Plugged.into()),
-            plug_time: Some(123456789),
+            plug_event: Some(PlugEvent {
+                state: fadevice::PlugState::Plugged.into(),
+                time: 123456789,
+            }),
             plug_detect_capabilities: Some(fadevice::PlugDetectCapabilities::Hardwired.into()),
             clock_domain: Some(ClockDomain(fhaudio::CLOCK_DOMAIN_MONOTONIC)),
-            supported_ring_buffer_formats: Some(vec![
-                PcmFormatSet {
-                    channel_sets: vec![
-                        ChannelSet::try_from(vec![ChannelAttributes::default()]).unwrap()
+            supported_dai_formats: Some({
+                let mut map = BTreeMap::new();
+                map.insert(
+                    fadevice::DEFAULT_DAI_INTERCONNECT_ELEMENT_ID,
+                    vec![fhaudio::DaiSupportedFormats {
+                        number_of_channels: vec![1, 2],
+                        sample_formats: vec![
+                            fhaudio::DaiSampleFormat::PcmSigned,
+                            fhaudio::DaiSampleFormat::PcmUnsigned,
+                        ],
+                        frame_formats: vec![
+                            fhaudio::DaiFrameFormat::FrameFormatStandard(
+                                fhaudio::DaiFrameFormatStandard::StereoLeft,
+                            ),
+                            fhaudio::DaiFrameFormat::FrameFormatStandard(
+                                fhaudio::DaiFrameFormatStandard::StereoRight,
+                            ),
+                        ],
+                        frame_rates: vec![16000, 22050, 32000, 44100, 48000, 88200, 96000],
+                        bits_per_slot: vec![32],
+                        bits_per_sample: vec![8, 16],
+                    }
+                    .into()],
+                );
+                map.insert(
+                    123,
+                    vec![fhaudio::DaiSupportedFormats {
+                        number_of_channels: vec![1],
+                        sample_formats: vec![fhaudio::DaiSampleFormat::PcmFloat],
+                        frame_formats: vec![fhaudio::DaiFrameFormat::FrameFormatCustom(
+                            fhaudio::DaiFrameFormatCustom {
+                                left_justified: false,
+                                sclk_on_raising: true,
+                                frame_sync_sclks_offset: 1,
+                                frame_sync_size: 2,
+                            },
+                        )],
+                        frame_rates: vec![16000, 22050, 32000, 44100, 48000, 88200, 96000],
+                        bits_per_slot: vec![16, 32],
+                        bits_per_sample: vec![16],
+                    }
+                    .into()],
+                );
+                map
+            }),
+            supported_ring_buffer_formats: Some({
+                let mut map = BTreeMap::new();
+                map.insert(
+                    fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID,
+                    vec![PcmFormatSet {
+                        channel_sets: vec![
+                            ChannelSet::try_from(vec![ChannelAttributes::default()]).unwrap(),
+                            ChannelSet::try_from(vec![
+                                ChannelAttributes::default(),
+                                ChannelAttributes::default(),
+                            ])
+                            .unwrap(),
+                        ],
+                        sample_types: vec![SampleType::Int16],
+                        frame_rates: vec![16000, 22050, 32000, 44100, 48000, 88200, 96000],
+                    }],
+                );
+                map.insert(
+                    123,
+                    vec![
+                        PcmFormatSet {
+                            channel_sets: vec![ChannelSet::try_from(vec![
+                                ChannelAttributes::default(),
+                            ])
+                            .unwrap()],
+                            sample_types: vec![SampleType::Uint8, SampleType::Int16],
+                            frame_rates: vec![16000, 22050, 32000],
+                        },
+                        PcmFormatSet {
+                            channel_sets: vec![
+                                ChannelSet::try_from(vec![ChannelAttributes::default()]).unwrap(),
+                                ChannelSet::try_from(vec![
+                                    ChannelAttributes::default(),
+                                    ChannelAttributes::default(),
+                                ])
+                                .unwrap(),
+                            ],
+                            sample_types: vec![SampleType::Float32],
+                            frame_rates: vec![44100, 48000, 88200, 96000],
+                        },
                     ],
-                    sample_types: vec![SampleType::Uint8, SampleType::Int16],
-                    frame_rates: vec![16000, 22050, 32000],
-                },
-                PcmFormatSet {
-                    channel_sets: vec![
-                        ChannelSet::try_from(vec![ChannelAttributes::default()]).unwrap(),
-                        ChannelSet::try_from(vec![
-                            ChannelAttributes::default(),
-                            ChannelAttributes::default(),
-                        ])
-                        .unwrap(),
-                    ],
-                    sample_types: vec![SampleType::Float32],
-                    frame_rates: vec![44100, 48000, 88200, 96000],
-                },
-            ]),
+                );
+                map
+            }),
         };
+    }
 
-        let output = Table::from(info_result).to_string();
+    #[test]
+    fn test_info_result_table() {
+        let output = Table::from(TEST_INFO_RESULT.clone()).to_string();
 
         let expected = r#"
                  Path:  /dev/class/audio-input/0c8301e0
@@ -394,11 +1012,47 @@
               Product:  Test product
          Current gain:  -3 dB (unmuted, AGC off)
     Gain capabilities:  Gain range [-100 dB, 0 dB]; 0 dB step (continuous); can mute; cannot AGC
-           Plug state:  Plugged
-            Plug time:  123456789
+           Plug state:  Plugged at 123456789
        Plug detection:  Hardwired
          Clock domain:  0 (monotonic)
+          DAI formats:  2 elements with DAI format sets:
+                        Element 1 has 1 DAI format set:
+                        ┌──────────────────────────────────────────────────────────────────────┐
+                        │ Number of channels:  1, 2                                            │
+                        │     Sample formats:  pcm_signed, pcm_unsigned                        │
+                        │      Frame formats:  stereo_left                                     │
+                        │                      stereo_right                                    │
+                        │   Frame rates (Hz):  16000, 22050, 32000, 44100, 48000, 88200, 96000 │
+                        │      Bits per slot:  32                                              │
+                        │    Bits per sample:  8, 16                                           │
+                        └──────────────────────────────────────────────────────────────────────┘
+                        Element 123 has 1 DAI format set:
+                        ┌──────────────────────────────────────────────────────────────────────┐
+                        │ Number of channels:  1                                               │
+                        │     Sample formats:  pcm_float                                       │
+                        │      Frame formats:  Custom format: right_justified,raising_sclk,1,2 │
+                        │                                    Justification:  Right             │
+                        │                                         Clocking:  Raising sclk      │
+                        │                        Frame sync offset (sclks):  1                 │
+                        │                          Frame sync size (sclks):  2                 │
+                        │   Frame rates (Hz):  16000, 22050, 32000, 44100, 48000, 88200, 96000 │
+                        │      Bits per slot:  16, 32                                          │
+                        │    Bits per sample:  16                                              │
+                        └──────────────────────────────────────────────────────────────────────┘
   Ring buffer formats:  2 elements with format sets:
+                        Element 0 has 1 format set:
+                        ┌────────────────────────────────────────────────────────────────────────────────────┐
+                        │       Sample types:  int16                                                         │
+                        │   Frame rates (Hz):  16000, 22050, 32000, 44100, 48000, 88200, 96000               │
+                        │ Number of channels:  1, 2                                                          │
+                        │ Channel attributes:  1 channel:   Channel 1:  Min frequency (Hz):  <unknown>       │
+                        │                                               Max frequency (Hz):  <unknown>       │
+                        │                      2 channels:  Channel 1:  Min frequency (Hz):  <unknown>       │
+                        │                                               Max frequency (Hz):  <unknown>       │
+                        │                                   Channel 2:  Min frequency (Hz):  <unknown>       │
+                        │                                               Max frequency (Hz):  <unknown>       │
+                        └────────────────────────────────────────────────────────────────────────────────────┘
+                        Element 123 has 2 format sets:
                         ┌───────────────────────────────────────────────────────────────────────────────────┐
                         │       Sample types:  uint8, int16                                                 │
                         │   Frame rates (Hz):  16000, 22050, 32000                                          │
@@ -422,4 +1076,109 @@
 
         assert_eq!(expected, output);
     }
+
+    #[test]
+    pub fn test_info_result_json() {
+        let output = serde_json::to_value(&*TEST_INFO_RESULT).unwrap();
+
+        let expected = json!({
+            "device_path": "/dev/class/audio-input/0c8301e0",
+            "unique_id": "000102030405060708090a0b0c0d0e0f",
+            "manufacturer": "Test manufacturer",
+            "product_name": "Test product",
+            "gain_state": {
+                "gain_db": -3.0,
+                "muted": false,
+                "agc_enabled": false
+            },
+            "gain_capabilities": {
+                "min_gain_db": -100.0,
+                "max_gain_db": 0.0,
+                "gain_step_db": 0.0,
+                "can_mute": true,
+                "can_agc": false
+            },
+            "plug_event": {
+                "state": "Plugged",
+                "time": 123456789,
+            },
+            "plug_detect_capabilities": "Hardwired",
+            "clock_domain": 0,
+            "supported_dai_formats": {
+                "1": [
+                    {
+                        "number_of_channels": [1, 2],
+                        "sample_formats": ["pcm_signed", "pcm_unsigned"],
+                        "frame_formats": ["stereo_left", "stereo_right"],
+                        "frame_rates": [16000, 22050, 32000, 44100, 48000, 88200, 96000],
+                        "bits_per_slot": [32],
+                        "bits_per_sample": [8, 16]
+                    }
+                ],
+                "123": [
+                    {
+                        "number_of_channels": [1],
+                        "sample_formats": ["pcm_float"],
+                        "frame_formats": ["custom:right_justified,raising_sclk,1,2"],
+                        "frame_rates": [16000, 22050, 32000, 44100, 48000, 88200, 96000],
+                        "bits_per_slot": [16, 32],
+                        "bits_per_sample": [16]
+                    }
+                ]
+            },
+            "supported_ring_buffer_formats": {
+                "0": [
+                    {
+                        "channel_sets": [
+                            {
+                                "attributes": [
+                                    { "min_frequency": null, "max_frequency": null }
+                                ]
+                            },
+                            {
+                                "attributes": [
+                                    { "min_frequency": null, "max_frequency": null },
+                                    { "min_frequency": null, "max_frequency": null }
+                                ]
+                            }
+                        ],
+                        "sample_types": ["int16"],
+                        "frame_rates": [16000, 22050, 32000, 44100, 48000, 88200, 96000]
+                    }
+                ],
+                "123": [
+                    {
+                        "channel_sets": [
+                            {
+                                "attributes": [
+                                    { "min_frequency": null, "max_frequency": null }
+                                ]
+                            }
+                        ],
+                        "sample_types": ["uint8", "int16"],
+                        "frame_rates": [16000, 22050, 32000]
+                    },
+                    {
+                        "channel_sets": [
+                            {
+                                "attributes": [
+                                    { "min_frequency": null, "max_frequency": null }
+                                ]
+                            },
+                            {
+                                "attributes": [
+                                    { "min_frequency": null, "max_frequency": null },
+                                    { "min_frequency": null, "max_frequency": null }
+                                ]
+                            }
+                        ],
+                        "sample_types": ["float32"],
+                        "frame_rates": [44100, 48000, 88200, 96000]
+                    }
+                ]
+            }
+        });
+
+        assert_eq!(output, expected);
+    }
 }
diff --git a/src/developer/ffx/plugins/audio/device/src/lib.rs b/src/developer/ffx/plugins/audio/device/src/lib.rs
index 0553634..8f3ae0e 100644
--- a/src/developer/ffx/plugins/audio/device/src/lib.rs
+++ b/src/developer/ffx/plugins/audio/device/src/lib.rs
@@ -6,8 +6,8 @@
 use async_trait::async_trait;
 use blocking::Unblock;
 use ffx_audio_common::ffxtool::{exposed_dir, optional_moniker};
-use ffx_audio_device_args::{DeviceCommand, DeviceRecordCommand, SubCommand};
-use ffx_command::{bug, user_error};
+use ffx_audio_device_args::{DeviceCommand, RecordCommand, SubCommand};
+use ffx_command::user_error;
 use fho::{moniker, FfxContext, FfxMain, FfxTool, MachineWriter, ToolIO};
 use fidl::{
     endpoints::{create_proxy, ServerEnd},
@@ -18,13 +18,14 @@
 use fidl_fuchsia_hardware_audio as fhaudio;
 use fidl_fuchsia_io as fio;
 use fidl_fuchsia_media as fmedia;
-use fuchsia_audio::device::Selector;
+use fuchsia_audio::{device::Selector, Registry};
 use fuchsia_zircon_status::Status;
 use futures::{AsyncWrite, FutureExt};
 use prettytable::Table;
 use serde::Serialize;
 use std::io::Read;
 
+mod connect;
 mod info;
 pub mod list;
 mod serde_ext;
@@ -61,10 +62,12 @@
     type Writer = MachineWriter<DeviceResult>;
 
     async fn main(self, mut writer: Self::Writer) -> fho::Result<()> {
+        let registry = self.registry.map(Registry::new);
+
         let devices = {
             let query = DeviceQuery::try_from(&self.cmd)
                 .map_err(|msg| user_error!("Invalid device query: {msg}"))?;
-            let mut devices = list::get_devices(&self.dev_class, self.registry.as_ref())
+            let mut devices = list::get_devices(&self.dev_class, registry.as_ref())
                 .await
                 .bug_context("Failed to get devices")?;
             match &mut devices {
@@ -87,7 +90,9 @@
 
         match self.cmd.subcommand {
             SubCommand::List(_) => unreachable!(),
-            SubCommand::Info(_) => device_info(self.device_controller, selector, writer).await,
+            SubCommand::Info(_) => {
+                device_info(&self.dev_class, registry.as_ref(), selector, writer).await
+            }
             SubCommand::Play(play_command) => {
                 let (play_remote, play_local) = fidl::Socket::create_datagram();
                 let reader: Box<dyn Read + Send + 'static> = match &play_command.file {
@@ -101,8 +106,16 @@
                     None => Box::new(std::io::stdin()),
                 };
 
-                device_play(self.play_controller, selector, play_local, play_remote, reader, writer)
-                    .await
+                device_play(
+                    self.play_controller,
+                    selector,
+                    play_command.element_id,
+                    play_local,
+                    play_remote,
+                    reader,
+                    writer,
+                )
+                .await
             }
             SubCommand::Record(record_command) => {
                 let mut stdout = Unblock::new(std::io::stdout());
@@ -150,21 +163,12 @@
 }
 
 async fn device_info(
-    device_control: fac::DeviceControlProxy,
+    dev_class: &fio::DirectoryProxy,
+    registry: Option<&Registry>,
     selector: Selector,
     mut writer: MachineWriter<DeviceResult>,
 ) -> fho::Result<()> {
-    let info = device_control
-        .get_device_info(fac::DeviceControlGetDeviceInfoRequest {
-            device: Some(selector.clone().into()),
-            ..Default::default()
-        })
-        .await
-        .bug_context("Failed to call DeviceControl.GetDeviceInfo")?
-        .map_err(|status| Status::from_raw(status))
-        .bug_context("Failed to get device info")?;
-
-    let device_info = info.device_info.ok_or_else(|| bug!("DeviceInfo missing from response."))?;
+    let device_info = info::get_info(dev_class, registry, selector.clone()).await?;
 
     let info_result = info::InfoResult::from((device_info, selector));
     let result = DeviceResult::Info(info_result.clone());
@@ -182,6 +186,7 @@
 async fn device_play(
     player_controller: fac::PlayerProxy,
     selector: Selector,
+    ring_buffer_element_id: Option<fadevice::ElementId>,
     play_local: fidl::Socket,
     play_remote: fidl::Socket,
     input_reader: Box<dyn Read + Send + 'static>,
@@ -193,9 +198,15 @@
         .duplicate_handle(fidl::Rights::SAME_RIGHTS)
         .bug_context("Error duplicating socket")?;
 
+    let ring_buffer_element_id =
+        ring_buffer_element_id.unwrap_or(fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID);
+
     let request = fac::PlayerPlayRequest {
         wav_source: Some(remote_socket),
-        destination: Some(fac::PlayDestination::DeviceRingBuffer(selector.into())),
+        destination: Some(fac::PlayDestination::DeviceRingBuffer(fac::DeviceRingBuffer {
+            selector: selector.into(),
+            ring_buffer_element_id,
+        })),
         gain_settings: Some(fac::GainSettings {
             mute: None, // TODO(https://fxbug.dev/42072218)
             gain: None, // TODO(https://fxbug.dev/42072218)
@@ -223,7 +234,7 @@
 async fn device_record<W, E>(
     recorder: fac::RecorderProxy,
     selector: Selector,
-    record_command: DeviceRecordCommand,
+    record_command: RecordCommand,
     cancel_server: ServerEnd<fac::RecordCancelerMarker>,
     mut output_writer: W,
     mut output_error_writer: E,
@@ -235,8 +246,14 @@
 {
     let (record_remote, record_local) = fidl::Socket::create_datagram();
 
+    let ring_buffer_element_id =
+        record_command.element_id.unwrap_or(fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID);
+
     let request = fac::RecorderRecordRequest {
-        source: Some(fac::RecordSource::DeviceRingBuffer(selector.into())),
+        source: Some(fac::RecordSource::DeviceRingBuffer(fac::DeviceRingBuffer {
+            selector: selector.into(),
+            ring_buffer_element_id,
+        })),
         stream_type: Some(fmedia::AudioStreamType::from(record_command.format)),
         duration: record_command.duration.map(|duration| duration.as_nanos() as i64),
         canceler: Some(cancel_server),
@@ -323,6 +340,8 @@
             device_type: fadevice::DeviceType::Output,
         });
 
+        let ring_buffer_element_id = Some(fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID);
+
         let (play_remote, play_local) = fidl::Socket::create_datagram();
         let mut async_play_local = fidl::AsyncSocket::from_socket(
             play_local.duplicate_handle(fidl::Rights::SAME_RIGHTS).unwrap(),
@@ -333,6 +352,7 @@
         device_play(
             audio_player,
             selector,
+            ring_buffer_element_id,
             play_local,
             play_remote,
             Box::new(&ffx_audio_common::tests::WAV_HEADER_EXT[..]),
@@ -378,9 +398,19 @@
             device_type: fadevice::DeviceType::Output,
         });
 
-        device_play(audio_player, selector, play_local, play_remote, Box::new(file_reader), writer)
-            .await
-            .unwrap();
+        let element_id = Some(fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID);
+
+        device_play(
+            audio_player,
+            selector,
+            element_id,
+            play_local,
+            play_remote,
+            Box::new(file_reader),
+            writer,
+        )
+        .await
+        .unwrap();
 
         let expected_output =
             format!("Successfully processed all audio data. Bytes processed: \"1\"\n");
@@ -399,13 +429,14 @@
         let test_buffers = TestBuffers::default();
         let mut result_writer: SimpleWriter = SimpleWriter::new_test(&test_buffers);
 
-        let record_command = DeviceRecordCommand {
+        let record_command = RecordCommand {
             duration: Some(std::time::Duration::from_nanos(500)),
             format: Format {
                 sample_type: SampleType::Uint8,
                 frames_per_second: 48000,
                 channels: 1,
             },
+            element_id: Some(fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID),
         };
 
         let selector = Selector::from(fac::Devfs {
@@ -449,13 +480,14 @@
         let test_buffers = TestBuffers::default();
         let mut result_writer: SimpleWriter = SimpleWriter::new_test(&test_buffers);
 
-        let record_command = DeviceRecordCommand {
+        let record_command = RecordCommand {
             duration: None,
             format: Format {
                 sample_type: SampleType::Uint8,
                 frames_per_second: 48000,
                 channels: 1,
             },
+            element_id: Some(fadevice::DEFAULT_RING_BUFFER_ELEMENT_ID),
         };
 
         let selector = Selector::from(fac::Devfs {
@@ -486,81 +518,6 @@
     }
 
     #[fuchsia::test]
-    pub async fn test_stream_config_info() -> Result<(), fho::Error> {
-        let audio_daemon = ffx_audio_common::tests::fake_audio_daemon();
-
-        let selector = Selector::from(fac::Devfs {
-            id: "abc123".to_string(),
-            device_type: fadevice::DeviceType::Input,
-        });
-
-        let test_buffers = TestBuffers::default();
-        let writer: MachineWriter<DeviceResult> =
-            MachineWriter::new_test(Some(ffx_writer::Format::Json), &test_buffers);
-        let result = device_info(audio_daemon, selector, writer).await;
-        result.unwrap();
-
-        let stdout = test_buffers.into_stdout_str();
-        let stdout_expected = "{\"Info\":{\
-            \"device_path\":\"/dev/class/audio-input/abc123\",\
-            \"unique_id\":\"000102030405060708090a0b0c0d0e0f\",\
-            \"manufacturer\":\"Spacely Sprockets\",\"product_name\":\"Test Microphone\",\
-            \"gain_state\":null,\
-            \"gain_capabilities\":{\
-                \"min_gain_db\":-32.0,\
-                \"max_gain_db\":60.0,\
-                \"gain_step_db\":0.5,\
-                \"can_mute\":true,\
-                \"can_agc\":true\
-            },\
-            \"plug_state\":null,\
-            \"plug_time\":null,\
-            \"plug_detect_capabilities\":null,\
-            \"clock_domain\":null,\
-            \"supported_ring_buffer_formats\":[\
-                {\"channel_sets\":[\
-                    {\"attributes\":[{\"min_frequency\":null,\"max_frequency\":null}]},\
-                    {\"attributes\":[{\"min_frequency\":null,\"max_frequency\":null},\
-                                     {\"min_frequency\":null,\"max_frequency\":null}]}\
-                ],\
-                \"sample_types\":[\"int16\"],\
-                \"frame_rates\":[16000,22050,32000,44100,48000,88200,96000]}\
-            ]}}\n";
-
-        assert_eq!(stdout, stdout_expected);
-
-        Ok(())
-    }
-
-    #[fuchsia::test]
-    pub async fn test_composite_info() -> Result<(), fho::Error> {
-        let audio_daemon = ffx_audio_common::tests::fake_audio_daemon();
-
-        let selector = Selector::from(fac::Devfs {
-            id: "abc123".to_string(),
-            device_type: fadevice::DeviceType::Composite,
-        });
-
-        let test_buffers = TestBuffers::default();
-        let writer: MachineWriter<DeviceResult> =
-            MachineWriter::new_test(Some(ffx_writer::Format::Json), &test_buffers);
-        let result = device_info(audio_daemon, selector, writer).await;
-        result.unwrap();
-
-        let stdout = test_buffers.into_stdout_str();
-        let stdout_expected = "\
-            {\"Info\":{\"device_path\":\"/dev/class/audio-composite/abc123\",\
-            \"unique_id\":null,\"manufacturer\":null,\"product_name\":null,\
-            \"gain_state\":null,\"gain_capabilities\":null,\"plug_state\":null,\
-            \"plug_time\":null,\"plug_detect_capabilities\":null,\"clock_domain\":0,\
-            \"supported_ring_buffer_formats\":null}}\n";
-
-        assert_eq!(stdout, stdout_expected);
-
-        Ok(())
-    }
-
-    #[fuchsia::test]
     pub async fn test_device_list() -> Result<(), fho::Error> {
         let test_buffers = TestBuffers::default();
         let writer: MachineWriter<DeviceResult> = MachineWriter::new_test(None, &test_buffers);
diff --git a/src/developer/ffx/plugins/audio/device/src/list.rs b/src/developer/ffx/plugins/audio/device/src/list.rs
index a73f6f1..a927696 100644
--- a/src/developer/ffx/plugins/audio/device/src/list.rs
+++ b/src/developer/ffx/plugins/audio/device/src/list.rs
@@ -7,9 +7,12 @@
 use fidl_fuchsia_audio_device as fadevice;
 use fidl_fuchsia_hardware_audio as fhaudio;
 use fidl_fuchsia_io as fio;
-use fuchsia_audio::device::{
-    DevfsSelector, HardwareType as HardwareDeviceType, Info as DeviceInfo, Selector,
-    Type as DeviceType,
+use fuchsia_audio::{
+    device::{
+        DevfsSelector, HardwareType as HardwareDeviceType, Info as DeviceInfo, Selector,
+        Type as DeviceType,
+    },
+    Registry,
 };
 use serde::{Serialize, Serializer};
 use std::fmt::Display;
@@ -194,20 +197,18 @@
 
 /// Returns a list of devices on the target.
 ///
-/// If the target is running audio_device_registry, i.e. when the `registry` protocol
-/// is served and calls on it succeed, this method returns registry devices.
+/// If the target is running audio_device_registry, i.e. when `registry` is Some, this method
+/// returns registry devices.
 ///
 /// Otherwise, this method returns devices from devfs.
 pub async fn get_devices(
     dev_class: &fio::DirectoryProxy,
-    registry: Option<&fadevice::RegistryProxy>,
+    registry: Option<&Registry>,
 ) -> fho::Result<Devices> {
     // Try the registry first.
     if let Some(registry) = registry {
-        if let Ok(mut infos) = fuchsia_audio::device::list_registry(registry).await {
-            infos.sort_by_key(|info| info.token_id());
-            return Ok(Devices::Registry(infos));
-        }
+        let infos = registry.get_all().await.into_values().collect();
+        return Ok(Devices::Registry(infos));
     }
 
     // Fall back to devfs.
diff --git a/src/developer/ffx/plugins/audio/device/src/serde_ext.rs b/src/developer/ffx/plugins/audio/device/src/serde_ext.rs
index 13f61f7..82555fd 100644
--- a/src/developer/ffx/plugins/audio/device/src/serde_ext.rs
+++ b/src/developer/ffx/plugins/audio/device/src/serde_ext.rs
@@ -4,12 +4,27 @@
 
 //! Helpers to serialize fuchsia_audio types with serde.
 
+use fidl_fuchsia_audio_device as fadevice;
 use fuchsia_audio::{
-    device::{ClockDomain, GainCapabilities, GainState},
+    dai::{DaiFormatSet, DaiFrameFormat, DaiSampleFormat},
+    device::{ClockDomain, GainCapabilities, GainState, PlugEvent, PlugState},
     format::SampleType,
     format_set::{ChannelAttributes, ChannelSet, PcmFormatSet},
 };
-use serde::{ser::SerializeSeq, Serialize, Serializer};
+use fuchsia_zircon_types as zx_types;
+use serde::{
+    ser::{SerializeMap, SerializeSeq},
+    Serialize, Serializer,
+};
+use std::collections::BTreeMap;
+
+/// Serialize an value that can be converted to a string to the string.
+pub fn serialize_tostring<S>(value: &impl ToString, serializer: S) -> Result<S::Ok, S::Error>
+where
+    S: Serializer,
+{
+    serializer.serialize_str(&value.to_string())
+}
 
 /// Serialize an optional value that can be converted to a string to either the string, or none.
 pub fn serialize_option_tostring<S>(
@@ -107,25 +122,44 @@
     pub frame_rates: Vec<u32>,
 }
 
-pub fn serialize_option_vec_pcmformatset<S>(
-    format_sets: &Option<Vec<PcmFormatSet>>,
+pub fn serialize_vec_pcmformatset<S>(
+    pcm_format_sets: &Vec<PcmFormatSet>,
     serializer: S,
 ) -> Result<S::Ok, S::Error>
 where
     S: Serializer,
 {
-    let Some(format_sets) = format_sets else { return serializer.serialize_none() };
-
     #[derive(Serialize)]
     struct Wrapper<'a>(#[serde(with = "PcmFormatSetDef")] &'a PcmFormatSet);
 
-    let mut seq = serializer.serialize_seq(Some(format_sets.len()))?;
-    for format_set in format_sets {
-        seq.serialize_element(&Wrapper(format_set))?;
+    let mut seq = serializer.serialize_seq(Some(pcm_format_sets.len()))?;
+    for pcm_format_set in pcm_format_sets {
+        seq.serialize_element(&Wrapper(pcm_format_set))?;
     }
     seq.end()
 }
 
+pub fn serialize_option_map_pcmformatset<S>(
+    format_set_map: &Option<BTreeMap<fadevice::ElementId, Vec<PcmFormatSet>>>,
+    serializer: S,
+) -> Result<S::Ok, S::Error>
+where
+    S: Serializer,
+{
+    let Some(format_set_map) = format_set_map else { return serializer.serialize_none() };
+
+    #[derive(Serialize)]
+    struct Wrapper<'a>(
+        #[serde(serialize_with = "serialize_vec_pcmformatset")] &'a Vec<PcmFormatSet>,
+    );
+
+    let mut map = serializer.serialize_map(Some(format_set_map.len()))?;
+    for (key, value) in format_set_map {
+        map.serialize_entry(key, &Wrapper(value))?;
+    }
+    map.end()
+}
+
 // Mirror type for serialization.
 // This exists to avoid the fuchsia-audio library from depending on serde.
 #[derive(Serialize)]
@@ -177,3 +211,77 @@
     }
     seq.end()
 }
+
+// Mirror type for serialization.
+// This exists to avoid the fuchsia-audio library from depending on serde.
+#[derive(Serialize)]
+#[serde(remote = "DaiFormatSet")]
+pub struct DaiFormatSetDef {
+    number_of_channels: Vec<u32>,
+    #[serde(serialize_with = "serialize_vec_tostring")]
+    sample_formats: Vec<DaiSampleFormat>,
+    #[serde(serialize_with = "serialize_vec_tostring")]
+    frame_formats: Vec<DaiFrameFormat>,
+    frame_rates: Vec<u32>,
+    bits_per_slot: Vec<u8>,
+    bits_per_sample: Vec<u8>,
+}
+
+pub fn serialize_vec_daiformatset<S>(
+    dai_format_sets: &Vec<DaiFormatSet>,
+    serializer: S,
+) -> Result<S::Ok, S::Error>
+where
+    S: Serializer,
+{
+    #[derive(Serialize)]
+    struct Wrapper<'a>(#[serde(with = "DaiFormatSetDef")] &'a DaiFormatSet);
+
+    let mut seq = serializer.serialize_seq(Some(dai_format_sets.len()))?;
+    for dai_format_set in dai_format_sets {
+        seq.serialize_element(&Wrapper(dai_format_set))?;
+    }
+    seq.end()
+}
+
+pub fn serialize_option_map_daiformatset<S>(
+    format_set_map: &Option<BTreeMap<fadevice::ElementId, Vec<DaiFormatSet>>>,
+    serializer: S,
+) -> Result<S::Ok, S::Error>
+where
+    S: Serializer,
+{
+    let Some(format_set_map) = format_set_map else { return serializer.serialize_none() };
+
+    #[derive(Serialize)]
+    struct Wrapper<'a>(
+        #[serde(serialize_with = "serialize_vec_daiformatset")] &'a Vec<DaiFormatSet>,
+    );
+
+    let mut map = serializer.serialize_map(Some(format_set_map.len()))?;
+    for (key, value) in format_set_map {
+        map.serialize_entry(key, &Wrapper(value))?;
+    }
+    map.end()
+}
+
+// Mirror type for serialization.
+// This exists to avoid the fuchsia-audio library from depending on serde.
+#[derive(Serialize)]
+#[serde(remote = "PlugEvent")]
+pub struct PlugEventDef {
+    #[serde(serialize_with = "serialize_tostring")]
+    pub state: PlugState,
+    pub time: zx_types::zx_time_t,
+}
+
+pub fn serialize_option_plugevent<S>(
+    plug_event: &Option<PlugEvent>,
+    serializer: S,
+) -> Result<S::Ok, S::Error>
+where
+    S: Serializer,
+{
+    let Some(plug_event) = plug_event else { return serializer.serialize_none() };
+    PlugEventDef::serialize(plug_event, serializer)
+}
diff --git a/src/developer/ffx/plugins/audio/list-devices/BUILD.gn b/src/developer/ffx/plugins/audio/list-devices/BUILD.gn
index 2061c18..9b0e5c5 100644
--- a/src/developer/ffx/plugins/audio/list-devices/BUILD.gn
+++ b/src/developer/ffx/plugins/audio/list-devices/BUILD.gn
@@ -19,6 +19,7 @@
     "//src/developer/ffx/lib/fho:lib",
     "//src/developer/ffx/plugins/audio/common:ffx_audio_common",
     "//src/developer/ffx/plugins/audio/device:ffx_audio_device",
+    "//src/media/audio/lib/rust",
     "//third_party/rust_crates:async-trait",
   ]
 
diff --git a/src/developer/ffx/plugins/audio/list-devices/src/lib.rs b/src/developer/ffx/plugins/audio/list-devices/src/lib.rs
index 9a06126..6db925c 100644
--- a/src/developer/ffx/plugins/audio/list-devices/src/lib.rs
+++ b/src/developer/ffx/plugins/audio/list-devices/src/lib.rs
@@ -12,6 +12,7 @@
 use fho::{FfxMain, FfxTool, MachineWriter};
 use fidl_fuchsia_audio_device as fadevice;
 use fidl_fuchsia_io as fio;
+use fuchsia_audio::Registry;
 
 #[derive(FfxTool)]
 pub struct ListDevicesTool {
@@ -29,7 +30,8 @@
     type Writer = MachineWriter<ListResult>;
 
     async fn main(self, writer: Self::Writer) -> fho::Result<()> {
-        let selectors = get_devices(&self.dev_class, self.registry.as_ref()).await?;
+        let registry = self.registry.map(Registry::new);
+        let selectors = get_devices(&self.dev_class, registry.as_ref()).await?;
         device_list_untagged(selectors, writer)
     }
 }
diff --git a/src/developer/ffx/plugins/emulator/commands/console/BUILD.gn b/src/developer/ffx/plugins/emulator/commands/console/BUILD.gn
index 5256c24..114e8d6a 100644
--- a/src/developer/ffx/plugins/emulator/commands/console/BUILD.gn
+++ b/src/developer/ffx/plugins/emulator/commands/console/BUILD.gn
@@ -13,11 +13,13 @@
       "//src/developer/ffx/plugins/emulator/configuration:ffx_emulator_config",
     ]
     deps = [
+      "//src/developer/ffx/config:lib",
       "//src/developer/ffx/lib/errors:lib",
       "//src/developer/ffx/lib/fho:lib",
       "//src/developer/ffx/plugins/emulator/commands:ffx_emulator_commands",
       "//src/developer/ffx/plugins/emulator/configuration:ffx_emulator_config",
       "//third_party/rust_crates:anyhow",
+      "//third_party/rust_crates:async-trait",
     ]
     args_sources = [ "src/args.rs" ]
     sources = [ "src/lib.rs" ]
diff --git a/src/developer/ffx/plugins/emulator/commands/console/src/lib.rs b/src/developer/ffx/plugins/emulator/commands/console/src/lib.rs
index 8ee39cb..43cc9c3 100644
--- a/src/developer/ffx/plugins/emulator/commands/console/src/lib.rs
+++ b/src/developer/ffx/plugins/emulator/commands/console/src/lib.rs
@@ -4,10 +4,51 @@
 
 use anyhow::{anyhow, Result};
 use errors::ffx_bail;
-use ffx_core::ffx_plugin;
+use ffx_config::EnvironmentContext;
 use ffx_emulator_commands::get_engine_by_name;
 use ffx_emulator_config::EngineConsoleType;
 use ffx_emulator_console_args::ConsoleCommand;
+use fho::{FfxMain, FfxTool, SimpleWriter};
+
+/// Sub-sub tool for `emu console`
+#[derive(FfxTool)]
+pub struct EmuConsoleTool {
+    #[command]
+    cmd: ConsoleCommand,
+    _context: EnvironmentContext,
+}
+
+// Since this is a part of a legacy plugin, add
+// the legacy entry points. If and when this
+// is migrated to a subcommand, this macro can be
+// removed.
+fho::embedded_plugin!(EmuConsoleTool);
+
+#[async_trait::async_trait(?Send)]
+impl FfxMain for EmuConsoleTool {
+    type Writer = SimpleWriter;
+
+    async fn main(self, _writer: Self::Writer) -> fho::Result<()> {
+        let console = match get_console_type(&self.cmd) {
+            Ok(c) => c,
+            Err(e) => ffx_bail!("{:?}", e),
+        };
+        let mut name: Option<String> = self.cmd.name.clone();
+        match get_engine_by_name(&mut name).await {
+            Ok(Some(engine)) => engine.attach(console),
+            Ok(None) => {
+                if let Some(name) = self.cmd.name {
+                    println!("Instance {name} not found.");
+                } else {
+                    println!("No instances found");
+                }
+
+                Ok(())
+            }
+            Err(e) => ffx_bail!("{:?}", e),
+        }
+    }
+}
 
 fn get_console_type(cmd: &ConsoleCommand) -> Result<EngineConsoleType> {
     let mut result = cmd.console_type;
@@ -38,27 +79,6 @@
     Ok(result)
 }
 
-#[ffx_plugin("emu.console.enabled")]
-pub async fn console(mut cmd: ConsoleCommand) -> fho::Result<()> {
-    let console = match get_console_type(&cmd) {
-        Ok(c) => c,
-        Err(e) => ffx_bail!("{:?}", e),
-    };
-    match get_engine_by_name(&mut cmd.name).await {
-        Ok(Some(engine)) => engine.attach(console),
-        Ok(None) => {
-            if let Some(name) = cmd.name {
-                println!("Instance {name} not found.");
-            } else {
-                println!("No instances found");
-            }
-
-            Ok(())
-        }
-        Err(e) => ffx_bail!("{:?}", e),
-    }
-}
-
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/src/developer/ffx/plugins/emulator/engines/src/qemu_based/mod.rs b/src/developer/ffx/plugins/emulator/engines/src/qemu_based/mod.rs
index 62ab10a..8109ac8 100644
--- a/src/developer/ffx/plugins/emulator/engines/src/qemu_based/mod.rs
+++ b/src/developer/ffx/plugins/emulator/engines/src/qemu_based/mod.rs
@@ -234,9 +234,14 @@
                         Self::fvm_extend(&dest_path, target_size).await?;
                     }
                     DiskImage::Fxfs(_) => {
-                        let tmp = NamedTempFile::new_in(&instance_root).map_err(|e| bug!("{e}"))?;
-                        fs::copy(src_path, tmp.path())
-                            .map_err(|e| bug!("cannot stage Fxfs image: {e}"))?;
+                        let mut tmp =
+                            NamedTempFile::new_in(&instance_root).map_err(|e| bug!("{e}"))?;
+                        {
+                            let mut reader = std::fs::File::open(src_path)
+                                .map_err(|e| bug!("open failed: {e}"))?;
+                            std::io::copy(&mut reader, &mut tmp)
+                                .map_err(|e| bug!("cannot stage Fxfs image: {e}"))?;
+                        }
                         if original_size < target_size {
                             // Resize the image if needed.
                             tmp.as_file().set_len(target_size).map_err(|e| {
@@ -1201,6 +1206,13 @@
         std::fs::write(&emu_config.guest.kernel_image, "whatever").expect("writing kernel image");
         std::fs::write(emu_config.guest.disk_image.as_ref().unwrap(), EXPECTED_DATA)
             .expect("writing guest image");
+        // Make the input file read-only to ensure that the staged version is RW.
+        let mut perms = std::fs::metadata(&emu_config.guest.disk_image.as_ref().unwrap())
+            .expect("get permissions")
+            .permissions();
+        perms.set_readonly(true);
+        std::fs::set_permissions(&emu_config.guest.disk_image.as_ref().unwrap(), perms)
+            .expect("set permissions");
 
         emu_config.device.storage = DataAmount { units: DataUnits::Kilobytes, quantity: 4 };
 
@@ -1226,6 +1238,7 @@
         assert_eq!(disk_contents.len(), 4096);
         assert_eq!(&disk_contents[..EXPECTED_DATA.len()], EXPECTED_DATA);
         assert_eq!(&disk_contents[EXPECTED_DATA.len()..], &[0u8; 4096 - EXPECTED_DATA.len()]);
+        assert!(!disk_image.metadata().expect("get metadata").permissions().readonly());
 
         Ok(())
     }
diff --git a/src/developer/ffx/plugins/log/BUILD.gn b/src/developer/ffx/plugins/log/BUILD.gn
index e401873..85b330d 100644
--- a/src/developer/ffx/plugins/log/BUILD.gn
+++ b/src/developer/ffx/plugins/log/BUILD.gn
@@ -25,11 +25,9 @@
     "//src/developer/ffx/lib/rcs:lib",
     "//src/developer/ffx/lib/symbol-index",
     "//src/diagnostics/lib/log-command",
-    "//src/diagnostics/lib/log_symbolizer",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia-async",
     "//third_party/rust_crates:anyhow",
-    "//third_party/rust_crates:async-channel",
     "//third_party/rust_crates:async-trait",
     "//third_party/rust_crates:derivative",
     "//third_party/rust_crates:futures",
@@ -69,6 +67,12 @@
 }
 
 ffx_tool("ffx_log_tool") {
+  # Needed for Honeydew's SDK inclusion
+  #
+  # TODO(b/330934833): Remove when IDK allows for `testonly` targets in dep
+  # tree or when we can separate the concept of data_dep from host_test_data.
+  testonly = false
+
   edition = "2021"
   output_name = "ffx-log"
   deps = [
diff --git a/src/developer/ffx/plugins/log/src/lib.rs b/src/developer/ffx/plugins/log/src/lib.rs
index f9ff9ca3..5e4595a 100644
--- a/src/developer/ffx/plugins/log/src/lib.rs
+++ b/src/developer/ffx/plugins/log/src/lib.rs
@@ -15,13 +15,10 @@
         dump_logs_from_socket, BootTimeAccessor, DefaultLogFormatter, LogEntry, LogFormatter,
         Symbolize, WriterContainer,
     },
-    InstanceGetter, LogSubCommand, SymbolizeMode, WatchCommand,
+    InstanceGetter, LogSubCommand, WatchCommand,
 };
-use log_symbolizer::LogSymbolizer;
-use std::{fmt::Debug, io::Write};
-use symbolizer::NonTransactionalSymbolizer;
-use tokio::io::{AsyncRead, AsyncWrite};
-use transactional_symbolizer::{RealSymbolizerProcess, SymbolizerProcess, TransactionalSymbolizer};
+use std::io::Write;
+use transactional_symbolizer::{RealSymbolizerProcess, TransactionalSymbolizer};
 
 // NOTE: This is required for the legacy ffx toolchain
 // which automatically adds ffx_core even though we don't use it.
@@ -30,7 +27,6 @@
 mod condition_variable;
 mod error;
 mod mutex;
-mod symbolizer;
 #[cfg(test)]
 mod testing_utils;
 mod transactional_symbolizer;
@@ -75,116 +71,35 @@
     target_collection_proxy: TargetCollectionProxy,
     cmd: LogCommand,
 ) -> Result<(), LogError> {
-    let enable_transactional_symbolizer =
-        ffx_config::get("log_cmd.pretty_backtraces").await.unwrap_or(false);
-    let mut disable_prettification = false;
-    let mut no_symbolize = cmd.no_symbolize;
-    // TODO(b/299980894): Clean this up once no longer needed.
-    if cmd.no_symbolize || cmd.raw {
-        eprintln!(concat!(
-            "WARNING: --no-symbolize and --raw have been deprecated",
-            " and replaced with --symbolize."
-        ));
-        eprintln!("These legacy options will eventually be removed.");
-        if cmd.raw {
-            no_symbolize = true;
-        }
-    } else {
-        match cmd.symbolize {
-            SymbolizeMode::Off => {
-                no_symbolize = true;
-            }
-            SymbolizeMode::Pretty => {}
-            SymbolizeMode::Classic => {
-                disable_prettification = true;
-            }
-        }
-    }
     let instance_getter = rcs::root_realm_query(&rcs_proxy, TIMEOUT).await?;
+    // TODO(b/333908164): We have 3 different flags that all do the same thing.
+    // Remove them when possible.
+    let symbolize_disabled = cmd.symbolize.is_symbolize_disabled() || cmd.no_symbolize || cmd.raw;
+    let prettification_disabled = cmd.symbolize.is_prettification_disabled();
     log_main(
         writer,
         rcs_proxy,
         target_collection_proxy,
         cmd,
-        if no_symbolize {
+        if symbolize_disabled {
             None
         } else {
-            if enable_transactional_symbolizer {
-                Some(EitherSymbolizer::Left(TransactionalSymbolizer::new(
-                    RealSymbolizerProcess::new(!disable_prettification).await?,
-                )?))
-            } else {
-                Some(EitherSymbolizer::Right(LogSymbolizer::new()))
-            }
+            Some(TransactionalSymbolizer::new(
+                RealSymbolizerProcess::new(!prettification_disabled).await?,
+            )?)
         },
         instance_getter,
     )
     .await
 }
 
-/// Temporary compatibility enum allowing for the usage of Symbolize
-/// and Symbolizer, until the legacy Symbolizer trait is removed.
-/// This is needed because we can't implement a foreign trait (Symbolize)
-/// on a foreign type (Either), and we likely don't want to define
-/// this in log_formatter as this is specific to ffx and not needed
-/// on the device.
-enum EitherSymbolizer<A, B> {
-    Left(A),
-    Right(B),
-}
-
-/// Temporary compatibility trait allowing for the usage of Symbolize
-/// and Symbolizer, until the legacy Symbolizer trait is removed.
-trait AsyncIntoSymbolize {
-    async fn into_symbolize(self) -> Result<impl Symbolize, LogError>;
-}
-
-impl AsyncIntoSymbolize for LogSymbolizer {
-    async fn into_symbolize(self) -> Result<impl Symbolize, LogError> {
-        NonTransactionalSymbolizer::new(self).await
-    }
-}
-
-impl<T: SymbolizerProcess + 'static> AsyncIntoSymbolize for TransactionalSymbolizer<T>
-where
-    T::Stdin: AsyncWrite + Unpin + Debug,
-    T::Stdout: AsyncRead + Unpin + Debug,
-{
-    async fn into_symbolize(self) -> Result<impl Symbolize, LogError> {
-        Ok(self)
-    }
-}
-
-impl<A: AsyncIntoSymbolize, B: AsyncIntoSymbolize> AsyncIntoSymbolize for EitherSymbolizer<A, B> {
-    async fn into_symbolize(self) -> Result<impl Symbolize, LogError> {
-        Ok(match self {
-            EitherSymbolizer::Left(result) => {
-                EitherSymbolizer::Left(result.into_symbolize().await?)
-            }
-            EitherSymbolizer::Right(result) => {
-                EitherSymbolizer::Right(result.into_symbolize().await?)
-            }
-        })
-    }
-}
-
-#[async_trait(?Send)]
-impl<A: Symbolize, B: Symbolize> Symbolize for EitherSymbolizer<A, B> {
-    async fn symbolize(&self, entry: LogEntry) -> Option<LogEntry> {
-        match self {
-            EitherSymbolizer::Left(value) => value.symbolize(entry).await,
-            EitherSymbolizer::Right(value) => value.symbolize(entry).await,
-        }
-    }
-}
-
 // Main logging event loop.
 async fn log_main<W>(
     writer: W,
     rcs_proxy: RemoteControlProxy,
     target_collection_proxy: TargetCollectionProxy,
     cmd: LogCommand,
-    symbolizer: Option<impl AsyncIntoSymbolize>,
+    symbolizer: Option<impl Symbolize>,
     instance_getter: impl InstanceGetter,
 ) -> Result<(), LogError>
 where
@@ -278,14 +193,14 @@
     target_query: TargetQuery,
     cmd: LogCommand,
     mut formatter: impl LogFormatter + BootTimeAccessor + WriterContainer<W>,
-    symbolizer: Option<impl AsyncIntoSymbolize>,
+    symbolizer: Option<impl Symbolize>,
     realm_query: &impl InstanceGetter,
 ) -> Result<(), LogError>
 where
     W: ToolIO<OutputItem = LogEntry> + Write,
 {
     let symbolizer_channel: Box<dyn Symbolize> = match symbolizer {
-        Some(inner) => Box::new(inner.into_symbolize().await?),
+        Some(inner) => Box::new(inner),
         None => Box::new(NoOpSymoblizer {}),
     };
     let mut stream_mode = get_stream_mode(cmd.clone())?;
@@ -394,7 +309,6 @@
         log_formatter::{LogData, TIMESTAMP_FORMAT},
         parse_seconds_string_as_duration, parse_time, DumpCommand, TimeFormat,
     };
-    use log_symbolizer::{FakeSymbolizerForTest, NoOpSymbolizer};
     use moniker::Moniker;
     use selectors::parse_log_interest_selector;
     use std::rc::Rc;
@@ -407,18 +321,6 @@
         expected_selector: Option<String>,
     }
 
-    impl AsyncIntoSymbolize for NoOpSymbolizer {
-        async fn into_symbolize(self) -> Result<impl Symbolize, LogError> {
-            NonTransactionalSymbolizer::new(self).await
-        }
-    }
-
-    impl AsyncIntoSymbolize for FakeSymbolizerForTest {
-        async fn into_symbolize(self) -> Result<impl Symbolize, LogError> {
-            NonTransactionalSymbolizer::new(self).await
-        }
-    }
-
     #[async_trait(?Send)]
     impl InstanceGetter for FakeInstanceGetter {
         async fn get_monikers_from_query(
@@ -433,83 +335,6 @@
     }
 
     #[fuchsia::test]
-    async fn symbolizer_replaces_markers_with_symbolized_logs() {
-        let (rcs_proxy, rcs_server) = fidl::endpoints::create_proxy().unwrap();
-        let (target_collection_proxy, target_collection_server) =
-            fidl::endpoints::create_proxy().unwrap();
-        let cmd = LogCommand {
-            sub_command: Some(LogSubCommand::Dump(DumpCommand {})),
-            ..LogCommand::default()
-        };
-        let symbolizer = FakeSymbolizerForTest::new("prefix", vec![]);
-        let mut manager = Manager::new_with_config(Rc::new(Configuration {
-            messages: vec![
-                LogsDataBuilder::new(BuilderArgs {
-                    component_url: Some("ffx".into()),
-                    moniker: "ffx".into(),
-                    severity: Severity::Info,
-                    timestamp_nanos: Timestamp::from(0),
-                })
-                .set_pid(1)
-                .set_tid(2)
-                .set_message("{{{reset}}}")
-                .build(),
-                LogsDataBuilder::new(BuilderArgs {
-                    component_url: Some("ffx".into()),
-                    moniker: "ffx".into(),
-                    severity: Severity::Info,
-                    timestamp_nanos: Timestamp::from(0),
-                })
-                .set_pid(1)
-                .set_tid(2)
-                .set_message("{{{mmap:something}}")
-                .build(),
-                LogsDataBuilder::new(BuilderArgs {
-                    component_url: Some("ffx".into()),
-                    moniker: "ffx".into(),
-                    severity: Severity::Info,
-                    timestamp_nanos: Timestamp::from(0),
-                })
-                .set_pid(1)
-                .set_tid(2)
-                .set_message("not_real")
-                .build(),
-            ],
-            ..Default::default()
-        }));
-        let mut event_stream = manager.take_event_stream().unwrap();
-        let environment = manager.get_environment();
-        Task::local(handle_rcs_connection(rcs_server, environment.clone())).detach();
-        Task::local(handle_target_collection_connection(
-            target_collection_server,
-            environment.clone(),
-        ))
-        .detach();
-        let test_buffers = TestBuffers::default();
-        log_main(
-            MachineWriter::<LogEntry>::new_test(None, &test_buffers),
-            rcs_proxy,
-            target_collection_proxy,
-            cmd,
-            Some(symbolizer),
-            FakeInstanceGetter::default(),
-        )
-        .await
-        .expect("log_main failed");
-
-        assert_eq!(
-            test_buffers.stdout.into_string().split('\n').collect::<Vec<_>>(),
-            vec![
-                "[00000.000000][ffx] INFO: prefix{{{reset}}}\u{1b}[m",
-                "[00000.000000][ffx] INFO: prefix{{{mmap:something}}\u{1b}[m",
-                "[00000.000000][ffx] INFO: not_real\u{1b}[m",
-                ""
-            ]
-        );
-        assert_matches!(event_stream.next().await, Some(TestEvent::LogSettingsConnectionClosed));
-    }
-
-    #[fuchsia::test]
     async fn json_logger_test() {
         let (rcs_proxy, rcs_server) = fidl::endpoints::create_proxy().unwrap();
         let (target_collection_proxy, target_collection_server) =
@@ -518,7 +343,7 @@
             sub_command: Some(LogSubCommand::Dump(DumpCommand {})),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let manager = Manager::new();
         let environment = manager.get_environment();
         Task::local(handle_rcs_connection(rcs_server, environment.clone())).detach();
@@ -570,7 +395,7 @@
             select: vec![parse_log_interest_selector("ambiguous_selector#INFO").unwrap()],
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let manager = Manager::new();
         let environment = manager.get_environment();
         Task::local(handle_rcs_connection(rcs_server, environment.clone())).detach();
@@ -630,7 +455,7 @@
             select: vec![parse_log_interest_selector("ambiguous_selector#INFO").unwrap()],
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new();
         let mut event_stream = manager.take_event_stream().unwrap();
         let environment = manager.get_environment();
@@ -670,7 +495,7 @@
             since: Some(parse_time("now").unwrap()),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let manager = Manager::new();
         let environment = manager.get_environment();
         Task::local(handle_rcs_connection(rcs_server, environment.clone())).detach();
@@ -704,7 +529,7 @@
             sub_command: Some(LogSubCommand::Dump(DumpCommand {})),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new();
         let mut event_stream = manager.take_event_stream().unwrap();
         let environment = manager.get_environment();
@@ -743,7 +568,7 @@
             no_color: true,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new();
         let mut event_stream = manager.take_event_stream().unwrap();
         let environment = manager.get_environment();
@@ -783,7 +608,7 @@
             no_color: true,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new();
         let mut event_stream = manager.take_event_stream().unwrap();
         let environment = manager.get_environment();
@@ -822,7 +647,7 @@
             clock: TimeFormat::Utc,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -874,7 +699,7 @@
             severity: Severity::Error,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![
                 LogsDataBuilder::new(BuilderArgs {
@@ -959,7 +784,7 @@
             until: None,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -1040,7 +865,7 @@
             until: None,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -1129,7 +954,7 @@
             until: Some(parse_time("1980-01-01T00:00:05").unwrap()),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![
                 LogsDataBuilder::new(BuilderArgs {
@@ -1222,7 +1047,7 @@
             until_monotonic: Some(parse_seconds_string_as_duration("5").unwrap()),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![
                 LogsDataBuilder::new(BuilderArgs {
@@ -1295,7 +1120,7 @@
             clock: TimeFormat::Local,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -1348,7 +1173,7 @@
             sub_command: Some(LogSubCommand::Dump(DumpCommand {})),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -1399,7 +1224,7 @@
             sub_command: Some(LogSubCommand::Dump(DumpCommand {})),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -1451,7 +1276,7 @@
             show_full_moniker: true,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -1503,7 +1328,7 @@
             hide_tags: true,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -1556,7 +1381,7 @@
             select: severity.clone(),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new();
         let mut event_stream = manager.take_event_stream().unwrap();
         let environment = manager.get_environment();
@@ -1595,7 +1420,7 @@
             sub_command: Some(LogSubCommand::Dump(DumpCommand {})),
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
@@ -1650,7 +1475,7 @@
             hide_file: true,
             ..LogCommand::default()
         };
-        let symbolizer = NoOpSymbolizer::new();
+        let symbolizer = NoOpSymoblizer;
         let mut manager = Manager::new_with_config(Rc::new(Configuration {
             messages: vec![LogsDataBuilder::new(BuilderArgs {
                 component_url: Some("ffx".into()),
diff --git a/src/developer/ffx/plugins/product/create/src/lib.rs b/src/developer/ffx/plugins/product/create/src/lib.rs
index b32695f..9a9cb5f 100644
--- a/src/developer/ffx/plugins/product/create/src/lib.rs
+++ b/src/developer/ffx/plugins/product/create/src/lib.rs
@@ -186,7 +186,7 @@
             name: "fuchsia.com".into(),
             metadata_path: main_metadata_path,
             blobs_path: blobs_path,
-            delivery_blob_type: Some(delivery_blob_type),
+            delivery_blob_type,
             root_private_key_path: copy_file(tuf_keys.join("root.json"), &keys_path).ok(),
             targets_private_key_path: copy_file(tuf_keys.join("targets.json"), &keys_path).ok(),
             snapshot_private_key_path: copy_file(tuf_keys.join("snapshot.json"), &keys_path).ok(),
@@ -673,7 +673,7 @@
                     name: "fuchsia.com".into(),
                     metadata_path: pb_dir.join("repository"),
                     blobs_path: pb_dir.join("blobs"),
-                    delivery_blob_type: Some(1),
+                    delivery_blob_type: 1,
                     root_private_key_path: Some(pb_dir.join("keys/root.json")),
                     targets_private_key_path: Some(pb_dir.join("keys/targets.json")),
                     snapshot_private_key_path: Some(pb_dir.join("keys/snapshot.json")),
@@ -749,7 +749,7 @@
                 name: "fuchsia.com".into(),
                 metadata_path: pb_dir.join("repository"),
                 blobs_path: pb_dir.join("blobs"),
-                delivery_blob_type: Some(DEFAULT_DELIVERY_BLOB_TYPE),
+                delivery_blob_type: DEFAULT_DELIVERY_BLOB_TYPE,
                 root_private_key_path: Some(pb_dir.join("keys/root.json")),
                 targets_private_key_path: Some(pb_dir.join("keys/targets.json")),
                 snapshot_private_key_path: Some(pb_dir.join("keys/snapshot.json")),
diff --git a/src/developer/ffx/plugins/product/get_repository/src/lib.rs b/src/developer/ffx/plugins/product/get_repository/src/lib.rs
index 8c40c89..475ea63 100644
--- a/src/developer/ffx/plugins/product/get_repository/src/lib.rs
+++ b/src/developer/ffx/plugins/product/get_repository/src/lib.rs
@@ -55,7 +55,7 @@
             name: repository.name.clone(),
             target_json: path_relative_from(target_json, &cmd.product_bundle)?,
             blobs_dir: path_relative_from(blobs_dir, &cmd.product_bundle)?,
-            delivery_blob_type: repository.delivery_blob_type.unwrap_or_default(),
+            delivery_blob_type: repository.delivery_blob_type,
         })
     }
     Ok(repository_infos)
@@ -92,7 +92,7 @@
                 name: "fuchsia.com".into(),
                 metadata_path: fuchsia_metadata_dir.clone(),
                 blobs_path: blobs_dir.clone(),
-                delivery_blob_type: Some(1),
+                delivery_blob_type: 1,
                 root_private_key_path: None,
                 targets_private_key_path: None,
                 snapshot_private_key_path: None,
diff --git a/src/developer/ffx/plugins/repository/add/src/lib.rs b/src/developer/ffx/plugins/repository/add/src/lib.rs
index 8c58a9f..ad815c8 100644
--- a/src/developer/ffx/plugins/repository/add/src/lib.rs
+++ b/src/developer/ffx/plugins/repository/add/src/lib.rs
@@ -107,7 +107,7 @@
                     name: "fuchsia.com".into(),
                     metadata_path: fuchsia_metadata_dir.clone(),
                     blobs_path: blobs_dir.clone(),
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
@@ -117,7 +117,7 @@
                     name: "example.com".into(),
                     metadata_path: example_metadata_dir.clone(),
                     blobs_path: blobs_dir.clone(),
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
@@ -186,7 +186,7 @@
                     name: "fuchsia.com".into(),
                     metadata_path: fuchsia_metadata_dir.clone(),
                     blobs_path: blobs_dir.clone(),
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
@@ -196,7 +196,7 @@
                     name: "example.com".into(),
                     metadata_path: example_metadata_dir.clone(),
                     blobs_path: blobs_dir.clone(),
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
diff --git a/src/developer/ffx/plugins/repository/packages/src/lib.rs b/src/developer/ffx/plugins/repository/packages/src/lib.rs
index e1c869b..9146f0f 100644
--- a/src/developer/ffx/plugins/repository/packages/src/lib.rs
+++ b/src/developer/ffx/plugins/repository/packages/src/lib.rs
@@ -307,18 +307,13 @@
     let fetch_blob = |hash: Hash| {
         let repo = &repo;
         async move {
-            let mut blob_resource = repo
-                .fetch_blob(&hash.to_string())
-                .await
-                .with_context(|| format!("fetching blob {hash}"))?;
-            let mut buf = vec![];
-            blob_resource
-                .read_to_end(&mut buf)
+            let blob = repo
+                .read_blob_decompressed(&hash)
                 .await
                 .with_context(|| format!("reading blob {hash}"))?;
             Ok::<(u64, Box<dyn Read>), anyhow::Error>((
-                blob_resource.total_len(),
-                Box::new(Cursor::new(buf)),
+                blob.len().try_into()?,
+                Box::new(Cursor::new(blob)),
             ))
         }
     };
@@ -425,7 +420,7 @@
         )
         .await;
 
-        let blobs_path = tmp.path().join("repository/blobs");
+        let blobs_path = tmp.path().join("repository/blobs/1");
 
         let pkg1_hash = &PKG1_HASH[..MAX_HASH];
         let pkg1_path = blobs_path.join(PKG1_HASH);
@@ -465,7 +460,7 @@
         )
         .await;
 
-        let blobs_path = tmp.path().join("repository/blobs");
+        let blobs_path = tmp.path().join("repository/blobs/1");
 
         let pkg1_hash = &PKG1_HASH;
         let pkg1_path = blobs_path.join(PKG1_HASH);
@@ -505,7 +500,7 @@
         )
         .await;
 
-        let blobs_path = tmp.path().join("repository/blobs");
+        let blobs_path = tmp.path().join("repository/blobs/1");
 
         let pkg1_hash = &PKG1_HASH[..MAX_HASH];
         let pkg1_path = blobs_path.join(PKG1_HASH);
@@ -546,7 +541,7 @@
         )
         .await;
 
-        let blobs_path = tmp.path().join("repository/blobs");
+        let blobs_path = tmp.path().join("repository/blobs/1");
 
         let pkg1_hash = &PKG1_HASH[..MAX_HASH];
         let pkg1_path = blobs_path.join(PKG1_HASH);
@@ -599,7 +594,7 @@
         )
         .await;
 
-        let blobs_path = tmp.path().join("repository/blobs");
+        let blobs_path = tmp.path().join("repository/blobs/1");
 
         let pkg1_hash = &PKG1_HASH;
         let pkg1_path = blobs_path.join(PKG1_HASH);
@@ -652,7 +647,7 @@
         )
         .await;
 
-        let blobs_path = tmp.path().join("repository/blobs");
+        let blobs_path = tmp.path().join("repository/blobs/1");
 
         let pkg1_hash = &PKG1_HASH[..MAX_HASH];
         let pkg1_path = blobs_path.join(PKG1_HASH);
diff --git a/src/developer/ffx/plugins/repository/serve/src/args.rs b/src/developer/ffx/plugins/repository/serve/src/args.rs
index 0ae87aa..ab221cf 100644
--- a/src/developer/ffx/plugins/repository/serve/src/args.rs
+++ b/src/developer/ffx/plugins/repository/serve/src/args.rs
@@ -32,8 +32,9 @@
     #[argh(option, default = "default_address()")]
     pub address: SocketAddr,
 
-    /// location of pm-built repo.
-    /// Default is "FUCHSIA_BUILD_DIR/amber-files"
+    /// location of the package repo.
+    /// Default is given by the build directory
+    /// obtained from the ffx context.
     #[argh(option)]
     pub repo_path: Option<Utf8PathBuf>,
 
diff --git a/src/developer/ffx/plugins/repository/serve/src/lib.rs b/src/developer/ffx/plugins/repository/serve/src/lib.rs
index 3ae515a..a1b8a2d 100644
--- a/src/developer/ffx/plugins/repository/serve/src/lib.rs
+++ b/src/developer/ffx/plugins/repository/serve/src/lib.rs
@@ -243,7 +243,6 @@
                 let repo_path = if let Some(repo_path) = repo_path {
                     repo_path
                 } else {
-                    // Default to "FUCHSIA_BUILD_DIR/amber-files"
                     let fuchsia_build_dir = self.context.build_dir().unwrap_or(&Path::new(""));
                     let fuchsia_build_dir =
                         Utf8Path::from_path(fuchsia_build_dir).with_context(|| {
@@ -1213,7 +1212,7 @@
                 name: repo_name.into(),
                 metadata_path,
                 blobs_path: blobs_dir.clone(),
-                delivery_blob_type: None,
+                delivery_blob_type: 1,
                 root_private_key_path: None,
                 targets_private_key_path: None,
                 snapshot_private_key_path: None,
diff --git a/src/developer/ffx/plugins/test/BUILD.gn b/src/developer/ffx/plugins/test/BUILD.gn
index 09c00ca..e447335 100644
--- a/src/developer/ffx/plugins/test/BUILD.gn
+++ b/src/developer/ffx/plugins/test/BUILD.gn
@@ -58,6 +58,12 @@
 }
 
 ffx_tool("ffx_test_tool") {
+  # Needed for Honeydew's SDK inclusion
+  #
+  # TODO(b/330934833): Remove when IDK allows for `testonly` targets in dep
+  # tree or when we can separate the concept of data_dep from host_test_data.
+  testonly = false
+
   edition = "2021"
   output_name = "ffx-test"
   deps = [
diff --git a/src/developer/ffx/tests/cli-goldens/goldens/ffx/audio/device/play.golden b/src/developer/ffx/tests/cli-goldens/goldens/ffx/audio/device/play.golden
index dd2e0f6..4fe9e97 100644
--- a/src/developer/ffx/tests/cli-goldens/goldens/ffx/audio/device/play.golden
+++ b/src/developer/ffx/tests/cli-goldens/goldens/ffx/audio/device/play.golden
@@ -22,6 +22,18 @@
       "short": null,
       "description": "file in WAV format containing audio signal. If not specified, ffx command will read from stdin.",
       "hidden": false
+    },
+    {
+      "kind": {
+        "Option": {
+          "arg_name": "element-id"
+        }
+      },
+      "optionality": "optional",
+      "long": "--element-id",
+      "short": null,
+      "description": "signal processing element ID, for an Endpoint element of type RingBuffer",
+      "hidden": false
     }
   ],
   "notes": [],
diff --git a/src/developer/ffx/tests/cli-goldens/goldens/ffx/audio/device/record.golden b/src/developer/ffx/tests/cli-goldens/goldens/ffx/audio/device/record.golden
index 9b3b977..3ad3b5a 100644
--- a/src/developer/ffx/tests/cli-goldens/goldens/ffx/audio/device/record.golden
+++ b/src/developer/ffx/tests/cli-goldens/goldens/ffx/audio/device/record.golden
@@ -34,6 +34,18 @@
       "short": null,
       "description": "output format (see 'ffx audio help' for more information).",
       "hidden": false
+    },
+    {
+      "kind": {
+        "Option": {
+          "arg_name": "element-id"
+        }
+      },
+      "optionality": "optional",
+      "long": "--element-id",
+      "short": null,
+      "description": "signal processing element ID, for an Endpoint element of type RingBuffer",
+      "hidden": false
     }
   ],
   "notes": [],
diff --git a/src/developer/ffx/tests/cli-goldens/goldens/ffx/repository/serve.golden b/src/developer/ffx/tests/cli-goldens/goldens/ffx/repository/serve.golden
index 0c7e7c2..8026438c 100644
--- a/src/developer/ffx/tests/cli-goldens/goldens/ffx/repository/serve.golden
+++ b/src/developer/ffx/tests/cli-goldens/goldens/ffx/repository/serve.golden
@@ -44,7 +44,7 @@
       "optionality": "optional",
       "long": "--repo-path",
       "short": null,
-      "description": "location of pm-built repo. Default is \"FUCHSIA_BUILD_DIR/amber-files\"",
+      "description": "location of the package repo. Default is given by the build directory obtained from the ffx context.",
       "hidden": false
     },
     {
diff --git a/src/developer/ffx/tools/profiler/BUILD.gn b/src/developer/ffx/tools/profiler/BUILD.gn
index 037d1e3..e3dc20c 100644
--- a/src/developer/ffx/tools/profiler/BUILD.gn
+++ b/src/developer/ffx/tools/profiler/BUILD.gn
@@ -23,6 +23,7 @@
     "//src/developer/ffx/lib/symbol-index",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia-async",
+    "//src/performance/experimental/profiler/samples_to_pprof:samples_to_pprof_rust",
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:argh",
     "//third_party/rust_crates:async-fs",
diff --git a/src/developer/ffx/tools/profiler/src/args.rs b/src/developer/ffx/tools/profiler/src/args.rs
index 6f341c9..823a72c 100644
--- a/src/developer/ffx/tools/profiler/src/args.rs
+++ b/src/developer/ffx/tools/profiler/src/args.rs
@@ -21,6 +21,7 @@
 #[derive(ArgsInfo, FromArgs, PartialEq, Debug)]
 /// Record a profile.
 #[argh(subcommand, name = "start")]
+#[derive(Default)]
 pub struct Start {
     /// url of a component to launch and profile
     #[argh(option)]
@@ -47,8 +48,8 @@
     #[argh(option)]
     pub duration: Option<f64>,
 
-    /// name of output trace file.  Defaults to profile.out.
-    #[argh(option, default = "String::from(\"profile.out\")")]
+    /// name of output trace file. Defaults to profile.pb.
+    #[argh(option, default = "String::from(\"profile.pb\")")]
     pub output: String,
 
     /// print stats about how the profiling session went
@@ -58,4 +59,9 @@
     /// if false, output the raw sample file instead of attempting to symbolize it
     #[argh(option, default = "true")]
     pub symbolize: bool,
+
+    /// if false, output the raw symbolized sample file instead of attempting to convert to the
+    /// pprof format. Ignored if --symbolize is false.
+    #[argh(option, default = "true")]
+    pub pprof_conversion: bool,
 }
diff --git a/src/developer/ffx/tools/profiler/src/lib.rs b/src/developer/ffx/tools/profiler/src/lib.rs
index 60712fd..db7c980 100644
--- a/src/developer/ffx/tools/profiler/src/lib.rs
+++ b/src/developer/ffx/tools/profiler/src/lib.rs
@@ -100,6 +100,22 @@
     }
 }
 
+pub fn pprof_conversion(from: &PathBuf, to: PathBuf) -> Result<()> {
+    let from_str = from
+        .clone()
+        .into_os_string()
+        .into_string()
+        .map_err(|err| ffx_error!("Invalid path name: {err:?}"))?;
+    let to_str = to
+        .into_os_string()
+        .into_string()
+        .map_err(|err| ffx_error!("Invalid path name: {err:?}"))?;
+    if !samples_to_pprof::convert(from_str, to_str) {
+        ffx_bail!("Failed to convert to pprof");
+    }
+    Ok(())
+}
+
 pub async fn profiler(
     controller: fho::Deferred<profiler::SessionProxy>,
     mut writer: Writer,
@@ -134,7 +150,7 @@
                 std::path::PathBuf::from(&opts.output)
             };
 
-            let mut output = File::create(&unsymbolized_path).await.unwrap();
+            let mut output = File::create(&unsymbolized_path).await?;
             let copy_task =
                 fuchsia_async::Task::local(
                     async move { futures::io::copy(client, &mut output).await },
@@ -183,8 +199,17 @@
             if !opts.symbolize {
                 return Ok(());
             }
-            let symbolized_path = std::path::PathBuf::from(&opts.output);
-            symbolize(&unsymbolized_path, &symbolized_path).await
+            let symbolized_path = if opts.pprof_conversion {
+                tmp_dir.path().join("symbolized.txt")
+            } else {
+                std::path::PathBuf::from(&opts.output)
+            };
+            symbolize(&unsymbolized_path, &symbolized_path).await?;
+
+            if !opts.pprof_conversion {
+                return Ok(());
+            }
+            pprof_conversion(&symbolized_path, PathBuf::from(&opts.output))
         }
     }
 }
@@ -202,8 +227,7 @@
             moniker: None,
             duration: None,
             output: String::from("output_file"),
-            print_stats: false,
-            symbolize: false,
+            ..Default::default()
         };
         let target = gather_targets(&args);
         match target {
@@ -219,8 +243,7 @@
             url: None,
             duration: None,
             output: String::from("output_file"),
-            print_stats: false,
-            symbolize: false,
+            ..Default::default()
         };
 
         let empty_targets = gather_targets(&empty_args);
@@ -234,8 +257,7 @@
             url: None,
             duration: None,
             output: String::from("output_file"),
-            print_stats: false,
-            symbolize: false,
+            ..Default::default()
         };
         let invalid_args2 = args::Start {
             pids: vec![],
@@ -245,8 +267,7 @@
             url: None,
             duration: None,
             output: String::from("output_file"),
-            print_stats: false,
-            symbolize: false,
+            ..Default::default()
         };
         let invalid_args3 = args::Start {
             pids: vec![],
@@ -256,8 +277,7 @@
             url: None,
             duration: None,
             output: String::from("output_file"),
-            print_stats: false,
-            symbolize: false,
+            ..Default::default()
         };
 
         let invalid_targets1 = gather_targets(&invalid_args1);
diff --git a/src/developer/ffx/tools/target-package/src/lib.rs b/src/developer/ffx/tools/target-package/src/lib.rs
index cbe3916..e1b803f 100644
--- a/src/developer/ffx/tools/target-package/src/lib.rs
+++ b/src/developer/ffx/tools/target-package/src/lib.rs
@@ -15,7 +15,7 @@
     dash_launcher_proxy: fho::Deferred<fdash::LauncherProxy>,
 }
 
-#[derive(ArgsInfo, FromArgs, Debug, PartialEq, Eq)]
+#[derive(ArgsInfo, FromArgs, Debug)]
 #[argh(
     subcommand,
     name = "target-package",
@@ -26,14 +26,14 @@
     subcommand: TargetPackageSubCommand,
 }
 
-#[derive(ArgsInfo, FromArgs, Debug, PartialEq, Eq)]
+#[derive(ArgsInfo, FromArgs, Debug)]
 #[argh(subcommand)]
 pub enum TargetPackageSubCommand {
     Explore(ExploreCommand),
 }
 
 // TODO(https://fxbug.dev/42079178) Make the explore command a separate subtool.
-#[derive(ArgsInfo, FromArgs, Debug, PartialEq, Eq)]
+#[derive(ArgsInfo, FromArgs, Debug)]
 #[argh(
     subcommand,
     name = "explore",
@@ -89,6 +89,19 @@
     /// execute a command instead of reading from stdin.
     /// the exit code of the command will be forwarded to the host.
     pub command: Option<String>,
+
+    #[argh(option, default = "fdash::FuchsiaPkgResolver::Full", from_str_fn(parse_resolver))]
+    /// the resolver to use when resolving package URLs with scheme "fuchsia-pkg".
+    /// Possible values are "base" and "full". Defaults to "full".
+    pub fuchsia_pkg_resolver: fdash::FuchsiaPkgResolver,
+}
+
+fn parse_resolver(flag: &str) -> Result<fdash::FuchsiaPkgResolver, String> {
+    Ok(match flag {
+        "base" => fdash::FuchsiaPkgResolver::Base,
+        "full" => fdash::FuchsiaPkgResolver::Full,
+        _ => return Err("supported fuchisa-pkg resolvers are: 'base' and 'full'".into()),
+    })
 }
 
 #[async_trait::async_trait(?Send)]
@@ -107,7 +120,7 @@
 }
 
 async fn explore(command: ExploreCommand, dash_launcher: fdash::LauncherProxy) -> fho::Result<()> {
-    let ExploreCommand { url, subpackages, tools, command } = command;
+    let ExploreCommand { url, subpackages, tools, command, fuchsia_pkg_resolver } = command;
 
     let (client, server) = fidl::Socket::create_stream();
     let stdout = if command.is_some() {
@@ -116,7 +129,14 @@
         socket_to_stdio::Stdout::raw()?
     };
     let () = dash_launcher
-        .explore_package_over_socket(&url, &subpackages, server, &tools, command.as_deref())
+        .explore_package_over_socket2(
+            fuchsia_pkg_resolver,
+            &url,
+            &subpackages,
+            server,
+            &tools,
+            command.as_deref(),
+        )
         .await
         .bug_context("fidl error launching dash")?
         .map_err(|e| match e {
diff --git a/src/developer/ffx/tools/target-package/tests/src/main.rs b/src/developer/ffx/tools/target-package/tests/src/main.rs
index aadbddc..4a13001 100644
--- a/src/developer/ffx/tools/target-package/tests/src/main.rs
+++ b/src/developer/ffx/tools/target-package/tests/src/main.rs
@@ -6,8 +6,8 @@
 use tracing::info;
 
 #[fuchsia::test]
-async fn cat_file_from_package_and_subpackages() {
-    let emu = IsolatedEmulator::start("test_ffx_target_package_explore").await.unwrap();
+async fn cat_file_from_package_and_subpackages_using_full_resolver() {
+    let emu = IsolatedEmulator::start("test_ffx_explore_package_full").await.unwrap();
 
     info!("resolving [sub]packages and cat'ing file");
     let output = emu
@@ -53,3 +53,25 @@
     assert_eq!(output, include_str!("../testdata/subsubpackage_file.txt"));
     emu.stop().await;
 }
+
+#[fuchsia::test]
+async fn cat_file_from_package_using_base_resolver() {
+    let emu = IsolatedEmulator::start("test_ffx_explore_package_base").await.unwrap();
+
+    info!("resolving base package and cat'ing file");
+    let output = emu
+        .ffx_output(&[
+            "target-package",
+            "explore",
+            "fuchsia-pkg://fuchsia.com/system_image",
+            "--fuchsia-pkg-resolver",
+            "base",
+            "-c",
+            "cat /pkg/meta/package",
+        ])
+        .await
+        .unwrap();
+    assert_eq!(output, r#"{"name":"system_image","version":"0"}"#);
+
+    emu.stop().await;
+}
diff --git a/src/developer/sshd-host/test.cc b/src/developer/sshd-host/test.cc
index 8081a38..bf02cd4 100644
--- a/src/developer/sshd-host/test.cc
+++ b/src/developer/sshd-host/test.cc
@@ -72,13 +72,12 @@
   void SetUp() override {
     EXPECT_EQ(loop_.StartThread(), ZX_OK);
 
-    auto items_endpoints = fidl::CreateEndpoints<Items>();
-    ASSERT_TRUE(items_endpoints.is_ok());
+    auto items_endpoints = fidl::Endpoints<Items>::Create();
 
     binding_ref_ =
-        fidl::BindServer(loop_.dispatcher(), std::move(items_endpoints->server), &fake_items_);
+        fidl::BindServer(loop_.dispatcher(), std::move(items_endpoints.server), &fake_items_);
 
-    items_client_ = fidl::SyncClient(std::move(items_endpoints->client));
+    items_client_ = fidl::SyncClient(std::move(items_endpoints.client));
   }
 
   void TearDown() override {
diff --git a/src/devices/acpi/drivers/acpi-battery/unit-tests.cc b/src/devices/acpi/drivers/acpi-battery/unit-tests.cc
index e89c476..c63e920 100644
--- a/src/devices/acpi/drivers/acpi-battery/unit-tests.cc
+++ b/src/devices/acpi/drivers/acpi-battery/unit-tests.cc
@@ -62,10 +62,9 @@
     device_ = ptr->zxdev();
 
     // Start the FIDL server.
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_powersource::Source>();
-    ASSERT_OK(endpoints.status_value());
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), ptr);
-    source_client_.Bind(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_powersource::Source>::Create();
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), ptr);
+    source_client_.Bind(std::move(endpoints.client));
   }
 
   void TearDown() override {
diff --git a/src/devices/acpi/drivers/intel-thermal/unit-tests.cc b/src/devices/acpi/drivers/intel-thermal/unit-tests.cc
index 6d4b409..f8598dcc 100644
--- a/src/devices/acpi/drivers/intel-thermal/unit-tests.cc
+++ b/src/devices/acpi/drivers/intel-thermal/unit-tests.cc
@@ -59,11 +59,10 @@
     device_ = ptr->zxdev();
 
     // Start the FIDL server.
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_thermal::Device>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_thermal::Device>::Create();
 
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), ptr);
-    thermal_client_.Bind(std::move(endpoints->client));
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), ptr);
+    thermal_client_.Bind(std::move(endpoints.client));
   }
 
   void TearDown() override {
diff --git a/src/devices/adc/drivers/adc/adc.cc b/src/devices/adc/drivers/adc/adc.cc
index bde1360..39ec409 100644
--- a/src/devices/adc/drivers/adc/adc.cc
+++ b/src/devices/adc/drivers/adc/adc.cc
@@ -128,18 +128,15 @@
                   .devfs_args(devfs.Build())
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   fidl::WireResult result =
-      fidl::WireCall(adc->node())->AddChild(args, std::move(controller_endpoints->server), {});
+      fidl::WireCall(adc->node())->AddChild(args, std::move(controller_endpoints.server), {});
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  dev->controller_.Bind(std::move(controller_endpoints->client));
+  dev->controller_.Bind(std::move(controller_endpoints.client));
 
   return zx::ok(std::move(dev));
 }
diff --git a/src/devices/adc/drivers/aml-saradc/aml-saradc.cc b/src/devices/adc/drivers/aml-saradc/aml-saradc.cc
index 152b2a3..4a15cba 100644
--- a/src/devices/adc/drivers/aml-saradc/aml-saradc.cc
+++ b/src/devices/adc/drivers/aml-saradc/aml-saradc.cc
@@ -150,18 +150,15 @@
                   .offers2(arena, std::move(offers))
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   fidl::WireResult result =
-      fidl::WireCall(node())->AddChild(args, std::move(controller_endpoints->server), {});
+      fidl::WireCall(node())->AddChild(args, std::move(controller_endpoints.server), {});
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
 
   return zx::ok();
 }
diff --git a/src/devices/bin/driver_host/driver_host_test.cc b/src/devices/bin/driver_host/driver_host_test.cc
index 061d315..4536428 100644
--- a/src/devices/bin/driver_host/driver_host_test.cc
+++ b/src/devices/bin/driver_host/driver_host_test.cc
@@ -57,14 +57,13 @@
  private:
   void GetBackingMemory(fio::VmoFlags flags, GetBackingMemoryCallback callback) override {
     EXPECT_EQ(fio::VmoFlags::READ | fio::VmoFlags::EXECUTE | fio::VmoFlags::PRIVATE_CLONE, flags);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::File>();
-    ASSERT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::File>::Create();
     EXPECT_EQ(ZX_OK, fdio_open(path_.data(),
                                static_cast<uint32_t>(fio::OpenFlags::RIGHT_READABLE |
                                                      fio::OpenFlags::RIGHT_EXECUTABLE),
-                               endpoints->server.channel().release()));
+                               endpoints.server.channel().release()));
 
-    fidl::WireSyncClient<fuchsia_io::File> file(std::move(endpoints->client));
+    fidl::WireSyncClient<fuchsia_io::File> file(std::move(endpoints.client));
     fidl::WireResult result = file->GetBackingMemory(fuchsia_io::wire::VmoFlags(uint32_t(flags)));
     EXPECT_TRUE(result.ok()) << result.FormatDescription();
     auto* res = result.Unwrap();
@@ -144,20 +143,19 @@
   StartDriverResult StartDriver(std::vector<fdf::NodeSymbol> symbols = {},
                                 fidl::ClientEnd<fuchsia_driver_framework::Node>* node = nullptr,
                                 zx_status_t expected_epitaph = ZX_OK) {
-    auto pkg_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_TRUE(pkg_endpoints.is_ok());
+    auto pkg_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
     EXPECT_TRUE(svc_endpoints.is_ok());
 
     std::vector<frunner::ComponentNamespaceEntry> ns_entries;
-    ns_entries.push_back({{.path = "/pkg", .directory = std::move(pkg_endpoints->client)}});
+    ns_entries.push_back({{.path = "/pkg", .directory = std::move(pkg_endpoints.client)}});
     ns_entries.push_back({{.path = "/svc", .directory = std::move(svc_endpoints->client)}});
 
     TestFile file("/pkg/driver/test_driver.so");
     fidl::Binding<fio::File> file_binding(&file);
     TestDirectory pkg_directory;
     fidl::Binding<fio::Directory> pkg_binding(&pkg_directory);
-    pkg_binding.Bind(pkg_endpoints->server.TakeChannel(), loop_.dispatcher());
+    pkg_binding.Bind(pkg_endpoints.server.TakeChannel(), loop_.dispatcher());
     pkg_directory.SetOpenHandler(
         [this, &file_binding](fio::OpenFlags flags, std::string path, auto object) {
           EXPECT_EQ(fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_EXECUTABLE, flags);
@@ -174,8 +172,7 @@
         }},
     };
 
-    auto outgoing_dir_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_TRUE(outgoing_dir_endpoints.is_ok());
+    auto outgoing_dir_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto driver_endpoints = fidl::CreateEndpoints<fdh::Driver>();
     EXPECT_TRUE(driver_endpoints.is_ok());
 
@@ -194,7 +191,7 @@
           .url = "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm",
           .program = std::move(dictionary),
           .incoming = std::move(ns_entries),
-          .outgoing_dir = std::move(std::move(outgoing_dir_endpoints->server)),
+          .outgoing_dir = std::move(std::move(outgoing_dir_endpoints.server)),
       }};
       client->Start({std::move(driver_start_args), std::move(driver_endpoints->server)})
           .Then([&](auto result) {
@@ -218,7 +215,7 @@
 
     return {
         .driver = std::move(driver_endpoints->client),
-        .outgoing_dir = std::move(outgoing_dir_endpoints->client),
+        .outgoing_dir = std::move(outgoing_dir_endpoints.client),
     };
   }
 
@@ -457,26 +454,24 @@
     connected = true;
     return ZX_OK;
   });
-  auto endpoints = fidl::CreateEndpoints<fdf::Node>();
-  ASSERT_TRUE(endpoints.is_ok());
-  auto& client_end = endpoints->client.channel();
+  auto endpoints = fidl::Endpoints<fdf::Node>::Create();
+  auto& client_end = endpoints.client.channel();
   ASSERT_EQ(ZX_OK, client_end.replace(ZX_RIGHT_TRANSFER, &client_end));
   // This should fail when node rights are not ZX_DEFAULT_CHANNEL_RIGHTS.
-  StartDriver({}, &endpoints->client, ZX_ERR_INVALID_ARGS);
+  StartDriver({}, &endpoints.client, ZX_ERR_INVALID_ARGS);
   EXPECT_FALSE(connected);
 }
 
 // Start a driver with an invalid binary.
 TEST_F(DriverHostTest, Start_InvalidBinary) {
-  auto pkg_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_TRUE(pkg_endpoints.is_ok());
+  auto pkg_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   std::vector<frunner::ComponentNamespaceEntry> ns_entries;
-  ns_entries.push_back({{.path = "/pkg", .directory = std::move(pkg_endpoints->client)}});
+  ns_entries.push_back({{.path = "/pkg", .directory = std::move(pkg_endpoints.client)}});
   TestFile file("/pkg/driver/test_not_driver.so");
   fidl::Binding<fio::File> file_binding(&file);
   TestDirectory pkg_directory;
   fidl::Binding<fio::Directory> pkg_binding(&pkg_directory);
-  pkg_binding.Bind(pkg_endpoints->server.TakeChannel(), loop().dispatcher());
+  pkg_binding.Bind(pkg_endpoints.server.TakeChannel(), loop().dispatcher());
   pkg_directory.SetOpenHandler(
       [this, &file_binding](fio::OpenFlags flags, std::string path, auto object) {
         EXPECT_EQ(fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_EXECUTABLE, flags);
diff --git a/src/devices/bin/driver_manager/devfs/BUILD.gn b/src/devices/bin/driver_manager/devfs/BUILD.gn
index 5a6276a..30ac225 100644
--- a/src/devices/bin/driver_manager/devfs/BUILD.gn
+++ b/src/devices/bin/driver_manager/devfs/BUILD.gn
@@ -10,8 +10,8 @@
     "devfs.h",
   ]
   public_deps = [
+    "//sdk/fidl/fuchsia.device:fuchsia.device_cpp",
     "//sdk/fidl/fuchsia.device.fs:fuchsia.device.fs_cpp",
-    "//sdk/fidl/fuchsia.device.manager:fuchsia.device.manager_cpp",
     "//sdk/fidl/fuchsia.io:fuchsia.io_cpp",
     "//sdk/lib/component/incoming/cpp",
     "//sdk/lib/component/outgoing/cpp",
diff --git a/src/devices/bin/driver_manager/devfs/devfs.h b/src/devices/bin/driver_manager/devfs/devfs.h
index 1ef31bd..08d5bc9 100644
--- a/src/devices/bin/driver_manager/devfs/devfs.h
+++ b/src/devices/bin/driver_manager/devfs/devfs.h
@@ -6,7 +6,7 @@
 #define SRC_DEVICES_BIN_DRIVER_MANAGER_DEVFS_DEVFS_H_
 
 #include <fidl/fuchsia.device.fs/cpp/wire.h>
-#include <fidl/fuchsia.device.manager/cpp/wire.h>
+#include <fidl/fuchsia.device/cpp/wire.h>
 #include <fidl/fuchsia.io/cpp/wire.h>
 #include <lib/async/dispatcher.h>
 #include <lib/component/incoming/cpp/clone.h>
diff --git a/src/devices/bin/driver_manager/main.cc b/src/devices/bin/driver_manager/main.cc
index 1ab973b..345e07a 100644
--- a/src/devices/bin/driver_manager/main.cc
+++ b/src/devices/bin/driver_manager/main.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <fidl/fuchsia.boot/cpp/wire.h>
-#include <fidl/fuchsia.device.manager/cpp/fidl.h>
 #include <fidl/fuchsia.driver.index/cpp/wire.h>
 #include <fidl/fuchsia.io/cpp/wire.h>
 #include <lib/async-loop/cpp/loop.h>
diff --git a/src/devices/bin/driver_manager/node_removal_tracker.cc b/src/devices/bin/driver_manager/node_removal_tracker.cc
index 12b5186..b8830d9 100644
--- a/src/devices/bin/driver_manager/node_removal_tracker.cc
+++ b/src/devices/bin/driver_manager/node_removal_tracker.cc
@@ -62,6 +62,7 @@
     LOGF(INFO, "  Node '%s' in state %s", node.name.c_str(),
          ShutdownHelper::NodeStateAsString(node.state));
   }
+  handle_timeout_task_.PostDelayed(dispatcher_, kRemovalTimeoutDuration);
 }
 
 void NodeRemovalTracker::CheckRemovalDone() {
diff --git a/src/devices/bin/driver_manager/tests/driver_runner_test.cc b/src/devices/bin/driver_manager/tests/driver_runner_test.cc
index 7361aeb..1d8ee23 100644
--- a/src/devices/bin/driver_manager/tests/driver_runner_test.cc
+++ b/src/devices/bin/driver_manager/tests/driver_runner_test.cc
@@ -1450,15 +1450,14 @@
 
   auto device_controller_1 = ConnectToDeviceController(kChildName);
 
-  zx::result controller_endpoints = fidl::CreateEndpoints<fuchsia_device::Controller>();
-  ASSERT_EQ(controller_endpoints.status_value(), ZX_OK);
+  auto controller_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create();
   fidl::OneWayStatus result =
-      device_controller_1->ConnectToController(std::move(controller_endpoints->server));
+      device_controller_1->ConnectToController(std::move(controller_endpoints.server));
   ASSERT_TRUE(RunLoopUntilIdle());
   ASSERT_EQ(result.status(), ZX_OK);
 
   fidl::WireClient<fuchsia_device::Controller> device_controller_2{
-      std::move(controller_endpoints->client), dispatcher()};
+      std::move(controller_endpoints.client), dispatcher()};
 
   // Verify that the two device controllers connect to the same device server.
   // This is done by verifying the topological paths returned by the device controllers are the
diff --git a/src/devices/bin/driver_manager/tests/driver_runner_test_fixture.cc b/src/devices/bin/driver_manager/tests/driver_runner_test_fixture.cc
index 81a285f..c86e3b9 100644
--- a/src/devices/bin/driver_manager/tests/driver_runner_test_fixture.cc
+++ b/src/devices/bin/driver_manager/tests/driver_runner_test_fixture.cc
@@ -141,11 +141,10 @@
 };
 
 fidl::ClientEnd<fuchsia_component::Realm> DriverRunnerTest::ConnectToRealm() {
-  zx::result realm_endpoints = fidl::CreateEndpoints<fcomponent::Realm>();
-  ZX_ASSERT(ZX_OK == realm_endpoints.status_value());
-  realm_binding_.emplace(dispatcher(), std::move(realm_endpoints->server), &realm_,
+  auto realm_endpoints = fidl::Endpoints<fcomponent::Realm>::Create();
+  realm_binding_.emplace(dispatcher(), std::move(realm_endpoints.server), &realm_,
                          fidl::kIgnoreBindingClosure);
-  return std::move(realm_endpoints->client);
+  return std::move(realm_endpoints.client);
 }
 FakeDriverIndex DriverRunnerTest::CreateDriverIndex() {
   return FakeDriverIndex(dispatcher(), [](auto args) -> zx::result<FakeDriverIndex::MatchResult> {
@@ -310,18 +309,17 @@
       .ns({})
       .numbered_handles(realm().TakeHandles(arena));
 
-  auto controller_endpoints = fidl::CreateEndpoints<frunner::ComponentController>();
-  EXPECT_EQ(ZX_OK, controller_endpoints.status_value());
+  auto controller_endpoints = fidl::Endpoints<frunner::ComponentController>::Create();
   TestTransaction transaction(driver.close);
   {
     fidl::WireServer<frunner::ComponentRunner>::StartCompleter::Sync completer(&transaction);
     fidl::WireRequest<frunner::ComponentRunner::Start> request{
-        start_info_builder.Build(), std::move(controller_endpoints->server)};
+        start_info_builder.Build(), std::move(controller_endpoints.server)};
     static_cast<fidl::WireServer<frunner::ComponentRunner>&>(driver_runner().runner_for_tests())
         .Start(&request, completer);
   }
   RunLoopUntilIdle();
-  return {std::move(started_driver), std::move(controller_endpoints->client)};
+  return {std::move(started_driver), std::move(controller_endpoints.client)};
 }
 zx::result<DriverRunnerTest::StartDriverResult> DriverRunnerTest::StartRootDriver() {
   realm().SetCreateChildHandler(
@@ -448,8 +446,7 @@
 std::shared_ptr<CreatedChild> TestDriver::AddChild(fdfw::NodeAddArgs child_args, bool owned,
                                                    bool expect_error,
                                                    fit::function<void()> on_bind) {
-  auto controller_endpoints = fidl::CreateEndpoints<fdfw::NodeController>();
-  ZX_ASSERT(ZX_OK == controller_endpoints.status_value());
+  auto controller_endpoints = fidl::Endpoints<fdfw::NodeController>::Create();
 
   auto child_node_endpoints = fidl::CreateEndpoints<fdfw::Node>();
   ZX_ASSERT(ZX_OK == child_node_endpoints.status_value());
@@ -460,7 +457,7 @@
   }
 
   node_
-      ->AddChild({std::move(child_args), std::move(controller_endpoints->server),
+      ->AddChild({std::move(child_args), std::move(controller_endpoints.server),
                   std::move(child_node_server)})
       .Then([expect_error](fidl::Result<fdfw::Node::AddChild> result) {
         if (expect_error) {
@@ -501,7 +498,7 @@
   };
 
   std::shared_ptr<CreatedChild> child = std::make_shared<CreatedChild>();
-  child->node_controller.emplace(std::move(controller_endpoints->client), dispatcher_,
+  child->node_controller.emplace(std::move(controller_endpoints.client), dispatcher_,
                                  new ControllerEventHandler(child, std::move(on_bind)));
   if (owned) {
     child->node.emplace(std::move(child_node_endpoints->client), dispatcher_,
@@ -523,18 +520,17 @@
   zx::result dev_res = devfs().Connect(vfs);
   EXPECT_EQ(dev_res.status_value(), ZX_OK);
   fidl::WireClient<fuchsia_io::Directory> dev{std::move(*dev_res), dispatcher()};
-  zx::result controller_endpoints = fidl::CreateEndpoints<fuchsia_device::Controller>();
-  EXPECT_EQ(controller_endpoints.status_value(), ZX_OK);
+  auto controller_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create();
 
   auto device_controller_path = std::string(child_name) + "/device_controller";
   EXPECT_EQ(dev->Open(fuchsia_io::OpenFlags::kNotDirectory, {},
                       fidl::StringView::FromExternal(device_controller_path),
-                      fidl::ServerEnd<fuchsia_io::Node>(controller_endpoints->server.TakeChannel()))
+                      fidl::ServerEnd<fuchsia_io::Node>(controller_endpoints.server.TakeChannel()))
                 .status(),
             ZX_OK);
   EXPECT_TRUE(RunLoopUntilIdle());
 
-  return fidl::WireClient<fuchsia_device::Controller>{std::move(controller_endpoints->client),
+  return fidl::WireClient<fuchsia_device::Controller>{std::move(controller_endpoints.client),
                                                       dispatcher()};
 }
 
diff --git a/src/devices/bind/fuchsia.test.platform/fuchsia.test.platform.bind b/src/devices/bind/fuchsia.test.platform/fuchsia.test.platform.bind
index ec038d4..7aa466b 100644
--- a/src/devices/bind/fuchsia.test.platform/fuchsia.test.platform.bind
+++ b/src/devices/bind/fuchsia.test.platform/fuchsia.test.platform.bind
@@ -31,6 +31,8 @@
   FALLBACK = 0x16,
   RESTART = 0x17,
   TEST = 0x18,
+  POWER_FRAMEWORK = 0x19,
+  POWER_TEST = 0x20,
 };
 
 extend uint fuchsia.BIND_PLATFORM_DEV_DID {
@@ -68,4 +70,8 @@
   PCI = 0x21,
   COMPOSITE_NODE_SPEC = 0x23,
   PARENT_SPEC = 0x24,
+  FAKE_POWER_PARENT = 0x25,
+  FAKE_POWER_CHILD = 0x26,
+  FAKE_POWER_PLATFORM_DEVICE_CHILD = 0x27,
+  FAKE_POWER_PLATFORM_DEVICE_PARENT = 0x28,
 };
diff --git a/src/devices/block/bin/iochk/iochk.cc b/src/devices/block/bin/iochk/iochk.cc
index 59b6333..b65a9ae 100644
--- a/src/devices/block/bin/iochk/iochk.cc
+++ b/src/devices/block/bin/iochk/iochk.cc
@@ -674,12 +674,7 @@
       return -1;
     }
 
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_block::Session>();
-    if (endpoints.is_error()) {
-      fprintf(stderr, "error: cannot create endpoints for device: %s\n", endpoints.status_string());
-      return endpoints.status_value();
-    }
-    auto& [client, server] = endpoints.value();
+    auto [client, server] = fidl::Endpoints<fuchsia_hardware_block::Session>::Create();
     if (fidl::Status result = fidl::WireCall(ctx.BorrowBlock())->OpenSession(std::move(server));
         !result.ok()) {
       fprintf(stderr, "error: cannot open session for device: %s\n",
diff --git a/src/devices/block/bin/sdio/sdio-test.cc b/src/devices/block/bin/sdio/sdio-test.cc
index 780ee75..7375d67 100644
--- a/src/devices/block/bin/sdio/sdio-test.cc
+++ b/src/devices/block/bin/sdio/sdio-test.cc
@@ -19,10 +19,9 @@
 class SdioTest : public zxtest::Test, public fidl::WireServer<fuchsia_hardware_sdio::Device> {
  public:
   SdioTest() : loop_(&kAsyncLoopConfigAttachToCurrentThread), arena_(fdf::Arena('S')) {
-    zx::result endpoints = fidl::CreateEndpoints<Device>();
-    ASSERT_OK(endpoints.status_value());
-    client_ = std::move(endpoints->client);
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), this);
+    auto endpoints = fidl::Endpoints<Device>::Create();
+    client_ = std::move(endpoints.client);
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), this);
     loop_.StartThread("sdio-test-loop");
   }
 
diff --git a/src/devices/block/drivers/aml-sdmmc/aml-sdmmc-test.cc b/src/devices/block/drivers/aml-sdmmc/aml-sdmmc-test.cc
index cc923ea..b66b4c6 100644
--- a/src/devices/block/drivers/aml-sdmmc/aml-sdmmc-test.cc
+++ b/src/devices/block/drivers/aml-sdmmc/aml-sdmmc-test.cc
@@ -254,9 +254,12 @@
   void handle_unknown_method(fidl::UnknownMethodMetadata<fuchsia_power_broker::LeaseControl> md,
                              fidl::UnknownMethodCompleter::Sync& completer) override {}
 
-  fuchsia_power_broker::LeaseStatus lease_status_ = fuchsia_power_broker::LeaseStatus::kPending;
+  static fuchsia_power_broker::LeaseStatus lease_status_;
 };
 
+fuchsia_power_broker::LeaseStatus FakeLeaseControl::lease_status_ =
+    fuchsia_power_broker::LeaseStatus::kPending;
+
 class FakeLessor : public fidl::Server<fuchsia_power_broker::Lessor> {
  public:
   void Lease(fuchsia_power_broker::LessorLeaseRequest& req,
diff --git a/src/devices/block/drivers/aml-sdmmc/aml-sdmmc.cc b/src/devices/block/drivers/aml-sdmmc/aml-sdmmc.cc
index c709017..219af0d 100644
--- a/src/devices/block/drivers/aml-sdmmc/aml-sdmmc.cc
+++ b/src/devices/block/drivers/aml-sdmmc/aml-sdmmc.cc
@@ -439,8 +439,6 @@
     }
   }
 
-  // The lease request on the hardware power element remains persistent throughout the lifetime
-  // of this driver.
   fidl::ClientEnd<fuchsia_power_broker::LeaseControl> lease_control_client_end;
   zx_status_t status = AcquireLease(hardware_power_lessor_client_, lease_control_client_end);
   if (status != ZX_OK) {
@@ -463,6 +461,11 @@
 
   // TODO(b/330223394): Update power level when ordered to do so by Power Broker via RequiredLevel
   // (instead of monitoring LeaseStatus via the WatchStatus() call).
+  if (!hardware_power_lease_control_client_.is_valid()) {
+    FDF_LOGL(ERROR, logger(),
+             "Invalid hardware power lease control client. Stop monitoring lease status.");
+    return;
+  }
   fidl::Arena<> arena;
   hardware_power_lease_control_client_.buffer(arena)
       ->WatchStatus(last_lease_status)
@@ -584,6 +587,24 @@
             last_lease_status = lease_status;
             // Communicate to Power Broker that the hardware power level has been lowered.
             UpdatePowerLevel(hardware_power_current_level_client_, kPowerLevelOff);
+
+            // TODO(b/330223394): Revert the following behaviour of releasing and reacquiring the
+            // lease.
+            // Release and reacquire lease on the hardware power element to unblock SAG's Execution
+            // State from going to inactive.
+            hardware_power_lease_control_client_ =
+                fidl::WireClient<fuchsia_power_broker::LeaseControl>();
+
+            fidl::ClientEnd<fuchsia_power_broker::LeaseControl> lease_control_client_end;
+            status = AcquireLease(hardware_power_lessor_client_, lease_control_client_end);
+            if (status != ZX_OK) {
+              FDF_LOGL(ERROR, logger(), "Failed to reacquire lease on hardware power: %s",
+                       zx_status_get_string(status));
+              return;
+            }
+            hardware_power_lease_control_client_ =
+                fidl::WireClient<fuchsia_power_broker::LeaseControl>(
+                    std::move(lease_control_client_end), dispatcher());
             break;
           }
           default:
diff --git a/src/devices/board/drivers/astro/astro-audio.cc b/src/devices/board/drivers/astro/astro-audio.cc
index da44bf4..9562e90 100644
--- a/src/devices/board/drivers/astro/astro-audio.cc
+++ b/src/devices/board/drivers/astro/astro-audio.cc
@@ -21,7 +21,6 @@
 #include <bind/fuchsia/hardware/i2c/cpp/bind.h>
 #include <bind/fuchsia/i2c/cpp/bind.h>
 #include <bind/fuchsia/ti/platform/cpp/bind.h>
-#include <ddktl/metadata/audio.h>
 #include <soc/aml-common/aml-audio.h>
 #include <soc/aml-meson/g12a-clk.h>
 #include <soc/aml-s905d2/s905d2-gpio.h>
diff --git a/src/devices/board/drivers/nelson/nelson-audio.cc b/src/devices/board/drivers/nelson/nelson-audio.cc
index 8f14ed7..96555193 100644
--- a/src/devices/board/drivers/nelson/nelson-audio.cc
+++ b/src/devices/board/drivers/nelson/nelson-audio.cc
@@ -20,7 +20,6 @@
 #include <bind/fuchsia/hardware/gpio/cpp/bind.h>
 #include <bind/fuchsia/hardware/i2c/cpp/bind.h>
 #include <bind/fuchsia/ti/platform/cpp/bind.h>
-#include <ddktl/metadata/audio.h>
 #include <soc/aml-common/aml-audio.h>
 #include <soc/aml-meson/sm1-clk.h>
 #include <soc/aml-s905d3/s905d3-gpio.h>
diff --git a/src/devices/board/drivers/sherlock/sherlock-audio.cc b/src/devices/board/drivers/sherlock/sherlock-audio.cc
index 2680ac5..9ac95f2 100644
--- a/src/devices/board/drivers/sherlock/sherlock-audio.cc
+++ b/src/devices/board/drivers/sherlock/sherlock-audio.cc
@@ -21,7 +21,6 @@
 #include <bind/fuchsia/hardware/gpio/cpp/bind.h>
 #include <bind/fuchsia/hardware/i2c/cpp/bind.h>
 #include <bind/fuchsia/ti/platform/cpp/bind.h>
-#include <ddktl/metadata/audio.h>
 #include <soc/aml-common/aml-audio.h>
 #include <soc/aml-meson/g12b-clk.h>
 #include <soc/aml-t931/t931-gpio.h>
diff --git a/src/devices/board/drivers/vim3-devicetree/BUILD.bazel b/src/devices/board/drivers/vim3-devicetree/BUILD.bazel
index b1b367c..4d0fd92 100644
--- a/src/devices/board/drivers/vim3-devicetree/BUILD.bazel
+++ b/src/devices/board/drivers/vim3-devicetree/BUILD.bazel
@@ -107,12 +107,12 @@
         "-Wno-vla-cxx-extension",
     ],
     deps = [
+        "//zircon/system/ulib/ddk-platform-defs",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
         "@fuchsia_sdk//pkg/async-loop-cpp",
         "@fuchsia_sdk//pkg/async-loop-default",
         "@internal_sdk//pkg/board-test-helper",
-        "@internal_sdk//pkg/ddk-platform-defs",
     ],
 )
 
diff --git a/src/devices/board/drivers/vim3/vim3-audio.cc b/src/devices/board/drivers/vim3/vim3-audio.cc
index f7b67e1d..d8abf40 100644
--- a/src/devices/board/drivers/vim3/vim3-audio.cc
+++ b/src/devices/board/drivers/vim3/vim3-audio.cc
@@ -19,7 +19,6 @@
 #include <bind/fuchsia/cpp/bind.h>
 #include <bind/fuchsia/gpio/cpp/bind.h>
 #include <bind/fuchsia/hardware/clock/cpp/bind.h>
-#include <ddktl/metadata/audio.h>
 #include <soc/aml-a311d/a311d-gpio.h>
 #include <soc/aml-a311d/a311d-hw.h>
 #include <soc/aml-common/aml-audio.h>
diff --git a/src/devices/board/drivers/vim3/vim3-power.cc b/src/devices/board/drivers/vim3/vim3-power.cc
index a0e94cb..7c99f776 100644
--- a/src/devices/board/drivers/vim3/vim3-power.cc
+++ b/src/devices/board/drivers/vim3/vim3-power.cc
@@ -53,13 +53,6 @@
               "Voltage step must be a factor of (kMaxVoltageUv - kMinVoltageUv)\n");
 const uint32_t kNumSteps = (kMaxVoltageUv - kMinVoltageUv) / kVoltageStepUv + 1;
 
-enum VregIdx {
-  PWM_AO_D_VREG,
-  PWM_A_VREG,
-
-  VREG_COUNT,
-};
-
 const std::vector<fuchsia_driver_framework::BindRule> kVregPwmAoDRules = {
     fdf::MakeAcceptBindRule(bind_fuchsia_hardware_vreg::SERVICE,
                             bind_fuchsia_hardware_vreg::SERVICE_ZIRCONTRANSPORT),
@@ -199,6 +192,69 @@
   return ZX_OK;
 }
 
+zx_status_t AddVreg(uint32_t pwm_id,
+                    fdf::WireSyncClient<fuchsia_hardware_platform_bus::PlatformBus>& pbus) {
+  auto gpio_init_node = fuchsia_driver_framework::ParentSpec{{
+      .bind_rules = {fdf::MakeAcceptBindRule(bind_fuchsia::INIT_STEP,
+                                             bind_fuchsia_gpio::BIND_INIT_STEP_GPIO)},
+      .properties = {fdf::MakeProperty(bind_fuchsia::INIT_STEP,
+                                       bind_fuchsia_gpio::BIND_INIT_STEP_GPIO)},
+  }};
+
+  fidl::Arena<> fidl_arena;
+  vreg::PwmVregMetadata pwm_vreg_metadata = vreg::BuildMetadata(
+      fidl_arena, pwm_id, kA311dPwmPeriodNs, kMinVoltageUv, kVoltageStepUv, kNumSteps);
+
+  fit::result encoded_metadata = fidl::Persist(pwm_vreg_metadata);
+  if (!encoded_metadata.is_ok()) {
+    zxlogf(ERROR, "%s: Could not build metadata %s\n", __func__,
+           encoded_metadata.error_value().FormatDescription().c_str());
+    return encoded_metadata.error_value().status();
+  }
+
+  char name[20];
+  snprintf(name, sizeof(name), "vreg-%d", pwm_id);
+  fpbus::Node vreg_dev;
+  vreg_dev.name() = name;
+  vreg_dev.vid() = bind_fuchsia_platform::BIND_PLATFORM_DEV_VID_GENERIC;
+  vreg_dev.pid() = bind_fuchsia_platform::BIND_PLATFORM_DEV_PID_GENERIC;
+  vreg_dev.did() = bind_fuchsia_platform::BIND_PLATFORM_DEV_DID_PWM_VREG;
+  vreg_dev.instance_id() = pwm_id;
+  vreg_dev.metadata() = std::vector<fpbus::Metadata>{
+      {{
+          .type = DEVICE_METADATA_VREG,
+          .data = encoded_metadata.value(),
+      }},
+  };
+
+  auto vreg_pwm_node = fdf::ParentSpec{{
+      .bind_rules = {fdf::MakeAcceptBindRule(bind_fuchsia_hardware_pwm::SERVICE,
+                                             bind_fuchsia_hardware_pwm::SERVICE_ZIRCONTRANSPORT),
+                     fdf::MakeAcceptBindRule(bind_fuchsia::PWM_ID, pwm_id)},
+      .properties =
+          {
+              fdf::MakeProperty(bind_fuchsia_hardware_pwm::SERVICE,
+                                bind_fuchsia_hardware_pwm::SERVICE_ZIRCONTRANSPORT),
+          },
+  }};
+
+  auto vreg_node_spec = fuchsia_driver_framework::CompositeNodeSpec{{
+      .name = name,
+      .parents = {{vreg_pwm_node, gpio_init_node}},
+  }};
+
+  fdf::Arena fdf_arena('VREG');
+  fdf::WireUnownedResult vreg_result = pbus.buffer(fdf_arena)->AddCompositeNodeSpec(
+      fidl::ToWire(fidl_arena, vreg_dev), fidl::ToWire(fidl_arena, vreg_node_spec));
+  if (!vreg_result.ok() || vreg_result.value().is_error()) {
+    zxlogf(ERROR, "AddCompositeNodeSpec for %sfailed, error = %s", name,
+           vreg_result.FormatDescription().c_str());
+    return vreg_result.ok() ? vreg_result->error_value() : vreg_result.status();
+  }
+
+  return ZX_OK;
+}
+
 }  // namespace
 
 zx_status_t Vim3::PowerInit() {
@@ -214,86 +270,23 @@
   // function 3 which puts in PWM_D mode. A73 cluster (Big)
   gpio_init_steps_.push_back({A311D_GPIOE(2), GpioSetAltFunction(A311D_GPIOE_2_PWM_D_FN)});
 
-  // Add voltage regulator
-  fidl::Arena<2048> allocator;
-  fidl::VectorView<vreg::PwmVregMetadataEntry> pwm_vreg_entries(allocator, VREG_COUNT);
-
-  pwm_vreg_entries[PWM_AO_D_VREG] = vreg::BuildMetadata(
-      allocator, A311D_PWM_AO_D, kA311dPwmPeriodNs, kMinVoltageUv, kVoltageStepUv, kNumSteps);
-  pwm_vreg_entries[PWM_A_VREG] = vreg::BuildMetadata(allocator, A311D_PWM_A, kA311dPwmPeriodNs,
-                                                     kMinVoltageUv, kVoltageStepUv, kNumSteps);
-
-  auto metadata = vreg::BuildMetadata(allocator, pwm_vreg_entries);
-  fit::result encoded_metadata = fidl::Persist(metadata);
-  if (!encoded_metadata.is_ok()) {
-    zxlogf(ERROR, "%s: Could not build metadata %s\n", __func__,
-           encoded_metadata.error_value().FormatDescription().c_str());
-    return encoded_metadata.error_value().status();
+  // Add PWM_AO_D voltage regulator
+  auto status = AddVreg(bind_fuchsia_amlogic_platform_a311d::BIND_PWM_ID_PWM_AO_D, pbus_);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "AddVreg for ID %d failed. status = %s",
+           bind_fuchsia_amlogic_platform_a311d::BIND_PWM_ID_PWM_AO_D, zx_status_get_string(status));
+    return status;
   }
 
-  fpbus::Node vreg_dev;
-  vreg_dev.name() = "vreg";
-  vreg_dev.vid() = bind_fuchsia_platform::BIND_PLATFORM_DEV_VID_GENERIC;
-  vreg_dev.pid() = bind_fuchsia_platform::BIND_PLATFORM_DEV_PID_GENERIC;
-  vreg_dev.did() = bind_fuchsia_platform::BIND_PLATFORM_DEV_DID_PWM_VREG;
-  vreg_dev.metadata() = std::vector<fpbus::Metadata>{
-      {{
-          .type = DEVICE_METADATA_VREG,
-          .data = encoded_metadata.value(),
-      }},
-  };
-
-  auto vreg_pwm_9_node = fdf::ParentSpec{{
-      .bind_rules = {fdf::MakeAcceptBindRule(bind_fuchsia_hardware_pwm::SERVICE,
-                                             bind_fuchsia_hardware_pwm::SERVICE_ZIRCONTRANSPORT),
-                     fdf::MakeAcceptBindRule(
-                         bind_fuchsia::PWM_ID,
-                         bind_fuchsia_amlogic_platform_a311d::BIND_PWM_ID_PWM_AO_D)},
-      .properties = {fdf::MakeProperty(bind_fuchsia_hardware_pwm::SERVICE,
-                                       bind_fuchsia_hardware_pwm::SERVICE_ZIRCONTRANSPORT),
-                     fdf::MakeProperty(
-                         bind_fuchsia_pwm::PWM_ID_FUNCTION,
-                         bind_fuchsia_pwm::PWM_ID_FUNCTION_CORE_POWER_LITTLE_CLUSTER)},
-  }};
-
-  auto vreg_pwm_0_node = fuchsia_driver_framework::ParentSpec{{
-      .bind_rules = {fdf::MakeAcceptBindRule(bind_fuchsia_hardware_pwm::SERVICE,
-                                             bind_fuchsia_hardware_pwm::SERVICE_ZIRCONTRANSPORT),
-                     fdf::MakeAcceptBindRule(
-                         bind_fuchsia::PWM_ID,
-                         bind_fuchsia_amlogic_platform_a311d::BIND_PWM_ID_PWM_A)},
-      .properties = {fdf::MakeProperty(bind_fuchsia_hardware_pwm::SERVICE,
-                                       bind_fuchsia_hardware_pwm::SERVICE_ZIRCONTRANSPORT),
-                     fdf::MakeProperty(bind_fuchsia_pwm::PWM_ID_FUNCTION,
-                                       bind_fuchsia_pwm::PWM_ID_FUNCTION_CORE_POWER_BIG_CLUSTER)},
-  }};
-
-  auto gpio_init_node = fuchsia_driver_framework::ParentSpec{{
-      .bind_rules = {fdf::MakeAcceptBindRule(bind_fuchsia::INIT_STEP,
-                                             bind_fuchsia_gpio::BIND_INIT_STEP_GPIO)},
-      .properties = {fdf::MakeProperty(bind_fuchsia::INIT_STEP,
-                                       bind_fuchsia_gpio::BIND_INIT_STEP_GPIO)},
-  }};
-
-  auto vreg_node_spec = fuchsia_driver_framework::CompositeNodeSpec{{
-      .name = "vreg",
-      .parents = {{vreg_pwm_9_node, vreg_pwm_0_node, gpio_init_node}},
-  }};
+  // Add PWM_A voltage regulator
+  status = AddVreg(bind_fuchsia_amlogic_platform_a311d::BIND_PWM_ID_PWM_A, pbus_);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "AddVreg for ID %d failed. status = %s",
+           bind_fuchsia_amlogic_platform_a311d::BIND_PWM_ID_PWM_A, zx_status_get_string(status));
+    return status;
+  }
 
   fidl::Arena<> fidl_arena;
-  fdf::Arena vreg_arena('VREG');
-  fdf::WireUnownedResult vreg_result =
-      pbus_.buffer(vreg_arena)
-          ->AddCompositeNodeSpec(fidl::ToWire(fidl_arena, vreg_dev),
-                                 fidl::ToWire(fidl_arena, vreg_node_spec));
-  if (!vreg_result.ok() || vreg_result.value().is_error()) {
-    zxlogf(ERROR, "AddCompositeNodeSpec for vreg failed, error = %s",
-           vreg_result.FormatDescription().c_str());
-    return vreg_result.ok() ? vreg_result->error_value() : vreg_result.status();
-  }
-
-  fidl_arena.Reset();
-
   fdf::Arena arena('PWR_');
   const std::vector<fdf::ParentSpec> kAmlPowerImplComposite = {
       fdf::ParentSpec{{kVregPwmAoDRules, kVregPwmAoDProperties}},
@@ -313,27 +306,28 @@
     return result->error_value();
   }
 
-  zx_status_t st = AddBigCore(pbus_);
-  if (st != ZX_OK) {
-    zxlogf(ERROR, "%s: CompositeDeviceAdd for power domain Big Arm Core failed, st = %d",
-           __FUNCTION__, st);
-    return st;
+  status = AddBigCore(pbus_);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "%s: CompositeDeviceAdd for power domain Big Arm Core failed, status = %d",
+           __FUNCTION__, status);
+    return status;
   }
 
-  st = AddLittleCore(pbus_);
-  if (st != ZX_OK) {
-    zxlogf(ERROR, "%s: CompositeDeviceAdd for power domain Little Arm Core failed, st = %d",
-           __FUNCTION__, st);
-    return st;
+  status = AddLittleCore(pbus_);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "%s: CompositeDeviceAdd for power domain Little Arm Core failed, status = %d",
+           __FUNCTION__, status);
+    return status;
   }
 
   // Add USB power delivery unit
-  st = DdkAddCompositeNodeSpec(
+  status = DdkAddCompositeNodeSpec(
       "fusb302",
       ddk::CompositeNodeSpec(kI2cRules, kI2cProperties).AddParentSpec(kGpioRules, kGpioProperties));
-  if (st != ZX_OK) {
-    zxlogf(ERROR, "%s: DdkAddCompositeNodeSpec for fusb302 failed, st = %d", __FUNCTION__, st);
-    return st;
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "%s: DdkAddCompositeNodeSpec for fusb302 failed, status = %d", __FUNCTION__,
+           status);
+    return status;
   }
 
   return ZX_OK;
diff --git a/src/devices/board/lib/acpi/device-test.cc b/src/devices/board/lib/acpi/device-test.cc
index 10ad028..6a15e49 100644
--- a/src/devices/board/lib/acpi/device-test.cc
+++ b/src/devices/board/lib/acpi/device-test.cc
@@ -173,12 +173,11 @@
     zx_device_t* dev = HandOffToDdk(std::move(device));
 
     // Bind FIDL device.
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_acpi::Device>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_acpi::Device>::Create();
 
-    fidl::BindServer(dispatcher(), std::move(endpoints->server),
+    fidl::BindServer(dispatcher(), std::move(endpoints.server),
                      dev->GetDeviceContext<acpi::Device>());
-    fidl_client_.Bind(std::move(endpoints->client), dispatcher());
+    fidl_client_.Bind(std::move(endpoints.client), dispatcher());
   }
 
   acpi::DeviceArgs Args(void* handle) {
diff --git a/src/devices/bus/BUILD.gn b/src/devices/bus/BUILD.gn
index 9b38a47..289025d 100644
--- a/src/devices/bus/BUILD.gn
+++ b/src/devices/bus/BUILD.gn
@@ -23,6 +23,9 @@
     "drivers/platform/test:test-parent",
     "drivers/platform/test:test-power",
     "drivers/platform/test:test-spi",
+    "drivers/platform/test/power-integration-test:test-power-child",
+    "drivers/platform/test/power-integration-test:test-power-integration-board",
+    "drivers/platform/test/power-integration-test:test-power-parent",
   ]
 }
 
diff --git a/src/devices/bus/drivers/platform/BUILD.gn b/src/devices/bus/drivers/platform/BUILD.gn
index fa9f0e8..898c83c 100644
--- a/src/devices/bus/drivers/platform/BUILD.gn
+++ b/src/devices/bus/drivers/platform/BUILD.gn
@@ -155,5 +155,6 @@
   deps = [
     ":platform-bus-unittest-package",
     "test:platform-bus-test",
+    "test/power-integration-test:power-integration-tests-package",
   ]
 }
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/BUILD.gn b/src/devices/bus/drivers/platform/test/power-integration-test/BUILD.gn
new file mode 100644
index 0000000..2393d13
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/BUILD.gn
@@ -0,0 +1,156 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/bind/bind.gni")
+import("//build/components.gni")
+import("//build/drivers.gni")
+import("//build/fidl/fidl.gni")
+import("//build/test.gni")
+
+driver_bind_rules("test-power-integration-board-bind") {
+  rules = "test-power-integration.bind"
+  deps = [
+    "//sdk/fidl/fuchsia.hardware.platform.bus:fuchsia.hardware.platform.bus_bindlib",
+    "//src/devices/bind/fuchsia.test.platform",
+  ]
+}
+
+fuchsia_driver("test-power-integration-board-driver") {
+  output_name = "power-integration-board"
+  sources = [ "test-power-integration-board.cc" ]
+  deps = [
+    ":test-power-integration-board-bind",
+    "//sdk/fidl/fuchsia.hardware.platform.bus:fuchsia.hardware.platform.bus_cpp",
+    "//sdk/lib/driver/component/cpp:cpp",
+    "//sdk/lib/driver/logging/cpp:cpp",
+    "//src/devices/bind/fuchsia:fuchsia_cpp",
+    "//src/devices/bind/fuchsia.test.platform:fuchsia.test.platform_cpp",
+    "//src/devices/lib/driver:driver_runtime",
+    "//zircon/system/ulib/fbl",
+  ]
+}
+
+fuchsia_driver_component("test-power-integration-board") {
+  deps = [ ":test-power-integration-board-driver" ]
+  info = "test-power-integration-board-info.json"
+  manifest = "meta/test-power-board.cml"
+}
+
+driver_bind_rules("test-power-parent-bind") {
+  rules = "test-power-parent.bind"
+  deps = [ "//src/devices/bind/fuchsia.test.platform" ]
+}
+
+fuchsia_driver("test-power-parent-driver") {
+  output_name = "test-power-parent"
+  sources = [ "test-power-parent-device.cc" ]
+  deps = [
+    ":test-power-parent-bind",
+    "//sdk/fidl/fuchsia.component.decl:fuchsia.component.decl_cpp",
+    "//sdk/fidl/fuchsia.hardware.platform.device:fuchsia.hardware.platform.device_cpp",
+    "//sdk/fidl/fuchsia.hardware.power:fuchsia.hardware.power_bindlib_cpp",
+    "//sdk/fidl/fuchsia.hardware.power:fuchsia.hardware.power_cpp",
+    "//sdk/fidl/fuchsia.power.broker:fuchsia.power.broker_cpp",
+    "//sdk/lib/driver/component/cpp:cpp",
+    "//sdk/lib/driver/logging/cpp:cpp",
+    "//sdk/lib/driver/power/cpp",
+    "//sdk/lib/sys/service/cpp",
+    "//src/devices/bind/fuchsia:fuchsia_cpp",
+    "//src/devices/bind/fuchsia.test.platform:fuchsia.test.platform_cpp",
+    "//src/devices/lib/driver:driver_runtime",
+    "//zircon/system/ulib/async:async-cpp",
+  ]
+}
+
+driver_bind_rules("test-power-child-bind") {
+  rules = "test-power-child.bind"
+  deps = [ "//src/devices/bind/fuchsia.test.platform" ]
+}
+
+fuchsia_driver("test-power-child-driver") {
+  output_name = "test-power-child"
+  sources = [ "test-power-child-device.cc" ]
+  deps = [
+    ":test-power-child-bind",
+    "//sdk/fidl/fuchsia.hardware.platform.device:fuchsia.hardware.platform.device_cpp",
+    "//sdk/fidl/fuchsia.hardware.power:fuchsia.hardware.power_cpp",
+    "//sdk/fidl/fuchsia.power.broker:fuchsia.power.broker_cpp",
+    "//sdk/lib/driver/component/cpp:cpp",
+    "//sdk/lib/driver/logging/cpp:cpp",
+    "//sdk/lib/driver/power/cpp",
+    "//src/devices/lib/driver:driver_runtime",
+  ]
+}
+
+fuchsia_driver_component("test-power-child") {
+  component_name = "test-power-child"
+  deps = [ ":test-power-child-driver" ]
+  info = "test-power-child-info.json"
+  manifest = "meta/test-power-child.cml"
+}
+
+fuchsia_driver_component("test-power-parent") {
+  component_name = "test-power-parent"
+  deps = [ ":test-power-parent-driver" ]
+  info = "test-power-parent-info.json"
+  manifest = "meta/test-power-parent.cml"
+}
+
+fidl("fuchsia.test.drivers.power") {
+  testonly = true
+  sources = [ "power_test.fidl" ]
+}
+
+executable("mock-power-broker-bin") {
+  sources = [ "mock-power-broker.cc" ]
+  testonly = true
+  output_name = "mock-power-broker"
+  deps = [
+    ":fuchsia.test.drivers.power_cpp",
+    "//sdk/fidl/fuchsia.power.broker:fuchsia.power.broker_cpp",
+    "//sdk/lib/driver/component/cpp:cpp",
+    "//sdk/lib/driver/logging/cpp:cpp",
+    "//sdk/lib/sys/cpp:cpp",
+    "//sdk/lib/syslog/cpp:cpp",
+    "//zircon/system/ulib/async-loop:async-loop-cpp",
+    "//zircon/system/ulib/async-loop:async-loop-default",
+  ]
+}
+
+fuchsia_component("mock-power-broker") {
+  testonly = true
+  manifest = "meta/mock-power-broker.cml"
+  deps = [ ":mock-power-broker-bin" ]
+}
+
+test("power-integration-test-test") {
+  sources = [ "test-power-integration.cc" ]
+  deps = [
+    ":fuchsia.test.drivers.power_cpp",
+    "//sdk/fidl/fuchsia.driver.test:fuchsia.driver.test_cpp",
+    "//sdk/fidl/fuchsia.hardware.platform.bus:fuchsia.hardware.platform.bus_cpp",
+    "//sdk/fidl/fuchsia.io:fuchsia.io_cpp",
+    "//sdk/fidl/fuchsia.power.broker:fuchsia.power.broker_cpp",
+    "//sdk/lib/device-watcher/cpp",
+    "//sdk/lib/driver/logging/cpp:cpp",
+    "//sdk/lib/driver_test_realm/realm_builder/cpp",
+    "//sdk/lib/sys/component/cpp/testing:cpp",
+    "//src/devices/lib/driver:driver_runtime",
+    "//src/lib/fxl/test:gtest_main",
+    "//src/lib/testing/loop_fixture",
+    "//zircon/system/ulib/async-loop:async-loop-cpp",
+  ]
+}
+
+fuchsia_unittest_package("power-integration-tests-package") {
+  package_name = "power-integration-tests"
+  deps = [
+    ":mock-power-broker",
+    ":power-integration-test-test",
+    ":test-power-child",
+    ":test-power-integration-board",
+    ":test-power-parent",
+    "//src/devices/bus/drivers/platform:platform-bus",
+  ]
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/meta/mock-power-broker.cml b/src/devices/bus/drivers/platform/test/power-integration-test/meta/mock-power-broker.cml
new file mode 100644
index 0000000..21109fb
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/meta/mock-power-broker.cml
@@ -0,0 +1,27 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "inspect/client.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        runner: "elf",
+        binary: "bin/mock-power-broker",
+    },
+    capabilities: [
+        { protocol: "fuchsia.power.broker.Topology" },
+        { protocol: "fuchsia.test.drivers.power.GetPowerElements" },
+    ],
+    expose: [
+        {
+            protocol: "fuchsia.power.broker.Topology",
+            from: "self",
+        },
+        {
+            protocol: "fuchsia.test.drivers.power.GetPowerElements",
+            from: "self",
+        },
+    ],
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-board.cml b/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-board.cml
new file mode 100644
index 0000000..046ac4f
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-board.cml
@@ -0,0 +1,19 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "driver_component/driver.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        runner: "driver",
+        binary: 'driver/power-integration-board.so',
+        bind: 'meta/bind/test-power-integration-board-bind.bindbc',
+        colocate: "true",
+        default_dispatcher_opts: [ "allow_sync_calls" ],
+    },
+    use: [
+        { service: "fuchsia.hardware.platform.bus.Service" },
+    ],
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-child.cml b/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-child.cml
new file mode 100644
index 0000000..7c68a06
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-child.cml
@@ -0,0 +1,36 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "driver_component/driver.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        runner: 'driver',
+        binary: 'driver/test-power-child.so',
+        bind: 'meta/bind/test-power-child-bind.bindbc',
+        default_dispatcher_ops: [ "allow_sync_calls" ],
+    },
+    capabilities: [
+        { protocol: "fuchsia.test.power-integration.Test" },
+        { service: "fuchsia.hardware.power.PowerTokenService" },
+    ],
+    use: [
+        { protocol: "fuchsia.power.broker.Topology" },
+        { service: "fuchsia.hardware.platform.device.Service" },
+        { service: "fuchsia.hardware.power.PowerTokenService" },
+    ],
+    expose: [
+        {
+            protocol: "fuchsia.test.power-integration.Test",
+            from: "self",
+        },
+        {
+            service: "fuchsia.hardware.power.PowerTokenService",
+            from: "self",
+        },
+    ],
+
+    // TODO add `expose` of token provider protocol
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-parent.cml b/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-parent.cml
new file mode 100644
index 0000000..1809fae
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/meta/test-power-parent.cml
@@ -0,0 +1,35 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "driver_component/driver.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        runner: 'driver',
+        binary: 'driver/test-power-parent.so',
+        bind: 'meta/bind/test-power-parent-bind.bindbc',
+        default_dispatcher_ops: [ "allow_sync_calls" ],
+    },
+    capabilities: [
+        { protocol: "fuchsia.test.power-integration.Test" },
+        { service: "fuchsia.hardware.power.PowerTokenService" },
+    ],
+    use: [
+        { protocol: "fuchsia.power.broker.Topology" },
+        { service: "fuchsia.hardware.platform.device.Service" },
+    ],
+    expose: [
+        {
+            protocol: "fuchsia.test.power-integration.Test",
+            from: "self",
+        },
+        {
+            service: "fuchsia.hardware.power.PowerTokenService",
+            from: "self",
+        },
+    ],
+
+    // TODO add `expose` of token provider protocol
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/mock-power-broker.cc b/src/devices/bus/drivers/platform/test/power-integration-test/mock-power-broker.cc
new file mode 100644
index 0000000..e74dec4
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/mock-power-broker.cc
@@ -0,0 +1,134 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fidl/fuchsia.power.broker/cpp/fidl.h>
+#include <fidl/fuchsia.test.drivers.power/cpp/fidl.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/async-loop/default.h>
+#include <lib/syslog/cpp/macros.h>
+
+#include <sdk/lib/sys/cpp/outgoing_directory.h>
+
+namespace mock_power_broker {
+
+class PowerElement {
+ public:
+  explicit PowerElement(fidl::ServerEnd<fuchsia_power_broker::ElementControl> ec,
+                        fidl::ServerEnd<fuchsia_power_broker::Lessor> less,
+                        fidl::ServerEnd<fuchsia_power_broker::CurrentLevel> current,
+                        fidl::ServerEnd<fuchsia_power_broker::RequiredLevel> required)
+      : element_control_(std::move(ec)),
+        lessor_(std::move(less)),
+        current_level_(std::move(current)),
+        required_level_(std::move(required)) {}
+
+ private:
+  fidl::ServerEnd<fuchsia_power_broker::ElementControl> element_control_;
+  fidl::ServerEnd<fuchsia_power_broker::Lessor> lessor_;
+  fidl::ServerEnd<fuchsia_power_broker::CurrentLevel> current_level_;
+  fidl::ServerEnd<fuchsia_power_broker::RequiredLevel> required_level_;
+};
+
+class Topology : public fidl::Server<fuchsia_power_broker::Topology>,
+                 public fidl::Server<fuchsia_test_drivers_power::GetPowerElements> {
+ public:
+  void AddElement(AddElementRequest& req, AddElementCompleter::Sync& completer) override {
+    FX_LOGS(INFO) << "Got add element request for element named '"
+                  << req.element_name().value().c_str() << "'";
+
+    // Make channel to return to client
+    auto element_control = fidl::CreateEndpoints<fuchsia_power_broker::ElementControl>();
+
+    clients_.emplace_back(std::move(element_control->server),
+                          std::move(req.lessor_channel().value()),
+                          std::move(req.level_control_channels().value().current()),
+                          std::move(req.level_control_channels().value().required()));
+
+    fuchsia_power_broker::TopologyAddElementResponse result{
+        {
+            .element_control_channel = std::move(element_control->client),
+        },
+    };
+    fit::success<fuchsia_power_broker::TopologyAddElementResponse> success(std::move(result));
+
+    std::string element_name(req.element_name().value().data(),
+                             req.element_name().value().length());
+    added_elements_.emplace_back(std::move(element_name));
+    if (completer_ != std::nullopt) {
+      auto local = std::move(completer_.value());
+      SendReply(local);
+    }
+
+    completer.Reply(std::move(success));
+  }
+  void handle_unknown_method(fidl::UnknownMethodMetadata<fuchsia_power_broker::Topology> md,
+                             fidl::UnknownMethodCompleter::Sync& completer) override {}
+
+  void GetElements(GetElementsCompleter::Sync& completer) override {
+    if (added_elements_.size() > 0) {
+      auto local = completer.ToAsync();
+      SendReply(local);
+      return;
+    }
+    completer_ = completer.ToAsync();
+  }
+
+ private:
+  void SendReply(GetElementsCompleter::Async& completer) {
+    fuchsia_test_drivers_power::GetPowerElementsGetElementsResponse resp;
+    resp.elements() = added_elements_;
+    completer.Reply(resp);
+    completer_ = std::nullopt;
+    added_elements_ = std::vector<std::string>();
+  }
+  std::optional<GetElementsCompleter::Async> completer_;
+  std::vector<std::string> added_elements_;
+  std::vector<PowerElement> clients_;
+};
+
+}  // namespace mock_power_broker
+
+int main(int argc, char** argv) {
+  async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
+  sys::OutgoingDirectory out_dir;
+  loop.StartThread();
+
+  std::vector<fidl::ServerBindingRef<fuchsia_power_broker::Topology>> topology_bindings_;
+  std::vector<fidl::ServerBindingRef<fuchsia_test_drivers_power::GetPowerElements>>
+      get_elements_bindings_;
+  std::shared_ptr<mock_power_broker::Topology> handler =
+      std::make_shared<mock_power_broker::Topology>();
+
+  fidl::ProtocolHandler<fuchsia_power_broker::Topology> req_handler =
+      [handler, &topology_bindings_, &loop](fidl::ServerEnd<fuchsia_power_broker::Topology> req) {
+        fidl::ServerBindingRef<fuchsia_power_broker::Topology> ref =
+            fidl::BindServer(loop.dispatcher(), std::move(req), handler,
+                             [&](mock_power_broker::Topology* topo, fidl::UnbindInfo info,
+                                 fidl::ServerEnd<fuchsia_power_broker::Topology> server_end) {});
+        topology_bindings_.emplace_back(std::move(ref));
+      };
+
+  out_dir.AddProtocol<fuchsia_power_broker::Topology>(std::move(req_handler));
+  fidl::ProtocolHandler<fuchsia_test_drivers_power::GetPowerElements> get_elements_handler =
+      [handler, &get_elements_bindings_,
+       &loop](fidl::ServerEnd<fuchsia_test_drivers_power::GetPowerElements> req) {
+        fidl::ServerBindingRef<fuchsia_test_drivers_power::GetPowerElements> binding_ref =
+            fidl::BindServer(
+                loop.dispatcher(), std::move(req), handler,
+                [&](mock_power_broker::Topology* t, fidl::UnbindInfo info,
+                    fidl::ServerEnd<fuchsia_test_drivers_power::GetPowerElements> server_end) {});
+        get_elements_bindings_.emplace_back(std::move(binding_ref));
+      };
+
+  out_dir.AddProtocol<fuchsia_test_drivers_power::GetPowerElements>(
+      std::move(get_elements_handler));
+
+  auto serve_result = out_dir.ServeFromStartupInfo(loop.dispatcher());
+  if (serve_result != ZX_OK) {
+    return -1;
+  }
+
+  loop.JoinThreads();
+  return 0;
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/power_test.fidl b/src/devices/bus/drivers/platform/test/power-integration-test/power_test.fidl
new file mode 100644
index 0000000..9634c03
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/power_test.fidl
@@ -0,0 +1,18 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+library fuchsia.test.drivers.power;
+
+/// Maximum length of an element name
+const MAX_ELEMENT_NAME_LENGTH uint16 = 1024;
+
+/// Maxium number of elements reported at once.
+const MAX_ELEMENTS uint16 = 60;
+
+@discoverable
+closed protocol GetPowerElements {
+    strict GetElements() -> (struct {
+        elements vector<string:MAX_ELEMENT_NAME_LENGTH>:MAX_ELEMENTS;
+    });
+};
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-device.cc b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-device.cc
new file mode 100644
index 0000000..a06aaa9
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-device.cc
@@ -0,0 +1,74 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-device.h"
+
+#include <fidl/fuchsia.hardware.platform.device/cpp/fidl.h>
+#include <fidl/fuchsia.hardware.power/cpp/fidl.h>
+#include <lib/driver/component/cpp/driver_export.h>
+#include <lib/driver/power/cpp/power-support.h>
+
+namespace fake_child_device {
+zx::result<> FakeChild::Start() {
+  // Connect to the Device from our platform device parent and get our power
+  // configuration.
+  auto device_connection =
+      incoming()->Connect<fuchsia_hardware_platform_device::Service::Device>("platform-device");
+  if (!device_connection.is_ok()) {
+    return device_connection.take_error();
+  }
+
+  fidl::WireSyncClient<fuchsia_hardware_platform_device::Device> device_client(
+      std::move(device_connection.value()));
+  auto power_config = device_client->GetPowerConfiguration();
+
+  // Ask the library to get our dependency tokens.
+  auto res = fdf_power::GetDependencyTokens(*incoming(), power_config->value()->config[0]);
+  if (res.is_error()) {
+    return zx::error(ZX_ERR_INTERNAL);
+  }
+  fdf_power::TokenMap tokens = std::move(res.value());
+
+  // Add our power element.
+  {
+    // Get a connection to the Topology capability.
+    auto pb_open = incoming()->Connect<fuchsia_power_broker::Topology>();
+    if (pb_open.is_error()) {
+      return pb_open.take_error();
+    }
+    fidl::ClientEnd<fuchsia_power_broker::Topology> broker = std::move(pb_open.value());
+
+    // Prepare a bunch of stuff we need for the element.
+    fidl::Endpoints<fuchsia_power_broker::RequiredLevel> required_level =
+        fidl::CreateEndpoints<fuchsia_power_broker::RequiredLevel>().value();
+    fidl::Endpoints<fuchsia_power_broker::CurrentLevel> current_level =
+        fidl::CreateEndpoints<fuchsia_power_broker::CurrentLevel>().value();
+    fidl::Endpoints<fuchsia_power_broker::Lessor> lessor =
+        fidl::CreateEndpoints<fuchsia_power_broker::Lessor>().value();
+    zx_handle_t active, passive;
+    zx_event_create(0, &active);
+    zx_event_create(0, &passive);
+    zx::event active_event(active);
+    zx::event passive_event(passive);
+
+    fit::result<fdf_power::Error, fuchsia_power_broker::TopologyAddElementResponse> add_result =
+        fdf_power::AddElement(
+            broker, power_config->value()->config[0], std::move(tokens), active_event.borrow(),
+            passive_event.borrow(),
+            std::pair{std::move(current_level.server), std::move(required_level.server)},
+            std::move(lessor.server));
+    if (!add_result.is_ok()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+
+    // That worked, so store the channels we'll need to work with the element.
+    required_level_ = std::move(required_level.client);
+    current_level_ = std::move(current_level.client);
+    lessor_ = std::move(lessor.client);
+  }
+  return zx::ok();
+}
+}  // namespace fake_child_device
+
+FUCHSIA_DRIVER_EXPORT(fake_child_device::FakeChild);
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-device.h b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-device.h
new file mode 100644
index 0000000..26810db
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-device.h
@@ -0,0 +1,31 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_TEST_CHILD_DEVICE_H_
+#define SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_TEST_CHILD_DEVICE_H_
+
+#include <fidl/fuchsia.power.broker/cpp/fidl.h>
+#include <lib/driver/component/cpp/driver_base.h>
+
+namespace fake_child_device {
+
+class FakeChild : public fdf::DriverBase {
+ public:
+  FakeChild(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher dispatcher)
+      : fdf::DriverBase("fake-child", std::move(start_args), std::move(dispatcher)) {}
+
+  ~FakeChild() override = default;
+
+  zx::result<> Start() override;
+
+ private:
+  fidl::WireSyncClient<fuchsia_driver_framework::Node> node_;
+  fidl::WireSyncClient<fuchsia_driver_framework::NodeController> controller_;
+  fidl::ClientEnd<fuchsia_power_broker::RequiredLevel> required_level_;
+  fidl::ClientEnd<fuchsia_power_broker::CurrentLevel> current_level_;
+  fidl::ClientEnd<fuchsia_power_broker::Lessor> lessor_;
+};
+}  // namespace fake_child_device
+
+#endif /* SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_TEST_CHILD_DEVICE_H_ */
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-info.json b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-info.json
new file mode 100644
index 0000000..f0ed4c4
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child-info.json
@@ -0,0 +1,11 @@
+{
+    "short_description": "Test Power Child Driver",
+    "manufacturer": "",
+    "families": [],
+    "models": [],
+    "areas": [
+        "Platform",
+        "Power",
+        "Test"
+    ]
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child.bind b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child.bind
new file mode 100644
index 0000000..4526c28
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-child.bind
@@ -0,0 +1,19 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+composite fake_power;
+
+using fuchsia.test.platform;
+
+primary node "power" {
+  fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.test.platform.BIND_PLATFORM_DEV_VID.TEST;
+  fuchsia.BIND_PLATFORM_DEV_PID == fuchsia.test.platform.BIND_PLATFORM_DEV_PID.POWER_TEST;
+  fuchsia.BIND_PLATFORM_DEV_DID == fuchsia.test.platform.BIND_PLATFORM_DEV_DID.FAKE_POWER_CHILD;
+}
+
+node "platform-device" {
+  fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.test.platform.BIND_PLATFORM_DEV_VID.TEST;
+  fuchsia.BIND_PLATFORM_DEV_PID == fuchsia.test.platform.BIND_PLATFORM_DEV_PID.POWER_TEST;
+  fuchsia.BIND_PLATFORM_DEV_DID == fuchsia.test.platform.BIND_PLATFORM_DEV_DID.FAKE_POWER_PLATFORM_DEVICE_CHILD;
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board-info.json b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board-info.json
new file mode 100644
index 0000000..b4fdccc
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board-info.json
@@ -0,0 +1,11 @@
+{
+    "short_description": "Fake Power Board Driver",
+    "manufacturer": "Google",
+    "families": [],
+    "models": [],
+    "areas": [
+        "Platform",
+        "Power",
+        "Test"
+    ]
+}
\ No newline at end of file
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board.cc b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board.cc
new file mode 100644
index 0000000..14d98f6
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board.cc
@@ -0,0 +1,225 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board.h"
+
+#include <fidl/fuchsia.hardware.platform.bus/cpp/driver/fidl.h>
+#include <fidl/fuchsia.hardware.platform.bus/cpp/fidl.h>
+#include <fidl/fuchsia.hardware.power/cpp/fidl.h>
+#include <lib/driver/component/cpp/composite_node_spec.h>
+#include <lib/driver/component/cpp/driver_export.h>
+#include <lib/driver/component/cpp/node_add_args.h>
+
+#include <bind/fuchsia/cpp/bind.h>
+#include <bind/fuchsia/test/platform/cpp/bind.h>
+
+namespace power_integration_board {
+
+zx::result<> PowerIntegrationBoard::Start() {
+  zx::result<fdf::WireSyncClient<fuchsia_hardware_platform_bus::PlatformBus>> client =
+      incoming()->Connect<fuchsia_hardware_platform_bus::Service::PlatformBus>();
+
+  if (client.is_error()) {
+    return zx::error_result(ZX_ERR_ACCESS_DENIED);
+  }
+
+  fdf::WireSyncClient<fuchsia_hardware_platform_bus::PlatformBus> &platform_bus = client.value();
+
+  fdf::Arena arena('TEST');
+  auto board_info = platform_bus.buffer(arena)->GetBoardInfo();
+
+  if (board_info->is_error()) {
+    return zx::error_result(ZX_ERR_IO);
+  }
+
+  fuchsia_hardware_power::PowerElementConfiguration config;
+
+  // create the composite node for the child
+  {
+    fuchsia_hardware_power::Transition to_on;
+    to_on.latency_us() = 350;
+    to_on.target_level() = 1;
+
+    fuchsia_hardware_power::PowerLevel off = fuchsia_hardware_power::PowerLevel();
+    off.level() = 0;
+    off.name() = "off";
+    off.transitions() = std::vector<fuchsia_hardware_power::Transition>{to_on};
+
+    fuchsia_hardware_power::Transition to_off;
+    to_off.latency_us() = 20;
+    to_off.target_level() = 0;
+
+    fuchsia_hardware_power::PowerLevel on;
+    on.name() = "on";
+    on.level() = 1;
+    on.transitions() = std::vector<fuchsia_hardware_power::Transition>{to_off};
+
+    fuchsia_hardware_power::PowerElement element;
+    element.name() = "pe-fake-child";
+    element.levels() = std::vector<fuchsia_hardware_power::PowerLevel>{on, off};
+
+    fuchsia_hardware_power::PowerElementConfiguration config;
+    config.element() = element;
+
+    // set up dependency between parent and child
+    fuchsia_hardware_power::PowerDependency dep;
+    dep.child() = "pe-fake-child";
+    dep.parent() = fuchsia_hardware_power::ParentElement::WithName("pe-fake-parent");
+    dep.level_deps() = std::vector<fuchsia_hardware_power::LevelTuple>{{{
+        .child_level = 1,
+        .parent_level = 1,
+    }}};
+    dep.strength() = fuchsia_hardware_power::RequirementType::kActive;
+    config.dependencies() = std::vector<fuchsia_hardware_power::PowerDependency>{dep};
+
+    std::vector<fuchsia_hardware_power::PowerElementConfiguration> power_config =
+        std::vector<fuchsia_hardware_power::PowerElementConfiguration>{config};
+
+    fuchsia_hardware_platform_bus::Node pdev;
+    pdev.name() = "composite_fake_child";
+    pdev.vid() = bind_fuchsia_test_platform::BIND_PLATFORM_DEV_VID_TEST;
+    pdev.pid() = bind_fuchsia_test_platform::BIND_PLATFORM_DEV_PID_POWER_TEST;
+    pdev.did() = bind_fuchsia_test_platform::BIND_PLATFORM_DEV_DID_FAKE_POWER_PLATFORM_DEVICE_CHILD;
+    pdev.power_config() = power_config;
+
+    auto bind_rules = std::vector{
+        fdf::MakeAcceptBindRule(bind_fuchsia::PLATFORM_DEV_VID,
+                                bind_fuchsia_test_platform::BIND_PLATFORM_DEV_VID_TEST),
+        fdf::MakeAcceptBindRule(bind_fuchsia::PLATFORM_DEV_PID,
+                                bind_fuchsia_test_platform::BIND_PLATFORM_DEV_PID_POWER_TEST),
+        fdf::MakeAcceptBindRule(
+            bind_fuchsia::PLATFORM_DEV_DID,
+            bind_fuchsia_test_platform::BIND_PLATFORM_DEV_DID_FAKE_POWER_CHILD)};
+
+    auto properties = std::vector{
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_VID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_VID_TEST),
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_PID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_PID_POWER_TEST),
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_DID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_DID_FAKE_POWER_CHILD)};
+
+    auto parents = std::vector{
+        fuchsia_driver_framework::ParentSpec{{.bind_rules = bind_rules, .properties = properties}}};
+
+    auto composite_node_spec = fuchsia_driver_framework::CompositeNodeSpec{{
+        .name = "composite_fake_child",
+        .parents = parents,
+    }};
+
+    auto result = platform_bus.buffer(arena)->AddCompositeNodeSpec(
+        fidl::ToWire(arena, pdev), fidl::ToWire(arena, composite_node_spec));
+
+    if (!result.ok()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+
+    if (result->is_error()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+  }
+
+  {
+    fuchsia_hardware_platform_bus::Node parent_pdev;
+    parent_pdev.name() = "pdev_parent";
+    parent_pdev.vid() = bind_fuchsia_test_platform::BIND_PLATFORM_DEV_VID_TEST;
+    parent_pdev.pid() = bind_fuchsia_test_platform::BIND_PLATFORM_DEV_PID_POWER_TEST;
+    parent_pdev.did() =
+        bind_fuchsia_test_platform::BIND_PLATFORM_DEV_DID_FAKE_POWER_PLATFORM_DEVICE_PARENT;
+
+    fuchsia_hardware_power::PowerLevel off;
+    off.level() = 0;
+    off.name() = "off";
+    off.transitions() =
+        std::vector<fuchsia_hardware_power::Transition>{fuchsia_hardware_power::Transition{{
+            .target_level = 1,
+            .latency_us = 200,
+        }}};
+
+    fuchsia_hardware_power::PowerLevel on;
+    on.level() = 1;
+    on.name() = "on";
+    on.transitions() =
+        std::vector<fuchsia_hardware_power::Transition>{fuchsia_hardware_power::Transition{{
+            .target_level = 0,
+            .latency_us = 5,
+        }}};
+
+    fuchsia_hardware_power::PowerElementConfiguration config;
+    config.element() = fuchsia_hardware_power::PowerElement{{
+        .name = "pe-fake-parent",
+        .levels =
+            std::vector<fuchsia_hardware_power::PowerLevel>{
+                on,
+                off,
+            },
+
+    }};
+
+    parent_pdev.power_config() = std::vector<fuchsia_hardware_power::PowerElementConfiguration>{
+        config,
+    };
+
+    auto bind_rules = std::vector{
+        fdf::MakeAcceptBindRule(bind_fuchsia::PLATFORM_DEV_VID,
+                                bind_fuchsia_test_platform::BIND_PLATFORM_DEV_VID_TEST),
+        fdf::MakeAcceptBindRule(bind_fuchsia::PLATFORM_DEV_PID,
+                                bind_fuchsia_test_platform::BIND_PLATFORM_DEV_PID_POWER_TEST),
+        fdf::MakeAcceptBindRule(
+            bind_fuchsia::PLATFORM_DEV_DID,
+            bind_fuchsia_test_platform::BIND_PLATFORM_DEV_DID_FAKE_POWER_PARENT)};
+
+    auto properties = std::vector{
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_VID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_VID_TEST),
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_PID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_PID_POWER_TEST),
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_DID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_DID_FAKE_POWER_PARENT)};
+
+    auto parents = std::vector{
+        fuchsia_driver_framework::ParentSpec{{.bind_rules = bind_rules, .properties = properties}}};
+
+    auto composite_node_spec = fuchsia_driver_framework::CompositeNodeSpec{{
+        .name = "composite_fake_parent",
+        .parents = parents,
+    }};
+
+    auto result = platform_bus.buffer(arena)->AddCompositeNodeSpec(
+        fidl::ToWire(arena, parent_pdev), fidl::ToWire(arena, composite_node_spec));
+
+    if (!result.ok()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+
+    if (result->is_error()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+  }
+
+  // Create the parent device
+  {
+    fuchsia_hardware_platform_bus::Node fake_parent_device;
+    fake_parent_device.name() = "fake_parent";
+    fake_parent_device.vid() = bind_fuchsia_test_platform::BIND_PLATFORM_DEV_VID_TEST;
+    fake_parent_device.pid() = bind_fuchsia_test_platform::BIND_PLATFORM_DEV_PID_POWER_TEST;
+    fake_parent_device.did() = bind_fuchsia_test_platform::BIND_PLATFORM_DEV_DID_FAKE_POWER_PARENT;
+
+    auto result = platform_bus.buffer(arena)->NodeAdd(fidl::ToWire(arena, fake_parent_device));
+
+    if (!result.ok()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+
+    if (result->is_error()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+  }
+
+  return zx::ok();
+}
+
+}  // namespace power_integration_board
+
+FUCHSIA_DRIVER_EXPORT(power_integration_board::PowerIntegrationBoard);
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board.h b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board.h
new file mode 100644
index 0000000..1ea3e85
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration-board.h
@@ -0,0 +1,26 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_TEST_POWER_INTEGRATION_BOARD_H
+#define SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_TEST_POWER_INTEGRATION_BOARD_H
+
+#include <lib/driver/component/cpp/driver_base.h>
+
+namespace power_integration_board {
+
+class PowerIntegrationBoard : public fdf::DriverBase {
+ public:
+  PowerIntegrationBoard(fdf::DriverStartArgs start_args,
+                        fdf::UnownedSynchronizedDispatcher dispatcher)
+      : fdf::DriverBase("power-integration-board", std::move(start_args), std::move(dispatcher)) {}
+  ~PowerIntegrationBoard() override = default;
+  zx::result<> Start() override;
+
+ private:
+  fidl::WireSyncClient<fuchsia_driver_framework::Node> node_;
+  fidl::WireSyncClient<fuchsia_driver_framework::NodeController> controller_;
+};
+}  // namespace power_integration_board
+
+#endif /* SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_TEST_POWER_INTEGRATION_BOARD_H */
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration.bind b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration.bind
new file mode 100644
index 0000000..c7c3cd9
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration.bind
@@ -0,0 +1,10 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+using fuchsia.hardware.platform.bus;
+using fuchsia.test.platform;
+
+fuchsia.hardware.platform.bus.Service == fuchsia.hardware.platform.bus.Service.DriverTransport;
+fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.test.platform.BIND_PLATFORM_DEV_VID.TEST;
+fuchsia.BIND_PLATFORM_DEV_PID == fuchsia.test.platform.BIND_PLATFORM_DEV_PID.PBUS_TEST;
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration.cc b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration.cc
new file mode 100644
index 0000000..e56bb67
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-integration.cc
@@ -0,0 +1,104 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fidl/fuchsia.driver.test/cpp/fidl.h>
+#include <fidl/fuchsia.test.drivers.power/cpp/fidl.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/async-loop/default.h>
+#include <lib/device-watcher/cpp/device-watcher.h>
+#include <lib/driver_test_realm/realm_builder/cpp/lib.h>
+#include <lib/sys/component/cpp/testing/realm_builder.h>
+#include <lib/syslog/cpp/macros.h>
+
+#include <unordered_set>
+
+#include <fbl/unique_fd.h>
+
+#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
+
+namespace power_integration_test {
+
+class PowerIntegrationTest : public gtest::TestLoopFixture {};
+
+TEST_F(PowerIntegrationTest, MetadataPassing) {
+  auto builder = component_testing::RealmBuilder::Create();
+  driver_test_realm::Setup(builder);
+
+  auto decl = builder.GetComponentDecl("driver_test_realm");
+
+  fuchsia::component::decl::OfferProtocol proto_offer;
+  proto_offer.set_source(
+      fuchsia::component::decl::Ref::WithParent(fuchsia::component::decl::ParentRef{}));
+  proto_offer.set_source_name("fuchsia.power.broker.Topology");
+  proto_offer.set_target(fuchsia::component::decl::Ref::WithCollection(
+      fuchsia::component::decl::CollectionRef{.name = "realm_builder"}));
+  proto_offer.set_target_name("fuchsia.power.broker.Topology");
+  proto_offer.set_dependency_type(::fuchsia::component::decl::DependencyType::STRONG);
+
+  decl.mutable_offers()->emplace_back(
+      fuchsia::component::decl::Offer::WithProtocol(std::move(proto_offer)));
+  builder.ReplaceComponentDecl("driver_test_realm", std::move(decl));
+
+  async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread};
+  loop.StartThread();
+
+  builder.AddChild(
+      "power-broker", "#meta/mock-power-broker.cm",
+      component_testing::ChildOptions{.startup_mode = component_testing::StartupMode::LAZY});
+
+  builder.AddRoute(component_testing::Route{
+      .capabilities = {component_testing::Protocol{.name = "fuchsia.logger.LogSink"}},
+      .source = {component_testing::ParentRef{}},
+      .targets = {component_testing::ChildRef{"power-broker"}},
+  });
+
+  builder.AddRoute(component_testing::Route{
+      .capabilities = {component_testing::Protocol{.name = "fuchsia.power.broker.Topology"}},
+      .source = {component_testing::ChildRef{"power-broker"}},
+      .targets = {component_testing::ChildRef{"driver_test_realm"}},
+  });
+
+  builder.AddRoute(component_testing::Route{
+      .capabilities = {component_testing::Protocol{
+          .name = "fuchsia.test.drivers.power.GetPowerElements"}},
+      .source = {component_testing::ChildRef{"power-broker"}},
+      .targets = {component_testing::ParentRef{}},
+  });
+
+  auto test_realm = builder.Build(dispatcher());
+
+  // connect to the realm protocol so we can control the test realm
+  fidl::SyncClient<fuchsia_driver_test::Realm> realm_protocol(
+      std::move(test_realm.component().Connect<fuchsia_driver_test::Realm>().value()));
+
+  // now actually start the realm
+  auto realm_args = fuchsia_driver_test::RealmArgs();
+  realm_args.root_driver() = "fuchsia-boot:///#meta/platform-bus.cm";
+  realm_args.offers() = {
+      {fuchsia_driver_test::Offer{{.protocol_name = "fuchsia.power.broker.Topology",
+                                   .collection = fuchsia_driver_test::Collection::kBootDrivers}}}};
+  auto start_result = realm_protocol->Start(std::move(realm_args));
+  ASSERT_TRUE(start_result.is_ok());
+
+  auto get_elements_result =
+      test_realm.component().Connect<fuchsia_test_drivers_power::GetPowerElements>(
+          "fuchsia.test.drivers.power.GetPowerElements");
+  ASSERT_TRUE(get_elements_result.is_ok());
+  fidl::WireSyncClient<fuchsia_test_drivers_power::GetPowerElements> elements_client(
+      std::move(get_elements_result.value()));
+
+  std::unordered_set<std::string> expected_elements{"pe-fake-parent", "pe-fake-child"};
+
+  while (expected_elements.size() > 0) {
+    auto resp = elements_client->GetElements();
+    fidl::VectorView<fidl::StringView> added_elements = resp->elements;
+    for (fidl::StringView e : added_elements) {
+      std::string element_name(e.data(), e.size());
+      ASSERT_NE(expected_elements.end(), expected_elements.find(element_name));
+      expected_elements.erase(element_name);
+      FX_LOGS(INFO) << "Found element named '" << element_name << "'";
+    }
+  }
+}
+}  // namespace power_integration_test
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-device.cc b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-device.cc
new file mode 100644
index 0000000..36284cc
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-device.cc
@@ -0,0 +1,161 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-device.h"
+
+#include <fidl/fuchsia.hardware.platform.device/cpp/fidl.h>
+#include <lib/driver/component/cpp/driver_export.h>
+#include <lib/driver/component/cpp/node_add_args.h>
+#include <lib/driver/power/cpp/power-support.h>
+
+#include <bind/fuchsia/cpp/bind.h>
+#include <bind/fuchsia/test/platform/cpp/bind.h>
+
+namespace fake_parent_device {
+
+zx::result<> FakeParent::Start() {
+  node_.Bind(std::move(node()));
+  fdf::Arena arena('TEST');
+
+  auto device_service =
+      incoming()->Connect<fuchsia_hardware_platform_device::Service::Device>("platform-device");
+  if (!device_service.is_ok()) {
+    return zx::error(ZX_ERR_INTERNAL);
+  }
+
+  fidl::WireSyncClient<fuchsia_hardware_platform_device::Device> device_client(
+      std::move(device_service.value()));
+  auto config_result = device_client->GetPowerConfiguration();
+  auto power_config = config_result->value()->config.data();
+
+  // connect to power broker
+  auto power_broker_req = incoming()->Connect<fuchsia_power_broker::Topology>();
+  {
+    if (power_broker_req.is_error()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+
+    fidl::Endpoints<fuchsia_power_broker::RequiredLevel> required_level =
+        fidl::CreateEndpoints<fuchsia_power_broker::RequiredLevel>().value();
+    fidl::Endpoints<fuchsia_power_broker::CurrentLevel> current_level =
+        fidl::CreateEndpoints<fuchsia_power_broker::CurrentLevel>().value();
+    fidl::Endpoints<fuchsia_power_broker::Lessor> lessor =
+        fidl::CreateEndpoints<fuchsia_power_broker::Lessor>().value();
+    zx::event active, passive;
+
+    fidl::ClientEnd<fuchsia_power_broker::Topology> broker = std::move(power_broker_req.value());
+
+    fit::result<fdf_power::Error, fdf_power::TokenMap> token_result =
+        fdf_power::GetDependencyTokens(*incoming(), power_config[0]);
+    if (token_result.is_error()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+
+    fdf_power::TokenMap tokens = std::move(token_result.value());
+    fit::result<fdf_power::Error, fuchsia_power_broker::TopologyAddElementResponse> add_result =
+        fdf_power::AddElement(
+            broker, power_config[0], std::move(tokens), active.borrow(), passive.borrow(),
+            std::pair{std::move(current_level.server), std::move(required_level.server)},
+            std::move(lessor.server));
+
+    topology_client_ =
+        fidl::WireClient<fuchsia_power_broker::Topology>(std::move(broker), dispatcher());
+
+    if (!add_result.is_ok()) {
+      return zx::error(ZX_ERR_INTERNAL);
+    }
+    element_ctrl_ = std::move(add_result->element_control_channel());
+  }
+
+  // Add a child
+  {
+    std::string power_element_name = std::string(power_config[0].element().name().data(),
+                                                 power_config[0].element().name().size());
+
+    // First we'll set up a FIDL server that provides a token which gives
+    // our child access to our power element.
+    server_ = std::make_unique<fake_parent_device::FakeParentServer>(power_element_name);
+    {
+      auto result = outgoing()->AddService<fuchsia_hardware_power::PowerTokenService>(
+          fuchsia_hardware_power::PowerTokenService::InstanceHandler({
+              .token_provider =
+                  bindings_.CreateHandler(server_.get(), dispatcher(), fidl::kIgnoreBindingClosure),
+          }),
+          power_element_name);
+
+      if (!result.is_ok()) {
+        return zx::error(ZX_ERR_INTERNAL);
+      }
+    }
+
+    // Next create a node for our child to bind to.
+    fuchsia_driver_framework::NodeAddArgs node_args;
+    node_args.name() = "fake-child";
+    auto properties = std::vector{
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_VID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_VID_TEST),
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_PID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_PID_POWER_TEST),
+        fdf::MakeProperty(bind_fuchsia::PLATFORM_DEV_DID,
+                          bind_fuchsia_test_platform::BIND_PLATFORM_DEV_DID_FAKE_POWER_CHILD),
+    };
+    node_args.properties() = properties;
+
+    // Create the offer for our token provider so the child can access it.
+    {
+      std::vector<fuchsia_component_decl::NameMapping> mappings =
+          std::vector<fuchsia_component_decl::NameMapping>{fuchsia_component_decl::NameMapping{{
+              .source_name = power_element_name,
+              .target_name = power_element_name,
+          }}};
+
+      fuchsia_component_decl::OfferService services = fuchsia_component_decl::OfferService{{
+          .source_name = std::string(fuchsia_hardware_power::PowerTokenService::Name),
+          .target_name = std::string(fuchsia_hardware_power::PowerTokenService::Name),
+          .source_instance_filter = std::vector<std::string>{power_element_name},
+          .renamed_instances = mappings,
+      }};
+
+      auto component_offer_decl = fuchsia_component_decl::Offer::WithService(services);
+      node_args.offers2() = std::vector<fuchsia_driver_framework::Offer>{
+          fuchsia_driver_framework::Offer::WithZirconTransport(component_offer_decl),
+      };
+    }
+
+    // The token service is ready, the child is defined, so we're ready to
+    // add the child device node
+    {
+      auto endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>().value();
+      auto result = node_->AddChild(fidl::ToWire(arena, std::move(node_args)),
+                                    std::move(endpoints.server), {});
+
+      if (!result.ok()) {
+        return zx::error(ZX_ERR_INTERNAL);
+      }
+
+      if (result->is_error()) {
+        return zx::error(ZX_ERR_INTERNAL);
+      }
+
+      child_controller_.Bind(std::move(endpoints.client));
+    }
+  }
+
+  return zx::ok();
+}
+
+void FakeParentServer::GetToken(GetTokenCompleter::Sync& completer) {
+  zx_handle_t mine;
+  zx_event_create(0, &mine);
+  zx_handle_t yours;
+  zx_handle_duplicate(mine, ZX_RIGHT_SAME_RIGHTS, &yours);
+  completer.ReplySuccess(zx::event(yours), fidl::StringView::FromExternal(element_name_));
+}
+void FakeParentServer::handle_unknown_method(
+    fidl::UnknownMethodMetadata<fuchsia_hardware_power::PowerTokenProvider> md,
+    fidl::UnknownMethodCompleter::Sync& completer) {}
+
+}  // namespace fake_parent_device
+
+FUCHSIA_DRIVER_EXPORT(fake_parent_device::FakeParent);
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-device.h b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-device.h
new file mode 100644
index 0000000..d9148d5
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-device.h
@@ -0,0 +1,46 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_FAKE_PARENT_DEVICE_H_
+#define SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_FAKE_PARENT_DEVICE_H_
+
+#include <fidl/fuchsia.hardware.power/cpp/fidl.h>
+#include <fidl/fuchsia.power.broker/cpp/fidl.h>
+#include <lib/driver/component/cpp/driver_base.h>
+
+namespace fake_parent_device {
+
+class FakeParentServer : public fidl::WireServer<fuchsia_hardware_power::PowerTokenProvider> {
+ public:
+  explicit FakeParentServer(std::string element_name) : element_name_(std::move(element_name)) {}
+  void GetToken(GetTokenCompleter::Sync& completer) override;
+  void handle_unknown_method(
+      fidl::UnknownMethodMetadata<fuchsia_hardware_power::PowerTokenProvider> md,
+      fidl::UnknownMethodCompleter::Sync& completer) override;
+
+ private:
+  std::string element_name_;
+};
+
+class FakeParent : public fdf::DriverBase {
+ public:
+  FakeParent(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher dispatcher)
+      : fdf::DriverBase("fake-parent", std::move(start_args), std::move(dispatcher)) {}
+
+  zx::result<> Start() override;
+
+ private:
+  fidl::ServerBindingGroup<fuchsia_hardware_power::PowerTokenProvider> bindings_;
+  fidl::WireSyncClient<fuchsia_driver_framework::Node> node_;
+  fidl::WireSyncClient<fuchsia_driver_framework::NodeController> controller_;
+  fidl::WireSyncClient<fuchsia_driver_framework::NodeController> child_controller_;
+  std::unique_ptr<FakeParentServer> server_;
+  std::unique_ptr<FakeParentServer> server2_;
+  fidl::WireClient<fuchsia_power_broker::Topology> topology_client_;
+  fidl::ClientEnd<fuchsia_power_broker::ElementControl> element_ctrl_;
+};
+
+}  // namespace fake_parent_device
+
+#endif /* SRC_DEVICES_BUS_DRIVERS_PLATFORM_TEST_FAKE_PARENT_DEVICE_H_ */
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-info.json b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-info.json
new file mode 100644
index 0000000..ea29a89
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent-info.json
@@ -0,0 +1,11 @@
+{
+    "short_description": "Fake Power Parent Driver",
+    "manufacturer": "",
+    "families": [],
+    "models": [],
+    "areas": [
+        "Platform",
+        "Power",
+        "Test"
+    ]
+}
diff --git a/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent.bind b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent.bind
new file mode 100644
index 0000000..caebe46
--- /dev/null
+++ b/src/devices/bus/drivers/platform/test/power-integration-test/test-power-parent.bind
@@ -0,0 +1,19 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+composite fake_power_parent;
+
+using fuchsia.test.platform;
+
+primary node "power" {
+  fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.test.platform.BIND_PLATFORM_DEV_VID.TEST;
+  fuchsia.BIND_PLATFORM_DEV_PID == fuchsia.test.platform.BIND_PLATFORM_DEV_PID.POWER_TEST;
+  fuchsia.BIND_PLATFORM_DEV_DID == fuchsia.test.platform.BIND_PLATFORM_DEV_DID.FAKE_POWER_PARENT;
+}
+
+node "platform-device" {
+  fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.test.platform.BIND_PLATFORM_DEV_VID.TEST;
+  fuchsia.BIND_PLATFORM_DEV_PID == fuchsia.test.platform.BIND_PLATFORM_DEV_PID.POWER_TEST;
+  fuchsia.BIND_PLATFORM_DEV_DID == fuchsia.test.platform.BIND_PLATFORM_DEV_DID.FAKE_POWER_PLATFORM_DEVICE_PARENT;
+}
diff --git a/src/devices/bus/drivers/platform/test/test/child-1.c b/src/devices/bus/drivers/platform/test/test/child-1.c
index 1502c54..07cecd2 100644
--- a/src/devices/bus/drivers/platform/test/test/child-1.c
+++ b/src/devices/bus/drivers/platform/test/test/child-1.c
@@ -11,6 +11,8 @@
 
 #define DRIVER_NAME "test-child-1"
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 typedef struct {
   zx_device_t* zxdev;
 } test_t;
@@ -44,7 +46,7 @@
       .ctx = child_2,
       .ops = &test_device_protocol,
       .props = child_2_props,
-      .prop_count = countof(child_2_props),
+      .prop_count = ARRAY_SIZE(child_2_props),
   };
 
   status = device_add(parent, &child_2_args, &child_2->zxdev);
@@ -71,7 +73,7 @@
       .ctx = child_3,
       .ops = &test_device_protocol,
       .props = child_3_props,
-      .prop_count = countof(child_3_props),
+      .prop_count = ARRAY_SIZE(child_3_props),
   };
 
   status = device_add(parent, &child_3_args, &child_3->zxdev);
diff --git a/src/devices/bus/drivers/platform/test/test/child-2.c b/src/devices/bus/drivers/platform/test/test/child-2.c
index 42e051a..22f7a05 100644
--- a/src/devices/bus/drivers/platform/test/test/child-2.c
+++ b/src/devices/bus/drivers/platform/test/test/child-2.c
@@ -11,6 +11,8 @@
 
 #define DRIVER_NAME "test-child-2"
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 typedef struct {
   zx_device_t* zxdev;
 } test_t;
@@ -54,7 +56,7 @@
       .ctx = test,
       .ops = &test_device_protocol,
       .props = child_props,
-      .prop_count = countof(child_props),
+      .prop_count = ARRAY_SIZE(child_props),
       .flags = DEVICE_ADD_MUST_ISOLATE | DEVICE_ADD_ALLOW_MULTI_COMPOSITE,
   };
 
diff --git a/src/devices/bus/drivers/platform/test/test/parent.c b/src/devices/bus/drivers/platform/test/test/parent.c
index 412e108..ced91b4 100644
--- a/src/devices/bus/drivers/platform/test/test/parent.c
+++ b/src/devices/bus/drivers/platform/test/test/parent.c
@@ -12,6 +12,8 @@
 
 #define DRIVER_NAME "test-parent"
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 typedef struct {
   zx_device_t* zxdev;
 } test_t;
@@ -52,7 +54,7 @@
       .ctx = test,
       .ops = &test_device_protocol,
       .props = child_props,
-      .prop_count = countof(child_props),
+      .prop_count = ARRAY_SIZE(child_props),
   };
 
   status = device_add(parent, &child_args, &test->zxdev);
@@ -74,7 +76,7 @@
       .ctx = test,
       .ops = &test_device_protocol,
       .props = node_props,
-      .prop_count = countof(node_props),
+      .prop_count = ARRAY_SIZE(node_props),
   };
 
   status = device_add(parent, &node_args, &test->zxdev);
diff --git a/src/devices/bus/lib/virtio/backend_tests.cc b/src/devices/bus/lib/virtio/backend_tests.cc
index 33042d5..a50e605 100644
--- a/src/devices/bus/lib/virtio/backend_tests.cc
+++ b/src/devices/bus/lib/virtio/backend_tests.cc
@@ -144,8 +144,7 @@
   AsyncState() : outgoing_(async_get_default_dispatcher()) {}
 
   fidl::ClientEnd<fuchsia_io::Directory> SetUpProtocol() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
     zx::result service_result = outgoing_.AddService<fuchsia_hardware_pci::Service>(
         fuchsia_hardware_pci::Service::InstanceHandler(
@@ -153,8 +152,8 @@
                                                fidl::kIgnoreBindingClosure)}));
     ZX_ASSERT(service_result.is_ok());
 
-    ZX_ASSERT(outgoing_.Serve(std::move(endpoints->server)).is_ok());
-    return std::move(endpoints->client);
+    ZX_ASSERT(outgoing_.Serve(std::move(endpoints.server)).is_ok());
+    return std::move(endpoints.client);
   }
 
   pci::FakePciProtocol fake_pci;
diff --git a/src/devices/clock/drivers/clock/clock-test.cc b/src/devices/clock/drivers/clock/clock-test.cc
index d5adcdb..d94e18a 100644
--- a/src/devices/clock/drivers/clock/clock-test.cc
+++ b/src/devices/clock/drivers/clock/clock-test.cc
@@ -310,14 +310,13 @@
                        fdf::WireSyncClient(std::move(clockimpl_endpoints->client)));
   ClockDevice dut(nullptr, std::move(proxy), kTestClockId);
 
-  zx::result clock_endpoints = fidl::CreateEndpoints<fuchsia_hardware_clock::Clock>();
-  ASSERT_TRUE(clock_endpoints.is_ok());
+  auto clock_endpoints = fidl::Endpoints<fuchsia_hardware_clock::Clock>::Create();
 
   fidl::BindServer(fdf::Dispatcher::GetCurrent()->async_dispatcher(),
-                   std::move(clock_endpoints->server), &dut);
+                   std::move(clock_endpoints.server), &dut);
 
   fidl::WireClient<fuchsia_hardware_clock::Clock> clock_client(
-      std::move(clock_endpoints->client), fdf::Dispatcher::GetCurrent()->async_dispatcher());
+      std::move(clock_endpoints.client), fdf::Dispatcher::GetCurrent()->async_dispatcher());
 
   clock_client->SetRate(1'000'000).ThenExactlyOnce(
       [&](fidl::WireUnownedResult<fuchsia_hardware_clock::Clock::SetRate>& result) {
@@ -358,15 +357,14 @@
   async_patterns::TestDispatcherBound<ClockDevice> dut(background_dispatcher, std::in_place,
                                                        nullptr, std::move(proxy), kTestClockId);
 
-  zx::result clock_endpoints = fidl::CreateEndpoints<fuchsia_hardware_clock::Clock>();
-  ASSERT_TRUE(clock_endpoints.is_ok());
+  auto clock_endpoints = fidl::Endpoints<fuchsia_hardware_clock::Clock>::Create();
 
   dut.SyncCall([&](ClockDevice* device) {
-    fidl::BindServer(background_dispatcher, std::move(clock_endpoints->server), device);
+    fidl::BindServer(background_dispatcher, std::move(clock_endpoints.server), device);
   });
 
   fidl::WireClient<fuchsia_hardware_clock::Clock> clock_client(
-      std::move(clock_endpoints->client), fdf::Dispatcher::GetCurrent()->async_dispatcher());
+      std::move(clock_endpoints.client), fdf::Dispatcher::GetCurrent()->async_dispatcher());
 
   // Call SetRate on the foreground dispatcher and run until the ClockDevice responds.
   clock_client->SetRate(1'000'000).ThenExactlyOnce(
diff --git a/src/devices/cpu/bin/cpuctl/cpuctl-test.cc b/src/devices/cpu/bin/cpuctl/cpuctl-test.cc
index 939d1732..561cf3d 100644
--- a/src/devices/cpu/bin/cpuctl/cpuctl-test.cc
+++ b/src/devices/cpu/bin/cpuctl/cpuctl-test.cc
@@ -111,12 +111,11 @@
 };
 
 void PerformanceDomainTest::SetUp() {
-  zx::result cpu_endpoints = fidl::CreateEndpoints<fuchsia_hardware_cpu_ctrl::Device>();
-  ASSERT_OK(cpu_endpoints);
-  fidl::BindServer(loop_.dispatcher(), std::move(cpu_endpoints->server),
+  auto cpu_endpoints = fidl::Endpoints<fuchsia_hardware_cpu_ctrl::Device>::Create();
+  fidl::BindServer(loop_.dispatcher(), std::move(cpu_endpoints.server),
                    static_cast<fidl::WireServer<cpuctrl::Device>*>(&cpu_));
 
-  pd_.emplace(std::move(cpu_endpoints->client));
+  pd_.emplace(std::move(cpu_endpoints.client));
   ASSERT_OK(loop_.StartThread("performance-domain-test-fidl-thread"));
 }
 
diff --git a/src/devices/cpu/drivers/aml-cpu-legacy/aml-cpu-test.cc b/src/devices/cpu/drivers/aml-cpu-legacy/aml-cpu-test.cc
index d85b313..7cf0e644 100644
--- a/src/devices/cpu/drivers/aml-cpu-legacy/aml-cpu-test.cc
+++ b/src/devices/cpu/drivers/aml-cpu-legacy/aml-cpu-test.cc
@@ -275,9 +275,8 @@
 
     fake_pdev::FakePDevFidl::Config config;
     config.mmios[0] = mmio_.mmio();
-    zx::result outgoing_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(outgoing_endpoints);
-    incoming_.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints->server)](
+    auto outgoing_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    incoming_.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints.server)](
                            IncomingNamespace* infra) mutable {
       infra->pdev_server.SetConfig(std::move(config));
       ASSERT_OK(infra->outgoing.AddService<fuchsia_hardware_platform_device::Service>(
@@ -286,7 +285,7 @@
     });
     ASSERT_NO_FATAL_FAILURE();
     root_->AddFidlService(fuchsia_hardware_platform_device::Service::Name,
-                          std::move(outgoing_endpoints->client), "pdev");
+                          std::move(outgoing_endpoints.client), "pdev");
 
     root_->AddProtocol(ZX_PROTOCOL_THERMAL, thermal_device_.proto()->ops,
                        thermal_device_.proto()->ctx, "thermal");
@@ -369,20 +368,18 @@
 };
 
 void AmlCpuTestFixture::SetUp() {
-  auto thermal_eps = fidl::CreateEndpoints<fuchsia_thermal::Device>();
-  ASSERT_OK(thermal_eps.status_value());
+  auto thermal_eps = fidl::Endpoints<fuchsia_thermal::Device>::Create();
 
-  ASSERT_OK(thermal_.Init(std::move(thermal_eps->server)));
-  ThermalSyncClient thermal_client = fidl::WireSyncClient(std::move(thermal_eps->client));
+  ASSERT_OK(thermal_.Init(std::move(thermal_eps.server)));
+  ThermalSyncClient thermal_client = fidl::WireSyncClient(std::move(thermal_eps.client));
 
   dut_ = std::make_unique<AmlCpuTest>(std::move(thermal_client));
 
-  auto cpu_eps = fidl::CreateEndpoints<fuchsia_cpuctrl::Device>();
-  ASSERT_OK(cpu_eps.status_value());
-  fidl::BindServer(loop_.dispatcher(), std::move(cpu_eps->server), dut_.get());
+  auto cpu_eps = fidl::Endpoints<fuchsia_cpuctrl::Device>::Create();
+  fidl::BindServer(loop_.dispatcher(), std::move(cpu_eps.server), dut_.get());
   loop_.StartThread("aml-cpu-legacy-test-thread");
 
-  cpu_client_ = CpuCtrlSyncClient(std::move(cpu_eps->client));
+  cpu_client_ = CpuCtrlSyncClient(std::move(cpu_eps.client));
 }
 
 TEST_F(AmlCpuTestFixture, TestGetOperatingPointInfo) {
diff --git a/src/devices/cpu/drivers/aml-cpu/aml-cpu-driver.cc b/src/devices/cpu/drivers/aml-cpu/aml-cpu-driver.cc
index 56bf126..bcf6356 100644
--- a/src/devices/cpu/drivers/aml-cpu/aml-cpu-driver.cc
+++ b/src/devices/cpu/drivers/aml-cpu/aml-cpu-driver.cc
@@ -65,6 +65,16 @@
       FDF_LOG(ERROR, "Failed to add child for performance domain: %s", st.status_string());
       return st.take_error();
     }
+    fuchsia_hardware_cpu_ctrl::Service::InstanceHandler handler({
+        .device = fit::bind_member<&AmlCpuPerformanceDomain::CpuCtrlConnector>(&**device),
+    });
+
+    auto result = outgoing()->AddService<fuchsia_hardware_cpu_ctrl::Service>(std::move(handler),
+                                                                             device->GetName());
+    if (result.is_error()) {
+      FDF_LOG(ERROR, "Failed to add service: %s", result.status_string());
+      return result.take_error();
+    }
 
     performance_domains_.push_back(std::move(device.value()));
   }
diff --git a/src/devices/cpu/drivers/aml-cpu/aml-cpu-driver.h b/src/devices/cpu/drivers/aml-cpu/aml-cpu-driver.h
index 5b4e17c..0f28dbb 100644
--- a/src/devices/cpu/drivers/aml-cpu/aml-cpu-driver.h
+++ b/src/devices/cpu/drivers/aml-cpu/aml-cpu-driver.h
@@ -26,9 +26,9 @@
 
   zx::vmo inspect_vmo() { return inspector_.DuplicateVmo(); }
 
- private:
   void CpuCtrlConnector(fidl::ServerEnd<fuchsia_hardware_cpu_ctrl::Device> server);
 
+ private:
   async_dispatcher_t* dispatcher_;
   fidl::ServerBindingGroup<fuchsia_hardware_cpu_ctrl::Device> bindings_;
   driver_devfs::Connector<fuchsia_hardware_cpu_ctrl::Device> devfs_connector_;
diff --git a/src/devices/cpu/drivers/aml-cpu/aml-cpu-test.cc b/src/devices/cpu/drivers/aml-cpu/aml-cpu-test.cc
index be32f02..0c69725 100644
--- a/src/devices/cpu/drivers/aml-cpu/aml-cpu-test.cc
+++ b/src/devices/cpu/drivers/aml-cpu/aml-cpu-test.cc
@@ -105,11 +105,10 @@
   }
 
   fidl::ClientEnd<fuchsia_hardware_clock::Clock> Connect() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_clock::Clock>();
-    EXPECT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_clock::Clock>::Create();
     binding_group_.AddBinding(fdf::Dispatcher::GetCurrent()->async_dispatcher(),
-                              std::move(endpoints->server), this, fidl::kIgnoreBindingClosure);
-    return std::move(endpoints->client);
+                              std::move(endpoints.server), this, fidl::kIgnoreBindingClosure);
+    return std::move(endpoints.client);
   }
 
   bool enabled() const { return enabled_; }
@@ -136,10 +135,9 @@
   }
 
   fidl::ClientEnd<fuchsia_hardware_power::Device> Connect() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_power::Device>();
-    EXPECT_OK(endpoints.status_value());
-    ConnectRequest(std::move(endpoints->server));
-    return std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_power::Device>::Create();
+    ConnectRequest(std::move(endpoints.server));
+    return std::move(endpoints.client);
   }
 
   void RegisterPowerDomain(RegisterPowerDomainRequestView request,
diff --git a/src/devices/cpu/drivers/aml-cpu/meta/aml-cpu.cml b/src/devices/cpu/drivers/aml-cpu/meta/aml-cpu.cml
index aa7c87d..dd768d1 100644
--- a/src/devices/cpu/drivers/aml-cpu/meta/aml-cpu.cml
+++ b/src/devices/cpu/drivers/aml-cpu/meta/aml-cpu.cml
@@ -15,9 +15,18 @@
         default_dispatcher_opts: [ "allow_sync_calls" ],
         fallback: "false",
     },
+    capabilities: [
+        { service: "fuchsia.hardware.cpu.ctrl.Service" },
+    ],
     use: [
         { service: "fuchsia.hardware.platform.device.Service" },
         { service: "fuchsia.hardware.power.Service" },
         { service: "fuchsia.hardware.clock.Service" },
     ],
+    expose: [
+        {
+            service: "fuchsia.hardware.cpu.ctrl.Service",
+            from: "self",
+        },
+    ],
 }
diff --git a/src/devices/gpio/drivers/aml-gpio/BUILD.bazel b/src/devices/gpio/drivers/aml-gpio/BUILD.bazel
index be45fd0..8cff25a 100644
--- a/src/devices/gpio/drivers/aml-gpio/BUILD.bazel
+++ b/src/devices/gpio/drivers/aml-gpio/BUILD.bazel
@@ -42,9 +42,10 @@
     output_name = "aml-gpio",
     deps = [
         "//src/devices/lib/amlogic",
+        "//src/lib/ddk:ddk_metadata",
+        "//zircon/system/ulib/ddk-platform-defs",
         "@fuchsia_sdk//fidl/fuchsia.hardware.platform.device:fuchsia.hardware.platform.device_cpp",
         "@fuchsia_sdk//pkg/async",
-        "@fuchsia_sdk//pkg/ddk",
         "@fuchsia_sdk//pkg/driver_component_cpp",
         "@fuchsia_sdk//pkg/driver_runtime_cpp",
         "@fuchsia_sdk//pkg/fit-promise",
@@ -53,7 +54,6 @@
         "@internal_sdk//fidl/fuchsia.hardware.gpioimpl:fuchsia.hardware.gpioimpl_bindlib_cc",
         "@internal_sdk//fidl/fuchsia.hardware.gpioimpl:fuchsia.hardware.gpioimpl_cpp",
         "@internal_sdk//fidl/fuchsia.logger:fuchsia.logger_cpp",
-        "@internal_sdk//pkg/ddk-platform-defs",
         "@internal_sdk//pkg/driver_compat",
     ],
 )
@@ -98,11 +98,12 @@
     ],
     deps = [
         "//src/devices/lib/amlogic",
+        "//src/lib/ddk:ddk_metadata",
+        "//zircon/system/ulib/ddk-platform-defs",
         "@com_google_googletest//:gtest",
         "@com_google_googletest//:gtest_main",
         "@fuchsia_sdk//fidl/fuchsia.hardware.platform.device:fuchsia.hardware.platform.device_cpp",
         "@fuchsia_sdk//pkg/async",
-        "@fuchsia_sdk//pkg/ddk",
         "@fuchsia_sdk//pkg/driver_component_cpp",
         "@fuchsia_sdk//pkg/driver_runtime_cpp",
         "@fuchsia_sdk//pkg/driver_testing_cpp",
@@ -112,7 +113,6 @@
         "@internal_sdk//fidl/fuchsia.hardware.gpioimpl:fuchsia.hardware.gpioimpl_bindlib_cc",
         "@internal_sdk//fidl/fuchsia.hardware.gpioimpl:fuchsia.hardware.gpioimpl_cpp",
         "@internal_sdk//fidl/fuchsia.logger:fuchsia.logger_cpp",
-        "@internal_sdk//pkg/ddk-platform-defs",
         "@internal_sdk//pkg/driver_compat",
         "@internal_sdk//pkg/fzl",
         "@internal_sdk//pkg/mock-mmio-reg",
diff --git a/src/devices/gpio/drivers/aml-gpio/aml-gpio-test.cc b/src/devices/gpio/drivers/aml-gpio/aml-gpio-test.cc
index 8fdd96e..12ef1a0 100644
--- a/src/devices/gpio/drivers/aml-gpio/aml-gpio-test.cc
+++ b/src/devices/gpio/drivers/aml-gpio/aml-gpio-test.cc
@@ -197,17 +197,16 @@
     ASSERT_NE(node_server_.children().find("aml-gpio"), node_server_.children().cend());
 
     // Connect to the driver through its outgoing directory and get a gpioimpl client.
-    zx::result svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_TRUE(svc_endpoints.is_ok());
+    auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
     EXPECT_EQ(fdio_open_at(driver_outgoing_.handle()->get(), "/svc",
                            static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
-                           svc_endpoints->server.TakeChannel().release()),
+                           svc_endpoints.server.TakeChannel().release()),
               ZX_OK);
 
     zx::result gpioimpl_client_end =
         fdf::internal::DriverTransportConnect<fuchsia_hardware_gpioimpl::Service::Device>(
-            svc_endpoints->client, component::kDefaultInstance);
+            svc_endpoints.client, component::kDefaultInstance);
     ASSERT_TRUE(gpioimpl_client_end.is_ok());
 
     client_.Bind(*std::move(gpioimpl_client_end), fdf::Dispatcher::GetCurrent()->get());
diff --git a/src/devices/gpio/drivers/ti-tca6408a/ti-tca6408a-test.cc b/src/devices/gpio/drivers/ti-tca6408a/ti-tca6408a-test.cc
index de9d0aa..5b65815 100644
--- a/src/devices/gpio/drivers/ti-tca6408a/ti-tca6408a-test.cc
+++ b/src/devices/gpio/drivers/ti-tca6408a/ti-tca6408a-test.cc
@@ -129,17 +129,16 @@
     ASSERT_TRUE(result.is_ok());
 
     // Connect to GpioImpl.
-    auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_EQ(ZX_OK, svc_endpoints.status_value());
+    auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
     zx_status_t status = fdio_open_at(outgoing_directory_client.handle()->get(), "/svc",
                                       static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
-                                      svc_endpoints->server.TakeChannel().release());
+                                      svc_endpoints.server.TakeChannel().release());
     EXPECT_EQ(ZX_OK, status);
 
     auto connect_result =
         fdf::internal::DriverTransportConnect<fuchsia_hardware_gpioimpl::Service::Device>(
-            svc_endpoints->client, component::kDefaultInstance);
+            svc_endpoints.client, component::kDefaultInstance);
     ASSERT_TRUE(connect_result.is_ok());
     gpio_.Bind(std::move(connect_result.value()));
     ASSERT_TRUE(gpio_.is_valid());
diff --git a/src/devices/gpio/drivers/ti-tca6408a/ti-tca6408a.cc b/src/devices/gpio/drivers/ti-tca6408a/ti-tca6408a.cc
index efca04a..69a9274 100644
--- a/src/devices/gpio/drivers/ti-tca6408a/ti-tca6408a.cc
+++ b/src/devices/gpio/drivers/ti-tca6408a/ti-tca6408a.cc
@@ -81,18 +81,15 @@
                   .offers2(arena, std::move(offers))
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   fidl::WireResult result =
-      fidl::WireCall(node())->AddChild(args, std::move(controller_endpoints->server), {});
+      fidl::WireCall(node())->AddChild(args, std::move(controller_endpoints.server), {});
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
 
   return zx::ok();
 }
diff --git a/src/devices/gpio/testing/fake-gpio/fake-gpio.cc b/src/devices/gpio/testing/fake-gpio/fake-gpio.cc
index a0f33cf..e3222cbe 100644
--- a/src/devices/gpio/testing/fake-gpio/fake-gpio.cc
+++ b/src/devices/gpio/testing/fake-gpio/fake-gpio.cc
@@ -179,11 +179,10 @@
 std::vector<State> FakeGpio::GetStateLog() { return state_log_; }
 
 fidl::ClientEnd<fuchsia_hardware_gpio::Gpio> FakeGpio::Connect() {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_gpio::Gpio>();
-  ZX_ASSERT(endpoints.is_ok());
-  bindings_.AddBinding(GetDefaultDispatcher(), std::move(endpoints->server), this,
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_gpio::Gpio>::Create();
+  bindings_.AddBinding(GetDefaultDispatcher(), std::move(endpoints.server), this,
                        fidl::kIgnoreBindingClosure);
-  return std::move(endpoints->client);
+  return std::move(endpoints.client);
 }
 
 fuchsia_hardware_gpio::Service::InstanceHandler FakeGpio::CreateInstanceHandler() {
diff --git a/src/devices/hrtimer/drivers/aml-hrtimer/aml-hrtimer.cc b/src/devices/hrtimer/drivers/aml-hrtimer/aml-hrtimer.cc
index dcbb184..217f7908 100644
--- a/src/devices/hrtimer/drivers/aml-hrtimer/aml-hrtimer.cc
+++ b/src/devices/hrtimer/drivers/aml-hrtimer/aml-hrtimer.cc
@@ -167,22 +167,19 @@
                   .devfs_args(devfs.Build())
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create node controller endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
   ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create node endpoints: %s",
                 node_endpoints.status_string());
 
   fidl::WireResult result = fidl::WireCall(node())->AddChild(
-      args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+      args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
   node_.Bind(std::move(node_endpoints->client));
   return zx::ok();
 }
diff --git a/src/devices/hrtimer/drivers/aml-hrtimer/unit-tests.cc b/src/devices/hrtimer/drivers/aml-hrtimer/unit-tests.cc
index 4c0d55a..a2c5ee7 100644
--- a/src/devices/hrtimer/drivers/aml-hrtimer/unit-tests.cc
+++ b/src/devices/hrtimer/drivers/aml-hrtimer/unit-tests.cc
@@ -323,7 +323,7 @@
  public:
   static constexpr bool kDriverOnForeground = false;
   static constexpr bool kAutoStartDriver = true;
-  static constexpr bool kAutoStopDriver = false;
+  static constexpr bool kAutoStopDriver = true;
 
   using DriverType = AmlHrtimer;
   using EnvironmentType = TestEnvironment;
@@ -633,7 +633,41 @@
   }
 }
 
-TEST_F(DriverTest, CancelOnDriverStop) {
+class FixtureConfigNoAutoStop final {
+ public:
+  static constexpr bool kDriverOnForeground = false;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = false;
+
+  using DriverType = AmlHrtimer;
+  using EnvironmentType = TestEnvironment;
+};
+
+class DriverTestNoAutoStop : public fdf_testing::DriverTestFixture<FixtureConfigNoAutoStop> {
+ protected:
+  void SetUp() override {
+    zx::result device_result = ConnectThroughDevfs<fuchsia_hardware_hrtimer::Device>("aml-hrtimer");
+    ASSERT_EQ(ZX_OK, device_result.status_value());
+    client_.Bind(std::move(device_result.value()));
+  }
+
+  void CheckLeaseRequested(size_t timer_id) {
+    RunInEnvironmentTypeContext([](TestEnvironment& env) {
+      ASSERT_FALSE(env.power_broker().GetLeaseRequested());
+      env.platform_device().TriggerAllIrqs();
+    });
+    auto result_start = client_->StartAndWait(
+        {timer_id, fuchsia_hardware_hrtimer::Resolution::WithDuration(1'000ULL), 0});
+    ASSERT_FALSE(result_start.is_error());
+    ASSERT_TRUE(result_start->keep_alive().is_valid());
+    RunInEnvironmentTypeContext(
+        [](TestEnvironment& env) { ASSERT_TRUE(env.power_broker().GetLeaseRequested()); });
+  }
+
+  fidl::SyncClient<fuchsia_hardware_hrtimer::Device> client_;
+};
+
+TEST_F(DriverTestNoAutoStop, CancelOnDriverStop) {
   std::vector<std::thread> threads;
   zx::event events[9];
   // Timers id 0 to 8 inclusive but not 4 support events and wait (via IRQ notification).
@@ -721,7 +755,7 @@
  public:
   static constexpr bool kDriverOnForeground = false;
   static constexpr bool kAutoStartDriver = true;
-  static constexpr bool kAutoStopDriver = false;
+  static constexpr bool kAutoStopDriver = true;
 
   using DriverType = AmlHrtimer;
   using EnvironmentType = TestEnvironmentNoPower;
diff --git a/src/devices/i2c/drivers/aml-i2c/BUILD.bazel b/src/devices/i2c/drivers/aml-i2c/BUILD.bazel
index ce1d545..37ff18e 100644
--- a/src/devices/i2c/drivers/aml-i2c/BUILD.bazel
+++ b/src/devices/i2c/drivers/aml-i2c/BUILD.bazel
@@ -40,8 +40,8 @@
     output_name = "aml-i2c",
     deps = [
         "//src/devices/lib/amlogic",
+        "//src/lib/ddk:ddk_metadata",
         "@fuchsia_sdk//fidl/fuchsia.hardware.platform.device:fuchsia.hardware.platform.device_cpp",
-        "@fuchsia_sdk//pkg/ddk",
         "@fuchsia_sdk//pkg/driver_component_cpp",
         "@fuchsia_sdk//pkg/driver_runtime",
         "@fuchsia_sdk//pkg/hwreg",
@@ -92,10 +92,10 @@
     ],
     deps = [
         "//src/devices/lib/amlogic",
+        "//src/lib/ddk:ddk_metadata",
         "@com_google_googletest//:gtest_main",
         "@fuchsia_sdk//pkg/async-loop-default",
         "@fuchsia_sdk//pkg/async_patterns_testing_cpp",
-        "@fuchsia_sdk//pkg/ddk",
         "@fuchsia_sdk//pkg/driver_component_cpp",
         "@fuchsia_sdk//pkg/driver_runtime",
         "@fuchsia_sdk//pkg/driver_testing_cpp",
diff --git a/src/devices/i2c/drivers/aml-i2c/aml-i2c-test.cc b/src/devices/i2c/drivers/aml-i2c/aml-i2c-test.cc
index 094df57..7f72679 100644
--- a/src/devices/i2c/drivers/aml-i2c/aml-i2c-test.cc
+++ b/src/devices/i2c/drivers/aml-i2c/aml-i2c-test.cc
@@ -306,17 +306,16 @@
   static constexpr size_t kMmioSize = sizeof(uint32_t) * 8;
 
   void ConnectToI2cImpl(fidl::ClientEnd<fuchsia_io::Directory>& outgoing_directory_client) {
-    auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(ZX_OK, svc_endpoints.status_value());
+    auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
     zx_status_t status = fdio_open_at(outgoing_directory_client.handle()->get(), "/svc",
                                       static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
-                                      svc_endpoints->server.TakeChannel().release());
+                                      svc_endpoints.server.TakeChannel().release());
     ASSERT_EQ(ZX_OK, status);
 
     auto connect_result =
         fdf::internal::DriverTransportConnect<fuchsia_hardware_i2cimpl::Service::Device>(
-            svc_endpoints->client, component::kDefaultInstance);
+            svc_endpoints.client, component::kDefaultInstance);
     ASSERT_TRUE(connect_result.is_ok());
     i2c_.Bind(std::move(connect_result.value()), fdf::Dispatcher::GetCurrent()->get());
     ASSERT_TRUE(i2c_.is_valid());
diff --git a/src/devices/i2c/drivers/i2c/i2c-child-test.cc b/src/devices/i2c/drivers/i2c/i2c-child-test.cc
index 1d93f95..dc47ec1 100644
--- a/src/devices/i2c/drivers/i2c/i2c-child-test.cc
+++ b/src/devices/i2c/drivers/i2c/i2c-child-test.cc
@@ -75,24 +75,22 @@
   void GetI2cChildClient(const char* name,
                          fidl::WireSyncClient<fuchsia_hardware_i2c::Device>* client,
                          const uint32_t bus_id) {
-    auto io_eps = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(io_eps);
-    namespace_.SyncCall(&FakeIncomingNamespace::AddI2cImplService, std::move(io_eps->server));
-    fake_root_->AddFidlService(fi2cimpl::Service::Name, std::move(io_eps->client));
+    auto io_eps = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    namespace_.SyncCall(&FakeIncomingNamespace::AddI2cImplService, std::move(io_eps.server));
+    fake_root_->AddFidlService(fi2cimpl::Service::Name, std::move(io_eps.client));
 
     SetMetadata(name, bus_id);
 
-    auto i2c_eps = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    ASSERT_OK(i2c_eps.status_value());
+    auto i2c_eps = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
 
-    *client = fidl::WireSyncClient<fuchsia_hardware_i2c::Device>(std::move(i2c_eps->client));
+    *client = fidl::WireSyncClient<fuchsia_hardware_i2c::Device>(std::move(i2c_eps.client));
 
     EXPECT_OK(I2cDevice::Create(nullptr, fake_root_.get()));
     ASSERT_EQ(fake_root_->child_count(), 1);
 
     zx_device_t* i2c_root = fake_root_->GetLatestChild();
     auto* const i2c_child = i2c_root->GetLatestChild()->GetDeviceContext<I2cChild>();
-    i2c_child->Bind(std::move(i2c_eps->server));
+    i2c_child->Bind(std::move(i2c_eps.server));
   }
 
   async_dispatcher_t* dispatcher() { return dispatcher_->async_dispatcher(); }
diff --git a/src/devices/i2c/drivers/i2c/i2c-test.cc b/src/devices/i2c/drivers/i2c/i2c-test.cc
index e92862a..84a5daa 100644
--- a/src/devices/i2c/drivers/i2c/i2c-test.cc
+++ b/src/devices/i2c/drivers/i2c/i2c-test.cc
@@ -42,12 +42,10 @@
  protected:
   void CreateDevice(fi2c::I2CBusMetadata& metadata) {
     // Setup i2c impl parent
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
-    incoming_.SyncCall(&i2c::FakeIncomingNamespace::AddI2cImplService,
-                       std::move(endpoints->server));
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    incoming_.SyncCall(&i2c::FakeIncomingNamespace::AddI2cImplService, std::move(endpoints.server));
     fake_root_->AddFidlService(fuchsia_hardware_i2cimpl::Service::Name,
-                               std::move(endpoints->client));
+                               std::move(endpoints.client));
 
     // Setup metadata
     fit::result metadata_bytes = fidl::Persist(metadata);
diff --git a/src/devices/i2c/lib/device-protocol-i2c-channel/test.cc b/src/devices/i2c/lib/device-protocol-i2c-channel/test.cc
index 83626cc..e510cd0 100644
--- a/src/devices/i2c/lib/device-protocol-i2c-channel/test.cc
+++ b/src/devices/i2c/lib/device-protocol-i2c-channel/test.cc
@@ -27,7 +27,7 @@
     count_++;
     // Unique errors below to check for retries.
     switch (count_) {
-      // clang-format off
+        // clang-format off
       case 1: return ZX_ERR_INTERNAL; break;
       case 2: return ZX_ERR_NOT_SUPPORTED; break;
       case 3: return ZX_ERR_NO_RESOURCES; break;
@@ -161,10 +161,9 @@
   I2cFlakyChannelTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) { loop_.StartThread(); }
 
   void SetUp() final {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    ASSERT_OK(endpoints.status_value());
-    i2c_server_.AsyncCall(&Server::BindProtocol, std::move(endpoints->server));
-    i2c_channel_.emplace(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    i2c_server_.AsyncCall(&Server::BindProtocol, std::move(endpoints.server));
+    i2c_channel_.emplace(std::move(endpoints.client));
   }
 
   ddk::I2cChannel& i2c_channel() { return i2c_channel_.value(); }
@@ -217,10 +216,9 @@
   I2cChannelTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) { loop_.StartThread(); }
 
   void SetUp() final {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    ASSERT_OK(endpoints.status_value());
-    i2c_server_.AsyncCall(&Server::BindProtocol, std::move(endpoints->server));
-    i2c_channel_.emplace(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    i2c_server_.AsyncCall(&Server::BindProtocol, std::move(endpoints.server));
+    i2c_channel_.emplace(std::move(endpoints.client));
   }
 
   ddk::I2cChannel& i2c_channel() { return i2c_channel_.value(); }
@@ -330,10 +328,9 @@
   I2cChannelServiceTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) { loop_.StartThread(); }
 
   void SetUp() final {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints.status_value());
-    i2c_server_.AsyncCall(&Server::PublishService, std::move(endpoints->server));
-    directory_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    i2c_server_.AsyncCall(&Server::PublishService, std::move(endpoints.server));
+    directory_ = std::move(endpoints.client);
   }
 
   async_patterns::TestDispatcherBound<Server>& i2c_server() { return i2c_server_; }
diff --git a/src/devices/lib/amlogic/BUILD.gn b/src/devices/lib/amlogic/BUILD.gn
index 55cdc38..4d59814 100644
--- a/src/devices/lib/amlogic/BUILD.gn
+++ b/src/devices/lib/amlogic/BUILD.gn
@@ -81,7 +81,6 @@
     "s905d2-pll-rates.cc",
   ]
   deps = [
-    "//src/lib/ddktl",  # Used for metadata.
     "//zircon/system/ulib/fbl",
     "//zircon/system/ulib/fzl",
     "//zircon/system/ulib/hwreg",
diff --git a/src/devices/lib/amlogic/a1-pll-rates.cc b/src/devices/lib/amlogic/a1-pll-rates.cc
index f720471..15addd9 100644
--- a/src/devices/lib/amlogic/a1-pll-rates.cc
+++ b/src/devices/lib/amlogic/a1-pll-rates.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <lib/ddk/debug.h>
 #include <zircon/errors.h>
 #include <zircon/status.h>
 #include <zircon/types.h>
diff --git a/src/devices/lib/amlogic/include/soc/aml-common/aml-audio.h b/src/devices/lib/amlogic/include/soc/aml-common/aml-audio.h
index 9ebde3f..4235866 100644
--- a/src/devices/lib/amlogic/include/soc/aml-common/aml-audio.h
+++ b/src/devices/lib/amlogic/include/soc/aml-common/aml-audio.h
@@ -7,8 +7,6 @@
 
 #include <zircon/device/audio.h>
 
-#include <ddktl/metadata/audio.h>
-
 namespace metadata {
 
 static constexpr uint32_t kMaxNumberOfLanes = 4;
@@ -104,6 +102,74 @@
   uint32_t datalb_chmask;
 };
 
+static constexpr uint32_t kMaxNumberOfChannelsInRingBuffer = 64;
+static constexpr uint32_t kMaxNumberOfCodecs = 8;
+static constexpr uint32_t kMaxNumberOfExternalDelays = 8;
+
+enum class CodecType : uint32_t {
+  Tas27xx,
+  Tas5782,
+  Tas58xx,
+  Tas5720,
+  Tas5707,
+};
+
+// Same as //sdk/fidl/fuchsia.hardware.audio/dai_format.fidl
+enum class DaiType : uint32_t {
+  I2s,
+  StereoLeftJustified,
+  Tdm1,
+  Tdm2,
+  Tdm3,
+};
+
+enum class SampleFormat : uint32_t {
+  PcmSigned,  // Default for zeroed out metadata.
+  PcmUnsigned,
+  PcmFloat,
+};
+
+struct ExternalDelay {
+  uint32_t frequency;
+  int64_t nsecs;
+};
+
+struct FrequencyRange {
+  uint32_t min_frequency;
+  uint32_t max_frequency;
+};
+
+struct RingBuffer {
+  uint8_t number_of_channels;
+  uint8_t bytes_per_sample;  // If not specified (set to 0), then 2 bytes.
+  FrequencyRange frequency_ranges[kMaxNumberOfChannelsInRingBuffer];  // Optional.
+};
+
+struct Dai {
+  DaiType type;
+  uint8_t number_of_channels;  // If not specified (set to 0), then 2 for stereo types like I2S.
+  SampleFormat sample_format;  // Defaults to PcmSigned.
+  uint8_t bits_per_sample;     // If not specified (set to 0), then 16 bits.
+  uint8_t bits_per_slot;       // If not specified (set to 0), then 32 bits.
+  bool sclk_on_raising;        // Invert the usual clocking out on falling edge.
+};
+
+struct Codecs {
+  uint8_t number_of_codecs;
+  CodecType types[kMaxNumberOfCodecs];
+  float delta_gains[kMaxNumberOfCodecs];
+  uint32_t number_of_external_delays;
+  ExternalDelay external_delays[kMaxNumberOfExternalDelays];
+  // Channels to enable in each codec as a bitmask of the channels in the DAI.
+  // The least significant bit correspond to the left most channel in the DAI.
+  uint8_t channels_to_use_bitmask[kMaxNumberOfCodecs];
+  // Defines mapping between ring buffer channels and codecs using them.
+  // Used for stopping codecs corresponding to the ring buffer channels to use bitmask.
+  // Each ring buffer channel to use is represented as a bit, the least significant bit
+  // corresponds to index 0.
+  uint64_t ring_buffer_channels_to_use_bitmask[kMaxNumberOfCodecs];
+};
+
 struct AmlConfig {
   char manufacturer[kMaxAmlConfigString];
   char product_name[kMaxAmlConfigString];
diff --git a/src/devices/lib/dev-operation/BUILD.gn b/src/devices/lib/dev-operation/BUILD.gn
index dc6f95e..6d16ebb 100644
--- a/src/devices/lib/dev-operation/BUILD.gn
+++ b/src/devices/lib/dev-operation/BUILD.gn
@@ -14,7 +14,6 @@
 
 zx_library("dev-operation") {
   sdk = "source"
-  sdk_publishable = "experimental"
   sdk_name = "dev-operation"
   sdk_headers = [
     "lib/operation/operation.h",
diff --git a/src/devices/lib/driver/BUILD.gn b/src/devices/lib/driver/BUILD.gn
index 67b1d91..c4a471c 100644
--- a/src/devices/lib/driver/BUILD.gn
+++ b/src/devices/lib/driver/BUILD.gn
@@ -177,7 +177,6 @@
     "//src/devices/tests/ddk-firmware-test:*",
     "//src/devices/tests/ddk-lifecycle:*",
     "//src/devices/tests/ddk-metadata-test:*",
-    "//src/devices/tests/ddk-power:*",
     "//src/devices/tests/ddk-topology-test:*",
     "//src/devices/tests/device-watcher:*",
     "//src/devices/tests/driver-inspect-test:*",
diff --git a/src/devices/lib/fragment-irq/test-dfv1.cc b/src/devices/lib/fragment-irq/test-dfv1.cc
index 5a76e1c..4c83353 100644
--- a/src/devices/lib/fragment-irq/test-dfv1.cc
+++ b/src/devices/lib/fragment-irq/test-dfv1.cc
@@ -26,12 +26,11 @@
     auto result = outgoing_.AddService<fuchsia_hardware_interrupt::Service>(std::move(handler));
     ASSERT_TRUE(result.is_ok());
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(ZX_OK, endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-    ASSERT_EQ(ZX_OK, outgoing_.Serve(std::move(endpoints->server)).status_value());
+    ASSERT_EQ(ZX_OK, outgoing_.Serve(std::move(endpoints.server)).status_value());
 
-    root_->AddFidlService(fint::Service::Name, std::move(endpoints->client), "irq001");
+    root_->AddFidlService(fint::Service::Name, std::move(endpoints.client), "irq001");
   }
 
   void Get(GetCompleter::Sync& completer) override {
diff --git a/src/devices/lib/fragment-irq/test-dfv2.cc b/src/devices/lib/fragment-irq/test-dfv2.cc
index a9a0bc5..17bbbd4 100644
--- a/src/devices/lib/fragment-irq/test-dfv2.cc
+++ b/src/devices/lib/fragment-irq/test-dfv2.cc
@@ -27,15 +27,14 @@
         outgoing_.AddService<fuchsia_hardware_interrupt::Service>(std::move(handler), "irq001");
     ASSERT_TRUE(result.is_ok());
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(ZX_OK, endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-    ASSERT_EQ(ZX_OK, outgoing_.Serve(std::move(endpoints->server)).status_value());
+    ASSERT_EQ(ZX_OK, outgoing_.Serve(std::move(endpoints.server)).status_value());
 
     std::vector<fcr::ComponentNamespaceEntry> entries;
     entries.emplace_back(fcr::ComponentNamespaceEntry{{
         .path = "/",
-        .directory = std::move(endpoints->client),
+        .directory = std::move(endpoints.client),
     }});
 
     auto ns = fdf::Namespace::Create(entries);
diff --git a/src/devices/lib/goldfish/pipe_io/BUILD.gn b/src/devices/lib/goldfish/pipe_io/BUILD.gn
index e199308..1ae57c80 100644
--- a/src/devices/lib/goldfish/pipe_io/BUILD.gn
+++ b/src/devices/lib/goldfish/pipe_io/BUILD.gn
@@ -18,9 +18,10 @@
   public_deps = [
     "//sdk/fidl/fuchsia.hardware.goldfish:fuchsia.hardware.goldfish_cpp",
     "//sdk/fidl/fuchsia.hardware.goldfish.pipe:fuchsia.hardware.goldfish.pipe_cpp",
+    "//src/devices/lib/dma-buffer",
     "//src/devices/lib/goldfish/pipe_headers",
+    "//src/graphics/display/lib/driver-framework-migration-utils/logging:zxlogf",
     "//src/lib/ddk",
-    "//src/lib/ddktl",
     "//src/lib/fxl",
     "//zircon/system/ulib/async:async-cpp",
     "//zircon/system/ulib/fbl",
@@ -40,6 +41,7 @@
     ":pipe_io",
     "//src/devices/testing/goldfish/fake_pipe",
     "//src/devices/testing/no_ddk",
+    "//src/graphics/display/lib/driver-framework-migration-utils/logging:logging-dfv1",
     "//src/lib/fxl/test:gtest_main",
     "//src/lib/testing/loop_fixture",
     "//third_party/googletest:gtest",
diff --git a/src/devices/lib/goldfish/pipe_io/pipe_auto_reader.cc b/src/devices/lib/goldfish/pipe_io/pipe_auto_reader.cc
index a255806..533956f 100644
--- a/src/devices/lib/goldfish/pipe_io/pipe_auto_reader.cc
+++ b/src/devices/lib/goldfish/pipe_io/pipe_auto_reader.cc
@@ -6,7 +6,8 @@
 
 #include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
 #include <lib/async/cpp/task.h>
-#include <lib/ddk/debug.h>
+
+#include "src/graphics/display/lib/driver-framework-migration-utils/logging/zxlogf.h"
 
 namespace goldfish {
 
diff --git a/src/devices/lib/goldfish/pipe_io/pipe_io.cc b/src/devices/lib/goldfish/pipe_io/pipe_io.cc
index b372a07..d912af9 100644
--- a/src/devices/lib/goldfish/pipe_io/pipe_io.cc
+++ b/src/devices/lib/goldfish/pipe_io/pipe_io.cc
@@ -5,9 +5,8 @@
 #include "src/devices/lib/goldfish/pipe_io/pipe_io.h"
 
 #include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
-#include <lib/ddk/debug.h>
+#include <lib/dma-buffer/buffer.h>
 #include <lib/fit/defer.h>
-#include <lib/fpromise/result.h>
 #include <lib/fzl/pinned-vmo.h>
 #include <lib/stdcompat/span.h>
 #include <lib/zx/result.h>
@@ -21,6 +20,7 @@
 #include <fbl/auto_lock.h>
 
 #include "src/devices/lib/goldfish/pipe_headers/include/base.h"
+#include "src/graphics/display/lib/driver-framework-migration-utils/logging/zxlogf.h"
 #include "src/lib/fxl/strings/string_number_conversions.h"
 
 namespace goldfish {
@@ -50,12 +50,15 @@
   }
   bti_ = std::move(result->value()->bti);
 
-  zx_status_t status = io_buffer_.Init(bti_.get(), PAGE_SIZE, IO_BUFFER_RW | IO_BUFFER_CONTIG);
-  io_buffer_size_ = io_buffer_.size();
+  std::unique_ptr<dma_buffer::BufferFactory> buffer_factory = dma_buffer::CreateBufferFactory();
+
+  zx_status_t status =
+      buffer_factory->CreateContiguous(bti_, /*size=*/PAGE_SIZE, /*alignment_log2=*/0, &io_buffer_);
   if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: Init IO buffer failed: %s", __func__, zx_status_get_string(status));
+    zxlogf(ERROR, "Failed to create contiguous IO buffer: %s", zx_status_get_string(status));
     return status;
   }
+  io_buffer_size_ = io_buffer_->size();
 
   ZX_DEBUG_ASSERT(!pipe_event_.is_valid());
   status = zx::event::create(0u, &pipe_event_);
@@ -85,16 +88,13 @@
     return set_event_result.status();
   }
 
-  status = cmd_buffer_.InitVmo(bti_.get(), vmo.get(), 0, IO_BUFFER_RW);
+  status = cmd_buffer_.Map(std::move(vmo));
   if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: InitVmo failed: %s", __func__, zx_status_get_string(status));
+    zxlogf(ERROR, "Failed to map the command buffer VMO: %s", zx_status_get_string(status));
     return status;
   }
 
-  auto release_buffer =
-      fit::defer([this]() TA_NO_THREAD_SAFETY_ANALYSIS { cmd_buffer_.release(); });
-
-  auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.virt());
+  auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.start());
   buffer->id = id_;
   buffer->cmd = static_cast<int32_t>(fuchsia_hardware_goldfish_pipe::PipeCmdCode::kOpen);
   buffer->status = static_cast<int32_t>(fuchsia_hardware_goldfish_pipe::PipeError::kInval);
@@ -110,10 +110,6 @@
     return ZX_ERR_INTERNAL;
   }
 
-  // Keep buffer after successful execution of OPEN command. This way
-  // we'll send CLOSE later.
-  release_buffer.cancel();
-
   return ZX_OK;
 }
 
@@ -139,8 +135,8 @@
 PipeIo::~PipeIo() {
   fbl::AutoLock lock(&lock_);
   if (id_) {
-    if (cmd_buffer_.is_valid()) {
-      auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.virt());
+    if (cmd_buffer_.start() != nullptr) {
+      auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.start());
       buffer->id = id_;
       buffer->cmd = static_cast<int32_t>(fuchsia_hardware_goldfish_pipe::PipeCmdCode::kClose);
       buffer->status = static_cast<int32_t>(fuchsia_hardware_goldfish_pipe::PipeError::kInval);
@@ -154,12 +150,12 @@
 }
 
 zx::result<uint32_t> PipeIo::TransferLocked(const TransferOp& op) {
-  auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.virt());
+  auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.start());
 
   buffer->rw_params.consumed_size = 0;
   buffer->rw_params.buffers_count = 1;
   buffer->rw_params.ptrs[0] = std::visit(
-      [base_addr = io_buffer_.phys()](const auto& data) -> zx_paddr_t {
+      [base_addr = io_buffer_->phys()](const auto& data) -> zx_paddr_t {
         using T = std::decay_t<decltype(data)>;
         if constexpr (std::is_same_v<T, TransferOp::IoBuffer>) {
           return base_addr + data.offset;
@@ -178,7 +174,7 @@
 
 zx::result<uint32_t> PipeIo::TransferLocked(cpp20::span<const TransferOp> ops) {
   ZX_DEBUG_ASSERT(!ops.empty());
-  auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.virt());
+  auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.start());
 
   bool has_read = false;
   bool has_write = false;
@@ -202,7 +198,7 @@
     }
 
     buffer->rw_params.ptrs[i] = std::visit(
-        [base_addr = io_buffer_.phys()](const auto& data) -> zx_paddr_t {
+        [base_addr = io_buffer_->phys()](const auto& data) -> zx_paddr_t {
           using T = std::decay_t<decltype(data)>;
           if constexpr (std::is_same_v<T, TransferOp::IoBuffer>) {
             return base_addr + data.offset;
@@ -221,7 +217,7 @@
 
 zx::result<uint32_t> PipeIo::ExecTransferCommandLocked(bool has_write, bool has_read) {
   ZX_DEBUG_ASSERT(has_write || has_read);
-  auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.virt());
+  auto buffer = static_cast<PipeCmdBuffer*>(cmd_buffer_.start());
   buffer->id = id_;
   buffer->cmd =
       has_read
@@ -297,7 +293,7 @@
   });
 
   if (status.is_ok()) {
-    memcpy(buf, io_buffer_.virt(), status.value());
+    memcpy(buf, io_buffer_->virt(), status.value());
   }
   return status;
 }
@@ -350,7 +346,7 @@
         return ZX_ERR_INVALID_ARGS;
       }
 
-      char* target_buf = reinterpret_cast<char*>(io_buffer_.virt()) + io_buffer_offset;
+      char* target_buf = reinterpret_cast<char*>(io_buffer_->virt()) + io_buffer_offset;
       std::copy(str->begin(), str->end(), target_buf);
       target_buf[str->length()] = '\0';
 
@@ -368,7 +364,7 @@
       }
 
       std::copy(span->begin(), span->end(),
-                reinterpret_cast<uint8_t*>(io_buffer_.virt()) + io_buffer_offset);
+                reinterpret_cast<uint8_t*>(io_buffer_->virt()) + io_buffer_offset);
       transfer_ops.push_back(TransferOp{
           .type = TransferOp::Type::kWrite,
           .data = TransferOp::IoBuffer{.offset = io_buffer_offset},
@@ -442,7 +438,7 @@
     }
   }
 
-  memcpy(read_dst, io_buffer_.virt(), read_size);
+  memcpy(read_dst, io_buffer_->virt(), read_size);
 
   return ZX_OK;
 }
diff --git a/src/devices/lib/goldfish/pipe_io/pipe_io.h b/src/devices/lib/goldfish/pipe_io/pipe_io.h
index 3ee63c7..5c570e0 100644
--- a/src/devices/lib/goldfish/pipe_io/pipe_io.h
+++ b/src/devices/lib/goldfish/pipe_io/pipe_io.h
@@ -6,19 +6,16 @@
 #define SRC_DEVICES_LIB_GOLDFISH_PIPE_IO_PIPE_IO_H_
 
 #include <fidl/fuchsia.hardware.goldfish.pipe/cpp/wire.h>
-#include <lib/ddk/device.h>
 #include <lib/ddk/io-buffer.h>
-#include <lib/fit/function.h>
-#include <lib/fpromise/result.h>
+#include <lib/dma-buffer/buffer.h>
+#include <lib/fzl/owned-vmo-mapper.h>
 #include <lib/fzl/pinned-vmo.h>
 #include <lib/stdcompat/span.h>
 #include <lib/zircon-internal/thread_annotations.h>
 #include <lib/zx/result.h>
 
-#include <map>
 #include <vector>
 
-#include <ddktl/device.h>
 #include <fbl/mutex.h>
 
 namespace goldfish {
@@ -210,8 +207,8 @@
   bool valid_ = false;
   int32_t id_ = 0;
   zx::bti bti_ TA_GUARDED(lock_);
-  ddk::IoBuffer cmd_buffer_ TA_GUARDED(lock_);
-  ddk::IoBuffer io_buffer_ TA_GUARDED(lock_);
+  fzl::OwnedVmoMapper cmd_buffer_ TA_GUARDED(lock_);
+  std::unique_ptr<dma_buffer::ContiguousBuffer> io_buffer_ TA_GUARDED(lock_);
   size_t io_buffer_size_ = 0u;
   zx::event pipe_event_;
 
diff --git a/src/devices/lib/goldfish/pipe_io/tests/pipe_io_test.cc b/src/devices/lib/goldfish/pipe_io/tests/pipe_io_test.cc
index 5c783a6..8cf2e20 100644
--- a/src/devices/lib/goldfish/pipe_io/tests/pipe_io_test.cc
+++ b/src/devices/lib/goldfish/pipe_io/tests/pipe_io_test.cc
@@ -30,13 +30,12 @@
   void SetUp() override {
     loop_.StartThread("pipe-io-server");
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_goldfish_pipe::GoldfishPipe>();
-    EXPECT_EQ(endpoints.status_value(), ZX_OK);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_goldfish_pipe::GoldfishPipe>::Create();
 
-    binding_ = fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &pipe_);
+    binding_ = fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &pipe_);
     EXPECT_TRUE(binding_.has_value());
 
-    pipe_client_ = fidl::WireSyncClient(std::move(endpoints->client));
+    pipe_client_ = fidl::WireSyncClient(std::move(endpoints.client));
     io_ = std::make_unique<PipeIo>(std::move(pipe_client_), "pipe");
   }
 
@@ -323,13 +322,12 @@
   void SetUp() override {
     TestLoopFixture::SetUp();
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_goldfish_pipe::GoldfishPipe>();
-    EXPECT_EQ(endpoints.status_value(), ZX_OK);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_goldfish_pipe::GoldfishPipe>::Create();
 
-    binding_ = fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &pipe_);
+    binding_ = fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &pipe_);
     EXPECT_TRUE(binding_.has_value());
 
-    pipe_client_ = fidl::WireSyncClient(std::move(endpoints->client));
+    pipe_client_ = fidl::WireSyncClient(std::move(endpoints.client));
 
     loop_.StartThread("pipe-io-server");
   }
diff --git a/src/devices/lib/metadata/llcpp/vreg.h b/src/devices/lib/metadata/llcpp/vreg.h
index 36ca4c5e..b7d80f7 100644
--- a/src/devices/lib/metadata/llcpp/vreg.h
+++ b/src/devices/lib/metadata/llcpp/vreg.h
@@ -11,23 +11,16 @@
 
 namespace vreg {
 
-using fuchsia_hardware_vreg::wire::PwmVregMetadataEntry;
-PwmVregMetadataEntry BuildMetadata(fidl::AnyArena& allocator, uint32_t pwm_index,
-                                   uint32_t period_ns, uint32_t min_voltage_uv,
-                                   uint32_t voltage_step_uv, uint32_t num_steps) {
-  PwmVregMetadataEntry entry(allocator);
-  entry.set_pwm_index(pwm_index);
-  entry.set_period_ns(period_ns);
-  entry.set_min_voltage_uv(min_voltage_uv);
-  entry.set_voltage_step_uv(voltage_step_uv);
-  entry.set_num_steps(num_steps);
-  return entry;
-}
-
-using fuchsia_hardware_vreg::wire::Metadata;
-Metadata BuildMetadata(fidl::AnyArena& allocator, fidl::VectorView<PwmVregMetadataEntry> pwm_vreg) {
-  Metadata metadata(allocator);
-  metadata.set_pwm_vreg(allocator, std::move(pwm_vreg));
+using fuchsia_hardware_vreg::wire::PwmVregMetadata;
+PwmVregMetadata BuildMetadata(fidl::AnyArena& allocator, uint32_t pwm_index, uint32_t period_ns,
+                              uint32_t min_voltage_uv, uint32_t voltage_step_uv,
+                              uint32_t num_steps) {
+  PwmVregMetadata metadata(allocator);
+  metadata.set_pwm_index(pwm_index);
+  metadata.set_period_ns(period_ns);
+  metadata.set_min_voltage_uv(min_voltage_uv);
+  metadata.set_voltage_step_uv(voltage_step_uv);
+  metadata.set_num_steps(num_steps);
   return metadata;
 }
 
diff --git a/src/devices/lib/mmio/BUILD.gn b/src/devices/lib/mmio/BUILD.gn
index 38f2d66..db7147d 100644
--- a/src/devices/lib/mmio/BUILD.gn
+++ b/src/devices/lib/mmio/BUILD.gn
@@ -14,7 +14,7 @@
 
 zx_library("mmio") {
   sdk = "source"
-  sdk_publishable = "internal"
+  sdk_publishable = "partner"
   sdk_headers = [
     "lib/mmio/mmio.h",
     "lib/mmio/mmio-buffer.h",
diff --git a/src/devices/light-sensor/drivers/ams-light/tcs3400-test.cc b/src/devices/light-sensor/drivers/ams-light/tcs3400-test.cc
index 13a847a..7a3d76b 100644
--- a/src/devices/light-sensor/drivers/ams-light/tcs3400-test.cc
+++ b/src/devices/light-sensor/drivers/ams-light/tcs3400-test.cc
@@ -399,10 +399,9 @@
     EXPECT_FALSE(response->is_error());
   }
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_OK(endpoints);
-  fidl::WireSyncClient reader(std::move(endpoints->client));
-  auto result = client->GetInputReportsReader(std::move(endpoints->server));
+  auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+  fidl::WireSyncClient reader(std::move(endpoints.client));
+  auto result = client->GetInputReportsReader(std::move(endpoints.server));
   ASSERT_OK(result.status());
   device_->WaitForNextReader();
 
@@ -515,10 +514,9 @@
 
   WaitForConfiguration();
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_OK(endpoints);
-  fidl::WireSyncClient reader(std::move(endpoints->client));
-  auto result = client->GetInputReportsReader(std::move(endpoints->server));
+  auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+  fidl::WireSyncClient reader(std::move(endpoints.client));
+  auto result = client->GetInputReportsReader(std::move(endpoints.server));
   ASSERT_OK(result.status());
   device_->WaitForNextReader();
 
@@ -574,10 +572,9 @@
 
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> readers[kReaderCount];
   for (auto& reader : readers) {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints);
-    reader.Bind(std::move(endpoints->client));
-    auto result = client->GetInputReportsReader(std::move(endpoints->server));
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+    reader.Bind(std::move(endpoints.client));
+    auto result = client->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
     device_->WaitForNextReader();
   }
@@ -624,10 +621,9 @@
     EXPECT_FALSE(response->is_error());
   }
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_OK(endpoints);
-  fidl::WireSyncClient reader(std::move(endpoints->client));
-  auto result = client->GetInputReportsReader(std::move(endpoints->server));
+  auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+  fidl::WireSyncClient reader(std::move(endpoints.client));
+  auto result = client->GetInputReportsReader(std::move(endpoints.server));
   ASSERT_OK(result.status());
   device_->WaitForNextReader();
 
diff --git a/src/devices/mcu/drivers/vim3-mcu/vim3-mcu-test.cc b/src/devices/mcu/drivers/vim3-mcu/vim3-mcu-test.cc
index ac27f0b..e44d8dc 100644
--- a/src/devices/mcu/drivers/vim3-mcu/vim3-mcu-test.cc
+++ b/src/devices/mcu/drivers/vim3-mcu/vim3-mcu-test.cc
@@ -24,13 +24,12 @@
 
   async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-  EXPECT_TRUE(endpoints.is_ok());
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
 
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &mock_i2c);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &mock_i2c);
   EXPECT_OK(loop.StartThread());
 
-  ddk::I2cChannel i2c(std::move(endpoints->client));
+  ddk::I2cChannel i2c(std::move(endpoints.client));
   StmMcu device(nullptr, std::move(i2c));
   device.Init();
   mock_i2c.VerifyAndClear();
@@ -49,13 +48,12 @@
 
   async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-  EXPECT_TRUE(endpoints.is_ok());
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
 
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &mock_i2c);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &mock_i2c);
   EXPECT_OK(loop.StartThread());
 
-  ddk::I2cChannel i2c(std::move(endpoints->client));
+  ddk::I2cChannel i2c(std::move(endpoints.client));
   StmMcu device(nullptr, std::move(i2c));
   device.Init();
   mock_i2c.VerifyAndClear();
diff --git a/src/devices/misc/drivers/compat/device_test.cc b/src/devices/misc/drivers/compat/device_test.cc
index 42a31e7..a9f6e7e0 100644
--- a/src/devices/misc/drivers/compat/device_test.cc
+++ b/src/devices/misc/drivers/compat/device_test.cc
@@ -588,11 +588,10 @@
   ASSERT_EQ(ZX_OK, device.Add(&args, &second_device));
   ASSERT_EQ(ZX_OK, second_device->CreateNode());
 
-  auto dev_endpoints = fidl::CreateEndpoints<fuchsia_device::Controller>();
-  ASSERT_EQ(ZX_OK, dev_endpoints.status_value());
+  auto dev_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create();
 
-  fidl::BindServer(dispatcher(), std::move(dev_endpoints->server), second_device);
-  fidl::WireClient client{std::move(dev_endpoints->client), dispatcher()};
+  fidl::BindServer(dispatcher(), std::move(dev_endpoints.server), second_device);
+  fidl::WireClient client{std::move(dev_endpoints.client), dispatcher()};
 
   bool callback_called = false;
   client->Bind("gpt.so").Then(
@@ -642,11 +641,10 @@
   second_device->Add(&args, &third_device);
   ASSERT_EQ(ZX_OK, third_device->CreateNode());
 
-  auto dev_endpoints = fidl::CreateEndpoints<fuchsia_device::Controller>();
-  ASSERT_EQ(ZX_OK, dev_endpoints.status_value());
+  auto dev_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create();
 
-  fidl::BindServer(dispatcher(), std::move(dev_endpoints->server), second_device);
-  fidl::WireClient client{std::move(dev_endpoints->client), dispatcher()};
+  fidl::BindServer(dispatcher(), std::move(dev_endpoints.server), second_device);
+  fidl::WireClient client{std::move(dev_endpoints.client), dispatcher()};
 
   bool got_reply = false;
   client->Bind("gpt.so").Then(
@@ -684,11 +682,10 @@
 
   bool got_reply = false;
 
-  auto dev_endpoints = fidl::CreateEndpoints<fuchsia_device::Controller>();
-  ASSERT_EQ(ZX_OK, dev_endpoints.status_value());
+  auto dev_endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create();
 
-  fidl::BindServer(dispatcher(), std::move(dev_endpoints->server), second_device);
-  fidl::WireClient client{std::move(dev_endpoints->client), dispatcher()};
+  fidl::BindServer(dispatcher(), std::move(dev_endpoints.server), second_device);
+  fidl::WireClient client{std::move(dev_endpoints.client), dispatcher()};
 
   client->Rebind("gpt.so").Then(
       [&got_reply](fidl::WireUnownedResult<fuchsia_device::Controller::Rebind>& result) {
diff --git a/src/devices/misc/drivers/compat/driver_test.cc b/src/devices/misc/drivers/compat/driver_test.cc
index 7c1e685..8340297 100644
--- a/src/devices/misc/drivers/compat/driver_test.cc
+++ b/src/devices/misc/drivers/compat/driver_test.cc
@@ -52,12 +52,11 @@
 namespace {
 
 zx::vmo GetVmo(std::string_view path) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::File>();
-  EXPECT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::File>::Create();
   zx_status_t status = fdio_open(path.data(), static_cast<uint32_t>(kOpenFlags),
-                                 endpoints->server.channel().release());
+                                 endpoints.server.channel().release());
   EXPECT_EQ(status, ZX_OK) << zx_status_get_string(status);
-  fidl::WireResult result = fidl::WireCall(endpoints->client)->GetBackingMemory(kVmoFlags);
+  fidl::WireResult result = fidl::WireCall(endpoints.client)->GetBackingMemory(kVmoFlags);
   EXPECT_TRUE(result.ok()) << result.FormatDescription();
   const auto& response = result.value();
   EXPECT_TRUE(response.is_ok()) << zx_status_get_string(response.error_value());
@@ -715,8 +714,7 @@
   std::unique_ptr<compat::Driver> StartDriver(StartDriverArgs args) {
     auto outgoing_dir_endpoints = fidl::CreateEndpoints<fio::Directory>();
     EXPECT_TRUE(outgoing_dir_endpoints.is_ok());
-    auto pkg_endpoints = fidl::CreateEndpoints<fio::Directory>();
-    EXPECT_TRUE(pkg_endpoints.is_ok());
+    auto pkg_endpoints = fidl::Endpoints<fio::Directory>::Create();
     auto svc_endpoints = fidl::CreateEndpoints<fio::Directory>();
     EXPECT_TRUE(svc_endpoints.is_ok());
 
@@ -727,11 +725,11 @@
     zx::result ns_start_result =
         incoming_ns_.SyncCall(&IncomingNamespace::Start, args.v1_driver_path,
                               args.compat_file_response, args.devices, args.expected_profile_role,
-                              std::move(pkg_endpoints->server), std::move(svc_endpoints->server));
+                              std::move(pkg_endpoints.server), std::move(svc_endpoints->server));
     EXPECT_EQ(ZX_OK, ns_start_result.status_value());
 
     auto entry_pkg = frunner::ComponentNamespaceEntry(
-        {.path = std::string("/pkg"), .directory = std::move(pkg_endpoints->client)});
+        {.path = std::string("/pkg"), .directory = std::move(pkg_endpoints.client)});
     auto entry_svc = frunner::ComponentNamespaceEntry(
         {.path = std::string("/svc"), .directory = std::move(svc_endpoints->client)});
     std::vector<frunner::ComponentNamespaceEntry> ns_entries;
diff --git a/src/devices/ml/drivers/aml-nna/BUILD.gn b/src/devices/ml/drivers/aml-nna/BUILD.gn
index 0081251..cd600b0 100644
--- a/src/devices/ml/drivers/aml-nna/BUILD.gn
+++ b/src/devices/ml/drivers/aml-nna/BUILD.gn
@@ -68,7 +68,7 @@
     "//src/devices/lib/mmio",
     "//src/devices/registers/testing/mock-registers",
     "//src/devices/testing/mock-ddk",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//src/lib/ddk",
     "//src/lib/ddktl",
     "//zircon/system/ulib/async-loop:async-loop-cpp",
diff --git a/src/devices/ml/drivers/aml-nna/aml-nna-test.cc b/src/devices/ml/drivers/aml-nna/aml-nna-test.cc
index 4cabc12..a08dd6f 100644
--- a/src/devices/ml/drivers/aml-nna/aml-nna-test.cc
+++ b/src/devices/ml/drivers/aml-nna/aml-nna-test.cc
@@ -7,7 +7,7 @@
 #include <lib/async-loop/cpp/loop.h>
 #include <lib/mmio/mmio.h>
 
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 
 #include "s905d3-nna-regs.h"
 #include "src/devices/registers/testing/mock-registers/mock-registers.h"
@@ -34,9 +34,7 @@
 
   // The caller should set the mock expectations before calling this.
   void CreateDeviceAndVerify(AmlNnaDevice::NnaBlock nna_block) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_registers::Device>();
-    ASSERT_OK(endpoints);
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_registers::Device>::Create();
     reset_mock_->Init(std::move(server_end));
 
     ddk::PDevFidl pdev;
diff --git a/src/devices/nand/drivers/aml-rawnand/tests/BUILD.gn b/src/devices/nand/drivers/aml-rawnand/tests/BUILD.gn
index 187fd84..3fce675 100644
--- a/src/devices/nand/drivers/aml-rawnand/tests/BUILD.gn
+++ b/src/devices/nand/drivers/aml-rawnand/tests/BUILD.gn
@@ -18,7 +18,7 @@
     "//sdk/lib/fdio",
     "//src/devices/testing/fake-bti",
     "//src/devices/testing/mock-ddk",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//zircon/system/ulib/zxtest",
   ]
 }
diff --git a/src/devices/nand/drivers/aml-rawnand/tests/aml-rawnand-test.cc b/src/devices/nand/drivers/aml-rawnand/tests/aml-rawnand-test.cc
index a79ee3b..4494aaf 100644
--- a/src/devices/nand/drivers/aml-rawnand/tests/aml-rawnand-test.cc
+++ b/src/devices/nand/drivers/aml-rawnand/tests/aml-rawnand-test.cc
@@ -13,7 +13,7 @@
 #include <memory>
 #include <queue>
 
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 #include <soc/aml-common/aml-rawnand.h>
 #include <zxtest/zxtest.h>
 
diff --git a/src/devices/nand/drivers/ram-nand/test/ram-nand.cc b/src/devices/nand/drivers/ram-nand/test/ram-nand.cc
index 77682de..e44cfb5 100644
--- a/src/devices/nand/drivers/ram-nand/test/ram-nand.cc
+++ b/src/devices/nand/drivers/ram-nand/test/ram-nand.cc
@@ -271,19 +271,18 @@
   NandParams params(kPageSize, kBlockSize, kNumBlocks, 6, 0);
   NandDevice* device(new NandDevice(params, fake_parent.get()));
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_nand::RamNand>();
-  ASSERT_TRUE(endpoints.is_ok());
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_nand::RamNand>::Create();
 
   async::Loop loop{&kAsyncLoopConfigNeverAttachToThread};
   loop.StartThread("fidl-thread");
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), device);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), device);
 
   // We need to DdkAdd the device, as Unlink will call DdkAsyncRemove.
   auto config = BuildConfig();
   ASSERT_OK(device->Bind(config));
   auto* child = fake_parent->GetLatestChild();
 
-  fidl::WireSyncClient client(std::move(endpoints->client));
+  fidl::WireSyncClient client(std::move(endpoints.client));
   {
     auto result = client->Unlink();
     ASSERT_OK(result.status());
diff --git a/src/devices/nand/drivers/skip-block/test/skip-block-test.cc b/src/devices/nand/drivers/skip-block/test/skip-block-test.cc
index 4fdd9a7..3b7f859 100644
--- a/src/devices/nand/drivers/skip-block/test/skip-block-test.cc
+++ b/src/devices/nand/drivers/skip-block/test/skip-block-test.cc
@@ -194,10 +194,9 @@
   void InitializeFidlClient() {
     if (!client_) {
       ASSERT_EQ(fake_parent().child_count(), 1);
-      auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_skipblock::SkipBlock>();
-      ASSERT_OK(endpoints.status_value());
-      fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &dev());
-      client_.Bind(std::move(endpoints->client));
+      auto endpoints = fidl::Endpoints<fuchsia_hardware_skipblock::SkipBlock>::Create();
+      fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &dev());
+      client_.Bind(std::move(endpoints.client));
     }
   }
 
diff --git a/src/devices/pci/lib/device-protocol-pci/test/pci-test.cc b/src/devices/pci/lib/device-protocol-pci/test/pci-test.cc
index 5dad046..8ad495e 100644
--- a/src/devices/pci/lib/device-protocol-pci/test/pci-test.cc
+++ b/src/devices/pci/lib/device-protocol-pci/test/pci-test.cc
@@ -24,19 +24,18 @@
   void SetUp() override {
     loop_.StartThread("pci-fidl-server-thread");
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pci::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_pci::Device>::Create();
 
     fake_pci_ = std::make_unique<pci::FakePciProtocol>();
     fake_pci_->CreateBar(bar_id_, zx_system_get_page_size(), /*is_mmio=*/true);
 
     binding_ = fidl::BindServer(
         loop_.dispatcher(),
-        fidl::ServerEnd<fuchsia_hardware_pci::Device>(endpoints->server.TakeChannel()),
+        fidl::ServerEnd<fuchsia_hardware_pci::Device>(endpoints.server.TakeChannel()),
         std::move(fake_pci_));
     EXPECT_TRUE(binding_.has_value());
 
-    client_ = std::move(endpoints->client);
+    client_ = std::move(endpoints.client);
   }
 
   void TearDown() override { loop_.Shutdown(); }
diff --git a/src/devices/pci/testing/pci_protocol_fake_tests.cc b/src/devices/pci/testing/pci_protocol_fake_tests.cc
index e9e9a6c..66146e9 100644
--- a/src/devices/pci/testing/pci_protocol_fake_tests.cc
+++ b/src/devices/pci/testing/pci_protocol_fake_tests.cc
@@ -30,14 +30,13 @@
   void SetUp() final {
     fake_pci_.Reset();
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pci::Device>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_pci::Device>::Create();
 
     fidl::BindServer(loop_.dispatcher(),
-                     fidl::ServerEnd<fuchsia_hardware_pci::Device>(endpoints->server.TakeChannel()),
+                     fidl::ServerEnd<fuchsia_hardware_pci::Device>(endpoints.server.TakeChannel()),
                      &fake_pci_);
 
-    pci_ = ddk::Pci(std::move(endpoints->client));
+    pci_ = ddk::Pci(std::move(endpoints.client));
     ASSERT_TRUE(pci_.is_valid());
 
     loop_.StartThread("pci-fidl-server-thread");
diff --git a/src/devices/pci/testing/protocol/fidl.cc b/src/devices/pci/testing/protocol/fidl.cc
index 3659ed2..e10c719 100644
--- a/src/devices/pci/testing/protocol/fidl.cc
+++ b/src/devices/pci/testing/protocol/fidl.cc
@@ -207,16 +207,15 @@
 }
 
 ddk::Pci FakePciProtocol::SetUpFidlServer(async::Loop& loop) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_pci::Device>();
-  ZX_ASSERT(endpoints.is_ok());
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_pci::Device>::Create();
 
   auto fake_pci = std::make_unique<FakePciProtocol>();
   std::optional<fidl::ServerBindingRef<fuchsia_hardware_pci::Device>> binding = fidl::BindServer(
       loop.dispatcher(),
-      fidl::ServerEnd<fuchsia_hardware_pci::Device>(endpoints->server.TakeChannel()), this);
+      fidl::ServerEnd<fuchsia_hardware_pci::Device>(endpoints.server.TakeChannel()), this);
   ZX_ASSERT(binding.has_value());
 
-  ddk::Pci pci = ddk::Pci(std::move(endpoints->client));
+  ddk::Pci pci = ddk::Pci(std::move(endpoints.client));
   ZX_ASSERT(pci.is_valid());
   return pci;
 }
diff --git a/src/devices/power/drivers/aml-meson-power/BUILD.gn b/src/devices/power/drivers/aml-meson-power/BUILD.gn
index 5c88cf3..2f6bd29 100644
--- a/src/devices/power/drivers/aml-meson-power/BUILD.gn
+++ b/src/devices/power/drivers/aml-meson-power/BUILD.gn
@@ -74,7 +74,6 @@
     "//src/devices/bus/lib/device-protocol-pdev",
     "//src/devices/lib/amlogic",
     "//src/devices/lib/mmio",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
     "//src/devices/testing/no_ddk",
     "//src/lib/ddk",
     "//src/lib/ddktl",
diff --git a/src/devices/power/drivers/aml-meson-power/aml-power-test.cc b/src/devices/power/drivers/aml-meson-power/aml-power-test.cc
index 2276be9..488a47f 100644
--- a/src/devices/power/drivers/aml-meson-power/aml-power-test.cc
+++ b/src/devices/power/drivers/aml-meson-power/aml-power-test.cc
@@ -135,10 +135,9 @@
   }
 
   fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> BindServer() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pwm::Pwm>();
-    EXPECT_TRUE(endpoints.is_ok());
-    fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints->server), this);
-    return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_pwm::Pwm>::Create();
+    fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints.server), this);
+    return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints.client));
   }
 
   void VerifyAndClear() {
@@ -180,11 +179,10 @@
   uint32_t voltage_step() const { return voltage_step_; }
 
   fidl::ClientEnd<fuchsia_hardware_vreg::Vreg> BindServer() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_vreg::Vreg>();
-    EXPECT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_vreg::Vreg>::Create();
     binding_ref_ =
-        fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints->server), this);
-    return std::move(endpoints->client);
+        fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints.server), this);
+    return std::move(endpoints.client);
   }
 
  private:
diff --git a/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator-test.cc b/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator-test.cc
index be6cbef..6b9b991 100644
--- a/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator-test.cc
+++ b/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator-test.cc
@@ -14,14 +14,7 @@
 #include <lib/driver/testing/cpp/test_node.h>
 #include <lib/sync/cpp/completion.h>
 
-#include <iterator>
-#include <vector>
-
 #include <zxtest/zxtest.h>
-
-#include "fidl/fuchsia.hardware.vreg/cpp/wire_types.h"
-#include "lib/fidl/cpp/wire/wire_messaging_declarations.h"
-#include "lib/fidl/cpp/wire/wire_types.h"
 #include "src/devices/lib/metadata/llcpp/vreg.h"
 
 bool operator==(const fuchsia_hardware_pwm::wire::PwmConfig& lhs,
@@ -96,11 +89,10 @@
     auto service_result = outgoing_.AddService<fuchsia_hardware_pwm::Service>(std::move(handler));
     ZX_ASSERT(service_result.is_ok());
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(endpoints.is_ok());
-    ZX_ASSERT(outgoing_.Serve(std::move(endpoints->server)).is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    ZX_ASSERT(outgoing_.Serve(std::move(endpoints.server)).is_ok());
 
-    return std::move(endpoints->client);
+    return std::move(endpoints.client);
   }
 
   void VerifyAndClear() {
@@ -154,12 +146,8 @@
 
       // Setup metadata.
       fidl::Arena<2048> allocator;
-      fuchsia_hardware_vreg::wire::PwmVregMetadataEntry pwm_entries[] = {
-          vreg::BuildMetadata(allocator, 0, 1250, 690'000, 1'000, 11)};
-      auto metadata = vreg::BuildMetadata(
-          allocator,
-          fidl::VectorView<fuchsia_hardware_vreg::wire::PwmVregMetadataEntry>::FromExternal(
-              pwm_entries));
+      fuchsia_hardware_vreg::wire::PwmVregMetadata metadata =
+          vreg::BuildMetadata(allocator, 0, 1250, 690'000, 1'000, 11);
       auto encoded = fidl::Persist(metadata);
       ASSERT_TRUE(encoded.is_ok());
       incoming->compat_server.AddMetadata(DEVICE_METADATA_VREG, encoded.value().data(),
@@ -173,7 +161,7 @@
       // Serve mock pwm server.
       auto result =
           incoming->test_env.incoming_directory().AddService<fuchsia_hardware_pwm::Service>(
-              incoming->mock_pwm_server.GetInstanceHandler(), "pwm-0");
+              incoming->mock_pwm_server.GetInstanceHandler(), "pwm");
       ASSERT_TRUE(result.is_ok());
 
       incoming->mock_pwm_server.ExpectEnable();
@@ -187,16 +175,15 @@
   }
 
   fidl::ClientEnd<fuchsia_hardware_vreg::Vreg> GetClient(std::string_view name) {
-    auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_EQ(ZX_OK, svc_endpoints.status_value());
+    auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
     zx_status_t status = fdio_open_at(outgoing_directory_client_.handle()->get(), "/svc",
                                       static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
-                                      svc_endpoints->server.TakeChannel().release());
+                                      svc_endpoints.server.TakeChannel().release());
     EXPECT_EQ(ZX_OK, status);
 
     auto connect_result = component::ConnectAtMember<fuchsia_hardware_vreg::Service::Vreg>(
-        svc_endpoints->client, name);
+        svc_endpoints.client, name);
     EXPECT_TRUE(connect_result.is_ok());
     return std::move(connect_result.value());
   }
diff --git a/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.bind b/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.bind
index 66cf4b0..a73951e 100644
--- a/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.bind
+++ b/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.bind
@@ -9,14 +9,8 @@
 using fuchsia.hardware.pwm;
 using fuchsia.pwm;
 
-primary node "pwm-9" {
+primary node "pwm" {
     fuchsia.hardware.pwm.Service == fuchsia.hardware.pwm.Service.ZirconTransport;
-    fuchsia.pwm.PWM_ID_FUNCTION == fuchsia.pwm.PWM_ID_FUNCTION.CORE_POWER_LITTLE_CLUSTER;
-}
-
-node "pwm-0" {
-    fuchsia.hardware.pwm.Service == fuchsia.hardware.pwm.Service.ZirconTransport;
-    fuchsia.pwm.PWM_ID_FUNCTION == fuchsia.pwm.PWM_ID_FUNCTION.CORE_POWER_BIG_CLUSTER;
 }
 
 node "pdev" {
diff --git a/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.cc b/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.cc
index bfb93f1..6125aee 100644
--- a/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.cc
+++ b/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.cc
@@ -19,7 +19,7 @@
 
 namespace aml_pwm_regulator {
 
-AmlPwmRegulator::AmlPwmRegulator(const PwmVregMetadataEntry& vreg_range,
+AmlPwmRegulator::AmlPwmRegulator(const PwmVregMetadata& vreg_range,
                                  fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> pwm_proto_client,
                                  AmlPwmRegulatorDriver* driver, std::string_view name)
     : pwm_index_(vreg_range.pwm_index()),
@@ -80,18 +80,15 @@
 }
 
 zx::result<std::unique_ptr<AmlPwmRegulator>> AmlPwmRegulator::Create(
-    const PwmVregMetadataEntry& metadata_entry, AmlPwmRegulatorDriver* driver) {
-  uint32_t idx = metadata_entry.pwm_index();
-  char name[20];
-  snprintf(name, sizeof(name), "pwm-%u", idx);
-
-  auto connect_result = driver->incoming()->Connect<fuchsia_hardware_pwm::Service::Pwm>(name);
+    const PwmVregMetadata& metadata, AmlPwmRegulatorDriver* driver) {
+  auto connect_result = driver->incoming()->Connect<fuchsia_hardware_pwm::Service::Pwm>("pwm");
   if (connect_result.is_error()) {
     FDF_LOG(ERROR, "Unable to connect to fidl protocol - status: %s",
             connect_result.status_string());
     return connect_result.take_error();
   }
 
+  uint32_t idx = metadata.pwm_index();
   fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> pwm_proto_client(
       std::move(connect_result.value()));
   auto result = pwm_proto_client->Enable();
@@ -103,10 +100,12 @@
     FDF_LOG(ERROR, "Unable to enable PWM %u, %s", idx, zx_status_get_string(result->error_value()));
     return result->take_error();
   }
+
+  char name[20];
   snprintf(name, sizeof(name), "pwm-%u-regulator", idx);
 
   auto device =
-      std::make_unique<AmlPwmRegulator>(metadata_entry, std::move(pwm_proto_client), driver, name);
+      std::make_unique<AmlPwmRegulator>(metadata, std::move(pwm_proto_client), driver, name);
 
   // Initialize our compat server.
   {
@@ -170,7 +169,7 @@
 
 zx::result<> AmlPwmRegulatorDriver::Start() {
   fidl::Arena arena;
-  auto decoded = compat::GetMetadata<fuchsia_hardware_vreg::wire::Metadata>(
+  auto decoded = compat::GetMetadata<fuchsia_hardware_vreg::wire::PwmVregMetadata>(
       incoming(), arena, DEVICE_METADATA_VREG, "pdev");
   if (decoded.is_error()) {
     FDF_LOG(ERROR, "Failed to get vreg metadata: %s", decoded.status_string());
@@ -180,25 +179,18 @@
   const auto& metadata = *decoded.value();
 
   // Validate
-  if (!metadata.has_pwm_vreg()) {
+  if (!metadata.has_pwm_index() || !metadata.has_period_ns() || !metadata.has_min_voltage_uv() ||
+      !metadata.has_voltage_step_uv() || !metadata.has_num_steps()) {
     FDF_LOG(ERROR, "Metadata incomplete");
     return zx::error(ZX_ERR_INTERNAL);
   }
-  for (const auto& pwm_vreg : metadata.pwm_vreg()) {
-    if (!pwm_vreg.has_pwm_index() || !pwm_vreg.has_period_ns() || !pwm_vreg.has_min_voltage_uv() ||
-        !pwm_vreg.has_voltage_step_uv() || !pwm_vreg.has_num_steps()) {
-      FDF_LOG(ERROR, "Metadata incomplete");
-      return zx::error(ZX_ERR_INTERNAL);
-    }
+
+  // Build Voltage Regulator
+  auto regulator = AmlPwmRegulator::Create(metadata, this);
+  if (regulator.is_error()) {
+    return regulator.take_error();
   }
-  // Build Voltage Regulators
-  for (const auto& pwm_vreg : metadata.pwm_vreg()) {
-    auto regulator = AmlPwmRegulator::Create(pwm_vreg, this);
-    if (regulator.is_error()) {
-      return regulator.take_error();
-    }
-    regulators_.push_back(std::move(*regulator));
-  }
+  regulators_ = std::move(*regulator);
   return zx::ok();
 }
 
diff --git a/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.h b/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.h
index c653d9b..7672960 100644
--- a/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.h
+++ b/src/devices/power/drivers/aml-pwm-regulator/aml-pwm-regulator.h
@@ -16,17 +16,17 @@
 
 namespace aml_pwm_regulator {
 
-using fuchsia_hardware_vreg::wire::PwmVregMetadataEntry;
+using fuchsia_hardware_vreg::wire::PwmVregMetadata;
 
 class AmlPwmRegulatorDriver;
 
 class AmlPwmRegulator : public fidl::WireServer<fuchsia_hardware_vreg::Vreg> {
  public:
-  explicit AmlPwmRegulator(const PwmVregMetadataEntry& vreg_range,
+  explicit AmlPwmRegulator(const PwmVregMetadata& vreg_range,
                            fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> pwm_proto_client,
                            AmlPwmRegulatorDriver* driver, std::string_view name);
-  static zx::result<std::unique_ptr<AmlPwmRegulator>> Create(
-      const PwmVregMetadataEntry& metadata_entry, AmlPwmRegulatorDriver* driver);
+  static zx::result<std::unique_ptr<AmlPwmRegulator>> Create(const PwmVregMetadata& metadata,
+                                                             AmlPwmRegulatorDriver* driver);
 
   // Vreg Implementation.
   void SetVoltageStep(SetVoltageStepRequestView request,
@@ -61,7 +61,7 @@
  private:
   friend class AmlPwmRegulator;
 
-  std::vector<std::unique_ptr<AmlPwmRegulator>> regulators_;
+  std::unique_ptr<AmlPwmRegulator> regulators_;
 };
 
 }  // namespace aml_pwm_regulator
diff --git a/src/devices/power/drivers/aml-pwm-regulator/bind-tests.json b/src/devices/power/drivers/aml-pwm-regulator/bind-tests.json
index 6983d5b..a5d214a 100644
--- a/src/devices/power/drivers/aml-pwm-regulator/bind-tests.json
+++ b/src/devices/power/drivers/aml-pwm-regulator/bind-tests.json
@@ -1,26 +1,12 @@
 [
     {
-        "node": "pwm-9",
+        "node": "pwm",
         "tests": [
             {
                 "name": "Match",
                 "expected": "match",
                 "device": {
-                    "fuchsia.hardware.pwm.Service": "fuchsia.hardware.pwm.Service.ZirconTransport",
-                    "fuchsia.pwm.PWM_ID_FUNCTION": "fuchsia.pwm.PWM_ID_FUNCTION.CORE_POWER_LITTLE_CLUSTER"
-                }
-            }
-        ]
-    },
-    {
-        "node": "pwm-0",
-        "tests": [
-            {
-                "name": "Match",
-                "expected": "match",
-                "device": {
-                    "fuchsia.hardware.pwm.Service": "fuchsia.hardware.pwm.Service.ZirconTransport",
-                    "fuchsia.pwm.PWM_ID_FUNCTION": "fuchsia.pwm.PWM_ID_FUNCTION.CORE_POWER_BIG_CLUSTER"
+                    "fuchsia.hardware.pwm.Service": "fuchsia.hardware.pwm.Service.ZirconTransport"
                 }
             }
         ]
diff --git a/src/devices/power/drivers/fusb302/fusb302-controls-test.cc b/src/devices/power/drivers/fusb302/fusb302-controls-test.cc
index c6caa19..d95df36 100644
--- a/src/devices/power/drivers/fusb302/fusb302-controls-test.cc
+++ b/src/devices/power/drivers/fusb302/fusb302-controls-test.cc
@@ -41,12 +41,11 @@
   void SetUp() override {
     fdf::Logger::SetGlobalInstance(&logger_);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    mock_i2c_client_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    mock_i2c_client_ = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
-    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server),
+    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints.server),
                                                    &mock_i2c_);
 
     sensors_.emplace(mock_i2c_client_, inspect_.GetRoot().CreateChild("Sensors"));
diff --git a/src/devices/power/drivers/fusb302/fusb302-fifos-test.cc b/src/devices/power/drivers/fusb302/fusb302-fifos-test.cc
index 1702d2c..d1d7283 100644
--- a/src/devices/power/drivers/fusb302/fusb302-fifos-test.cc
+++ b/src/devices/power/drivers/fusb302/fusb302-fifos-test.cc
@@ -54,12 +54,11 @@
   void SetUp() override {
     fdf::Logger::SetGlobalInstance(&logger_);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    mock_i2c_client_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    mock_i2c_client_ = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
-    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server),
+    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints.server),
                                                    &mock_i2c_);
 
     fifos_.emplace(mock_i2c_client_);
diff --git a/src/devices/power/drivers/fusb302/fusb302-identity-test.cc b/src/devices/power/drivers/fusb302/fusb302-identity-test.cc
index 55ff069..816a51b 100644
--- a/src/devices/power/drivers/fusb302/fusb302-identity-test.cc
+++ b/src/devices/power/drivers/fusb302/fusb302-identity-test.cc
@@ -28,12 +28,11 @@
   void SetUp() override {
     fdf::Logger::SetGlobalInstance(&logger_);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    mock_i2c_client_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    mock_i2c_client_ = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
-    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server),
+    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints.server),
                                                    &mock_i2c_);
 
     identity_.emplace(mock_i2c_client_, inspect_.GetRoot().CreateChild("Identity"));
diff --git a/src/devices/power/drivers/fusb302/fusb302-protocol-test.cc b/src/devices/power/drivers/fusb302/fusb302-protocol-test.cc
index f7a8f77..edef18d 100644
--- a/src/devices/power/drivers/fusb302/fusb302-protocol-test.cc
+++ b/src/devices/power/drivers/fusb302/fusb302-protocol-test.cc
@@ -52,12 +52,11 @@
  public:
   void SetUp() override {
     fdf::Logger::SetGlobalInstance(&logger_);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    mock_i2c_client_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    mock_i2c_client_ = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
-    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server),
+    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints.server),
                                                    &mock_i2c_);
 
     fifos_.emplace(mock_i2c_client_);
diff --git a/src/devices/power/drivers/fusb302/fusb302-sensors-test.cc b/src/devices/power/drivers/fusb302/fusb302-sensors-test.cc
index a2838e2..e0cd138 100644
--- a/src/devices/power/drivers/fusb302/fusb302-sensors-test.cc
+++ b/src/devices/power/drivers/fusb302/fusb302-sensors-test.cc
@@ -33,12 +33,11 @@
  public:
   void SetUp() override {
     fdf::Logger::SetGlobalInstance(&logger_);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    mock_i2c_client_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    mock_i2c_client_ = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
-    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server),
+    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints.server),
                                                    &mock_i2c_);
 
     sensors_.emplace(mock_i2c_client_, inspect_.GetRoot().CreateChild("Sensors"));
diff --git a/src/devices/power/drivers/fusb302/fusb302-signals-test.cc b/src/devices/power/drivers/fusb302/fusb302-signals-test.cc
index e2bd56f..0f5512a 100644
--- a/src/devices/power/drivers/fusb302/fusb302-signals-test.cc
+++ b/src/devices/power/drivers/fusb302/fusb302-signals-test.cc
@@ -57,12 +57,11 @@
  public:
   void SetUp() override {
     fdf::Logger::SetGlobalInstance(&logger_);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    mock_i2c_client_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    mock_i2c_client_ = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
-    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server),
+    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints.server),
                                                    &mock_i2c_);
 
     sensors_.emplace(mock_i2c_client_, inspect_.GetRoot().CreateChild("Sensors"));
diff --git a/src/devices/power/drivers/fusb302/fusb302-test.cc b/src/devices/power/drivers/fusb302/fusb302-test.cc
index 65d988c..9ac6b5a 100644
--- a/src/devices/power/drivers/fusb302/fusb302-test.cc
+++ b/src/devices/power/drivers/fusb302/fusb302-test.cc
@@ -30,12 +30,11 @@
 class Fusb302Test : public inspect::InspectTestHelper, public zxtest::Test {
  public:
   void SetUp() override {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    fidl::ClientEnd<fuchsia_hardware_i2c::Device> mock_i2c_client = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    fidl::ClientEnd<fuchsia_hardware_i2c::Device> mock_i2c_client = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
-    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server),
+    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints.server),
                                                    &mock_i2c_);
     zx::interrupt gpio_interrupt;
     ASSERT_OK(
diff --git a/src/devices/power/drivers/fusb302/fusb302.cc b/src/devices/power/drivers/fusb302/fusb302.cc
index c15274f..71596b4 100644
--- a/src/devices/power/drivers/fusb302/fusb302.cc
+++ b/src/devices/power/drivers/fusb302/fusb302.cc
@@ -211,22 +211,19 @@
                   .devfs_args(devfs.Build())
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
   ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create endpoints: %s",
                 node_endpoints.status_string());
 
   fidl::WireResult result = fidl::WireCall(node())->AddChild(
-      args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+      args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
   node_.Bind(std::move(node_endpoints->client));
   return zx::ok();
 }
diff --git a/src/devices/power/drivers/fusb302/registers-test.cc b/src/devices/power/drivers/fusb302/registers-test.cc
index 4ec8020..437a2bdc 100644
--- a/src/devices/power/drivers/fusb302/registers-test.cc
+++ b/src/devices/power/drivers/fusb302/registers-test.cc
@@ -311,12 +311,11 @@
 class Fusb302RegisterTest : public zxtest::Test {
  public:
   void SetUp() override {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    mock_i2c_client_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    mock_i2c_client_ = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
-    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints->server),
+    fidl::BindServer<fuchsia_hardware_i2c::Device>(loop_.dispatcher(), std::move(endpoints.server),
                                                    &mock_i2c_);
   }
 
diff --git a/src/devices/power/drivers/nelson-brownout-protection/nelson-brownout-protection-test.cc b/src/devices/power/drivers/nelson-brownout-protection/nelson-brownout-protection-test.cc
index 42ffdc1..3c6709c 100644
--- a/src/devices/power/drivers/nelson-brownout-protection/nelson-brownout-protection-test.cc
+++ b/src/devices/power/drivers/nelson-brownout-protection/nelson-brownout-protection-test.cc
@@ -158,8 +158,7 @@
 
  private:
   void SetupPowerSensorFragment() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto power_handler = power_sensor_.SyncCall(&FakePowerSensor::CreateInstanceHandler);
     zx::result service_result = power_outgoing_.SyncCall(
         [handler = std::move(power_handler)](component::OutgoingDirectory* outgoing) mutable {
@@ -167,15 +166,14 @@
         });
     ZX_ASSERT(service_result.is_ok());
     ZX_ASSERT(
-        power_outgoing_.SyncCall(&component::OutgoingDirectory::Serve, std::move(endpoints->server))
+        power_outgoing_.SyncCall(&component::OutgoingDirectory::Serve, std::move(endpoints.server))
             .is_ok());
     fake_parent_->AddFidlService(fuchsia_hardware_power_sensor::Service::Name,
-                                 std::move(endpoints->client), "power-sensor");
+                                 std::move(endpoints.client), "power-sensor");
   }
 
   void SetupCodecFragment() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     ASSERT_OK(audio::SimpleCodecServer::CreateAndAddToDdk<FakeCodec>(fake_parent_.get()));
     auto* child_dev = fake_parent_->GetLatestChild();
     ASSERT_NOT_NULL(child_dev);
@@ -187,15 +185,14 @@
         });
     ZX_ASSERT(service_result.is_ok());
     ZX_ASSERT(
-        codec_outgoing_.SyncCall(&component::OutgoingDirectory::Serve, std::move(endpoints->server))
+        codec_outgoing_.SyncCall(&component::OutgoingDirectory::Serve, std::move(endpoints.server))
             .is_ok());
     fake_parent_->AddFidlService(fuchsia_hardware_audio::CodecService::Name,
-                                 std::move(endpoints->client), "codec");
+                                 std::move(endpoints.client), "codec");
   }
 
   void SetupAlertGpioFragment() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     ASSERT_OK(
         zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &alert_gpio_interrupt_));
     zx::interrupt interrupt;
@@ -208,9 +205,9 @@
         });
     ZX_ASSERT(service_result.is_ok());
     ZX_ASSERT(alert_gpio_outgoing_
-                  .SyncCall(&component::OutgoingDirectory::Serve, std::move(endpoints->server))
+                  .SyncCall(&component::OutgoingDirectory::Serve, std::move(endpoints.server))
                   .is_ok());
-    fake_parent_->AddFidlService(fuchsia_hardware_gpio::Service::Name, std::move(endpoints->client),
+    fake_parent_->AddFidlService(fuchsia_hardware_gpio::Service::Name, std::move(endpoints.client),
                                  "alert-gpio");
   }
 
diff --git a/src/devices/power/drivers/power/power-test.cc b/src/devices/power/drivers/power/power-test.cc
index 44f1bd1..1ac6eea 100644
--- a/src/devices/power/drivers/power/power-test.cc
+++ b/src/devices/power/drivers/power/power-test.cc
@@ -139,10 +139,9 @@
   }
 
   fidl::ClientEnd<fuchsia_hardware_power::Device> ConnectDut() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_power::Device>();
-    EXPECT_OK(endpoints.status_value());
-    dut_->GetHandler()(std::move(endpoints->server));
-    return std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_power::Device>::Create();
+    dut_->GetHandler()(std::move(endpoints.server));
+    return std::move(endpoints.client);
   }
 
   static void RunSyncClientTask(fit::closure task) {
@@ -344,10 +343,9 @@
   auto dut_fixed =
       std::make_unique<PowerDevice>(fake_parent_.get(), 1, power_impl_->GetClient(),
                                     std::move(parent_power_client.value()), 1000, 1000, true);
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_power::Device>();
-  EXPECT_OK(endpoints.status_value());
-  dut_fixed->GetHandler()(std::move(endpoints->server));
-  fidl::WireSyncClient<fuchsia_hardware_power::Device> dut_client_2(std::move(endpoints->client));
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_power::Device>::Create();
+  dut_fixed->GetHandler()(std::move(endpoints.server));
+  fidl::WireSyncClient<fuchsia_hardware_power::Device> dut_client_2(std::move(endpoints.client));
 
   RunSyncClientTask([&dut_client_2]() {
     fidl::WireResult result = dut_client_2->RegisterPowerDomain(0, 0);
diff --git a/src/devices/power/drivers/ti-ina231/ti-ina231-test.cc b/src/devices/power/drivers/ti-ina231/ti-ina231-test.cc
index 07aff9b1..aaee101 100644
--- a/src/devices/power/drivers/ti-ina231/ti-ina231-test.cc
+++ b/src/devices/power/drivers/ti-ina231/ti-ina231-test.cc
@@ -69,11 +69,10 @@
 
   void SetUp() override {
     root_ = MockDevice::FakeRootParent();
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
 
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &fake_i2c_);
-    i2c_client_ = std::move(endpoints->client);
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &fake_i2c_);
+    i2c_client_ = std::move(endpoints.client);
 
     EXPECT_OK(loop_.StartThread());
   }
@@ -111,11 +110,10 @@
   EXPECT_OK(dut->DdkAdd("ti-ina231"));
   EXPECT_EQ(root()->child_count(), 1);
 
-  auto endpoints = fidl::CreateEndpoints<power_sensor_fidl::Device>();
-  ASSERT_OK(endpoints.status_value());
-  ASSERT_OK(dut->PowerSensorConnectServer(endpoints->server.TakeChannel()));
+  auto endpoints = fidl::Endpoints<power_sensor_fidl::Device>::Create();
+  ASSERT_OK(dut->PowerSensorConnectServer(endpoints.server.TakeChannel()));
   fidl::WireSyncClient client{
-      fidl::ClientEnd<power_sensor_fidl::Device>{std::move(endpoints->client)}};
+      fidl::ClientEnd<power_sensor_fidl::Device>{std::move(endpoints.client)}};
 
   {
     fake_i2c().set_power(4792);
@@ -226,11 +224,10 @@
 
   EXPECT_OK(dut->DdkAdd("ti-ina231"));
 
-  auto endpoints = fidl::CreateEndpoints<power_sensor_fidl::Device>();
-  ASSERT_OK(endpoints.status_value());
-  ASSERT_OK(dut->PowerSensorConnectServer(endpoints->server.TakeChannel()));
+  auto endpoints = fidl::Endpoints<power_sensor_fidl::Device>::Create();
+  ASSERT_OK(dut->PowerSensorConnectServer(endpoints.server.TakeChannel()));
   fidl::WireSyncClient client{
-      fidl::ClientEnd<power_sensor_fidl::Device>{std::move(endpoints->client)}};
+      fidl::ClientEnd<power_sensor_fidl::Device>{std::move(endpoints.client)}};
 
   {
     fake_i2c().set_bus_voltage(9200);
@@ -276,11 +273,10 @@
 
   EXPECT_OK(dut->DdkAdd("ti-ina231"));
 
-  auto endpoints = fidl::CreateEndpoints<power_sensor_fidl::Device>();
-  ASSERT_OK(endpoints.status_value());
-  ASSERT_OK(dut->PowerSensorConnectServer(endpoints->server.TakeChannel()));
+  auto endpoints = fidl::Endpoints<power_sensor_fidl::Device>::Create();
+  ASSERT_OK(dut->PowerSensorConnectServer(endpoints.server.TakeChannel()));
   fidl::WireSyncClient client{
-      fidl::ClientEnd<power_sensor_fidl::Device>{std::move(endpoints->client)}};
+      fidl::ClientEnd<power_sensor_fidl::Device>{std::move(endpoints.client)}};
 
   {
     auto response = client->GetSensorName();
diff --git a/src/devices/pwm/drivers/aml-pwm-init/aml-pwm-init-test.cc b/src/devices/pwm/drivers/aml-pwm-init/aml-pwm-init-test.cc
index 0da05a9..5aa6bfc 100644
--- a/src/devices/pwm/drivers/aml-pwm-init/aml-pwm-init-test.cc
+++ b/src/devices/pwm/drivers/aml-pwm-init/aml-pwm-init-test.cc
@@ -66,10 +66,9 @@
   }
 
   fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> BindServer() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pwm::Pwm>();
-    EXPECT_TRUE(endpoints.is_ok());
-    fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints->server), this);
-    return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_pwm::Pwm>::Create();
+    fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints.server), this);
+    return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints.client));
   }
 
   void VerifyAndClear() {
@@ -101,10 +100,9 @@
   auto wifi_gpio_client = wifi_gpio.SyncCall(&fake_gpio::FakeGpio::Connect);
   auto bt_gpio_client = bt_gpio.SyncCall(&fake_gpio::FakeGpio::Connect);
   // Create a clock connection, but don't connect it to anything.
-  zx::result clock_endpoints = fidl::CreateEndpoints<fuchsia_hardware_clock::Clock>();
-  EXPECT_TRUE(clock_endpoints.is_ok());
-  fidl::ClientEnd<fuchsia_hardware_clock::Clock> clock(std::move(clock_endpoints->client));
-  clock_endpoints->server.Close(ZX_OK);
+  auto clock_endpoints = fidl::Endpoints<fuchsia_hardware_clock::Clock>::Create();
+  fidl::ClientEnd<fuchsia_hardware_clock::Clock> clock(std::move(clock_endpoints.client));
+  clock_endpoints.server.Close(ZX_OK);
 
   pwm.SyncCall(&MockPwmServer::ExpectEnable);
   aml_pwm::mode_config two_timer = {
diff --git a/src/devices/pwm/drivers/aml-pwm/BUILD.gn b/src/devices/pwm/drivers/aml-pwm/BUILD.gn
index 35b52650..3852b93 100644
--- a/src/devices/pwm/drivers/aml-pwm/BUILD.gn
+++ b/src/devices/pwm/drivers/aml-pwm/BUILD.gn
@@ -54,7 +54,7 @@
   ]
   deps = [
     ":common",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//src/devices/testing/no_ddk",
     "//zircon/system/ulib/zx",
     "//zircon/system/ulib/zxtest",
diff --git a/src/devices/pwm/drivers/aml-pwm/aml-pwm-test.cc b/src/devices/pwm/drivers/aml-pwm/aml-pwm-test.cc
index 352e956..c735562 100644
--- a/src/devices/pwm/drivers/aml-pwm/aml-pwm-test.cc
+++ b/src/devices/pwm/drivers/aml-pwm/aml-pwm-test.cc
@@ -9,7 +9,7 @@
 #include <ddk/metadata/pwm.h>
 #include <fbl/alloc_checker.h>
 #include <fbl/array.h>
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 #include <soc/aml-common/aml-pwm-regs.h>
 
 namespace {
@@ -32,8 +32,13 @@
       zxlogf(ERROR, "%s: device object alloc failed", __func__);
       return nullptr;
     }
-    device->Init(std::move(mmio0), std::move(mmio1), std::move(mmio2), std::move(mmio3),
-                 std::move(mmio4), ids);
+    std::vector<fdf::MmioBuffer> mmios;
+    mmios.push_back(std::move(mmio0));
+    mmios.push_back(std::move(mmio1));
+    mmios.push_back(std::move(mmio2));
+    mmios.push_back(std::move(mmio3));
+    mmios.push_back(std::move(mmio4));
+    device->Init(std::move(mmios), ids);
 
     return device;
   }
@@ -96,8 +101,9 @@
     fdf::MmioBuffer mmio3(mock_mmio3_->GetMmioBuffer());
     fdf::MmioBuffer mmio4(mock_mmio4_->GetMmioBuffer());
     // Protect channel 3 for protect tests
-    std::vector<pwm_id_t> ids = {{0}, {1}, {2}, {3, /* init = */ false}, {4}, {5}, {6},
-                                 {7}, {8}, {9}};
+    std::vector<pwm_id_t> ids = {{.id = 0}, {.id = 1}, {.id = 2}, {.id = 3, .init = false},
+                                 {.id = 4}, {.id = 5}, {.id = 6}, {.id = 7},
+                                 {.id = 8}, {.id = 9}};
     pwm_ = FakeAmlPwmDevice::Create(std::move(mmio0), std::move(mmio1), std::move(mmio2),
                                     std::move(mmio3), std::move(mmio4), ids);
     ASSERT_NOT_NULL(pwm_);
diff --git a/src/devices/pwm/drivers/aml-pwm/aml-pwm.cc b/src/devices/pwm/drivers/aml-pwm/aml-pwm.cc
index 5d40afa..1f3657b 100644
--- a/src/devices/pwm/drivers/aml-pwm/aml-pwm.cc
+++ b/src/devices/pwm/drivers/aml-pwm/aml-pwm.cc
@@ -10,7 +10,9 @@
 #include <zircon/assert.h>
 #include <zircon/errors.h>
 
+#include <cstdint>
 #include <limits>
+#include <vector>
 
 #include <soc/aml-a1/a1-pwm.h>
 #include <soc/aml-a113/a113-pwm.h>
@@ -528,20 +530,58 @@
 }
 
 zx_status_t AmlPwmDevice::Init(zx_device_t* parent) {
-  zx_status_t status = ZX_OK;
+  ddk::PDevFidl pdev(parent);
+
+  pdev_device_info_t device_info;
+  auto status = pdev.GetDeviceInfo(&device_info);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "Failed to get GetDeviceInfo : %s", zx_status_get_string(status));
+    return status;
+  }
+
+  std::vector<fdf::MmioBuffer> mmios;
+  for (uint32_t i = 0; i < device_info.mmio_count; i++) {
+    std::optional<fdf::MmioBuffer> mmio;
+    status = pdev.MapMmio(i, &mmio);
+    if (status != ZX_OK) {
+      zxlogf(ERROR, "Failed to get mmio for index %d : %s", i, zx_status_get_string(status));
+      return status;
+    }
+    mmios.push_back(std::move(*mmio));
+  }
+
   auto pwm_ids = ddk::GetMetadataArray<pwm_id_t>(parent, DEVICE_METADATA_PWM_IDS);
   if (!pwm_ids.is_ok()) {
+    zxlogf(ERROR, "Failed to get PWM_IDS metadata : %s", pwm_ids.status_string());
     return pwm_ids.error_value();
   }
 
-  ddk::PDevFidl pdev(parent);
-  for (uint32_t i = 0;; i++) {
-    std::optional<fdf::MmioBuffer> mmio;
-    if ((status = pdev.MapMmio(i, &mmio)) != ZX_OK) {
-      break;
+  return Init(std::move(mmios), std::move(*pwm_ids));
+}
+
+zx_status_t AmlPwmDevice::Init(std::vector<fdf::MmioBuffer> mmios, std::vector<pwm_id_t> ids) {
+  // PWM IDs are expected to be continuous starting with 0. There will be 2 PWM ID per mmio.
+  max_pwm_id_ = (mmios.size() * 2) - 1;
+  std::vector<pwm_id_t> supported_pwm_ids;
+  supported_pwm_ids.resize(mmios.size() * 2lu);
+  for (uint32_t i = 0; i < supported_pwm_ids.size(); i++) {
+    supported_pwm_ids[i].id = i;
+  }
+
+  // Validate the pwm ids passed in and copy init information. The value of init is left as default
+  // for the rest of pwms which are not part of the metadata.
+  for (auto& pwm_id : ids) {
+    if (pwm_id.id > max_pwm_id_) {
+      zxlogf(ERROR, "Invalid PWM ID - %d in metadata. Maximum valid PWM ID is %d", pwm_id.id,
+             max_pwm_id_);
+      return ZX_ERR_INVALID_ARGS;
     }
-    pwms_.push_back(std::make_unique<AmlPwm>(*std::move(mmio), pwm_ids.value()[2 * i],
-                                             pwm_ids.value()[2 * i + 1]));
+    supported_pwm_ids[pwm_id.id].init = pwm_id.init;
+  }
+
+  for (uint32_t i = 0; i < mmios.size(); i++) {
+    pwms_.push_back(std::make_unique<AmlPwm>(std::move(mmios[i]), supported_pwm_ids[2lu * i],
+                                             supported_pwm_ids[2lu * i + 1]));
     pwms_.back()->Init();
   }
 
@@ -549,28 +589,28 @@
 }
 
 zx_status_t AmlPwmDevice::PwmImplGetConfig(uint32_t idx, pwm_config_t* out_config) {
-  if (idx >= pwms_.size() * 2 || out_config == nullptr) {
+  if (idx > max_pwm_id_ || out_config == nullptr) {
     return ZX_ERR_INVALID_ARGS;
   }
   return pwms_[idx / 2]->PwmImplGetConfig(idx % 2, out_config);
 }
 
 zx_status_t AmlPwmDevice::PwmImplSetConfig(uint32_t idx, const pwm_config_t* config) {
-  if (idx >= pwms_.size() * 2 || config == nullptr || config->mode_config_buffer == nullptr) {
+  if (idx > max_pwm_id_ || config == nullptr || config->mode_config_buffer == nullptr) {
     return ZX_ERR_INVALID_ARGS;
   }
   return pwms_[idx / 2]->PwmImplSetConfig(idx % 2, config);
 }
 
 zx_status_t AmlPwmDevice::PwmImplEnable(uint32_t idx) {
-  if (idx >= pwms_.size() * 2) {
+  if (idx > max_pwm_id_) {
     return ZX_ERR_INVALID_ARGS;
   }
   return pwms_[idx / 2]->PwmImplEnable(idx % 2);
 }
 
 zx_status_t AmlPwmDevice::PwmImplDisable(uint32_t idx) {
-  if (idx >= pwms_.size() * 2) {
+  if (idx > max_pwm_id_) {
     return ZX_ERR_INVALID_ARGS;
   }
   return pwms_[idx / 2]->PwmImplDisable(idx % 2);
diff --git a/src/devices/pwm/drivers/aml-pwm/aml-pwm.h b/src/devices/pwm/drivers/aml-pwm/aml-pwm.h
index fa32060..f6ce897 100644
--- a/src/devices/pwm/drivers/aml-pwm/aml-pwm.h
+++ b/src/devices/pwm/drivers/aml-pwm/aml-pwm.h
@@ -11,6 +11,7 @@
 #include <zircon/types.h>
 
 #include <array>
+#include <cstdint>
 #include <vector>
 
 #include <ddk/metadata/pwm.h>
@@ -36,8 +37,11 @@
     for (size_t i = 0; i < kPwmPairCount; i++) {
       mode_configs_[i].mode = Mode::kOff;
       mode_configs_[i].regular = {};
-      configs_[i] = {false, 0, 0.0, reinterpret_cast<uint8_t*>(&mode_configs_[i]),
-                     sizeof(mode_config)};
+      configs_[i] = {.polarity = false,
+                     .period_ns = 0,
+                     .duty_cycle = 0.0,
+                     .mode_config_buffer = reinterpret_cast<uint8_t*>(&mode_configs_[i]),
+                     .mode_config_size = sizeof(mode_config)};
       if (ids_[i].init) {
         SetMode(i, Mode::kOff);
       }
@@ -99,21 +103,7 @@
  protected:
   // For unit testing
   explicit AmlPwmDevice() : AmlPwmDeviceType(nullptr) {}
-  zx_status_t Init(fdf::MmioBuffer mmio0, fdf::MmioBuffer mmio1, fdf::MmioBuffer mmio2,
-                   fdf::MmioBuffer mmio3, fdf::MmioBuffer mmio4, std::vector<pwm_id_t> ids) {
-    pwms_.push_back(std::make_unique<AmlPwm>(std::move(mmio0), ids.at(0), ids.at(1)));
-    pwms_.back()->Init();
-    pwms_.push_back(std::make_unique<AmlPwm>(std::move(mmio1), ids.at(2), ids.at(3)));
-    pwms_.back()->Init();
-    pwms_.push_back(std::make_unique<AmlPwm>(std::move(mmio2), ids.at(4), ids.at(5)));
-    pwms_.back()->Init();
-    pwms_.push_back(std::make_unique<AmlPwm>(std::move(mmio3), ids.at(6), ids.at(7)));
-    pwms_.back()->Init();
-    pwms_.push_back(std::make_unique<AmlPwm>(std::move(mmio4), ids.at(8), ids.at(9)));
-    pwms_.back()->Init();
-
-    return ZX_OK;
-  }
+  zx_status_t Init(std::vector<fdf::MmioBuffer> mmios, std::vector<pwm_id_t> ids);
 
  private:
   explicit AmlPwmDevice(zx_device_t* parent) : AmlPwmDeviceType(parent) {}
@@ -121,6 +111,8 @@
   zx_status_t Init(zx_device_t* parent);
 
   std::vector<std::unique_ptr<AmlPwm>> pwms_;
+
+  uint32_t max_pwm_id_ = 0;
 };
 
 }  // namespace pwm
diff --git a/src/devices/radar/bin/radar-proxy/test/radar-proxy-test.h b/src/devices/radar/bin/radar-proxy/test/radar-proxy-test.h
index 2e6334d..e367ad628 100644
--- a/src/devices/radar/bin/radar-proxy/test/radar-proxy-test.h
+++ b/src/devices/radar/bin/radar-proxy/test/radar-proxy-test.h
@@ -168,25 +168,22 @@
     ASSERT_OK(driver_loop_.StartThread("Radar driver"));
 
     {
-      zx::result endpoints =
-          fidl::CreateEndpoints<fuchsia_hardware_radar::RadarBurstReaderProvider>();
-      ASSERT_TRUE(endpoints.is_ok());
+      auto endpoints = fidl::Endpoints<fuchsia_hardware_radar::RadarBurstReaderProvider>::Create();
 
-      dut_client_.Bind(std::move(endpoints->client));
+      dut_client_.Bind(std::move(endpoints.client));
       EXPECT_TRUE(fdf::RunOnDispatcherSync(proxy_loop_.dispatcher(), [&]() {
-                    fidl::BindServer(proxy_loop_.dispatcher(), std::move(endpoints->server), &dut_);
+                    fidl::BindServer(proxy_loop_.dispatcher(), std::move(endpoints.server), &dut_);
                   }).is_ok());
     }
 
     {
-      zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-      ASSERT_TRUE(endpoints.is_ok());
+      auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-      outgoing_client_ = std::move(endpoints->client);
+      outgoing_client_ = std::move(endpoints.client);
       EXPECT_TRUE(fdf::RunOnDispatcherSync(proxy_loop_.dispatcher(), [&]() {
                     outgoing_.emplace(proxy_loop_.dispatcher());
                     EXPECT_TRUE(dut_.AddProtocols(&(*outgoing_)).is_ok());
-                    EXPECT_TRUE(outgoing_->Serve(std::move(endpoints->server)).is_ok());
+                    EXPECT_TRUE(outgoing_->Serve(std::move(endpoints.server)).is_ok());
                   }).is_ok());
     }
   }
@@ -213,13 +210,11 @@
 
   void ConnectToFirstRadarDevice(ConnectDeviceCallback connect_device) override {
     if (!provider_connect_fail_) {
-      zx::result endpoints =
-          fidl::CreateEndpoints<fuchsia_hardware_radar::RadarBurstReaderProvider>();
-      ASSERT_TRUE(endpoints.is_ok());
+      auto endpoints = fidl::Endpoints<fuchsia_hardware_radar::RadarBurstReaderProvider>::Create();
 
-      fake_driver_.Bind(std::move(endpoints->server));
+      fake_driver_.Bind(std::move(endpoints.server));
       // This may not succeed if we've told the radar driver to return errors for certain calls.
-      connect_device(std::move(endpoints->client));
+      connect_device(std::move(endpoints.client));
     }
 
     sync_completion_signal(&device_connected_);
diff --git a/src/devices/radar/bin/radar-proxy/test/radar-reader-proxy-test.cc b/src/devices/radar/bin/radar-proxy/test/radar-reader-proxy-test.cc
index 93483909..eed5baf 100644
--- a/src/devices/radar/bin/radar-proxy/test/radar-reader-proxy-test.cc
+++ b/src/devices/radar/bin/radar-proxy/test/radar-reader-proxy-test.cc
@@ -459,11 +459,10 @@
     AddRadarDevice();
 
     {
-      zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_radar::RadarBurstReader>();
-      ASSERT_TRUE(endpoints.is_ok());
-      reader_client_.emplace(std::move(endpoints->client), loop_.dispatcher(),
+      auto endpoints = fidl::Endpoints<fuchsia_hardware_radar::RadarBurstReader>::Create();
+      reader_client_.emplace(std::move(endpoints.client), loop_.dispatcher(),
                              fit::bind_member<&RadarReaderProxyInjectionTest::OnBurst>(this));
-      EXPECT_TRUE(dut_client_->Connect(std::move(endpoints->server)).is_ok());
+      EXPECT_TRUE(dut_client_->Connect(std::move(endpoints.server)).is_ok());
     }
 
     {
@@ -481,16 +480,15 @@
     }
 
     {
-      zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_radar::RadarBurstInjector>();
-      ASSERT_TRUE(endpoints.is_ok());
-      injector_client_.emplace(std::move(endpoints->client), loop_.dispatcher(),
+      auto endpoints = fidl::Endpoints<fuchsia_hardware_radar::RadarBurstInjector>::Create();
+      injector_client_.emplace(std::move(endpoints.client), loop_.dispatcher(),
                                [&](uint32_t bursts_id) {
                                  received_vmo_ids_.push_back(bursts_id);
                                  if (on_bursts_delivered_) {
                                    on_bursts_delivered_();
                                  }
                                });
-      BindInjector(std::move(endpoints->server));
+      BindInjector(std::move(endpoints.server));
     }
   }
 
diff --git a/src/devices/radar/tests/radar-integration-test/radar-injection-integration-test.cc b/src/devices/radar/tests/radar-integration-test/radar-injection-integration-test.cc
index d46dc26..e465a6d 100644
--- a/src/devices/radar/tests/radar-integration-test/radar-injection-integration-test.cc
+++ b/src/devices/radar/tests/radar-integration-test/radar-injection-integration-test.cc
@@ -212,24 +212,22 @@
       std::move(provider_client_end.value()));
 
   {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_radar::RadarBurstReader>();
-    ASSERT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_radar::RadarBurstReader>::Create();
 
-    const auto result = provider_client->Connect(std::move(endpoints->server));
+    const auto result = provider_client->Connect(std::move(endpoints.server));
     EXPECT_TRUE(result.is_ok());
 
-    reader1.emplace(std::move(endpoints->client), loop.dispatcher(), on_test_event);
+    reader1.emplace(std::move(endpoints.client), loop.dispatcher(), on_test_event);
     EXPECT_NO_FAILURES(reader1->RegisterVmos(10));
   }
 
   {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_radar::RadarBurstReader>();
-    ASSERT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_radar::RadarBurstReader>::Create();
 
-    const auto result = provider_client->Connect(std::move(endpoints->server));
+    const auto result = provider_client->Connect(std::move(endpoints.server));
     EXPECT_TRUE(result.is_ok());
 
-    reader2.emplace(std::move(endpoints->client), loop.dispatcher(), on_test_event);
+    reader2.emplace(std::move(endpoints.client), loop.dispatcher(), on_test_event);
     EXPECT_NO_FAILURES(reader2->RegisterVmos(10));
   }
 
@@ -309,13 +307,12 @@
     fidl::SyncClient<fuchsia_hardware_radar::RadarBurstReaderProvider> provider_client(
         std::move(provider_client_end.value()));
 
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_radar::RadarBurstReader>();
-    ASSERT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_radar::RadarBurstReader>::Create();
 
-    const auto result = provider_client->Connect(std::move(endpoints->server));
+    const auto result = provider_client->Connect(std::move(endpoints.server));
     EXPECT_TRUE(result.is_ok());
 
-    reader.emplace(std::move(endpoints->client), loop.dispatcher(), on_test_event);
+    reader.emplace(std::move(endpoints.client), loop.dispatcher(), on_test_event);
     EXPECT_NO_FAILURES(reader->RegisterVmos(10));
   }
 
diff --git a/src/devices/radar/tests/radar-integration-test/radar-integration-test.cc b/src/devices/radar/tests/radar-integration-test/radar-integration-test.cc
index 623c658..6d4b905 100644
--- a/src/devices/radar/tests/radar-integration-test/radar-integration-test.cc
+++ b/src/devices/radar/tests/radar-integration-test/radar-integration-test.cc
@@ -76,9 +76,7 @@
     fidl::WireSyncClient<BurstReaderProvider> provider_client(
         std::move(provider_client_end_or.value()));
 
-    zx::result endpoints = fidl::CreateEndpoints<BurstReader>();
-    ASSERT_OK(endpoints.status_value());
-    auto [client_end, server_end] = std::move(*endpoints);
+    auto [client_end, server_end] = fidl::Endpoints<BurstReader>::Create();
 
     const auto result = provider_client->Connect(std::move(server_end));
     ASSERT_OK(result.status());
diff --git a/src/devices/ram/drivers/aml-ram/aml-ram-test.cc b/src/devices/ram/drivers/aml-ram/aml-ram-test.cc
index 4f33a9d..199f314 100644
--- a/src/devices/ram/drivers/aml-ram/aml-ram-test.cc
+++ b/src/devices/ram/drivers/aml-ram/aml-ram-test.cc
@@ -60,10 +60,9 @@
 
     dmc_offsets_ = g12_dmc_regs;
 
-    zx::result outgoing_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(outgoing_endpoints);
+    auto outgoing_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     ASSERT_OK(incoming_loop_.StartThread("incoming-ns-thread"));
-    incoming_.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints->server)](
+    incoming_.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints.server)](
                            IncomingNamespace* infra) mutable {
       infra->pdev_server.SetConfig(std::move(config));
       ASSERT_OK(infra->outgoing.AddService<fuchsia_hardware_platform_device::Service>(
@@ -72,7 +71,7 @@
     });
     ASSERT_NO_FATAL_FAILURE();
     fake_parent_->AddFidlService(fuchsia_hardware_platform_device::Service::Name,
-                                 std::move(outgoing_endpoints->client));
+                                 std::move(outgoing_endpoints.client));
 
     EXPECT_OK(amlogic_ram::AmlRam::Create(nullptr, fake_parent_.get()));
   }
@@ -86,11 +85,10 @@
     auto* child = fake_parent_->GetLatestChild();
     EXPECT_NOT_NULL(child);
 
-    auto endpoints = fidl::CreateEndpoints<ram_metrics::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    binding_ = fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server),
+    auto endpoints = fidl::Endpoints<ram_metrics::Device>::Create();
+    binding_ = fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server),
                                 child->GetDeviceContext<AmlRam>());
-    return std::move(endpoints->client);
+    return std::move(endpoints.client);
   }
 
   void InjectInterrupt() { irq_signaller_->trigger(0, zx::time()); }
diff --git a/src/devices/registers/drivers/registers/registers.cc b/src/devices/registers/drivers/registers/registers.cc
index 7ffbd1b..5a8cab2 100644
--- a/src/devices/registers/drivers/registers/registers.cc
+++ b/src/devices/registers/drivers/registers/registers.cc
@@ -188,19 +188,16 @@
                   .properties(arena, std::move(properties))
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create controller endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
   {
     fidl::WireResult result =
-        fidl::WireCall(node())->AddChild(args, std::move(controller_endpoints->server), {});
+        fidl::WireCall(node())->AddChild(args, std::move(controller_endpoints.server), {});
     if (!result.ok()) {
       FDF_LOG(ERROR, "Failed to add child %s", result.FormatDescription().c_str());
       return zx::error(result.status());
     }
   }
-  reg.controller_.Bind(std::move(controller_endpoints->client));
+  reg.controller_.Bind(std::move(controller_endpoints.client));
 
   return zx::ok();
 }
diff --git a/src/devices/registers/testing/mock-registers/mock-registers-test.cc b/src/devices/registers/testing/mock-registers/mock-registers-test.cc
index 16e457b..1a9d070 100644
--- a/src/devices/registers/testing/mock-registers/mock-registers-test.cc
+++ b/src/devices/registers/testing/mock-registers/mock-registers-test.cc
@@ -17,9 +17,7 @@
 
     registers_ = std::make_unique<MockRegisters>(loop_.dispatcher());
 
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_registers::Device>();
-    ASSERT_OK(endpoints);
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_hardware_registers::Device>::Create();
     registers_->Init(std::move(server_end));
     client_.Bind(std::move(client_end));
   }
diff --git a/src/devices/securemem/drivers/aml-securemem/device.cc b/src/devices/securemem/drivers/aml-securemem/device.cc
index 09fedcb..c81b63b 100644
--- a/src/devices/securemem/drivers/aml-securemem/device.cc
+++ b/src/devices/securemem/drivers/aml-securemem/device.cc
@@ -83,8 +83,8 @@
   return status;
 }
 
-// TODO(https://fxbug.dev/42112465): Determine if we only ever use mexec to reboot from zedboot into a
-// netboot(ed) image. Iff so, we could avoid some complexity here by not loading aml-securemem in
+// TODO(https://fxbug.dev/42112465): Determine if we only ever use mexec to reboot from zedboot into
+// a netboot(ed) image. Iff so, we could avoid some complexity here by not loading aml-securemem in
 // zedboot, and not handling suspend(mexec) here, and not having UnregisterSecureMem().
 void AmlogicSecureMemDevice::DdkSuspend(ddk::SuspendTxn txn) {
   LOG(DEBUG, "aml-securemem: begin DdkSuspend() - Suspend Reason: %d", txn.suspend_reason());
@@ -239,11 +239,7 @@
 zx_status_t AmlogicSecureMemDevice::CreateAndServeSysmemTee() {
   ZX_DEBUG_ASSERT(tee_proto_client_.is_valid());
 
-  zx::result tee_endpoints = fidl::CreateEndpoints<fuchsia_tee::Application>();
-  if (!tee_endpoints.is_ok()) {
-    return tee_endpoints.status_value();
-  }
-  auto& [tee_client, tee_server] = tee_endpoints.value();
+  auto [tee_client, tee_server] = fidl::Endpoints<fuchsia_tee::Application>::Create();
   sysmem_secure_mem_server_.emplace(async_patterns::PassDispatcher, tee_client.TakeChannel());
 
   const fuchsia_tee::wire::Uuid kSecmemUuid = {
@@ -258,12 +254,8 @@
     }
   }
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_sysmem::SecureMem>();
-  if (endpoints.is_error()) {
-    LOG(ERROR, "failed to create sysmem tee channels - status: %d", endpoints.status_value());
-    return endpoints.status_value();
-  }
-  auto& [sysmem_secure_mem_client, sysmem_secure_mem_server] = endpoints.value();
+  auto [sysmem_secure_mem_client, sysmem_secure_mem_server] =
+      fidl::Endpoints<fuchsia_sysmem::SecureMem>::Create();
 
   sysmem_secure_mem_server_.AsyncCall(
       &SysmemSecureMemServer::Bind, std::move(sysmem_secure_mem_server),
diff --git a/src/devices/securemem/drivers/aml-securemem/test/aml-securemem-test.cc b/src/devices/securemem/drivers/aml-securemem/test/aml-securemem-test.cc
index 34dbee09..7fc70aa 100644
--- a/src/devices/securemem/drivers/aml-securemem/test/aml-securemem-test.cc
+++ b/src/devices/securemem/drivers/aml-securemem/test/aml-securemem-test.cc
@@ -96,10 +96,9 @@
     pdev_.SyncCall(&fake_pdev::FakePDevFidl::SetConfig, std::move(config));
     auto pdev_handler = pdev_.SyncCall(&fake_pdev::FakePDevFidl::GetInstanceHandler,
                                        async_patterns::PassDispatcher);
-    auto pdev_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(pdev_endpoints.is_ok());
+    auto pdev_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     root_->AddFidlService(fuchsia_hardware_platform_device::Service::Name,
-                          std::move(pdev_endpoints->client), "pdev");
+                          std::move(pdev_endpoints.client), "pdev");
 
     // Create sysmem fragment
     auto sysmem_handler = sysmem_.SyncCall(&FakeSysmem::CreateInstanceHandler);
@@ -110,14 +109,13 @@
 
     // Create tee fragment
     auto tee_handler = tee_.SyncCall(&FakeTee::CreateInstanceHandler);
-    auto tee_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(tee_endpoints.is_ok());
-    root_->AddFidlService(fuchsia_hardware_tee::Service::Name, std::move(tee_endpoints->client),
+    auto tee_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    root_->AddFidlService(fuchsia_hardware_tee::Service::Name, std::move(tee_endpoints.client),
                           "tee");
 
-    outgoing_.SyncCall([pdev_server = std::move(pdev_endpoints->server),
+    outgoing_.SyncCall([pdev_server = std::move(pdev_endpoints.server),
                         sysmem_server = std::move(sysmem_endpoints->server),
-                        tee_server = std::move(tee_endpoints->server),
+                        tee_server = std::move(tee_endpoints.server),
                         pdev_handler = std::move(pdev_handler),
                         sysmem_handler = std::move(sysmem_handler),
                         tee_handler = std::move(tee_handler)](
diff --git a/src/devices/serial/OWNERS b/src/devices/serial/OWNERS
index b816969..aa9706f 100644
--- a/src/devices/serial/OWNERS
+++ b/src/devices/serial/OWNERS
@@ -1,2 +1 @@
-bbosak@google.com
-surajmalhotra@google.com
+include /src/devices/platform/OWNERS
diff --git a/src/devices/serial/drivers/aml-uart/tests/aml-uart-dfv1-test.cc b/src/devices/serial/drivers/aml-uart/tests/aml-uart-dfv1-test.cc
index 2b1289a..0cb49e5 100644
--- a/src/devices/serial/drivers/aml-uart/tests/aml-uart-dfv1-test.cc
+++ b/src/devices/serial/drivers/aml-uart/tests/aml-uart-dfv1-test.cc
@@ -35,11 +35,10 @@
     ASSERT_OK(zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &config.irqs[0]));
     state_.set_irq_signaller(config.irqs[0].borrow());
 
-    zx::result pdev = fidl::CreateEndpoints<fuchsia_hardware_platform_device::Device>();
-    ASSERT_OK(pdev);
+    auto pdev = fidl::Endpoints<fuchsia_hardware_platform_device::Device>::Create();
     ASSERT_OK(incoming_loop_.StartThread("incoming-ns-thread"));
     incoming_.SyncCall([config = std::move(config),
-                        server = std::move(pdev->server)](IncomingNamespace* infra) mutable {
+                        server = std::move(pdev.server)](IncomingNamespace* infra) mutable {
       infra->pdev_server.SetConfig(std::move(config));
       infra->pdev_server.Connect(std::move(server));
     });
@@ -47,7 +46,7 @@
 
     auto uart = std::make_unique<serial::AmlUartV1>(fake_parent_.get());
     zx_status_t status =
-        uart->Init(ddk::PDevFidl(std::move(pdev->client)), kSerialInfo, state_.GetMmio());
+        uart->Init(ddk::PDevFidl(std::move(pdev.client)), kSerialInfo, state_.GetMmio());
     ASSERT_OK(status);
     device_ = uart.get();
     // The AmlUart* is now owned by the fake_ddk.
diff --git a/src/devices/serial/drivers/ftdi/test/ftdi-test.cc b/src/devices/serial/drivers/ftdi/test/ftdi-test.cc
index 11a705b..1aaa185 100644
--- a/src/devices/serial/drivers/ftdi/test/ftdi-test.cc
+++ b/src/devices/serial/drivers/ftdi/test/ftdi-test.cc
@@ -92,9 +92,7 @@
   zx::result result = component::ConnectAt<fuchsia_hardware_serial::DeviceProxy>(
       fdio_cpp::UnownedFdioCaller(bus_->GetRootFd()).directory(), devpath_.c_str());
   ASSERT_OK(result.status_value());
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_serial::Device>();
-  ASSERT_OK(endpoints);
-  auto& [client_end, server] = endpoints.value();
+  auto [client_end, server] = fidl::Endpoints<fuchsia_hardware_serial::Device>::Create();
   ASSERT_OK(fidl::WireCall(result.value())->GetChannel(std::move(server)));
 
   auto assert_read_with_timeout = [&client_end = client_end](cpp20::span<uint8_t> write_data) {
diff --git a/src/devices/serial/drivers/serial-async/tests/serial-async-test.cc b/src/devices/serial/drivers/serial-async/tests/serial-async-test.cc
index 8665389..ecad14e 100644
--- a/src/devices/serial/drivers/serial-async/tests/serial-async-test.cc
+++ b/src/devices/serial/drivers/serial-async/tests/serial-async-test.cc
@@ -172,10 +172,9 @@
     device_ = new serial::SerialDevice(tester_.root().get());
     ASSERT_OK(device_->Init());
     loop_.StartThread();
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_serial::Device>();
-    ASSERT_OK(endpoints.status_value());
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), device_);
-    fidl_.Bind(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_serial::Device>::Create();
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), device_);
+    fidl_.Bind(std::move(endpoints.client));
   }
 
   void TearDown() override {
diff --git a/src/devices/serial/drivers/serial/tests/serial-test.cc b/src/devices/serial/drivers/serial/tests/serial-test.cc
index e24e5cd..d8ced2a 100644
--- a/src/devices/serial/drivers/serial/tests/serial-test.cc
+++ b/src/devices/serial/drivers/serial/tests/serial-test.cc
@@ -220,9 +220,7 @@
 
 TEST_F(SerialDeviceTest, Read) {
   async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_serial::Device>();
-  ASSERT_OK(endpoints);
-  auto& [client_end, server] = endpoints.value();
+  auto [client_end, server] = fidl::Endpoints<fuchsia_hardware_serial::Device>::Create();
   fidl::BindServer(loop.dispatcher(), std::move(server), device());
   fidl::WireClient client(std::move(client_end), loop.dispatcher());
 
@@ -247,9 +245,7 @@
 
 TEST_F(SerialDeviceTest, Write) {
   async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_serial::Device>();
-  ASSERT_OK(endpoints);
-  auto& [client_end, server] = endpoints.value();
+  auto [client_end, server] = fidl::Endpoints<fuchsia_hardware_serial::Device>::Create();
   fidl::BindServer(loop.dispatcher(), std::move(server), device());
   fidl::WireClient client(std::move(client_end), loop.dispatcher());
 
diff --git a/src/devices/serial/drivers/usb-cdc-acm/usb-cdc-acm-test.cc b/src/devices/serial/drivers/usb-cdc-acm/usb-cdc-acm-test.cc
index 6f1a1c0..2349b19 100644
--- a/src/devices/serial/drivers/usb-cdc-acm/usb-cdc-acm-test.cc
+++ b/src/devices/serial/drivers/usb-cdc-acm/usb-cdc-acm-test.cc
@@ -87,9 +87,7 @@
   zx::result result = component::ConnectAt<fuchsia_hardware_serial::DeviceProxy>(
       fdio_cpp::UnownedFdioCaller(bus_->GetRootFd()).directory(), devpath_.c_str());
   ASSERT_OK(result.status_value());
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_serial::Device>();
-  ASSERT_OK(endpoints);
-  auto& [client_end, server] = endpoints.value();
+  auto [client_end, server] = fidl::Endpoints<fuchsia_hardware_serial::Device>::Create();
   ASSERT_OK(fidl::WireCall(result.value())->GetChannel(std::move(server)));
 
   auto assert_read_with_timeout = [&client_end = client_end](cpp20::span<uint8_t> write_data) {
diff --git a/src/devices/spi/bin/spiutil/spiutil.cc b/src/devices/spi/bin/spiutil/spiutil.cc
index b9eba20..3584083 100644
--- a/src/devices/spi/bin/spiutil/spiutil.cc
+++ b/src/devices/spi/bin/spiutil/spiutil.cc
@@ -71,12 +71,7 @@
     fprintf(stderr, "component::Connect(%s): %s\n", argv[1], controller.status_string());
     return -1;
   }
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_spi::Device>();
-  if (endpoints.is_error()) {
-    fprintf(stderr, "fidl::CreateEndpoints(): %s\n", endpoints.status_string());
-    return -1;
-  }
-  auto& [device, server] = endpoints.value();
+  auto [device, server] = fidl::Endpoints<fuchsia_hardware_spi::Device>::Create();
 
   const fidl::Status result = fidl::WireCall(controller.value())->OpenSession(std::move(server));
   if (!result.ok()) {
diff --git a/src/devices/spi/drivers/aml-spi/BUILD.gn b/src/devices/spi/drivers/aml-spi/BUILD.gn
index 485ef97..521c18c 100644
--- a/src/devices/spi/drivers/aml-spi/BUILD.gn
+++ b/src/devices/spi/drivers/aml-spi/BUILD.gn
@@ -51,17 +51,21 @@
 test("aml-spi-test-bin") {
   output_name = "aml-spi-test"
   sources = [
-    "aml-spi-test.cc",
     "aml-spi.cc",
+    "tests/aml-spi-bti-test.cc",
+    "tests/aml-spi-clock-mode-test.cc",
+    "tests/aml-spi-shutdown-test.cc",
+    "tests/aml-spi-test.cc",
   ]
   deps = [
     ":common",
-    "//sdk/lib/driver/testing/cpp",
+    "//sdk/lib/driver/testing/cpp:gtest_fixture",
     "//src/devices/gpio/testing/fake-gpio",
     "//src/devices/registers/testing/mock-registers",
     "//src/devices/testing/fake-bti",
     "//src/devices/testing/fake-mmio-reg",
-    "//zircon/system/ulib/zxtest",
+    "//src/lib/fxl/test:gtest_main",
+    "//src/lib/testing/predicates",
   ]
 
   # TODO(https://fxbug.dev/42136089): delete the below and fix compiler warnings
diff --git a/src/devices/spi/drivers/aml-spi/aml-spi-test.cc b/src/devices/spi/drivers/aml-spi/aml-spi-test.cc
deleted file mode 100644
index facc99f..0000000
--- a/src/devices/spi/drivers/aml-spi/aml-spi-test.cc
+++ /dev/null
@@ -1,1765 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "aml-spi.h"
-
-#include <endian.h>
-#include <fidl/fuchsia.hardware.platform.device/cpp/wire_test_base.h>
-#include <fidl/fuchsia.scheduler/cpp/wire.h>
-#include <lib/ddk/metadata.h>
-#include <lib/driver/testing/cpp/driver_lifecycle.h>
-#include <lib/driver/testing/cpp/driver_runtime.h>
-#include <lib/driver/testing/cpp/test_environment.h>
-#include <lib/driver/testing/cpp/test_node.h>
-#include <lib/fake-bti/bti.h>
-#include <lib/zx/clock.h>
-#include <lib/zx/vmo.h>
-#include <zircon/errors.h>
-
-#include <fake-mmio-reg/fake-mmio-reg.h>
-#include <zxtest/zxtest.h>
-
-#include "registers.h"
-#include "src/devices/gpio/testing/fake-gpio/fake-gpio.h"
-#include "src/devices/registers/testing/mock-registers/mock-registers.h"
-
-namespace spi {
-
-class TestAmlSpiDriver : public AmlSpiDriver {
- public:
-  TestAmlSpiDriver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher dispatcher)
-      : AmlSpiDriver(std::move(start_args), std::move(dispatcher)),
-        mmio_region_(sizeof(uint32_t), 17) {}
-
-  static DriverRegistration GetDriverRegistration() {
-    // Use a custom DriverRegistration to create the DUT. Without this, the non-test implementation
-    // will be used by default.
-    return FUCHSIA_DRIVER_REGISTRATION_V1(fdf_internal::DriverServer<TestAmlSpiDriver>::initialize,
-                                          fdf_internal::DriverServer<TestAmlSpiDriver>::destroy);
-  }
-
-  ddk_fake::FakeMmioRegRegion& mmio() { return mmio_region_; }
-
-  uint32_t conreg() const { return conreg_; }
-  uint32_t enhance_cntl() const { return enhance_cntl_; }
-  uint32_t testreg() const { return testreg_; }
-
- protected:
-  fpromise::promise<fdf::MmioBuffer, zx_status_t> MapMmio(
-      fidl::WireClient<fuchsia_hardware_platform_device::Device>& pdev, uint32_t mmio_id) override {
-    return fpromise::make_promise([this]() -> fpromise::result<fdf::MmioBuffer, zx_status_t> {
-      // Set the transfer complete bit so the driver doesn't get stuck waiting on the interrupt.
-      mmio_region_[AML_SPI_STATREG].SetReadCallback(
-          []() { return StatReg::Get().FromValue(0).set_tc(1).set_te(1).set_rr(1).reg_value(); });
-
-      mmio_region_[AML_SPI_CONREG].SetWriteCallback([this](uint32_t value) { conreg_ = value; });
-      mmio_region_[AML_SPI_CONREG].SetReadCallback([this]() { return conreg_; });
-      mmio_region_[AML_SPI_ENHANCE_CNTL].SetWriteCallback(
-          [this](uint32_t value) { enhance_cntl_ = value; });
-      mmio_region_[AML_SPI_TESTREG].SetWriteCallback([this](uint32_t value) { testreg_ = value; });
-
-      return fpromise::ok(mmio_region_.GetMmioBuffer());
-    });
-  }
-
- private:
-  ddk_fake::FakeMmioRegRegion mmio_region_;
-  uint32_t conreg_{};
-  uint32_t enhance_cntl_{};
-  uint32_t testreg_{};
-};
-
-class FakePDev : public fidl::testing::WireTestBase<fuchsia_hardware_platform_device::Device> {
- public:
-  fuchsia_hardware_platform_device::Service::InstanceHandler GetInstanceHandler(
-      async_dispatcher_t* dispatcher) {
-    return fuchsia_hardware_platform_device::Service::InstanceHandler({
-        .device = binding_group_.CreateHandler(this, dispatcher, fidl::kIgnoreBindingClosure),
-    });
-  }
-
-  void set_interrupt(zx::interrupt interrupt) { interrupt_ = std::move(interrupt); }
-
-  void set_bti(zx::bti bti) { bti_ = std::move(bti); }
-
- private:
-  void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override {}
-
-  void GetInterruptById(
-      fuchsia_hardware_platform_device::wire::DeviceGetInterruptByIdRequest* request,
-      GetInterruptByIdCompleter::Sync& completer) override {
-    if (request->index != 0 || !interrupt_) {
-      return completer.ReplyError(ZX_ERR_NOT_FOUND);
-    }
-
-    zx::interrupt out_interrupt;
-    zx_status_t status = interrupt_.duplicate(ZX_RIGHT_SAME_RIGHTS, &out_interrupt);
-    if (status == ZX_OK) {
-      completer.ReplySuccess(std::move(out_interrupt));
-    } else {
-      completer.ReplyError(status);
-    }
-  }
-
-  void GetBtiById(fuchsia_hardware_platform_device::wire::DeviceGetBtiByIdRequest* request,
-                  GetBtiByIdCompleter::Sync& completer) override {
-    if (request->index != 0 || !bti_) {
-      return completer.ReplyError(ZX_ERR_NOT_FOUND);
-    }
-
-    zx::bti out_bti;
-    zx_status_t status = bti_.duplicate(ZX_RIGHT_SAME_RIGHTS, &out_bti);
-    if (status == ZX_OK) {
-      completer.ReplySuccess(std::move(out_bti));
-    } else {
-      completer.ReplyError(status);
-    }
-  }
-
-  zx::interrupt interrupt_;
-  zx::bti bti_;
-  fidl::ServerBindingGroup<fuchsia_hardware_platform_device::Device> binding_group_;
-};
-
-class AmlSpiTest : public zxtest::Test {
- public:
-  AmlSpiTest()
-      : registers_(fdf::Dispatcher::GetCurrent()->async_dispatcher()),
-        node_server_("root"),
-        dut_(TestAmlSpiDriver::GetDriverRegistration()) {}
-
-  virtual void SetUpInterrupt() {
-    ASSERT_OK(zx::interrupt::create({}, 0, ZX_INTERRUPT_VIRTUAL, &interrupt_));
-    zx::interrupt dut_interrupt;
-    ASSERT_OK(interrupt_.duplicate(ZX_RIGHT_SAME_RIGHTS, &dut_interrupt));
-    pdev_server_.set_interrupt(std::move(dut_interrupt));
-    interrupt_.trigger(0, zx::clock::get_monotonic());
-  }
-
-  virtual void SetUpBti() {}
-
-  virtual bool SetupResetRegister() { return true; }
-
-  virtual void SetMetadata(compat::DeviceServer& compat) {
-    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
-  }
-
-  void SetUp() override {
-    SetUpInterrupt();
-    SetUpBti();
-
-    zx::result start_args = node_server_.CreateStartArgsAndServe();
-    ASSERT_TRUE(start_args.is_ok());
-
-    driver_outgoing_ = std::move(start_args->outgoing_directory_client);
-
-    ASSERT_TRUE(
-        test_environment_.Initialize(std::move(start_args->incoming_directory_server)).is_ok());
-
-    start_args_ = std::move(start_args->start_args);
-
-    auto& directory = test_environment_.incoming_directory();
-
-    auto result = directory.AddService<fuchsia_hardware_platform_device::Service>(
-        pdev_server_.GetInstanceHandler(fdf::Dispatcher::GetCurrent()->async_dispatcher()), "pdev");
-    ASSERT_TRUE(result.is_ok());
-
-    SetMetadata(compat_);
-    compat_.Init("pdev", {});
-    EXPECT_OK(compat_.Serve(fdf::Dispatcher::GetCurrent()->async_dispatcher(), &directory));
-
-    // Servec a second compat instance at default in order to satisfy AmlSpiDriver's compat server.
-    // Without this, metadata doesn't get forwarded.
-    compat_default_.Init("default", {});
-    EXPECT_OK(compat_default_.Serve(fdf::Dispatcher::GetCurrent()->async_dispatcher(), &directory));
-
-    result = directory.AddService<fuchsia_hardware_gpio::Service>(gpio_.CreateInstanceHandler(),
-                                                                  "gpio-cs-2");
-    ASSERT_TRUE(result.is_ok());
-
-    result = directory.AddService<fuchsia_hardware_gpio::Service>(gpio_.CreateInstanceHandler(),
-                                                                  "gpio-cs-3");
-    ASSERT_TRUE(result.is_ok());
-
-    result = directory.AddService<fuchsia_hardware_gpio::Service>(gpio_.CreateInstanceHandler(),
-                                                                  "gpio-cs-5");
-    ASSERT_TRUE(result.is_ok());
-
-    gpio_.SetCurrentState(fake_gpio::State{.polarity = fuchsia_hardware_gpio::GpioPolarity::kHigh,
-                                           .sub_state = fake_gpio::WriteSubState{.value = 0}});
-    gpio_.SetWriteCallback([this](fake_gpio::FakeGpio& gpio) {
-      if (gpio_writes_.empty()) {
-        EXPECT_FALSE(gpio_writes_.empty());
-        return ZX_ERR_INTERNAL;
-      }
-      auto [status, value] = gpio_writes_.front();
-      gpio_writes_.pop();
-      if (status != ZX_OK) {
-        EXPECT_EQ(value, gpio_.GetWriteValue());
-      }
-      return status;
-    });
-
-    if (SetupResetRegister()) {
-      auto result =
-          test_environment_.incoming_directory().AddService<fuchsia_hardware_registers::Service>(
-              registers_.GetInstanceHandler(), "reset");
-      ASSERT_TRUE(result.is_ok());
-    }
-
-    registers_.ExpectWrite<uint32_t>(0x1c, 1 << 1, 1 << 1);
-  }
-
-  void TearDown() override {
-    zx::result prepare_stop_result = runtime_.RunToCompletion(dut_.PrepareStop());
-    EXPECT_OK(prepare_stop_result.status_value());
-    EXPECT_TRUE(dut_.Stop().is_ok());
-  }
-
-  void ExpectGpioWrite(zx_status_t status, uint8_t value) { gpio_writes_.emplace(status, value); }
-
-  void VerifyGpioAndClear() {
-    EXPECT_EQ(gpio_writes_.size(), 0);
-    gpio_writes_ = {};
-  }
-
-  ddk_fake::FakeMmioRegRegion& mmio() { return dut_->mmio(); }
-  bool ControllerReset() {
-    zx_status_t status = registers_.VerifyAll();
-    if (status == ZX_OK) {
-      // Always keep a single expectation in the queue, that way we can verify when the controller
-      // is not reset.
-      registers_.ExpectWrite<uint32_t>(0x1c, 1 << 1, 1 << 1);
-    }
-
-    return status == ZX_OK;
-  }
-
- protected:
-  zx::result<fdf::ClientEnd<fuchsia_hardware_spiimpl::SpiImpl>> GetFidlClient() {
-    // Connect to the driver through its outgoing directory and get a spiimpl client.
-    zx::result svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    if (svc_endpoints.is_error()) {
-      return svc_endpoints.take_error();
-    }
-
-    EXPECT_OK(fdio_open_at(driver_outgoing_.handle()->get(), "/svc",
-                           static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
-                           svc_endpoints->server.TakeChannel().release()));
-
-    return fdf::internal::DriverTransportConnect<fuchsia_hardware_spiimpl::Service::Device>(
-        svc_endpoints->client, component::kDefaultInstance);
-  }
-
-  zx::result<fuchsia_scheduler::RoleName> GetSchedulerRoleName() {
-    zx::result svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    if (svc_endpoints.is_error()) {
-      return svc_endpoints.take_error();
-    }
-
-    EXPECT_OK(fdio_open_at(driver_outgoing_.handle()->get(), "/svc",
-                           static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
-                           svc_endpoints->server.TakeChannel().release()));
-
-    zx::result compat_client_end = component::ConnectAt<fuchsia_driver_compat::Device>(
-        svc_endpoints->client,
-        component::MakeServiceMemberPath<fuchsia_driver_compat::Service::Device>(
-            component::kDefaultInstance));
-    if (compat_client_end.is_error()) {
-      return compat_client_end.take_error();
-    }
-
-    fidl::WireClient<fuchsia_driver_compat::Device> client(
-        *std::move(compat_client_end), fdf::Dispatcher::GetCurrent()->async_dispatcher());
-
-    zx::result<fuchsia_scheduler::RoleName> scheduler_role_name = zx::error(ZX_ERR_NOT_FOUND);
-
-    client->GetMetadata().Then(
-        [&](fidl::WireUnownedResult<fuchsia_driver_compat::Device::GetMetadata>& result) {
-          if (!result.ok()) {
-            scheduler_role_name = zx::error(result.status());
-            return;
-          }
-          if (result->is_error()) {
-            scheduler_role_name = result->take_error();
-            return;
-          }
-
-          for (auto& metadata : result->value()->metadata) {
-            if (metadata.type != DEVICE_METADATA_SCHEDULER_ROLE_NAME) {
-              continue;
-            }
-
-            size_t size = 0;
-            zx_status_t status = metadata.data.get_prop_content_size(&size);
-            if (status != ZX_OK) {
-              continue;
-            }
-
-            std::vector<uint8_t> data(size);
-            status = metadata.data.read(data.data(), 0, data.size());
-            if (status != ZX_OK) {
-              continue;
-            }
-
-            auto role_name = fidl::Unpersist<fuchsia_scheduler::RoleName>(std::move(data));
-            if (role_name.is_error()) {
-              continue;
-            }
-
-            scheduler_role_name = zx::ok(*std::move(role_name));
-            break;
-          }
-
-          runtime_.Quit();
-        });
-    runtime_.Run();
-
-    return scheduler_role_name;
-  }
-
-  fdf_testing::DriverRuntime runtime_;
-  FakePDev pdev_server_;
-  mock_registers::MockRegisters registers_;
-  std::queue<std::pair<zx_status_t, uint8_t>> gpio_writes_;
-  fake_gpio::FakeGpio gpio_;
-  fdf_testing::TestNode node_server_;
-  fdf_testing::TestEnvironment test_environment_;
-  fdf_testing::DriverUnderTest<TestAmlSpiDriver> dut_;
-  fuchsia_driver_framework::DriverStartArgs start_args_;
-
- private:
-  static constexpr amlogic_spi::amlspi_config_t kSpiConfig = {
-      .bus_id = 0,
-      .cs_count = 3,
-      .cs = {5, 3, amlogic_spi::amlspi_config_t::kCsClientManaged},
-      .clock_divider_register_value = 0,
-      .use_enhanced_clock_mode = false,
-  };
-
-  zx::interrupt interrupt_;
-  fidl::ClientEnd<fuchsia_io::Directory> driver_outgoing_;
-  compat::DeviceServer compat_;
-  compat::DeviceServer compat_default_;
-};
-
-zx_koid_t GetVmoKoid(const zx::vmo& vmo) {
-  zx_info_handle_basic_t info = {};
-  size_t actual = 0;
-  size_t available = 0;
-  zx_status_t status = vmo.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), &actual, &available);
-  if (status != ZX_OK || actual < 1) {
-    return ZX_KOID_INVALID;
-  }
-  return info.koid;
-}
-
-TEST_F(AmlSpiTest, DdkLifecycle) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  ASSERT_NE(node_server_.children().find("aml-spi-0"), node_server_.children().cend());
-}
-
-TEST_F(AmlSpiTest, ChipSelectCount) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-  fdf::Arena arena('TEST');
-  spiimpl.buffer(arena)->GetChipSelectCount().Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_EQ(result->count, 3);
-    runtime_.Quit();
-  });
-  runtime_.Run();
-}
-
-TEST_F(AmlSpiTest, Exchange) {
-  uint8_t kTxData[] = {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12};
-  constexpr uint8_t kExpectedRxData[] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab};
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return kExpectedRxData[0]; });
-
-  uint64_t tx_data = 0;
-  mmio()[AML_SPI_TXDATA].SetWriteCallback([&tx_data](uint64_t value) { tx_data = value; });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  fdf::Arena arena('TEST');
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(kTxData, sizeof(kTxData)))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        ASSERT_EQ(result->value()->rxdata.count(), sizeof(kExpectedRxData));
-        EXPECT_BYTES_EQ(result->value()->rxdata.data(), kExpectedRxData, sizeof(kExpectedRxData));
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  EXPECT_EQ(tx_data, kTxData[0]);
-
-  EXPECT_FALSE(ControllerReset());
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, ExchangeCsManagedByClient) {
-  uint8_t kTxData[] = {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12};
-  constexpr uint8_t kExpectedRxData[] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab};
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return kExpectedRxData[0]; });
-
-  uint64_t tx_data = 0;
-  mmio()[AML_SPI_TXDATA].SetWriteCallback([&tx_data](uint64_t value) { tx_data = value; });
-
-  fdf::Arena arena('TEST');
-  spiimpl.buffer(arena)
-      ->ExchangeVector(2, fidl::VectorView<uint8_t>::FromExternal(kTxData, sizeof(kTxData)))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        ASSERT_EQ(result->value()->rxdata.count(), sizeof(kExpectedRxData));
-        EXPECT_BYTES_EQ(result->value()->rxdata.data(), kExpectedRxData, sizeof(kExpectedRxData));
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  EXPECT_EQ(tx_data, kTxData[0]);
-
-  EXPECT_FALSE(ControllerReset());
-
-  // There should be no GPIO calls as the client manages CS for this device.
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, RegisterVmo) {
-  using fuchsia_hardware_sharedmemory::SharedVmoRight;
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  zx::vmo test_vmo;
-  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
-
-  const zx_koid_t test_vmo_koid = GetVmoKoid(test_vmo);
-
-  fdf::Arena arena('TEST');
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_error());
-        });
-  }
-
-  spiimpl.buffer(arena)->UnregisterVmo(0, 1).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    ASSERT_TRUE(result->is_ok());
-    EXPECT_EQ(test_vmo_koid, GetVmoKoid(result->value()->vmo));
-  });
-
-  spiimpl.buffer(arena)->UnregisterVmo(0, 1).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-    runtime_.Quit();
-  });
-  runtime_.Run();
-}
-
-TEST_F(AmlSpiTest, TransmitVmo) {
-  using fuchsia_hardware_sharedmemory::SharedVmoRight;
-
-  constexpr uint8_t kTxData[] = {0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5};
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  zx::vmo test_vmo;
-  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
-
-  fdf::Arena arena('TEST');
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 256, PAGE_SIZE - 256}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  EXPECT_OK(test_vmo.write(kTxData, 512, sizeof(kTxData)));
-
-  uint64_t tx_data = 0;
-  mmio()[AML_SPI_TXDATA].SetWriteCallback([&tx_data](uint64_t value) { tx_data = value; });
-
-  spiimpl.buffer(arena)->TransmitVmo(0, {1, 256, sizeof(kTxData)}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-    runtime_.Quit();
-  });
-  runtime_.Run();
-
-  EXPECT_EQ(tx_data, kTxData[0]);
-
-  EXPECT_FALSE(ControllerReset());
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, ReceiveVmo) {
-  using fuchsia_hardware_sharedmemory::SharedVmoRight;
-
-  constexpr uint8_t kExpectedRxData[] = {0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78};
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  zx::vmo test_vmo;
-  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
-
-  fdf::Arena arena('TEST');
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 256, PAGE_SIZE - 256},
-                      SharedVmoRight::kRead | SharedVmoRight::kWrite)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return kExpectedRxData[0]; });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)->ReceiveVmo(0, {1, 512, sizeof(kExpectedRxData)}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-    runtime_.Quit();
-  });
-  runtime_.Run();
-
-  uint8_t rx_buffer[sizeof(kExpectedRxData)];
-  EXPECT_OK(test_vmo.read(rx_buffer, 768, sizeof(rx_buffer)));
-  EXPECT_BYTES_EQ(rx_buffer, kExpectedRxData, sizeof(rx_buffer));
-
-  EXPECT_FALSE(ControllerReset());
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, ExchangeVmo) {
-  using fuchsia_hardware_sharedmemory::SharedVmoRight;
-
-  constexpr uint8_t kTxData[] = {0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef};
-  constexpr uint8_t kExpectedRxData[] = {0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78};
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  zx::vmo test_vmo;
-  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
-
-  fdf::Arena arena('TEST');
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 256, PAGE_SIZE - 256},
-                      SharedVmoRight::kRead | SharedVmoRight::kWrite)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return kExpectedRxData[0]; });
-
-  uint64_t tx_data = 0;
-  mmio()[AML_SPI_TXDATA].SetWriteCallback([&tx_data](uint64_t value) { tx_data = value; });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  EXPECT_OK(test_vmo.write(kTxData, 512, sizeof(kTxData)));
-
-  spiimpl.buffer(arena)
-      ->ExchangeVmo(0, {1, 256, sizeof(kTxData)}, {1, 512, sizeof(kExpectedRxData)})
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        EXPECT_TRUE(result->is_ok());
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  uint8_t rx_buffer[sizeof(kExpectedRxData)];
-  EXPECT_OK(test_vmo.read(rx_buffer, 768, sizeof(rx_buffer)));
-  EXPECT_BYTES_EQ(rx_buffer, kExpectedRxData, sizeof(rx_buffer));
-
-  EXPECT_EQ(tx_data, kTxData[0]);
-
-  EXPECT_FALSE(ControllerReset());
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, TransfersOutOfRange) {
-  using fuchsia_hardware_sharedmemory::SharedVmoRight;
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  zx::vmo test_vmo;
-  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
-
-  fdf::Arena arena('TEST');
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(1, 1, {std::move(vmo), PAGE_SIZE - 4, 4},
-                      SharedVmoRight::kRead | SharedVmoRight::kWrite)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)->ExchangeVmo(1, {1, 0, 2}, {1, 2, 2}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-  });
-  spiimpl.buffer(arena)->ExchangeVmo(1, {1, 0, 2}, {1, 3, 2}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-  spiimpl.buffer(arena)->ExchangeVmo(1, {1, 3, 2}, {1, 0, 2}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-  spiimpl.buffer(arena)->ExchangeVmo(1, {1, 0, 3}, {1, 2, 3}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)->TransmitVmo(1, {1, 0, 4}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-  });
-  spiimpl.buffer(arena)->TransmitVmo(1, {1, 0, 5}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-  spiimpl.buffer(arena)->TransmitVmo(1, {1, 3, 2}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-  spiimpl.buffer(arena)->TransmitVmo(1, {1, 4, 1}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-  spiimpl.buffer(arena)->TransmitVmo(1, {1, 5, 1}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 0, 4}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-  });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 3, 1}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-  });
-
-  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 3, 2}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 4, 1}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 5, 1}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-    runtime_.Quit();
-  });
-  runtime_.Run();
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, VmoBadRights) {
-  using fuchsia_hardware_sharedmemory::SharedVmoRight;
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  zx::vmo test_vmo;
-  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
-
-  fdf::Arena arena('TEST');
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 0, 256}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 2, {std::move(vmo), 0, 256},
-                      SharedVmoRight::kRead | SharedVmoRight::kWrite)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)->ExchangeVmo(0, {1, 0, 128}, {2, 128, 128}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-  });
-  spiimpl.buffer(arena)->ExchangeVmo(0, {2, 0, 128}, {1, 128, 128}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_EQ(result->error_value(), ZX_ERR_ACCESS_DENIED);
-  });
-  spiimpl.buffer(arena)->ExchangeVmo(0, {1, 0, 128}, {1, 128, 128}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_EQ(result->error_value(), ZX_ERR_ACCESS_DENIED);
-  });
-  spiimpl.buffer(arena)->ReceiveVmo(0, {1, 0, 128}).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_EQ(result->error_value(), ZX_ERR_ACCESS_DENIED);
-    runtime_.Quit();
-  });
-  runtime_.Run();
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, Exchange64BitWords) {
-  uint8_t kTxData[] = {
-      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb, 0xbd,
-      0xd4, 0xcf, 0xa8, 0xbf, 0x85, 0xf2, 0x6a, 0xe3, 0xba, 0xf1, 0x49, 0x00,
-  };
-  constexpr uint8_t kExpectedRxData[] = {
-      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
-      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
-  };
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  // First (and only) word of kExpectedRxData with bytes swapped.
-  mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return 0xea2b'8f8f; });
-
-  uint64_t tx_data = 0;
-  mmio()[AML_SPI_TXDATA].SetWriteCallback([&tx_data](uint64_t value) { tx_data = value; });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  fdf::Arena arena('TEST');
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(kTxData, sizeof(kTxData)))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        ASSERT_EQ(result->value()->rxdata.count(), sizeof(kExpectedRxData));
-        EXPECT_BYTES_EQ(result->value()->rxdata.data(), kExpectedRxData, sizeof(kExpectedRxData));
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  // Last word of kTxData with bytes swapped.
-  EXPECT_EQ(tx_data, 0xbaf1'4900);
-
-  EXPECT_FALSE(ControllerReset());
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, Exchange64Then8BitWords) {
-  uint8_t kTxData[] = {
-      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb,
-      0xbd, 0xd4, 0xcf, 0xa8, 0xbf, 0x85, 0xf2, 0x6a, 0xe3, 0xba,
-  };
-  constexpr uint8_t kExpectedRxData[] = {
-      0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00,
-      0xea, 0x00, 0x00, 0x00, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea,
-  };
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return 0xea; });
-
-  uint64_t tx_data = 0;
-  mmio()[AML_SPI_TXDATA].SetWriteCallback([&tx_data](uint64_t value) { tx_data = value; });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  fdf::Arena arena('TEST');
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(kTxData, sizeof(kTxData)))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        ASSERT_EQ(result->value()->rxdata.count(), sizeof(kExpectedRxData));
-        EXPECT_BYTES_EQ(result->value()->rxdata.data(), kExpectedRxData, sizeof(kExpectedRxData));
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  EXPECT_EQ(tx_data, 0xba);
-
-  EXPECT_FALSE(ControllerReset());
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, ExchangeResetsController) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  fdf::Arena arena('TEST');
-
-  uint8_t buf[17] = {};
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 17))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 17);
-        EXPECT_FALSE(ControllerReset());
-      });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  // Controller should be reset because a 64-bit transfer was preceded by a transfer of an odd
-  // number of bytes.
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 16))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 16);
-        EXPECT_TRUE(ControllerReset());
-      });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 3))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 3);
-        EXPECT_FALSE(ControllerReset());
-      });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 6))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 6);
-        EXPECT_FALSE(ControllerReset());
-      });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 8))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 8);
-        EXPECT_TRUE(ControllerReset());
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-TEST_F(AmlSpiTest, ReleaseVmos) {
-  using fuchsia_hardware_sharedmemory::SharedVmoRight;
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  fdf::Arena arena('TEST');
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-
-    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 2, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  spiimpl.buffer(arena)->UnregisterVmo(0, 2).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-  });
-
-  // Release VMO 1 and make sure that a subsequent call to unregister it fails.
-  EXPECT_TRUE(spiimpl.buffer(arena)->ReleaseRegisteredVmos(0).ok());
-
-  spiimpl.buffer(arena)->UnregisterVmo(0, 2).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-  });
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-
-    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 2, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-  }
-
-  // Release both VMOs and make sure that they can be registered again.
-  EXPECT_TRUE(spiimpl.buffer(arena)->ReleaseRegisteredVmos(0).ok());
-
-  {
-    zx::vmo vmo;
-    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-        });
-
-    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
-    spiimpl.buffer(arena)
-        ->RegisterVmo(0, 2, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-          runtime_.Quit();
-        });
-  }
-
-  runtime_.Run();
-}
-
-TEST_F(AmlSpiTest, ReleaseVmosAfterClientsUnbind) {
-  using fuchsia_hardware_sharedmemory::SharedVmoRight;
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client1 = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client1.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl1(*std::move(spiimpl_client1),
-                                                              fdf::Dispatcher::GetCurrent()->get());
-
-  fdf::Arena arena('TEST');
-
-  // Register three VMOs through the first client.
-  for (uint32_t i = 1; i <= 3; i++) {
-    zx::vmo vmo;
-    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
-    spiimpl1.buffer(arena)
-        ->RegisterVmo(0, i, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
-        .Then([&](auto& result) {
-          ASSERT_TRUE(result.ok());
-          EXPECT_TRUE(result->is_ok());
-          runtime_.Quit();
-        });
-    runtime_.Run();
-    runtime_.ResetQuit();
-  }
-
-  auto spiimpl_client2 = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client2.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl2(*std::move(spiimpl_client2),
-                                                              fdf::Dispatcher::GetCurrent()->get());
-
-  // The second client should be able to see the registered VMOs.
-  spiimpl2.buffer(arena)->UnregisterVmo(0, 1).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-    runtime_.Quit();
-  });
-  runtime_.Run();
-  runtime_.ResetQuit();
-
-  // Unbind the first client.
-  EXPECT_TRUE(spiimpl1.UnbindMaybeGetEndpoint().is_ok());
-  runtime_.RunUntilIdle();
-
-  // The VMOs registered by the first client should remain.
-  spiimpl2.buffer(arena)->UnregisterVmo(0, 2).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_ok());
-    runtime_.Quit();
-  });
-  runtime_.Run();
-  runtime_.ResetQuit();
-
-  // Unbind the second client, then connect a third client.
-  EXPECT_TRUE(spiimpl2.UnbindMaybeGetEndpoint().is_ok());
-  runtime_.RunUntilIdle();
-
-  auto spiimpl_client3 = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client3.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl3(*std::move(spiimpl_client3),
-                                                              fdf::Dispatcher::GetCurrent()->get());
-
-  // All registered VMOs should have been released after the second client unbound.
-  spiimpl3.buffer(arena)->UnregisterVmo(0, 3).Then([&](auto& result) {
-    ASSERT_TRUE(result.ok());
-    EXPECT_TRUE(result->is_error());
-    runtime_.Quit();
-  });
-  runtime_.Run();
-}
-
-class AmlSpiNormalClockModeTest : public AmlSpiTest {
- public:
-  void SetMetadata(compat::DeviceServer& compat) override {
-    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
-        .bus_id = 0,
-        .cs_count = 2,
-        .cs = {5, 3},
-        .clock_divider_register_value = 0x5,
-        .use_enhanced_clock_mode = false,
-    };
-
-    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
-  }
-};
-
-TEST_F(AmlSpiNormalClockModeTest, Test) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto conreg = ConReg::Get().FromValue(dut_->conreg());
-  auto enhanced_cntl = EnhanceCntl::Get().FromValue(dut_->enhance_cntl());
-  auto testreg = TestReg::Get().FromValue(dut_->testreg());
-
-  EXPECT_EQ(conreg.data_rate(), 0x5);
-  EXPECT_EQ(conreg.drctl(), 0);
-  EXPECT_EQ(conreg.ssctl(), 0);
-  EXPECT_EQ(conreg.smc(), 0);
-  EXPECT_EQ(conreg.xch(), 0);
-  EXPECT_EQ(conreg.mode(), ConReg::kModeMaster);
-  EXPECT_EQ(conreg.en(), 1);
-
-  EXPECT_EQ(enhanced_cntl.reg_value(), 0);
-
-  EXPECT_EQ(testreg.dlyctl(), 0x15);
-  EXPECT_EQ(testreg.clk_free_en(), 1);
-}
-
-class AmlSpiEnhancedClockModeTest : public AmlSpiTest {
- public:
-  void SetMetadata(compat::DeviceServer& compat) override {
-    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
-        .bus_id = 0,
-        .cs_count = 2,
-        .cs = {5, 3},
-        .clock_divider_register_value = 0xa5,
-        .use_enhanced_clock_mode = true,
-        .delay_control = 0b00'11'00,
-    };
-
-    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
-  }
-};
-
-TEST_F(AmlSpiEnhancedClockModeTest, Test) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto conreg = ConReg::Get().FromValue(dut_->conreg());
-  auto enhanced_cntl = EnhanceCntl::Get().FromValue(dut_->enhance_cntl());
-  auto testreg = TestReg::Get().FromValue(dut_->testreg());
-
-  EXPECT_EQ(conreg.data_rate(), 0);
-  EXPECT_EQ(conreg.drctl(), 0);
-  EXPECT_EQ(conreg.ssctl(), 0);
-  EXPECT_EQ(conreg.smc(), 0);
-  EXPECT_EQ(conreg.xch(), 0);
-  EXPECT_EQ(conreg.mode(), ConReg::kModeMaster);
-  EXPECT_EQ(conreg.en(), 1);
-
-  EXPECT_EQ(enhanced_cntl.main_clock_always_on(), 0);
-  EXPECT_EQ(enhanced_cntl.clk_cs_delay_enable(), 1);
-  EXPECT_EQ(enhanced_cntl.cs_oen_enhance_enable(), 1);
-  EXPECT_EQ(enhanced_cntl.clk_oen_enhance_enable(), 1);
-  EXPECT_EQ(enhanced_cntl.mosi_oen_enhance_enable(), 1);
-  EXPECT_EQ(enhanced_cntl.spi_clk_select(), 1);
-  EXPECT_EQ(enhanced_cntl.enhance_clk_div(), 0xa5);
-  EXPECT_EQ(enhanced_cntl.clk_cs_delay(), 0);
-
-  EXPECT_EQ(testreg.dlyctl(), 0b00'11'00);
-  EXPECT_EQ(testreg.clk_free_en(), 1);
-}
-
-class AmlSpiNormalClockModeInvalidDividerTest : public AmlSpiTest {
- public:
-  void SetMetadata(compat::DeviceServer& compat) override {
-    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
-        .bus_id = 0,
-        .cs_count = 2,
-        .cs = {5, 3},
-        .clock_divider_register_value = 0xa5,
-        .use_enhanced_clock_mode = false,
-    };
-
-    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
-  }
-};
-
-TEST_F(AmlSpiNormalClockModeInvalidDividerTest, Test) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  EXPECT_TRUE(start_result.is_error());
-}
-
-class AmlSpiEnhancedClockModeInvalidDividerTest : public AmlSpiTest {
- public:
-  void SetMetadata(compat::DeviceServer& compat) override {
-    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
-        .bus_id = 0,
-        .cs_count = 2,
-        .cs = {5, 3},
-        .clock_divider_register_value = 0x1a5,
-        .use_enhanced_clock_mode = true,
-    };
-
-    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
-  }
-};
-
-TEST_F(AmlSpiEnhancedClockModeInvalidDividerTest, Test) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  EXPECT_TRUE(start_result.is_error());
-}
-
-class AmlSpiBtiPaddrTest : public AmlSpiTest {
- public:
-  static constexpr zx_paddr_t kDmaPaddrs[] = {0x1212'0000, 0xabab'000};
-
-  virtual void SetUpBti() override {
-    zx::bti bti;
-    ASSERT_OK(fake_bti_create_with_paddrs(kDmaPaddrs, std::size(kDmaPaddrs),
-                                          bti.reset_and_get_address()));
-    bti_local_ = bti.borrow();
-    pdev_server_.set_bti(std::move(bti));
-  }
-
- protected:
-  zx::unowned_bti bti_local_;
-};
-
-TEST_F(AmlSpiBtiPaddrTest, ExchangeDma) {
-  constexpr uint8_t kTxData[24] = {
-      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb, 0xbd,
-      0xd4, 0xcf, 0xa8, 0xbf, 0x85, 0xf2, 0x6a, 0xe3, 0xba, 0xf1, 0x49, 0x00,
-  };
-  constexpr uint8_t kExpectedRxData[24] = {
-      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
-      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
-  };
-
-  uint8_t reversed_tx_data[24];
-  for (size_t i = 0; i < sizeof(kTxData); i += sizeof(uint64_t)) {
-    uint64_t tmp;
-    memcpy(&tmp, kTxData + i, sizeof(tmp));
-    tmp = htobe64(tmp);
-    memcpy(reversed_tx_data + i, &tmp, sizeof(tmp));
-  }
-
-  uint8_t reversed_expected_rx_data[24];
-  for (size_t i = 0; i < sizeof(kExpectedRxData); i += sizeof(uint64_t)) {
-    uint64_t tmp;
-    memcpy(&tmp, kExpectedRxData + i, sizeof(tmp));
-    tmp = htobe64(tmp);
-    memcpy(reversed_expected_rx_data + i, &tmp, sizeof(tmp));
-  }
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  fake_bti_pinned_vmo_info_t dma_vmos[2] = {};
-  size_t actual_vmos = 0;
-  EXPECT_OK(
-      fake_bti_get_pinned_vmos(bti_local_->get(), dma_vmos, std::size(dma_vmos), &actual_vmos));
-  EXPECT_EQ(actual_vmos, std::size(dma_vmos));
-
-  zx::vmo tx_dma_vmo(dma_vmos[0].vmo);
-  zx::vmo rx_dma_vmo(dma_vmos[1].vmo);
-
-  // Copy the reversed expected RX data to the RX VMO. The driver should copy this to the user
-  // output buffer with the correct endianness.
-  rx_dma_vmo.write(reversed_expected_rx_data, 0, sizeof(reversed_expected_rx_data));
-
-  zx_paddr_t tx_paddr = 0;
-  zx_paddr_t rx_paddr = 0;
-
-  mmio()[AML_SPI_DRADDR].SetWriteCallback([&tx_paddr](uint64_t value) { tx_paddr = value; });
-  mmio()[AML_SPI_DWADDR].SetWriteCallback([&rx_paddr](uint64_t value) { rx_paddr = value; });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  uint8_t buf[24] = {};
-  memcpy(buf, kTxData, sizeof(buf));
-
-  fdf::Arena arena('TEST');
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, sizeof(buf)))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        ASSERT_EQ(result->value()->rxdata.count(), sizeof(buf));
-        EXPECT_BYTES_EQ(kExpectedRxData, result->value()->rxdata.data(), sizeof(buf));
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  // Verify that the driver wrote the TX data to the TX VMO.
-  EXPECT_OK(tx_dma_vmo.read(buf, 0, sizeof(buf)));
-  EXPECT_BYTES_EQ(reversed_tx_data, buf, sizeof(buf));
-
-  EXPECT_EQ(tx_paddr, kDmaPaddrs[0]);
-  EXPECT_EQ(rx_paddr, kDmaPaddrs[1]);
-
-  EXPECT_FALSE(ControllerReset());
-}
-
-class AmlSpiBtiEmptyTest : public AmlSpiTest {
- public:
-  virtual void SetUpBti() override {
-    zx::bti bti;
-    ASSERT_OK(fake_bti_create(bti.reset_and_get_address()));
-    bti_local_ = bti.borrow();
-    pdev_server_.set_bti(std::move(bti));
-  }
-
- protected:
-  zx::unowned_bti bti_local_;
-};
-
-TEST_F(AmlSpiBtiEmptyTest, ExchangeFallBackToPio) {
-  constexpr uint8_t kTxData[15] = {
-      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb, 0xbd, 0xd4, 0xcf, 0xa8,
-  };
-  constexpr uint8_t kExpectedRxData[15] = {
-      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
-  };
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  fake_bti_pinned_vmo_info_t dma_vmos[2] = {};
-  size_t actual_vmos = 0;
-  EXPECT_OK(
-      fake_bti_get_pinned_vmos(bti_local_->get(), dma_vmos, std::size(dma_vmos), &actual_vmos));
-  EXPECT_EQ(actual_vmos, std::size(dma_vmos));
-
-  zx_paddr_t tx_paddr = 0;
-  zx_paddr_t rx_paddr = 0;
-
-  mmio()[AML_SPI_DRADDR].SetWriteCallback([&tx_paddr](uint64_t value) { tx_paddr = value; });
-  mmio()[AML_SPI_DWADDR].SetWriteCallback([&rx_paddr](uint64_t value) { rx_paddr = value; });
-
-  mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return 0xea2b'8f8f; });
-
-  uint64_t tx_data = 0;
-  mmio()[AML_SPI_TXDATA].SetWriteCallback([&tx_data](uint64_t value) { tx_data = value; });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  uint8_t buf[15] = {};
-  memcpy(buf, kTxData, sizeof(buf));
-
-  fdf::Arena arena('TEST');
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, sizeof(buf)))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        ASSERT_EQ(result->value()->rxdata.count(), sizeof(buf));
-        EXPECT_BYTES_EQ(kExpectedRxData, result->value()->rxdata.data(), sizeof(buf));
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  EXPECT_EQ(tx_data, kTxData[14]);
-
-  // Verify that DMA was not used.
-  EXPECT_EQ(tx_paddr, 0);
-  EXPECT_EQ(rx_paddr, 0);
-
-  EXPECT_FALSE(ControllerReset());
-}
-
-class AmlSpiExchangeDmaClientReversesBufferTest : public AmlSpiBtiPaddrTest {
- public:
-  void SetMetadata(compat::DeviceServer& compat) override {
-    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
-        .bus_id = 0,
-        .cs_count = 3,
-        .cs = {5, 3, amlogic_spi::amlspi_config_t::kCsClientManaged},
-        .clock_divider_register_value = 0,
-        .use_enhanced_clock_mode = false,
-        .client_reverses_dma_transfers = true,
-    };
-
-    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
-  }
-};
-
-TEST_F(AmlSpiExchangeDmaClientReversesBufferTest, Test) {
-  constexpr uint8_t kTxData[24] = {
-      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb, 0xbd,
-      0xd4, 0xcf, 0xa8, 0xbf, 0x85, 0xf2, 0x6a, 0xe3, 0xba, 0xf1, 0x49, 0x00,
-  };
-  constexpr uint8_t kExpectedRxData[24] = {
-      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
-      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
-  };
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  fake_bti_pinned_vmo_info_t dma_vmos[2] = {};
-  size_t actual_vmos = 0;
-  EXPECT_OK(
-      fake_bti_get_pinned_vmos(bti_local_->get(), dma_vmos, std::size(dma_vmos), &actual_vmos));
-  EXPECT_EQ(actual_vmos, std::size(dma_vmos));
-
-  zx::vmo tx_dma_vmo(dma_vmos[0].vmo);
-  zx::vmo rx_dma_vmo(dma_vmos[1].vmo);
-
-  rx_dma_vmo.write(kExpectedRxData, 0, sizeof(kExpectedRxData));
-
-  zx_paddr_t tx_paddr = 0;
-  zx_paddr_t rx_paddr = 0;
-
-  mmio()[AML_SPI_DRADDR].SetWriteCallback([&tx_paddr](uint64_t value) { tx_paddr = value; });
-  mmio()[AML_SPI_DWADDR].SetWriteCallback([&rx_paddr](uint64_t value) { rx_paddr = value; });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  uint8_t buf[sizeof(kTxData)] = {};
-  memcpy(buf, kTxData, sizeof(buf));
-
-  fdf::Arena arena('TEST');
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, sizeof(buf)))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        ASSERT_EQ(result->value()->rxdata.count(), sizeof(buf));
-        EXPECT_BYTES_EQ(kExpectedRxData, result->value()->rxdata.data(), sizeof(buf));
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  // Verify that the driver wrote the TX data to the TX VMO with the original byte order.
-  EXPECT_OK(tx_dma_vmo.read(buf, 0, sizeof(buf)));
-  EXPECT_BYTES_EQ(kTxData, buf, sizeof(buf));
-
-  EXPECT_EQ(tx_paddr, kDmaPaddrs[0]);
-  EXPECT_EQ(rx_paddr, kDmaPaddrs[1]);
-
-  EXPECT_FALSE(ControllerReset());
-}
-
-class AmlSpiShutdownTest : public AmlSpiTest {
- public:
-  // Override teardown so that the test case itself can call PrepareStop/Stop.
-  void TearDown() override {}
-};
-
-TEST_F(AmlSpiShutdownTest, Shutdown) {
-  // Must outlive AmlSpi device.
-  bool dmareg_cleared = false;
-  bool conreg_cleared = false;
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  uint8_t buf[16] = {};
-  fdf::Arena arena('TEST');
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, sizeof(buf)))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  mmio()[AML_SPI_DMAREG].SetWriteCallback(
-      [&dmareg_cleared](uint64_t value) { dmareg_cleared = value == 0; });
-
-  mmio()[AML_SPI_CONREG].SetWriteCallback(
-      [&conreg_cleared](uint64_t value) { conreg_cleared = value == 0; });
-
-  zx::result prepare_stop_result = runtime_.RunToCompletion(dut_.PrepareStop());
-  EXPECT_OK(prepare_stop_result.status_value());
-  EXPECT_TRUE(dut_.Stop().is_ok());
-
-  EXPECT_TRUE(dmareg_cleared);
-  EXPECT_TRUE(conreg_cleared);
-
-  // All SPI devices have been released at this point, so no further calls can be made.
-
-  EXPECT_FALSE(ControllerReset());
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-class AmlSpiNoResetFragmentTest : public AmlSpiTest {
- public:
-  bool SetupResetRegister() override { return false; }
-};
-
-TEST_F(AmlSpiNoResetFragmentTest, ExchangeWithNoResetFragment) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  auto spiimpl_client = GetFidlClient();
-  ASSERT_TRUE(spiimpl_client.is_ok());
-
-  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
-                                                             fdf::Dispatcher::GetCurrent()->get());
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  fdf::Arena arena('TEST');
-
-  uint8_t buf[17] = {};
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 17))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 17);
-        EXPECT_FALSE(ControllerReset());
-      });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  // Controller should not be reset because no reset fragment was provided.
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 16))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 16);
-        EXPECT_FALSE(ControllerReset());
-      });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 3))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 3);
-        EXPECT_FALSE(ControllerReset());
-      });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 6))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 6);
-        EXPECT_FALSE(ControllerReset());
-      });
-
-  ExpectGpioWrite(ZX_OK, 0);
-  ExpectGpioWrite(ZX_OK, 1);
-
-  spiimpl.buffer(arena)
-      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 8))
-      .Then([&](auto& result) {
-        ASSERT_TRUE(result.ok());
-        ASSERT_TRUE(result->is_ok());
-        EXPECT_EQ(result->value()->rxdata.count(), 8);
-        EXPECT_FALSE(ControllerReset());
-        runtime_.Quit();
-      });
-  runtime_.Run();
-
-  ASSERT_NO_FATAL_FAILURE(VerifyGpioAndClear());
-}
-
-class AmlSpiNoIrqTest : public AmlSpiTest {
- public:
-  virtual void SetUpInterrupt() override {}
-};
-
-TEST_F(AmlSpiNoIrqTest, InterruptRequired) {
-  // Bind should fail if no interrupt was provided.
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  EXPECT_TRUE(start_result.is_error());
-}
-
-TEST_F(AmlSpiTest, DefaultRoleMetadata) {
-  constexpr char kExpectedRoleName[] = "fuchsia.devices.spi.drivers.aml-spi.transaction";
-
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  zx::result<fuchsia_scheduler::RoleName> metadata = GetSchedulerRoleName();
-  ASSERT_TRUE(metadata.is_ok());
-  EXPECT_STREQ(metadata->role(), kExpectedRoleName);
-}
-
-class AmlSpiForwardRoleMetadataTest : public AmlSpiTest {
- public:
-  void SetMetadata(compat::DeviceServer& compat) override {
-    constexpr amlogic_spi::amlspi_config_t kSpiConfig = {
-        .bus_id = 0,
-        .cs_count = 3,
-        .cs = {5, 3, amlogic_spi::amlspi_config_t::kCsClientManaged},
-        .clock_divider_register_value = 0,
-        .use_enhanced_clock_mode = false,
-    };
-
-    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
-
-    const fuchsia_scheduler::wire::RoleName role{kExpectedRoleName};
-
-    fit::result result = fidl::Persist(role);
-    ASSERT_TRUE(result.is_ok());
-
-    EXPECT_OK(
-        compat.AddMetadata(DEVICE_METADATA_SCHEDULER_ROLE_NAME, result->data(), result->size()));
-  }
-
- protected:
-  static constexpr char kExpectedRoleName[] = "no.such.scheduler.role";
-};
-
-TEST_F(AmlSpiForwardRoleMetadataTest, Test) {
-  zx::result start_result = runtime_.RunToCompletion(dut_.Start(std::move(start_args_)));
-  ASSERT_TRUE(start_result.is_ok());
-
-  zx::result<fuchsia_scheduler::RoleName> metadata = GetSchedulerRoleName();
-  ASSERT_TRUE(metadata.is_ok());
-  EXPECT_STREQ(metadata->role(), kExpectedRoleName);
-}
-
-}  // namespace spi
diff --git a/src/devices/spi/drivers/aml-spi/tests/aml-spi-bti-test.cc b/src/devices/spi/drivers/aml-spi/tests/aml-spi-bti-test.cc
new file mode 100644
index 0000000..4e949c1
--- /dev/null
+++ b/src/devices/spi/drivers/aml-spi/tests/aml-spi-bti-test.cc
@@ -0,0 +1,324 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/devices/spi/drivers/aml-spi/tests/aml-spi-test-env.h"
+
+namespace spi {
+
+namespace {
+bool IsBytesEqual(const uint8_t* expected, const uint8_t* actual, size_t len) {
+  return memcmp(expected, actual, len) == 0;
+}
+}  // namespace
+
+class AmlSpiBtiPaddrEnvironment : public BaseTestEnvironment {
+ public:
+  static constexpr zx_paddr_t kDmaPaddrs[] = {0x1212'0000, 0xabab'000};
+
+  virtual void SetUpBti() override {
+    zx::bti bti;
+    ASSERT_OK(fake_bti_create_with_paddrs(kDmaPaddrs, std::size(kDmaPaddrs),
+                                          bti.reset_and_get_address()));
+    bti_local_ = bti.borrow();
+    pdev_server_.set_bti(std::move(bti));
+  }
+
+  zx::unowned_bti& GetBtiLocal() { return bti_local_; }
+
+ private:
+  zx::unowned_bti bti_local_;
+};
+
+class AmlSpiBtiPaddrFixtureConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiBtiPaddrEnvironment;
+};
+
+class AmlSpiBtiPaddrTest : public fdf_testing::DriverTestFixture<AmlSpiBtiPaddrFixtureConfig> {};
+
+TEST_F(AmlSpiBtiPaddrTest, ExchangeDma) {
+  constexpr uint8_t kTxData[24] = {
+      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb, 0xbd,
+      0xd4, 0xcf, 0xa8, 0xbf, 0x85, 0xf2, 0x6a, 0xe3, 0xba, 0xf1, 0x49, 0x00,
+  };
+  constexpr uint8_t kExpectedRxData[24] = {
+      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
+      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
+  };
+
+  uint8_t reversed_tx_data[24];
+  for (size_t i = 0; i < sizeof(kTxData); i += sizeof(uint64_t)) {
+    uint64_t tmp;
+    memcpy(&tmp, kTxData + i, sizeof(tmp));
+    tmp = htobe64(tmp);
+    memcpy(reversed_tx_data + i, &tmp, sizeof(tmp));
+  }
+
+  uint8_t reversed_expected_rx_data[24];
+  for (size_t i = 0; i < sizeof(kExpectedRxData); i += sizeof(uint64_t)) {
+    uint64_t tmp;
+    memcpy(&tmp, kExpectedRxData + i, sizeof(tmp));
+    tmp = htobe64(tmp);
+    memcpy(reversed_expected_rx_data + i, &tmp, sizeof(tmp));
+  }
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  fake_bti_pinned_vmo_info_t dma_vmos[2] = {};
+  size_t actual_vmos = 0;
+  RunInEnvironmentTypeContext([&dma_vmos, &actual_vmos](AmlSpiBtiPaddrEnvironment& env) {
+    EXPECT_OK(fake_bti_get_pinned_vmos(env.GetBtiLocal()->get(), dma_vmos, std::size(dma_vmos),
+                                       &actual_vmos));
+    EXPECT_EQ(actual_vmos, std::size(dma_vmos));
+  });
+
+  zx::vmo tx_dma_vmo(dma_vmos[0].vmo);
+  zx::vmo rx_dma_vmo(dma_vmos[1].vmo);
+
+  // Copy the reversed expected RX data to the RX VMO. The driver should copy this to the user
+  // output buffer with the correct endianness.
+  rx_dma_vmo.write(reversed_expected_rx_data, 0, sizeof(reversed_expected_rx_data));
+
+  zx_paddr_t tx_paddr = 0;
+  zx_paddr_t rx_paddr = 0;
+
+  driver()->mmio()[AML_SPI_DRADDR].SetWriteCallback(
+      [&tx_paddr](uint64_t value) { tx_paddr = value; });
+  driver()->mmio()[AML_SPI_DWADDR].SetWriteCallback(
+      [&rx_paddr](uint64_t value) { rx_paddr = value; });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  uint8_t buf[24] = {};
+  memcpy(buf, kTxData, sizeof(buf));
+
+  fdf::Arena arena('TEST');
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, sizeof(buf)))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        ASSERT_EQ(result->value()->rxdata.count(), sizeof(buf));
+        EXPECT_TRUE(IsBytesEqual(kExpectedRxData, result->value()->rxdata.data(), sizeof(buf)));
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  // Verify that the driver wrote the TX data to the TX VMO.
+  EXPECT_OK(tx_dma_vmo.read(buf, 0, sizeof(buf)));
+  EXPECT_TRUE(IsBytesEqual(reversed_tx_data, buf, sizeof(buf)));
+
+  EXPECT_EQ(tx_paddr, AmlSpiBtiPaddrEnvironment::kDmaPaddrs[0]);
+  EXPECT_EQ(rx_paddr, AmlSpiBtiPaddrEnvironment::kDmaPaddrs[1]);
+
+  RunInEnvironmentTypeContext(
+      [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+}
+
+class AmlSpiBtiEmptyEnvironment : public BaseTestEnvironment {
+ public:
+  static constexpr zx_paddr_t kDmaPaddrs[] = {0x1212'0000, 0xabab'000};
+
+  virtual void SetUpBti() override {
+    zx::bti bti;
+    ASSERT_OK(fake_bti_create(bti.reset_and_get_address()));
+    bti_local_ = bti.borrow();
+    pdev_server_.set_bti(std::move(bti));
+  }
+
+  zx::unowned_bti& GetBtiLocal() { return bti_local_; }
+
+ private:
+  zx::unowned_bti bti_local_;
+};
+
+class AmlSpiBtiEmptyFixtureConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiBtiPaddrEnvironment;
+};
+
+class AmlSpiBtiEmptyTest : public fdf_testing::DriverTestFixture<AmlSpiBtiEmptyFixtureConfig> {};
+
+TEST_F(AmlSpiBtiEmptyTest, ExchangeFallBackToPio) {
+  constexpr uint8_t kTxData[15] = {
+      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb, 0xbd, 0xd4, 0xcf, 0xa8,
+  };
+  constexpr uint8_t kExpectedRxData[15] = {
+      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f,
+  };
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  fake_bti_pinned_vmo_info_t dma_vmos[2] = {};
+  size_t actual_vmos = 0;
+  RunInEnvironmentTypeContext([&dma_vmos, &actual_vmos](AmlSpiBtiPaddrEnvironment& env) {
+    EXPECT_OK(fake_bti_get_pinned_vmos(env.GetBtiLocal()->get(), dma_vmos, std::size(dma_vmos),
+                                       &actual_vmos));
+    EXPECT_EQ(actual_vmos, std::size(dma_vmos));
+  });
+
+  zx_paddr_t tx_paddr = 0;
+  zx_paddr_t rx_paddr = 0;
+
+  driver()->mmio()[AML_SPI_DRADDR].SetWriteCallback(
+      [&tx_paddr](uint64_t value) { tx_paddr = value; });
+  driver()->mmio()[AML_SPI_DWADDR].SetWriteCallback(
+      [&rx_paddr](uint64_t value) { rx_paddr = value; });
+
+  driver()->mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return 0xea2b'8f8f; });
+
+  uint64_t tx_data = 0;
+  driver()->mmio()[AML_SPI_TXDATA].SetWriteCallback(
+      [&tx_data](uint64_t value) { tx_data = value; });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  uint8_t buf[15] = {};
+  memcpy(buf, kTxData, sizeof(buf));
+
+  fdf::Arena arena('TEST');
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, sizeof(buf)))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        ASSERT_EQ(result->value()->rxdata.count(), sizeof(buf));
+        EXPECT_TRUE(IsBytesEqual(kExpectedRxData, result->value()->rxdata.data(), sizeof(buf)));
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  EXPECT_EQ(tx_data, kTxData[14]);
+
+  // Verify that DMA was not used.
+  EXPECT_EQ(tx_paddr, 0u);
+  EXPECT_EQ(rx_paddr, 0u);
+
+  RunInEnvironmentTypeContext(
+      [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+}
+
+class AmlSpiExchangeDmaClientReversesBufferEnvironment : public AmlSpiBtiPaddrEnvironment {
+ public:
+  void SetMetadata(compat::DeviceServer& compat) override {
+    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
+        .bus_id = 0,
+        .cs_count = 3,
+        .cs = {5, 3, amlogic_spi::amlspi_config_t::kCsClientManaged},
+        .clock_divider_register_value = 0,
+        .use_enhanced_clock_mode = false,
+        .client_reverses_dma_transfers = true,
+    };
+
+    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
+  }
+};
+
+class AmlSpiExchangeDmaClientReversesBufferConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiExchangeDmaClientReversesBufferEnvironment;
+};
+
+class AmlSpiExchangeDmaClientReversesBufferTest
+    : public fdf_testing::DriverTestFixture<AmlSpiExchangeDmaClientReversesBufferConfig> {};
+
+TEST_F(AmlSpiExchangeDmaClientReversesBufferTest, Test) {
+  constexpr uint8_t kTxData[24] = {
+      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb, 0xbd,
+      0xd4, 0xcf, 0xa8, 0xbf, 0x85, 0xf2, 0x6a, 0xe3, 0xba, 0xf1, 0x49, 0x00,
+  };
+  constexpr uint8_t kExpectedRxData[24] = {
+      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
+      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
+  };
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  fake_bti_pinned_vmo_info_t dma_vmos[2] = {};
+  size_t actual_vmos = 0;
+  RunInEnvironmentTypeContext([&dma_vmos, &actual_vmos](AmlSpiBtiPaddrEnvironment& env) {
+    EXPECT_OK(fake_bti_get_pinned_vmos(env.GetBtiLocal()->get(), dma_vmos, std::size(dma_vmos),
+                                       &actual_vmos));
+    EXPECT_EQ(actual_vmos, std::size(dma_vmos));
+  });
+
+  zx::vmo tx_dma_vmo(dma_vmos[0].vmo);
+  zx::vmo rx_dma_vmo(dma_vmos[1].vmo);
+
+  rx_dma_vmo.write(kExpectedRxData, 0, sizeof(kExpectedRxData));
+
+  zx_paddr_t tx_paddr = 0;
+  zx_paddr_t rx_paddr = 0;
+
+  driver()->mmio()[AML_SPI_DRADDR].SetWriteCallback(
+      [&tx_paddr](uint64_t value) { tx_paddr = value; });
+  driver()->mmio()[AML_SPI_DWADDR].SetWriteCallback(
+      [&rx_paddr](uint64_t value) { rx_paddr = value; });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  uint8_t buf[sizeof(kTxData)] = {};
+  memcpy(buf, kTxData, sizeof(buf));
+
+  fdf::Arena arena('TEST');
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, sizeof(buf)))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        ASSERT_EQ(result->value()->rxdata.count(), sizeof(buf));
+        EXPECT_TRUE(IsBytesEqual(kExpectedRxData, result->value()->rxdata.data(), sizeof(buf)));
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  // Verify that the driver wrote the TX data to the TX VMO with the original byte order.
+  EXPECT_OK(tx_dma_vmo.read(buf, 0, sizeof(buf)));
+  EXPECT_TRUE(IsBytesEqual(kTxData, buf, sizeof(buf)));
+
+  EXPECT_EQ(tx_paddr, AmlSpiBtiPaddrEnvironment::kDmaPaddrs[0]);
+  EXPECT_EQ(rx_paddr, AmlSpiBtiPaddrEnvironment::kDmaPaddrs[1]);
+
+  RunInEnvironmentTypeContext([](AmlSpiExchangeDmaClientReversesBufferEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+  });
+}
+
+}  // namespace spi
diff --git a/src/devices/spi/drivers/aml-spi/tests/aml-spi-clock-mode-test.cc b/src/devices/spi/drivers/aml-spi/tests/aml-spi-clock-mode-test.cc
new file mode 100644
index 0000000..b530fb4
--- /dev/null
+++ b/src/devices/spi/drivers/aml-spi/tests/aml-spi-clock-mode-test.cc
@@ -0,0 +1,168 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/devices/spi/drivers/aml-spi/tests/aml-spi-test-env.h"
+
+namespace spi {
+
+class AmlSpiNormalClockModeTestEnvironment : public BaseTestEnvironment {
+  void SetMetadata(compat::DeviceServer& compat) override {
+    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
+        .bus_id = 0,
+        .cs_count = 2,
+        .cs = {5, 3},
+        .clock_divider_register_value = 0x5,
+        .use_enhanced_clock_mode = false,
+    };
+
+    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
+  }
+};
+
+class AmlSpiNormalClockModeFixtureConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiNormalClockModeTestEnvironment;
+};
+
+class AmlSpiNormalClockModeTest
+    : public fdf_testing::DriverTestFixture<AmlSpiNormalClockModeFixtureConfig> {};
+
+TEST_F(AmlSpiNormalClockModeTest, Test) {
+  auto conreg = ConReg::Get().FromValue(driver()->conreg());
+  auto enhanced_cntl = EnhanceCntl::Get().FromValue(driver()->enhance_cntl());
+  auto testreg = TestReg::Get().FromValue(driver()->testreg());
+
+  EXPECT_EQ(conreg.data_rate(), 0x5u);
+  EXPECT_EQ(conreg.drctl(), 0u);
+  EXPECT_EQ(conreg.ssctl(), 0u);
+  EXPECT_EQ(conreg.smc(), 0u);
+  EXPECT_EQ(conreg.xch(), 0u);
+  EXPECT_EQ(conreg.mode(), ConReg::kModeMaster);
+  EXPECT_EQ(conreg.en(), 1u);
+
+  EXPECT_EQ(enhanced_cntl.reg_value(), 0u);
+
+  EXPECT_EQ(testreg.dlyctl(), 0x15u);
+  EXPECT_EQ(testreg.clk_free_en(), 1u);
+}
+
+class AmlSpiEnhancedClockModeEnvironment : public BaseTestEnvironment {
+  void SetMetadata(compat::DeviceServer& compat) override {
+    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
+        .bus_id = 0,
+        .cs_count = 2,
+        .cs = {5, 3},
+        .clock_divider_register_value = 0xa5,
+        .use_enhanced_clock_mode = true,
+        .delay_control = 0b00'11'00,
+    };
+
+    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
+  }
+};
+
+class AmlSpiEnhancedClockModeFixtureConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiEnhancedClockModeEnvironment;
+};
+
+class AmlSpiEnhancedClockModeTest
+    : public fdf_testing::DriverTestFixture<AmlSpiEnhancedClockModeFixtureConfig> {};
+
+TEST_F(AmlSpiEnhancedClockModeTest, Test) {
+  auto conreg = ConReg::Get().FromValue(driver()->conreg());
+  auto enhanced_cntl = EnhanceCntl::Get().FromValue(driver()->enhance_cntl());
+  auto testreg = TestReg::Get().FromValue(driver()->testreg());
+
+  EXPECT_EQ(conreg.data_rate(), 0u);
+  EXPECT_EQ(conreg.drctl(), 0u);
+  EXPECT_EQ(conreg.ssctl(), 0u);
+  EXPECT_EQ(conreg.smc(), 0u);
+  EXPECT_EQ(conreg.xch(), 0u);
+  EXPECT_EQ(conreg.mode(), ConReg::kModeMaster);
+  EXPECT_EQ(conreg.en(), 1u);
+
+  EXPECT_EQ(enhanced_cntl.main_clock_always_on(), 0u);
+  EXPECT_EQ(enhanced_cntl.clk_cs_delay_enable(), 1u);
+  EXPECT_EQ(enhanced_cntl.cs_oen_enhance_enable(), 1u);
+  EXPECT_EQ(enhanced_cntl.clk_oen_enhance_enable(), 1u);
+  EXPECT_EQ(enhanced_cntl.mosi_oen_enhance_enable(), 1u);
+  EXPECT_EQ(enhanced_cntl.spi_clk_select(), 1u);
+  EXPECT_EQ(enhanced_cntl.enhance_clk_div(), 0xa5u);
+  EXPECT_EQ(enhanced_cntl.clk_cs_delay(), 0u);
+
+  EXPECT_EQ(testreg.dlyctl(), 0b00'11'00u);
+  EXPECT_EQ(testreg.clk_free_en(), 1u);
+}
+
+class AmlSpiNormalClockModeInvalidDividerEnvironment : public BaseTestEnvironment {
+  void SetMetadata(compat::DeviceServer& compat) override {
+    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
+        .bus_id = 0,
+        .cs_count = 2,
+        .cs = {5, 3},
+        .clock_divider_register_value = 0xa5,
+        .use_enhanced_clock_mode = false,
+    };
+
+    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
+  }
+};
+
+class AmlSpiNormalClockModeInvalidDividerFixtureConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = false;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiNormalClockModeInvalidDividerEnvironment;
+};
+
+class AmlSpiNormalClockModeInvalidDividerTest
+    : public fdf_testing::DriverTestFixture<AmlSpiNormalClockModeInvalidDividerFixtureConfig> {};
+
+TEST_F(AmlSpiNormalClockModeInvalidDividerTest, Test) { EXPECT_TRUE(StartDriver().is_error()); }
+
+class AmlSpiEnhancedClockModeInvalidDividerEnvironment : public BaseTestEnvironment {
+ public:
+  void SetMetadata(compat::DeviceServer& compat) override {
+    constexpr amlogic_spi::amlspi_config_t kSpiConfig{
+        .bus_id = 0,
+        .cs_count = 2,
+        .cs = {5, 3},
+        .clock_divider_register_value = 0x1a5,
+        .use_enhanced_clock_mode = true,
+    };
+
+    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
+  }
+};
+
+class AmlSpiEnhancedClockModeInvalidDividerFixtureConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = false;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiEnhancedClockModeInvalidDividerEnvironment;
+};
+
+class AmlSpiEnhancedClockModeInvalidDividerTest
+    : public fdf_testing::DriverTestFixture<AmlSpiEnhancedClockModeInvalidDividerFixtureConfig> {};
+
+TEST_F(AmlSpiEnhancedClockModeInvalidDividerTest, Test) { EXPECT_TRUE(StartDriver().is_error()); }
+
+}  // namespace spi
diff --git a/src/devices/spi/drivers/aml-spi/tests/aml-spi-shutdown-test.cc b/src/devices/spi/drivers/aml-spi/tests/aml-spi-shutdown-test.cc
new file mode 100644
index 0000000..f2c0ce8
--- /dev/null
+++ b/src/devices/spi/drivers/aml-spi/tests/aml-spi-shutdown-test.cc
@@ -0,0 +1,67 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/devices/spi/drivers/aml-spi/tests/aml-spi-test-env.h"
+
+namespace spi {
+
+class AmlSpiShutdownConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = false;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = BaseTestEnvironment;
+};
+
+class AmlSpiShutdownTest : public fdf_testing::DriverTestFixture<AmlSpiShutdownConfig> {};
+
+TEST_F(AmlSpiShutdownTest, Shutdown) {
+  // Must outlive AmlSpi device.
+  bool dmareg_cleared = false;
+  bool conreg_cleared = false;
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  uint8_t buf[16] = {};
+  fdf::Arena arena('TEST');
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, sizeof(buf)))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok() && result->is_ok());
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  driver()->mmio()[AML_SPI_DMAREG].SetWriteCallback(
+      [&dmareg_cleared](uint64_t value) { dmareg_cleared = value == 0; });
+
+  driver()->mmio()[AML_SPI_CONREG].SetWriteCallback(
+      [&conreg_cleared](uint64_t value) { conreg_cleared = value == 0; });
+
+  EXPECT_TRUE(StopDriver().is_ok());
+
+  // All SPI devices have been released at this point, so no further calls can be made.
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+    ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear());
+  });
+
+  ShutdownDispatchersAndDestroyDriver();
+
+  EXPECT_TRUE(dmareg_cleared);
+  EXPECT_TRUE(conreg_cleared);
+}
+
+}  // namespace spi
diff --git a/src/devices/spi/drivers/aml-spi/tests/aml-spi-test-env.h b/src/devices/spi/drivers/aml-spi/tests/aml-spi-test-env.h
new file mode 100644
index 0000000..f52707e
--- /dev/null
+++ b/src/devices/spi/drivers/aml-spi/tests/aml-spi-test-env.h
@@ -0,0 +1,249 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_DEVICES_SPI_DRIVERS_AML_SPI_TESTS_AML_SPI_TEST_ENV_H_
+#define SRC_DEVICES_SPI_DRIVERS_AML_SPI_TESTS_AML_SPI_TEST_ENV_H_
+
+#include <endian.h>
+#include <fidl/fuchsia.hardware.platform.device/cpp/wire_test_base.h>
+#include <lib/ddk/metadata.h>
+#include <lib/driver/testing/cpp/fixtures/gtest_fixture.h>
+#include <lib/fake-bti/bti.h>
+#include <lib/zx/clock.h>
+#include <lib/zx/vmo.h>
+#include <zircon/errors.h>
+
+#include <fake-mmio-reg/fake-mmio-reg.h>
+
+#include "src/devices/gpio/testing/fake-gpio/fake-gpio.h"
+#include "src/devices/registers/testing/mock-registers/mock-registers.h"
+#include "src/devices/spi/drivers/aml-spi/aml-spi.h"
+#include "src/devices/spi/drivers/aml-spi/registers.h"
+#include "src/lib/testing/predicates/status.h"
+
+namespace spi {
+
+class TestAmlSpiDriver : public AmlSpiDriver {
+ public:
+  TestAmlSpiDriver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher dispatcher)
+      : AmlSpiDriver(std::move(start_args), std::move(dispatcher)),
+        mmio_region_(sizeof(uint32_t), 17) {}
+
+  static DriverRegistration GetDriverRegistration() {
+    // Use a custom DriverRegistration to create the DUT. Without this, the non-test
+    // implementation will be used by default.
+    return FUCHSIA_DRIVER_REGISTRATION_V1(fdf_internal::DriverServer<TestAmlSpiDriver>::initialize,
+                                          fdf_internal::DriverServer<TestAmlSpiDriver>::destroy);
+  }
+
+  ddk_fake::FakeMmioRegRegion& mmio() { return mmio_region_; }
+
+  uint32_t conreg() const { return conreg_; }
+  uint32_t enhance_cntl() const { return enhance_cntl_; }
+  uint32_t testreg() const { return testreg_; }
+
+ protected:
+  fpromise::promise<fdf::MmioBuffer, zx_status_t> MapMmio(
+      fidl::WireClient<fuchsia_hardware_platform_device::Device>& pdev, uint32_t mmio_id) override {
+    return fpromise::make_promise([this]() -> fpromise::result<fdf::MmioBuffer, zx_status_t> {
+      // Set the transfer complete bit so the driver doesn't get stuck waiting on the interrupt.
+      mmio_region_[AML_SPI_STATREG].SetReadCallback(
+          []() { return StatReg::Get().FromValue(0).set_tc(1).set_te(1).set_rr(1).reg_value(); });
+
+      mmio_region_[AML_SPI_CONREG].SetWriteCallback([this](uint32_t value) { conreg_ = value; });
+      mmio_region_[AML_SPI_CONREG].SetReadCallback([this]() { return conreg_; });
+      mmio_region_[AML_SPI_ENHANCE_CNTL].SetWriteCallback(
+          [this](uint32_t value) { enhance_cntl_ = value; });
+      mmio_region_[AML_SPI_TESTREG].SetWriteCallback([this](uint32_t value) { testreg_ = value; });
+
+      return fpromise::ok(mmio_region_.GetMmioBuffer());
+    });
+  }
+
+ private:
+  ddk_fake::FakeMmioRegRegion mmio_region_;
+  uint32_t conreg_{};
+  uint32_t enhance_cntl_{};
+  uint32_t testreg_{};
+};
+
+class FakePDev : public fidl::testing::WireTestBase<fuchsia_hardware_platform_device::Device> {
+ public:
+  fuchsia_hardware_platform_device::Service::InstanceHandler GetInstanceHandler(
+      async_dispatcher_t* dispatcher) {
+    return fuchsia_hardware_platform_device::Service::InstanceHandler({
+        .device = binding_group_.CreateHandler(this, dispatcher, fidl::kIgnoreBindingClosure),
+    });
+  }
+
+  void set_interrupt(zx::interrupt interrupt) { interrupt_ = std::move(interrupt); }
+
+  void set_bti(zx::bti bti) { bti_ = std::move(bti); }
+
+ private:
+  void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override {}
+
+  void GetInterruptById(
+      fuchsia_hardware_platform_device::wire::DeviceGetInterruptByIdRequest* request,
+      GetInterruptByIdCompleter::Sync& completer) override {
+    if (request->index != 0 || !interrupt_) {
+      return completer.ReplyError(ZX_ERR_NOT_FOUND);
+    }
+
+    zx::interrupt out_interrupt;
+    zx_status_t status = interrupt_.duplicate(ZX_RIGHT_SAME_RIGHTS, &out_interrupt);
+    if (status == ZX_OK) {
+      completer.ReplySuccess(std::move(out_interrupt));
+    } else {
+      completer.ReplyError(status);
+    }
+  }
+
+  void GetBtiById(fuchsia_hardware_platform_device::wire::DeviceGetBtiByIdRequest* request,
+                  GetBtiByIdCompleter::Sync& completer) override {
+    if (request->index != 0 || !bti_) {
+      return completer.ReplyError(ZX_ERR_NOT_FOUND);
+    }
+
+    zx::bti out_bti;
+    zx_status_t status = bti_.duplicate(ZX_RIGHT_SAME_RIGHTS, &out_bti);
+    if (status == ZX_OK) {
+      completer.ReplySuccess(std::move(out_bti));
+    } else {
+      completer.ReplyError(status);
+    }
+  }
+
+  zx::interrupt interrupt_;
+  zx::bti bti_;
+  fidl::ServerBindingGroup<fuchsia_hardware_platform_device::Device> binding_group_;
+};
+
+class BaseTestEnvironment : public fdf_testing::Environment {
+ public:
+  BaseTestEnvironment()
+      : fdf_testing::Environment(), registers_(fdf::Dispatcher::GetCurrent()->async_dispatcher()) {}
+
+  zx::result<> Serve(fdf::OutgoingDirectory& to_driver_vfs) override {
+    SetUpInterrupt();
+    SetUpBti();
+
+    auto result = to_driver_vfs.AddService<fuchsia_hardware_platform_device::Service>(
+        pdev_server_.GetInstanceHandler(fdf::Dispatcher::GetCurrent()->async_dispatcher()), "pdev");
+    if (!result.is_ok()) {
+      return result.take_error();
+    }
+
+    SetMetadata(compat_);
+    compat_.Init("pdev", {});
+    EXPECT_OK(compat_.Serve(fdf::Dispatcher::GetCurrent()->async_dispatcher(), &to_driver_vfs));
+
+    // Serve a second compat instance at default in order to satisfy AmlSpiDriver's compat
+    // server. Without this, metadata doesn't get forwarded.
+    compat_default_.Init("default", {});
+    EXPECT_OK(
+        compat_default_.Serve(fdf::Dispatcher::GetCurrent()->async_dispatcher(), &to_driver_vfs));
+
+    result = to_driver_vfs.AddService<fuchsia_hardware_gpio::Service>(gpio_.CreateInstanceHandler(),
+                                                                      "gpio-cs-2");
+    if (result.is_error()) {
+      return result.take_error();
+    }
+
+    result = to_driver_vfs.AddService<fuchsia_hardware_gpio::Service>(gpio_.CreateInstanceHandler(),
+                                                                      "gpio-cs-3");
+    if (result.is_error()) {
+      return result.take_error();
+    }
+
+    result = to_driver_vfs.AddService<fuchsia_hardware_gpio::Service>(gpio_.CreateInstanceHandler(),
+                                                                      "gpio-cs-5");
+    if (result.is_error()) {
+      return result.take_error();
+    }
+
+    gpio_.SetCurrentState(fake_gpio::State{.polarity = fuchsia_hardware_gpio::GpioPolarity::kHigh,
+                                           .sub_state = fake_gpio::WriteSubState{.value = 0}});
+    gpio_.SetWriteCallback([this](fake_gpio::FakeGpio& gpio) {
+      if (gpio_writes_.empty()) {
+        EXPECT_FALSE(gpio_writes_.empty());
+        return ZX_ERR_INTERNAL;
+      }
+      auto [status, value] = gpio_writes_.front();
+      gpio_writes_.pop();
+      if (status != ZX_OK) {
+        EXPECT_EQ(value, gpio_.GetWriteValue());
+      }
+      return status;
+    });
+
+    if (SetupResetRegister()) {
+      auto result = to_driver_vfs.AddService<fuchsia_hardware_registers::Service>(
+          registers_.GetInstanceHandler(), "reset");
+      if (result.is_error()) {
+        return result.take_error();
+      }
+    }
+
+    registers_.ExpectWrite<uint32_t>(0x1c, 1 << 1, 1 << 1);
+    return zx::ok();
+  }
+
+  virtual void SetUpInterrupt() {
+    ASSERT_OK(zx::interrupt::create({}, 0, ZX_INTERRUPT_VIRTUAL, &interrupt_));
+    zx::interrupt dut_interrupt;
+    ASSERT_OK(interrupt_.duplicate(ZX_RIGHT_SAME_RIGHTS, &dut_interrupt));
+    pdev_server_.set_interrupt(std::move(dut_interrupt));
+    interrupt_.trigger(0, zx::clock::get_monotonic());
+  }
+
+  virtual void SetUpBti() {}
+
+  virtual bool SetupResetRegister() { return true; }
+
+  virtual void SetMetadata(compat::DeviceServer& compat) {
+    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
+  }
+
+  void ExpectGpioWrite(zx_status_t status, uint8_t value) { gpio_writes_.emplace(status, value); }
+
+  void VerifyGpioAndClear() {
+    EXPECT_EQ(gpio_writes_.size(), 0u);
+    gpio_writes_ = {};
+  }
+
+  bool ControllerReset() {
+    zx_status_t status = registers_.VerifyAll();
+    if (status == ZX_OK) {
+      // Always keep a single expectation in the queue, that way we can verify when the controller
+      // is not reset.
+      registers_.ExpectWrite<uint32_t>(0x1c, 1 << 1, 1 << 1);
+    }
+
+    return status == ZX_OK;
+  }
+
+ protected:
+  static constexpr amlogic_spi::amlspi_config_t kSpiConfig = {
+      .bus_id = 0,
+      .cs_count = 3,
+      .cs = {5, 3, amlogic_spi::amlspi_config_t::kCsClientManaged},
+      .clock_divider_register_value = 0,
+      .use_enhanced_clock_mode = false,
+  };
+
+  FakePDev pdev_server_;
+  zx::interrupt interrupt_;
+
+  mock_registers::MockRegisters registers_;
+  std::queue<std::pair<zx_status_t, uint8_t>> gpio_writes_;
+  fake_gpio::FakeGpio gpio_;
+
+  compat::DeviceServer compat_;
+  compat::DeviceServer compat_default_;
+};
+
+}  // namespace spi
+
+#endif  // SRC_DEVICES_SPI_DRIVERS_AML_SPI_TESTS_AML_SPI_TEST_ENV_H_
diff --git a/src/devices/spi/drivers/aml-spi/tests/aml-spi-test.cc b/src/devices/spi/drivers/aml-spi/tests/aml-spi-test.cc
new file mode 100644
index 0000000..a25068f
--- /dev/null
+++ b/src/devices/spi/drivers/aml-spi/tests/aml-spi-test.cc
@@ -0,0 +1,1138 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fidl/fuchsia.scheduler/cpp/wire.h>
+
+#include "src/devices/spi/drivers/aml-spi/tests/aml-spi-test-env.h"
+
+namespace spi {
+
+namespace {
+bool IsBytesEqual(const uint8_t* expected, const uint8_t* actual, size_t len) {
+  return memcmp(expected, actual, len) == 0;
+}
+
+zx_koid_t GetVmoKoid(const zx::vmo& vmo) {
+  zx_info_handle_basic_t info = {};
+  size_t actual = 0;
+  size_t available = 0;
+  zx_status_t status = vmo.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), &actual, &available);
+  if (status != ZX_OK || actual < 1) {
+    return ZX_KOID_INVALID;
+  }
+  return info.koid;
+}
+
+zx::result<fuchsia_scheduler::RoleName> GetSchedulerRoleName(
+    fidl::WireClient<fuchsia_driver_compat::Device> client, fdf_testing::DriverRuntime& runtime) {
+  zx::result<fuchsia_scheduler::RoleName> scheduler_role_name = zx::error(ZX_ERR_NOT_FOUND);
+  client->GetMetadata().Then(
+      [&](fidl::WireUnownedResult<fuchsia_driver_compat::Device::GetMetadata>& result) {
+        if (!result.ok()) {
+          scheduler_role_name = zx::error(result.status());
+          return;
+        }
+        if (result->is_error()) {
+          scheduler_role_name = result->take_error();
+          return;
+        }
+
+        for (auto& metadata : result->value()->metadata) {
+          if (metadata.type != DEVICE_METADATA_SCHEDULER_ROLE_NAME) {
+            continue;
+          }
+
+          size_t size = 0;
+          zx_status_t status = metadata.data.get_prop_content_size(&size);
+          if (status != ZX_OK) {
+            continue;
+          }
+
+          std::vector<uint8_t> data(size);
+          status = metadata.data.read(data.data(), 0, data.size());
+          if (status != ZX_OK) {
+            continue;
+          }
+
+          auto role_name = fidl::Unpersist<fuchsia_scheduler::RoleName>(std::move(data));
+          if (role_name.is_error()) {
+            continue;
+          }
+
+          scheduler_role_name = zx::ok(*std::move(role_name));
+          break;
+        }
+
+        runtime.Quit();
+      });
+  runtime.Run();
+  return scheduler_role_name;
+}
+
+}  // namespace
+
+class AmlSpiTestConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = BaseTestEnvironment;
+};
+
+class AmlSpiTest : public fdf_testing::DriverTestFixture<AmlSpiTestConfig> {};
+
+TEST_F(AmlSpiTest, DdkLifecycle) {
+  RunInNodeContext([](fdf_testing::TestNode& node) {
+    EXPECT_NE(node.children().find("aml-spi-0"), node.children().cend());
+  });
+}
+
+TEST_F(AmlSpiTest, ChipSelectCount) {
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(std::move(spiimpl_client.value()),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+  fdf::Arena arena('TEST');
+  spiimpl.buffer(arena)->GetChipSelectCount().Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_EQ(result->count, 3u);
+    runtime().Quit();
+  });
+  runtime().Run();
+}
+
+TEST_F(AmlSpiTest, Exchange) {
+  uint8_t kTxData[] = {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12};
+  constexpr uint8_t kExpectedRxData[] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab};
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  driver()->mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return kExpectedRxData[0]; });
+
+  uint64_t tx_data = 0;
+  driver()->mmio()[AML_SPI_TXDATA].SetWriteCallback(
+      [&tx_data](uint64_t value) { tx_data = value; });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  fdf::Arena arena('TEST');
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(kTxData, sizeof(kTxData)))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok() && result->is_ok());
+        ASSERT_EQ(result->value()->rxdata.count(), sizeof(kExpectedRxData));
+        EXPECT_TRUE(
+            IsBytesEqual(result->value()->rxdata.data(), kExpectedRxData, sizeof(kExpectedRxData)));
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  EXPECT_EQ(tx_data, kTxData[0]);
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+    ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear());
+  });
+}
+
+TEST_F(AmlSpiTest, ExchangeCsManagedByClient) {
+  uint8_t kTxData[] = {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12};
+  constexpr uint8_t kExpectedRxData[] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab};
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  driver()->mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return kExpectedRxData[0]; });
+
+  uint64_t tx_data = 0;
+  driver()->mmio()[AML_SPI_TXDATA].SetWriteCallback(
+      [&tx_data](uint64_t value) { tx_data = value; });
+
+  fdf::Arena arena('TEST');
+  spiimpl.buffer(arena)
+      ->ExchangeVector(2, fidl::VectorView<uint8_t>::FromExternal(kTxData, sizeof(kTxData)))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok() && result->is_ok());
+        ASSERT_EQ(result->value()->rxdata.count(), sizeof(kExpectedRxData));
+        EXPECT_TRUE(
+            IsBytesEqual(result->value()->rxdata.data(), kExpectedRxData, sizeof(kExpectedRxData)));
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  EXPECT_EQ(tx_data, kTxData[0]);
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+
+    // There should be no GPIO calls as the client manages CS for this device.
+    ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear());
+  });
+}
+
+TEST_F(AmlSpiTest, RegisterVmo) {
+  using fuchsia_hardware_sharedmemory::SharedVmoRight;
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  zx::vmo test_vmo;
+  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
+
+  const zx_koid_t test_vmo_koid = GetVmoKoid(test_vmo);
+
+  fdf::Arena arena('TEST');
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_error());
+        });
+  }
+
+  spiimpl.buffer(arena)->UnregisterVmo(0, 1).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    ASSERT_TRUE(result->is_ok());
+    EXPECT_EQ(test_vmo_koid, GetVmoKoid(result->value()->vmo));
+  });
+
+  spiimpl.buffer(arena)->UnregisterVmo(0, 1).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+    runtime().Quit();
+  });
+  runtime().Run();
+}
+
+TEST_F(AmlSpiTest, TransmitVmo) {
+  using fuchsia_hardware_sharedmemory::SharedVmoRight;
+
+  constexpr uint8_t kTxData[] = {0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5};
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  zx::vmo test_vmo;
+  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
+
+  fdf::Arena arena('TEST');
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 256, PAGE_SIZE - 256}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  EXPECT_OK(test_vmo.write(kTxData, 512, sizeof(kTxData)));
+
+  uint64_t tx_data = 0;
+  driver()->mmio()[AML_SPI_TXDATA].SetWriteCallback(
+      [&tx_data](uint64_t value) { tx_data = value; });
+
+  spiimpl.buffer(arena)->TransmitVmo(0, {1, 256, sizeof(kTxData)}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+    runtime().Quit();
+  });
+  runtime().Run();
+
+  EXPECT_EQ(tx_data, kTxData[0]);
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+    ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear());
+  });
+}
+
+TEST_F(AmlSpiTest, ReceiveVmo) {
+  using fuchsia_hardware_sharedmemory::SharedVmoRight;
+
+  constexpr uint8_t kExpectedRxData[] = {0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78};
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  zx::vmo test_vmo;
+  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
+
+  fdf::Arena arena('TEST');
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 256, PAGE_SIZE - 256},
+                      SharedVmoRight::kRead | SharedVmoRight::kWrite)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  driver()->mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return kExpectedRxData[0]; });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)->ReceiveVmo(0, {1, 512, sizeof(kExpectedRxData)}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+    runtime().Quit();
+  });
+  runtime().Run();
+
+  uint8_t rx_buffer[sizeof(kExpectedRxData)];
+  EXPECT_OK(test_vmo.read(rx_buffer, 768, sizeof(rx_buffer)));
+  EXPECT_TRUE(IsBytesEqual(rx_buffer, kExpectedRxData, sizeof(rx_buffer)));
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+    ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear());
+  });
+}
+
+TEST_F(AmlSpiTest, ExchangeVmo) {
+  using fuchsia_hardware_sharedmemory::SharedVmoRight;
+
+  constexpr uint8_t kTxData[] = {0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef};
+  constexpr uint8_t kExpectedRxData[] = {0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78};
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  zx::vmo test_vmo;
+  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
+
+  fdf::Arena arena('TEST');
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 256, PAGE_SIZE - 256},
+                      SharedVmoRight::kRead | SharedVmoRight::kWrite)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  driver()->mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return kExpectedRxData[0]; });
+
+  uint64_t tx_data = 0;
+  driver()->mmio()[AML_SPI_TXDATA].SetWriteCallback(
+      [&tx_data](uint64_t value) { tx_data = value; });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  EXPECT_OK(test_vmo.write(kTxData, 512, sizeof(kTxData)));
+
+  spiimpl.buffer(arena)
+      ->ExchangeVmo(0, {1, 256, sizeof(kTxData)}, {1, 512, sizeof(kExpectedRxData)})
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        EXPECT_TRUE(result->is_ok());
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  uint8_t rx_buffer[sizeof(kExpectedRxData)];
+  EXPECT_OK(test_vmo.read(rx_buffer, 768, sizeof(rx_buffer)));
+  EXPECT_TRUE(IsBytesEqual(rx_buffer, kExpectedRxData, sizeof(rx_buffer)));
+
+  EXPECT_EQ(tx_data, kTxData[0]);
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+    ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear());
+  });
+}
+
+TEST_F(AmlSpiTest, TransfersOutOfRange) {
+  using fuchsia_hardware_sharedmemory::SharedVmoRight;
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  zx::vmo test_vmo;
+  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
+
+  fdf::Arena arena('TEST');
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(1, 1, {std::move(vmo), PAGE_SIZE - 4, 4},
+                      SharedVmoRight::kRead | SharedVmoRight::kWrite)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)->ExchangeVmo(1, {1, 0, 2}, {1, 2, 2}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+  });
+  spiimpl.buffer(arena)->ExchangeVmo(1, {1, 0, 2}, {1, 3, 2}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+  spiimpl.buffer(arena)->ExchangeVmo(1, {1, 3, 2}, {1, 0, 2}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+  spiimpl.buffer(arena)->ExchangeVmo(1, {1, 0, 3}, {1, 2, 3}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)->TransmitVmo(1, {1, 0, 4}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+  });
+  spiimpl.buffer(arena)->TransmitVmo(1, {1, 0, 5}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+  spiimpl.buffer(arena)->TransmitVmo(1, {1, 3, 2}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+  spiimpl.buffer(arena)->TransmitVmo(1, {1, 4, 1}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+  spiimpl.buffer(arena)->TransmitVmo(1, {1, 5, 1}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 0, 4}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+  });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 3, 1}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+  });
+
+  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 3, 2}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 4, 1}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+  spiimpl.buffer(arena)->ReceiveVmo(1, {1, 5, 1}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+    runtime().Quit();
+  });
+  runtime().Run();
+
+  RunInEnvironmentTypeContext(
+      [](BaseTestEnvironment& env) { ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear()); });
+}
+
+TEST_F(AmlSpiTest, VmoBadRights) {
+  using fuchsia_hardware_sharedmemory::SharedVmoRight;
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  zx::vmo test_vmo;
+  EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &test_vmo));
+
+  fdf::Arena arena('TEST');
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 0, 256}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(test_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 2, {std::move(vmo), 0, 256},
+                      SharedVmoRight::kRead | SharedVmoRight::kWrite)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)->ExchangeVmo(0, {1, 0, 128}, {2, 128, 128}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+  });
+  spiimpl.buffer(arena)->ExchangeVmo(0, {2, 0, 128}, {1, 128, 128}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_EQ(result->error_value(), ZX_ERR_ACCESS_DENIED);
+  });
+  spiimpl.buffer(arena)->ExchangeVmo(0, {1, 0, 128}, {1, 128, 128}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_EQ(result->error_value(), ZX_ERR_ACCESS_DENIED);
+  });
+  spiimpl.buffer(arena)->ReceiveVmo(0, {1, 0, 128}).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_EQ(result->error_value(), ZX_ERR_ACCESS_DENIED);
+    runtime().Quit();
+  });
+  runtime().Run();
+
+  RunInEnvironmentTypeContext(
+      [](BaseTestEnvironment& env) { ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear()); });
+}
+
+TEST_F(AmlSpiTest, Exchange64BitWords) {
+  uint8_t kTxData[] = {
+      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb, 0xbd,
+      0xd4, 0xcf, 0xa8, 0xbf, 0x85, 0xf2, 0x6a, 0xe3, 0xba, 0xf1, 0x49, 0x00,
+  };
+  constexpr uint8_t kExpectedRxData[] = {
+      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
+      0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f, 0xea, 0x2b, 0x8f, 0x8f,
+  };
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  // First (and only) word of kExpectedRxData with bytes swapped.
+  driver()->mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return 0xea2b'8f8f; });
+
+  uint64_t tx_data = 0;
+  driver()->mmio()[AML_SPI_TXDATA].SetWriteCallback(
+      [&tx_data](uint64_t value) { tx_data = value; });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  fdf::Arena arena('TEST');
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(kTxData, sizeof(kTxData)))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok() && result->is_ok());
+        ASSERT_EQ(result->value()->rxdata.count(), sizeof(kExpectedRxData));
+        EXPECT_TRUE(
+            IsBytesEqual(result->value()->rxdata.data(), kExpectedRxData, sizeof(kExpectedRxData)));
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  // Last word of kTxData with bytes swapped.
+  EXPECT_EQ(tx_data, 0xbaf1'4900);
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+    ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear());
+  });
+}
+
+TEST_F(AmlSpiTest, Exchange64Then8BitWords) {
+  uint8_t kTxData[] = {
+      0x3c, 0xa7, 0x5f, 0xc8, 0x4b, 0x0b, 0xdf, 0xef, 0xb9, 0xa0, 0xcb,
+      0xbd, 0xd4, 0xcf, 0xa8, 0xbf, 0x85, 0xf2, 0x6a, 0xe3, 0xba,
+  };
+  constexpr uint8_t kExpectedRxData[] = {
+      0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00,
+      0xea, 0x00, 0x00, 0x00, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea,
+  };
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  driver()->mmio()[AML_SPI_RXDATA].SetReadCallback([]() { return 0xea; });
+
+  uint64_t tx_data = 0;
+  driver()->mmio()[AML_SPI_TXDATA].SetWriteCallback(
+      [&tx_data](uint64_t value) { tx_data = value; });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  fdf::Arena arena('TEST');
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(kTxData, sizeof(kTxData)))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok() && result->is_ok());
+        ASSERT_EQ(result->value()->rxdata.count(), sizeof(kExpectedRxData));
+        EXPECT_TRUE(
+            IsBytesEqual(result->value()->rxdata.data(), kExpectedRxData, sizeof(kExpectedRxData)));
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  EXPECT_EQ(tx_data, 0xbau);
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    EXPECT_FALSE(env.ControllerReset());
+    ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear());
+  });
+}
+
+TEST_F(AmlSpiTest, ExchangeResetsController) {
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  fdf::Arena arena('TEST');
+
+  uint8_t buf[17] = {};
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 17))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 17u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  // Controller should be reset because a 64-bit transfer was preceded by a transfer of an odd
+  // number of bytes.
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 16))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 16u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_TRUE(env.ControllerReset()); });
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 3))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 3u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 6))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 6u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 8))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 8u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_TRUE(env.ControllerReset()); });
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  RunInEnvironmentTypeContext(
+      [](BaseTestEnvironment& env) { ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear()); });
+}
+
+TEST_F(AmlSpiTest, ReleaseVmos) {
+  using fuchsia_hardware_sharedmemory::SharedVmoRight;
+
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  fdf::Arena arena('TEST');
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+
+    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 2, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  spiimpl.buffer(arena)->UnregisterVmo(0, 2).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+  });
+
+  // Release VMO 1 and make sure that a subsequent call to unregister it fails.
+  EXPECT_TRUE(spiimpl.buffer(arena)->ReleaseRegisteredVmos(0).ok());
+
+  spiimpl.buffer(arena)->UnregisterVmo(0, 2).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+  });
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+
+    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 2, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+  }
+
+  // Release both VMOs and make sure that they can be registered again.
+  EXPECT_TRUE(spiimpl.buffer(arena)->ReleaseRegisteredVmos(0).ok());
+
+  {
+    zx::vmo vmo;
+    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 1, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+        });
+
+    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
+    spiimpl.buffer(arena)
+        ->RegisterVmo(0, 2, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+          runtime().Quit();
+        });
+  }
+
+  runtime().Run();
+}
+
+TEST_F(AmlSpiTest, ReleaseVmosAfterClientsUnbind) {
+  using fuchsia_hardware_sharedmemory::SharedVmoRight;
+
+  auto spiimpl_client1 = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client1.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl1(*std::move(spiimpl_client1),
+                                                              fdf::Dispatcher::GetCurrent()->get());
+
+  fdf::Arena arena('TEST');
+
+  // Register three VMOs through the first client.
+  for (uint32_t i = 1; i <= 3; i++) {
+    zx::vmo vmo;
+    EXPECT_OK(zx::vmo::create(PAGE_SIZE, 0, &vmo));
+    spiimpl1.buffer(arena)
+        ->RegisterVmo(0, i, {std::move(vmo), 0, PAGE_SIZE}, SharedVmoRight::kRead)
+        .Then([&](auto& result) {
+          ASSERT_TRUE(result.ok());
+          EXPECT_TRUE(result->is_ok());
+          runtime().Quit();
+        });
+    runtime().Run();
+    runtime().ResetQuit();
+  }
+
+  auto spiimpl_client2 = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client2.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl2(*std::move(spiimpl_client2),
+                                                              fdf::Dispatcher::GetCurrent()->get());
+
+  // The second client should be able to see the registered VMOs.
+  spiimpl2.buffer(arena)->UnregisterVmo(0, 1).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+    runtime().Quit();
+  });
+  runtime().Run();
+  runtime().ResetQuit();
+
+  // Unbind the first client.
+  EXPECT_TRUE(spiimpl1.UnbindMaybeGetEndpoint().is_ok());
+  runtime().RunUntilIdle();
+
+  // The VMOs registered by the first client should remain.
+  spiimpl2.buffer(arena)->UnregisterVmo(0, 2).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_ok());
+    runtime().Quit();
+  });
+  runtime().Run();
+  runtime().ResetQuit();
+
+  // Unbind the second client, then connect a third client.
+  EXPECT_TRUE(spiimpl2.UnbindMaybeGetEndpoint().is_ok());
+  runtime().RunUntilIdle();
+
+  auto spiimpl_client3 = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client3.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl3(*std::move(spiimpl_client3),
+                                                              fdf::Dispatcher::GetCurrent()->get());
+
+  // All registered VMOs should have been released after the second client unbound.
+  spiimpl3.buffer(arena)->UnregisterVmo(0, 3).Then([&](auto& result) {
+    ASSERT_TRUE(result.ok());
+    EXPECT_TRUE(result->is_error());
+    runtime().Quit();
+  });
+  runtime().Run();
+}
+
+class AmlSpiNoResetFragmentEnvironment : public BaseTestEnvironment {
+ public:
+  bool SetupResetRegister() override { return false; }
+};
+
+class AmlSpiNoResetFragmentConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiNoResetFragmentEnvironment;
+};
+
+class AmlSpiNoResetFragmentTest
+    : public fdf_testing::DriverTestFixture<AmlSpiNoResetFragmentConfig> {};
+
+TEST_F(AmlSpiNoResetFragmentTest, ExchangeWithNoResetFragment) {
+  auto spiimpl_client = Connect<fuchsia_hardware_spiimpl::Service::Device>();
+  ASSERT_TRUE(spiimpl_client.is_ok());
+
+  fdf::WireClient<fuchsia_hardware_spiimpl::SpiImpl> spiimpl(*std::move(spiimpl_client),
+                                                             fdf::Dispatcher::GetCurrent()->get());
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  fdf::Arena arena('TEST');
+
+  uint8_t buf[17] = {};
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 17))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 17u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+      });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  // Controller should not be reset because no reset fragment was provided.
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 16))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 16u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+      });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 3))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 3u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+      });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 6))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 6u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+      });
+
+  RunInEnvironmentTypeContext([](BaseTestEnvironment& env) {
+    env.ExpectGpioWrite(ZX_OK, 0);
+    env.ExpectGpioWrite(ZX_OK, 1);
+  });
+
+  spiimpl.buffer(arena)
+      ->ExchangeVector(0, fidl::VectorView<uint8_t>::FromExternal(buf, 8))
+      .Then([&](auto& result) {
+        ASSERT_TRUE(result.ok());
+        ASSERT_TRUE(result->is_ok());
+        EXPECT_EQ(result->value()->rxdata.count(), 8u);
+        RunInEnvironmentTypeContext(
+            [](BaseTestEnvironment& env) { EXPECT_FALSE(env.ControllerReset()); });
+        runtime().Quit();
+      });
+  runtime().Run();
+
+  RunInEnvironmentTypeContext(
+      [](BaseTestEnvironment& env) { ASSERT_NO_FATAL_FAILURE(env.VerifyGpioAndClear()); });
+}
+
+class AmlSpiNoIrqEnvironment : public BaseTestEnvironment {
+  virtual void SetUpInterrupt() override {}
+};
+
+class AmlSpiNoIrqConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = false;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiNoIrqEnvironment;
+};
+
+class AmlSpiNoIrqTest : public fdf_testing::DriverTestFixture<AmlSpiNoIrqConfig> {};
+
+TEST_F(AmlSpiNoIrqTest, InterruptRequired) {
+  // Bind should fail if no interrupt was provided.
+  EXPECT_TRUE(StartDriver().is_error());
+}
+
+TEST_F(AmlSpiTest, DefaultRoleMetadata) {
+  constexpr char kExpectedRoleName[] = "fuchsia.devices.spi.drivers.aml-spi.transaction";
+
+  zx::result compat_client_end = Connect<fuchsia_driver_compat::Service::Device>();
+  fidl::WireClient<fuchsia_driver_compat::Device> client(
+      *std::move(compat_client_end), fdf::Dispatcher::GetCurrent()->async_dispatcher());
+
+  zx::result<fuchsia_scheduler::RoleName> metadata =
+      GetSchedulerRoleName(std::move(client), runtime());
+  ASSERT_TRUE(metadata.is_ok());
+  EXPECT_EQ(metadata->role(), kExpectedRoleName);
+}
+
+class AmlSpiForwardRoleMetadataEnvironment : public BaseTestEnvironment {
+ public:
+  void SetMetadata(compat::DeviceServer& compat) override {
+    constexpr amlogic_spi::amlspi_config_t kSpiConfig = {
+        .bus_id = 0,
+        .cs_count = 3,
+        .cs = {5, 3, amlogic_spi::amlspi_config_t::kCsClientManaged},
+        .clock_divider_register_value = 0,
+        .use_enhanced_clock_mode = false,
+    };
+
+    EXPECT_OK(compat.AddMetadata(DEVICE_METADATA_AMLSPI_CONFIG, &kSpiConfig, sizeof(kSpiConfig)));
+
+    const fuchsia_scheduler::wire::RoleName role{kExpectedRoleName};
+
+    fit::result result = fidl::Persist(role);
+    ASSERT_TRUE(result.is_ok());
+
+    EXPECT_OK(
+        compat.AddMetadata(DEVICE_METADATA_SCHEDULER_ROLE_NAME, result->data(), result->size()));
+  }
+
+  static constexpr char kExpectedRoleName[] = "no.such.scheduler.role";
+};
+
+class AmlSpiForwardRoleMetadataConfig final {
+ public:
+  static constexpr bool kDriverOnForeground = true;
+  static constexpr bool kAutoStartDriver = true;
+  static constexpr bool kAutoStopDriver = true;
+
+  using DriverType = TestAmlSpiDriver;
+  using EnvironmentType = AmlSpiForwardRoleMetadataEnvironment;
+};
+
+class AmlSpiForwardRoleMetadataTest
+    : public fdf_testing::DriverTestFixture<AmlSpiForwardRoleMetadataConfig> {};
+
+TEST_F(AmlSpiForwardRoleMetadataTest, Test) {
+  zx::result compat_client_end = Connect<fuchsia_driver_compat::Service::Device>();
+  fidl::WireClient<fuchsia_driver_compat::Device> client(
+      *std::move(compat_client_end), fdf::Dispatcher::GetCurrent()->async_dispatcher());
+
+  zx::result<fuchsia_scheduler::RoleName> metadata =
+      GetSchedulerRoleName(std::move(client), runtime());
+  ASSERT_TRUE(metadata.is_ok());
+  EXPECT_EQ(metadata->role(), AmlSpiForwardRoleMetadataEnvironment::kExpectedRoleName);
+}
+
+}  // namespace spi
diff --git a/src/devices/spi/drivers/spi/spi-test.cc b/src/devices/spi/drivers/spi/spi-test.cc
index e1660bc..245063a 100644
--- a/src/devices/spi/drivers/spi/spi-test.cc
+++ b/src/devices/spi/drivers/spi/spi-test.cc
@@ -318,8 +318,7 @@
     // TODO(https://fxbug.dev/42075363): Migrate test to use dispatcher integration.
     parent_ = MockDevice::FakeRootParent();
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
     ns_.SyncCall([&](IncomingNamespace* ns) {
       auto service_result = ns->outgoing.AddService<fuchsia_hardware_spiimpl::Service>(
@@ -328,10 +327,10 @@
           }));
       ZX_ASSERT(service_result.is_ok());
 
-      ZX_ASSERT(ns->outgoing.Serve(std::move(endpoints->server)).is_ok());
+      ZX_ASSERT(ns->outgoing.Serve(std::move(endpoints.server)).is_ok());
     });
 
-    parent_->AddFidlService(fuchsia_hardware_spiimpl::Service::Name, std::move(endpoints->client));
+    parent_->AddFidlService(fuchsia_hardware_spiimpl::Service::Name, std::move(endpoints.client));
     SetSpiChannelMetadata(0, kSpiChannels, std::size(kSpiChannels));
     parent_->SetMetadata(DEVICE_METADATA_PRIVATE, &kTestBusId, sizeof(kTestBusId));
   }
@@ -415,9 +414,7 @@
   for (auto it = spi_bus->children().begin(); it != spi_bus->children().end(); it++, i++) {
     set_current_test_cs(i);
 
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_spi::Device>();
-    ASSERT_OK(endpoints);
-    auto& [client, server] = endpoints.value();
+    auto [client, server] = fidl::Endpoints<fuchsia_hardware_spi::Device>::Create();
     fidl::BindServer(dispatcher_->async_dispatcher(), std::move(server),
                      (*it)->GetDeviceContext<SpiChild>());
 
@@ -837,15 +834,11 @@
 
   // OpenSession should fail when another client is connected.
   {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_spi::Controller>();
-    ASSERT_OK(endpoints);
-    auto& [controller, server] = endpoints.value();
+    auto [controller, server] = fidl::Endpoints<fuchsia_hardware_spi::Controller>::Create();
     fidl::BindServer(dispatcher_->async_dispatcher(), std::move(server),
                      spi_child->GetDeviceContext<SpiChild>());
     {
-      zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_spi::Device>();
-      ASSERT_OK(endpoints);
-      auto& [device, server] = endpoints.value();
+      auto [device, server] = fidl::Endpoints<fuchsia_hardware_spi::Device>::Create();
       ASSERT_OK(fidl::WireCall(controller)->OpenSession(std::move(server)));
       ASSERT_STATUS(fidl::WireCall(device)->CanAssertCs(), ZX_ERR_PEER_CLOSED);
     }
@@ -856,9 +849,7 @@
 
   fidl::ClientEnd<fuchsia_hardware_spi::Device> device;
   while (true) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_spi::Controller>();
-    ASSERT_OK(endpoints);
-    auto& [controller, server] = endpoints.value();
+    auto [controller, server] = fidl::Endpoints<fuchsia_hardware_spi::Controller>::Create();
     fidl::BindServer(dispatcher_->async_dispatcher(), std::move(server),
                      spi_child->GetDeviceContext<SpiChild>());
     {
@@ -884,15 +875,11 @@
   }
 
   {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_spi::Controller>();
-    ASSERT_OK(endpoints);
-    auto& [controller, server] = endpoints.value();
+    auto [controller, server] = fidl::Endpoints<fuchsia_hardware_spi::Controller>::Create();
     fidl::BindServer(dispatcher_->async_dispatcher(), std::move(server),
                      spi_child->GetDeviceContext<SpiChild>());
     {
-      zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_spi::Device>();
-      ASSERT_OK(endpoints);
-      auto& [device, server] = endpoints.value();
+      auto [device, server] = fidl::Endpoints<fuchsia_hardware_spi::Device>::Create();
       ASSERT_OK(fidl::WireCall(controller)->OpenSession(std::move(server)));
       ASSERT_STATUS(fidl::WireCall(device)->CanAssertCs(), ZX_ERR_PEER_CLOSED);
     }
diff --git a/src/devices/suspend/drivers/aml-suspend/aml-suspend.cc b/src/devices/suspend/drivers/aml-suspend/aml-suspend.cc
index e7858f8..5c220c5 100644
--- a/src/devices/suspend/drivers/aml-suspend/aml-suspend.cc
+++ b/src/devices/suspend/drivers/aml-suspend/aml-suspend.cc
@@ -63,22 +63,19 @@
                   .devfs_args(devfs.Build())
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
   ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create endpoints: %s",
                 node_endpoints.status_string());
 
   fidl::WireResult result = fidl::WireCall(node())->AddChild(
-      args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+      args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
   parent_.Bind(std::move(node_endpoints->client));
   return zx::ok();
 }
diff --git a/src/devices/suspend/drivers/aml-suspend/tests/BUILD.gn b/src/devices/suspend/drivers/aml-suspend/tests/BUILD.gn
index 69f2d5e..c0589db 100644
--- a/src/devices/suspend/drivers/aml-suspend/tests/BUILD.gn
+++ b/src/devices/suspend/drivers/aml-suspend/tests/BUILD.gn
@@ -31,7 +31,6 @@
     "//src/devices/lib/amlogic",
     "//src/devices/lib/mmio",
     "//src/devices/testing/fake-mmio-reg",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
     "//src/lib/fxl/test:gtest_main",
     "//zircon/system/ulib/async-loop:async-loop-cpp",
     "//zircon/system/ulib/async-loop:async-loop-default",
diff --git a/src/devices/sysmem/drivers/sysmem/test/device_test.cc b/src/devices/sysmem/drivers/sysmem/test/device_test.cc
index f8502f5..a80e177 100644
--- a/src/devices/sysmem/drivers/sysmem/test/device_test.cc
+++ b/src/devices/sysmem/drivers/sysmem/test/device_test.cc
@@ -181,10 +181,9 @@
     });
     EXPECT_OK(pdev_loop_.StartThread());
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-    RunSyncOnLoop(pdev_loop_, [this, server = std::move(endpoints->server)]() mutable {
+    RunSyncOnLoop(pdev_loop_, [this, server = std::move(endpoints.server)]() mutable {
       outgoing_.emplace(pdev_loop_.dispatcher());
       auto device_handler =
           [this](fidl::ServerEnd<fuchsia_hardware_platform_device::Device> request) {
@@ -200,7 +199,7 @@
     });
 
     fake_parent_->AddFidlService(fuchsia_hardware_platform_device::Service::Name,
-                                 std::move(endpoints->client));
+                                 std::move(endpoints.client));
     EXPECT_EQ(sysmem_->Bind(), ZX_OK);
   }
 
@@ -214,14 +213,11 @@
   }
 
   fidl::ClientEnd<fuchsia_sysmem::Allocator> Connect() {
-    zx::result allocator_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::Allocator>();
-    EXPECT_OK(allocator_endpoints);
-    auto [allocator_client_end, allocator_server_end] = std::move(*allocator_endpoints);
+    auto [allocator_client_end, allocator_server_end] =
+        fidl::Endpoints<fuchsia_sysmem::Allocator>::Create();
 
-    zx::result connector_endpoints =
-        fidl::CreateEndpoints<fuchsia_hardware_sysmem::DriverConnector>();
-    EXPECT_OK(connector_endpoints);
-    auto [connector_client_end, connector_server_end] = std::move(*connector_endpoints);
+    auto [connector_client_end, connector_server_end] =
+        fidl::Endpoints<fuchsia_hardware_sysmem::DriverConnector>::Create();
 
     fidl::BindServer(loop_.dispatcher(), std::move(connector_server_end), sysmem_.get());
     EXPECT_OK(loop_.StartThread());
@@ -235,9 +231,8 @@
   fidl::ClientEnd<fuchsia_sysmem::BufferCollection> AllocateNonSharedCollection() {
     fidl::WireSyncClient<fuchsia_sysmem::Allocator> allocator(Connect());
 
-    zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-    EXPECT_OK(collection_endpoints);
-    auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+    auto [collection_client_end, collection_server_end] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
     EXPECT_OK(allocator->AllocateNonSharedCollection(std::move(collection_server_end)));
     return std::move(collection_client_end);
@@ -275,9 +270,7 @@
 
 // Test that creating and tearing down a SecureMem connection works correctly.
 TEST_F(FakeDdkSysmem, DummySecureMem) {
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_sysmem::SecureMem>();
-  ASSERT_OK(endpoints);
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_sysmem::SecureMem>::Create();
   ASSERT_OK(sysmem_->CommonSysmemRegisterSecureMem(std::move(client)));
 
   // This shouldn't deadlock waiting for a message on the channel.
@@ -290,9 +283,8 @@
 TEST_F(FakeDdkSysmem, NamedToken) {
   fidl::WireSyncClient<fuchsia_sysmem::Allocator> allocator(Connect());
 
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints);
-  auto [token_client_end, token_server_end] = std::move(*token_endpoints);
+  auto [token_client_end, token_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   EXPECT_OK(allocator->AllocateSharedCollection(std::move(token_server_end)));
 
@@ -303,9 +295,8 @@
   EXPECT_OK(token->SetName(100u, "a"));
   EXPECT_OK(token->SetName(6u, "b"));
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  EXPECT_OK(collection_endpoints);
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
   EXPECT_OK(
       allocator->BindSharedCollection(token.TakeClientEnd(), std::move(collection_server_end)));
@@ -369,9 +360,8 @@
 TEST_F(FakeDdkSysmem, NamedAllocatorToken) {
   fidl::WireSyncClient<fuchsia_sysmem::Allocator> allocator(Connect());
 
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints);
-  auto [token_client_end, token_server_end] = std::move(*token_endpoints);
+  auto [token_client_end, token_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   EXPECT_OK(allocator->AllocateSharedCollection(std::move(token_server_end)));
 
@@ -380,9 +370,8 @@
   EXPECT_OK(token->SetDebugClientInfo("bad", 6));
   EXPECT_OK(allocator->SetDebugClientInfo("a", 5));
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  EXPECT_OK(collection_endpoints);
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
   EXPECT_OK(
       allocator->BindSharedCollection(token.TakeClientEnd(), std::move(collection_server_end)));
diff --git a/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz.cc b/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz.cc
index 9c143b7..8463df02 100644
--- a/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz.cc
+++ b/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz.cc
@@ -42,16 +42,14 @@
   LOGRTN(allocator_client.status_value(), "Failed to connect to sysmem driver.\n");
   fidl::WireSyncClient<fuchsia_sysmem::Allocator> allocator(std::move(allocator_client.value()));
 
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  LOGRTN(token_endpoints.status_value(), "Failed token channel create.\n");
-  auto [token_client_end, token_server_end] = std::move(*token_endpoints);
+  auto [token_client_end, token_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   auto allocate_result = allocator->AllocateSharedCollection(std::move(token_server_end));
   LOGRTN(allocate_result.status(), "Failed to allocate shared collection.\n");
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  LOGRTN(collection_endpoints.status_value(), "Failed collection channel create.\n");
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
   auto bind_result = allocator->BindSharedCollection(std::move(token_client_end),
                                                      std::move(collection_server_end));
diff --git a/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz_common.cc b/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz_common.cc
index 8d49f8e..e63b354 100644
--- a/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz_common.cc
+++ b/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz_common.cc
@@ -62,12 +62,8 @@
 
   fidl::BindServer(loop_.dispatcher(), std::move(driver_endpoints->server), &sysmem_);
 
-  zx::result allocator_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::Allocator>();
-  if (allocator_endpoints.is_error()) {
-    return zx::error(allocator_endpoints.status_value());
-  }
-
-  auto [allocator_client_end, allocator_server_end] = std::move(*allocator_endpoints);
+  auto [allocator_client_end, allocator_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::Allocator>::Create();
 
   fidl::WireSyncClient<fuchsia_hardware_sysmem::DriverConnector> driver_client(
       std::move(driver_endpoints->client));
diff --git a/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz_multi.cc b/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz_multi.cc
index 15c1a58..1c604c6 100644
--- a/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz_multi.cc
+++ b/src/devices/sysmem/tests/sysmem/fuzz/sysmem_fuzz_multi.cc
@@ -21,18 +21,16 @@
   fidl::WireSyncClient<fuchsia_sysmem::Allocator> allocator_1(
       std::move(allocator_client_1.value()));
 
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  LOGRTN(token_endpoints.status_value(), "Failed token 1 channel create.\n");
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 1 creates a token and new LogicalBufferCollection using
   // AllocateSharedCollection().
   auto new_collection_result = allocator_1->AllocateSharedCollection(std::move(token_server_1));
   LOGRTN(new_collection_result.status(), "Failed client 1 shared collection allocate.\n");
 
-  zx::result token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  LOGRTN(token_endpoints_2.status_value(), "Failed token 2 channel create.\n");
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -42,18 +40,16 @@
   auto duplicate_result_2 = token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2));
   LOGRTN(duplicate_result_2.status(), "Failed token 1 -> 2 duplicate.\n");
 
-  zx::result token_endpoints_3 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  LOGRTN(token_endpoints_3.status_value(), "Failed token 3 channel create.\n");
-  auto [token_client_3, token_server_3] = std::move(*token_endpoints_3);
+  auto [token_client_3, token_server_3] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 3 is used to test a participant that doesn't set any constraints
   // and only wants a notification that the allocation is done.
   auto duplicate_result_3 = token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_3));
   LOGRTN(duplicate_result_3.status(), "Failed token 1 -> 3 duplicate.\n");
 
-  zx::result collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  LOGRTN(collection_endpoints_1.status_value(), "Failed collection 1 channel create.\n");
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   LOGRTNC(token_1.client_end().channel().get() == ZX_HANDLE_INVALID, "Invalid token client 1.\n");
   auto bind_result =
       allocator_1->BindSharedCollection(token_1.TakeClientEnd(), std::move(collection_server_1));
@@ -78,9 +74,8 @@
   fidl::WireSyncClient<fuchsia_sysmem::Allocator> allocator_2(
       std::move(allocator_client_2.value()));
 
-  zx::result collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  LOGRTN(collection_endpoints_2.status_value(), "Failed collection 2 channel create.\n");
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient<fuchsia_sysmem::BufferCollection> collection_2(
       std::move(collection_client_2));
 
@@ -96,9 +91,8 @@
       allocator_2->BindSharedCollection(std::move(token_client_2), std::move(collection_server_2));
   LOGRTN(bind_result_2.status(), "Failed BindSharedCollection 2.\n");
 
-  zx::result collection_endpoints_3 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  LOGRTN(collection_endpoints_3.status_value(), "Failed collection 3 channel create.\n");
-  auto [collection_client_3, collection_server_3] = std::move(*collection_endpoints_3);
+  auto [collection_client_3, collection_server_3] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient<fuchsia_sysmem::BufferCollection> collection_3(
       std::move(collection_client_3));
   LOGRTNC(token_client_3.channel().get() == ZX_HANDLE_INVALID, "Invalid token client 3.\n");
diff --git a/src/devices/sysmem/tests/sysmem/sysmem_tests.cc b/src/devices/sysmem/tests/sysmem/sysmem_tests.cc
index 0c0f331..d28622b 100644
--- a/src/devices/sysmem/tests/sysmem/sysmem_tests.cc
+++ b/src/devices/sysmem/tests/sysmem/sysmem_tests.cc
@@ -139,12 +139,8 @@
 }
 
 zx_status_t verify_connectivity_v1(fidl::WireSyncClient<fuchsia_sysmem::Allocator>& allocator) {
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  EXPECT_OK(collection_endpoints);
-  if (!collection_endpoints.is_ok()) {
-    return collection_endpoints.status_value();
-  }
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
   auto result = allocator->AllocateNonSharedCollection(std::move(collection_server_end));
   EXPECT_OK(result);
@@ -183,12 +179,8 @@
     return zx::error(allocator.status_value());
   }
 
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints);
-  if (!token_endpoints.is_ok()) {
-    return zx::error(token_endpoints.status_value());
-  }
-  auto [token_client_end, token_server_end] = std::move(*token_endpoints);
+  auto [token_client_end, token_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   auto new_collection_result = allocator->AllocateSharedCollection(std::move(token_server_end));
   EXPECT_OK(new_collection_result);
@@ -196,12 +188,8 @@
     return zx::error(new_collection_result.status());
   }
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  EXPECT_OK(collection_endpoints);
-  if (!collection_endpoints.is_ok()) {
-    return zx::error(collection_endpoints.status_value());
-  }
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
   EXPECT_NE(token_client_end.channel().get(), ZX_HANDLE_INVALID);
   auto bind_result = allocator->BindSharedCollection(std::move(token_client_end),
@@ -221,9 +209,8 @@
 fidl::WireSyncClient<fuchsia_sysmem::BufferCollectionToken> create_initial_token_v1() {
   zx::result allocator = connect_to_sysmem_service_v1();
   EXPECT_OK(allocator.status_value());
-  zx::result token_endpoints_0 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints_0.status_value());
-  auto& [token_client_0, token_server_0] = token_endpoints_0.value();
+  auto [token_client_0, token_server_0] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   EXPECT_OK(allocator->AllocateSharedCollection(std::move(token_server_0)).status());
   fidl::WireSyncClient token{std::move(token_client_0)};
   EXPECT_OK(token->Sync().status());
@@ -238,16 +225,14 @@
   for (uint32_t i = 0; i < client_count; ++i) {
     auto cur_token = std::move(next_token);
     if (i < client_count - 1) {
-      zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-      EXPECT_OK(token_endpoints.status_value());
-      auto& [token_client_endpoint, token_server_endpoint] = token_endpoints.value();
+      auto [token_client_endpoint, token_server_endpoint] =
+          fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
       EXPECT_OK(
           cur_token->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_endpoint)).status());
       next_token = fidl::WireSyncClient(std::move(token_client_endpoint));
     }
-    zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-    EXPECT_OK(collection_endpoints.status_value());
-    auto& [collection_client_endpoint, collection_server_endpoint] = collection_endpoints.value();
+    auto [collection_client_endpoint, collection_server_endpoint] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
     EXPECT_OK(
         allocator
             ->BindSharedCollection(cur_token.TakeClientEnd(), std::move(collection_server_endpoint))
@@ -265,9 +250,8 @@
 
 fidl::WireSyncClient<fuchsia_sysmem::BufferCollectionToken> create_token_under_token_v1(
     fidl::WireSyncClient<fuchsia_sysmem::BufferCollectionToken>& token_a) {
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints.status_value());
-  auto& [token_b_client, token_b_server] = token_endpoints.value();
+  auto [token_b_client, token_b_server] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   EXPECT_OK(token_a->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_b_server)).status());
   fidl::WireSyncClient token_b{std::move(token_b_client)};
   EXPECT_OK(token_b->Sync().status());
@@ -276,9 +260,8 @@
 
 fidl::WireSyncClient<fuchsia_sysmem::BufferCollectionTokenGroup> create_group_under_token_v1(
     fidl::WireSyncClient<fuchsia_sysmem::BufferCollectionToken>& token) {
-  zx::result group_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionTokenGroup>();
-  EXPECT_OK(group_endpoints.status_value());
-  auto& [group_client, group_server] = group_endpoints.value();
+  auto [group_client, group_server] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionTokenGroup>::Create();
   EXPECT_OK(token->CreateBufferCollectionTokenGroup(std::move(group_server)).status());
   auto group = fidl::WireSyncClient(std::move(group_client));
   EXPECT_OK(group->Sync().status());
@@ -288,9 +271,8 @@
 fidl::WireSyncClient<fuchsia_sysmem::BufferCollectionToken> create_token_under_group_v1(
     fidl::WireSyncClient<fuchsia_sysmem::BufferCollectionTokenGroup>& group,
     uint32_t rights_attenuation_mask = ZX_RIGHT_SAME_RIGHTS) {
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints.status_value());
-  auto& [token_client, token_server] = token_endpoints.value();
+  auto [token_client, token_server] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::Arena arena;
   auto request_builder =
       fuchsia_sysmem::wire::BufferCollectionTokenGroupCreateChildRequest::Builder(arena);
@@ -323,9 +305,8 @@
 fidl::WireSyncClient<fuchsia_sysmem::BufferCollection> convert_token_to_collection_v1(
     fidl::WireSyncClient<fuchsia_sysmem::BufferCollectionToken> token) {
   auto allocator = connect_to_sysmem_service_v1();
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  EXPECT_OK(collection_endpoints);
-  auto& [collection_client, collection_server] = collection_endpoints.value();
+  auto [collection_client, collection_server] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   EXPECT_OK(allocator->BindSharedCollection(token.TakeClientEnd(), std::move(collection_server))
                 .status());
   return fidl::WireSyncClient(std::move(collection_client));
@@ -467,20 +448,16 @@
   EXPECT_OK(allocator);
   IF_FAILURES_RETURN_FALSE();
 
-  zx::result token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints_1);
-  IF_FAILURES_RETURN_FALSE();
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 1 creates a token and new LogicalBufferCollection using
   // AllocateSharedCollection().
   EXPECT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
   IF_FAILURES_RETURN_FALSE();
 
-  zx::result token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints_2);
-  IF_FAILURES_RETURN_FALSE();
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -492,10 +469,8 @@
 
   // Client 3 is attached later.
 
-  zx::result collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  EXPECT_OK(collection_endpoints_1);
-  IF_FAILURES_RETURN_FALSE();
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   EXPECT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -578,10 +553,8 @@
   EXPECT_OK(allocator_2);
   IF_FAILURES_RETURN_FALSE();
 
-  zx::result collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  EXPECT_OK(collection_endpoints_2);
-  IF_FAILURES_RETURN_FALSE();
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
   // Just because we can, perform this sync as late as possible, just before
@@ -654,10 +627,8 @@
     collection_3 = {};
     ZX_DEBUG_ASSERT(!collection_3.is_valid());
 
-    zx::result collection_endpoints_3 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-    EXPECT_OK(collection_endpoints_3);
-    IF_FAILURES_RETURN();
-    auto [collection_client_3, collection_server_3] = std::move(*collection_endpoints_3);
+    auto [collection_client_3, collection_server_3] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
     collection_3 = fidl::WireSyncClient(std::move(collection_client_3));
 
     EXPECT_OK(allocator_2->BindSharedCollection(std::move(token_client_3),
@@ -894,23 +865,20 @@
   auto allocator = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator);
 
-  auto token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints);
-  auto [token_client, token_server] = std::move(*token_endpoints);
+  auto [token_client, token_server] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token{std::move(token_client)};
 
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server)));
 
-  auto token2_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token2_endpoints);
-  auto [token2_client, token2_server] = std::move(*token2_endpoints);
+  auto [token2_client, token2_server] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token2{std::move(token2_client)};
 
   ASSERT_OK(token->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token2_server)));
 
-  auto not_token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(not_token_endpoints);
-  auto [not_token_client, not_token_server] = std::move(*not_token_endpoints);
+  auto [not_token_client, not_token_server] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   ASSERT_OK(token->Sync());
   ASSERT_OK(token2->Sync());
@@ -1105,10 +1073,8 @@
     ASSERT_TRUE(!!(pending_signals & ZX_EVENTPAIR_PEER_CLOSED) == (i >= kNumBuffers));
   }
 
-  zx::result attached_token_endpoints =
-      fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(attached_token_endpoints);
-  auto [attached_token_client, attached_token_server] = std::move(*attached_token_endpoints);
+  auto [attached_token_client, attached_token_server] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   ASSERT_OK(collection->AttachToken(std::numeric_limits<uint32_t>::max(),
                                     std::move(attached_token_server)));
@@ -1371,9 +1337,8 @@
 
 TEST(Sysmem, NoTokenV1) {
   auto allocator = connect_to_sysmem_driver_v1();
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints);
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection{std::move(collection_client_end)};
 
   ASSERT_OK(allocator->AllocateNonSharedCollection(std::move(collection_server_end)));
@@ -1433,9 +1398,8 @@
   auto allocator_1 = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator_1);
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   ASSERT_OK(allocator_1->AllocateSharedCollection(std::move(token_server_1)));
@@ -1451,13 +1415,11 @@
   fidl::WireSyncClient<fuchsia_sysmem::BufferCollection> collection_3;
 
   {
-    auto token_endpoints_3 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-    ASSERT_OK(token_endpoints_3);
-    auto [token_client_3, token_server_3] = std::move(*token_endpoints_3);
+    auto [token_client_3, token_server_3] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
-    auto collection_endpoints_3 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-    ASSERT_OK(collection_endpoints_3);
-    auto [collection_client_3, collection_server_3] = std::move(*collection_endpoints_3);
+    auto [collection_client_3, collection_server_3] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
     ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_3)));
     ASSERT_OK(token_1->Sync());
@@ -1470,14 +1432,12 @@
     ASSERT_OK(collection_3->SetName(1u, fidl::StringView::FromExternal(kCollectionName)).status());
   }
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_2{std::move(token_client_2)};
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   const char* kClient2Name = "TestClient2";
@@ -1502,18 +1462,16 @@
 TEST(Sysmem, MultipleParticipantsV1) {
   auto allocator = connect_to_sysmem_driver_v1();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   // Client 1 creates a token and new LogicalBufferCollection using
   // AllocateSharedCollection().
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -1521,17 +1479,15 @@
   // token_client_2 transferred to another participant).
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2)));
 
-  auto token_endpoints_3 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_3);
-  auto [token_client_3, token_server_3] = std::move(*token_endpoints_3);
+  auto [token_client_3, token_server_3] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 3 is used to test a participant that doesn't set any constraints
   // and only wants a notification that the allocation is done.
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_3)));
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -1611,9 +1567,8 @@
   auto allocator_2 = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator_2);
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
   // Just because we can, perform this sync as late as possible, just before
@@ -1627,8 +1582,8 @@
   // to re-alloc all the server's held FIDL tables 4 times before we continue.  These are
   // synchronous calls, so the 4 re-allocs are done by the time this loop completes.
   //
-  // TODO(https://fxbug.dev/42108892): Switch to creating real churn instead, once we have new messages that
-  // can create real churn.
+  // TODO(https://fxbug.dev/42108892): Switch to creating real churn instead, once we have new
+  // messages that can create real churn.
   constexpr uint32_t kChurnCount = 256 * 2;  // 256 * 4;
   for (uint32_t i = 0; i < kChurnCount; ++i) {
     ASSERT_OK(collection_1->Sync());
@@ -1638,9 +1593,8 @@
   ASSERT_OK(
       allocator_2->BindSharedCollection(std::move(token_client_2), std::move(collection_server_2)));
 
-  auto collection_endpoints_3 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_3);
-  auto [collection_client_3, collection_server_3] = std::move(*collection_endpoints_3);
+  auto [collection_client_3, collection_server_3] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_3{std::move(collection_client_3)};
 
   ASSERT_NE(token_client_3.channel().get(), ZX_HANDLE_INVALID);
@@ -1788,22 +1742,19 @@
 TEST(Sysmem, ComplicatedFormatModifiersV1) {
   auto allocator = connect_to_sysmem_driver_v1();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2)));
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -1864,9 +1815,8 @@
 
   ASSERT_OK(collection_1->SetConstraints(true, std::move(constraints_1)));
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
   ASSERT_OK(collection_1->Sync());
@@ -1891,22 +1841,19 @@
 TEST(Sysmem, MultipleParticipantsColorspaceRankingV1) {
   auto allocator = connect_to_sysmem_driver_v1();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2)));
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -1955,9 +1902,8 @@
 
   ASSERT_OK(collection_1->SetConstraints(true, std::move(constraints_1)));
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
   ASSERT_OK(collection_1->Sync());
@@ -1997,8 +1943,8 @@
 //    client going first in the first couple iterations.
 TEST(Sysmem,
      MultipleParticipants_TwoImageFormatConstraintsSamePixelFormat_CompatibleColorspacesV1) {
-  // Multiple iterations to try to repro https://fxbug.dev/42139125, in case it comes back.  This should be
-  // at least 2 to check both orderings with two clients.
+  // Multiple iterations to try to repro https://fxbug.dev/42139125, in case it comes back.  This
+  // should be at least 2 to check both orderings with two clients.
   std::atomic<uint32_t> clean_failure_seen_count = 0;
   const uint32_t kCleanFailureSeenGoal = 15;
   const uint32_t kMaxIterations = 50;
@@ -2107,9 +2053,8 @@
 TEST(Sysmem, DuplicateSyncV1) {
   auto allocator = connect_to_sysmem_driver_v1();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
@@ -2121,9 +2066,8 @@
   ASSERT_EQ(duplicate_result.value().tokens.count(), 1);
   auto token_client_2 = std::move(duplicate_result.value().tokens[0]);
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2150,9 +2094,8 @@
 
   ASSERT_OK(collection_1->SetConstraints(true, std::move(constraints_1)));
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  fidl::WireSyncClient collection_2{std::move(collection_endpoints_2->client)};
+  auto collection_endpoints_2 = fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
+  fidl::WireSyncClient collection_2{std::move(collection_endpoints_2.client)};
 
   fidl::WireSyncClient token_2{std::move(token_client_2)};
   // Remove write from last token
@@ -2165,13 +2108,12 @@
 
   ASSERT_NE(token_2.client_end().channel().get(), ZX_HANDLE_INVALID);
   ASSERT_OK(allocator->BindSharedCollection(token_2.TakeClientEnd(),
-                                            std::move(collection_endpoints_2->server)));
+                                            std::move(collection_endpoints_2.server)));
 
   ASSERT_OK(collection_2->SetConstraints(true, std::move(constraints_2)));
 
-  auto collection_endpoints_3 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_3);
-  fidl::WireSyncClient collection_3{std::move(collection_endpoints_3->client)};
+  auto collection_endpoints_3 = fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
+  fidl::WireSyncClient collection_3{std::move(collection_endpoints_3.client)};
 
   auto collection_endpoints_4 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
   ASSERT_OK(collection_endpoints_4);
@@ -2179,7 +2121,7 @@
 
   ASSERT_NE(duplicate_result_2->tokens[0].channel().get(), ZX_HANDLE_INVALID);
   ASSERT_OK(allocator->BindSharedCollection(std::move(duplicate_result_2->tokens[0]),
-                                            std::move(collection_endpoints_3->server)));
+                                            std::move(collection_endpoints_3.server)));
 
   ASSERT_NE(duplicate_result_2->tokens[1].channel().get(), ZX_HANDLE_INVALID);
   ASSERT_OK(allocator->BindSharedCollection(std::move(duplicate_result_2->tokens[1]),
@@ -2221,22 +2163,19 @@
   auto allocator_1 = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator_1);
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   ASSERT_OK(allocator_1->AllocateSharedCollection(std::move(token_server_1)));
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2)));
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2272,9 +2211,8 @@
   // Try to wait until the wait has been processed by the server.
   zx_nanosleep(zx_deadline_after(ZX_SEC(5)));
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
   ASSERT_OK(collection_1->Sync());
@@ -2293,18 +2231,16 @@
 TEST(Sysmem, ConstraintsRetainedBeyondCleanCloseV1) {
   auto allocator = connect_to_sysmem_driver_v1();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   // Client 1 creates a token and new LogicalBufferCollection using
   // AllocateSharedCollection().
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -2312,9 +2248,8 @@
   // token_client_2 transferred to another participant).
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2)));
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2353,9 +2288,8 @@
   auto allocator_2 = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator_2);
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
   // Just because we can, perform this sync as late as possible, just before
@@ -2607,22 +2541,19 @@
   auto allocator_1 = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator_1);
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   ASSERT_OK(allocator_1->AllocateSharedCollection(std::move(token_server_1)));
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2)));
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2659,9 +2590,8 @@
   auto allocator_2 = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator_2);
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
   ASSERT_OK(collection_1->Sync());
@@ -2898,18 +2828,16 @@
 TEST(Sysmem, NoneUsageWithSeparateOtherUsageSucceedsV1) {
   auto allocator = connect_to_sysmem_driver_v1();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   // Client 1 creates a token and new LogicalBufferCollection using
   // AllocateSharedCollection().
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -2917,9 +2845,8 @@
   // token_client_2 transferred to another participant).
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2)));
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2962,9 +2889,8 @@
   auto allocator_2 = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator_2);
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
   // Just because we can, perform this sync as late as possible, just before
@@ -3090,16 +3016,14 @@
 TEST(Sysmem, CloseTokenV1) {
   auto allocator = connect_to_sysmem_driver_v1();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_1{std::move(token_client_1)};
 
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
   fidl::WireSyncClient token_2{std::move(token_client_2)};
 
   ASSERT_OK(token_1->Duplicate(ZX_RIGHT_SAME_RIGHTS, std::move(token_server_2)));
@@ -3683,15 +3607,13 @@
   auto allocator = connect_to_sysmem_driver_v1();
   ASSERT_OK(allocator);
 
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints);
-  auto [token_client_end, token_server_end] = std::move(*token_endpoints);
+  auto [token_client_end, token_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
 
   ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_end)));
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints);
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
   EXPECT_NE(token_client_end.channel().get(), ZX_HANDLE_INVALID);
   ASSERT_OK(allocator->BindSharedCollection(std::move(token_client_end),
@@ -3732,9 +3654,8 @@
 TEST(Sysmem, TooManyBuffersV1) {
   auto allocator = connect_to_sysmem_driver_v1();
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_OK(collection_endpoints);
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
   fidl::WireSyncClient collection{std::move(collection_client_end)};
 
   ASSERT_OK(allocator->AllocateNonSharedCollection(std::move(collection_server_end)));
@@ -4105,18 +4026,16 @@
   for (Variant variant : variants) {
     auto allocator = connect_to_sysmem_driver_v1();
 
-    auto token_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-    ASSERT_OK(token_endpoints_1);
-    auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+    auto [token_client_1, token_server_1] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
     fidl::WireSyncClient token_1{std::move(token_client_1)};
 
     // Client 1 creates a token and new LogicalBufferCollection using
     // AllocateSharedCollection().
     ASSERT_OK(allocator->AllocateSharedCollection(std::move(token_server_1)));
 
-    auto token_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
-    ASSERT_OK(token_endpoints_2);
-    auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+    auto [token_client_2, token_server_2] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollectionToken>::Create();
     fidl::WireSyncClient token_2{std::move(token_client_2)};
 
     // Client 1 duplicates its token and gives the duplicate to client 2 (this
@@ -4130,9 +4049,8 @@
     // LogicalBufferCollection.
     ASSERT_OK(token_2->SetDispensable());
 
-    auto collection_endpoints_1 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-    ASSERT_OK(collection_endpoints_1);
-    auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+    auto [collection_client_1, collection_server_1] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
     fidl::WireSyncClient collection_1{std::move(collection_client_1)};
 
     ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -4167,9 +4085,8 @@
     auto allocator_2 = connect_to_sysmem_driver_v1();
     ASSERT_OK(allocator_2);
 
-    auto collection_endpoints_2 = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-    ASSERT_OK(collection_endpoints_2);
-    auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+    auto [collection_client_2, collection_server_2] =
+        fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
     fidl::WireSyncClient collection_2{std::move(collection_client_2)};
 
     // Just because we can, perform this sync as late as possible, just before
diff --git a/src/devices/sysmem/tests/sysmem/sysmem_tests_v2.cc b/src/devices/sysmem/tests/sysmem/sysmem_tests_v2.cc
index 90358ec..bcffcc1 100644
--- a/src/devices/sysmem/tests/sysmem/sysmem_tests_v2.cc
+++ b/src/devices/sysmem/tests/sysmem/sysmem_tests_v2.cc
@@ -122,12 +122,8 @@
 }
 
 zx_status_t verify_connectivity_v2(fidl::SyncClient<fuchsia_sysmem2::Allocator>& allocator) {
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollection>();
-  EXPECT_TRUE(collection_endpoints.is_ok());
-  if (!collection_endpoints.is_ok()) {
-    return collection_endpoints.status_value();
-  }
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem2::BufferCollection>::Create();
 
   fuchsia_sysmem2::AllocatorAllocateNonSharedCollectionRequest request;
   request.collection_request().emplace(std::move(collection_server_end));
@@ -171,12 +167,8 @@
     return zx::error(allocator.status_value());
   }
 
-  zx::result token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollectionToken>();
-  EXPECT_TRUE(token_endpoints.is_ok());
-  if (!token_endpoints.is_ok()) {
-    return zx::error(token_endpoints.status_value());
-  }
-  auto [token_client_end, token_server_end] = std::move(*token_endpoints);
+  auto [token_client_end, token_server_end] =
+      fidl::Endpoints<fuchsia_sysmem2::BufferCollectionToken>::Create();
 
   fuchsia_sysmem2::AllocatorAllocateSharedCollectionRequest allocate_shared_request;
   allocate_shared_request.token_request() = std::move(token_server_end);
@@ -187,12 +179,8 @@
     return zx::error(new_collection_result.error_value().status());
   }
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollection>();
-  EXPECT_TRUE(collection_endpoints.is_ok());
-  if (!collection_endpoints.is_ok()) {
-    return zx::error(collection_endpoints.status_value());
-  }
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem2::BufferCollection>::Create();
 
   EXPECT_NE(token_client_end.channel().get(), ZX_HANDLE_INVALID);
   fuchsia_sysmem2::AllocatorBindSharedCollectionRequest bind_shared_request;
@@ -214,9 +202,7 @@
 fidl::SyncClient<v2::BufferCollectionToken> create_initial_token_v2() {
   zx::result allocator = connect_to_sysmem_service_v2();
   EXPECT_TRUE(allocator.is_ok());
-  zx::result token_endpoints_0 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  EXPECT_TRUE(token_endpoints_0.is_ok());
-  auto& [token_client_0, token_server_0] = token_endpoints_0.value();
+  auto [token_client_0, token_server_0] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   v2::AllocatorAllocateSharedCollectionRequest allocate_shared_request;
   allocate_shared_request.token_request() = std::move(token_server_0);
   EXPECT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
@@ -232,9 +218,8 @@
   for (uint32_t i = 0; i < client_count; ++i) {
     auto cur_token = std::move(next_token);
     if (i < client_count - 1) {
-      zx::result token_endpoints = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-      EXPECT_TRUE(token_endpoints.is_ok());
-      auto& [token_client_endpoint, token_server_endpoint] = token_endpoints.value();
+      auto [token_client_endpoint, token_server_endpoint] =
+          fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
       v2::BufferCollectionTokenDuplicateRequest duplicate_request;
       duplicate_request.rights_attenuation_mask() = ZX_RIGHT_SAME_RIGHTS;
@@ -243,9 +228,8 @@
 
       next_token = fidl::SyncClient(std::move(token_client_endpoint));
     }
-    zx::result collection_endpoints = fidl::CreateEndpoints<v2::BufferCollection>();
-    EXPECT_TRUE(collection_endpoints.is_ok());
-    auto& [collection_client_endpoint, collection_server_endpoint] = collection_endpoints.value();
+    auto [collection_client_endpoint, collection_server_endpoint] =
+        fidl::Endpoints<v2::BufferCollection>::Create();
 
     v2::AllocatorBindSharedCollectionRequest bind_shared_request;
     bind_shared_request.token() = cur_token.TakeClientEnd();
@@ -265,9 +249,7 @@
 
 fidl::SyncClient<v2::BufferCollectionToken> create_token_under_token_v2(
     fidl::SyncClient<v2::BufferCollectionToken>& token_a) {
-  zx::result token_endpoints = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  EXPECT_TRUE(token_endpoints.is_ok());
-  auto& [token_b_client, token_b_server] = token_endpoints.value();
+  auto [token_b_client, token_b_server] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   v2::BufferCollectionTokenDuplicateRequest duplicate_request;
   duplicate_request.rights_attenuation_mask() = ZX_RIGHT_SAME_RIGHTS;
   duplicate_request.token_request() = std::move(token_b_server);
@@ -279,9 +261,7 @@
 
 fidl::SyncClient<v2::BufferCollectionTokenGroup> create_group_under_token_v2(
     fidl::SyncClient<v2::BufferCollectionToken>& token) {
-  zx::result group_endpoints = fidl::CreateEndpoints<v2::BufferCollectionTokenGroup>();
-  EXPECT_TRUE(group_endpoints.is_ok());
-  auto& [group_client, group_server] = group_endpoints.value();
+  auto [group_client, group_server] = fidl::Endpoints<v2::BufferCollectionTokenGroup>::Create();
   v2::BufferCollectionTokenCreateBufferCollectionTokenGroupRequest create_group_request;
   create_group_request.group_request() = std::move(group_server);
   EXPECT_TRUE(token->CreateBufferCollectionTokenGroup(std::move(create_group_request)).is_ok());
@@ -293,9 +273,7 @@
 fidl::SyncClient<v2::BufferCollectionToken> create_token_under_group_v2(
     fidl::SyncClient<v2::BufferCollectionTokenGroup>& group,
     uint32_t rights_attenuation_mask = ZX_RIGHT_SAME_RIGHTS) {
-  zx::result token_endpoints = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  EXPECT_OK(token_endpoints.status_value());
-  auto& [token_client, token_server] = token_endpoints.value();
+  auto [token_client, token_server] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   v2::BufferCollectionTokenGroupCreateChildRequest create_child_request;
   create_child_request.token_request() = std::move(token_server);
   if (rights_attenuation_mask != ZX_RIGHT_SAME_RIGHTS) {
@@ -326,9 +304,7 @@
 fidl::SyncClient<v2::BufferCollection> convert_token_to_collection_v2(
     fidl::SyncClient<v2::BufferCollectionToken> token) {
   auto allocator = connect_to_sysmem_service_v2();
-  zx::result collection_endpoints = fidl::CreateEndpoints<v2::BufferCollection>();
-  EXPECT_TRUE(collection_endpoints.is_ok());
-  auto& [collection_client, collection_server] = collection_endpoints.value();
+  auto [collection_client, collection_server] = fidl::Endpoints<v2::BufferCollection>::Create();
   v2::AllocatorBindSharedCollectionRequest bind_shared_request;
   bind_shared_request.token() = token.TakeClientEnd();
   bind_shared_request.buffer_collection_request() = std::move(collection_server);
@@ -569,10 +545,7 @@
   EXPECT_TRUE(allocator.is_ok());
   IF_FAILURES_RETURN_FALSE();
 
-  zx::result token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  EXPECT_TRUE(token_endpoints_1.is_ok());
-  IF_FAILURES_RETURN_FALSE();
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   // Client 1 creates a token and new LogicalBufferCollection using
   // AllocateSharedCollection().
@@ -581,10 +554,7 @@
   EXPECT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
   IF_FAILURES_RETURN_FALSE();
 
-  zx::result token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  EXPECT_TRUE(token_endpoints_2.is_ok());
-  IF_FAILURES_RETURN_FALSE();
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -599,10 +569,7 @@
 
   // Client 3 is attached later.
 
-  zx::result collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  EXPECT_TRUE(collection_endpoints_1.is_ok());
-  IF_FAILURES_RETURN_FALSE();
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   EXPECT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -681,10 +648,7 @@
   EXPECT_TRUE(allocator_2.is_ok());
   IF_FAILURES_RETURN_FALSE();
 
-  zx::result collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  EXPECT_TRUE(collection_endpoints_2.is_ok());
-  IF_FAILURES_RETURN_FALSE();
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_2{std::move(collection_client_2)};
 
   // Just because we can, perform this sync as late as possible, just before
@@ -765,10 +729,8 @@
     collection_3 = {};
     ZX_DEBUG_ASSERT(!collection_3.is_valid());
 
-    zx::result collection_endpoints_3 = fidl::CreateEndpoints<v2::BufferCollection>();
-    EXPECT_TRUE(collection_endpoints_3.is_ok());
-    IF_FAILURES_RETURN();
-    auto [collection_client_3, collection_server_3] = std::move(*collection_endpoints_3);
+    auto [collection_client_3, collection_server_3] =
+        fidl::Endpoints<v2::BufferCollection>::Create();
     collection_3 = fidl::SyncClient(std::move(collection_client_3));
 
     v2::AllocatorBindSharedCollectionRequest bind_shared_request;
@@ -1005,18 +967,16 @@
   auto allocator = connect_to_sysmem_driver_v2();
   ASSERT_TRUE(allocator.is_ok());
 
-  auto token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints.is_ok());
-  auto [token_client, token_server] = std::move(*token_endpoints);
+  auto [token_client, token_server] =
+      fidl::Endpoints<fuchsia_sysmem2::BufferCollectionToken>::Create();
   fidl::SyncClient token{std::move(token_client)};
 
   fuchsia_sysmem2::AllocatorAllocateSharedCollectionRequest request;
   request.token_request() = std::move(token_server);
   ASSERT_TRUE(allocator->AllocateSharedCollection(std::move(request)).is_ok());
 
-  auto token2_endpoints = fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollectionToken>();
-  ASSERT_TRUE(token2_endpoints.is_ok());
-  auto [token2_client, token2_server] = std::move(*token2_endpoints);
+  auto [token2_client, token2_server] =
+      fidl::Endpoints<fuchsia_sysmem2::BufferCollectionToken>::Create();
   fidl::SyncClient token2{std::move(token2_client)};
 
   fuchsia_sysmem2::BufferCollectionTokenDuplicateRequest duplicate_request;
@@ -1024,9 +984,8 @@
   duplicate_request.token_request() = std::move(token2_server);
   ASSERT_TRUE(token->Duplicate(std::move(duplicate_request)).is_ok());
 
-  auto not_token_endpoints = fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollectionToken>();
-  ASSERT_TRUE(not_token_endpoints.is_ok());
-  auto [not_token_client, not_token_server] = std::move(*not_token_endpoints);
+  auto [not_token_client, not_token_server] =
+      fidl::Endpoints<fuchsia_sysmem2::BufferCollectionToken>::Create();
 
   ASSERT_TRUE(token->Sync().is_ok());
   ASSERT_TRUE(token2->Sync().is_ok());
@@ -1236,10 +1195,8 @@
     ASSERT_TRUE(!!(pending_signals & ZX_EVENTPAIR_PEER_CLOSED) == (i >= kNumBuffers));
   }
 
-  zx::result attached_token_endpoints =
-      fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollectionToken>();
-  ASSERT_TRUE(attached_token_endpoints.is_ok());
-  auto [attached_token_client, attached_token_server] = std::move(*attached_token_endpoints);
+  auto [attached_token_client, attached_token_server] =
+      fidl::Endpoints<fuchsia_sysmem2::BufferCollectionToken>::Create();
 
   fuchsia_sysmem2::BufferCollectionAttachTokenRequest attach_request;
   attach_request.rights_attenuation_mask() = std::numeric_limits<uint32_t>::max();
@@ -1526,9 +1483,8 @@
 
 TEST(Sysmem, NoTokenV2) {
   auto allocator = connect_to_sysmem_driver_v2();
-  zx::result collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints.is_ok());
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<fuchsia_sysmem2::BufferCollection>::Create();
   fidl::SyncClient collection{std::move(collection_client_end)};
 
   fuchsia_sysmem2::AllocatorAllocateNonSharedCollectionRequest allocate_non_shared_request;
@@ -1598,9 +1554,7 @@
   auto allocator_1 = connect_to_sysmem_driver_v2();
   ASSERT_OK(allocator_1);
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   v2::AllocatorAllocateSharedCollectionRequest request;
@@ -1623,13 +1577,10 @@
   fidl::SyncClient<v2::BufferCollection> collection_3;
 
   {
-    auto token_endpoints_3 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-    ASSERT_OK(token_endpoints_3);
-    auto [token_client_3, token_server_3] = std::move(*token_endpoints_3);
+    auto [token_client_3, token_server_3] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
-    auto collection_endpoints_3 = fidl::CreateEndpoints<v2::BufferCollection>();
-    ASSERT_OK(collection_endpoints_3);
-    auto [collection_client_3, collection_server_3] = std::move(*collection_endpoints_3);
+    auto [collection_client_3, collection_server_3] =
+        fidl::Endpoints<v2::BufferCollection>::Create();
 
     v2::BufferCollectionTokenDuplicateRequest duplicate_request;
     duplicate_request.rights_attenuation_mask() = ZX_RIGHT_SAME_RIGHTS;
@@ -1652,14 +1603,10 @@
     ASSERT_TRUE(collection_3->SetName(std::move(set_name_request)).is_ok());
   }
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_2{std::move(token_client_2)};
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   const char* kClient2Name = "TestClient2";
@@ -1693,9 +1640,7 @@
 TEST(Sysmem, MultipleParticipantsV2) {
   auto allocator = connect_to_sysmem_driver_v2();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   // Client 1 creates a token and new LogicalBufferCollection using
@@ -1704,9 +1649,7 @@
   allocate_shared_request.token_request() = std::move(token_server_1);
   ASSERT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_2);
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -1717,9 +1660,7 @@
   duplicate_request.token_request() = std::move(token_server_2);
   ASSERT_TRUE(token_1->Duplicate(std::move(duplicate_request)).is_ok());
 
-  auto token_endpoints_3 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_3);
-  auto [token_client_3, token_server_3] = std::move(*token_endpoints_3);
+  auto [token_client_3, token_server_3] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   // Client 3 is used to test a participant that doesn't set any constraints
   // and only wants a notification that the allocation is done.
@@ -1728,9 +1669,7 @@
   duplicate_request2.token_request() = std::move(token_server_3);
   ASSERT_TRUE(token_1->Duplicate(std::move(duplicate_request2)).is_ok());
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -1808,9 +1747,7 @@
   auto allocator_2 = connect_to_sysmem_driver_v2();
   ASSERT_OK(allocator_2);
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_2{std::move(collection_client_2)};
 
   // Just because we can, perform this sync as late as possible, just before
@@ -1838,9 +1775,7 @@
   bind_shared_request2.buffer_collection_request() = std::move(collection_server_2);
   ASSERT_TRUE(allocator_2->BindSharedCollection(std::move(bind_shared_request2)).is_ok());
 
-  auto collection_endpoints_3 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_OK(collection_endpoints_3);
-  auto [collection_client_3, collection_server_3] = std::move(*collection_endpoints_3);
+  auto [collection_client_3, collection_server_3] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_3{std::move(collection_client_3)};
 
   ASSERT_NE(token_client_3.channel().get(), ZX_HANDLE_INVALID);
@@ -1986,27 +1921,21 @@
 TEST(Sysmem, ComplicatedFormatModifiersV2) {
   auto allocator = connect_to_sysmem_driver_v2();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_1.is_ok());
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   v2::AllocatorAllocateSharedCollectionRequest allocate_shared_request;
   allocate_shared_request.token_request() = std::move(token_server_1);
   ASSERT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_2.is_ok());
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   v2::BufferCollectionTokenDuplicateRequest duplicate_request;
   duplicate_request.rights_attenuation_mask() = ZX_RIGHT_SAME_RIGHTS;
   duplicate_request.token_request() = std::move(token_server_2);
   ASSERT_TRUE(token_1->Duplicate(std::move(duplicate_request)).is_ok());
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_1.is_ok());
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2069,9 +1998,7 @@
   set_constraints_request.constraints() = std::move(constraints_1);
   ASSERT_TRUE(collection_1->SetConstraints(std::move(set_constraints_request)).is_ok());
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_2.is_ok());
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_2{std::move(collection_client_2)};
 
   ASSERT_TRUE(collection_1->Sync().is_ok());
@@ -2100,27 +2027,21 @@
 TEST(Sysmem, MultipleParticipantsColorspaceRankingV2) {
   auto allocator = connect_to_sysmem_driver_v2();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   v2::AllocatorAllocateSharedCollectionRequest allocate_shared_request;
   allocate_shared_request.token_request() = std::move(token_server_1);
   ASSERT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_2.is_ok());
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   v2::BufferCollectionTokenDuplicateRequest duplicate_request;
   duplicate_request.rights_attenuation_mask() = ZX_RIGHT_SAME_RIGHTS;
   duplicate_request.token_request() = std::move(token_server_2);
   ASSERT_TRUE(token_1->Duplicate(std::move(duplicate_request)).is_ok());
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_1.is_ok());
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2162,9 +2083,7 @@
   set_constraints_request.constraints() = std::move(constraints_1);
   ASSERT_TRUE(collection_1->SetConstraints(std::move(set_constraints_request)).is_ok());
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_2.is_ok());
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_2{std::move(collection_client_2)};
 
   ASSERT_TRUE(collection_1->Sync().is_ok());
@@ -2328,9 +2247,7 @@
 TEST(Sysmem, DuplicateSyncV2) {
   auto allocator = connect_to_sysmem_driver_v2();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_1.is_ok());
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   v2::AllocatorAllocateSharedCollectionRequest allocate_non_shared_request;
@@ -2346,9 +2263,7 @@
   ASSERT_EQ(duplicate_result->tokens()->size(), 1);
   auto token_client_2 = std::move(duplicate_result->tokens()->at(0));
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2380,9 +2295,8 @@
   set_constraints_request.constraints() = std::move(constraints_1);
   ASSERT_TRUE(collection_1->SetConstraints(std::move(set_constraints_request)).is_ok());
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_OK(collection_endpoints_2);
-  fidl::SyncClient collection_2{std::move(collection_endpoints_2->client)};
+  auto collection_endpoints_2 = fidl::Endpoints<v2::BufferCollection>::Create();
+  fidl::SyncClient collection_2{std::move(collection_endpoints_2.client)};
 
   fidl::SyncClient token_2{std::move(token_client_2)};
   // Remove write from last token
@@ -2399,16 +2313,15 @@
 
   v2::AllocatorBindSharedCollectionRequest bind_shared_request2;
   bind_shared_request2.token() = token_2.TakeClientEnd();
-  bind_shared_request2.buffer_collection_request() = std::move(collection_endpoints_2->server);
+  bind_shared_request2.buffer_collection_request() = std::move(collection_endpoints_2.server);
   ASSERT_TRUE(allocator->BindSharedCollection(std::move(bind_shared_request2)).is_ok());
 
   v2::BufferCollectionSetConstraintsRequest set_constraints_request2;
   set_constraints_request2.constraints() = std::move(constraints_2);
   ASSERT_TRUE(collection_2->SetConstraints(std::move(set_constraints_request2)).is_ok());
 
-  auto collection_endpoints_3 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_3.is_ok());
-  fidl::SyncClient collection_3{std::move(collection_endpoints_3->client)};
+  auto collection_endpoints_3 = fidl::Endpoints<v2::BufferCollection>::Create();
+  fidl::SyncClient collection_3{std::move(collection_endpoints_3.client)};
 
   auto collection_endpoints_4 = fidl::CreateEndpoints<v2::BufferCollection>();
   ASSERT_TRUE(collection_endpoints_4.is_ok());
@@ -2419,7 +2332,7 @@
 
   v2::AllocatorBindSharedCollectionRequest bind_shared_request3;
   bind_shared_request3.token() = std::move(duplicate_result_2->tokens()->at(0));
-  bind_shared_request3.buffer_collection_request() = std::move(collection_endpoints_3->server);
+  bind_shared_request3.buffer_collection_request() = std::move(collection_endpoints_3.server);
   ASSERT_TRUE(allocator->BindSharedCollection(std::move(bind_shared_request3)).is_ok());
 
   ASSERT_NE(duplicate_result_2->tokens()->at(1).channel().get(), ZX_HANDLE_INVALID);
@@ -2467,27 +2380,21 @@
   auto allocator_1 = connect_to_sysmem_driver_v2();
   ASSERT_TRUE(allocator_1.is_ok());
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_1.is_ok());
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   v2::AllocatorAllocateSharedCollectionRequest allocate_shared_request;
   allocate_shared_request.token_request() = std::move(token_server_1);
   ASSERT_TRUE(allocator_1->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_2.is_ok());
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   v2::BufferCollectionTokenDuplicateRequest duplicate_request;
   duplicate_request.rights_attenuation_mask() = ZX_RIGHT_SAME_RIGHTS;
   duplicate_request.token_request() = std::move(token_server_2);
   ASSERT_TRUE(token_1->Duplicate(std::move(duplicate_request)).is_ok());
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_OK(collection_endpoints_1);
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2526,9 +2433,7 @@
   // Try to wait until the wait has been processed by the server.
   zx_nanosleep(zx_deadline_after(ZX_SEC(5)));
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_2.is_ok());
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_2{std::move(collection_client_2)};
 
   ASSERT_TRUE(collection_1->Sync().is_ok());
@@ -2550,9 +2455,7 @@
 TEST(Sysmem, ConstraintsRetainedBeyondReleaseV2) {
   auto allocator = connect_to_sysmem_driver_v2();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_1.is_ok());
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   // Client 1 creates a token and new LogicalBufferCollection using
@@ -2562,9 +2465,7 @@
   ASSERT_TRUE(
       allocator->AllocateSharedCollection(std::move(std::move(allocate_shared_request))).is_ok());
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_2.is_ok());
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -2575,9 +2476,7 @@
   duplicate_request.token_request() = std::move(token_server_2);
   ASSERT_TRUE(token_1->Duplicate(std::move(duplicate_request)).is_ok());
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_1.is_ok());
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2620,9 +2519,7 @@
   auto allocator_2 = connect_to_sysmem_driver_v2();
   ASSERT_TRUE(allocator_2.is_ok());
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_2.is_ok());
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_2{std::move(collection_client_2)};
 
   // Just because we can, perform this sync as late as possible, just before
@@ -2901,27 +2798,21 @@
   auto allocator_1 = connect_to_sysmem_driver_v2();
   ASSERT_TRUE(allocator_1.is_ok());
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_1.is_ok());
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   v2::AllocatorAllocateSharedCollectionRequest allocate_shared_request;
   allocate_shared_request.token_request() = std::move(token_server_1);
   ASSERT_TRUE(allocator_1->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_2.is_ok());
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   v2::BufferCollectionTokenDuplicateRequest duplicate_request;
   duplicate_request.rights_attenuation_mask() = ZX_RIGHT_SAME_RIGHTS;
   duplicate_request.token_request() = std::move(token_server_2);
   ASSERT_TRUE(token_1->Duplicate(std::move(duplicate_request)).is_ok());
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_1.is_ok());
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -2964,9 +2855,7 @@
   auto allocator_2 = connect_to_sysmem_driver_v2();
   ASSERT_TRUE(allocator_2.is_ok());
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_2.is_ok());
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_2{std::move(collection_client_2)};
 
   ASSERT_TRUE(collection_1->Sync().is_ok());
@@ -3253,9 +3142,7 @@
 TEST(Sysmem, NoneUsageWithSeparateOtherUsageSucceedsV2) {
   auto allocator = connect_to_sysmem_driver_v2();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_OK(token_endpoints_1);
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   // Client 1 creates a token and new LogicalBufferCollection using
@@ -3264,9 +3151,7 @@
   allocate_shared_request.token_request() = std::move(token_server_1);
   ASSERT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_2.is_ok());
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   // Client 1 duplicates its token and gives the duplicate to client 2 (this
   // test is single proc, so both clients are coming from this client
@@ -3277,9 +3162,7 @@
   duplicate_request.token_request() = std::move(token_server_2);
   ASSERT_TRUE(token_1->Duplicate(std::move(duplicate_request)).is_ok());
 
-  auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_1.is_ok());
-  auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+  auto [collection_client_1, collection_server_1] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_1{std::move(collection_client_1)};
 
   ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -3326,9 +3209,7 @@
   auto allocator_2 = connect_to_sysmem_driver_v2();
   ASSERT_TRUE(allocator_2.is_ok());
 
-  auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints_2.is_ok());
-  auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+  auto [collection_client_2, collection_server_2] = fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection_2{std::move(collection_client_2)};
 
   // Just because we can, perform this sync as late as possible, just before
@@ -3451,18 +3332,14 @@
 TEST(Sysmem, ReleaseTokenV2) {
   auto allocator = connect_to_sysmem_driver_v2();
 
-  auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_1.is_ok());
-  auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+  auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_1{std::move(token_client_1)};
 
   v2::AllocatorAllocateSharedCollectionRequest allocate_shared_request;
   allocate_shared_request.token_request() = std::move(token_server_1);
   ASSERT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-  auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints_2.is_ok());
-  auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+  auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
   fidl::SyncClient token_2{std::move(token_client_2)};
 
   v2::BufferCollectionTokenDuplicateRequest duplicate_request;
@@ -4076,17 +3953,14 @@
   auto allocator = connect_to_sysmem_driver_v2();
   ASSERT_TRUE(allocator.is_ok());
 
-  zx::result token_endpoints = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-  ASSERT_TRUE(token_endpoints.is_ok());
-  auto [token_client_end, token_server_end] = std::move(*token_endpoints);
+  auto [token_client_end, token_server_end] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
 
   v2::AllocatorAllocateSharedCollectionRequest allocate_shared_request;
   allocate_shared_request.token_request() = std::move(token_server_end);
   ASSERT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints.is_ok());
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<v2::BufferCollection>::Create();
 
   EXPECT_NE(token_client_end.channel().get(), ZX_HANDLE_INVALID);
 
@@ -4132,9 +4006,8 @@
 TEST(Sysmem, TooManyBuffersV2) {
   auto allocator = connect_to_sysmem_driver_v2();
 
-  zx::result collection_endpoints = fidl::CreateEndpoints<v2::BufferCollection>();
-  ASSERT_TRUE(collection_endpoints.is_ok());
-  auto [collection_client_end, collection_server_end] = std::move(*collection_endpoints);
+  auto [collection_client_end, collection_server_end] =
+      fidl::Endpoints<v2::BufferCollection>::Create();
   fidl::SyncClient collection{std::move(collection_client_end)};
 
   v2::AllocatorAllocateNonSharedCollectionRequest allocate_non_shared_request;
@@ -4502,9 +4375,7 @@
   for (Variant variant : variants) {
     auto allocator = connect_to_sysmem_driver_v2();
 
-    auto token_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-    ASSERT_TRUE(token_endpoints_1.is_ok());
-    auto [token_client_1, token_server_1] = std::move(*token_endpoints_1);
+    auto [token_client_1, token_server_1] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
     fidl::SyncClient token_1{std::move(token_client_1)};
 
     // Client 1 creates a token and new LogicalBufferCollection using
@@ -4513,9 +4384,7 @@
     allocate_shared_request.token_request() = std::move(token_server_1);
     ASSERT_TRUE(allocator->AllocateSharedCollection(std::move(allocate_shared_request)).is_ok());
 
-    auto token_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollectionToken>();
-    ASSERT_TRUE(token_endpoints_2.is_ok());
-    auto [token_client_2, token_server_2] = std::move(*token_endpoints_2);
+    auto [token_client_2, token_server_2] = fidl::Endpoints<v2::BufferCollectionToken>::Create();
     fidl::SyncClient token_2{std::move(token_client_2)};
 
     // Client 1 duplicates its token and gives the duplicate to client 2 (this
@@ -4532,9 +4401,8 @@
     // LogicalBufferCollection.
     ASSERT_TRUE(token_2->SetDispensable().is_ok());
 
-    auto collection_endpoints_1 = fidl::CreateEndpoints<v2::BufferCollection>();
-    ASSERT_TRUE(collection_endpoints_1.is_ok());
-    auto [collection_client_1, collection_server_1] = std::move(*collection_endpoints_1);
+    auto [collection_client_1, collection_server_1] =
+        fidl::Endpoints<v2::BufferCollection>::Create();
     fidl::SyncClient collection_1{std::move(collection_client_1)};
 
     ASSERT_NE(token_1.client_end().channel().get(), ZX_HANDLE_INVALID);
@@ -4570,9 +4438,8 @@
     auto allocator_2 = connect_to_sysmem_driver_v2();
     ASSERT_TRUE(allocator_2.is_ok());
 
-    auto collection_endpoints_2 = fidl::CreateEndpoints<v2::BufferCollection>();
-    ASSERT_TRUE(collection_endpoints_2.is_ok());
-    auto [collection_client_2, collection_server_2] = std::move(*collection_endpoints_2);
+    auto [collection_client_2, collection_server_2] =
+        fidl::Endpoints<v2::BufferCollection>::Create();
     fidl::SyncClient collection_2{std::move(collection_client_2)};
 
     // Just because we can, perform this sync as late as possible, just before
@@ -6361,15 +6228,14 @@
           child_token_v2.TakeClientEnd().TakeChannel()));
 
   // Convert child_token_v1 into v1 BufferCollection.
-  auto v1_collection_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollection>();
-  ASSERT_TRUE(v1_collection_endpoints.is_ok());
-  auto child_collection_v1 = fidl::SyncClient(std::move(v1_collection_endpoints->client));
+  auto v1_collection_endpoints = fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
+  auto child_collection_v1 = fidl::SyncClient(std::move(v1_collection_endpoints.client));
   auto allocator_result = component::Connect<fuchsia_sysmem::Allocator>();
   ASSERT_OK(allocator_result.status_value());
   auto allocator = fidl::SyncClient(std::move(allocator_result.value()));
   fuchsia_sysmem::AllocatorBindSharedCollectionRequest bind_shared_request;
   bind_shared_request.token() = child_token_v1.TakeClientEnd();
-  bind_shared_request.buffer_collection_request() = std::move(v1_collection_endpoints->server);
+  bind_shared_request.buffer_collection_request() = std::move(v1_collection_endpoints.server);
   ASSERT_TRUE(allocator->BindSharedCollection(std::move(bind_shared_request)).is_ok());
 
   auto parent_collection = convert_token_to_collection_v2(std::move(parent_token));
diff --git a/src/devices/sysmem/tools/memory-pressure.cc b/src/devices/sysmem/tools/memory-pressure.cc
index 900744d..139558b8 100644
--- a/src/devices/sysmem/tools/memory-pressure.cc
+++ b/src/devices/sysmem/tools/memory-pressure.cc
@@ -103,12 +103,8 @@
     return 1;
   };
 
-  zx::result endpoints = fidl::CreateEndpoints<sysmem::BufferCollection>();
-  if (endpoints.is_error()) {
-    LogError("Failed to create buffer collection endpoints, error %d\n", endpoints.status_value());
-    return 1;
-  }
-  auto& [client_collection_channel, server_collection] = endpoints.value();
+  auto [client_collection_channel, server_collection] =
+      fidl::Endpoints<sysmem::BufferCollection>::Create();
 
   if (const fidl::OneWayStatus status =
           sysmem_allocator->AllocateNonSharedCollection(std::move(server_collection));
diff --git a/src/devices/tee/drivers/optee/optee-client.cc b/src/devices/tee/drivers/optee/optee-client.cc
index b3532a6..74100e5 100644
--- a/src/devices/tee/drivers/optee/optee-client.cc
+++ b/src/devices/tee/drivers/optee/optee-client.cc
@@ -167,13 +167,7 @@
   flags |= fuchsia_io::wire::OpenFlags::kDescribe;
 
   // Create temporary channel ends to make FIDL call
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Node>();
-  if (endpoints.is_error()) {
-    LOG(ERROR, "failed to create channel pair (status: %s)", endpoints.status_string());
-    return endpoints.take_error();
-  }
-
-  auto [client_end, server_end] = std::move(endpoints.value());
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_io::Node>::Create();
 
   auto result = fidl::WireCall(root)->Open(flags, {}, fidl::StringView::FromExternal(path),
                                            std::move(server_end));
diff --git a/src/devices/tee/drivers/optee/test/optee-client-test.cc b/src/devices/tee/drivers/optee/test/optee-client-test.cc
index 822a7be..0edf842 100644
--- a/src/devices/tee/drivers/optee/test/optee-client-test.cc
+++ b/src/devices/tee/drivers/optee/test/optee-client-test.cc
@@ -167,9 +167,7 @@
 };
 
 TEST_F(OpteeClientTest, OpenSessionsClosedOnClientUnbind) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_tee::Application>();
-  ASSERT_TRUE(endpoints.is_ok());
-  auto [client_end, server_end] = std::move(endpoints.value());
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_tee::Application>::Create();
   auto optee_client = std::make_unique<OpteeClient>(
       this, fidl::ClientEnd<fuchsia_tee_manager::Provider>(), optee::Uuid{kOpteeOsUuid});
 
@@ -249,9 +247,7 @@
   OpteeClientTestRpmb() : rpmb_loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
     ASSERT_OK(rpmb_loop_.StartThread());
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_tee::Application>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client_end, server_end] = std::move(endpoints.value());
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_tee::Application>::Create();
     optee_client_.reset(new OpteeClient(this, fidl::ClientEnd<fuchsia_tee_manager::Provider>(),
                                         optee::Uuid{kOpteeOsUuid}));
     fidl::BindServer(loop_.dispatcher(), std::move(server_end), optee_client_.get());
@@ -855,12 +851,8 @@
 };
 
 TEST_F(OpteeClientTestWaitQueue, WakeUpBeforeSleep) {
-  auto endpoints1 = fidl::CreateEndpoints<fuchsia_tee::Application>();
-  auto endpoints2 = fidl::CreateEndpoints<fuchsia_tee::Application>();
-  ASSERT_TRUE(endpoints1.is_ok());
-  ASSERT_TRUE(endpoints2.is_ok());
-  auto [client1_end, server1_end] = std::move(endpoints1.value());
-  auto [client2_end, server2_end] = std::move(endpoints2.value());
+  auto [client1_end, server1_end] = fidl::Endpoints<fuchsia_tee::Application>::Create();
+  auto [client2_end, server2_end] = fidl::Endpoints<fuchsia_tee::Application>::Create();
   auto optee1_client = std::make_unique<OpteeClient>(
       this, fidl::ClientEnd<fuchsia_tee_manager::Provider>(), optee::Uuid{kOpteeOsUuid});
   auto optee2_client = std::make_unique<OpteeClient>(
@@ -954,12 +946,8 @@
 }
 
 TEST_F(OpteeClientTestWaitQueue, SleepWakeup) {
-  auto endpoints1 = fidl::CreateEndpoints<fuchsia_tee::Application>();
-  auto endpoints2 = fidl::CreateEndpoints<fuchsia_tee::Application>();
-  ASSERT_TRUE(endpoints1.is_ok());
-  ASSERT_TRUE(endpoints2.is_ok());
-  auto [client1_end, server1_end] = std::move(endpoints1.value());
-  auto [client2_end, server2_end] = std::move(endpoints2.value());
+  auto [client1_end, server1_end] = fidl::Endpoints<fuchsia_tee::Application>::Create();
+  auto [client2_end, server2_end] = fidl::Endpoints<fuchsia_tee::Application>::Create();
   auto optee1_client = std::make_unique<OpteeClient>(
       this, fidl::ClientEnd<fuchsia_tee_manager::Provider>(), optee::Uuid{kOpteeOsUuid});
   auto optee2_client = std::make_unique<OpteeClient>(
diff --git a/src/devices/tee/drivers/optee/test/optee-controller-test.cc b/src/devices/tee/drivers/optee/test/optee-controller-test.cc
index 0f70691..efad759 100644
--- a/src/devices/tee/drivers/optee/test/optee-controller-test.cc
+++ b/src/devices/tee/drivers/optee/test/optee-controller-test.cc
@@ -115,11 +115,10 @@
     auto service_result = outgoing_.AddService<fuchsia_hardware_rpmb::Service>(std::move(handler));
     ZX_ASSERT(service_result.is_ok());
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(endpoints.is_ok());
-    ZX_ASSERT(outgoing_.Serve(std::move(endpoints->server)).is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    ZX_ASSERT(outgoing_.Serve(std::move(endpoints.server)).is_ok());
 
-    return std::move(endpoints->client);
+    return std::move(endpoints.client);
   }
 
   fidl::ClientEnd<fuchsia_io::Directory> ConnectPdev() {
@@ -127,11 +126,10 @@
         std::move(pdev_.GetInstanceHandler()));
     ZX_ASSERT(service_result.is_ok());
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(endpoints.is_ok());
-    ZX_ASSERT(outgoing_.Serve(std::move(endpoints->server)).is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    ZX_ASSERT(outgoing_.Serve(std::move(endpoints.server)).is_ok());
 
-    return std::move(endpoints->client);
+    return std::move(endpoints.client);
   }
 
   fake_pdev::FakePDevFidl& pdev() { return pdev_; }
@@ -159,11 +157,10 @@
     auto service_result = outgoing_.AddService<fuchsia_hardware_tee::Service>(std::move(handler));
     ZX_ASSERT(service_result.is_ok());
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(endpoints.is_ok());
-    ZX_ASSERT(outgoing_.Serve(std::move(endpoints->server)).is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    ZX_ASSERT(outgoing_.Serve(std::move(endpoints.server)).is_ok());
 
-    return std::move(endpoints->client);
+    return std::move(endpoints.client);
   }
 
   void ConnectToApplication(ConnectToApplicationRequestView request,
@@ -287,14 +284,13 @@
   zx_status_t status;
 
   for (auto& i : tee_app_client) {
-    auto tee_endpoints = fidl::CreateEndpoints<fuchsia_tee::Application>();
-    ASSERT_OK(tee_endpoints.status_value());
+    auto tee_endpoints = fidl::Endpoints<fuchsia_tee::Application>::Create();
 
-    i = std::move(tee_endpoints->client);
+    i = std::move(tee_endpoints.client);
 
     auto result = tee_proto_client_->ConnectToApplication(
         kOpteeOsUuid, fidl::ClientEnd<::fuchsia_tee_manager::Provider>(),
-        std::move(tee_endpoints->server));
+        std::move(tee_endpoints.server));
     ASSERT_OK(result.status());
   }
 
@@ -355,14 +351,13 @@
   zx_status_t status;
 
   for (auto& i : tee_app_client) {
-    auto tee_endpoints = fidl::CreateEndpoints<fuchsia_tee::Application>();
-    ASSERT_OK(tee_endpoints.status_value());
+    auto tee_endpoints = fidl::Endpoints<fuchsia_tee::Application>::Create();
 
-    i = std::move(tee_endpoints->client);
+    i = std::move(tee_endpoints.client);
 
     auto result = tee_proto_client_->ConnectToApplication(
         kOpteeOsUuid, fidl::ClientEnd<::fuchsia_tee_manager::Provider>(),
-        std::move(tee_endpoints->server));
+        std::move(tee_endpoints.server));
     ASSERT_OK(result.status());
   }
 
@@ -428,14 +423,13 @@
   libsync::Completion smc_sleep_completion;
 
   for (auto& i : tee_app_client) {
-    auto tee_endpoints = fidl::CreateEndpoints<fuchsia_tee::Application>();
-    ASSERT_OK(tee_endpoints.status_value());
+    auto tee_endpoints = fidl::Endpoints<fuchsia_tee::Application>::Create();
 
-    i = std::move(tee_endpoints->client);
+    i = std::move(tee_endpoints.client);
 
     auto result = tee_proto_client_->ConnectToApplication(
         kOpteeOsUuid, fidl::ClientEnd<::fuchsia_tee_manager::Provider>(),
-        std::move(tee_endpoints->server));
+        std::move(tee_endpoints.server));
     ASSERT_OK(result.status());
   }
 
@@ -529,14 +523,13 @@
   libsync::Completion smc_sleep_completion2;
 
   for (auto& i : tee_app_client) {
-    auto tee_endpoints = fidl::CreateEndpoints<fuchsia_tee::Application>();
-    ASSERT_OK(tee_endpoints.status_value());
+    auto tee_endpoints = fidl::Endpoints<fuchsia_tee::Application>::Create();
 
-    i = std::move(tee_endpoints->client);
+    i = std::move(tee_endpoints.client);
 
     auto result = tee_proto_client_->ConnectToApplication(
         kOpteeOsUuid, fidl::ClientEnd<::fuchsia_tee_manager::Provider>(),
-        std::move(tee_endpoints->server));
+        std::move(tee_endpoints.server));
     ASSERT_OK(result.status());
   }
 
diff --git a/src/devices/temperature/drivers/aml-trip/aml-trip.cc b/src/devices/temperature/drivers/aml-trip/aml-trip.cc
index e2eccf8..229daf1 100644
--- a/src/devices/temperature/drivers/aml-trip/aml-trip.cc
+++ b/src/devices/temperature/drivers/aml-trip/aml-trip.cc
@@ -152,22 +152,19 @@
                   .devfs_args(devfs.Build())
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
   ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create endpoints: %s",
                 node_endpoints.status_string());
 
   fidl::WireResult result = fidl::WireCall(node())->AddChild(
-      args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+      args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
   parent_.Bind(std::move(node_endpoints->client));
   return zx::ok();
 }
diff --git a/src/devices/temperature/drivers/aml-trip/tests/BUILD.gn b/src/devices/temperature/drivers/aml-trip/tests/BUILD.gn
index d021082..8e32a60 100644
--- a/src/devices/temperature/drivers/aml-trip/tests/BUILD.gn
+++ b/src/devices/temperature/drivers/aml-trip/tests/BUILD.gn
@@ -32,7 +32,6 @@
     "//src/devices/lib/amlogic",
     "//src/devices/lib/mmio",
     "//src/devices/testing/fake-mmio-reg",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
     "//zircon/system/ulib/async-loop:async-loop-cpp",
     "//zircon/system/ulib/async-loop:async-loop-default",
     "//zircon/system/ulib/fbl",
diff --git a/src/devices/temperature/drivers/shtv3/shtv3-test.cc b/src/devices/temperature/drivers/shtv3/shtv3-test.cc
index d9a6866..41ae015 100644
--- a/src/devices/temperature/drivers/shtv3/shtv3-test.cc
+++ b/src/devices/temperature/drivers/shtv3/shtv3-test.cc
@@ -101,12 +101,11 @@
   ASSERT_OK(fdf::RunOnDispatcherSync(
       i2c_loop_.dispatcher(), [this]() { EXPECT_EQ(fake_i2c_->state(), FakeShtv3Device::kIdle); }));
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_temperature::Device>();
-  EXPECT_TRUE(endpoints.is_ok());
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_temperature::Device>::Create();
 
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &dut);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &dut);
 
-  fidl::WireClient<fuchsia_hardware_temperature::Device> client(std::move(endpoints->client),
+  fidl::WireClient<fuchsia_hardware_temperature::Device> client(std::move(endpoints.client),
                                                                 loop.dispatcher());
 
   client->GetTemperatureCelsius().Then([&loop](auto& result) {
@@ -130,12 +129,11 @@
   Shtv3Device dut(nullptr, std::move(i2c_client_), kSensorName);
   EXPECT_OK(dut.Init());
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_temperature::Device>();
-  EXPECT_TRUE(endpoints.is_ok());
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_temperature::Device>::Create();
 
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), &dut);
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), &dut);
 
-  fidl::WireClient<fuchsia_hardware_temperature::Device> client(std::move(endpoints->client),
+  fidl::WireClient<fuchsia_hardware_temperature::Device> client(std::move(endpoints.client),
                                                                 loop.dispatcher());
 
   client->GetSensorName().Then([&](auto& result) {
diff --git a/src/devices/temperature/drivers/tmp112/tmp112-test.cc b/src/devices/temperature/drivers/tmp112/tmp112-test.cc
index 1f989a2..02e1f47 100644
--- a/src/devices/temperature/drivers/tmp112/tmp112-test.cc
+++ b/src/devices/temperature/drivers/tmp112/tmp112-test.cc
@@ -27,15 +27,14 @@
   Tmp112DeviceTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) {}
 
   void SetUp() override {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    ASSERT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
 
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &mock_i2c_);
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &mock_i2c_);
 
     ASSERT_OK(loop_.StartThread());
     root_ = MockDevice::FakeRootParent();
     dev_ =
-        std::make_unique<Tmp112Device>(root_.get(), ddk::I2cChannel(std::move(endpoints->client)));
+        std::make_unique<Tmp112Device>(root_.get(), ddk::I2cChannel(std::move(endpoints.client)));
   }
 
  protected:
@@ -56,15 +55,14 @@
 
 TEST_F(Tmp112DeviceTest, GetTemperatureCelsius) {
   mock_i2c_.ExpectWrite({kTemperatureReg}).ExpectReadStop({0x34, 0x12});
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_temperature::Device>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_temperature::Device>::Create();
 
   async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
-  fidl::BindServer(loop.dispatcher(), std::move(endpoints->server), dev_.get());
+  fidl::BindServer(loop.dispatcher(), std::move(endpoints.server), dev_.get());
   ASSERT_OK(loop.StartThread());
 
   TemperatureClient client;
-  client.Bind(std::move(endpoints->client));
+  client.Bind(std::move(endpoints.client));
   auto result = client->GetTemperatureCelsius();
   EXPECT_OK(result->status);
   EXPECT_TRUE(FloatNear(result->temp, dev_->RegToTemperatureCelsius(0x1234)));
diff --git a/src/devices/testing/BUILD.gn b/src/devices/testing/BUILD.gn
index 1f239bb6..722f01e 100644
--- a/src/devices/testing/BUILD.gn
+++ b/src/devices/testing/BUILD.gn
@@ -15,7 +15,6 @@
     "mock-ddk:tests",
     "mock-mmio-range:tests",
     "mock-mmio-reg:tests",
-    "mock-mmio-reg-zxtest:tests",
     "syslog:tests",
   ]
 }
diff --git a/src/devices/testing/goldfish/fake_pipe/fake_pipe.cc b/src/devices/testing/goldfish/fake_pipe/fake_pipe.cc
index 803f421..9ceaf00 100644
--- a/src/devices/testing/goldfish/fake_pipe/fake_pipe.cc
+++ b/src/devices/testing/goldfish/fake_pipe/fake_pipe.cc
@@ -200,16 +200,6 @@
   completer.ReplySuccess(std::move(bti));
 }
 
-void FakePipe::ConnectSysmem(ConnectSysmemRequestView request,
-                             ConnectSysmemCompleter::Sync& completer) {
-  completer.ReplySuccess();
-}
-
-void FakePipe::RegisterSysmemHeap(RegisterSysmemHeapRequestView request,
-                                  RegisterSysmemHeapCompleter::Sync& completer) {
-  completer.ReplySuccess();
-}
-
 zx_status_t FakePipe::SetUpPipeDevice() {
   fbl::AutoLock lock(&lock_);
 
diff --git a/src/devices/testing/goldfish/fake_pipe/fake_pipe.h b/src/devices/testing/goldfish/fake_pipe/fake_pipe.h
index 372b0df..a314894 100644
--- a/src/devices/testing/goldfish/fake_pipe/fake_pipe.h
+++ b/src/devices/testing/goldfish/fake_pipe/fake_pipe.h
@@ -32,10 +32,6 @@
   void Open(OpenRequestView request, OpenCompleter::Sync& completer) override;
   void Exec(ExecRequestView request, ExecCompleter::Sync& completer) override;
   void GetBti(GetBtiCompleter::Sync& completer) override;
-  void ConnectSysmem(ConnectSysmemRequestView request,
-                     ConnectSysmemCompleter::Sync& completer) override;
-  void RegisterSysmemHeap(RegisterSysmemHeapRequestView request,
-                          RegisterSysmemHeapCompleter::Sync& completer) override;
 
   // FakePipe stores a queue of byte vectors for PIPE_CMD_READ commands.
   // Every time it receives a PIPE_CMD_READ command, it will pop a byte vector
diff --git a/src/devices/testing/mock-ddk/mock-ddk-test.cc b/src/devices/testing/mock-ddk/mock-ddk-test.cc
index 75bde9e..cd7fa1f 100644
--- a/src/devices/testing/mock-ddk/mock-ddk-test.cc
+++ b/src/devices/testing/mock-ddk/mock-ddk-test.cc
@@ -552,12 +552,11 @@
     ASSERT_OK(service_result.status_value());
   }
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-  ASSERT_OK(outgoing.Serve(std::move(endpoints->server)).status_value());
+  ASSERT_OK(outgoing.Serve(std::move(endpoints.server)).status_value());
 
-  parent->AddFidlService(fidl_examples_echo::EchoService::Name, std::move(endpoints->client));
+  parent->AddFidlService(fidl_examples_echo::EchoService::Name, std::move(endpoints.client));
 
   // Service is available after being set.
   auto echo_client = test_device->DdkConnectFidlProtocol<fidl_examples_echo::EchoService::Echo>();
@@ -656,8 +655,7 @@
 
   // So we add the necessary service to the parent:
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   auto service_result = outgoing.AddService<fidl_examples_echo::DriverEchoService>(
       fidl_examples_echo::DriverEchoService::InstanceHandler({
@@ -665,9 +663,9 @@
       }));
   EXPECT_OK(service_result.status_value());
 
-  EXPECT_OK(outgoing.Serve(std::move(endpoints->server)).status_value());
+  EXPECT_OK(outgoing.Serve(std::move(endpoints.server)).status_value());
 
-  parent->AddFidlService(fidl_examples_echo::DriverEchoService::Name, std::move(endpoints->client));
+  parent->AddFidlService(fidl_examples_echo::DriverEchoService::Name, std::move(endpoints.client));
 
   // Service is available after being set.
   auto echo_client =
diff --git a/src/devices/testing/mock-mmio-reg-zxtest/BUILD.gn b/src/devices/testing/mock-mmio-reg-zxtest/BUILD.gn
deleted file mode 100644
index b1eb548..0000000
--- a/src/devices/testing/mock-mmio-reg-zxtest/BUILD.gn
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2019 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/cpp/sdk_source_set.gni")
-
-group("tests") {
-  testonly = true
-  deps = [ "test:mock-mmio-reg-zxtest-test" ]
-}
-
-config("headers.config") {
-  include_dirs = [ "include" ]
-}
-
-source_set("mock-mmio-reg-zxtest") {
-  public = [ "include/mock-mmio-reg-zxtest/mock-mmio-reg.h" ]
-  deps = [
-    "//src/devices/lib/mmio:test_helper",
-    "//zircon/system/ulib/mmio-ptr:mmio-ptr-fake",
-  ]
-  public_configs = [ ":headers.config" ]
-
-  # New tests should use gtest and the gtest version of this library:
-  # //src/devices/testing/mock-mmio-reg
-  visibility = [
-    "test:*",
-    "//src/camera/drivers/hw_accel/gdc:*",
-    "//src/camera/drivers/hw_accel/ge2d:*",
-    "//src/devices/ml/drivers/aml-nna:*",
-    "//src/devices/nand/drivers/aml-rawnand/tests:*",
-    "//src/devices/power/drivers/aml-meson-power:*",
-    "//src/devices/pwm/drivers/aml-pwm:*",
-    "//src/devices/registers/drivers/registers:*",
-    "//src/devices/suspend/drivers/aml-suspend/tests:*",
-    "//src/devices/temperature/drivers/aml-trip/tests:*",
-    "//src/devices/thermal/drivers/aml-thermal:*",
-    "//src/devices/thermal/drivers/aml-thermal-s905d2g-legacy:*",
-    "//src/media/audio/drivers/aml-g12-tdm/test:*",
-    "//src/ui/backlight/drivers/ti-lp8556:*",
-    "//vendor/*",
-  ]
-}
diff --git a/src/devices/testing/mock-mmio-reg-zxtest/include/mock-mmio-reg-zxtest/mock-mmio-reg.h b/src/devices/testing/mock-mmio-reg-zxtest/include/mock-mmio-reg-zxtest/mock-mmio-reg.h
deleted file mode 100644
index 71ab3e6..0000000
--- a/src/devices/testing/mock-mmio-reg-zxtest/include/mock-mmio-reg-zxtest/mock-mmio-reg.h
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SRC_DEVICES_TESTING_MOCK_MMIO_REG_INCLUDE_MOCK_MMIO_REG_MOCK_MMIO_REG_H_
-#define SRC_DEVICES_TESTING_MOCK_MMIO_REG_INCLUDE_MOCK_MMIO_REG_MOCK_MMIO_REG_H_
-
-#include <lib/mmio-ptr/fake.h>
-#include <lib/mmio/mmio.h>
-
-#include <memory>
-
-#include <fbl/vector.h>
-#include <zxtest/zxtest.h>
-
-#include "src/devices/lib/mmio/test-helper.h"
-
-namespace ddk_mock {
-
-namespace {
-
-// Mocks a single MMIO register. This class is intended to be used with a fdf::MmioBuffer;
-// operations on an instance of that class will be directed to the mock if the mock-mmio-reg-zxtest
-// library is a dependency of the test.
-class MockMmioReg {
- public:
-  // Reads from the mocked register. Returns the value set by the next expectation, or the default
-  // value. The default is initially zero and can be set by calling ReadReturns() or Write(). This
-  // method is expected to be called (indirectly) by the code under test.
-  uint64_t Read() {
-    if (read_expectations_index_ >= read_expectations_.size()) {
-      return last_value_;
-    }
-
-    MmioExpectation& exp = read_expectations_[read_expectations_index_++];
-    if (exp.match == MmioExpectation::Match::kAny) {
-      return last_value_;
-    }
-
-    return last_value_ = exp.value;
-  }
-
-  // Writes to the mocked register. This method is expected to be called (indirectly) by the code
-  // under test.
-  void Write(uint64_t value) {
-    last_value_ = value;
-
-    if (write_expectations_index_ >= write_expectations_.size()) {
-      return;
-    }
-
-    MmioExpectation& exp = write_expectations_[write_expectations_index_++];
-    if (exp.match != MmioExpectation::Match::kAny) {
-      EXPECT_EQ(exp.value, value);
-    }
-  }
-
-  // Matches a register read and returns the specified value.
-  MockMmioReg& ExpectRead(uint64_t value) {
-    read_expectations_.push_back(
-        MmioExpectation{.match = MmioExpectation::Match::kEqual, .value = value});
-
-    return *this;
-  }
-
-  // Matches a register read and returns the default value.
-  MockMmioReg& ExpectRead() {
-    read_expectations_.push_back(
-        MmioExpectation{.match = MmioExpectation::Match::kAny, .value = 0});
-
-    return *this;
-  }
-
-  // Sets the default register read value.
-  MockMmioReg& ReadReturns(uint64_t value) {
-    last_value_ = value;
-    return *this;
-  }
-
-  // Matches a register write with the specified value.
-  MockMmioReg& ExpectWrite(uint64_t value) {
-    write_expectations_.push_back(
-        MmioExpectation{.match = MmioExpectation::Match::kEqual, .value = value});
-
-    return *this;
-  }
-
-  // Matches any register write.
-  MockMmioReg& ExpectWrite() {
-    write_expectations_.push_back(
-        MmioExpectation{.match = MmioExpectation::Match::kAny, .value = 0});
-
-    return *this;
-  }
-
-  // Removes and ignores all expectations and resets the default read value.
-  void Clear() {
-    last_value_ = 0;
-
-    read_expectations_index_ = 0;
-    while (read_expectations_.size() > 0) {
-      read_expectations_.pop_back();
-    }
-
-    write_expectations_index_ = 0;
-    while (write_expectations_.size() > 0) {
-      write_expectations_.pop_back();
-    }
-  }
-
-  // Removes all expectations and resets the default value. The presence of any outstanding
-  // expectations causes a test failure.
-  void VerifyAndClear() {
-    EXPECT_GE(read_expectations_index_, read_expectations_.size());
-    EXPECT_GE(write_expectations_index_, write_expectations_.size());
-    Clear();
-  }
-
- private:
-  struct MmioExpectation {
-    enum class Match { kEqual, kAny } match;
-    uint64_t value;
-  };
-
-  uint64_t last_value_ = 0;
-
-  size_t read_expectations_index_ = 0;
-  fbl::Vector<MmioExpectation> read_expectations_;
-
-  size_t write_expectations_index_ = 0;
-  fbl::Vector<MmioExpectation> write_expectations_;
-};
-
-}  // namespace
-
-// Mocks a region of MMIO registers. Each register is backed by a MockMmioReg instance.
-//
-// Example:
-// ddk_mock::MockMmioRegRegion mock_registers(register_size, number_of_registers);
-// fdf::MmioBuffer mmio_buffer(mock_registers.GetMmioBuffer());
-//
-// SomeDriver dut(mmio_buffer);
-// mock_registers[0]
-//     .ExpectRead()
-//     .ExpectWrite(0xdeadbeef)
-//     .ExpectRead(0xcafecafe)
-//     .ExpectWrite()
-//     .ExpectRead();
-// mock_registers[5]
-//     .ExpectWrite(0)
-//     .ExpectWrite(1024)
-//     .ReadReturns(0);
-//
-// EXPECT_OK(dut.SomeMethod());
-// mock_registers.VerifyAll();
-//
-class MockMmioRegRegion {
- public:
-  // Constructs a MockMmioRegRegion. reg_size is the size of each register in bytes, and reg_count
-  // is the total number of registers. If all accesses will be to registers past a certain address,
-  // reg_offset can be set to this value (in number of registers) to reduce the required reg_count.
-  // Accesses to registers lower than this offset are not permitted.
-  MockMmioRegRegion(size_t reg_size, size_t reg_count, size_t reg_offset = 0)
-      : reg_size_(reg_size), reg_count_(reg_count), reg_offset_(reg_offset) {
-    ASSERT_GT(reg_size_, 0);
-    regs_.resize(reg_count_);
-  }
-
-  // Accesses the MockMmioReg at the given offset. Note that this is the _offset_, not the
-  // _index_.
-  const MockMmioReg& operator[](size_t offset) const {
-    CheckOffset(offset);
-    return regs_[(offset / reg_size_) - reg_offset_];
-  }
-
-  // Accesses the MockMmioReg at the given offset. Note that this is the _offset_, not the
-  // _index_.
-  MockMmioReg& operator[](size_t offset) {
-    CheckOffset(offset);
-    return regs_[(offset / reg_size_) - reg_offset_];
-  }
-
-  // Calls VerifyAndClear() on all MockMmioReg objects.
-  void VerifyAll() {
-    for (auto& reg : regs_) {
-      reg.VerifyAndClear();
-    }
-  }
-
-  fdf::MmioBuffer GetMmioBuffer() {
-    return fdf_testing::CreateMmioBuffer((reg_offset_ + reg_size_) + reg_count_,
-                                         ZX_CACHE_POLICY_CACHED, &kMockMmioOps, this);
-  }
-
- private:
-  static uint8_t Read8(const void* ctx, const mmio_buffer_t& mmio, zx_off_t offs) {
-    auto& reg_region = *reinterpret_cast<MockMmioRegRegion*>(const_cast<void*>(ctx));
-    return static_cast<uint8_t>(reg_region[offs + mmio.offset].Read());
-  }
-
-  static uint16_t Read16(const void* ctx, const mmio_buffer_t& mmio, zx_off_t offs) {
-    auto& reg_region = *reinterpret_cast<MockMmioRegRegion*>(const_cast<void*>(ctx));
-    return static_cast<uint16_t>(reg_region[offs + mmio.offset].Read());
-  }
-
-  static uint32_t Read32(const void* ctx, const mmio_buffer_t& mmio, zx_off_t offs) {
-    auto& reg_region = *reinterpret_cast<MockMmioRegRegion*>(const_cast<void*>(ctx));
-    return static_cast<uint32_t>(reg_region[offs + mmio.offset].Read());
-  }
-
-  static uint64_t Read64(const void* ctx, const mmio_buffer_t& mmio, zx_off_t offs) {
-    auto& reg_region = *reinterpret_cast<MockMmioRegRegion*>(const_cast<void*>(ctx));
-    return reg_region[offs + mmio.offset].Read();
-  }
-
-  static void Write8(const void* ctx, const mmio_buffer_t& mmio, uint8_t val, zx_off_t offs) {
-    Write64(ctx, mmio, val, offs);
-  }
-
-  static void Write16(const void* ctx, const mmio_buffer_t& mmio, uint16_t val, zx_off_t offs) {
-    Write64(ctx, mmio, val, offs);
-  }
-
-  static void Write32(const void* ctx, const mmio_buffer_t& mmio, uint32_t val, zx_off_t offs) {
-    Write64(ctx, mmio, val, offs);
-  }
-
-  static void Write64(const void* ctx, const mmio_buffer_t& mmio, uint64_t val, zx_off_t offs) {
-    auto& reg_region = *reinterpret_cast<MockMmioRegRegion*>(const_cast<void*>(ctx));
-    reg_region[offs + mmio.offset].Write(val);
-  }
-
-  static constexpr fdf::MmioBufferOps kMockMmioOps = {
-      .Read8 = Read8,
-      .Read16 = Read16,
-      .Read32 = Read32,
-      .Read64 = Read64,
-      .Write8 = Write8,
-      .Write16 = Write16,
-      .Write32 = Write32,
-      .Write64 = Write64,
-  };
-
-  void CheckOffset(zx_off_t offs) const {
-    ASSERT_GE(offs / reg_size_, reg_offset_);
-    ASSERT_LT((offs / reg_size_) - reg_offset_, reg_count_);
-  }
-
-  fbl::Vector<MockMmioReg> regs_;
-  const size_t reg_size_;
-  const size_t reg_count_;
-  const size_t reg_offset_;
-};
-
-}  // namespace ddk_mock
-
-#endif  // SRC_DEVICES_TESTING_MOCK_MMIO_REG_INCLUDE_MOCK_MMIO_REG_MOCK_MMIO_REG_H_
diff --git a/src/devices/testing/mock-mmio-reg-zxtest/test/BUILD.gn b/src/devices/testing/mock-mmio-reg-zxtest/test/BUILD.gn
deleted file mode 100644
index d8ceaca..0000000
--- a/src/devices/testing/mock-mmio-reg-zxtest/test/BUILD.gn
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2019 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/components.gni")
-import("//build/test.gni")
-
-group("test") {
-  testonly = true
-  deps = [ ":mock-mmio-reg-zxtest-test-bin" ]
-}
-
-test("mock-mmio-reg-zxtest-test-bin") {
-  if (is_fuchsia) {
-    fdio_config = [ "//build/config/fuchsia:fdio_config" ]
-    if (configs + fdio_config - fdio_config != configs) {
-      configs -= fdio_config
-    }
-  }
-  output_name = "mock-mmio-reg-zxtest-test"
-  sources = [ "mock-mmio-reg-test.cc" ]
-  deps = [
-    "//sdk/lib/fdio",
-    "//src/devices/lib/mmio",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
-    "//zircon/system/ulib/zx",
-    "//zircon/system/ulib/zxtest",
-  ]
-}
-
-fuchsia_unittest_package("mock-mmio-reg-zxtest-test") {
-  deps = [ ":mock-mmio-reg-zxtest-test-bin" ]
-}
diff --git a/src/devices/testing/mock-mmio-reg-zxtest/test/mock-mmio-reg-test.cc b/src/devices/testing/mock-mmio-reg-zxtest/test/mock-mmio-reg-test.cc
deleted file mode 100644
index 994ba0a..0000000
--- a/src/devices/testing/mock-mmio-reg-zxtest/test/mock-mmio-reg-test.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <lib/mmio/mmio.h>
-
-#include <fbl/algorithm.h>
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
-#include <zxtest/zxtest.h>
-
-namespace ddk_mock_test {
-
-TEST(MockMmioReg, CopyFrom) {
-  ddk_mock::MockMmioRegRegion reg_region_1(sizeof(uint32_t), 0x100);
-  ddk_mock::MockMmioRegRegion reg_region_2(sizeof(uint32_t), 0x100);
-
-  fdf::MmioBuffer dut_1 = reg_region_1.GetMmioBuffer();
-  fdf::MmioBuffer dut_2 = reg_region_2.GetMmioBuffer();
-
-  constexpr uint32_t reg_values[] = {0xdb5a95fd, 0xc1c8f880, 0x733c2bed, 0xf74e857c};
-  for (size_t i = 0; i < std::size(reg_values); i++) {
-    reg_region_1[0x10 + (i * 4)].ExpectRead(reg_values[i]);
-    reg_region_2[0x40 + (i * 4)].ExpectWrite(reg_values[i]);
-  }
-
-  dut_2.CopyFrom32(dut_1, 0x10, 0x40, 4);
-
-  ASSERT_NO_FATAL_FAILURE(reg_region_1.VerifyAll());
-  ASSERT_NO_FATAL_FAILURE(reg_region_2.VerifyAll());
-}
-
-TEST(MockMmioReg, View) {
-  ddk_mock::MockMmioRegRegion reg_region(sizeof(uint32_t), 0x100);
-
-  fdf::MmioBuffer dut = reg_region.GetMmioBuffer();
-  fdf::MmioView dut_view_1 = dut.View(0x40);
-  fdf::MmioView dut_view_2 = dut_view_1.View(0x20);
-
-  reg_region[0x20].ExpectRead(0x8ed43ca9).ExpectWrite(0x7a5da8d8);
-  reg_region[0x80].ExpectRead(0x5be3254c).ExpectWrite(0x6ba7d0af);
-  reg_region[0x60].ExpectRead(0xa1026dfe).ExpectWrite(0x0164bff2);
-
-  EXPECT_EQ(dut.Read32(0x20), 0x8ed43ca9);
-  EXPECT_EQ(dut_view_1.Read32(0x40), 0x5be3254c);
-  EXPECT_EQ(dut_view_2.Read32(0), 0xa1026dfe);
-
-  dut.Write32(0x7a5da8d8, 0x20);
-  dut_view_1.Write32(0x6ba7d0af, 0x40);
-  dut_view_2.Write32(0x0164bff2, 0);
-
-  ASSERT_NO_FATAL_FAILURE(reg_region.VerifyAll());
-}
-
-TEST(MockMmioReg, Offset) {
-  ddk_mock::MockMmioRegRegion reg_region(sizeof(uint32_t), 0x100,
-                                         0x1'0000 / sizeof(uint32_t));
-
-  fdf::MmioBuffer dut = reg_region.GetMmioBuffer();
-
-  reg_region[0x1'0020].ExpectRead(0x8ed43ca9).ExpectWrite(0x7a5da8d8);
-  reg_region[0x1'0080].ExpectRead(0x5be3254c).ExpectWrite(0x6ba7d0af);
-  reg_region[0x1'0060].ExpectRead(0xa1026dfe).ExpectWrite(0x0164bff2);
-
-  EXPECT_EQ(dut.Read32(0x1'0020), 0x8ed43ca9);
-  EXPECT_EQ(dut.Read32(0x1'0080), 0x5be3254c);
-  EXPECT_EQ(dut.Read32(0x1'0060), 0xa1026dfe);
-
-  dut.Write32(0x7a5da8d8, 0x1'0020);
-  dut.Write32(0x6ba7d0af, 0x1'0080);
-  dut.Write32(0x0164bff2, 0x1'0060);
-
-  ASSERT_NO_FATAL_FAILURE(reg_region.VerifyAll());
-}
-
-}  // namespace ddk_mock_test
diff --git a/src/devices/testing/mock-mmio-reg/BUILD.gn b/src/devices/testing/mock-mmio-reg/BUILD.gn
index a1f03ad..8ece911 100644
--- a/src/devices/testing/mock-mmio-reg/BUILD.gn
+++ b/src/devices/testing/mock-mmio-reg/BUILD.gn
@@ -13,6 +13,40 @@
   include_dirs = [ "include" ]
 }
 
+config("zxtest-backend") {
+  defines = [ "MOCK_MMIO_REG_USE_ZXTEST" ]
+}
+
+source_set("mock-mmio-reg-zxtest") {
+  public = [ "include/mock-mmio-reg/mock-mmio-reg.h" ]
+  deps = [
+    "//src/devices/lib/mmio:test_helper",
+    "//zircon/system/ulib/mmio-ptr:mmio-ptr-fake",
+  ]
+  public_configs = [
+    ":headers.config",
+    ":zxtest-backend",
+  ]
+
+  visibility = [
+    "test:*",
+    "//src/camera/drivers/hw_accel/gdc:*",
+    "//src/camera/drivers/hw_accel/ge2d:*",
+    "//src/devices/ml/drivers/aml-nna:*",
+    "//src/devices/nand/drivers/aml-rawnand/tests:*",
+    "//src/devices/power/drivers/aml-meson-power:*",
+    "//src/devices/pwm/drivers/aml-pwm:*",
+    "//src/devices/registers/drivers/registers:*",
+    "//src/devices/suspend/drivers/aml-suspend/tests:*",
+    "//src/devices/temperature/drivers/aml-trip/tests:*",
+    "//src/devices/thermal/drivers/aml-thermal:*",
+    "//src/devices/thermal/drivers/aml-thermal-s905d2g-legacy:*",
+    "//src/media/audio/drivers/aml-g12-tdm/test:*",
+    "//src/ui/backlight/drivers/ti-lp8556:*",
+    "//vendor/*",
+  ]
+}
+
 sdk_source_set("mock-mmio-reg") {
   category = "internal"
   sdk_name = "mock-mmio-reg"
diff --git a/src/devices/testing/mock-mmio-reg/include/mock-mmio-reg/mock-mmio-reg.h b/src/devices/testing/mock-mmio-reg/include/mock-mmio-reg/mock-mmio-reg.h
index 8615406..f3a403e 100644
--- a/src/devices/testing/mock-mmio-reg/include/mock-mmio-reg/mock-mmio-reg.h
+++ b/src/devices/testing/mock-mmio-reg/include/mock-mmio-reg/mock-mmio-reg.h
@@ -11,7 +11,13 @@
 #include <memory>
 
 #include <fbl/vector.h>
+
+// SDK-users, don't build with -DMOCK_MMIO_REG_USE_ZXTEST in effect, zxtest isn't available.
+#ifdef MOCK_MMIO_REG_USE_ZXTEST
+#include <zxtest/zxtest.h>
+#else
 #include <gtest/gtest.h>
+#endif
 
 #include "src/devices/lib/mmio/test-helper.h"
 
@@ -163,6 +169,9 @@
   MockMmioRegRegion(size_t reg_size, size_t reg_count, size_t reg_offset = 0)
       : reg_size_(reg_size), reg_count_(reg_count), reg_offset_(reg_offset) {
     regs_.resize(reg_count_);
+#ifdef MOCK_MMIO_REG_USE_ZXTEST
+    ASSERT_GT(reg_size_, 0);
+#endif
   }
 
   // Accesses the MockMmioReg at the given offset. Note that this is the _offset_, not the
diff --git a/src/devices/tests/BUILD.gn b/src/devices/tests/BUILD.gn
index ef85557..be63f13 100644
--- a/src/devices/tests/BUILD.gn
+++ b/src/devices/tests/BUILD.gn
@@ -15,7 +15,6 @@
     "ddk-firmware-test:tests",
     "ddk-lifecycle:tests",
     "ddk-metadata-test",
-    "ddk-power:tests",
     "ddk-topology-test:tests",
     "devfs:tests",
     "device-controller-fidl:tests",
@@ -57,8 +56,6 @@
     "ddk-firmware-test:ddk-firmware-test-driver",
     "ddk-lifecycle:ddk-lifecycle-test-driver-component",
     "ddk-metadata-test:driver",
-    "ddk-power:ddk-power-test",
-    "ddk-power:ddk-power-test-child",
     "ddk-topology-test:ddk-topology-test-driver",
     "driver-inspect-test:inspect-test-driver",
     "driver-multiname-test:parent_device_component",
diff --git a/src/devices/tests/ddk-lifecycle/test.cc b/src/devices/tests/ddk-lifecycle/test.cc
index 58e55ac..6684cdd 100644
--- a/src/devices/tests/ddk-lifecycle/test.cc
+++ b/src/devices/tests/ddk-lifecycle/test.cc
@@ -53,9 +53,7 @@
     chan_ = fidl::ClientEnd<TestDevice>(std::move(channel.value()));
 
     // Subscribe to the device lifecycle events.
-    auto endpoints = fidl::CreateEndpoints<Lifecycle>();
-    ASSERT_OK(endpoints.status_value());
-    auto [local, remote] = *std::move(endpoints);
+    auto [local, remote] = fidl::Endpoints<Lifecycle>::Create();
 
     auto result = fidl::WireCall(chan_)->SubscribeToLifecycle(std::move(remote));
     ASSERT_OK(result.status());
diff --git a/src/devices/tests/ddk-power/BUILD.gn b/src/devices/tests/ddk-power/BUILD.gn
deleted file mode 100644
index 455d161..0000000
--- a/src/devices/tests/ddk-power/BUILD.gn
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright 2019 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/bind/bind.gni")
-import("//build/components.gni")
-import("//build/drivers.gni")
-import("//build/fidl/fidl.gni")
-import("//build/test.gni")
-
-fidl("fuchsia.device.power.test") {
-  sources = [ "test.fidl" ]
-  public_deps = [ "//sdk/fidl/fuchsia.device" ]
-}
-
-driver_bind_rules("test-power-bind") {
-  rules = "test-power.bind"
-  deps = [ "//src/devices/bind/fuchsia.test.platform" ]
-}
-
-fuchsia_driver("ddk-power-test-driver") {
-  output_name = "ddk-power-test"
-  configs += [
-    "//build/config:all_source",
-    "//build/config/fuchsia:enable_zircon_asserts",
-  ]
-  sources = [ "test-driver.cc" ]
-  deps = [
-    ":fuchsia.device.power.test_cpp",
-    ":test-power-bind",
-    "//sdk/lib/fdio",
-    "//src/devices/lib/driver",
-    "//src/lib/ddk",
-    "//src/lib/ddktl",
-    "//zircon/system/ulib/fbl",
-  ]
-}
-
-fuchsia_driver_component("ddk-power-test") {
-  component_name = "ddk-power-test"
-  deps = [ ":ddk-power-test-driver" ]
-  info = "ddk-power-test-info.json"
-  manifest = "meta/ddk-power-test.cml"
-}
-
-driver_bind_rules("test-power-child-bind") {
-  rules = "test-power-child.bind"
-  deps = [ "//src/devices/bind/fuchsia.test" ]
-}
-
-fuchsia_driver("ddk-power-test-child-driver") {
-  output_name = "ddk-power-test-child"
-  configs += [
-    "//build/config:all_source",
-    "//build/config/fuchsia:enable_zircon_asserts",
-  ]
-  sources = [ "test-driver-child.cc" ]
-  deps = [
-    ":fuchsia.device.power.test_cpp",
-    ":test-power-child-bind",
-    "//sdk/lib/fdio",
-    "//src/devices/lib/driver",
-    "//src/lib/ddk",
-    "//src/lib/ddktl",
-    "//zircon/system/ulib/fbl",
-  ]
-}
-
-fuchsia_driver_component("ddk-power-test-child") {
-  component_name = "ddk-power-test-child"
-  deps = [ ":ddk-power-test-child-driver" ]
-  info = "ddk-power-test-child-info.json"
-  manifest = "meta/ddk-power-test-child.cml"
-}
-
-test("ddk-power") {
-  sources = [ "test.cc" ]
-  deps = [
-    ":fuchsia.device.power.test_cpp",
-    "//sdk/fidl/fuchsia.device:fuchsia.device_cpp",
-    "//sdk/fidl/fuchsia.device.manager:fuchsia.device.manager_cpp",
-    "//sdk/fidl/fuchsia.hardware.power.statecontrol:fuchsia.hardware.power.statecontrol_cpp",
-    "//sdk/fidl/fuchsia.process.lifecycle:fuchsia.process.lifecycle_cpp",
-    "//sdk/lib/component/outgoing/cpp",
-    "//sdk/lib/device-watcher/cpp",
-    "//src/devices/testing/driver-integration-test-shim",
-    "//src/lib/ddk",
-    "//zircon/system/ulib/fbl",
-    "//zircon/system/ulib/zx",
-    "//zircon/system/ulib/zxtest",
-  ]
-}
-
-fuchsia_unittest_package("ddk-power-test-package") {
-  deps = [
-    ":ddk-power",
-    ":ddk-power-test",
-    ":ddk-power-test-child",
-    "//src/devices/board/drivers/integration-test",
-    "//src/devices/bus/drivers/platform",
-  ]
-}
-
-group("tests") {
-  testonly = true
-  deps = [ ":ddk-power-test-package" ]
-}
diff --git a/src/devices/tests/ddk-power/ddk-power-test-child-info.json b/src/devices/tests/ddk-power/ddk-power-test-child-info.json
deleted file mode 100644
index 4696a0f..0000000
--- a/src/devices/tests/ddk-power/ddk-power-test-child-info.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "short_description": "Driver Framework power test driver",
-    "manufacturer": "",
-    "families": [],
-    "models": [],
-    "areas": [
-        "DriverFramework",
-        "Test"
-    ]
-}
diff --git a/src/devices/tests/ddk-power/ddk-power-test-info.json b/src/devices/tests/ddk-power/ddk-power-test-info.json
deleted file mode 100644
index 4696a0f..0000000
--- a/src/devices/tests/ddk-power/ddk-power-test-info.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-    "short_description": "Driver Framework power test driver",
-    "manufacturer": "",
-    "families": [],
-    "models": [],
-    "areas": [
-        "DriverFramework",
-        "Test"
-    ]
-}
diff --git a/src/devices/tests/ddk-power/meta/ddk-power-test-child.cml b/src/devices/tests/ddk-power/meta/ddk-power-test-child.cml
deleted file mode 100644
index 047aeed..0000000
--- a/src/devices/tests/ddk-power/meta/ddk-power-test-child.cml
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    include: [
-        "//sdk/lib/driver/compat/compat.shard.cml",
-        "inspect/client.shard.cml",
-        "syslog/client.shard.cml",
-    ],
-    program: {
-        runner: "driver",
-        bind: "meta/bind/test-power-child-bind.bindbc",
-        colocate: "true",
-        compat: "driver/ddk-power-test-child.so",
-        default_dispatcher_opts: [ "allow_sync_calls" ],
-        fallback: "false",
-    },
-    use: [],
-}
diff --git a/src/devices/tests/ddk-power/meta/ddk-power-test.cml b/src/devices/tests/ddk-power/meta/ddk-power-test.cml
deleted file mode 100644
index 2a45e02..0000000
--- a/src/devices/tests/ddk-power/meta/ddk-power-test.cml
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    include: [
-        "//sdk/lib/driver/compat/compat.shard.cml",
-        "inspect/client.shard.cml",
-        "syslog/client.shard.cml",
-    ],
-    program: {
-        runner: "driver",
-        bind: "meta/bind/test-power-bind.bindbc",
-        compat: "driver/ddk-power-test.so",
-        default_dispatcher_opts: [ "allow_sync_calls" ],
-        fallback: "false",
-    },
-    use: [],
-}
diff --git a/src/devices/tests/ddk-power/test-driver-child.cc b/src/devices/tests/ddk-power/test-driver-child.cc
deleted file mode 100644
index 94744e8..0000000
--- a/src/devices/tests/ddk-power/test-driver-child.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <fidl/fuchsia.device.power.test/cpp/wire.h>
-#include <lib/ddk/binding_driver.h>
-#include <lib/ddk/debug.h>
-#include <lib/ddk/device.h>
-#include <lib/ddk/driver.h>
-#include <lib/ddk/platform-defs.h>
-#include <lib/fdio/fd.h>
-#include <lib/fdio/fdio.h>
-#include <lib/fdio/namespace.h>
-#include <lib/fdio/spawn.h>
-#include <lib/fdio/unsafe.h>
-#include <lib/fdio/watcher.h>
-
-#include <ddktl/device.h>
-#include <ddktl/fidl.h>
-#include <fbl/alloc_checker.h>
-
-using fuchsia_device::wire::DevicePowerState;
-using fuchsia_device::wire::DevicePowerStateInfo;
-using fuchsia_device_power_test::TestDevice;
-
-class TestPowerDriverChild;
-using DeviceType =
-    ddk::Device<TestPowerDriverChild, ddk::Messageable<TestDevice>::Mixin, ddk::Suspendable,
-                ddk::Resumable, ddk::AutoSuspendable, ddk::Initializable>;
-class TestPowerDriverChild : public DeviceType {
- public:
-  TestPowerDriverChild(zx_device_t* parent) : DeviceType(parent) {
-    zx::event::create(0, &suspend_completion_event_);
-  }
-  static zx_status_t Create(void* ctx, zx_device_t* device);
-  zx_status_t Bind();
-
-  void AddDeviceWithPowerArgs(AddDeviceWithPowerArgsRequestView request,
-                              AddDeviceWithPowerArgsCompleter::Sync& completer) override;
-
-  void GetCurrentDevicePowerState(GetCurrentDevicePowerStateCompleter::Sync& completer) override;
-  void GetCurrentSuspendReason(GetCurrentSuspendReasonCompleter::Sync& completer) override;
-  void GetCurrentDeviceAutoSuspendConfig(
-      GetCurrentDeviceAutoSuspendConfigCompleter::Sync& completer) override;
-
-  void SetTestStatusInfo(SetTestStatusInfoRequestView request,
-                         SetTestStatusInfoCompleter::Sync& completer) override;
-
-  void DdkInit(ddk::InitTxn txn);
-  void DdkRelease() { delete this; }
-  void DdkSuspend(ddk::SuspendTxn txn);
-  void DdkResume(ddk::ResumeTxn txn);
-  zx_status_t DdkConfigureAutoSuspend(bool enable, uint8_t deepest_sleep_state);
-
-  void SavePowerStateInfo(std::unique_ptr<device_power_state_info_t[]> states,
-                          uint8_t states_count) {
-    states_ = std::move(states);
-    states_count_ = states_count;
-  }
-
-  void GetSuspendCompletionEvent(GetSuspendCompletionEventCompleter::Sync& completer) override {
-    zx::event complete;
-    zx_status_t status =
-        suspend_completion_event_.duplicate(ZX_RIGHT_WAIT | ZX_RIGHT_TRANSFER, &complete);
-    if (status != ZX_OK) {
-      completer.ReplyError(status);
-      return;
-    }
-    completer.ReplySuccess(std::move(complete));
-  }
-
- private:
-  uint8_t current_power_state_ = 0;
-  uint8_t auto_suspend_sleep_state_ = 0;
-  bool auto_suspend_enabled_ = false;
-  uint8_t current_suspend_reason_ = 0;
-
-  zx_status_t reply_suspend_status_ = ZX_OK;
-  zx_status_t reply_resume_status_ = ZX_OK;
-  uint8_t reply_out_power_state_ = DEV_POWER_STATE_D0;
-  uint32_t reply_out_performance_state_ = DEV_PERFORMANCE_STATE_P0;
-
-  std::unique_ptr<device_power_state_info_t[]> states_;
-  uint8_t states_count_ = 0;
-  zx::event suspend_completion_event_;
-};
-
-void TestPowerDriverChild::DdkInit(ddk::InitTxn txn) {
-  txn.Reply(ZX_OK, states_.get(), states_count_);
-}
-
-void TestPowerDriverChild::DdkSuspend(ddk::SuspendTxn txn) {
-  if (reply_suspend_status_ == ZX_OK) {
-    reply_out_power_state_ = txn.requested_state();
-  }
-  current_suspend_reason_ = txn.suspend_reason();
-  current_power_state_ = reply_out_power_state_;
-  suspend_completion_event_.signal(0, ZX_USER_SIGNAL_0);
-  txn.Reply(reply_suspend_status_, reply_out_power_state_);
-
-  // Reset for next test.
-  reply_suspend_status_ = ZX_OK;
-  reply_out_power_state_ = DEV_POWER_STATE_D0;
-  reply_out_performance_state_ = DEV_PERFORMANCE_STATE_P0;
-}
-
-void TestPowerDriverChild::DdkResume(ddk::ResumeTxn txn) {
-  if (reply_resume_status_ == ZX_OK) {
-    reply_out_power_state_ = DEV_POWER_STATE_D0;
-    reply_out_performance_state_ = txn.requested_state();
-  }
-  current_power_state_ = reply_out_power_state_;
-  // In a successful response, power state is a working state.
-  txn.Reply(reply_resume_status_, reply_out_power_state_, reply_out_performance_state_);
-  reply_resume_status_ = ZX_OK;
-  reply_out_power_state_ = DEV_POWER_STATE_D0;
-  reply_out_performance_state_ = DEV_PERFORMANCE_STATE_P0;
-}
-
-zx_status_t TestPowerDriverChild::DdkConfigureAutoSuspend(bool enable,
-                                                          uint8_t deepest_sleep_state) {
-  auto_suspend_enabled_ = enable;
-  auto_suspend_sleep_state_ = deepest_sleep_state;
-  return ZX_OK;
-}
-
-void TestPowerDriverChild::AddDeviceWithPowerArgs(
-    AddDeviceWithPowerArgsRequestView request, AddDeviceWithPowerArgsCompleter::Sync& completer) {
-  fbl::AllocChecker ac;
-  auto child2 = fbl::make_unique_checked<TestPowerDriverChild>(&ac, this->parent());
-  if (!ac.check()) {
-    completer.ReplyError(ZX_ERR_NO_MEMORY);
-    return;
-  }
-
-  auto state_info = request->info.data();
-  auto states = std::make_unique<device_power_state_info_t[]>(request->info.count());
-  auto count = static_cast<uint8_t>(request->info.count());
-  for (uint8_t i = 0; i < count; i++) {
-    states[i].state_id = static_cast<device_power_state_t>(state_info[i].state_id);
-    states[i].restore_latency = state_info[i].restore_latency;
-    states[i].wakeup_capable = state_info[i].wakeup_capable;
-    states[i].system_wake_state = state_info[i].system_wake_state;
-  }
-
-  zx_status_t status;
-  if (!request->make_visible) {
-    status = child2->DdkAdd(
-        ddk::DeviceAddArgs("power-test-child-2").set_power_states({states.get(), count}));
-  } else {
-    child2->SavePowerStateInfo(std::move(states), count);
-    status = child2->DdkAdd("power-test-child-2");
-  }
-  if (status != ZX_OK) {
-    completer.ReplyError(status);
-  } else {
-    completer.ReplySuccess();
-    [[maybe_unused]] auto ptr = child2.release();
-  }
-}
-
-void TestPowerDriverChild::SetTestStatusInfo(SetTestStatusInfoRequestView request,
-                                             SetTestStatusInfoCompleter::Sync& completer) {
-  reply_suspend_status_ = request->test_info.suspend_status;
-  reply_resume_status_ = request->test_info.resume_status;
-  reply_out_power_state_ = request->test_info.out_power_state;
-  reply_out_performance_state_ = request->test_info.out_performance_state;
-  completer.ReplySuccess();
-}
-
-void TestPowerDriverChild::GetCurrentDevicePowerState(
-    GetCurrentDevicePowerStateCompleter::Sync& completer) {
-  completer.ReplySuccess(static_cast<DevicePowerState>(current_power_state_));
-}
-
-void TestPowerDriverChild::GetCurrentSuspendReason(
-    GetCurrentSuspendReasonCompleter::Sync& completer) {
-  completer.ReplySuccess(current_suspend_reason_);
-}
-
-void TestPowerDriverChild::GetCurrentDeviceAutoSuspendConfig(
-    GetCurrentDeviceAutoSuspendConfigCompleter::Sync& completer) {
-  completer.ReplySuccess(auto_suspend_enabled_,
-                         static_cast<DevicePowerState>(auto_suspend_sleep_state_));
-}
-
-zx_status_t TestPowerDriverChild::Bind() { return DdkAdd("power-test-child"); }
-
-zx_status_t TestPowerDriverChild::Create(void* ctx, zx_device_t* device) {
-  fbl::AllocChecker ac;
-  auto dev = fbl::make_unique_checked<TestPowerDriverChild>(&ac, device);
-
-  if (!ac.check()) {
-    return ZX_ERR_NO_MEMORY;
-  }
-  auto status = dev->Bind();
-  if (status == ZX_OK) {
-    // devmgr is now in charge of the memory for dev
-    [[maybe_unused]] auto ptr = dev.release();
-  }
-  return status;
-}
-
-static zx_driver_ops_t test_power_child_driver_ops = []() -> zx_driver_ops_t {
-  zx_driver_ops_t ops = {};
-  ops.version = DRIVER_OPS_VERSION;
-  ops.bind = TestPowerDriverChild::Create;
-  return ops;
-}();
-
-ZIRCON_DRIVER(TestPowerChild, test_power_child_driver_ops, "zircon", "0.1");
diff --git a/src/devices/tests/ddk-power/test-driver.cc b/src/devices/tests/ddk-power/test-driver.cc
deleted file mode 100644
index 0dbed87..0000000
--- a/src/devices/tests/ddk-power/test-driver.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <fidl/fuchsia.device.power.test/cpp/wire.h>
-#include <lib/ddk/binding_driver.h>
-#include <lib/ddk/debug.h>
-#include <lib/ddk/device.h>
-#include <lib/ddk/driver.h>
-#include <lib/ddk/platform-defs.h>
-
-#include <ddktl/device.h>
-#include <ddktl/fidl.h>
-#include <ddktl/protocol/empty-protocol.h>
-#include <fbl/alloc_checker.h>
-
-using fuchsia_device::wire::DevicePerformanceStateInfo;
-using fuchsia_device::wire::DevicePowerState;
-using fuchsia_device::wire::DevicePowerStateInfo;
-using fuchsia_device_power_test::TestDevice;
-
-class TestPowerDriver;
-using DeviceType =
-    ddk::Device<TestPowerDriver, ddk::Suspendable, ddk::Messageable<TestDevice>::Mixin>;
-class TestPowerDriver : public DeviceType, public ddk::EmptyProtocol<ZX_PROTOCOL_TEST_POWER_CHILD> {
- public:
-  TestPowerDriver(zx_device_t* parent) : DeviceType(parent) {}
-  zx_status_t Bind();
-  void DdkRelease() { delete this; }
-  void DdkSuspend(ddk::SuspendTxn txn) {
-    current_power_state_ = static_cast<DevicePowerState>(txn.requested_state());
-    suspend_complete_event_.signal(0, ZX_USER_SIGNAL_0);
-    txn.Reply(ZX_OK, txn.requested_state());
-  }
-
-  void GetSuspendCompletionEvent(GetSuspendCompletionEventCompleter::Sync& completer) override {
-    zx::event complete;
-    zx_status_t status =
-        suspend_complete_event_.duplicate(ZX_RIGHT_WAIT | ZX_RIGHT_TRANSFER, &complete);
-    if (status != ZX_OK) {
-      completer.ReplyError(status);
-    } else {
-      completer.ReplySuccess(std::move(complete));
-    }
-  }
-
-  void AddDeviceWithPowerArgs(AddDeviceWithPowerArgsRequestView request,
-                              AddDeviceWithPowerArgsCompleter::Sync& completer) override;
-
-  void GetCurrentDevicePowerState(GetCurrentDevicePowerStateCompleter::Sync& completer) override;
-  void GetCurrentSuspendReason(GetCurrentSuspendReasonCompleter::Sync& completer) override;
-  void GetCurrentDeviceAutoSuspendConfig(
-      GetCurrentDeviceAutoSuspendConfigCompleter::Sync& completer) override;
-  void SetTestStatusInfo(SetTestStatusInfoRequestView request,
-                         SetTestStatusInfoCompleter::Sync& completer) override;
-
- private:
-  DevicePowerState current_power_state_ = DevicePowerState::kDevicePowerStateD0;
-  bool auto_suspend_enabled_ = false;
-  DevicePowerState deepest_autosuspend_sleep_state_ = DevicePowerState::kDevicePowerStateD0;
-  zx_status_t reply_suspend_status_ = ZX_OK;
-  zx_status_t reply_resume_status_ = ZX_OK;
-  zx::event suspend_complete_event_;
-};
-
-zx_status_t TestPowerDriver::Bind() {
-  zx_status_t status = zx::event::create(0, &suspend_complete_event_);
-  if (status != ZX_OK) {
-    return status;
-  }
-  return DdkAdd("power-test");
-}
-
-void TestPowerDriver::AddDeviceWithPowerArgs(AddDeviceWithPowerArgsRequestView request,
-                                             AddDeviceWithPowerArgsCompleter::Sync& completer) {
-  completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
-}
-
-void TestPowerDriver::GetCurrentDevicePowerState(
-    GetCurrentDevicePowerStateCompleter::Sync& completer) {
-  completer.ReplySuccess(current_power_state_);
-}
-
-void TestPowerDriver::GetCurrentDeviceAutoSuspendConfig(
-    GetCurrentDeviceAutoSuspendConfigCompleter::Sync& completer) {
-  completer.ReplySuccess(auto_suspend_enabled_,
-                         static_cast<DevicePowerState>(deepest_autosuspend_sleep_state_));
-}
-void TestPowerDriver::SetTestStatusInfo(SetTestStatusInfoRequestView request,
-                                        SetTestStatusInfoCompleter::Sync& completer) {
-  reply_suspend_status_ = request->test_info.suspend_status;
-  reply_resume_status_ = request->test_info.resume_status;
-  completer.ReplySuccess();
-}
-
-void TestPowerDriver::GetCurrentSuspendReason(GetCurrentSuspendReasonCompleter::Sync& completer) {
-  completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
-}
-
-zx_status_t test_power_hook_bind(void* ctx, zx_device_t* device) {
-  fbl::AllocChecker ac;
-  auto dev = fbl::make_unique_checked<TestPowerDriver>(&ac, device);
-  if (!ac.check()) {
-    return ZX_ERR_NO_MEMORY;
-  }
-  auto status = dev->Bind();
-  if (status == ZX_OK) {
-    // devmgr is now in charge of the memory for dev
-    [[maybe_unused]] auto ptr = dev.release();
-  }
-  return status;
-}
-
-static zx_driver_ops_t test_power_hook_driver_ops = []() -> zx_driver_ops_t {
-  zx_driver_ops_t ops = {};
-  ops.version = DRIVER_OPS_VERSION;
-  ops.bind = test_power_hook_bind;
-  return ops;
-}();
-
-ZIRCON_DRIVER(TestPower, test_power_hook_driver_ops, "zircon", "0.1");
diff --git a/src/devices/tests/ddk-power/test-power-child.bind b/src/devices/tests/ddk-power/test-power-child.bind
deleted file mode 100644
index 1894e67..0000000
--- a/src/devices/tests/ddk-power/test-power-child.bind
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-using fuchsia.test;
-
-fuchsia.BIND_PROTOCOL == fuchsia.test.BIND_PROTOCOL.POWER_CHILD;
diff --git a/src/devices/tests/ddk-power/test-power.bind b/src/devices/tests/ddk-power/test-power.bind
deleted file mode 100644
index f7f3b3d4..0000000
--- a/src/devices/tests/ddk-power/test-power.bind
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-using fuchsia.test.platform;
-
-fuchsia.BIND_PLATFORM_DEV_VID == fuchsia.test.platform.BIND_PLATFORM_DEV_VID.TEST;
-fuchsia.BIND_PLATFORM_DEV_PID == fuchsia.test.platform.BIND_PLATFORM_DEV_PID.POWER;
diff --git a/src/devices/tests/ddk-power/test.cc b/src/devices/tests/ddk-power/test.cc
deleted file mode 100644
index 1b248cf..0000000
--- a/src/devices/tests/ddk-power/test.cc
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <fidl/fuchsia.device.manager/cpp/wire.h>
-#include <fidl/fuchsia.device.power.test/cpp/wire.h>
-#include <fidl/fuchsia.device/cpp/wire.h>
-#include <fidl/fuchsia.hardware.power.statecontrol/cpp/wire.h>
-#include <fidl/fuchsia.process.lifecycle/cpp/wire.h>
-#include <lib/ddk/device.h>
-#include <lib/ddk/platform-defs.h>
-#include <lib/device-watcher/cpp/device-watcher.h>
-#include <lib/driver-integration-test/fixture.h>
-#include <zircon/processargs.h>
-#include <zircon/syscalls.h>
-
-#include <zxtest/zxtest.h>
-
-using driver_integration_test::IsolatedDevmgr;
-using fuchsia_device::wire::DevicePerformanceStateInfo;
-using fuchsia_device::wire::DevicePowerState;
-using fuchsia_device::wire::DevicePowerStateInfo;
-using fuchsia_device::wire::kDevicePerformanceStateP0;
-using fuchsia_device::wire::kMaxDevicePowerStates;
-using fuchsia_device::wire::SystemPowerStateInfo;
-using fuchsia_device_manager::wire::SystemPowerState;
-using fuchsia_device_power_test::TestDevice;
-namespace device_manager_fidl = fuchsia_device_manager;
-namespace lifecycle_fidl = fuchsia_process_lifecycle;
-
-constexpr char kPowerTestPath[] = "sys/platform/11:0b:0/power-test";
-constexpr char kPowerTestChild1Path[] = "sys/platform/11:0b:0/power-test/power-test-child";
-constexpr char kPowerTestChild2Path[] = "sys/platform/11:0b:0/power-test/power-test-child-2";
-
-class PowerTestCase : public zxtest::Test {
- public:
-  ~PowerTestCase() override = default;
-  void SetUp() override {
-    IsolatedDevmgr::Args args;
-
-    board_test::DeviceEntry dev = {};
-    dev.vid = PDEV_VID_TEST;
-    dev.pid = PDEV_PID_POWER_TEST;
-    dev.did = 0;
-    args.device_list.push_back(dev);
-
-    zx_status_t status = IsolatedDevmgr::Create(&args, &devmgr);
-    ASSERT_OK(status);
-
-    zx::result parent_channel =
-        device_watcher::RecursiveWaitForFile(devmgr.devfs_root().get(), kPowerTestPath);
-    ASSERT_OK(parent_channel);
-    parent_device_client.Bind(fidl::ClientEnd<TestDevice>{std::move(parent_channel.value())});
-
-    std::string parent_controller_path = std::string(kPowerTestPath) + "/device_controller";
-    parent_channel = device_watcher::RecursiveWaitForFile(devmgr.devfs_root().get(),
-                                                          parent_controller_path.c_str());
-    ASSERT_OK(parent_channel);
-    parent_device_controller.Bind(
-        fidl::ClientEnd<fuchsia_device::Controller>{std::move(parent_channel.value())});
-
-    zx::result child_channel =
-        device_watcher::RecursiveWaitForFile(devmgr.devfs_root().get(), kPowerTestChild1Path);
-    ASSERT_OK(child_channel);
-    child1_device_client.Bind(fidl::ClientEnd<TestDevice>{std::move(child_channel.value())});
-
-    std::string child_controller_path = std::string(kPowerTestChild1Path) + "/device_controller";
-    child_channel = device_watcher::RecursiveWaitForFile(devmgr.devfs_root().get(),
-                                                         child_controller_path.c_str());
-    ASSERT_OK(child_channel);
-    child1_device_controller.Bind(
-        fidl::ClientEnd<fuchsia_device::Controller>{std::move(child_channel.value())});
-  }
-
-  void AddChildWithPowerArgs(DevicePowerStateInfo *states, uint8_t sleep_state_count,
-                             bool add_invisible = false) {
-    auto power_states =
-        ::fidl::VectorView<DevicePowerStateInfo>::FromExternal(states, sleep_state_count);
-    auto response = child1_device_client->AddDeviceWithPowerArgs(power_states, add_invisible);
-    ASSERT_OK(response.status());
-    zx_status_t call_status = ZX_OK;
-    if (response->is_error()) {
-      call_status = response->error_value();
-    }
-    ASSERT_OK(call_status);
-
-    zx::result channel =
-        device_watcher::RecursiveWaitForFile(devmgr.devfs_root().get(), kPowerTestChild2Path);
-    ASSERT_OK(channel);
-    child2_device_client.Bind(fidl::ClientEnd<TestDevice>{std::move(channel.value())});
-
-    std::string child_controller_path = std::string(kPowerTestChild2Path) + "/device_controller";
-    channel = device_watcher::RecursiveWaitForFile(devmgr.devfs_root().get(),
-                                                   child_controller_path.c_str());
-    ASSERT_OK(channel);
-    child2_device_controller.Bind(
-        fidl::ClientEnd<fuchsia_device::Controller>{std::move(channel.value())});
-  }
-
-  void WaitForDeviceSuspendCompletion(const fidl::WireSyncClient<TestDevice> &client) {
-    const fidl::WireResult result = client->GetSuspendCompletionEvent();
-    ASSERT_OK(result.status());
-    const fit::result response = result.value();
-    ASSERT_TRUE(response.is_ok(), "%s", zx_status_get_string(response.error_value()));
-    zx_signals_t signals;
-    ASSERT_OK(response->event.wait_one(ZX_USER_SIGNAL_0, zx::time::infinite(), &signals));
-  }
-
-  fidl::WireSyncClient<TestDevice> parent_device_client;
-  fidl::WireSyncClient<fuchsia_device::Controller> parent_device_controller;
-
-  fidl::WireSyncClient<TestDevice> child1_device_client;
-  fidl::WireSyncClient<fuchsia_device::Controller> child1_device_controller;
-
-  fidl::WireSyncClient<TestDevice> child2_device_client;
-  fidl::WireSyncClient<fuchsia_device::Controller> child2_device_controller;
-  IsolatedDevmgr devmgr;
-};
-
-TEST_F(PowerTestCase, AddDevicePowerCaps_Success) {
-  std::array<DevicePowerStateInfo, 2> states;
-  states[0].state_id = DevicePowerState::kDevicePowerStateD0;
-  states[0].is_supported = true;
-  states[1].state_id = DevicePowerState::kDevicePowerStateD3Cold;
-  states[1].is_supported = true;
-  auto response = child1_device_client->AddDeviceWithPowerArgs(
-      fidl::VectorView<DevicePowerStateInfo>::FromExternal(states), false);
-  ASSERT_OK(response.status());
-  zx_status_t call_status = ZX_OK;
-  if (response->is_error()) {
-    call_status = response->error_value();
-  }
-
-  ASSERT_STATUS(call_status, ZX_OK);
-}
-
-TEST_F(PowerTestCase, AddDevicePowerCaps_MakeVisible_Success) {
-  DevicePowerStateInfo states[3];
-  states[0].state_id = DevicePowerState::kDevicePowerStateD0;
-  states[0].is_supported = true;
-  states[0].restore_latency = 0;
-  states[1].state_id = DevicePowerState::kDevicePowerStateD1;
-  states[1].is_supported = true;
-  states[1].restore_latency = 100;
-  states[2].state_id = DevicePowerState::kDevicePowerStateD3Cold;
-  states[2].is_supported = true;
-  states[2].restore_latency = 1000;
-
-  AddChildWithPowerArgs(states, std::size(states), true);
-}
-
-// TODO(https://fxbug.dev/42071033): Re-enable this test after fixing.
-// This test is not easy to replicate without a lot of plumbing changes to allow test to modify the
-// response to fuchsia.device.manager/SystemStateTransition.GetTerminationSystemState.
-TEST_F(PowerTestCase, DISABLED_SystemSuspend_SuspendReasonReboot) {
-  // Add Capabilities
-  DevicePowerStateInfo states[3];
-  states[0].state_id = DevicePowerState::kDevicePowerStateD0;
-  states[0].is_supported = true;
-  states[0].restore_latency = 0;
-  states[1].state_id = DevicePowerState::kDevicePowerStateD2;
-  states[1].is_supported = true;
-  states[1].restore_latency = 100;
-  states[2].state_id = DevicePowerState::kDevicePowerStateD3Cold;
-  states[2].is_supported = true;
-  states[2].restore_latency = 1000;
-  AddChildWithPowerArgs(states, std::size(states));
-
-  ASSERT_OK(devmgr.SuspendDriverManager());
-
-  // Wait till child2's suspend event is called.
-  WaitForDeviceSuspendCompletion(child2_device_client);
-
-  auto child_dev_suspend_response = child2_device_client->GetCurrentDevicePowerState();
-  ASSERT_OK(child_dev_suspend_response.status());
-  auto call_status = ZX_OK;
-  if (child_dev_suspend_response->is_error()) {
-    call_status = child_dev_suspend_response->error_value();
-  }
-  ASSERT_OK(call_status);
-  ASSERT_EQ(child_dev_suspend_response->value()->cur_state,
-            DevicePowerState::kDevicePowerStateD3Cold);
-
-  // Verify that the suspend reason is received correctly
-  auto suspend_reason_response = child2_device_client->GetCurrentSuspendReason();
-  ASSERT_OK(suspend_reason_response.status());
-  call_status = ZX_OK;
-  if (suspend_reason_response->is_error()) {
-    call_status = suspend_reason_response->error_value();
-  }
-  ASSERT_OK(call_status);
-  ASSERT_EQ(suspend_reason_response->value()->cur_suspend_reason, DEVICE_SUSPEND_REASON_REBOOT);
-
-  // Wait till parent's suspend event is called.
-  WaitForDeviceSuspendCompletion(parent_device_client);
-
-  auto parent_dev_suspend_response = parent_device_client->GetCurrentDevicePowerState();
-  ASSERT_OK(parent_dev_suspend_response.status());
-  call_status = ZX_OK;
-  if (parent_dev_suspend_response->is_error()) {
-    call_status = parent_dev_suspend_response->error_value();
-  }
-  ASSERT_OK(call_status);
-  ASSERT_EQ(parent_dev_suspend_response->value()->cur_state,
-            DevicePowerState::kDevicePowerStateD3Cold);
-}
-
-// TODO(https://fxbug.dev/42071033): Re-enable this test after fixing.
-// This test is not easy to replicate without a lot of plumbing changes to allow test to modify the
-// response to fuchsia.device.manager/SystemStateTransition.GetTerminationSystemState.
-TEST_F(PowerTestCase, DISABLED_SystemSuspend_SuspendReasonRebootRecovery) {
-  // Add Capabilities
-  DevicePowerStateInfo states[3];
-  states[0].state_id = DevicePowerState::kDevicePowerStateD0;
-  states[0].is_supported = true;
-  states[0].restore_latency = 0;
-  states[1].state_id = DevicePowerState::kDevicePowerStateD2;
-  states[1].is_supported = true;
-  states[1].restore_latency = 100;
-  states[2].state_id = DevicePowerState::kDevicePowerStateD3Cold;
-  states[2].is_supported = true;
-  states[2].restore_latency = 1000;
-  AddChildWithPowerArgs(states, std::size(states));
-
-  // TODO(https://fxbug.dev/42071033): Modify GetTerminationSystemState response.
-
-  ASSERT_OK(devmgr.SuspendDriverManager());
-
-  // Wait till child2's suspend event is called.
-  WaitForDeviceSuspendCompletion(child2_device_client);
-
-  auto child_dev_suspend_response = child2_device_client->GetCurrentDevicePowerState();
-  ASSERT_OK(child_dev_suspend_response.status());
-  auto call_status = ZX_OK;
-  if (child_dev_suspend_response->is_error()) {
-    call_status = child_dev_suspend_response->error_value();
-  }
-  ASSERT_OK(call_status);
-  ASSERT_EQ(child_dev_suspend_response->value()->cur_state,
-            DevicePowerState::kDevicePowerStateD3Cold);
-
-  auto suspend_reason_response = child2_device_client->GetCurrentSuspendReason();
-  ASSERT_OK(suspend_reason_response.status());
-  call_status = ZX_OK;
-  if (suspend_reason_response->is_error()) {
-    call_status = suspend_reason_response->error_value();
-  }
-  ASSERT_OK(call_status);
-  ASSERT_EQ(suspend_reason_response->value()->cur_suspend_reason,
-            DEVICE_SUSPEND_REASON_REBOOT_RECOVERY);
-
-  // Wait till parent's suspend event is called.
-  WaitForDeviceSuspendCompletion(parent_device_client);
-  auto parent_dev_suspend_response = parent_device_client->GetCurrentDevicePowerState();
-  ASSERT_OK(parent_dev_suspend_response.status());
-  call_status = ZX_OK;
-  if (parent_dev_suspend_response->is_error()) {
-    call_status = parent_dev_suspend_response->error_value();
-  }
-  ASSERT_OK(call_status);
-  ASSERT_EQ(parent_dev_suspend_response->value()->cur_state,
-            DevicePowerState::kDevicePowerStateD3Cold);
-}
diff --git a/src/devices/tests/ddk-power/test.fidl b/src/devices/tests/ddk-power/test.fidl
deleted file mode 100644
index 956a407..0000000
--- a/src/devices/tests/ddk-power/test.fidl
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-library fuchsia.device.power.test;
-
-using zx;
-using fuchsia.device;
-
-type TestStatusInfo = struct {
-    /// Driver will respond to suspend hook with this status.
-    suspend_status zx.Status;
-    /// Driver will respond to resume hook with this status.
-    resume_status zx.Status;
-    /// This is the out_power_state we want as a reply.
-    out_power_state uint8;
-    /// This is the out_perf_state we want as a reply.
-    out_performance_state uint8;
-};
-
-closed protocol TestDevice {
-    /// Add Test Device with some powerargs
-    strict AddDeviceWithPowerArgs(struct {
-        info vector<fuchsia.device.DevicePowerStateInfo>:MAX;
-        make_visible bool;
-    }) -> () error zx.Status;
-    /// Get current power state of the device
-    strict GetCurrentDevicePowerState() -> (struct {
-        cur_state fuchsia.device.DevicePowerState;
-    }) error zx.Status;
-    /// Get the suspend reason of the last suspend call
-    strict GetCurrentSuspendReason() -> (struct {
-        cur_suspend_reason uint8;
-    }) error zx.Status;
-    /// Get current auto suspend status and deepest_sleep_state
-    strict GetCurrentDeviceAutoSuspendConfig() -> (struct {
-        enabled bool;
-        deepest_sleep_state fuchsia.device.DevicePowerState;
-    }) error zx.Status;
-    strict SetTestStatusInfo(struct {
-        test_info TestStatusInfo;
-    }) -> () error zx.Status;
-
-    strict GetSuspendCompletionEvent() -> (resource struct {
-        event zx.Handle:EVENT;
-    }) error zx.Status;
-};
diff --git a/src/devices/tests/devfs/fidl-tests.cc b/src/devices/tests/devfs/fidl-tests.cc
index 2a94363..dc23afb 100644
--- a/src/devices/tests/devfs/fidl-tests.cc
+++ b/src/devices/tests/devfs/fidl-tests.cc
@@ -23,11 +23,10 @@
 
 void FidlOpenValidator(const fidl::ClientEnd<fio::Directory>& directory, const char* path,
                        zx::result<fio::wire::NodeInfoDeprecated::Tag> expected) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
   const fidl::Status result = fidl::WireCall(directory)->Open(
       fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kDescribe, {},
-      fidl::StringView::FromExternal(path), std::move(endpoints->server));
+      fidl::StringView::FromExternal(path), std::move(endpoints.server));
   ASSERT_OK(result.status());
 
   class EventHandler : public fidl::testing::WireSyncEventHandlerTestBase<fio::Node> {
@@ -52,7 +51,7 @@
   };
 
   EventHandler event_handler;
-  ASSERT_OK(event_handler.HandleOneEvent(endpoints->client).status());
+  ASSERT_OK(event_handler.HandleOneEvent(endpoints.client).status());
   ASSERT_TRUE(event_handler.status().has_value());
   if (expected.is_ok()) {
     ASSERT_OK(event_handler.status().value());
@@ -68,35 +67,32 @@
 // Ensure that our hand-rolled FIDL messages within devfs and memfs are acting correctly
 // for open event messages (on both success and error).
 TEST(FidlTestCase, OpenDev) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fio::Directory>::Create();
   ASSERT_OK(fdio_open("/dev", static_cast<uint32_t>(fio::OpenFlags::kRightReadable),
-                      endpoints->server.channel().release()));
+                      endpoints.server.channel().release()));
 
-  FidlOpenValidator(endpoints->client, "zero", zx::ok(fio::wire::NodeInfoDeprecated::Tag::kFile));
-  FidlOpenValidator(endpoints->client, "this-path-better-not-actually-exist",
+  FidlOpenValidator(endpoints.client, "zero", zx::ok(fio::wire::NodeInfoDeprecated::Tag::kFile));
+  FidlOpenValidator(endpoints.client, "this-path-better-not-actually-exist",
                     zx::error(ZX_ERR_NOT_FOUND));
-  FidlOpenValidator(endpoints->client, "zero/this-path-better-not-actually-exist",
+  FidlOpenValidator(endpoints.client, "zero/this-path-better-not-actually-exist",
                     zx::error(ZX_ERR_NOT_SUPPORTED));
 }
 
 TEST(FidlTestCase, OpenPkg) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fio::Directory>::Create();
   ASSERT_OK(fdio_open("/pkg", static_cast<uint32_t>(fio::OpenFlags::kRightReadable),
-                      endpoints->server.channel().release()));
+                      endpoints.server.channel().release()));
 
-  FidlOpenValidator(endpoints->client, "bin",
+  FidlOpenValidator(endpoints.client, "bin",
                     zx::ok(fio::wire::NodeInfoDeprecated::Tag::kDirectory));
-  FidlOpenValidator(endpoints->client, "this-path-better-not-actually-exist",
+  FidlOpenValidator(endpoints.client, "this-path-better-not-actually-exist",
                     zx::error(ZX_ERR_NOT_FOUND));
 }
 
 TEST(FidlTestCase, BasicDevClass) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_OK(endpoints.status_value());
-  ASSERT_OK(fdio_service_connect("/dev/class", endpoints->server.channel().release()));
-  const fidl::WireResult result = fidl::WireCall(endpoints->client)->Query();
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
+  ASSERT_OK(fdio_service_connect("/dev/class", endpoints.server.channel().release()));
+  const fidl::WireResult result = fidl::WireCall(endpoints.client)->Query();
   ASSERT_OK(result.status());
   const auto& response = result.value();
   const cpp20::span data = response.protocol.get();
@@ -105,10 +101,9 @@
 }
 
 TEST(FidlTestCase, BasicDevZero) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_OK(endpoints.status_value());
-  ASSERT_OK(fdio_service_connect("/dev/zero", endpoints->server.channel().release()));
-  const fidl::WireResult result = fidl::WireCall(endpoints->client)->Query();
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
+  ASSERT_OK(fdio_service_connect("/dev/zero", endpoints.server.channel().release()));
+  const fidl::WireResult result = fidl::WireCall(endpoints.client)->Query();
   ASSERT_OK(result.status());
   const auto& response = result.value();
   const cpp20::span data = response.protocol.get();
@@ -159,16 +154,15 @@
 }
 
 TEST(FidlTestCase, DirectoryWatcherExisting) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fio::Directory>::Create();
 
   zx::result watcher_endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
   ASSERT_OK(watcher_endpoints.status_value());
 
-  ASSERT_OK(fdio_service_connect("/dev/class", endpoints->server.channel().release()));
+  ASSERT_OK(fdio_service_connect("/dev/class", endpoints.server.channel().release()));
 
   const fidl::WireResult result =
-      fidl::WireCall(endpoints->client)
+      fidl::WireCall(endpoints.client)
           ->Watch(fio::wire::WatchMask::kMask, 0, std::move(watcher_endpoints->server));
   ASSERT_OK(result.status());
   const auto& response = result.value();
@@ -190,10 +184,9 @@
 }
 
 TEST(FidlTestCase, DirectoryWatcherWithClosedHalf) {
-  zx::result endpoints = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fio::Directory>::Create();
 
-  ASSERT_OK(fdio_service_connect("/dev/class", endpoints->server.channel().release()));
+  ASSERT_OK(fdio_service_connect("/dev/class", endpoints.server.channel().release()));
 
   {
     zx::result watcher_endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
@@ -203,7 +196,7 @@
     watcher_endpoints->client.reset();
 
     const fidl::WireResult result =
-        fidl::WireCall(endpoints->client)
+        fidl::WireCall(endpoints.client)
             ->Watch(fio::wire::WatchMask::kMask, 0, std::move(watcher_endpoints->server));
     ASSERT_OK(result.status());
     const auto& response = result.value();
@@ -213,12 +206,11 @@
 
   {
     // Create a new watcher, and see if it's functional at all
-    zx::result watcher_endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
-    ASSERT_OK(watcher_endpoints.status_value());
+    auto watcher_endpoints = fidl::Endpoints<fio::DirectoryWatcher>::Create();
 
     const fidl::WireResult result =
-        fidl::WireCall(endpoints->client)
-            ->Watch(fio::wire::WatchMask::kMask, 0, std::move(watcher_endpoints->server));
+        fidl::WireCall(endpoints.client)
+            ->Watch(fio::wire::WatchMask::kMask, 0, std::move(watcher_endpoints.server));
     ASSERT_OK(result.status());
     const auto& response = result.value();
     ASSERT_OK(response.s);
@@ -226,7 +218,7 @@
     watch_buffer_t wb = {};
     const char* name = nullptr;
     fio::wire::WatchEvent event;
-    ReadEvent(&wb, watcher_endpoints->client, &name, &event);
+    ReadEvent(&wb, watcher_endpoints.client, &name, &event);
     ASSERT_EQ(event, fio::wire::WatchEvent::kExisting);
   }
 }
diff --git a/src/devices/tests/device-controller-fidl/test.cc b/src/devices/tests/device-controller-fidl/test.cc
index b9d329f..814dd4ab 100644
--- a/src/devices/tests/device-controller-fidl/test.cc
+++ b/src/devices/tests/device-controller-fidl/test.cc
@@ -48,8 +48,7 @@
       device_watcher::RecursiveWaitForFile(root_fd.get(), "sys/test/sample_driver");
   ASSERT_EQ(dev_channel.status_value(), ZX_OK);
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_device::Controller>();
-  ASSERT_EQ(endpoints.status_value(), ZX_OK);
+  auto endpoints = fidl::Endpoints<fuchsia_device::Controller>::Create();
 
   fdio_cpp::UnownedFdioCaller caller(root_fd);
   zx::result channel = component::ConnectAt<fuchsia_device::Controller>(
diff --git a/src/devices/tests/v2/devfs_exporter/root_driver.cc b/src/devices/tests/v2/devfs_exporter/root_driver.cc
index 0896f3e..a49c337 100644
--- a/src/devices/tests/v2/devfs_exporter/root_driver.cc
+++ b/src/devices/tests/v2/devfs_exporter/root_driver.cc
@@ -43,22 +43,19 @@
                     .Build();
 
     // Create endpoints of the `NodeController` for the node.
-    zx::result controller_endpoints =
-        fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-    ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                  controller_endpoints.status_string());
+    auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
     zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
     ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create endpoints: %s",
                   node_endpoints.status_string());
 
     fidl::WireResult result = fidl::WireCall(node())->AddChild(
-        args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+        args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
     if (!result.ok()) {
       FDF_SLOG(ERROR, "Failed to add child", KV("status", result.status_string()));
       return zx::error(result.status());
     }
-    controller_.Bind(std::move(controller_endpoints->client));
+    controller_.Bind(std::move(controller_endpoints.client));
     node_.Bind(std::move(node_endpoints->client));
     return zx::ok();
   }
diff --git a/src/devices/tests/v2/rebind/rebind_child.cc b/src/devices/tests/v2/rebind/rebind_child.cc
index c56b938..e468f0f 100644
--- a/src/devices/tests/v2/rebind/rebind_child.cc
+++ b/src/devices/tests/v2/rebind/rebind_child.cc
@@ -44,20 +44,18 @@
                     .Build();
 
     // Create endpoints of the `NodeController` for the node.
-    zx::result controller_endpoints =
-        fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-    ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed: %s", controller_endpoints.status_string());
+    auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
     zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
     ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed: %s", node_endpoints.status_string());
 
     fidl::WireResult result = fidl::WireCall(node())->AddChild(
-        args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+        args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
     if (!result.ok()) {
       FDF_SLOG(ERROR, "Failed to add child", KV("status", result.status_string()));
       return zx::error(result.status());
     }
-    controller_.Bind(std::move(controller_endpoints->client));
+    controller_.Bind(std::move(controller_endpoints.client));
     node_.Bind(std::move(node_endpoints->client));
     return zx::ok();
   }
diff --git a/src/devices/tests/v2/rebind/rebind_parent.cc b/src/devices/tests/v2/rebind/rebind_parent.cc
index 031ad2c..a12b963 100644
--- a/src/devices/tests/v2/rebind/rebind_parent.cc
+++ b/src/devices/tests/v2/rebind/rebind_parent.cc
@@ -102,20 +102,18 @@
                     .Build();
 
     // Create endpoints of the `NodeController` for the node.
-    zx::result controller_endpoints =
-        fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-    ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed: %s", controller_endpoints.status_string());
+    auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
     zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
     ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed: %s", node_endpoints.status_string());
 
     fidl::WireResult result = fidl::WireCall(node())->AddChild(
-        args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+        args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
     if (!result.ok()) {
       FDF_SLOG(ERROR, "Failed to add child", KV("status", result.status_string()));
       return zx::error(result.status());
     }
-    controller_.Bind(std::move(controller_endpoints->client));
+    controller_.Bind(std::move(controller_endpoints.client));
     server_.emplace(dispatcher(), std::move(node_endpoints->client));
 
     return zx::ok();
diff --git a/src/devices/thermal/bin/fan-controller/fan-controller-test.cc b/src/devices/thermal/bin/fan-controller/fan-controller-test.cc
index 20aac6d..2d55c3a 100644
--- a/src/devices/thermal/bin/fan-controller/fan-controller-test.cc
+++ b/src/devices/thermal/bin/fan-controller/fan-controller-test.cc
@@ -126,10 +126,9 @@
     ASSERT_EQ(vfs_.Serve(dir_, std::move(channel0), fs::VnodeConnectionOptions::ReadOnly()), ZX_OK);
     ASSERT_EQ(fdio_ns_bind(ns_, fan_controller::kFanDirectory, channel1.release()), ZX_OK);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_thermal::ClientStateConnector>();
-    EXPECT_OK(endpoints);
-    client_state_.emplace(std::move(endpoints->server));
-    client_end_ = std::move(endpoints->client);
+    auto endpoints = fidl::Endpoints<fuchsia_thermal::ClientStateConnector>::Create();
+    client_state_.emplace(std::move(endpoints.server));
+    client_end_ = std::move(endpoints.client);
   }
 
   void TearDown() override {
diff --git a/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/BUILD.gn b/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/BUILD.gn
index 591f0d9..670f05c 100644
--- a/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/BUILD.gn
+++ b/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/BUILD.gn
@@ -93,7 +93,7 @@
     "//src/devices/lib/amlogic",
     "//src/devices/lib/mmio",
     "//src/devices/lib/mmio:test_helper",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//src/devices/testing/no_ddk",
     "//src/lib/ddk",
     "//src/lib/ddktl",
diff --git a/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/aml-fclk-rates.c b/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/aml-fclk-rates.c
index d8f69a7..f58216d 100644
--- a/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/aml-fclk-rates.c
+++ b/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/aml-fclk-rates.c
@@ -6,6 +6,8 @@
 
 #include "aml-fclk.h"
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 #define FCLK_PLL_RATE(_r, _premux, _postmux, _mux_div) \
   { .rate = (_r), .premux = (_premux), .postmux = (_postmux), .mux_div = (_mux_div), }
 
@@ -18,4 +20,4 @@
 
 const aml_fclk_rate_table_t* s905d2_fclk_get_rate_table(void) { return fclk_pll_rate_table; }
 
-size_t s905d2_fclk_get_rate_table_count(void) { return countof(fclk_pll_rate_table); }
+size_t s905d2_fclk_get_rate_table_count(void) { return ARRAY_SIZE(fclk_pll_rate_table); }
diff --git a/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/aml-thermal-test.cc b/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/aml-thermal-test.cc
index 189f03d..ee01c83 100644
--- a/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/aml-thermal-test.cc
+++ b/src/devices/thermal/drivers/aml-thermal-s905d2g-legacy/aml-thermal-test.cc
@@ -23,7 +23,7 @@
 
 #include <fbl/alloc_checker.h>
 #include <fbl/array.h>
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 #include <zxtest/zxtest.h>
 
 #include "src/devices/lib/mmio/test-helper.h"
@@ -503,10 +503,9 @@
   }
 
   fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> BindServer() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pwm::Pwm>();
-    EXPECT_TRUE(endpoints.is_ok());
-    fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints->server), this);
-    return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_pwm::Pwm>::Create();
+    fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints.server), this);
+    return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints.client));
   }
 
   void VerifyAndClear() {
diff --git a/src/devices/thermal/drivers/aml-thermal/BUILD.gn b/src/devices/thermal/drivers/aml-thermal/BUILD.gn
index 3a5198ce..b077c80 100644
--- a/src/devices/thermal/drivers/aml-thermal/BUILD.gn
+++ b/src/devices/thermal/drivers/aml-thermal/BUILD.gn
@@ -75,7 +75,7 @@
     "//src/devices/bus/lib/device-protocol-pdev",
     "//src/devices/lib/amlogic",
     "//src/devices/lib/mmio",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//src/devices/testing/no_ddk",
     "//src/lib/ddk",
     "//src/lib/ddktl",
diff --git a/src/devices/thermal/drivers/aml-thermal/aml-thermal-test.cc b/src/devices/thermal/drivers/aml-thermal/aml-thermal-test.cc
index c297c85..d95acaa 100644
--- a/src/devices/thermal/drivers/aml-thermal/aml-thermal-test.cc
+++ b/src/devices/thermal/drivers/aml-thermal/aml-thermal-test.cc
@@ -17,7 +17,7 @@
 
 #include <fbl/alloc_checker.h>
 #include <fbl/array.h>
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 #include <zxtest/zxtest.h>
 
 namespace {
diff --git a/src/devices/thermal/drivers/aml-thermistor/test/test.cc b/src/devices/thermal/drivers/aml-thermistor/test/test.cc
index a8d1ab2..f1e4e24 100644
--- a/src/devices/thermal/drivers/aml-thermistor/test/test.cc
+++ b/src/devices/thermal/drivers/aml-thermistor/test/test.cc
@@ -104,10 +104,9 @@
     }
 
     loop_.StartThread();
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_temperature::Device>();
-    ASSERT_OK(endpoints.status_value());
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), thermistor_.get());
-    client_.Bind(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_temperature::Device>::Create();
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), thermistor_.get());
+    client_.Bind(std::move(endpoints.client));
   }
 
  protected:
diff --git a/src/devices/tpm/drivers/tpm/tpm-test.cc b/src/devices/tpm/drivers/tpm/tpm-test.cc
index 6738a6e..a6b1d8d 100644
--- a/src/devices/tpm/drivers/tpm/tpm-test.cc
+++ b/src/devices/tpm/drivers/tpm/tpm-test.cc
@@ -203,11 +203,10 @@
   }
 
   fidl::WireSyncClient<fuchsia_tpm::TpmDevice> GetTpmClient() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_tpm::TpmDevice>();
-    ZX_ASSERT(endpoints.status_value() == ZX_OK);
+    auto endpoints = fidl::Endpoints<fuchsia_tpm::TpmDevice>::Create();
     tpm::TpmDevice* tpm = fake_root_->GetLatestChild()->GetDeviceContext<tpm::TpmDevice>();
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), tpm);
-    fidl::WireSyncClient<fuchsia_tpm::TpmDevice> client(std::move(endpoints->client));
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), tpm);
+    fidl::WireSyncClient<fuchsia_tpm::TpmDevice> client(std::move(endpoints.client));
 
     return client;
   }
diff --git a/src/devices/usb/bin/usbctl/usbctl.cc b/src/devices/usb/bin/usbctl/usbctl.cc
index d47e3b4..546e369 100644
--- a/src/devices/usb/bin/usbctl/usbctl.cc
+++ b/src/devices/usb/bin/usbctl/usbctl.cc
@@ -160,11 +160,7 @@
 }
 
 zx_status_t device_clear_functions(const fidl::WireSyncClient<peripheral::Device>& client) {
-  zx::result endpoints = fidl::CreateEndpoints<peripheral::Events>();
-  if (endpoints.is_error()) {
-    return endpoints.error_value();
-  }
-  auto& [client_end, server_end] = endpoints.value();
+  auto [client_end, server_end] = fidl::Endpoints<peripheral::Events>::Create();
   auto set_result = client->SetStateChangeListener(std::move(client_end));
   if (set_result.status() != ZX_OK) {
     return set_result.status();
diff --git a/src/devices/usb/drivers/aml-usb-phy/BUILD.bazel b/src/devices/usb/drivers/aml-usb-phy/BUILD.bazel
index 23d1f50..9ea5917 100644
--- a/src/devices/usb/drivers/aml-usb-phy/BUILD.bazel
+++ b/src/devices/usb/drivers/aml-usb-phy/BUILD.bazel
@@ -52,12 +52,13 @@
     output_name = "aml-usb-phy",
     deps = [
         "//src/devices/lib/amlogic",
+        "//src/lib/ddk:ddk_metadata",
+        "//zircon/system/ulib/ddk-platform-defs",
         "@fuchsia_sdk//bind/fuchsia.amlogic.platform:fuchsia.amlogic.platform_cc",
         "@fuchsia_sdk//bind/fuchsia:fuchsia_cc",
         "@fuchsia_sdk//bind/fuchsia.platform:fuchsia.platform_cc",
         "@fuchsia_sdk//bind/fuchsia.register:fuchsia.register_cc",
         "@fuchsia_sdk//fidl/fuchsia.hardware.platform.device:fuchsia.hardware.platform.device_cpp",
-        "@fuchsia_sdk//pkg/ddk",
         "@fuchsia_sdk//pkg/driver_component_cpp",
         "@fuchsia_sdk//pkg/driver_runtime",
         "@fuchsia_sdk//pkg/hwreg",
@@ -66,7 +67,6 @@
         "@internal_sdk//fidl/fuchsia.driver.compat:fuchsia.driver.compat_cpp",
         "@internal_sdk//fidl/fuchsia.hardware.registers:fuchsia.hardware.registers_cpp",
         "@internal_sdk//fidl/fuchsia.hardware.usb.phy:fuchsia.hardware.usb.phy_cpp",
-        "@internal_sdk//pkg/ddk-platform-defs",
         "@internal_sdk//pkg/driver_compat",
     ],
 )
@@ -117,6 +117,8 @@
     ],
     deps = [
         "//src/devices/lib/amlogic",
+        "//src/lib/ddk:ddk_metadata",
+        "//zircon/system/ulib/ddk-platform-defs",
         "@com_google_googletest//:gtest_main",
         "@fuchsia_sdk//bind/fuchsia.amlogic.platform:fuchsia.amlogic.platform_cc",
         "@fuchsia_sdk//bind/fuchsia:fuchsia_cc",
@@ -124,7 +126,6 @@
         "@fuchsia_sdk//bind/fuchsia.register:fuchsia.register_cc",
         "@fuchsia_sdk//fidl/fuchsia.hardware.platform.device:fuchsia.hardware.platform.device_cpp",
         "@fuchsia_sdk//pkg/async_patterns_testing_cpp",
-        "@fuchsia_sdk//pkg/ddk",
         "@fuchsia_sdk//pkg/driver_component_cpp",
         "@fuchsia_sdk//pkg/driver_runtime",
         "@fuchsia_sdk//pkg/driver_testing_cpp",
@@ -134,7 +135,6 @@
         "@internal_sdk//fidl/fuchsia.driver.compat:fuchsia.driver.compat_cpp",
         "@internal_sdk//fidl/fuchsia.hardware.registers:fuchsia.hardware.registers_cpp",
         "@internal_sdk//fidl/fuchsia.hardware.usb.phy:fuchsia.hardware.usb.phy_cpp",
-        "@internal_sdk//pkg/ddk-platform-defs",
         "@internal_sdk//pkg/driver_compat",
         "@internal_sdk//pkg/fake-mmio-reg",
         "@internal_sdk//pkg/mock-registers",
diff --git a/src/devices/usb/drivers/aml-usb-phy/aml-usb-phy-device.cc b/src/devices/usb/drivers/aml-usb-phy/aml-usb-phy-device.cc
index cfaab3e..45955a5 100644
--- a/src/devices/usb/drivers/aml-usb-phy/aml-usb-phy-device.cc
+++ b/src/devices/usb/drivers/aml-usb-phy/aml-usb-phy-device.cc
@@ -314,23 +314,20 @@
   auto args =
       fuchsia_driver_framework::wire::NodeAddArgs::Builder(arena).name(arena, kDeviceName).Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create controller endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
   zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
   ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create node endpoints: %s",
                 node_endpoints.status_string());
 
   {
     fidl::WireResult result = fidl::WireCall(node())->AddChild(
-        args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+        args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
     if (!result.ok()) {
       FDF_LOG(ERROR, "Failed to add child %s", result.FormatDescription().c_str());
       return zx::error(result.status());
     }
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
   node_.Bind(std::move(node_endpoints->client));
 
   return zx::ok();
@@ -379,17 +376,14 @@
                       })
           .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create controller endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   fidl::WireResult result =
-      parent_->node_->AddChild(args, std::move(controller_endpoints->server), {});
+      parent_->node_->AddChild(args, std::move(controller_endpoints.server), {});
   ZX_ASSERT_MSG(result.ok(), "Failed to add child %s", result.FormatDescription().c_str());
   ZX_ASSERT_MSG(result->is_ok(), "Failed to add child %d",
                 static_cast<uint32_t>(result->error_value()));
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
 
   return *this;
 }
diff --git a/src/devices/usb/drivers/aml-usb-phy/aml-usb-phy-test.cc b/src/devices/usb/drivers/aml-usb-phy/aml-usb-phy-test.cc
index aef8b02..b88f3b7 100644
--- a/src/devices/usb/drivers/aml-usb-phy/aml-usb-phy-test.cc
+++ b/src/devices/usb/drivers/aml-usb-phy/aml-usb-phy-test.cc
@@ -294,15 +294,14 @@
   });
   CheckDevices(phy, {"xhci"});
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_TRUE(endpoints.is_ok());
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   auto status = fdio_open_at(outgoing_.handle()->get(), "/svc",
                              static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
-                             endpoints->server.TakeChannel().release());
+                             endpoints.server.TakeChannel().release());
   EXPECT_EQ(ZX_OK, status);
 
   auto result = fdf::internal::DriverTransportConnect<fuchsia_hardware_usb_phy::Service::Device>(
-      endpoints->client, "xhci");
+      endpoints.client, "xhci");
   ASSERT_TRUE(result.is_ok());
 
   runtime_.PerformBlockingWork([&result]() {
diff --git a/src/devices/usb/drivers/dwc3/dwc3-test.cc b/src/devices/usb/drivers/dwc3/dwc3-test.cc
index 8cc3940..9ec6c02 100644
--- a/src/devices/usb/drivers/dwc3/dwc3-test.cc
+++ b/src/devices/usb/drivers/dwc3/dwc3-test.cc
@@ -90,10 +90,9 @@
   config.irqs[0] = {};
   ASSERT_OK(zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &config.irqs[0]));
 
-  zx::result outgoing_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(outgoing_endpoints);
+  auto outgoing_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   ASSERT_OK(incoming_loop_.StartThread("incoming-ns-thread"));
-  incoming_.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints->server)](
+  incoming_.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints.server)](
                          IncomingNamespace* infra) mutable {
     infra->pdev_server.SetConfig(std::move(config));
     ASSERT_OK(infra->outgoing.AddService<fuchsia_hardware_platform_device::Service>(
@@ -103,7 +102,7 @@
   });
   ASSERT_NO_FATAL_FAILURE();
   mock_parent_->AddFidlService(fuchsia_hardware_platform_device::Service::Name,
-                               std::move(outgoing_endpoints->client));
+                               std::move(outgoing_endpoints.client));
 }
 
 void TestFixture::SetUp() { stuck_reset_test_ = false; }
diff --git a/src/devices/usb/drivers/usb-bus/tests/usb-device.cc b/src/devices/usb/drivers/usb-bus/tests/usb-device.cc
index c308923..5ef9199b 100644
--- a/src/devices/usb/drivers/usb-bus/tests/usb-device.cc
+++ b/src/devices/usb/drivers/usb-bus/tests/usb-device.cc
@@ -263,10 +263,9 @@
       device_ = device.get();
     });
     EXPECT_TRUE(result.is_ok());
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_usb_device::Device>();
-    ASSERT_OK(endpoints.status_value());
-    fidl::BindServer(dispatcher_->async_dispatcher(), std::move(endpoints->server), device_);
-    fidl_.Bind(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_usb_device::Device>::Create();
+    fidl::BindServer(dispatcher_->async_dispatcher(), std::move(endpoints.server), device_);
+    fidl_.Bind(std::move(endpoints.client));
   }
 
   void TearDown() override {
@@ -868,10 +867,9 @@
 
   async::Loop loop{&kAsyncLoopConfigNeverAttachToThread};
   std::shared_ptr<MockDevice> root = MockDevice::FakeRootParent();
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_usb_hci::UsbHci>();
-  ASSERT_OK(endpoints);
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_usb_hci::UsbHci>::Create();
   auto device = fbl::MakeRefCounted<UsbDevice>(root.get(), ddk::UsbHciProtocolClient(hci.proto()),
-                                               std::move(endpoints->client), kDeviceId, kHubId,
+                                               std::move(endpoints.client), kDeviceId, kHubId,
                                                kDeviceSpeed, timer, loop.dispatcher());
   auto result = device->Init(loop.dispatcher());
   ASSERT_EQ(result, ZX_ERR_IO);
diff --git a/src/devices/usb/drivers/xhci/usb-xhci-test.cc b/src/devices/usb/drivers/xhci/usb-xhci-test.cc
index 1415bd34..fbb9938e 100644
--- a/src/devices/usb/drivers/xhci/usb-xhci-test.cc
+++ b/src/devices/usb/drivers/xhci/usb-xhci-test.cc
@@ -434,10 +434,9 @@
     fake_device_.set_irq_signaller(config.irqs[0].borrow());
     config.use_fake_bti = true;
 
-    zx::result outgoing_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(outgoing_endpoints);
+    auto outgoing_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     ASSERT_OK(incoming_loop_.StartThread("incoming-ns-thread"));
-    incoming_.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints->server)](
+    incoming_.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints.server)](
                            IncomingNamespace* infra) mutable {
       infra->pdev_server.SetConfig(std::move(config));
       ASSERT_OK(infra->outgoing.AddService<fuchsia_hardware_platform_device::Service>(
@@ -447,7 +446,7 @@
     });
     ASSERT_NO_FATAL_FAILURE();
     root_->AddFidlService(fuchsia_hardware_platform_device::Service::Name,
-                          std::move(outgoing_endpoints->client));
+                          std::move(outgoing_endpoints.client));
 
     auto dev =
         std::make_unique<UsbXhci>(root_.get(), ddk_fake::CreateBufferFactory(), loop_.dispatcher());
diff --git a/src/devices/usb/drivers/xhci/xhci-endpoint-test.cc b/src/devices/usb/drivers/xhci/xhci-endpoint-test.cc
index 98f4bb3..279f809 100644
--- a/src/devices/usb/drivers/xhci/xhci-endpoint-test.cc
+++ b/src/devices/usb/drivers/xhci/xhci-endpoint-test.cc
@@ -45,10 +45,9 @@
     EXPECT_OK(ep_->Init(nullptr, nullptr));
 
     // Connect client
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_usb_endpoint::Endpoint>();
-    ASSERT_TRUE(endpoints.is_ok());
-    ep_->Connect(ep_->dispatcher(), std::move(endpoints->server));
-    client_.Bind(std::move(endpoints->client), loop_.dispatcher(),
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_usb_endpoint::Endpoint>::Create();
+    ep_->Connect(ep_->dispatcher(), std::move(endpoints.server));
+    client_.Bind(std::move(endpoints.client), loop_.dispatcher(),
                  fidl::ObserveTeardown([&]() { sync_completion_signal(&client_unbound_); }));
   }
 
diff --git a/src/devices/usb/lib/usb-endpoint/tests/usb-endpoint-client-test.cc b/src/devices/usb/lib/usb-endpoint/tests/usb-endpoint-client-test.cc
index 3e35b06..7821101 100644
--- a/src/devices/usb/lib/usb-endpoint/tests/usb-endpoint-client-test.cc
+++ b/src/devices/usb/lib/usb-endpoint/tests/usb-endpoint-client-test.cc
@@ -61,14 +61,13 @@
     client_ = std::make_unique<usb_endpoint::UsbEndpoint<UsbEndpointClientTest>>(
         usb::EndpointType::BULK, this, std::mem_fn(&UsbEndpointClientTest::Complete));
 
-    auto endpoints = fidl::CreateEndpoints<UsbProtocolType>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<UsbProtocolType>::Create();
     server_ =
-        std::make_unique<FakeUsbServer>(server_loop_.dispatcher(), std::move(endpoints->server));
+        std::make_unique<FakeUsbServer>(server_loop_.dispatcher(), std::move(endpoints.server));
     ASSERT_NOT_NULL(server_);
 
     server_->ExpectConnectToEndpoint(kEpAddr);
-    EXPECT_OK(client_->Init(kEpAddr, endpoints->client, client_loop_.dispatcher()));
+    EXPECT_OK(client_->Init(kEpAddr, endpoints.client, client_loop_.dispatcher()));
   }
 
   void TearDown() override {
diff --git a/src/devices/usb/lib/usb-endpoint/tests/usb-endpoint-server-test.cc b/src/devices/usb/lib/usb-endpoint/tests/usb-endpoint-server-test.cc
index e80414f..d9f8794 100644
--- a/src/devices/usb/lib/usb-endpoint/tests/usb-endpoint-server-test.cc
+++ b/src/devices/usb/lib/usb-endpoint/tests/usb-endpoint-server-test.cc
@@ -48,11 +48,10 @@
     client_loop_.StartThread("client-loop");
     ASSERT_OK(fake_bti_create(fake_bti_.reset_and_get_address()));
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_usb_endpoint::Endpoint>();
-    ASSERT_TRUE(endpoints.is_ok());
-    ep_ = std::make_unique<FakeEndpoint>(fake_bti_, 0, std::move(endpoints->server));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_usb_endpoint::Endpoint>::Create();
+    ep_ = std::make_unique<FakeEndpoint>(fake_bti_, 0, std::move(endpoints.server));
 
-    client_.Bind(std::move(endpoints->client), client_loop_.dispatcher(), &event_handler_);
+    client_.Bind(std::move(endpoints.client), client_loop_.dispatcher(), &event_handler_);
   }
 
   void VerifyRegisteredVmos(size_t count) {
diff --git a/src/devices/usb/lib/usb-phy/tests/usb-phy-test.cc b/src/devices/usb/lib/usb-phy/tests/usb-phy-test.cc
index 7154dad..7c372d1 100644
--- a/src/devices/usb/lib/usb-phy/tests/usb-phy-test.cc
+++ b/src/devices/usb/lib/usb-phy/tests/usb-phy-test.cc
@@ -111,29 +111,26 @@
 class UsbPhyFidlTest : public UsbPhyTest<FakeUsbPhyFidlServer> {
  public:
   void SetUpAsFragment() {
-    auto io_eps = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(io_eps);
+    auto io_eps = fidl::Endpoints<fuchsia_io::Directory>::Create();
     incoming_.SyncCall([&](IncomingNamespace* ns) {
       ASSERT_OK(ns->outgoing.AddService<fuchsia_hardware_usb_phy::Service>(
                     ns->fake_phy_server_.GetInstanceHandler()),
                 "phy");
-      ASSERT_OK(ns->outgoing.Serve(std::move(io_eps->server)));
+      ASSERT_OK(ns->outgoing.Serve(std::move(io_eps.server)));
     });
-    root_->AddFidlService(fuchsia_hardware_usb_phy::Service::Name, std::move(io_eps->client),
-                          "phy");
+    root_->AddFidlService(fuchsia_hardware_usb_phy::Service::Name, std::move(io_eps.client), "phy");
 
     GetClient("phy");
   }
 
   void SetUpAsParent() {
-    auto io_eps = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(io_eps);
+    auto io_eps = fidl::Endpoints<fuchsia_io::Directory>::Create();
     incoming_.SyncCall([&](IncomingNamespace* ns) {
       ASSERT_OK(ns->outgoing.AddService<fuchsia_hardware_usb_phy::Service>(
           ns->fake_phy_server_.GetInstanceHandler()));
-      ASSERT_OK(ns->outgoing.Serve(std::move(io_eps->server)));
+      ASSERT_OK(ns->outgoing.Serve(std::move(io_eps.server)));
     });
-    root_->AddFidlService(fuchsia_hardware_usb_phy::Service::Name, std::move(io_eps->client));
+    root_->AddFidlService(fuchsia_hardware_usb_phy::Service::Name, std::move(io_eps.client));
 
     GetClient();
   }
diff --git a/src/devices/usb/lib/usb/BUILD.gn b/src/devices/usb/lib/usb/BUILD.gn
index c4d2d57..ab8192a 100644
--- a/src/devices/usb/lib/usb/BUILD.gn
+++ b/src/devices/usb/lib/usb/BUILD.gn
@@ -19,7 +19,7 @@
   ]
   sources = [
     "align.h",
-    "usb-request.c",
+    "usb-request.cc",
     "usb-wrapper.cc",
     "usb.c",
   ]
@@ -45,6 +45,46 @@
   public_configs = [ ":includes" ]
 }
 
+config("enable_dfv2_compat_logging") {
+  defines = [ "DFV2_COMPAT_LOGGING" ]
+}
+
+source_set("usb-dfv2-compat-logging") {
+  public = [
+    "include/usb/request-cpp.h",
+    "include/usb/usb-request.h",
+    "include/usb/usb.h",
+  ]
+  sources = [
+    "align.h",
+    "usb-request.cc",
+    "usb-wrapper.cc",
+    "usb.c",
+  ]
+  public_deps = [
+    "//sdk/banjo/fuchsia.hardware.usb:fuchsia.hardware.usb_banjo_cpp",
+    "//sdk/banjo/fuchsia.hardware.usb.composite:fuchsia.hardware.usb.composite_banjo_cpp",
+
+    # <ddk/usb/usb.h> has #include <fuchsia/hardware/usb/c/banjo.h>.
+    "//src/lib/ddk",
+
+    # <usb/request-cpp.h> has  #include <lib/operation/operation.h>.
+    "//sdk/lib/fit",
+    "//src/devices/lib/dev-operation",
+  ]
+  deps = [
+    "//sdk/banjo/ddk.hw.physiter:ddk.hw.physiter_banjo_cpp",
+    "//sdk/banjo/fuchsia.hardware.usb:fuchsia.hardware.usb_banjo_cpp",
+    "//sdk/banjo/fuchsia.hardware.usb.composite:fuchsia.hardware.usb.composite_banjo_cpp",
+    "//sdk/banjo/fuchsia.hardware.usb.request:fuchsia.hardware.usb.request_banjo_cpp",
+    "//sdk/lib/driver/compat/cpp:logging",
+    "//src/lib/ddk",
+    "//src/lib/ddktl",
+  ]
+  public_configs = [ ":includes" ]
+  configs += [ ":enable_dfv2_compat_logging" ]
+}
+
 source_set("usb-fidl") {
   public = [ "include/usb/request-fidl.h" ]
   sources = [
diff --git a/src/devices/usb/lib/usb/usb-request.c b/src/devices/usb/lib/usb/usb-request.cc
similarity index 94%
rename from src/devices/usb/lib/usb/usb-request.c
rename to src/devices/usb/lib/usb/usb-request.cc
index c439cad..2d6e020 100644
--- a/src/devices/usb/lib/usb/usb-request.c
+++ b/src/devices/usb/lib/usb/usb-request.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <fuchsia/hardware/usb/c/banjo.h>
-#include <lib/ddk/debug.h>
 #include <lib/ddk/phys-iter.h>
 #include <lib/trace/event.h>
 #include <stdint.h>
@@ -20,6 +19,12 @@
 
 #include "src/devices/usb/lib/usb/align.h"
 
+#ifdef DFV2_COMPAT_LOGGING
+#include <lib/driver/compat/cpp/logging.h>  // nogncheck
+#else
+#include <lib/ddk/debug.h>  // nogncheck
+#endif
+
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 
 static inline size_t req_buffer_size(usb_request_t* req, size_t offset) {
@@ -70,7 +75,7 @@
   if (req_size < sizeof(usb_request_t)) {
     return ZX_ERR_INVALID_ARGS;
   }
-  usb_request_t* req = calloc(1, req_size);
+  usb_request_t* req = static_cast<usb_request_t*>(calloc(1, req_size));
   if (!req) {
     return ZX_ERR_NO_MEMORY;
   }
@@ -109,7 +114,7 @@
 __EXPORT zx_status_t usb_request_alloc_vmo(usb_request_t** out, zx_handle_t vmo_handle,
                                            uint64_t vmo_offset, uint64_t length, uint8_t ep_address,
                                            size_t req_size) {
-  usb_request_t* req = calloc(1, req_size);
+  usb_request_t* req = static_cast<usb_request_t*>(calloc(1, req_size));
   if (!req) {
     return ZX_ERR_NO_MEMORY;
   }
@@ -219,7 +224,7 @@
     total_length += entry->length;
   }
   size_t num_bytes = sg_count * sizeof(sg_entry_t);
-  req->sg_list = malloc(num_bytes);
+  req->sg_list = static_cast<sg_entry_t*>(malloc(num_bytes));
   if (req->sg_list == NULL) {
     zxlogf(ERROR, "usb_request_set_sg_list: out of memory");
     return ZX_ERR_NO_MEMORY;
@@ -233,14 +238,14 @@
 __EXPORT ssize_t usb_request_copy_from(usb_request_t* req, void* data, size_t length,
                                        size_t offset) {
   length = MIN(req_buffer_size(req, offset), length);
-  memcpy(data, req_buffer_virt(req) + offset, length);
+  memcpy(data, static_cast<uint8_t*>(req_buffer_virt(req)) + offset, length);
   return length;
 }
 
 __EXPORT ssize_t usb_request_copy_to(usb_request_t* req, const void* data, size_t length,
                                      size_t offset) {
   length = MIN(req_buffer_size(req, offset), length);
-  memcpy(req_buffer_virt(req) + offset, data, length);
+  memcpy(static_cast<uint8_t*>(req_buffer_virt(req)) + offset, data, length);
   return length;
 }
 
@@ -254,7 +259,8 @@
   if (offset + length < offset || offset + length > req->size) {
     return ZX_ERR_OUT_OF_RANGE;
   }
-  return zx_cache_flush(req_buffer_virt(req) + offset, length, ZX_CACHE_FLUSH_DATA);
+  return zx_cache_flush(static_cast<uint8_t*>(req_buffer_virt(req)) + offset, length,
+                        ZX_CACHE_FLUSH_DATA);
 }
 
 __EXPORT zx_status_t usb_request_cache_flush_invalidate(usb_request_t* req, zx_off_t offset,
@@ -262,7 +268,7 @@
   if (offset + length < offset || offset + length > req->size) {
     return ZX_ERR_OUT_OF_RANGE;
   }
-  return zx_cache_flush(req_buffer_virt(req) + offset, length,
+  return zx_cache_flush(static_cast<uint8_t*>(req_buffer_virt(req)) + offset, length,
                         ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INVALIDATE);
 }
 
@@ -278,7 +284,7 @@
   uint64_t page_length = req->size - page_offset;
   uint64_t pages = USB_ROUNDUP(page_length, kPageSize) / kPageSize;
 
-  zx_paddr_t* paddrs = malloc(pages * sizeof(zx_paddr_t));
+  zx_paddr_t* paddrs = static_cast<zx_paddr_t*>(malloc(pages * sizeof(zx_paddr_t)));
   if (paddrs == NULL) {
     zxlogf(ERROR, "usb_request_physmap: out of memory");
     return ZX_ERR_NO_MEMORY;
@@ -391,10 +397,10 @@
 }
 
 __EXPORT void usb_request_phys_iter_init(phys_iter_t* iter, usb_request_t* req, size_t max_length) {
-  phys_iter_buffer_t buf = {.length = req->header.length,
-                            .vmo_offset = req->offset,
-                            .phys = req->phys_list,
+  phys_iter_buffer_t buf = {.phys = req->phys_list,
                             .phys_count = req->phys_count,
+                            .length = req->header.length,
+                            .vmo_offset = req->offset,
                             .sg_list = (phys_iter_sg_entry_t*)(req->sg_list),
                             .sg_count = req->sg_count};
   phys_iter_init(iter, &buf, max_length);
diff --git a/src/diagnostics/archivist/BUILD.gn b/src/diagnostics/archivist/BUILD.gn
index d601b2a..7878d60 100644
--- a/src/diagnostics/archivist/BUILD.gn
+++ b/src/diagnostics/archivist/BUILD.gn
@@ -73,7 +73,6 @@
     "//third_party/rust_crates:futures",
     "//third_party/rust_crates:lazy_static",
     "//third_party/rust_crates:pin-project",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:serde",
     "//third_party/rust_crates:serde_cbor",
     "//third_party/rust_crates:serde_json",
diff --git a/src/diagnostics/archivist/src/archivist.rs b/src/diagnostics/archivist/src/archivist.rs
index 02b164fe..7ec73c1 100644
--- a/src/diagnostics/archivist/src/archivist.rs
+++ b/src/diagnostics/archivist/src/archivist.rs
@@ -260,7 +260,11 @@
     /// Run archivist to completion.
     /// # Arguments:
     /// * `outgoing_channel`- channel to serve outgoing directory on.
-    pub async fn run(mut self, mut fs: ServiceFs<ServiceObj<'static, ()>>) -> Result<(), Error> {
+    pub async fn run(
+        mut self,
+        mut fs: ServiceFs<ServiceObj<'static, ()>>,
+        is_embedded: bool,
+    ) -> Result<(), Error> {
         debug!("Running Archivist.");
 
         // Start servicing all outgoing services.
@@ -305,9 +309,7 @@
             Some(stop_recv) => async move {
                 stop_recv.into_future().await.ok();
                 terminate_handle.terminate().await;
-                for task in incoming_external_event_producers {
-                    task.cancel().await;
-                }
+                std::mem::drop(incoming_external_event_producers);
                 inspect_sink_server.stop();
                 log_server.stop();
                 accessor_server.stop();
@@ -322,7 +324,12 @@
         // should remain alive.
         let _logs_repo = self.logs_repository;
 
-        info!("archivist: Entering core loop.");
+        if is_embedded {
+            debug!("Entering core loop.");
+        } else {
+            info!("archivist: Entering core loop.");
+        }
+
         // Combine all three futures into a main future.
         future::join3(abortable_fut, stop_fut, all_msg).map(|_| Ok(())).await
     }
@@ -489,7 +496,7 @@
         archivist.set_lifecycle_request_stream(request_stream);
         let (signal_send, signal_recv) = oneshot::channel();
         fasync::Task::spawn(async move {
-            archivist.run(fs).await.expect("Cannot run archivist");
+            archivist.run(fs, false).await.expect("Cannot run archivist");
             signal_send.send(()).unwrap();
         })
         .detach();
@@ -503,7 +510,7 @@
         fs.serve_connection(server_end).unwrap();
         let archivist = init_archivist(&mut fs).await;
         fasync::Task::spawn(async move {
-            archivist.run(fs).await.expect("Cannot run archivist");
+            archivist.run(fs, false).await.expect("Cannot run archivist");
         })
         .detach();
         directory
diff --git a/src/diagnostics/archivist/src/inspect/collector.rs b/src/diagnostics/archivist/src/inspect/collector.rs
index 36c64c9..2fccf96 100644
--- a/src/diagnostics/archivist/src/inspect/collector.rs
+++ b/src/diagnostics/archivist/src/inspect/collector.rs
@@ -10,8 +10,7 @@
     fidl_fuchsia_inspect_deprecated::{InspectMarker, InspectProxy},
     fidl_fuchsia_io as fio, fuchsia_zircon as zx,
     futures::stream::StreamExt,
-    pin_utils::pin_mut,
-    std::collections::HashMap,
+    std::{collections::HashMap, pin::pin},
     tracing::error,
 };
 
@@ -74,15 +73,15 @@
 async fn populate_data_map_from_dir(inspect_proxy: &fio::DirectoryProxy) -> DataMap {
     // TODO(https://fxbug.dev/42112326): Use a streaming and bounded readdir API when available to avoid
     // being hung.
-    let entries = fuchsia_fs::directory::readdir_recursive(inspect_proxy, /* timeout= */ None)
-        .filter_map(|result| {
-            async move {
-                // TODO(https://fxbug.dev/42126094): decide how to show directories that we failed to read.
-                result.ok()
-            }
-        });
+    let mut entries =
+        pin!(fuchsia_fs::directory::readdir_recursive(inspect_proxy, /* timeout= */ None)
+            .filter_map(|result| {
+                async move {
+                    // TODO(https://fxbug.dev/42126094): decide how to show directories that we failed to read.
+                    result.ok()
+                }
+            }));
     let mut data_map = DataMap::new();
-    pin_mut!(entries);
     // TODO(https://fxbug.dev/42138410) convert this async loop to a stream so we can carry backpressure
     while let Some(entry) = entries.next().await {
         // We are only currently interested in inspect VMO files (root.inspect) and
diff --git a/src/diagnostics/archivist/src/logs/listener.rs b/src/diagnostics/archivist/src/logs/listener.rs
index 5bf5369..2c0cca4 100644
--- a/src/diagnostics/archivist/src/logs/listener.rs
+++ b/src/diagnostics/archivist/src/logs/listener.rs
@@ -114,11 +114,10 @@
         self.status == Status::Fine
     }
 
-    async fn send_new_logs<S>(&mut self, logs: S)
+    async fn send_new_logs<S>(&mut self, mut logs: S)
     where
         S: Stream<Item = Arc<LogsData>> + Unpin,
     {
-        pin_utils::pin_mut!(logs);
         while let Some(message) = logs.next().await {
             self.send_log(&message).await;
             if !self.is_healthy() {
diff --git a/src/diagnostics/archivist/src/main.rs b/src/diagnostics/archivist/src/main.rs
index 494cf54..27a3f2e 100644
--- a/src/diagnostics/archivist/src/main.rs
+++ b/src/diagnostics/archivist/src/main.rs
@@ -49,6 +49,7 @@
         .root()
         .record_child("config", |config_node| config.record_inspect(config_node));
 
+    let is_embedded = !config.log_to_debuglog;
     let mut archivist = Archivist::new(config).await;
     archivist.set_lifecycle_request_stream(component_lifecycle::take_lifecycle_request_stream());
     debug!("Archivist initialized from configuration.");
@@ -59,7 +60,7 @@
 
     let mut fs = ServiceFs::new();
     fs.serve_connection(fidl::endpoints::ServerEnd::new(zx::Channel::from(startup_handle)))?;
-    archivist.run(fs).await?;
+    archivist.run(fs, is_embedded).await?;
 
     Ok(())
 }
@@ -84,7 +85,7 @@
     }
 
     if config.log_to_debuglog {
-        info!("Logging started.");
+        info!("archivist: started.");
     }
 
     component::init_inspector_with_size(INSPECTOR_SIZE);
diff --git a/src/diagnostics/archivist/testing/realm-factory/fuchsia_configured_component.gni b/src/diagnostics/archivist/testing/realm-factory/fuchsia_configured_component.gni
deleted file mode 100644
index 7290544..0000000
--- a/src/diagnostics/archivist/testing/realm-factory/fuchsia_configured_component.gni
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2023 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/components.gni")
-
-# Same as fuchsia_component but accepts structured config values and
-# and doesn't require separate fuchsia_component_manifest target.
-#
-# Parameters
-#
-#    config_values
-#      Structured configuration values.
-#
-# Other parameters are the same as fuchsia_component.
-template("fuchsia_configured_component") {
-  component_manifest_target = "${target_name}_manifest"
-  fuchsia_component_manifest(component_manifest_target) {
-    forward_variables_from(invoker,
-                           [
-                             "testonly",
-                             "component_name",
-                             "manifest",
-                           ])
-  }
-
-  component_target = "${target_name}_component"
-  fuchsia_component(component_target) {
-    forward_variables_from(invoker,
-                           "*",
-                           [
-                             "values",
-                             "config_values",
-                             "cm_label",
-                             "manifest",
-                           ])
-    cm_label = ":$component_manifest_target"
-  }
-
-  component_config_target = "${target_name}_config"
-  fuchsia_structured_config_values(component_config_target) {
-    forward_variables_from(invoker, [ "testonly" ])
-    cm_label = ":$component_manifest_target"
-    values = invoker.config_values
-  }
-
-  group(target_name) {
-    forward_variables_from(invoker, [ "testonly" ])
-    deps = [
-      ":$component_config_target",
-      ":$component_target",
-    ]
-  }
-}
diff --git a/src/diagnostics/archivist/tests/integration/BUILD.gn b/src/diagnostics/archivist/tests/integration/BUILD.gn
index 3088988..1f78a04 100644
--- a/src/diagnostics/archivist/tests/integration/BUILD.gn
+++ b/src/diagnostics/archivist/tests/integration/BUILD.gn
@@ -7,98 +7,20 @@
 import("//build/rust/rustc_test.gni")
 import("//src/diagnostics/archivist/build/pipeline.gni")
 
-rustc_test("integration_tests_bin") {
-  output_name = "archivist_integration_tests"
-  edition = "2021"
-  deps = [
-    "components/fidl:fidl_rust",
-    "//sdk/fidl/fuchsia.component:fuchsia.component_rust",
-    "//sdk/fidl/fuchsia.component.decl:fuchsia.component.decl_rust",
-    "//sdk/fidl/fuchsia.diagnostics:fuchsia.diagnostics_rust",
-    "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
-    "//sdk/fidl/fuchsia.logger:fuchsia.logger_rust",
-    "//sdk/fidl/fuchsia.testing.harness:fuchsia.testing.harness_rust",
-    "//src/diagnostics/archivist:lib",
-    "//src/diagnostics/archivist/testing/fidl:fuchsia.archivist.test_rust",
-    "//src/lib/diagnostics/data/rust",
-    "//src/lib/diagnostics/log/message/rust",
-    "//src/lib/diagnostics/log/rust",
-    "//src/lib/diagnostics/reader/rust",
-    "//src/lib/diagnostics/selectors",
-    "//src/lib/diagnostics/testing/diagnostics-assertions/rust:diagnostics-assertions",
-    "//src/lib/fidl/rust/fidl",
-    "//src/lib/fuchsia",
-    "//src/lib/fuchsia-async",
-    "//src/lib/fuchsia-component",
-    "//src/lib/fuchsia-component-test",
-    "//src/lib/syslog/rust:syslog-listener",
-    "//src/lib/zircon/rust:fuchsia-zircon",
-    "//src/sys/lib/cm_rust",
-    "//src/sys/lib/cm_types",
-    "//src/sys/lib/component-events",
-    "//src/testing/realm_proxy/client",
-    "//third_party/rust_crates:anyhow",
-    "//third_party/rust_crates:async-trait",
-    "//third_party/rust_crates:difference",
-    "//third_party/rust_crates:futures",
-    "//third_party/rust_crates:itertools",
-    "//third_party/rust_crates:lazy_static",
-    "//third_party/rust_crates:rand",
-    "//third_party/rust_crates:serde_json",
-    "//third_party/rust_crates:tracing",
-  ]
-
-  sources = [
-    "src/assert.rs",
-    "src/constants.rs",
-    "src/inspect/mod.rs",
-    "src/inspect/reader.rs",
-    "src/inspect/recursive_glob.rs",
-    "src/inspect/truncation.rs",
-    "src/lib.rs",
-    "src/logs/attribution.rs",
-    "src/logs/basic.rs",
-    "src/logs/budget.rs",
-    "src/logs/crash.rs",
-    "src/logs/interest.rs",
-    "src/logs/lifecycle.rs",
-    "src/logs/lifecycle_stop.rs",
-    "src/logs/mod.rs",
-    "src/logs/selectors.rs",
-    "src/logs/sorting.rs",
-    "src/logs/utils.rs",
-    "src/puppet.rs",
-    "src/test_topology.rs",
-    "src/utils.rs",
-  ]
-  inputs = [
-    "test_data/empty_result_golden.json",
-    "test_data/unified_reader_all_golden.json",
-    "test_data/pipeline_reader_all_golden.json",
-    "test_data/unified_reader_full_filter_golden.json",
-    "test_data/pipeline_reader_nonoverlapping_selectors_golden.json",
-    "test_data/unified_reader_single_value_golden.json",
-    "test_data/pipeline_reader_single_value_golden.json",
-  ]
-  configs += [ "//build/config/rust/lints:clippy_warn_all" ]
-}
-
-fuchsia_test_component("archivist_integration_tests") {
-  deps = [ ":integration_tests_bin" ]
-  manifest = "meta/archivist_integration_tests.cml"
+fuchsia_test_component("integration_tests_component") {
+  manifest = "meta/test_root.cml"
   test_type = "system"
 }
 
-fuchsia_test_package("archivist-integration-tests") {
-  test_components = [ ":archivist_integration_tests" ]
-  deps = [
-    "components",
-    "//src/diagnostics/archivist/testing/realm-factory:archivist-component",
+fuchsia_test_package("archivist_integration_tests") {
+  test_components = [ ":integration_tests_component" ]
+  subpackages = [
+    "test_cases:pkg",
+    "realm_factory:pkg",
   ]
-  subpackages = [ "//src/diagnostics/archivist/testing/realm-factory" ]
 }
 
 group("tests") {
   testonly = true
-  deps = [ ":archivist-integration-tests" ]
+  deps = [ ":archivist_integration_tests" ]
 }
diff --git a/src/diagnostics/archivist/tests/integration/components/BUILD.gn b/src/diagnostics/archivist/tests/integration/components/BUILD.gn
deleted file mode 100644
index d4f20ba..0000000
--- a/src/diagnostics/archivist/tests/integration/components/BUILD.gn
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright 2021 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/components.gni")
-import("//build/rust/rustc_binary.gni")
-
-rustc_binary("stub_inspect_component_bin") {
-  testonly = true
-  output_name = "stub_inspect_component"
-  edition = "2021"
-  source_root = "src/stub_inspect_component.rs"
-  deps = [
-    "//src/lib/diagnostics/inspect/runtime/rust",
-    "//src/lib/diagnostics/inspect/rust",
-    "//src/lib/fuchsia",
-    "//third_party/rust_crates:tracing",
-  ]
-
-  sources = [ "src/stub_inspect_component.rs" ]
-  configs += [ "//build/config/rust/lints:clippy_warn_all" ]
-}
-
-rustc_binary("log_and_exit_component_bin") {
-  testonly = true
-  output_name = "log_and_exit"
-  edition = "2021"
-  source_root = "src/log_and_exit.rs"
-  deps = [
-    "//src/lib/fuchsia",
-    "//third_party/rust_crates:tracing",
-  ]
-
-  sources = [ "src/log_and_exit.rs" ]
-  configs += [ "//build/config/rust/lints:clippy_warn_all" ]
-}
-
-rustc_binary("log_on_interest_bin") {
-  testonly = true
-  output_name = "log_on_interest"
-  edition = "2021"
-  source_root = "src/log_on_interest.rs"
-  deps = [
-    "//sdk/fidl/fuchsia.diagnostics:fuchsia.diagnostics_rust",
-    "//src/lib/diagnostics/log/rust",
-    "//src/lib/fuchsia",
-    "//src/lib/fuchsia-component",
-    "//third_party/rust_crates:anyhow",
-    "//third_party/rust_crates:futures",
-    "//third_party/rust_crates:tracing",
-  ]
-
-  sources = [ "src/log_on_interest.rs" ]
-  configs += [ "//build/config/rust/lints:clippy_warn_all" ]
-}
-
-fuchsia_component("stub_inspect_component") {
-  testonly = true
-  deps = [ ":stub_inspect_component_bin" ]
-  manifest = "meta/stub_inspect_component.cml"
-}
-
-fuchsia_component("component_with_children") {
-  testonly = true
-  deps = [ ":stub_inspect_component_bin" ]
-  manifest = "meta/component_with_children.cml"
-}
-
-fuchsia_component("log_and_exit_component") {
-  testonly = true
-  component_name = "log-and-exit"
-  deps = [ ":log_and_exit_component_bin" ]
-  manifest = "meta/log-and-exit.cml"
-}
-
-fuchsia_component("log_on_interest_component") {
-  component_name = "log-on-interest"
-  testonly = true
-  deps = [ ":log_on_interest_bin" ]
-  manifest = "meta/log-on-interest.cml"
-}
-
-rustc_binary("socket_puppet_bin") {
-  edition = "2021"
-  testonly = true
-  name = "socket_puppet"
-  source_root = "src/socket_puppet.rs"
-
-  deps = [
-    "fidl:fidl_rust",
-    "//sdk/fidl/fuchsia.logger:fuchsia.logger_rust",
-    "//src/lib/fidl/rust/fidl",
-    "//src/lib/fuchsia-async",
-    "//src/lib/fuchsia-component",
-    "//src/lib/zircon/rust:fuchsia-zircon",
-    "//third_party/rust_crates:futures",
-  ]
-
-  sources = [ "src/socket_puppet.rs" ]
-  configs += [ "//build/config/rust/lints:clippy_warn_all" ]
-}
-
-fuchsia_component("socket-puppet") {
-  testonly = true
-  manifest = "meta/socket-puppet.cml"
-  deps = [ ":socket_puppet_bin" ]
-}
-
-group("components") {
-  testonly = true
-  deps = [
-    ":component_with_children",
-    ":log_and_exit_component",
-    ":log_on_interest_component",
-    ":socket-puppet",
-    ":stub_inspect_component",
-  ]
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/fidl/BUILD.gn b/src/diagnostics/archivist/tests/integration/components/fidl/BUILD.gn
deleted file mode 100644
index 74db635..0000000
--- a/src/diagnostics/archivist/tests/integration/components/fidl/BUILD.gn
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2021 The Fuchsia Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/fidl/fidl.gni")
-
-fidl("fidl") {
-  testonly = true
-  name = "fuchsia.archivist.tests"
-  sources = [
-    "socket_puppet.test.fidl",
-    "stdio_puppet.test.fidl",
-  ]
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/fidl/socket_puppet.test.fidl b/src/diagnostics/archivist/tests/integration/components/fidl/socket_puppet.test.fidl
deleted file mode 100644
index 0ea92d2..0000000
--- a/src/diagnostics/archivist/tests/integration/components/fidl/socket_puppet.test.fidl
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-library fuchsia.archivist.tests;
-
-@discoverable
-closed protocol SocketPuppetController {
-    /// Send a puppet client to the controller. This channel is closed after this call.
-    strict ControlPuppet(resource struct {
-        to_control client_end:SocketPuppet;
-    });
-};
-
-closed protocol SocketPuppet {
-    strict ConnectToLogSink() -> ();
-    strict EmitPacket(struct {
-        packet vector<uint8>:32768;
-    }) -> ();
-};
diff --git a/src/diagnostics/archivist/tests/integration/components/fidl/stdio_puppet.test.fidl b/src/diagnostics/archivist/tests/integration/components/fidl/stdio_puppet.test.fidl
deleted file mode 100644
index 4b95122..0000000
--- a/src/diagnostics/archivist/tests/integration/components/fidl/stdio_puppet.test.fidl
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-library fuchsia.archivist.tests;
-
-/// `StdioPuppet` is a test interface through which a test controller commands
-/// a puppet to write logs to stdio. This allows the controller to verify stdio
-/// piping.
-@discoverable
-closed protocol StdioPuppet {
-    /// Writes |line| to stdout, appending a newline character.
-    strict WritelnStdout(struct {
-        line string:1024;
-    });
-
-    /// Writes |line| to stderr, appending a newline character.
-    strict WritelnStderr(struct {
-        line string:1024;
-    });
-};
diff --git a/src/diagnostics/archivist/tests/integration/components/meta/component_with_children.cml b/src/diagnostics/archivist/tests/integration/components/meta/component_with_children.cml
deleted file mode 100644
index 7199988..0000000
--- a/src/diagnostics/archivist/tests/integration/components/meta/component_with_children.cml
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    include: [
-        "inspect/client.shard.cml",
-        "syslog/client.shard.cml",
-    ],
-    program: {
-        runner: "elf",
-        binary: "bin/stub_inspect_component",
-    },
-    children: [
-        {
-            name: "stub_inspect_1",
-            url: "fuchsia-pkg://fuchsia.com/archivist-integration-tests#meta/stub_inspect_component.cm",
-            startup: "eager",
-        },
-        {
-            name: "stub_inspect_2",
-            url: "fuchsia-pkg://fuchsia.com/archivist-integration-tests#meta/stub_inspect_component.cm",
-            startup: "eager",
-        },
-    ],
-    offer: [
-        {
-            protocol: "fuchsia.logger.LogSink",
-            from: "parent",
-            to: [
-                "#stub_inspect_1",
-                "#stub_inspect_2",
-            ],
-        },
-    ],
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/meta/log-and-exit.cml b/src/diagnostics/archivist/tests/integration/components/meta/log-and-exit.cml
deleted file mode 100644
index 7648e89..0000000
--- a/src/diagnostics/archivist/tests/integration/components/meta/log-and-exit.cml
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    include: [ "syslog/client.shard.cml" ],
-    program: {
-        runner: "elf",
-        binary: "bin/log_and_exit",
-    },
-    expose: [
-        {
-            protocol: "fuchsia.component.Binder",
-            from: "framework",
-        },
-    ],
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/meta/log-on-interest.cml b/src/diagnostics/archivist/tests/integration/components/meta/log-on-interest.cml
deleted file mode 100644
index 3c7a801..0000000
--- a/src/diagnostics/archivist/tests/integration/components/meta/log-on-interest.cml
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    include: [ "syslog/client.shard.cml" ],
-    program: {
-        runner: "elf",
-        binary: "bin/log_on_interest",
-    },
-    expose: [
-        {
-            protocol: "fuchsia.component.Binder",
-            from: "framework",
-        },
-    ],
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/meta/socket-puppet.cml b/src/diagnostics/archivist/tests/integration/components/meta/socket-puppet.cml
deleted file mode 100644
index e09e8aa..0000000
--- a/src/diagnostics/archivist/tests/integration/components/meta/socket-puppet.cml
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    include: [ "syslog/client.shard.cml" ],
-    program: {
-        runner: "elf",
-        binary: "bin/socket_puppet",
-    },
-    use: [
-        { protocol: "fuchsia.archivist.tests.SocketPuppetController" },
-    ],
-    expose: [
-        {
-            protocol: "fuchsia.component.Binder",
-            from: "framework",
-        },
-    ],
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/meta/stub_inspect_component.cml b/src/diagnostics/archivist/tests/integration/components/meta/stub_inspect_component.cml
deleted file mode 100644
index 8bbd64fb..0000000
--- a/src/diagnostics/archivist/tests/integration/components/meta/stub_inspect_component.cml
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    include: [
-        "inspect/client.shard.cml",
-        "syslog/client.shard.cml",
-    ],
-    program: {
-        runner: "elf",
-        binary: "bin/stub_inspect_component",
-    },
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/src/log_and_exit.rs b/src/diagnostics/archivist/tests/integration/components/src/log_and_exit.rs
deleted file mode 100644
index e636b7c..0000000
--- a/src/diagnostics/archivist/tests/integration/components/src/log_and_exit.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#[fuchsia::main]
-async fn main() {
-    tracing::debug!("debugging world");
-    tracing::info!("Hello, world!");
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/src/log_on_interest.rs b/src/diagnostics/archivist/tests/integration/components/src/log_on_interest.rs
deleted file mode 100644
index 2585a0f..0000000
--- a/src/diagnostics/archivist/tests/integration/components/src/log_on_interest.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use anyhow::Error;
-use diagnostics_log::{OnInterestChanged, PublishOptions, Publisher};
-use fidl_fuchsia_diagnostics::Severity;
-use fuchsia_component::server::ServiceFs;
-use futures::StreamExt;
-use tracing::{debug, error, info, warn};
-
-#[fuchsia::main(logging = false)]
-async fn main() -> Result<(), Error> {
-    diagnostics_log::initialize(PublishOptions::default().wait_for_initial_interest(false))
-        .expect("initialized tracing");
-    let mut fs = ServiceFs::new();
-    tracing::dispatcher::get_default(|dispatcher| {
-        let publisher: &Publisher = dispatcher.downcast_ref().unwrap();
-        publisher.set_interest_listener(Listener::new());
-    });
-    fs.take_and_serve_directory_handle()?;
-    fs.collect::<()>().await;
-    Ok(())
-}
-
-struct Listener;
-
-impl Listener {
-    fn new() -> Self {
-        Self {}
-    }
-}
-
-impl OnInterestChanged for Listener {
-    fn on_changed(&self, severity: &Severity) {
-        if *severity <= Severity::Debug {
-            debug!("debug msg");
-        }
-        if *severity <= Severity::Info {
-            info!("info msg");
-        }
-        if *severity <= Severity::Warn {
-            warn!("warn msg");
-        }
-        if *severity <= Severity::Error {
-            error!("error msg");
-        }
-    }
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/src/socket_puppet.rs b/src/diagnostics/archivist/tests/integration/components/src/socket_puppet.rs
deleted file mode 100644
index a41074e..0000000
--- a/src/diagnostics/archivist/tests/integration/components/src/socket_puppet.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use fidl::endpoints::create_request_stream;
-use fidl_fuchsia_archivist_tests::{
-    SocketPuppetControllerMarker, SocketPuppetMarker, SocketPuppetRequest,
-};
-use fidl_fuchsia_logger::LogSinkMarker;
-use fuchsia_component::client::connect_to_protocol;
-use fuchsia_zircon as zx;
-use futures::StreamExt;
-
-#[fuchsia_async::run_singlethreaded]
-async fn main() {
-    let controller = connect_to_protocol::<SocketPuppetControllerMarker>().unwrap();
-    let (client, mut requests) = create_request_stream::<SocketPuppetMarker>().unwrap();
-    controller.control_puppet(client).unwrap();
-
-    let (send, recv) = zx::Socket::create_datagram();
-    let mut recv = Some(recv); // so we can send it to LogSink
-    while let Some(Ok(next)) = requests.next().await {
-        match next {
-            SocketPuppetRequest::ConnectToLogSink { responder } => {
-                connect_to_protocol::<LogSinkMarker>()
-                    .unwrap()
-                    .connect(recv.take().unwrap())
-                    .unwrap();
-                responder.send().unwrap();
-            }
-            SocketPuppetRequest::EmitPacket { packet, responder } => {
-                send.write(&packet).unwrap();
-                responder.send().unwrap();
-            }
-        }
-    }
-}
diff --git a/src/diagnostics/archivist/tests/integration/components/src/stub_inspect_component.rs b/src/diagnostics/archivist/tests/integration/components/src/stub_inspect_component.rs
deleted file mode 100644
index 6ec8ba8..0000000
--- a/src/diagnostics/archivist/tests/integration/components/src/stub_inspect_component.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use fuchsia_inspect::{component, health::Reporter};
-use tracing::info;
-
-#[fuchsia::main]
-async fn main() {
-    component::health().set_ok();
-    info!("This is a syslog message");
-    info!("This is another syslog message");
-    if let Some(inspect_server) =
-        inspect_runtime::publish(component::inspector(), inspect_runtime::PublishOptions::default())
-    {
-        inspect_server.await
-    }
-}
diff --git a/src/diagnostics/archivist/tests/integration/meta/archivist_integration_tests.cml b/src/diagnostics/archivist/tests/integration/meta/archivist_integration_tests.cml
deleted file mode 100644
index 0c3c9c2..0000000
--- a/src/diagnostics/archivist/tests/integration/meta/archivist_integration_tests.cml
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-{
-    include: [
-        "//src/sys/test_runners/rust/default.shard.cml",
-        "//src/testing/realm_proxy/client/meta/realm_proxy.shard.cml",
-        "inspect/client.shard.cml",
-        "sys/component/realm_builder.shard.cml",
-        "syslog/client.shard.cml",
-    ],
-    program: {
-        binary: "bin/archivist_integration_tests",
-    },
-    children: [
-        // TODO(289370551): Move this to a test-root.cml and make this test a sibling.
-        // These tests are being incrementally refactored to use this realm
-        // factory instead of RealmBuilder.
-        {
-            name: "realm_factory",
-            url: "archivist-realm-factory#meta/archivist-realm-factory.cm",
-        },
-    ],
-    use: [
-        {
-            protocol: "fuchsia.archivist.test.RealmFactory",
-            from: "#realm_factory",
-        },
-        {
-            protocol: "fuchsia.sys2.RealmQuery",
-            from: "framework",
-        },
-        {
-            protocol: [ "fuchsia.logger.Log" ],
-        },
-        {
-            event_stream: [
-                "started",
-                "stopped",
-            ],
-            from: "parent",
-        },
-    ],
-    offer: [
-        {
-            protocol: [ "fuchsia.boot.ReadOnlyLog" ],
-            from: "parent",
-            to: [
-                "#realm_builder",
-                "#realm_factory",
-            ],
-        },
-        {
-            protocol: [ "fuchsia.tracing.provider.Registry" ],
-            from: "parent",
-            to: [
-                "#realm_builder",
-                "#realm_factory",
-            ],
-            availability: "optional",
-        },
-        {
-            event_stream: [ "capability_requested" ],
-            from: "parent",
-            to: "#realm_factory",
-        },
-    ],
-}
diff --git a/src/diagnostics/archivist/tests/integration/meta/test_root.cml b/src/diagnostics/archivist/tests/integration/meta/test_root.cml
new file mode 100644
index 0000000..e173df8
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/meta/test_root.cml
@@ -0,0 +1,58 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "//src/testing/realm_proxy/client/meta/realm_proxy.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    children: [
+        {
+            name: "realm_factory",
+            url: "archivist_realm_factory#meta/realm_factory.cm",
+        },
+        {
+            name: "test_cases",
+            url: "archivist_integration_test_cases#meta/test_cases.cm",
+        },
+    ],
+    offer: [
+        {
+            protocol: [ "fuchsia.archivist.test.RealmFactory" ],
+            from: "#realm_factory",
+            to: "#test_cases",
+        },
+        {
+            protocol: [ "fuchsia.boot.ReadOnlyLog" ],
+            from: "parent",
+            to: [ "#realm_factory" ],
+        },
+        {
+            protocol: [ "fuchsia.logger.Log" ],
+            from: "parent",
+            to: [ "#test_cases" ],
+        },
+        {
+            protocol: [ "fuchsia.tracing.provider.Registry" ],
+            from: "parent",
+            to: [ "#realm_factory" ],
+            availability: "optional",
+        },
+        {
+            event_stream: [ "stopped" ],
+            from: "parent",
+            to: [ "#test_cases" ],
+        },
+        {
+            event_stream: [ "capability_requested" ],
+            from: "parent",
+            to: [ "#realm_factory" ],
+        },
+    ],
+    expose: [
+        {
+            protocol: "fuchsia.test.Suite",
+            from: "#test_cases",
+        },
+    ],
+}
diff --git a/src/diagnostics/archivist/testing/realm-factory/BUILD.gn b/src/diagnostics/archivist/tests/integration/realm_factory/BUILD.gn
similarity index 77%
rename from src/diagnostics/archivist/testing/realm-factory/BUILD.gn
rename to src/diagnostics/archivist/tests/integration/realm_factory/BUILD.gn
index 17a40939..9067524 100644
--- a/src/diagnostics/archivist/testing/realm-factory/BUILD.gn
+++ b/src/diagnostics/archivist/tests/integration/realm_factory/BUILD.gn
@@ -5,8 +5,6 @@
 import("//build/components.gni")
 import("//build/rust/rustc_binary.gni")
 import("//src/diagnostics/archivist/configs.gni")
-import(
-    "//src/diagnostics/archivist/testing/realm-factory/fuchsia_configured_component.gni")
 
 rustc_binary("bin") {
   testonly = true
@@ -17,12 +15,12 @@
     "src/realm_factory.rs",
   ]
   deps = [
+    "fidl:fuchsia.archivist.test_rust",
     "//sdk/fidl/fuchsia.boot:fuchsia.boot_rust",
     "//sdk/fidl/fuchsia.diagnostics:fuchsia.diagnostics_rust",
     "//sdk/fidl/fuchsia.inspect:fuchsia.inspect_rust",
     "//sdk/fidl/fuchsia.logger:fuchsia.logger_rust",
     "//sdk/fidl/fuchsia.tracing.provider:fuchsia.tracing.provider_rust",
-    "//src/diagnostics/archivist/testing/fidl:fuchsia.archivist.test_rust",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia",
     "//src/lib/fuchsia-async",
@@ -36,27 +34,39 @@
   ]
 }
 
-fuchsia_component("archivist-realm-factory-component") {
+fuchsia_component("archivist_realm_factory_component") {
   testonly = true
-  component_name = "archivist-realm-factory"
-  manifest = "meta/realm-factory.cml"
+  component_name = "realm_factory"
+  manifest = "meta/realm_factory.cml"
   deps = [ ":bin" ]
 }
 
-fuchsia_configured_component("archivist-component") {
+fuchsia_component_manifest("archivist_manifest") {
   testonly = true
   component_name = "archivist"
   manifest = "meta/archivist.cml"
-  config_values = embedded_config
-  deps = [ "//src/diagnostics/archivist:bin" ]
 }
 
-fuchsia_package("realm-factory") {
-  package_name = "archivist-realm-factory"
+fuchsia_component("archivist_component") {
+  testonly = true
+  deps = [ "//src/diagnostics/archivist:bin" ]
+  component_name = "archivist"
+  cm_label = ":archivist_manifest"
+}
+
+fuchsia_structured_config_values("archivist_config") {
+  testonly = true
+  cm_label = ":archivist_manifest"
+  values = embedded_config
+}
+
+fuchsia_package("pkg") {
+  package_name = "archivist_realm_factory"
   testonly = true
   deps = [
-    ":archivist-component",
-    ":archivist-realm-factory-component",
+    ":archivist_component",
+    ":archivist_config",
+    ":archivist_realm_factory_component",
     ":do_not_filter_feedback",
     ":filter_feedback",
     ":filter_lowpan",
@@ -67,7 +77,7 @@
     # `metadata.component_url` property that gets overwritten by realm builder,
     # whereas the inspect data for a subpackaged component uses a stable,
     # relative URL for this property.
-    "//src/diagnostics/archivist/testing/puppet",
+    "puppet",
   ]
 }
 
diff --git a/src/diagnostics/archivist/testing/realm-factory/README.md b/src/diagnostics/archivist/tests/integration/realm_factory/README.md
similarity index 100%
rename from src/diagnostics/archivist/testing/realm-factory/README.md
rename to src/diagnostics/archivist/tests/integration/realm_factory/README.md
diff --git a/src/diagnostics/archivist/testing/realm-factory/configs/pipelines/DISABLE_FILTERING.txt b/src/diagnostics/archivist/tests/integration/realm_factory/configs/pipelines/DISABLE_FILTERING.txt
similarity index 100%
rename from src/diagnostics/archivist/testing/realm-factory/configs/pipelines/DISABLE_FILTERING.txt
rename to src/diagnostics/archivist/tests/integration/realm_factory/configs/pipelines/DISABLE_FILTERING.txt
diff --git a/src/diagnostics/archivist/testing/realm-factory/configs/pipelines/static_selectors.cfg b/src/diagnostics/archivist/tests/integration/realm_factory/configs/pipelines/static_selectors.cfg
similarity index 100%
rename from src/diagnostics/archivist/testing/realm-factory/configs/pipelines/static_selectors.cfg
rename to src/diagnostics/archivist/tests/integration/realm_factory/configs/pipelines/static_selectors.cfg
diff --git a/src/diagnostics/archivist/testing/fidl/BUILD.gn b/src/diagnostics/archivist/tests/integration/realm_factory/fidl/BUILD.gn
similarity index 100%
rename from src/diagnostics/archivist/testing/fidl/BUILD.gn
rename to src/diagnostics/archivist/tests/integration/realm_factory/fidl/BUILD.gn
diff --git a/src/diagnostics/archivist/testing/fidl/puppet.test.fidl b/src/diagnostics/archivist/tests/integration/realm_factory/fidl/puppet.test.fidl
similarity index 71%
rename from src/diagnostics/archivist/testing/fidl/puppet.test.fidl
rename to src/diagnostics/archivist/tests/integration/realm_factory/fidl/puppet.test.fidl
index 9d45d8aa..630bb8d1 100644
--- a/src/diagnostics/archivist/testing/fidl/puppet.test.fidl
+++ b/src/diagnostics/archivist/tests/integration/realm_factory/fidl/puppet.test.fidl
@@ -5,6 +5,7 @@
 library fuchsia.archivist.test;
 
 using fuchsia.diagnostics;
+using zx;
 
 alias LogMessage = string:MAX;
 
@@ -23,9 +24,9 @@
         client client_end:LazyInspectPuppet;
     });
 
-    // Causes the puppet to crash with an optional error message.
-    //
-    // The connection will be closed after this is called.
+    /// Causes the puppet to crash with an optional error message.
+    ///
+    /// The connection will be closed after this is called.
     flexible Crash(struct {
         message LogMessage;
     });
@@ -36,24 +37,31 @@
     /// Prints a message to stdout and appends a newline.
     flexible Println(struct {
         message LogMessage;
-    });
+    }) -> ();
 
     /// Prints a message stderr and appends a newline.
     flexible Eprintln(struct {
         message LogMessage;
-    });
-
-    // Emits a tracing event at the specified severity level.
-    flexible Log(table {
-        1: message LogMessage;
-        2: severity fuchsia.diagnostics.Severity;
     }) -> ();
 
-    // Blocks the caller until the next time an interest change event is observed.
-    // Messages are lost if they are emitted using LogPuppet.Log before the
-    // puppet has observed the the interest change.
+    /// Emits a tracing event at the specified severity level.
+    flexible Log(table {
+        /// The message carried by this log.
+        /// Required.
+        1: message LogMessage;
+        /// The severity of this log.
+        /// Required.
+        2: severity fuchsia.diagnostics.Severity;
+        /// Hardcode the time at which log is emitted.
+        /// Optional, defaults to current time.
+        3: time zx.Time;
+    }) -> ();
+
+    /// Blocks the caller until the next time an interest change event is observed.
+    /// Messages are lost if they are emitted using LogPuppet.Log before the
+    /// puppet has observed the the interest change.
     flexible WaitForInterestChange() -> (table {
-        // The new log interest observed by this component.
+        /// The new log interest observed by this component.
         1: severity fuchsia.diagnostics.Severity;
     });
 };
@@ -61,6 +69,7 @@
 /// InspectPuppet emits inspect data when requested.
 ///
 /// Values are always reported on the root inspect node.
+@discoverable
 open protocol InspectPuppet {
     /// Emits a health inspect node with OK status.
     flexible SetHealthOk() -> ();
@@ -69,21 +78,21 @@
     flexible RecordString(struct {
         key string:MAX;
         value string:MAX;
-    });
+    }) -> ();
 
     /// Records an integer inspect property.
     flexible RecordInt(struct {
         key string:MAX;
-        // Inspect properties don't distinguish between int8, int16, etc...
-        // so we accept the maximum width for convenience.
+        /// Inspect properties don't distinguish between int8, int16, etc...
+        /// so we accept the maximum width for convenience.
         value int64;
-    });
+    }) -> ();
 
     /// Emits a collection of example of inspect data.
     ///
     /// TODO(https://fuchsia.dev/302716196): Split this into several methods
     /// tests can call to explicitly emit the same data as this method.
-    flexible EmitExampleInspectData();
+    flexible EmitExampleInspectData() -> ();
 };
 
 /// Records values on a lazy inspect node.
@@ -100,7 +109,7 @@
     /// The server will close the connection after this method is called.
     flexible Commit(struct {
         options CommitOptions;
-    });
+    }) -> ();
 };
 
 type CommitOptions = table {
diff --git a/src/diagnostics/archivist/testing/fidl/realm_factory.test.fidl b/src/diagnostics/archivist/tests/integration/realm_factory/fidl/realm_factory.test.fidl
similarity index 100%
rename from src/diagnostics/archivist/testing/fidl/realm_factory.test.fidl
rename to src/diagnostics/archivist/tests/integration/realm_factory/fidl/realm_factory.test.fidl
diff --git a/src/diagnostics/archivist/testing/realm-factory/meta/archivist.cml b/src/diagnostics/archivist/tests/integration/realm_factory/meta/archivist.cml
similarity index 100%
rename from src/diagnostics/archivist/testing/realm-factory/meta/archivist.cml
rename to src/diagnostics/archivist/tests/integration/realm_factory/meta/archivist.cml
diff --git a/src/diagnostics/archivist/testing/realm-factory/meta/realm-factory.cml b/src/diagnostics/archivist/tests/integration/realm_factory/meta/realm_factory.cml
similarity index 100%
rename from src/diagnostics/archivist/testing/realm-factory/meta/realm-factory.cml
rename to src/diagnostics/archivist/tests/integration/realm_factory/meta/realm_factory.cml
diff --git a/src/diagnostics/archivist/testing/puppet/BUILD.gn b/src/diagnostics/archivist/tests/integration/realm_factory/puppet/BUILD.gn
similarity index 93%
rename from src/diagnostics/archivist/testing/puppet/BUILD.gn
rename to src/diagnostics/archivist/tests/integration/realm_factory/puppet/BUILD.gn
index b02b57a..a3c9ddc 100644
--- a/src/diagnostics/archivist/testing/puppet/BUILD.gn
+++ b/src/diagnostics/archivist/tests/integration/realm_factory/puppet/BUILD.gn
@@ -12,12 +12,13 @@
   source_root = "src/main.rs"
   sources = [ "src/main.rs" ]
   deps = [
+    "../fidl:fuchsia.archivist.test_rust",
     "//sdk/fidl/fuchsia.diagnostics:fuchsia.diagnostics_rust",
-    "//src/diagnostics/archivist/testing/fidl:fuchsia.archivist.test_rust",
     "//src/lib/diagnostics/hierarchy/rust",
     "//src/lib/diagnostics/inspect/runtime/rust",
     "//src/lib/diagnostics/inspect/rust",
     "//src/lib/diagnostics/inspect/rust/testing:inspect_testing",
+    "//src/lib/diagnostics/log/encoding/rust",
     "//src/lib/diagnostics/log/rust",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fidl_table_validation",
diff --git a/src/diagnostics/archivist/testing/puppet/README.md b/src/diagnostics/archivist/tests/integration/realm_factory/puppet/README.md
similarity index 100%
rename from src/diagnostics/archivist/testing/puppet/README.md
rename to src/diagnostics/archivist/tests/integration/realm_factory/puppet/README.md
diff --git a/src/diagnostics/archivist/tests/integration/realm_factory/puppet/meta/puppet.cml b/src/diagnostics/archivist/tests/integration/realm_factory/puppet/meta/puppet.cml
new file mode 100644
index 0000000..9dc6673
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/realm_factory/puppet/meta/puppet.cml
@@ -0,0 +1,46 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "inspect/client.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        runner: "elf",
+        binary: "bin/archivist_test_puppet",
+    },
+    children: [
+        {
+            name: "nested_one",
+            url: "#meta/puppet.cm",
+        },
+        {
+            name: "nested_two",
+            url: "#meta/puppet.cm",
+        },
+    ],
+    capabilities: [
+        { protocol: "fuchsia.archivist.test.Puppet" },
+        { protocol: "fuchsia.archivist.test.InspectPuppet" },
+    ],
+    expose: [
+        {
+            protocol: [
+                "fuchsia.archivist.test.InspectPuppet",
+                "fuchsia.archivist.test.Puppet",
+            ],
+            from: "self",
+        },
+        {
+            protocol: "fuchsia.archivist.test.InspectPuppet",
+            from: "#nested_one",
+            as: "fuchsia.archivist.test.InspectPuppet.nested_one",
+        },
+        {
+            protocol: "fuchsia.archivist.test.InspectPuppet",
+            from: "#nested_two",
+            as: "fuchsia.archivist.test.InspectPuppet.nested_two",
+        },
+    ],
+}
diff --git a/src/diagnostics/archivist/testing/puppet/src/main.rs b/src/diagnostics/archivist/tests/integration/realm_factory/puppet/src/main.rs
similarity index 62%
rename from src/diagnostics/archivist/testing/puppet/src/main.rs
rename to src/diagnostics/archivist/tests/integration/realm_factory/puppet/src/main.rs
index 9d89603..478d34a 100644
--- a/src/diagnostics/archivist/testing/puppet/src/main.rs
+++ b/src/diagnostics/archivist/tests/integration/realm_factory/puppet/src/main.rs
@@ -12,7 +12,8 @@
 
 use anyhow::{Context, Error, Result};
 use diagnostics_hierarchy::Property;
-use diagnostics_log::{OnInterestChanged, Publisher, PublisherOptions};
+use diagnostics_log::{OnInterestChanged, Publisher, PublisherOptions, TestRecord};
+use diagnostics_log_encoding::encode::{Argument, Value};
 use fidl::endpoints::create_request_stream;
 use fidl_fuchsia_archivist_test as fpuppet;
 use fidl_fuchsia_diagnostics::Severity;
@@ -20,7 +21,7 @@
 use fuchsia_async::{Task, TaskGroup, Timer};
 use fuchsia_component::server::ServiceFs;
 use fuchsia_inspect::{component, health::Reporter, Inspector};
-use fuchsia_zircon::Duration;
+use fuchsia_zircon as zx;
 use futures::{
     channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
     lock::Mutex,
@@ -32,6 +33,7 @@
 
 enum IncomingServices {
     Puppet(fpuppet::PuppetRequestStream),
+    InspectPuppet(fpuppet::InspectPuppetRequestStream),
 }
 
 // `logging = false` allows us to set the global default trace dispatcher
@@ -50,13 +52,18 @@
     let publish_options = inspect_runtime::PublishOptions::default();
     _inspect_publish_task = inspect_runtime::publish(component::inspector(), publish_options);
 
-    fs.dir("svc").add_fidl_service(IncomingServices::Puppet);
+    fs.dir("svc")
+        .add_fidl_service(IncomingServices::Puppet)
+        .add_fidl_service(IncomingServices::InspectPuppet);
     fs.take_and_serve_directory_handle()?;
     fs.for_each_concurrent(0, |service| async {
         match service {
             IncomingServices::Puppet(s) => {
                 serve_puppet(puppet_server.clone(), s).await;
             }
+            IncomingServices::InspectPuppet(s) => {
+                serve_inspect_puppet(puppet_server.clone(), s).await;
+            }
         }
     })
     .await;
@@ -102,6 +109,23 @@
             inspect_data: Mutex::new(ExampleInspectData::default()),
         }
     }
+
+    async fn emit_example_inspect_data(&self) {
+        let mut inspect_data = self.inspect_data.lock().await;
+        inspect_data.write_to(component::inspector().root());
+    }
+
+    fn record_string(&self, key: String, value: String) {
+        component::inspector().root().record_string(key, value);
+    }
+
+    fn record_int(&self, key: String, value: i64) {
+        component::inspector().root().record_int(key, value);
+    }
+
+    fn set_health_ok(&self) {
+        component::health().set_ok();
+    }
 }
 
 // Notifies the puppet when log interest changes.
@@ -130,6 +154,43 @@
     }
 }
 
+async fn serve_inspect_puppet(
+    server: Arc<PuppetServer>,
+    mut stream: fpuppet::InspectPuppetRequestStream,
+) {
+    while let Ok(Some(request)) = stream.try_next().await {
+        handle_inspect_puppet_request(server.clone(), request)
+            .await
+            .unwrap_or_else(|e| error!(?e, "handle_puppet_request"));
+    }
+}
+
+async fn handle_inspect_puppet_request(
+    server: Arc<PuppetServer>,
+    request: fpuppet::InspectPuppetRequest,
+) -> Result<(), Error> {
+    match request {
+        fpuppet::InspectPuppetRequest::EmitExampleInspectData { responder } => {
+            server.emit_example_inspect_data().await;
+            responder.send().expect("response succeeds")
+        }
+        fpuppet::InspectPuppetRequest::RecordString { key, value, responder } => {
+            server.record_string(key, value);
+            responder.send().expect("response succeeds")
+        }
+        fpuppet::InspectPuppetRequest::RecordInt { key, value, responder } => {
+            server.record_int(key, value);
+            responder.send().expect("response succeeds")
+        }
+        fpuppet::InspectPuppetRequest::SetHealthOk { responder } => {
+            server.set_health_ok();
+            responder.send().expect("response succeeds")
+        }
+        fpuppet::InspectPuppetRequest::_UnknownMethod { .. } => unreachable!(),
+    }
+    Ok(())
+}
+
 async fn handle_puppet_request(
     server: Arc<PuppetServer>,
     request: fpuppet::PuppetRequest,
@@ -138,51 +199,66 @@
         fpuppet::PuppetRequest::Crash { message, .. } => {
             panic!("{message}");
         }
-        fpuppet::PuppetRequest::EmitExampleInspectData { .. } => {
-            let mut inspect_data = server.inspect_data.lock().await;
-            inspect_data.write_to(component::inspector().root());
-            Ok(())
+        fpuppet::PuppetRequest::EmitExampleInspectData { responder } => {
+            server.emit_example_inspect_data().await;
+            responder.send().expect("response succeeds")
         }
         fpuppet::PuppetRequest::RecordLazyValues { key, responder } => {
             let (client, requests) = create_request_stream()?;
-            responder.send(client)?;
+            responder.send(client).expect("response succeeds");
             record_lazy_values(key, requests).await?;
-            Ok(())
         }
-        fpuppet::PuppetRequest::RecordString { key, value, .. } => {
-            component::inspector().root().record_string(key, value);
-            Ok(())
+        fpuppet::PuppetRequest::RecordString { key, value, responder } => {
+            server.record_string(key, value);
+            responder.send().expect("response succeeds")
         }
-        fpuppet::PuppetRequest::RecordInt { key, value, .. } => {
-            component::inspector().root().record_int(key, value);
-            Ok(())
+        fpuppet::PuppetRequest::RecordInt { key, value, responder } => {
+            server.record_int(key, value);
+            responder.send().expect("response succeeds")
         }
         fpuppet::PuppetRequest::SetHealthOk { responder } => {
-            component::health().set_ok();
-            responder.send()?;
-            Ok(())
+            server.set_health_ok();
+            responder.send().expect("response succeeds")
         }
-        fpuppet::PuppetRequest::Println { message, .. } => {
+        fpuppet::PuppetRequest::Println { message, responder } => {
             println!("{message}");
-            Ok(())
+            responder.send().expect("response succeeds")
         }
-        fpuppet::PuppetRequest::Eprintln { message, .. } => {
+        fpuppet::PuppetRequest::Eprintln { message, responder } => {
             eprintln!("{message}");
-            Ok(())
+            responder.send().expect("response succeeds")
         }
         fpuppet::PuppetRequest::Log { payload, responder, .. } => {
-            let request = LogRequest::try_from(payload).context("Log")?;
-            let LogRequest { message, severity, .. } = request;
+            let request = LogRequest::try_from(payload).context("Invalid log")?;
+            let LogRequest { message, severity, time, .. } = request;
 
-            match severity {
-                Severity::Debug => debug!("{message}"),
-                Severity::Error => error!("{message}"),
-                Severity::Info => info!("{message}"),
-                Severity::Warn => warn!("{message}"),
-                _ => unimplemented!("Logging with severity: {severity:?}"),
+            match time {
+                None => match severity {
+                    Severity::Debug => debug!("{message}"),
+                    Severity::Error => error!("{message}"),
+                    Severity::Info => info!("{message}"),
+                    Severity::Warn => warn!("{message}"),
+                    _ => unimplemented!("Logging with severity: {severity:?}"),
+                },
+                Some(time) => {
+                    tracing::dispatcher::get_default(|dispatcher| {
+                        let publisher: &diagnostics_log::Publisher =
+                            dispatcher.downcast_ref().unwrap();
+                        let record = TestRecord {
+                            severity: severity.into_primitive(),
+                            timestamp: zx::Time::from_nanos(time),
+                            file: None,
+                            line: None,
+                            record_arguments: vec![Argument {
+                                name: "message",
+                                value: Value::Text(&message),
+                            }],
+                        };
+                        publisher.event_for_testing(record);
+                    });
+                }
             }
-            responder.send()?;
-            Ok(())
+            responder.send().expect("response succeeds")
         }
         fpuppet::PuppetRequest::WaitForInterestChange { responder } => {
             let mut task_group = server.interest_waiters.lock().await;
@@ -193,12 +269,12 @@
                     severity: Some(event.severity),
                     ..Default::default()
                 };
-                responder.send(response).unwrap();
+                responder.send(response).expect("response succeeds");
             });
-            Ok(())
         }
         fpuppet::PuppetRequest::_UnknownMethod { .. } => unreachable!(),
     }
+    Ok(())
 }
 
 #[derive(Debug, Clone, ValidFidlTable)]
@@ -206,6 +282,8 @@
 pub struct LogRequest {
     pub message: String,
     pub severity: Severity,
+    #[fidl_field_type(optional)]
+    pub time: Option<i64>,
 }
 
 // Converts InspectPuppet requests into callbacks that report inspect values lazily.
@@ -218,18 +296,20 @@
     let mut properties = vec![];
     while let Ok(Some(request)) = stream.try_next().await {
         match request {
-            fpuppet::LazyInspectPuppetRequest::RecordString { key, value, .. } => {
+            fpuppet::LazyInspectPuppetRequest::RecordString { key, value, responder } => {
                 properties.push(Property::String(key, value));
+                responder.send().expect("response succeeds")
             }
-            fpuppet::LazyInspectPuppetRequest::RecordInt { key, value, .. } => {
+            fpuppet::LazyInspectPuppetRequest::RecordInt { key, value, responder } => {
                 properties.push(Property::Int(key, value));
+                responder.send().expect("response succeeds")
             }
-            fpuppet::LazyInspectPuppetRequest::Commit { options, .. } => {
+            fpuppet::LazyInspectPuppetRequest::Commit { options, responder } => {
                 component::inspector().root().record_lazy_values(key, move || {
                     let properties = properties.clone();
                     async move {
                         if options.hang.unwrap_or_default() {
-                            Timer::new(Duration::from_minutes(60)).await;
+                            Timer::new(zx::Duration::from_minutes(60)).await;
                         }
                         let inspector = Inspector::default();
                         let node = inspector.root();
@@ -244,6 +324,7 @@
                     }
                     .boxed()
                 });
+                responder.send().expect("response succeeds");
                 return Ok(()); // drop the connection.
             }
             fpuppet::LazyInspectPuppetRequest::_UnknownMethod { .. } => unreachable!(),
diff --git a/src/diagnostics/archivist/testing/realm-factory/src/main.rs b/src/diagnostics/archivist/tests/integration/realm_factory/src/main.rs
similarity index 100%
rename from src/diagnostics/archivist/testing/realm-factory/src/main.rs
rename to src/diagnostics/archivist/tests/integration/realm_factory/src/main.rs
diff --git a/src/diagnostics/archivist/testing/realm-factory/src/realm_factory.rs b/src/diagnostics/archivist/tests/integration/realm_factory/src/realm_factory.rs
similarity index 81%
rename from src/diagnostics/archivist/testing/realm-factory/src/realm_factory.rs
rename to src/diagnostics/archivist/tests/integration/realm_factory/src/realm_factory.rs
index 5f894c2..df7e5fc 100644
--- a/src/diagnostics/archivist/testing/realm-factory/src/realm_factory.rs
+++ b/src/diagnostics/archivist/tests/integration/realm_factory/src/realm_factory.rs
@@ -156,7 +156,25 @@
                         Route::new()
                             .capability(
                                 Capability::protocol::<PuppetMarker>()
-                                    .as_(decl.unique_protocol_alias()),
+                                    .as_(unique_puppet_protocol_name(&decl)),
+                            )
+                            .capability(
+                                Capability::protocol_by_name(format!(
+                                    "{}.nested_one",
+                                    InspectPuppetMarker::PROTOCOL_NAME
+                                ))
+                                .as_(
+                                    unique_puppet_child_inspect_protocol_name(&decl, "nested_one"),
+                                ),
+                            )
+                            .capability(
+                                Capability::protocol_by_name(format!(
+                                    "{}.nested_two",
+                                    InspectPuppetMarker::PROTOCOL_NAME
+                                ))
+                                .as_(
+                                    unique_puppet_child_inspect_protocol_name(&decl, "nested_two"),
+                                ),
                             )
                             .from(&puppet)
                             .to(Ref::parent()),
@@ -166,7 +184,15 @@
                 builder
                     .add_route(
                         Route::new()
-                            .capability(Capability::protocol_by_name(decl.unique_protocol_alias()))
+                            .capability(Capability::protocol_by_name(unique_puppet_protocol_name(
+                                &decl,
+                            )))
+                            .capability(Capability::protocol_by_name(
+                                unique_puppet_child_inspect_protocol_name(&decl, "nested_one"),
+                            ))
+                            .capability(Capability::protocol_by_name(
+                                unique_puppet_child_inspect_protocol_name(&decl, "nested_two"),
+                            ))
                             .from(&test_realm)
                             .to(Ref::parent()),
                     )
@@ -177,16 +203,12 @@
     }
 }
 
-trait PuppetDeclExt {
-    // A unique alias for the puppet's protocol.
-    //
-    // The test suite connects to the puppet using this alias.
-    fn unique_protocol_alias(&self) -> String;
+fn unique_puppet_protocol_name(decl: &PuppetDecl) -> String {
+    let name = decl.name.as_ref().unwrap();
+    format!("{}.{}", PuppetMarker::PROTOCOL_NAME, name)
 }
 
-impl PuppetDeclExt for PuppetDecl {
-    fn unique_protocol_alias(&self) -> String {
-        let name = self.name.as_ref().unwrap();
-        format!("{}.{}", PuppetMarker::PROTOCOL_NAME, name)
-    }
+fn unique_puppet_child_inspect_protocol_name(decl: &PuppetDecl, nested_name: &str) -> String {
+    let name = decl.name.as_ref().unwrap();
+    format!("{}.{name}.{nested_name}", InspectPuppetMarker::PROTOCOL_NAME)
 }
diff --git a/src/diagnostics/archivist/tests/integration/src/constants.rs b/src/diagnostics/archivist/tests/integration/src/constants.rs
deleted file mode 100644
index 6e0f65d..0000000
--- a/src/diagnostics/archivist/tests/integration/src/constants.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-pub const INTEGRATION_ARCHIVIST_URL: &str = "#meta/archivist.cm";
-pub const COMPONENT_WITH_CHILDREN_URL: &str =
-    "fuchsia-pkg://fuchsia.com/archivist-integration-tests#meta/component_with_children.cm";
-pub const SOCKET_PUPPET_COMPONENT_URL: &str =
-    "fuchsia-pkg://fuchsia.com/archivist-integration-tests#meta/socket-puppet.cm";
-pub const LOG_AND_EXIT_COMPONENT_URL: &str =
-    "fuchsia-pkg://fuchsia.com/archivist-integration-tests#meta/log-and-exit.cm";
-pub const STUB_INSPECT_COMPONENT_URL: &str =
-    "fuchsia-pkg://fuchsia.com/archivist-integration-tests#meta/stub_inspect_component.cm";
diff --git a/src/diagnostics/archivist/tests/integration/src/inspect/recursive_glob.rs b/src/diagnostics/archivist/tests/integration/src/inspect/recursive_glob.rs
deleted file mode 100644
index a9ef9f1..0000000
--- a/src/diagnostics/archivist/tests/integration/src/inspect/recursive_glob.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use crate::{constants::*, test_topology};
-use diagnostics_assertions::{assert_data_tree, AnyProperty};
-use diagnostics_reader::{ArchiveReader, Inspect};
-use fidl_fuchsia_diagnostics::ArchiveAccessorMarker;
-use std::collections::HashSet;
-
-#[fuchsia::test]
-async fn read_components_recursive_glob() {
-    let (builder, test_realm) = test_topology::create(test_topology::Options::default())
-        .await
-        .expect("create base topology");
-    test_topology::add_eager_child(&test_realm, "child_a", COMPONENT_WITH_CHILDREN_URL)
-        .await
-        .expect("add child a");
-    test_topology::add_eager_child(&test_realm, "child_b", COMPONENT_WITH_CHILDREN_URL)
-        .await
-        .expect("add child b");
-    let instance = builder.build().await.expect("create instance");
-
-    // Only inspect from descendants of child_a should be reported
-    let expected_monikers = HashSet::from_iter(vec![
-        "child_a/stub_inspect_1".to_string(),
-        "child_a/stub_inspect_2".to_string(),
-    ]);
-
-    let accessor =
-        instance.root.connect_to_protocol_at_exposed_dir::<ArchiveAccessorMarker>().unwrap();
-    let data_vec = ArchiveReader::new()
-        .add_selector("child_a/**:root")
-        .with_archive(accessor)
-        .with_minimum_schema_count(expected_monikers.len())
-        .snapshot::<Inspect>()
-        .await
-        .expect("got inspect data");
-
-    assert_eq!(data_vec.len(), expected_monikers.len());
-    let mut found_monikers = HashSet::new();
-    for data in data_vec {
-        assert_data_tree!(data.payload.as_ref().unwrap(), root: {
-            "fuchsia.inspect.Health": {
-                status: "OK",
-                start_timestamp_nanos: AnyProperty,
-            }
-        });
-        found_monikers.replace(data.moniker);
-    }
-    assert_eq!(expected_monikers, found_monikers);
-}
-
-#[fuchsia::test]
-async fn read_components_subtree_with_recursive_glob() {
-    let (builder, test_realm) = test_topology::create(test_topology::Options::default())
-        .await
-        .expect("create base topology");
-    test_topology::add_eager_child(&test_realm, "child_a", COMPONENT_WITH_CHILDREN_URL)
-        .await
-        .expect("add child a");
-    test_topology::add_eager_child(&test_realm, "child_b", COMPONENT_WITH_CHILDREN_URL)
-        .await
-        .expect("add child b");
-    let instance = builder.build().await.expect("create instance");
-
-    // Only inspect from test_app_a, and descendants of test_app_a should be reported
-    let expected_monikers = HashSet::from_iter(vec![
-        "child_a".to_string(),
-        "child_a/stub_inspect_1".to_string(),
-        "child_a/stub_inspect_2".to_string(),
-    ]);
-
-    let accessor =
-        instance.root.connect_to_protocol_at_exposed_dir::<ArchiveAccessorMarker>().unwrap();
-    let data_vec = ArchiveReader::new()
-        .add_selector("child_a/**:root")
-        .add_selector("child_a:root")
-        .with_archive(accessor)
-        .with_minimum_schema_count(expected_monikers.len())
-        .snapshot::<Inspect>()
-        .await
-        .expect("got inspect data");
-
-    assert_eq!(data_vec.len(), expected_monikers.len());
-    let mut found_monikers = HashSet::new();
-    for data in data_vec {
-        if data.payload.is_none() {
-            tracing::error!("UNEXPECTED EMPTY PAYLOAD: {data:?}");
-        }
-        assert_data_tree!(data.payload.as_ref().unwrap(), root: {
-            "fuchsia.inspect.Health": {
-                status: "OK",
-                start_timestamp_nanos: AnyProperty,
-            }
-        });
-        found_monikers.replace(data.moniker);
-    }
-    assert_eq!(expected_monikers, found_monikers);
-}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/attribution.rs b/src/diagnostics/archivist/tests/integration/src/logs/attribution.rs
deleted file mode 100644
index 86223d1..0000000
--- a/src/diagnostics/archivist/tests/integration/src/logs/attribution.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use crate::{constants::*, logs::utils::Listener, test_topology};
-use component_events::{
-    events::{EventStream, Started},
-    matcher::EventMatcher,
-};
-use diagnostics_assertions::assert_data_tree;
-use diagnostics_message::fx_log_packet_t;
-use diagnostics_reader::{ArchiveReader, Logs, Severity};
-use fidl::Socket;
-use fidl_fuchsia_diagnostics as fdiagnostics;
-use fidl_fuchsia_logger::{LogFilterOptions, LogLevelFilter, LogMarker, LogSinkMarker};
-use fuchsia_async as fasync;
-use fuchsia_syslog_listener::run_log_listener_with_proxy;
-use futures::{channel::mpsc, StreamExt};
-
-// This test verifies that Archivist knows about logging from this component.
-#[fuchsia::test]
-async fn log_attribution() {
-    let (builder, test_realm) = test_topology::create(test_topology::Options::default())
-        .await
-        .expect("create base topology");
-    test_topology::add_eager_child(&test_realm, "child", STUB_INSPECT_COMPONENT_URL)
-        .await
-        .expect("add child");
-
-    let instance = builder.build().await.expect("create instance");
-
-    let accessor = instance
-        .root
-        .connect_to_protocol_at_exposed_dir::<fdiagnostics::ArchiveAccessorMarker>()
-        .unwrap();
-    let mut result = ArchiveReader::new()
-        .with_archive(accessor)
-        .snapshot_then_subscribe::<Logs>()
-        .expect("snapshot then subscribe");
-
-    for log_str in &["This is a syslog message", "This is another syslog message"] {
-        let log_record = result.next().await.expect("received log").expect("log is not an error");
-
-        assert_eq!(log_record.moniker, "child");
-        assert_eq!(log_record.metadata.component_url, Some(STUB_INSPECT_COMPONENT_URL.to_string()));
-        assert_eq!(log_record.metadata.severity, Severity::Info);
-        assert_data_tree!(log_record.payload.unwrap(), root: contains {
-            message: {
-              value: log_str.to_string(),
-            }
-        });
-    }
-}
-
-// TODO(https://fxbug.dev/297211132): re-enable when we actually support unattributed connections again.
-#[ignore]
-#[fuchsia::test]
-async fn log_unattributed_stream() {
-    let (builder, _test_realm) = test_topology::create(test_topology::Options::default())
-        .await
-        .expect("create base topology");
-
-    // Hook to up to event source before starting realm. This is done to avoid
-    // a race condition in which the instance is started before the proper
-    // event matcher is ready.
-    let mut event_stream = EventStream::open().await.unwrap();
-
-    let instance = builder.build().await.expect("create instance");
-
-    // Bind to Log to start archivist.
-    let log_proxy = instance.root.connect_to_protocol_at_exposed_dir::<LogMarker>().unwrap();
-
-    // Ensure that Archivist has started before continuing with tests.
-    let _ = EventMatcher::ok()
-        .moniker_regex("archivist$")
-        .wait::<Started>(&mut event_stream)
-        .await
-        .unwrap();
-
-    // connect multiple identical log sinks
-    for _ in 0..50 {
-        let (message_client, message_server) = Socket::create_datagram();
-        let log_sink = instance.root.connect_to_protocol_at_exposed_dir::<LogSinkMarker>().unwrap();
-        log_sink.connect(message_server).unwrap();
-
-        // each with the same message repeated multiple times
-        let mut packet = fx_log_packet_t::default();
-        packet.metadata.pid = 1000;
-        packet.metadata.tid = 2000;
-        packet.metadata.severity = LogLevelFilter::Info.into_primitive().into();
-        packet.data[0] = 0;
-        packet.add_data(1, "repeated log".as_bytes());
-        for _ in 0..5 {
-            message_client.write(packet.as_bytes()).unwrap();
-        }
-    }
-
-    // run log listener
-    let (send_logs, recv_logs) = mpsc::unbounded();
-    fasync::Task::spawn(async move {
-        let listen = Listener { send_logs };
-        let options = LogFilterOptions {
-            filter_by_pid: true,
-            pid: 1000,
-            filter_by_tid: true,
-            tid: 2000,
-            verbosity: 0,
-            min_severity: LogLevelFilter::None,
-            tags: Vec::new(),
-        };
-        run_log_listener_with_proxy(&log_proxy, listen, Some(&options), false, None).await.unwrap();
-    })
-    .detach();
-
-    // collect all logs
-    let logs = recv_logs
-        .map(|message| (message.severity, message.msg))
-        .take(250)
-        .collect::<Vec<_>>()
-        .await;
-
-    assert_eq!(
-        logs,
-        std::iter::repeat((
-            fdiagnostics::Severity::Info.into_primitive() as i32,
-            "repeated log".to_owned()
-        ))
-        .take(250)
-        .collect::<Vec<_>>()
-    );
-}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/budget.rs b/src/diagnostics/archivist/tests/integration/src/logs/budget.rs
deleted file mode 100644
index 51bd82d..0000000
--- a/src/diagnostics/archivist/tests/integration/src/logs/budget.rs
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#![allow(clippy::large_futures)]
-
-use crate::{constants::*, test_topology};
-use anyhow::Error;
-use diagnostics_data::{Data, Logs};
-use diagnostics_message::{fx_log_packet_t, METADATA_SIZE};
-use diagnostics_reader::{ArchiveReader, RetryConfig};
-use fidl::prelude::*;
-use fidl_fuchsia_archivist_test as ftest;
-use fidl_fuchsia_archivist_tests::{
-    SocketPuppetControllerRequest, SocketPuppetControllerRequestStream, SocketPuppetProxy,
-};
-use fidl_fuchsia_component as fcomponent;
-use fidl_fuchsia_component::RealmMarker;
-use fidl_fuchsia_component_decl::ChildRef;
-use fidl_fuchsia_diagnostics as fdiagnostics;
-use fidl_fuchsia_io as fio;
-use fuchsia_async::Task;
-use fuchsia_component::{client, server::ServiceFs};
-use fuchsia_component_test::{
-    Capability, ChildOptions, LocalComponentHandles, RealmInstance, Ref, Route,
-};
-use fuchsia_zircon as zx;
-use futures::{
-    channel::mpsc::{self, Receiver},
-    StreamExt,
-};
-use std::ops::Deref;
-use tracing::{debug, info};
-
-const TEST_PACKET_LEN: usize = 49;
-const MAX_PUPPETS: usize = 5;
-const SPAM_PUPPET_ID: usize = 0;
-const VICTIM_PUPPET_ID: usize = 1;
-const SPAM_COUNT: usize = 9001;
-
-#[fuchsia::test(logging_minimum_severity = "debug")]
-async fn test_budget() {
-    info!("testing that the archivist's log buffers correctly enforce their budget");
-
-    info!("creating nested environment for collecting diagnostics");
-    let mut env = PuppetEnv::create(MAX_PUPPETS).await;
-    // New test
-    // Spam puppet which spams the good puppet's logs removing them from the buffer
-    env.create_puppet(SPAM_PUPPET_ID).await;
-    env.create_puppet(VICTIM_PUPPET_ID).await;
-    let expected = env.running_puppets[VICTIM_PUPPET_ID].emit_packet().await;
-    let mut observed_logs = env.log_reader.snapshot_then_subscribe::<Logs>().unwrap();
-    // split_streams is needed here to ensure parallel execution.
-    // If this isn't ran in parallel, the ordering required by this
-    // test never happens.
-    let (mut observed_logs_2, _errors) =
-        env.log_reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams();
-    let msg_a = observed_logs.next().await.unwrap().unwrap();
-    let msg_a_2 = observed_logs_2.next().await.unwrap();
-    assert_eq!(expected, msg_a);
-    assert_eq!(expected, msg_a_2);
-    for _ in 0..SPAM_COUNT {
-        let last_msg = env.running_puppets[SPAM_PUPPET_ID].emit_packet().await;
-        assert_eq!(last_msg, observed_logs.next().await.unwrap().unwrap());
-    }
-    let log = observed_logs_2.skip(33).next().await.unwrap();
-    assert_eq!(log.rolled_out_logs(), Some(8907));
-    let mut observed_logs = env.log_reader.snapshot::<Logs>().await.unwrap().into_iter();
-    let msg_b = observed_logs.next().unwrap();
-    assert!(!msg_b.moniker.contains(&format!("puppet-{VICTIM_PUPPET_ID}")));
-    // Vicitm logs should have been rolled out.
-    let messages = observed_logs
-        .filter(|log| log.moniker.contains(&format!("puppet-{VICTIM_PUPPET_ID}")))
-        .collect::<Vec<_>>();
-    assert!(messages.is_empty());
-    assert_ne!(msg_a, msg_b);
-}
-
-struct PuppetEnv {
-    max_puppets: usize,
-    instance: RealmInstance,
-    controllers: Receiver<SocketPuppetControllerRequestStream>,
-    launched_monikers: Vec<String>,
-    running_puppets: Vec<Puppet>,
-    log_reader: ArchiveReader,
-    _log_errors: Task<()>,
-}
-
-impl PuppetEnv {
-    async fn create(max_puppets: usize) -> Self {
-        let (sender, controllers) = mpsc::channel(1);
-        let (builder, test_realm) = test_topology::create(test_topology::Options {
-            archivist_config: ftest::ArchivistConfig {
-                logs_max_cached_original_bytes: Some(3000),
-                ..Default::default()
-            },
-            realm_name: None,
-        })
-        .await
-        .expect("create base topology");
-        let mocks_server = builder
-            .add_local_child(
-                "mocks-server",
-                move |handles: LocalComponentHandles| Box::pin(run_mocks(handles, sender.clone())),
-                ChildOptions::new(),
-            )
-            .await
-            .unwrap();
-
-        builder
-            .add_route(
-                Route::new()
-                    .capability(Capability::protocol_by_name(
-                        "fuchsia.archivist.tests.SocketPuppetController",
-                    ))
-                    .from(&mocks_server)
-                    .to(&test_realm),
-            )
-            .await
-            .unwrap();
-
-        for i in 0..max_puppets {
-            let name = format!("puppet-{i}");
-            let puppet = test_realm
-                .add_child(name.clone(), SOCKET_PUPPET_COMPONENT_URL, ChildOptions::new())
-                .await
-                .unwrap();
-            test_realm
-                .add_route(
-                    Route::new()
-                        .capability(Capability::protocol_by_name(
-                            "fuchsia.archivist.tests.SocketPuppetController",
-                        ))
-                        .from(Ref::parent())
-                        .to(&puppet),
-                )
-                .await
-                .unwrap();
-            test_realm
-                .add_route(
-                    Route::new()
-                        .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
-                        .from(Ref::child("archivist"))
-                        .to(&puppet),
-                )
-                .await
-                .unwrap();
-        }
-
-        info!("starting our instance");
-        test_topology::expose_test_realm_protocol(&builder, &test_realm).await;
-        let instance = builder.build().await.expect("create instance");
-
-        let archive = || {
-            instance
-                .root
-                .connect_to_protocol_at_exposed_dir::<fdiagnostics::ArchiveAccessorMarker>()
-                .unwrap()
-        };
-        let mut inspect_reader = ArchiveReader::new();
-        inspect_reader
-            .with_archive(archive())
-            .with_minimum_schema_count(1) // we only request inspect from our archivist
-            .add_selector("archivist:root/logs_buffer")
-            .add_selector("archivist:root/sources");
-        let mut log_reader = ArchiveReader::new();
-        log_reader
-            .with_archive(archive())
-            .with_minimum_schema_count(0) // we want this to return even when no log messages
-            .retry(RetryConfig::never());
-        let (_log_subscription, mut errors) =
-            log_reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams();
-
-        let _log_errors = Task::spawn(async move {
-            if let Some(error) = errors.next().await {
-                panic!("{error:#?}");
-            }
-        });
-
-        Self {
-            max_puppets,
-            controllers,
-            instance,
-            launched_monikers: vec![],
-            running_puppets: vec![],
-            log_reader,
-            _log_errors,
-        }
-    }
-
-    async fn create_puppet(&mut self, id: usize) -> String {
-        assert!(id < self.max_puppets);
-        let child_ref = ChildRef { name: format!("puppet-{id}"), collection: None };
-
-        let (exposed_dir, server_end) =
-            fidl::endpoints::create_proxy::<fio::DirectoryMarker>().unwrap();
-        let realm = self.instance.root.connect_to_protocol_at_exposed_dir::<RealmMarker>().unwrap();
-        realm.open_exposed_dir(&child_ref, server_end).await.unwrap().unwrap();
-
-        let _ = client::connect_to_protocol_at_dir_root::<fcomponent::BinderMarker>(&exposed_dir)
-            .unwrap();
-
-        debug!("waiting for controller request");
-        let mut controller = self.controllers.next().await.unwrap();
-
-        debug!("waiting for ControlPuppet call");
-        let proxy = match controller.next().await {
-            Some(Ok(SocketPuppetControllerRequest::ControlPuppet {
-                to_control,
-                control_handle,
-            })) => {
-                control_handle.shutdown();
-                to_control.into_proxy().unwrap()
-            }
-            _ => panic!("did not expect that"),
-        };
-
-        let moniker = format!("puppet-{id}");
-        let puppet = Puppet { moniker: moniker.clone(), proxy };
-
-        info!("having the puppet connect to LogSink");
-        puppet.connect_to_log_sink().await.unwrap();
-
-        info!("observe the puppet appears in archivist's inspect output");
-        self.launched_monikers.push(moniker.clone());
-        self.running_puppets.push(puppet);
-        moniker
-    }
-}
-
-struct Puppet {
-    proxy: SocketPuppetProxy,
-    moniker: String,
-}
-
-impl std::fmt::Debug for Puppet {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("Puppet").field("moniker", &self.moniker).finish()
-    }
-}
-
-impl Puppet {
-    async fn emit_packet(&self) -> MessageReceipt {
-        let timestamp = zx::Time::get_monotonic().into_nanos();
-        let mut packet: fx_log_packet_t = Default::default();
-        packet.metadata.severity = fdiagnostics::Severity::Info.into_primitive() as i32;
-        packet.metadata.time = timestamp;
-        packet.fill_data(1..(TEST_PACKET_LEN - METADATA_SIZE), b'A' as _);
-        self.proxy.emit_packet(packet.as_bytes()).await.unwrap();
-        MessageReceipt { timestamp, moniker: self.moniker.clone() }
-    }
-}
-
-impl Deref for Puppet {
-    type Target = SocketPuppetProxy;
-    fn deref(&self) -> &Self::Target {
-        &self.proxy
-    }
-}
-
-async fn run_mocks(
-    handles: LocalComponentHandles,
-    mut sender: mpsc::Sender<SocketPuppetControllerRequestStream>,
-) -> Result<(), Error> {
-    let mut fs = ServiceFs::new();
-    fs.dir("svc").add_fidl_service(move |stream: SocketPuppetControllerRequestStream| {
-        sender.start_send(stream).unwrap();
-    });
-    fs.serve_connection(handles.outgoing_dir)?;
-    fs.collect::<()>().await;
-    Ok(())
-}
-
-/// A value indicating a message was sent by a particular puppet.
-#[derive(Clone, Debug, PartialEq)]
-struct MessageReceipt {
-    moniker: String,
-    timestamp: i64,
-}
-
-impl PartialEq<Data<Logs>> for MessageReceipt {
-    fn eq(&self, other: &Data<Logs>) -> bool {
-        other.moniker == self.moniker && other.metadata.timestamp == self.timestamp
-    }
-}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/lifecycle.rs b/src/diagnostics/archivist/tests/integration/src/logs/lifecycle.rs
deleted file mode 100644
index 90e77f2..0000000
--- a/src/diagnostics/archivist/tests/integration/src/logs/lifecycle.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use crate::{
-    constants::*,
-    test_topology::{self, expose_test_realm_protocol},
-    utils,
-};
-use component_events::{events::*, matcher::*};
-use diagnostics_assertions::assert_data_tree;
-use diagnostics_reader::{ArchiveReader, Data, Logs, RetryConfig};
-use fidl_fuchsia_component as fcomponent;
-use fidl_fuchsia_diagnostics::ArchiveAccessorMarker;
-use fuchsia_async as fasync;
-use fuchsia_component_test::ScopedInstanceFactory;
-use futures::StreamExt;
-
-const LOG_AND_EXIT_COMPONENT: &str = "log_and_exit";
-
-#[fuchsia::test]
-async fn test_logs_lifecycle() {
-    let (builder, test_realm) = test_topology::create(test_topology::Options::default())
-        .await
-        .expect("create base topology");
-    test_topology::add_collection(&test_realm, "coll").await.unwrap();
-
-    // Currently RealmBuilder doesn't support to expose a capability from framework, therefore we
-    // manually update the decl that the builder creates.
-    expose_test_realm_protocol(&builder, &test_realm).await;
-    let realm = builder.build().await.unwrap();
-    let accessor =
-        realm.root.connect_to_protocol_at_exposed_dir::<ArchiveAccessorMarker>().unwrap();
-
-    let mut reader = ArchiveReader::new();
-    reader
-        .with_archive(accessor)
-        .with_minimum_schema_count(0) // we want this to return even when no log messages
-        .retry(RetryConfig::never());
-
-    let (mut subscription, mut errors) =
-        reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams();
-    let _log_errors = fasync::Task::spawn(async move {
-        if let Some(error) = errors.next().await {
-            panic!("{error:#?}");
-        }
-    });
-
-    let moniker = "coll:log_and_exit";
-
-    let mut event_stream = EventStream::open().await.unwrap();
-    reader.retry(RetryConfig::EMPTY);
-    for i in 1..50 {
-        // launch our child, wait for it to exit, and destroy (so all its outgoing log connections
-        // are processed) before asserting on its logs
-        let realm_proxy =
-            realm.root.connect_to_protocol_at_exposed_dir::<fcomponent::RealmMarker>().unwrap();
-        let mut instance = ScopedInstanceFactory::new("coll")
-            .with_realm_proxy(realm_proxy)
-            .new_named_instance(LOG_AND_EXIT_COMPONENT, LOG_AND_EXIT_COMPONENT_URL)
-            .await
-            .unwrap();
-        let _ = instance.connect_to_protocol_at_exposed_dir::<fcomponent::BinderMarker>().unwrap();
-
-        utils::wait_for_component_stopped_event(
-            realm.root.child_name(),
-            &format!("coll:{LOG_AND_EXIT_COMPONENT}"),
-            ExitStatusMatcher::Clean,
-            &mut event_stream,
-        )
-        .await;
-
-        check_message(&moniker, subscription.next().await.unwrap());
-
-        reader.with_minimum_schema_count(i);
-        let all_messages = reader.snapshot::<Logs>().await.unwrap();
-
-        for message in all_messages {
-            check_message(&moniker, message);
-        }
-
-        let waiter = instance.take_destroy_waiter();
-        drop(instance);
-        waiter.await.unwrap();
-    }
-}
-
-fn check_message(expected_moniker: &str, message: Data<Logs>) {
-    assert_eq!(message.moniker, expected_moniker,);
-    assert_eq!(message.metadata.component_url, Some(LOG_AND_EXIT_COMPONENT_URL.to_string()));
-
-    assert_data_tree!(message.payload.unwrap(), root: {
-        message: {
-            value: "Hello, world!",
-        }
-    });
-}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/selectors.rs b/src/diagnostics/archivist/tests/integration/src/logs/selectors.rs
deleted file mode 100644
index b5ae246..0000000
--- a/src/diagnostics/archivist/tests/integration/src/logs/selectors.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use crate::{constants, test_topology, utils};
-use component_events::{events::*, matcher::*};
-use diagnostics_assertions::assert_data_tree;
-use diagnostics_reader::{ArchiveReader, Logs};
-use fidl_fuchsia_component as fcomponent;
-use fidl_fuchsia_diagnostics::ArchiveAccessorMarker;
-use fuchsia_async as fasync;
-use fuchsia_component_test::{RealmInstance, ScopedInstanceFactory};
-use futures::{FutureExt, StreamExt};
-
-#[fuchsia::test]
-async fn component_selectors_filter_logs() {
-    let (builder, test_realm) = test_topology::create(test_topology::Options::default())
-        .await
-        .expect("create base topology");
-    test_topology::add_collection(&test_realm, "coll").await.unwrap();
-
-    test_topology::expose_test_realm_protocol(&builder, &test_realm).await;
-    let realm = builder.build().await.expect("create instance");
-    let accessor =
-        realm.root.connect_to_protocol_at_exposed_dir::<ArchiveAccessorMarker>().unwrap();
-
-    let mut event_stream = EventStream::open().await.unwrap();
-
-    // Start a few components.
-    for _ in 0..3 {
-        launch_and_wait_for_exit(&realm, "a", &mut event_stream).await;
-        launch_and_wait_for_exit(&realm, "b", &mut event_stream).await;
-    }
-
-    // Start listening
-    let mut reader = ArchiveReader::new();
-    reader.add_selector("coll\\:a:root").with_archive(accessor).with_minimum_schema_count(5);
-
-    let (mut stream, mut errors) =
-        reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams();
-    let _errors = fasync::Task::spawn(async move {
-        if let Some(e) = errors.next().await {
-            panic!("error in subscription: {e}");
-        }
-    });
-
-    // Start a few more components
-    for _ in 0..3 {
-        launch_and_wait_for_exit(&realm, "a", &mut event_stream).await;
-        launch_and_wait_for_exit(&realm, "b", &mut event_stream).await;
-    }
-
-    // We should see logs from components started before and after we began to listen.
-    for _ in 0..6 {
-        let log = stream.next().await.unwrap();
-        assert_eq!(log.moniker, "coll:a");
-        assert_data_tree!(log.payload.unwrap(), root: {
-            message: {
-                value: "Hello, world!",
-            }
-        });
-    }
-    // We only expect 6 logs.
-    assert!(stream.next().now_or_never().is_none());
-}
-
-async fn launch_and_wait_for_exit(
-    realm: &RealmInstance,
-    name: &str,
-    event_stream: &mut EventStream,
-) {
-    // launch our child, wait for it to exit, and destroy (so all its outgoing log connections
-    // are processed) before asserting on its logs
-    let realm_proxy =
-        realm.root.connect_to_protocol_at_exposed_dir::<fcomponent::RealmMarker>().unwrap();
-    let mut instance = ScopedInstanceFactory::new("coll")
-        .with_realm_proxy(realm_proxy)
-        .new_named_instance(name, constants::LOG_AND_EXIT_COMPONENT_URL)
-        .await
-        .unwrap();
-    let _ = instance.connect_to_protocol_at_exposed_dir::<fcomponent::BinderMarker>().unwrap();
-
-    utils::wait_for_component_stopped_event(
-        realm.root.child_name(),
-        &format!("coll:{name}"),
-        ExitStatusMatcher::Clean,
-        event_stream,
-    )
-    .await;
-    let waiter = instance.take_destroy_waiter();
-    drop(instance);
-    waiter.await.unwrap();
-}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/sorting.rs b/src/diagnostics/archivist/tests/integration/src/logs/sorting.rs
deleted file mode 100644
index 9dd9258..0000000
--- a/src/diagnostics/archivist/tests/integration/src/logs/sorting.rs
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use crate::test_topology;
-use diagnostics_message::fx_log_packet_t;
-use fidl_fuchsia_diagnostics as fdiagnostics;
-use fidl_fuchsia_logger::{LogLevelFilter, LogMarker, LogMessage, LogSinkMarker};
-use fuchsia_async as fasync;
-use fuchsia_component_test::{Capability, ChildOptions, RealmInstance, Ref, Route};
-use fuchsia_syslog_listener::run_log_listener_with_proxy;
-use fuchsia_zircon as zx;
-use futures::{channel::mpsc, FutureExt, StreamExt};
-use std::sync::{Arc, Mutex};
-
-#[fuchsia::test]
-async fn timestamp_sorting_for_batches() {
-    let (builder, test_realm) = test_topology::create(test_topology::Options::default())
-        .await
-        .expect("create base topology");
-
-    // TODO(b/297211132): this is a workaround to a current bug due to which unattributed
-    // connections don't currently work. In an ideal world, we'd be able to connect ot
-    // fuchsia.logger.LogSink directly without requiring a local child.
-    let (connect_socket_snd, connect_socket_rcv) = mpsc::unbounded();
-    let rcv_arc = Arc::new(Mutex::new(Some(connect_socket_rcv)));
-    let logger = test_realm
-        .add_local_child(
-            "logger",
-            move |handles| {
-                // Note: ok to unwrap, for the test purposes, this will be called once.
-                let rcv = rcv_arc.clone();
-                async move {
-                    let log_sink = handles
-                        .connect_to_protocol::<LogSinkMarker>()
-                        .expect("logsink is available");
-                    // Unwrap is fine, we call this once.
-                    let mut rcv = rcv.lock().unwrap().take().unwrap();
-                    while let Some(socket) = rcv.next().await {
-                        log_sink.connect(socket).unwrap();
-                    }
-                    Ok(())
-                }
-                .boxed()
-            },
-            ChildOptions::new().eager(),
-        )
-        .await
-        .expect("add logger");
-    test_realm
-        .add_route(
-            Route::new()
-                .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
-                .from(Ref::child("archivist"))
-                .to(&logger),
-        )
-        .await
-        .expect("route logsink to logger");
-
-    let instance = builder.build().await.expect("create instance");
-
-    let message_times = [1_000, 5_000, 10_000, 15_000];
-    let hare_times = (0, 2);
-    let tort_times = (1, 3);
-    let packets = message_times
-        .iter()
-        .map(|t| {
-            let mut packet = fx_log_packet_t::default();
-            packet.metadata.time = *t;
-            packet.metadata.pid = 1000;
-            packet.metadata.tid = 2000;
-            packet.metadata.severity = LogLevelFilter::Info.into_primitive().into();
-            packet.add_data(1, "timing log".as_bytes());
-            packet
-        })
-        .collect::<Vec<_>>();
-    let messages = packets
-        .iter()
-        .map(|p| LogMessage {
-            severity: fdiagnostics::Severity::Info.into_primitive() as i32,
-            time: p.metadata.time,
-            dropped_logs: 0,
-            msg: "timing log".to_owned(),
-            tags: vec!["logger".into()],
-            pid: p.metadata.pid,
-            tid: p.metadata.tid,
-        })
-        .collect::<Vec<_>>();
-
-    {
-        // there are two writers in this test, a "tortoise" and a "hare"
-        // the hare's messages are always timestamped earlier but arrive later
-        let (send_tort, recv_tort) = zx::Socket::create_datagram();
-        let (send_hare, recv_hare) = zx::Socket::create_datagram();
-
-        // put a message in each socket
-        send_tort.write(packets[tort_times.0].as_bytes()).unwrap();
-        send_hare.write(packets[hare_times.0].as_bytes()).unwrap();
-
-        // connect to log_sink and make sure we have a clean slate
-        let mut early_listener = listen_to_archivist(&instance);
-
-        // connect the tortoise's socket
-        connect_socket_snd.unbounded_send(recv_tort).expect("send socket");
-        let tort_expected = messages[tort_times.0].clone();
-        let mut expected_dump = vec![tort_expected.clone()];
-        assert_eq!(early_listener.next().await.unwrap(), tort_expected);
-        assert_eq!(dump_from_archivist(&instance).await, expected_dump);
-
-        // connect hare's socket
-        connect_socket_snd.unbounded_send(recv_hare).expect("send socket");
-        let hare_expected = messages[hare_times.0].clone();
-        expected_dump.push(hare_expected.clone());
-        expected_dump.sort_by_key(|m| m.time);
-
-        assert_eq!(early_listener.next().await.unwrap(), hare_expected);
-        assert_eq!(dump_from_archivist(&instance).await, expected_dump);
-
-        // start a new listener and make sure it gets backlog reversed from early listener
-        let mut middle_listener = listen_to_archivist(&instance);
-        assert_eq!(middle_listener.next().await.unwrap(), hare_expected);
-        assert_eq!(middle_listener.next().await.unwrap(), tort_expected);
-
-        // send the second tortoise message and assert it's seen
-        send_tort.write(packets[tort_times.1].as_bytes()).unwrap();
-        let tort_expected2 = messages[tort_times.1].clone();
-        expected_dump.push(tort_expected2.clone());
-        expected_dump.sort_by_key(|m| m.time);
-
-        assert_eq!(early_listener.next().await.unwrap(), tort_expected2);
-        assert_eq!(middle_listener.next().await.unwrap(), tort_expected2);
-        assert_eq!(dump_from_archivist(&instance).await, expected_dump);
-
-        // send the second hare message and assert it's seen
-        send_tort.write(packets[hare_times.1].as_bytes()).unwrap();
-        let hare_expected2 = messages[hare_times.1].clone();
-        expected_dump.push(hare_expected2.clone());
-        expected_dump.sort_by_key(|m| m.time);
-
-        assert_eq!(early_listener.next().await.unwrap(), hare_expected2);
-        assert_eq!(middle_listener.next().await.unwrap(), hare_expected2);
-        assert_eq!(dump_from_archivist(&instance).await, expected_dump);
-
-        // listening after all messages were seen by archivist-for-embedding should be time-ordered
-        let mut final_listener = listen_to_archivist(&instance);
-        assert_eq!(final_listener.next().await.unwrap(), hare_expected);
-        assert_eq!(final_listener.next().await.unwrap(), tort_expected);
-        assert_eq!(final_listener.next().await.unwrap(), hare_expected2);
-        assert_eq!(final_listener.next().await.unwrap(), tort_expected2);
-    }
-}
-
-async fn dump_from_archivist(instance: &RealmInstance) -> Vec<LogMessage> {
-    let log_proxy = instance.root.connect_to_protocol_at_exposed_dir::<LogMarker>().unwrap();
-    let (send_logs, recv_logs) = mpsc::unbounded();
-    fasync::Task::spawn(async move {
-        run_log_listener_with_proxy(&log_proxy, send_logs, None, true, None).await.unwrap();
-    })
-    .detach();
-    recv_logs.collect::<Vec<_>>().await
-}
-
-fn listen_to_archivist(instance: &RealmInstance) -> mpsc::UnboundedReceiver<LogMessage> {
-    let log_proxy = instance.root.connect_to_protocol_at_exposed_dir::<LogMarker>().unwrap();
-    let (send_logs, recv_logs) = mpsc::unbounded();
-    fasync::Task::spawn(async move {
-        run_log_listener_with_proxy(&log_proxy, send_logs, None, false, None).await.unwrap();
-    })
-    .detach();
-    recv_logs
-}
diff --git a/src/diagnostics/archivist/tests/integration/src/test_topology.rs b/src/diagnostics/archivist/tests/integration/src/test_topology.rs
deleted file mode 100644
index 23583a2..0000000
--- a/src/diagnostics/archivist/tests/integration/src/test_topology.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright 2021 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use crate::constants;
-
-use anyhow::{Context, Error, Result};
-use fidl::endpoints::{create_endpoints, DiscoverableProtocolMarker, ProtocolMarker};
-use fidl_fuchsia_archivist_test as ftest;
-use fidl_fuchsia_component_decl as fdecl;
-use fidl_fuchsia_testing_harness as fharness;
-use fuchsia_component::client::connect_to_protocol;
-use fuchsia_component_test::{
-    Capability, ChildOptions, ChildRef, RealmBuilder, RealmBuilderParams, Ref, Route,
-    SubRealmBuilder,
-};
-use realm_proxy_client::RealmProxyClient;
-
-/// Options for creating a test topology.
-#[derive(Default)]
-pub struct Options {
-    pub archivist_config: ftest::ArchivistConfig,
-    pub realm_name: Option<&'static str>,
-}
-
-/// Creates a new test realm with an archivist inside.
-/// `options_fn` is called with a default RealmOptions struct and can modify any options
-/// before the realm is created.
-pub async fn create_realm(options: ftest::RealmOptions) -> Result<RealmProxyClient> {
-    let realm_factory = connect_to_protocol::<ftest::RealmFactoryMarker>()?;
-    let (client, server) = create_endpoints::<fharness::RealmProxy_Marker>();
-    realm_factory
-        .create_realm(&options, server)
-        .await?
-        .map_err(realm_proxy_client::Error::OperationError)?;
-    Ok(RealmProxyClient::from(client))
-}
-
-// Helper type for constructing `PuppetDecl`.
-pub(crate) struct PuppetDeclBuilder {
-    name: String,
-}
-
-impl PuppetDeclBuilder {
-    pub fn new(name: impl Into<String>) -> Self {
-        Self { name: name.into() }
-    }
-}
-
-impl Into<ftest::PuppetDecl> for PuppetDeclBuilder {
-    fn into(self) -> ftest::PuppetDecl {
-        ftest::PuppetDecl { name: Some(self.name), ..Default::default() }
-    }
-}
-
-/// Connects to the puppet in the test realm with the given name.
-pub async fn connect_to_puppet(
-    realm_proxy: &RealmProxyClient,
-    puppet_name: &str,
-) -> Result<<ftest::PuppetMarker as ProtocolMarker>::Proxy> {
-    let puppet_protocol_alias = format!("{}.{puppet_name}", ftest::PuppetMarker::PROTOCOL_NAME);
-    realm_proxy
-        .connect_to_named_protocol::<ftest::PuppetMarker>(&puppet_protocol_alias)
-        .await
-        .with_context(|| format!("failed to connect to {puppet_name}"))
-}
-
-/// Creates a new topology for tests with an archivist inside.
-pub async fn create(opts: Options) -> Result<(RealmBuilder, SubRealmBuilder), Error> {
-    let mut params = RealmBuilderParams::new();
-    if let Some(realm_name) = opts.realm_name {
-        params = params.realm_name(realm_name);
-    }
-    let builder = RealmBuilder::with_params(params).await?;
-    let test_realm = builder.add_child_realm("test", ChildOptions::new().eager()).await?;
-    let archivist = test_realm
-        .add_child("archivist", constants::INTEGRATION_ARCHIVIST_URL, ChildOptions::new().eager())
-        .await?;
-
-    // The following configurations are tweakable.
-    builder
-        .add_capability(cm_rust::CapabilityDecl::Config(cm_rust::ConfigurationDecl {
-            name: "fuchsia.diagnostics.EnableKlog".parse()?,
-            value: cm_rust::ConfigValue::Single(cm_rust::ConfigSingleValue::Bool(
-                opts.archivist_config.enable_klog.unwrap_or(false),
-            )),
-        }))
-        .await?;
-    if let Some(logs_max_cached_original_bytes) =
-        opts.archivist_config.logs_max_cached_original_bytes
-    {
-        builder
-            .add_capability(cm_rust::CapabilityDecl::Config(cm_rust::ConfigurationDecl {
-                name: "fuchsia.diagnostics.LogsMaxCachedOriginalBytes".parse()?,
-                value: cm_rust::ConfigValue::Single(cm_rust::ConfigSingleValue::Uint64(
-                    logs_max_cached_original_bytes,
-                )),
-            }))
-            .await?;
-    }
-    builder
-        .add_capability(cm_rust::CapabilityDecl::Config(cm_rust::ConfigurationDecl {
-            name: "fuchsia.diagnostics.PipelinesPath".parse()?,
-            value: cm_rust::ConfigValue::Single(cm_rust::ConfigSingleValue::String(
-                opts.archivist_config.pipelines_path.unwrap_or("/pkg/data/config".to_string()),
-            )),
-        }))
-        .await?;
-
-    builder
-        .add_route(
-            Route::new()
-                .capability(
-                    Capability::event_stream("capability_requested").with_scope(&test_realm),
-                )
-                .from(Ref::parent())
-                .to(&test_realm),
-        )
-        .await?;
-
-    test_realm
-        .add_route(
-            Route::new()
-                .capability(Capability::event_stream("capability_requested"))
-                .from(Ref::parent())
-                .to(&archivist),
-        )
-        .await?;
-
-    let mut self_to_archivist = Route::new()
-        .capability(Capability::configuration("fuchsia.diagnostics.EnableKlog"))
-        .capability(Capability::configuration("fuchsia.diagnostics.PipelinesPath"));
-
-    // The following config capabilities are routed from "void" to archivist since we use the
-    // package default config values for them.
-    let mut void_to_archivist = Route::new()
-        .capability(Capability::configuration("fuchsia.diagnostics.BindServices"))
-        .capability(Capability::configuration(
-            "fuchsia.diagnostics.MaximumConcurrentSnapshotsPerReader",
-        ))
-        .capability(Capability::configuration("fuchsia.diagnostics.NumThreads"))
-        .capability(Capability::configuration("fuchsia.diagnostics.AllowSerialLogs"))
-        .capability(Capability::configuration("fuchsia.diagnostics.DenySerialLogs"))
-        .capability(Capability::configuration("fuchsia.diagnostics.LogToDebuglog"));
-
-    let logs_max_cached_original_bytes_config_capability =
-        Capability::configuration("fuchsia.diagnostics.LogsMaxCachedOriginalBytes");
-    if opts.archivist_config.logs_max_cached_original_bytes.is_none() {
-        void_to_archivist =
-            void_to_archivist.capability(logs_max_cached_original_bytes_config_capability);
-    } else {
-        self_to_archivist =
-            self_to_archivist.capability(logs_max_cached_original_bytes_config_capability);
-    }
-
-    builder.add_route(self_to_archivist.clone().from(Ref::self_()).to(&test_realm)).await?;
-    test_realm.add_route(self_to_archivist.from(Ref::parent()).to(&archivist)).await?;
-    test_realm.add_route(void_to_archivist.from(Ref::void()).to(&archivist)).await?;
-
-    let parent_to_archivist = Route::new()
-        .capability(Capability::protocol_by_name("fuchsia.boot.ReadOnlyLog"))
-        .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
-        .capability(Capability::protocol_by_name("fuchsia.tracing.provider.Registry").optional());
-
-    builder.add_route(parent_to_archivist.clone().from(Ref::parent()).to(&test_realm)).await?;
-    test_realm.add_route(parent_to_archivist.from(Ref::parent()).to(&archivist)).await?;
-
-    let archivist_to_parent = Route::new()
-        .capability(Capability::protocol_by_name("fuchsia.diagnostics.ArchiveAccessor"))
-        .capability(Capability::protocol_by_name("fuchsia.diagnostics.FeedbackArchiveAccessor"))
-        .capability(Capability::protocol_by_name("fuchsia.diagnostics.LoWPANArchiveAccessor"))
-        .capability(Capability::protocol_by_name("fuchsia.diagnostics.LogSettings"))
-        .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
-        .capability(Capability::protocol_by_name("fuchsia.inspect.InspectSink"))
-        .capability(Capability::protocol_by_name("fuchsia.logger.Log"));
-    test_realm.add_route(archivist_to_parent.clone().from(&archivist).to(Ref::parent())).await?;
-    builder.add_route(archivist_to_parent.from(&test_realm).to(Ref::parent())).await?;
-
-    Ok((builder, test_realm))
-}
-
-pub async fn add_eager_child(
-    test_realm: &SubRealmBuilder,
-    name: &str,
-    url: &str,
-) -> Result<ChildRef, Error> {
-    let child_ref = test_realm.add_child(name, url, ChildOptions::new().eager()).await?;
-    test_realm
-        .add_route(
-            Route::new()
-                .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
-                .capability(Capability::protocol_by_name("fuchsia.inspect.InspectSink"))
-                .from(Ref::child("archivist"))
-                .to(&child_ref),
-        )
-        .await?;
-    Ok(child_ref)
-}
-
-pub async fn add_collection(test_realm: &SubRealmBuilder, name: &str) -> Result<(), Error> {
-    let mut decl = test_realm.get_realm_decl().await?;
-    decl.collections.push(cm_rust::CollectionDecl {
-        name: name.parse().unwrap(),
-        durability: fdecl::Durability::Transient,
-        environment: None,
-        allowed_offers: cm_types::AllowedOffers::StaticOnly,
-        allow_long_names: false,
-        persistent_storage: None,
-    });
-    test_realm.replace_realm_decl(decl).await?;
-    test_realm
-        .add_route(
-            Route::new()
-                .capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
-                .capability(Capability::protocol_by_name("fuchsia.inspect.InspectSink"))
-                .from(Ref::child("archivist"))
-                .to(Ref::collection(name)),
-        )
-        .await?;
-    Ok(())
-}
-
-pub async fn expose_test_realm_protocol(builder: &RealmBuilder, test_realm: &SubRealmBuilder) {
-    test_realm
-        .add_route(
-            Route::new()
-                .capability(Capability::protocol_by_name("fuchsia.component.Realm"))
-                .from(Ref::framework())
-                .to(Ref::parent()),
-        )
-        .await
-        .unwrap();
-    builder
-        .add_route(
-            Route::new()
-                .capability(Capability::protocol_by_name("fuchsia.component.Realm"))
-                .from(Ref::child("test"))
-                .to(Ref::parent()),
-        )
-        .await
-        .unwrap();
-}
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/BUILD.gn b/src/diagnostics/archivist/tests/integration/test_cases/BUILD.gn
new file mode 100644
index 0000000..0dc09be
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/BUILD.gn
@@ -0,0 +1,93 @@
+# Copyrigh 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/components.gni")
+import("//build/rust/rustc_binary.gni")
+import("//build/rust/rustc_test.gni")
+import("//src/diagnostics/archivist/build/pipeline.gni")
+
+rustc_test("bin") {
+  output_name = "archivist_integration_test_cases"
+  edition = "2021"
+  deps = [
+    "../realm_factory/fidl:fuchsia.archivist.test_rust",
+    "//sdk/fidl/fuchsia.diagnostics:fuchsia.diagnostics_rust",
+    "//sdk/fidl/fuchsia.logger:fuchsia.logger_rust",
+    "//sdk/fidl/fuchsia.testing.harness:fuchsia.testing.harness_rust",
+    "//src/diagnostics/archivist:lib",
+    "//src/lib/diagnostics/data/rust",
+    "//src/lib/diagnostics/log/rust",
+    "//src/lib/diagnostics/reader/rust",
+    "//src/lib/diagnostics/selectors",
+    "//src/lib/diagnostics/testing/diagnostics-assertions/rust:diagnostics-assertions",
+    "//src/lib/fidl/rust/fidl",
+    "//src/lib/fuchsia",
+    "//src/lib/fuchsia-async",
+    "//src/lib/fuchsia-component",
+    "//src/lib/syslog/rust:syslog-listener",
+    "//src/lib/zircon/rust:fuchsia-zircon",
+    "//src/sys/lib/component-events",
+    "//src/testing/realm_proxy/client",
+    "//third_party/rust_crates:anyhow",
+    "//third_party/rust_crates:async-trait",
+    "//third_party/rust_crates:difference",
+    "//third_party/rust_crates:futures",
+    "//third_party/rust_crates:itertools",
+    "//third_party/rust_crates:lazy_static",
+    "//third_party/rust_crates:rand",
+    "//third_party/rust_crates:serde_json",
+    "//third_party/rust_crates:tracing",
+  ]
+
+  sources = [
+    "src/assert.rs",
+    "src/inspect/mod.rs",
+    "src/inspect/reader.rs",
+    "src/inspect/recursive_glob.rs",
+    "src/inspect/truncation.rs",
+    "src/lib.rs",
+    "src/logs/attribution.rs",
+    "src/logs/basic.rs",
+    "src/logs/budget.rs",
+    "src/logs/crash.rs",
+    "src/logs/interest.rs",
+    "src/logs/lifecycle.rs",
+    "src/logs/lifecycle_stop.rs",
+    "src/logs/mod.rs",
+    "src/logs/selectors.rs",
+    "src/logs/sorting.rs",
+    "src/logs/utils.rs",
+    "src/puppet.rs",
+    "src/test_topology.rs",
+    "src/utils.rs",
+  ]
+  inputs = [
+    "test_data/empty_result_golden.json",
+    "test_data/unified_reader_all_golden.json",
+    "test_data/pipeline_reader_all_golden.json",
+    "test_data/unified_reader_full_filter_golden.json",
+    "test_data/pipeline_reader_nonoverlapping_selectors_golden.json",
+    "test_data/unified_reader_single_value_golden.json",
+    "test_data/pipeline_reader_single_value_golden.json",
+  ]
+  configs += [ "//build/config/rust/lints:clippy_warn_all" ]
+}
+
+fuchsia_component("archivist_integration_test_cases_component") {
+  testonly = true
+  component_name = "test_cases"
+  deps = [ ":bin" ]
+  manifest = "meta/test_cases.cml"
+}
+
+fuchsia_package("pkg") {
+  testonly = true
+  package_name = "archivist_integration_test_cases"
+  deps = [
+    ":archivist_integration_test_cases_component",
+    "../realm_factory:archivist_component",
+    "../realm_factory:archivist_config",
+  ]
+  subpackages = [ "../realm_factory:pkg" ]
+}
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/meta/test_cases.cml b/src/diagnostics/archivist/tests/integration/test_cases/meta/test_cases.cml
new file mode 100644
index 0000000..5c8419e
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/meta/test_cases.cml
@@ -0,0 +1,25 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "//src/sys/test_runners/rust/default.shard.cml",
+        "//src/testing/realm_proxy/client/meta/realm_proxy.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/archivist_integration_test_cases",
+    },
+    use: [
+        {
+            protocol: [
+                "fuchsia.archivist.test.RealmFactory",
+                "fuchsia.logger.Log",
+            ],
+        },
+        {
+            event_stream: "stopped",
+            from: "parent",
+        },
+    ],
+}
diff --git a/src/diagnostics/archivist/tests/integration/src/assert.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/assert.rs
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/src/assert.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/assert.rs
diff --git a/src/diagnostics/archivist/tests/integration/src/inspect/mod.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/inspect/mod.rs
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/src/inspect/mod.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/inspect/mod.rs
diff --git a/src/diagnostics/archivist/tests/integration/src/inspect/reader.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/inspect/reader.rs
similarity index 97%
rename from src/diagnostics/archivist/tests/integration/src/inspect/reader.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/inspect/reader.rs
index 3d4118f..1652b41 100644
--- a/src/diagnostics/archivist/tests/integration/src/inspect/reader.rs
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/inspect/reader.rs
@@ -77,12 +77,12 @@
 
     let puppet = test_topology::connect_to_puppet(&realm_proxy, "hanging_data").await?;
 
-    puppet.record_string("child", "value")?;
+    puppet.record_string("child", "value").await?;
 
     let lazy = puppet.record_lazy_values("lazy-node-always-hangs").await?.into_proxy()?;
-    lazy.commit(&ftest::CommitOptions { hang: Some(true), ..Default::default() })?;
+    lazy.commit(&ftest::CommitOptions { hang: Some(true), ..Default::default() }).await?;
 
-    puppet.record_int("int", 3)?;
+    puppet.record_int("int", 3).await?;
 
     let accessor = realm_proxy.connect_to_protocol::<ArchiveAccessorMarker>().await?;
     let data = ArchiveReader::new()
@@ -150,7 +150,7 @@
     .expect("create realm");
 
     let puppet = test_topology::connect_to_puppet(&realm_proxy, "puppet").await.unwrap();
-    puppet.emit_example_inspect_data().unwrap();
+    puppet.emit_example_inspect_data().await.unwrap();
 
     // First, retrieve all of the information in our realm to make sure that everything
     // we expect is present.
@@ -213,7 +213,7 @@
     .expect("create base topology");
 
     let puppet = test_topology::connect_to_puppet(&realm_proxy, "test_component").await.unwrap();
-    puppet.emit_example_inspect_data().unwrap();
+    puppet.emit_example_inspect_data().await.unwrap();
 
     // First, retrieve all of the information in our realm to make sure that everything
     // we expect is present.
@@ -267,7 +267,7 @@
     .expect("create base topology");
 
     let puppet = test_topology::connect_to_puppet(&realm_proxy, "test_component").await.unwrap();
-    puppet.emit_example_inspect_data().unwrap();
+    puppet.emit_example_inspect_data().await.unwrap();
 
     assert!(!pipeline_is_filtered(realm_proxy, 2, constants::FEEDBACK_ARCHIVE_ACCESSOR_NAME).await);
 
@@ -285,7 +285,7 @@
     .expect("create base topology");
 
     let puppet = test_topology::connect_to_puppet(&realm_proxy, "test_component").await.unwrap();
-    puppet.emit_example_inspect_data().unwrap();
+    puppet.emit_example_inspect_data().await.unwrap();
 
     assert!(!pipeline_is_filtered(realm_proxy, 2, constants::FEEDBACK_ARCHIVE_ACCESSOR_NAME).await);
 
@@ -306,7 +306,7 @@
     .expect("create base topology");
 
     let puppet = test_topology::connect_to_puppet(&realm_proxy, "test_component").await.unwrap();
-    puppet.emit_example_inspect_data().unwrap();
+    puppet.emit_example_inspect_data().await.unwrap();
 
     // First, retrieve all of the information in our realm to make sure that everything
     // we expect is present.
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/src/inspect/recursive_glob.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/inspect/recursive_glob.rs
new file mode 100644
index 0000000..640d73a
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/inspect/recursive_glob.rs
@@ -0,0 +1,133 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::test_topology;
+use diagnostics_assertions::{assert_data_tree, AnyProperty};
+use diagnostics_reader::{ArchiveReader, Inspect};
+use fidl::endpoints::DiscoverableProtocolMarker;
+use fidl_fuchsia_archivist_test as ftest;
+use fidl_fuchsia_diagnostics::ArchiveAccessorMarker;
+use realm_proxy_client::RealmProxyClient;
+use std::collections::HashSet;
+
+#[fuchsia::test]
+async fn read_components_recursive_glob() {
+    let realm_proxy = test_topology::create_realm(ftest::RealmOptions {
+        puppets: Some(vec![
+            test_topology::PuppetDeclBuilder::new("child_a").into(),
+            test_topology::PuppetDeclBuilder::new("child_b").into(),
+        ]),
+        ..Default::default()
+    })
+    .await
+    .unwrap();
+
+    // Only inspect from descendants of child_a should be reported
+    let expected_monikers = HashSet::from_iter(vec![
+        "child_a/nested_one".to_string(),
+        "child_a/nested_two".to_string(),
+    ]);
+
+    let puppet_a = test_topology::connect_to_puppet(&realm_proxy, "child_a").await.unwrap();
+    puppet_a.set_health_ok().await.unwrap();
+    let puppet_b = test_topology::connect_to_puppet(&realm_proxy, "child_b").await.unwrap();
+    puppet_b.set_health_ok().await.unwrap();
+
+    expose_nested_inspect(&realm_proxy, "child_a", "nested_one").await;
+    expose_nested_inspect(&realm_proxy, "child_a", "nested_two").await;
+    expose_nested_inspect(&realm_proxy, "child_b", "nested_one").await;
+    expose_nested_inspect(&realm_proxy, "child_b", "nested_two").await;
+
+    let accessor = realm_proxy.connect_to_protocol::<ArchiveAccessorMarker>().await.unwrap();
+    let data_vec = ArchiveReader::new()
+        .add_selector("child_a/**:root")
+        .with_archive(accessor)
+        .with_minimum_schema_count(expected_monikers.len())
+        .snapshot::<Inspect>()
+        .await
+        .expect("got inspect data");
+
+    assert_eq!(data_vec.len(), expected_monikers.len());
+    let mut found_monikers = HashSet::new();
+    for data in data_vec {
+        assert_data_tree!(data.payload.as_ref().unwrap(), root: {
+            "fuchsia.inspect.Health": {
+                status: "OK",
+                start_timestamp_nanos: AnyProperty,
+            }
+        });
+        found_monikers.replace(data.moniker);
+    }
+    assert_eq!(expected_monikers, found_monikers);
+}
+
+#[fuchsia::test]
+async fn read_components_subtree_with_recursive_glob() {
+    let realm_proxy = test_topology::create_realm(ftest::RealmOptions {
+        puppets: Some(vec![
+            test_topology::PuppetDeclBuilder::new("child_a").into(),
+            test_topology::PuppetDeclBuilder::new("child_b").into(),
+        ]),
+        ..Default::default()
+    })
+    .await
+    .unwrap();
+
+    let puppet_a = test_topology::connect_to_puppet(&realm_proxy, "child_a").await.unwrap();
+    puppet_a.set_health_ok().await.unwrap();
+    let puppet_b = test_topology::connect_to_puppet(&realm_proxy, "child_b").await.unwrap();
+    puppet_b.set_health_ok().await.unwrap();
+
+    expose_nested_inspect(&realm_proxy, "child_a", "nested_one").await;
+    expose_nested_inspect(&realm_proxy, "child_a", "nested_two").await;
+    expose_nested_inspect(&realm_proxy, "child_b", "nested_one").await;
+    expose_nested_inspect(&realm_proxy, "child_b", "nested_two").await;
+
+    // Only inspect from test_app_a, and descendants of test_app_a should be reported
+    let expected_monikers = HashSet::from_iter(vec![
+        "child_a".to_string(),
+        "child_a/nested_one".to_string(),
+        "child_a/nested_two".to_string(),
+    ]);
+
+    let accessor = realm_proxy.connect_to_protocol::<ArchiveAccessorMarker>().await.unwrap();
+    let data_vec = ArchiveReader::new()
+        .add_selector("child_a/**:root")
+        .add_selector("child_a:root")
+        .with_archive(accessor)
+        .with_minimum_schema_count(expected_monikers.len())
+        .snapshot::<Inspect>()
+        .await
+        .expect("got inspect data");
+
+    assert_eq!(data_vec.len(), expected_monikers.len());
+    let mut found_monikers = HashSet::new();
+    for data in data_vec {
+        if data.payload.is_none() {
+            tracing::error!("UNEXPECTED EMPTY PAYLOAD: {data:?}");
+        }
+        assert_data_tree!(data.payload.as_ref().unwrap(), root: {
+            "fuchsia.inspect.Health": {
+                status: "OK",
+                start_timestamp_nanos: AnyProperty,
+            }
+        });
+        found_monikers.replace(data.moniker);
+    }
+    assert_eq!(expected_monikers, found_monikers);
+}
+
+async fn expose_nested_inspect(
+    realm_proxy: &RealmProxyClient,
+    puppet_name: &str,
+    nested_puppet_name: &str,
+) {
+    let puppet_protocol_alias =
+        format!("{}.{puppet_name}.{nested_puppet_name}", ftest::InspectPuppetMarker::PROTOCOL_NAME);
+    let puppet_inspect = realm_proxy
+        .connect_to_named_protocol::<ftest::InspectPuppetMarker>(&puppet_protocol_alias)
+        .await
+        .expect("failed to connect to nested inspect puppet");
+    puppet_inspect.set_health_ok().await.expect("set health to ok");
+}
diff --git a/src/diagnostics/archivist/tests/integration/src/inspect/truncation.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/inspect/truncation.rs
similarity index 98%
rename from src/diagnostics/archivist/tests/integration/src/inspect/truncation.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/inspect/truncation.rs
index 06ac4b7..f7d9938 100644
--- a/src/diagnostics/archivist/tests/integration/src/inspect/truncation.rs
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/inspect/truncation.rs
@@ -23,7 +23,7 @@
     for (i, x) in itertools::iproduct!(0..3, letters.iter()) {
         let puppet =
             test_topology::connect_to_puppet(&realm_proxy, &format!("child_{x}{i}")).await.unwrap();
-        puppet.emit_example_inspect_data().unwrap();
+        puppet.emit_example_inspect_data().await.unwrap();
     }
 
     let accessor = realm_proxy.connect_to_protocol::<ArchiveAccessorMarker>().await.unwrap();
diff --git a/src/diagnostics/archivist/tests/integration/src/lib.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/lib.rs
similarity index 93%
rename from src/diagnostics/archivist/tests/integration/src/lib.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/lib.rs
index f2e667df..1660cec 100644
--- a/src/diagnostics/archivist/tests/integration/src/lib.rs
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/lib.rs
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 mod assert;
-mod constants;
 mod inspect;
 mod logs;
 mod puppet;
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/src/logs/attribution.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/attribution.rs
new file mode 100644
index 0000000..155e061
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/attribution.rs
@@ -0,0 +1,54 @@
+// Copyright 2020 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::test_topology;
+use diagnostics_assertions::assert_data_tree;
+use diagnostics_reader::{ArchiveReader, Logs, Severity};
+use fidl_fuchsia_archivist_test as ftest;
+use fidl_fuchsia_archivist_test::LogPuppetLogRequest;
+use fidl_fuchsia_diagnostics as fdiagnostics;
+use futures::StreamExt;
+
+// This test verifies that Archivist knows about logging from this component.
+#[fuchsia::test]
+async fn log_attribution() {
+    const REALM_NAME: &str = "child";
+    let realm = test_topology::create_realm(ftest::RealmOptions {
+        puppets: Some(vec![test_topology::PuppetDeclBuilder::new(REALM_NAME).into()]),
+        ..Default::default()
+    })
+    .await
+    .expect("create base topology");
+
+    let accessor =
+        realm.connect_to_protocol::<fdiagnostics::ArchiveAccessorMarker>().await.unwrap();
+    let mut result = ArchiveReader::new()
+        .with_archive(accessor)
+        .snapshot_then_subscribe::<Logs>()
+        .expect("snapshot then subscribe");
+
+    let puppet = test_topology::connect_to_puppet(&realm, REALM_NAME).await.unwrap();
+    let messages = ["This is a syslog message", "This is another syslog message"];
+    for message in messages {
+        puppet
+            .log(&LogPuppetLogRequest {
+                severity: Some(fdiagnostics::Severity::Info),
+                message: Some(message.to_string()),
+                ..Default::default()
+            })
+            .await
+            .expect("Log succeeds");
+    }
+
+    for log_str in &messages {
+        let log_record = result.next().await.expect("received log").expect("log is not an error");
+        assert_eq!(log_record.moniker, REALM_NAME);
+        assert_eq!(log_record.metadata.severity, Severity::Info);
+        assert_data_tree!(log_record.payload.unwrap(), root: contains {
+            message: {
+              value: log_str.to_string(),
+            }
+        });
+    }
+}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/basic.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/basic.rs
similarity index 98%
rename from src/diagnostics/archivist/tests/integration/src/logs/basic.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/logs/basic.rs
index 2043a9a..30dea9b 100644
--- a/src/diagnostics/archivist/tests/integration/src/logs/basic.rs
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/basic.rs
@@ -117,12 +117,12 @@
     assert_eq!(Some(Severity::Info), puppet.wait_for_interest_change().await.unwrap().severity);
 
     let msg = format!("logger_integration_rust test_klog stdout {}", rand::random::<u64>());
-    puppet.println(&msg).unwrap();
+    puppet.println(&msg).await.unwrap();
     info!("printed '{msg}' to stdout");
     logs.by_ref().filter(|m| futures::future::ready(m.msg().unwrap() == msg)).next().await;
 
     let msg = format!("logger_integration_rust test_klog stderr {}", rand::random::<u64>());
-    puppet.eprintln(&msg).unwrap();
+    puppet.eprintln(&msg).await.unwrap();
     info!("Printed '{msg}' to stderr");
     logs.filter(|m| futures::future::ready(m.msg().unwrap() == msg)).next().await;
 
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/src/logs/budget.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/budget.rs
new file mode 100644
index 0000000..92a06de
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/budget.rs
@@ -0,0 +1,91 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::test_topology;
+use diagnostics_data::Logs;
+use diagnostics_reader::{ArchiveReader, RetryConfig};
+use fidl_fuchsia_archivist_test as ftest;
+use fidl_fuchsia_diagnostics as fdiagnostics;
+use futures::StreamExt;
+
+const SPAM_COUNT: usize = 9001;
+
+#[fuchsia::test]
+async fn test_budget() {
+    let realm_proxy = test_topology::create_realm(ftest::RealmOptions {
+        puppets: Some(vec![
+            test_topology::PuppetDeclBuilder::new("spammer").into(),
+            test_topology::PuppetDeclBuilder::new("victim").into(),
+        ]),
+        archivist_config: Some(ftest::ArchivistConfig {
+            logs_max_cached_original_bytes: Some(3000),
+            ..Default::default()
+        }),
+        ..Default::default()
+    })
+    .await
+    .unwrap();
+
+    let spammer_puppet = test_topology::connect_to_puppet(&realm_proxy, "spammer").await.unwrap();
+    let victim_puppet = test_topology::connect_to_puppet(&realm_proxy, "victim").await.unwrap();
+    spammer_puppet.wait_for_interest_change().await.unwrap();
+    victim_puppet.wait_for_interest_change().await.unwrap();
+
+    let letters = ('A'..'Z').map(|c| c.to_string()).collect::<Vec<_>>();
+    let mut letters_iter = letters.iter().cycle();
+    let expected = letters_iter.next().unwrap().repeat(50);
+    victim_puppet
+        .log(&ftest::LogPuppetLogRequest {
+            severity: Some(fdiagnostics::Severity::Info),
+            message: Some(expected.clone()),
+            ..Default::default()
+        })
+        .await
+        .expect("emitted log");
+
+    let accessor =
+        realm_proxy.connect_to_protocol::<fdiagnostics::ArchiveAccessorMarker>().await.unwrap();
+    let mut log_reader = ArchiveReader::new();
+    log_reader
+        .with_archive(accessor)
+        .with_minimum_schema_count(0) // we want this to return even when no log messages
+        .retry(RetryConfig::never());
+
+    let (mut observed_logs, _errors) =
+        log_reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams();
+    let (mut observed_logs_2, _errors) =
+        log_reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams();
+
+    let msg_a = observed_logs.next().await.unwrap();
+    let msg_a_2 = observed_logs_2.next().await.unwrap();
+    assert_eq!(expected, msg_a.msg().unwrap());
+    assert_eq!(expected, msg_a_2.msg().unwrap());
+
+    // Spam many logs.
+    for _ in 0..SPAM_COUNT {
+        let message = letters_iter.next().unwrap().repeat(50);
+        spammer_puppet
+            .log(&ftest::LogPuppetLogRequest {
+                severity: Some(fdiagnostics::Severity::Info),
+                message: Some(message.clone()),
+                ..Default::default()
+            })
+            .await
+            .expect("emitted log");
+        assert_eq!(message, observed_logs.next().await.unwrap().msg().unwrap());
+    }
+
+    // We observe some logs were rolled out.
+    let log = observed_logs_2.skip(33).next().await.unwrap();
+    assert_eq!(log.rolled_out_logs(), Some(8946));
+    let mut observed_logs = log_reader.snapshot::<Logs>().await.unwrap().into_iter();
+    let msg_b = observed_logs.next().unwrap();
+    assert!(!msg_b.moniker.contains("puppet-victim"));
+
+    // Vicitm logs should have been rolled out.
+    let messages =
+        observed_logs.filter(|log| log.moniker.contains("puppet-victim")).collect::<Vec<_>>();
+    assert!(messages.is_empty());
+    assert_ne!(msg_a.msg().unwrap(), msg_b.msg().unwrap());
+}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/crash.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/crash.rs
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/src/logs/crash.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/logs/crash.rs
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/interest.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/interest.rs
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/src/logs/interest.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/logs/interest.rs
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/src/logs/lifecycle.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/lifecycle.rs
new file mode 100644
index 0000000..b0078fb
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/lifecycle.rs
@@ -0,0 +1,74 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::test_topology;
+use diagnostics_assertions::assert_data_tree;
+use diagnostics_reader::{ArchiveReader, Data, Logs, RetryConfig};
+use fidl_fuchsia_archivist_test as ftest;
+use fidl_fuchsia_archivist_test::LogPuppetLogRequest;
+use fidl_fuchsia_diagnostics::{ArchiveAccessorMarker, Severity};
+use fuchsia_async as fasync;
+use futures::StreamExt;
+
+const HELLO_WORLD: &str = "Hello, world!";
+
+#[fuchsia::test]
+async fn test_logs_lifecycle() {
+    let mut puppets = Vec::with_capacity(12);
+    for i in 0..50 {
+        puppets.push(test_topology::PuppetDeclBuilder::new(format!("puppet{i}")).into());
+    }
+    let realm = test_topology::create_realm(ftest::RealmOptions {
+        puppets: Some(puppets),
+        ..Default::default()
+    })
+    .await
+    .expect("create base topology");
+
+    let accessor = realm.connect_to_protocol::<ArchiveAccessorMarker>().await.unwrap();
+
+    let mut reader = ArchiveReader::new();
+    reader
+        .with_archive(accessor)
+        .with_minimum_schema_count(0) // we want this to return even when no log messages
+        .retry(RetryConfig::never());
+
+    let (mut subscription, mut errors) =
+        reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams();
+    let _log_errors = fasync::Task::spawn(async move {
+        if let Some(error) = errors.next().await {
+            panic!("{error:#?}");
+        }
+    });
+
+    reader.retry(RetryConfig::EMPTY);
+    for i in 0..50 {
+        let puppet_name = format!("puppet{i}");
+        let puppet = test_topology::connect_to_puppet(&realm, &puppet_name).await.unwrap();
+        let request = LogPuppetLogRequest {
+            severity: Some(Severity::Info),
+            message: Some(HELLO_WORLD.to_string()),
+            ..Default::default()
+        };
+        puppet.log(&request).await.expect("Log succeeds");
+
+        check_message(&puppet_name, subscription.next().await.unwrap());
+
+        reader.with_minimum_schema_count(i);
+        let all_messages = reader.snapshot::<Logs>().await.unwrap();
+
+        for message in all_messages {
+            check_message("puppet", message);
+        }
+    }
+}
+
+fn check_message(expected_moniker_prefix: &str, message: Data<Logs>) {
+    assert!(message.moniker.starts_with(expected_moniker_prefix));
+    assert_data_tree!(message.payload.unwrap(), root: {
+        message: {
+            value: HELLO_WORLD,
+        }
+    });
+}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/lifecycle_stop.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/lifecycle_stop.rs
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/src/logs/lifecycle_stop.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/logs/lifecycle_stop.rs
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/mod.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/mod.rs
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/src/logs/mod.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/logs/mod.rs
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/src/logs/selectors.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/selectors.rs
new file mode 100644
index 0000000..095ba4fed
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/selectors.rs
@@ -0,0 +1,80 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::test_topology;
+use diagnostics_assertions::assert_data_tree;
+use diagnostics_reader::{ArchiveReader, Logs};
+use fidl_fuchsia_archivist_test as ftest;
+use fidl_fuchsia_archivist_test::LogPuppetLogRequest;
+use fidl_fuchsia_diagnostics::ArchiveAccessorMarker;
+use fidl_fuchsia_diagnostics::Severity;
+use fuchsia_async as fasync;
+use futures::{FutureExt, StreamExt};
+use realm_proxy_client::RealmProxyClient;
+
+const HELLO_WORLD: &'static str = "Hello, world!!!";
+
+#[fuchsia::test]
+async fn component_selectors_filter_logs() {
+    let mut puppets = Vec::with_capacity(12);
+    for i in 0..6 {
+        puppets.push(test_topology::PuppetDeclBuilder::new(format!("puppet_a{i}")).into());
+        puppets.push(test_topology::PuppetDeclBuilder::new(format!("puppet_b{i}")).into());
+    }
+    let realm = test_topology::create_realm(ftest::RealmOptions {
+        puppets: Some(puppets),
+        ..Default::default()
+    })
+    .await
+    .expect("create base topology");
+
+    let accessor = realm.connect_to_protocol::<ArchiveAccessorMarker>().await.unwrap();
+
+    // Start a few components.
+    for i in 0..3 {
+        log_and_exit(&realm, format!("puppet_a{i}")).await;
+        log_and_exit(&realm, format!("puppet_b{i}")).await;
+    }
+
+    // Start listening
+    let mut reader = ArchiveReader::new();
+    reader.add_selector("puppet_a*:root").with_archive(accessor).with_minimum_schema_count(5);
+
+    let (mut stream, mut errors) =
+        reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams();
+    let _errors = fasync::Task::spawn(async move {
+        if let Some(e) = errors.next().await {
+            panic!("error in subscription: {e}");
+        }
+    });
+
+    // Start a few more components
+    for i in 3..6 {
+        log_and_exit(&realm, format!("puppet_a{i}")).await;
+        log_and_exit(&realm, format!("puppet_b{i}")).await;
+    }
+
+    // We should see logs from components started before and after we began to listen.
+    for _ in 0..6 {
+        let log = stream.next().await.unwrap();
+        assert!(log.moniker.starts_with("puppet_a"));
+        assert_data_tree!(log.payload.unwrap(), root: {
+            message: {
+                value: HELLO_WORLD,
+            }
+        });
+    }
+    // We only expect 6 logs.
+    assert!(stream.next().now_or_never().is_none());
+}
+
+async fn log_and_exit(realm: &RealmProxyClient, puppet_name: String) {
+    let puppet = test_topology::connect_to_puppet(&realm, &puppet_name).await.unwrap();
+    let request = LogPuppetLogRequest {
+        severity: Some(Severity::Info),
+        message: Some(HELLO_WORLD.to_string()),
+        ..Default::default()
+    };
+    puppet.log(&request).await.expect("Log succeeds");
+}
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/src/logs/sorting.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/sorting.rs
new file mode 100644
index 0000000..7759d61
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/sorting.rs
@@ -0,0 +1,120 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::test_topology;
+use diagnostics_data::{Data, Logs};
+use diagnostics_reader::{ArchiveReader, Subscription};
+use fidl_fuchsia_archivist_test as ftest;
+use fidl_fuchsia_diagnostics as fdiagnostics;
+use futures::StreamExt;
+use realm_proxy_client::RealmProxyClient;
+
+#[fuchsia::test]
+async fn timestamp_sorting_for_batches() {
+    let realm_proxy = test_topology::create_realm(ftest::RealmOptions {
+        puppets: Some(vec![
+            test_topology::PuppetDeclBuilder::new("tort").into(),
+            test_topology::PuppetDeclBuilder::new("hare").into(),
+        ]),
+        ..Default::default()
+    })
+    .await
+    .unwrap();
+
+    let child_tort = test_topology::connect_to_puppet(&realm_proxy, "tort").await.unwrap();
+    let child_hare = test_topology::connect_to_puppet(&realm_proxy, "hare").await.unwrap();
+    child_tort.wait_for_interest_change().await.unwrap();
+    child_hare.wait_for_interest_change().await.unwrap();
+
+    let hare_times = (1_000, 10_000);
+    let tort_times = (5_000, 15_000);
+
+    // connect to log_sink and make sure we have a clean slate
+    let mut early_listener = Listener::new(&realm_proxy).await;
+
+    // Log to tortoise
+    child_tort.log(&log_message(tort_times.0)).await.expect("logged");
+    let mut expected_dump = vec![(tort_times.0, "tort".to_string())];
+    early_listener.check_next(tort_times.0, "tort").await;
+    check_log_snapshot(&realm_proxy, &expected_dump).await;
+
+    // Log to hare
+    child_hare.log(&log_message(hare_times.0)).await.expect("logged");
+    expected_dump.push((hare_times.0, "hare".to_string()));
+    expected_dump.sort_by_key(|(time, _)| *time);
+
+    early_listener.check_next(hare_times.0, "hare").await;
+    check_log_snapshot(&realm_proxy, &expected_dump).await;
+
+    // start a new listener and make sure it gets backlog reversed from early listener
+    let mut middle_listener = Listener::new(&realm_proxy).await;
+    middle_listener.check_next(hare_times.0, "hare").await;
+    middle_listener.check_next(tort_times.0, "tort").await;
+
+    // send the second tortoise message and assert it's seen
+    child_tort.log(&log_message(tort_times.1)).await.expect("logged");
+    expected_dump.push((tort_times.1, "tort".to_string()));
+    expected_dump.sort_by_key(|(time, _)| *time);
+    early_listener.check_next(tort_times.1, "tort").await;
+    middle_listener.check_next(tort_times.1, "tort").await;
+    check_log_snapshot(&realm_proxy, &expected_dump).await;
+
+    // send the second hare message and assert it's seen
+    child_hare.log(&log_message(hare_times.1)).await.expect("logged");
+    expected_dump.push((hare_times.1, "hare".to_string()));
+    expected_dump.sort_by_key(|(time, _)| *time);
+    early_listener.check_next(hare_times.1, "hare").await;
+    middle_listener.check_next(hare_times.1, "hare").await;
+    check_log_snapshot(&realm_proxy, &expected_dump).await;
+
+    // listening after all messages were seen by archivist-for-embedding should be time-ordered
+    let mut final_listener = Listener::new(&realm_proxy).await;
+    final_listener.check_next(hare_times.0, "hare").await;
+    final_listener.check_next(tort_times.0, "tort").await;
+    final_listener.check_next(hare_times.1, "hare").await;
+    final_listener.check_next(tort_times.1, "tort").await;
+}
+
+struct Listener {
+    stream: Subscription<Data<Logs>>,
+}
+
+impl Listener {
+    async fn new(realm_proxy: &RealmProxyClient) -> Self {
+        let accessor =
+            realm_proxy.connect_to_protocol::<fdiagnostics::ArchiveAccessorMarker>().await.unwrap();
+        let stream = ArchiveReader::new()
+            .with_archive(accessor)
+            .snapshot_then_subscribe::<Logs>()
+            .expect("snapshot then subscribe");
+        Self { stream }
+    }
+
+    async fn check_next(&mut self, time: i64, expected_moniker: &str) {
+        let log = self.stream.next().await.unwrap().unwrap();
+        assert_eq!(log.msg().unwrap(), "timing log");
+        assert_eq!(log.metadata.timestamp, time);
+        assert_eq!(log.moniker, expected_moniker);
+    }
+}
+
+fn log_message(time: i64) -> ftest::LogPuppetLogRequest {
+    ftest::LogPuppetLogRequest {
+        severity: Some(fdiagnostics::Severity::Info),
+        time: Some(time),
+        message: Some("timing log".into()),
+        ..Default::default()
+    }
+}
+
+async fn check_log_snapshot(realm_proxy: &RealmProxyClient, expected_dump: &Vec<(i64, String)>) {
+    let accessor =
+        realm_proxy.connect_to_protocol::<fdiagnostics::ArchiveAccessorMarker>().await.unwrap();
+    let logs = ArchiveReader::new().with_archive(accessor).snapshot::<Logs>().await.unwrap();
+    let result = logs
+        .into_iter()
+        .map(|log| (log.metadata.timestamp, log.moniker.clone()))
+        .collect::<Vec<_>>();
+    assert_eq!(result, *expected_dump);
+}
diff --git a/src/diagnostics/archivist/tests/integration/src/logs/utils.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/logs/utils.rs
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/src/logs/utils.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/logs/utils.rs
diff --git a/src/diagnostics/archivist/tests/integration/src/puppet.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/puppet.rs
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/src/puppet.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/puppet.rs
diff --git a/src/diagnostics/archivist/tests/integration/test_cases/src/test_topology.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/test_topology.rs
new file mode 100644
index 0000000..6785b2c
--- /dev/null
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/test_topology.rs
@@ -0,0 +1,52 @@
+// Copyright 2021 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use anyhow::{Context, Result};
+use fidl::endpoints::{create_endpoints, DiscoverableProtocolMarker, ProtocolMarker};
+use fidl_fuchsia_archivist_test as ftest;
+use fidl_fuchsia_testing_harness as fharness;
+use fuchsia_component::client::connect_to_protocol;
+use realm_proxy_client::RealmProxyClient;
+
+/// Creates a new test realm with an archivist inside.
+/// `options_fn` is called with a default RealmOptions struct and can modify any options
+/// before the realm is created.
+pub async fn create_realm(options: ftest::RealmOptions) -> Result<RealmProxyClient> {
+    let realm_factory = connect_to_protocol::<ftest::RealmFactoryMarker>()?;
+    let (client, server) = create_endpoints::<fharness::RealmProxy_Marker>();
+    realm_factory
+        .create_realm(&options, server)
+        .await?
+        .map_err(realm_proxy_client::Error::OperationError)?;
+    Ok(RealmProxyClient::from(client))
+}
+
+// Helper type for constructing `PuppetDecl`.
+pub(crate) struct PuppetDeclBuilder {
+    name: String,
+}
+
+impl PuppetDeclBuilder {
+    pub fn new(name: impl Into<String>) -> Self {
+        Self { name: name.into() }
+    }
+}
+
+impl Into<ftest::PuppetDecl> for PuppetDeclBuilder {
+    fn into(self) -> ftest::PuppetDecl {
+        ftest::PuppetDecl { name: Some(self.name), ..Default::default() }
+    }
+}
+
+/// Connects to the puppet in the test realm with the given name.
+pub async fn connect_to_puppet(
+    realm_proxy: &RealmProxyClient,
+    puppet_name: &str,
+) -> Result<<ftest::PuppetMarker as ProtocolMarker>::Proxy> {
+    let puppet_protocol_alias = format!("{}.{puppet_name}", ftest::PuppetMarker::PROTOCOL_NAME);
+    realm_proxy
+        .connect_to_named_protocol::<ftest::PuppetMarker>(&puppet_protocol_alias)
+        .await
+        .with_context(|| format!("failed to connect to {puppet_name}"))
+}
diff --git a/src/diagnostics/archivist/tests/integration/src/utils.rs b/src/diagnostics/archivist/tests/integration/test_cases/src/utils.rs
similarity index 84%
rename from src/diagnostics/archivist/tests/integration/src/utils.rs
rename to src/diagnostics/archivist/tests/integration/test_cases/src/utils.rs
index 314fb4d..016bc7c 100644
--- a/src/diagnostics/archivist/tests/integration/src/utils.rs
+++ b/src/diagnostics/archivist/tests/integration/test_cases/src/utils.rs
@@ -36,21 +36,6 @@
         .unwrap();
 }
 
-pub(crate) async fn wait_for_component_stopped_event(
-    instance_child_name: &str,
-    component: &str,
-    status_match: ExitStatusMatcher,
-    event_stream: &mut EventStream,
-) {
-    let moniker_for_match = format!("./realm_builder:{instance_child_name}/test/{component}");
-    EventMatcher::ok()
-        .stop(Some(status_match))
-        .moniker(moniker_for_match)
-        .wait::<Stopped>(event_stream)
-        .await
-        .unwrap();
-}
-
 /// Extension methods on LogSettingsProxy.
 #[async_trait::async_trait]
 pub(crate) trait LogSettingsExt {
diff --git a/src/diagnostics/archivist/tests/integration/test_data/empty_result_golden.json b/src/diagnostics/archivist/tests/integration/test_cases/test_data/empty_result_golden.json
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/test_data/empty_result_golden.json
rename to src/diagnostics/archivist/tests/integration/test_cases/test_data/empty_result_golden.json
diff --git a/src/diagnostics/archivist/tests/integration/test_data/pipeline_reader_all_golden.json b/src/diagnostics/archivist/tests/integration/test_cases/test_data/pipeline_reader_all_golden.json
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/test_data/pipeline_reader_all_golden.json
rename to src/diagnostics/archivist/tests/integration/test_cases/test_data/pipeline_reader_all_golden.json
diff --git a/src/diagnostics/archivist/tests/integration/test_data/pipeline_reader_nonoverlapping_selectors_golden.json b/src/diagnostics/archivist/tests/integration/test_cases/test_data/pipeline_reader_nonoverlapping_selectors_golden.json
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/test_data/pipeline_reader_nonoverlapping_selectors_golden.json
rename to src/diagnostics/archivist/tests/integration/test_cases/test_data/pipeline_reader_nonoverlapping_selectors_golden.json
diff --git a/src/diagnostics/archivist/tests/integration/test_data/pipeline_reader_single_value_golden.json b/src/diagnostics/archivist/tests/integration/test_cases/test_data/pipeline_reader_single_value_golden.json
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/test_data/pipeline_reader_single_value_golden.json
rename to src/diagnostics/archivist/tests/integration/test_cases/test_data/pipeline_reader_single_value_golden.json
diff --git a/src/diagnostics/archivist/tests/integration/test_data/unified_reader_all_golden.json b/src/diagnostics/archivist/tests/integration/test_cases/test_data/unified_reader_all_golden.json
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/test_data/unified_reader_all_golden.json
rename to src/diagnostics/archivist/tests/integration/test_cases/test_data/unified_reader_all_golden.json
diff --git a/src/diagnostics/archivist/tests/integration/test_data/unified_reader_full_filter_golden.json b/src/diagnostics/archivist/tests/integration/test_cases/test_data/unified_reader_full_filter_golden.json
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/test_data/unified_reader_full_filter_golden.json
rename to src/diagnostics/archivist/tests/integration/test_cases/test_data/unified_reader_full_filter_golden.json
diff --git a/src/diagnostics/archivist/tests/integration/test_data/unified_reader_single_value_golden.json b/src/diagnostics/archivist/tests/integration/test_cases/test_data/unified_reader_single_value_golden.json
similarity index 100%
rename from src/diagnostics/archivist/tests/integration/test_data/unified_reader_single_value_golden.json
rename to src/diagnostics/archivist/tests/integration/test_cases/test_data/unified_reader_single_value_golden.json
diff --git a/src/diagnostics/config/fire/projects/cpu.json5 b/src/diagnostics/config/fire/projects/cpu.json5
index 8a0ea64..a1878ec0 100644
--- a/src/diagnostics/config/fire/projects/cpu.json5
+++ b/src/diagnostics/config/fire/projects/cpu.json5
@@ -4,7 +4,7 @@
             metric_id: 1,
             metric_type: "IntHistogram",
             selector: [
-                "<component_manager>:root/stats/histograms:\\/{MONIKER}",
+                "<component_manager>:root/stats/histograms:{MONIKER}",
             ],
         },
     ],
diff --git a/src/diagnostics/lib/log-command/src/filter.rs b/src/diagnostics/lib/log-command/src/filter.rs
index 60f2ba2..4234dbd 100644
--- a/src/diagnostics/lib/log-command/src/filter.rs
+++ b/src/diagnostics/lib/log-command/src/filter.rs
@@ -98,9 +98,6 @@
     pub fn matches(&self, entry: &LogEntry) -> bool {
         match entry {
             LogEntry { data: LogData::TargetLog(data), .. } => self.match_filters_to_log_data(data),
-            LogEntry { data: LogData::SymbolizedTargetLog(data, _), .. } => {
-                self.match_filters_to_log_data(data)
-            }
         }
     }
 
@@ -227,7 +224,6 @@
 
 #[cfg(test)]
 mod test {
-    use assert_matches::assert_matches;
     use diagnostics_data::Timestamp;
     use selectors::parse_log_interest_selector;
     use std::time::Duration;
@@ -814,7 +810,7 @@
             .into()
         )));
 
-        let mut entry = make_log_entry(
+        let entry = make_log_entry(
             diagnostics_data::LogsDataBuilder::new(diagnostics_data::BuilderArgs {
                 timestamp_nanos: 0.into(),
                 component_url: Some(String::default()),
@@ -825,10 +821,6 @@
             .build()
             .into(),
         );
-        entry.data = assert_matches!(
-            entry.data.clone(),
-            LogData::TargetLog(d) => LogData::SymbolizedTargetLog(d, "symbolized".to_string())
-        );
 
         assert!(!criteria.matches(&entry));
     }
diff --git a/src/diagnostics/lib/log-command/src/lib.rs b/src/diagnostics/lib/log-command/src/lib.rs
index 68c1429..c557509 100644
--- a/src/diagnostics/lib/log-command/src/lib.rs
+++ b/src/diagnostics/lib/log-command/src/lib.rs
@@ -114,6 +114,16 @@
     Classic,
 }
 
+impl SymbolizeMode {
+    pub fn is_prettification_disabled(&self) -> bool {
+        matches!(self, SymbolizeMode::Classic)
+    }
+
+    pub fn is_symbolize_disabled(&self) -> bool {
+        matches!(self, SymbolizeMode::Off)
+    }
+}
+
 #[derive(ArgsInfo, FromArgs, Clone, Debug, PartialEq)]
 #[argh(
     subcommand,
diff --git a/src/diagnostics/lib/log-command/src/log_formatter.rs b/src/diagnostics/lib/log-command/src/log_formatter.rs
index e155feb..9d96226 100644
--- a/src/diagnostics/lib/log-command/src/log_formatter.rs
+++ b/src/diagnostics/lib/log-command/src/log_formatter.rs
@@ -35,8 +35,6 @@
 pub enum LogData {
     /// A log entry from the target
     TargetLog(LogsData),
-    /// A symbolized log (Original log, Symbolizer output)
-    SymbolizedTargetLog(LogsData, String),
 }
 
 impl LogData {
@@ -44,22 +42,12 @@
     pub fn as_target_log(&self) -> Option<&LogsData> {
         match self {
             LogData::TargetLog(log) => Some(log),
-            _ => None,
-        }
-    }
-
-    /// Gets the LogData as a symbolized log.
-    pub fn as_symbolized_log(&self) -> Option<(&LogsData, &String)> {
-        match self {
-            LogData::SymbolizedTargetLog(log, message) => Some((log, message)),
-            _ => None,
         }
     }
 
     pub fn as_target_log_mut(&mut self) -> Option<&mut LogsData> {
         match self {
             LogData::TargetLog(log) => Some(log),
-            _ => None,
         }
     }
 }
@@ -193,18 +181,11 @@
     pub since: Option<DeviceOrLocalTimestamp>,
     /// Only display logs until the specified time.
     pub until: Option<DeviceOrLocalTimestamp>,
-    /// If true, displays "raw" logs without symbolization.
-    pub raw: bool,
 }
 
 impl Default for LogFormatterOptions {
     fn default() -> Self {
-        LogFormatterOptions {
-            display: Some(Default::default()),
-            raw: false,
-            since: None,
-            until: None,
-        }
+        LogFormatterOptions { display: Some(Default::default()), since: None, until: None }
     }
 }
 
@@ -260,11 +241,6 @@
             }
             None => {
                 match log_entry {
-                    LogEntry { data: LogData::SymbolizedTargetLog(_, ref symbolized), .. } => {
-                        if !self.options.raw && symbolized.is_empty() {
-                            return Ok(());
-                        }
-                    }
                     _ => {}
                 }
                 self.writer.item(&log_entry)?;
@@ -361,7 +337,6 @@
                         ..Default::default()
                     })
                 },
-                raw: cmd.raw,
                 since: DeviceOrLocalTimestamp::new(
                     cmd.since.as_ref(),
                     cmd.since_monotonic.as_ref(),
@@ -413,17 +388,6 @@
                 // features listed in the design doc.
                 writeln!(self.writer, "{}", LogTextPresenter::new(&data, text_options))?;
             }
-            LogEntry { data: LogData::SymbolizedTargetLog(mut data, symbolized), .. } => {
-                if !options.raw && symbolized.is_empty() {
-                    return Ok(());
-                }
-                if !options.raw {
-                    *data.msg_mut().expect(
-                        "if a symbolized message is provided then the payload has a message",
-                    ) = symbolized;
-                }
-                writeln!(self.writer, "{}", LogTextPresenter::new(&data, text_options))?;
-            }
         })
     }
 }
@@ -486,16 +450,15 @@
     /// Symbolizer that prints "Fuchsia".
     pub struct FakeFuchsiaSymbolizer;
 
+    fn set_log_msg(entry: &mut LogEntry, msg: impl Into<String>) {
+        *entry.data.as_target_log_mut().unwrap().msg_mut().unwrap() = msg.into();
+    }
+
     #[async_trait(?Send)]
     impl Symbolize for FakeFuchsiaSymbolizer {
-        async fn symbolize(&self, entry: LogEntry) -> Option<LogEntry> {
-            Some(LogEntry {
-                data: LogData::SymbolizedTargetLog(
-                    entry.data.as_target_log().unwrap().clone(),
-                    "Fuchsia".to_string(),
-                ),
-                timestamp: entry.timestamp,
-            })
+        async fn symbolize(&self, mut entry: LogEntry) -> Option<LogEntry> {
+            set_log_msg(&mut entry, "Fuchsia");
+            Some(entry)
         }
     }
 
@@ -511,20 +474,13 @@
 
     #[async_trait(?Send)]
     impl Symbolize for FakeSymbolizerCallback {
-        async fn symbolize(&self, input: LogEntry) -> Option<LogEntry> {
+        async fn symbolize(&self, mut input: LogEntry) -> Option<LogEntry> {
             self.should_discard.set(!self.should_discard.get());
             if self.should_discard.get() {
                 None
             } else {
-                let timestamp = input.timestamp;
-                Some(LogEntry {
-                    timestamp,
-                    data: LogData::SymbolizedTargetLog(
-                        input.data.as_target_log().unwrap().clone(),
-                        "symbolized log".into(),
-                    ),
-                    ..log_entry()
-                })
+                set_log_msg(&mut input, "symbolized log");
+                Some(input)
             }
         }
     }
@@ -844,22 +800,6 @@
         );
     }
 
-    #[fuchsia::test]
-    async fn test_default_formatter_symbolized_log_message() {
-        let buffers = TestBuffers::default();
-        let stdout = MachineWriter::<LogEntry>::new_test(None, &buffers);
-        let options = LogFormatterOptions::default();
-        let mut formatter = DefaultLogFormatter::new(LogFilterCriteria::default(), stdout, options);
-        let mut entry = log_entry();
-        entry.data = assert_matches!(entry.data.clone(), LogData::TargetLog(d)=>LogData::SymbolizedTargetLog(d, "symbolized".to_string()));
-        formatter.push_log(entry).await.unwrap();
-        drop(formatter);
-        assert_eq!(
-            buffers.into_stdout_str(),
-            "[1615535969.000000][1][2][some/moniker][tag1,tag2] WARN: symbolized\n"
-        );
-    }
-
     fn emit_log(
         sender: &mut fuchsia_zircon::Socket,
         msg: &str,
@@ -884,15 +824,17 @@
     async fn test_default_formatter_discards_when_told_by_symbolizer() {
         let mut formatter = FakeFormatter::new();
         let (mut sender, receiver) = fuchsia_zircon::Socket::create_stream();
-        let target_log_0 = emit_log(&mut sender, "Hello world!", 0);
+        let mut target_log_0 = emit_log(&mut sender, "Hello world!", 0);
         emit_log(&mut sender, "Dropped world!", 1);
-        let target_log_2 = emit_log(&mut sender, "Hello world!", 2);
+        let mut target_log_2 = emit_log(&mut sender, "Hello world!", 2);
         emit_log(&mut sender, "Dropped world!", 3);
-        let target_log_4 = emit_log(&mut sender, "Hello world!", 4);
+        let mut target_log_4 = emit_log(&mut sender, "Hello world!", 4);
         drop(sender);
         // Drop every other log.
         let symbolizer = FakeSymbolizerCallback::new();
-
+        *target_log_0.msg_mut().unwrap() = "symbolized log".into();
+        *target_log_2.msg_mut().unwrap() = "symbolized log".into();
+        *target_log_4.msg_mut().unwrap() = "symbolized log".into();
         dump_logs_from_socket(
             fuchsia_async::Socket::from_socket(receiver),
             &mut formatter,
@@ -903,109 +845,22 @@
         assert_eq!(
             formatter.logs,
             vec![
-                LogEntry {
-                    data: LogData::SymbolizedTargetLog(target_log_0, "symbolized log".into()),
-                    timestamp: Timestamp::from(0)
-                },
-                LogEntry {
-                    data: LogData::SymbolizedTargetLog(target_log_2, "symbolized log".into()),
-                    timestamp: Timestamp::from(2)
-                },
-                LogEntry {
-                    data: LogData::SymbolizedTargetLog(target_log_4, "symbolized log".into()),
-                    timestamp: Timestamp::from(4)
-                }
+                LogEntry { data: LogData::TargetLog(target_log_0), timestamp: Timestamp::from(0) },
+                LogEntry { data: LogData::TargetLog(target_log_2), timestamp: Timestamp::from(2) },
+                LogEntry { data: LogData::TargetLog(target_log_4), timestamp: Timestamp::from(4) }
             ],
         );
     }
 
     #[fuchsia::test]
-    async fn test_default_formatter_symbolized_log_message_with_empty_discarded() {
-        let buffers = TestBuffers::default();
-        let stdout = MachineWriter::<LogEntry>::new_test(None, &buffers);
-        let options = LogFormatterOptions::default();
-        let mut formatter = DefaultLogFormatter::new(LogFilterCriteria::default(), stdout, options);
-        let mut entry = log_entry();
-        entry.data = match entry.data.clone() {
-            LogData::TargetLog(data) => LogData::SymbolizedTargetLog(data, "".into()),
-            _ => unreachable!(),
-        };
-        formatter.push_log(entry).await.unwrap();
-        drop(formatter);
-        assert_eq!(buffers.into_stdout_str().is_empty(), true);
-    }
-
-    #[fuchsia::test]
-    async fn test_default_formatter_symbolized_json_log_message() {
-        let buffers = TestBuffers::default();
-        let stdout = MachineWriter::<LogEntry>::new_test(Some(Format::Json), &buffers);
-        let options = LogFormatterOptions { display: None, ..Default::default() };
-        let mut formatter = DefaultLogFormatter::new(LogFilterCriteria::default(), stdout, options);
-        let mut entry = log_entry();
-        entry.data = assert_matches!(entry.data.clone(), LogData::TargetLog(d)=>LogData::SymbolizedTargetLog(d, "symbolized".to_string()));
-        formatter.push_log(entry.clone()).await.unwrap();
-        drop(formatter);
-        assert_eq!(serde_json::from_str::<LogEntry>(&buffers.into_stdout_str()).unwrap(), entry);
-    }
-
-    #[fuchsia::test]
-    async fn test_default_formatter_symbolize_failed_json_log_message() {
-        let buffers = TestBuffers::default();
-        let stdout = MachineWriter::<LogEntry>::new_test(None, &buffers);
-        let options = LogFormatterOptions { display: None, ..Default::default() };
-        let mut formatter = DefaultLogFormatter::new(LogFilterCriteria::default(), stdout, options);
-        let mut entry = log_entry();
-        entry.data = assert_matches!(entry.data.clone(), LogData::TargetLog(d)=>LogData::SymbolizedTargetLog(d, "".to_string()));
-        formatter.push_log(entry.clone()).await.unwrap();
-        drop(formatter);
-        assert_eq!(buffers.into_stdout_str().is_empty(), true);
-    }
-
-    #[fuchsia::test]
-    async fn test_raw_omits_symbolized_output() {
+    async fn test_symbolized_output() {
         let symbolizer = FakeFuchsiaSymbolizer;
         let buffers = TestBuffers::default();
         let output = MachineWriter::<LogEntry>::new_test(None, &buffers);
         let mut formatter = DefaultLogFormatter::new(
             LogFilterCriteria::default(),
             output,
-            LogFormatterOptions { raw: true, ..Default::default() },
-        );
-        formatter.set_boot_timestamp(0);
-        let target_log = LogsDataBuilder::new(diagnostics_data::BuilderArgs {
-            moniker: "ffx".into(),
-            timestamp_nanos: Timestamp::from(0),
-            component_url: Some("ffx".into()),
-            severity: Severity::Info,
-        })
-        .set_message("Hello world!")
-        .set_pid(1)
-        .set_tid(2)
-        .build();
-        let (sender, receiver) = fuchsia_zircon::Socket::create_stream();
-        sender
-            .write(serde_json::to_string(&target_log).unwrap().as_bytes())
-            .expect("failed to write target log");
-        drop(sender);
-        dump_logs_from_socket(
-            fuchsia_async::Socket::from_socket(receiver),
-            &mut formatter,
-            &symbolizer,
-        )
-        .await
-        .unwrap();
-        assert_eq!(buffers.stdout.into_string(), "[00000.000000][1][2][ffx] INFO: Hello world!\n");
-    }
-
-    #[fuchsia::test]
-    async fn test_raw_false_includes_symbolized_output() {
-        let symbolizer = FakeFuchsiaSymbolizer;
-        let buffers = TestBuffers::default();
-        let output = MachineWriter::<LogEntry>::new_test(None, &buffers);
-        let mut formatter = DefaultLogFormatter::new(
-            LogFilterCriteria::default(),
-            output,
-            LogFormatterOptions { raw: false, ..Default::default() },
+            LogFormatterOptions { ..Default::default() },
         );
         formatter.set_boot_timestamp(0);
         let target_log = LogsDataBuilder::new(diagnostics_data::BuilderArgs {
diff --git a/src/diagnostics/lib/triage/wasm/BUILD.gn b/src/diagnostics/lib/triage/wasm/BUILD.gn
index d9f38ad..789703c 100644
--- a/src/diagnostics/lib/triage/wasm/BUILD.gn
+++ b/src/diagnostics/lib/triage/wasm/BUILD.gn
@@ -46,10 +46,14 @@
     name = "triage_lib"
     edition = "2021"
 
-    configs += [
-      ":env",
-      "//build/config/lto:thinlto",
-    ]
+    configs += [ ":env" ]
+
+    # Add thinlto config if lto variants are not used.
+    if (!is_lto_variant) {
+      # Allow cross-crate optimization since netstack3 is split between multiple
+      # crates.
+      configs += [ "//build/config/lto:thinlto" ]
+    }
 
     deps = lib_deps + [ "//third_party/rust_crates:wasm-bindgen" ]
 
diff --git a/src/firmware/drivers/usb-fastboot-function/unit-tests.cc b/src/firmware/drivers/usb-fastboot-function/unit-tests.cc
index 82af8e6..399cd67 100644
--- a/src/firmware/drivers/usb-fastboot-function/unit-tests.cc
+++ b/src/firmware/drivers/usb-fastboot-function/unit-tests.cc
@@ -113,11 +113,10 @@
     device_->zxdev()->InitOp();
     ASSERT_OK(device_->zxdev()->WaitUntilInitReplyCalled(zx::time::infinite()));
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_fastboot::FastbootImpl>();
-    ASSERT_OK(endpoints.status_value());
-    client_ = fidl::WireSyncClient(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_fastboot::FastbootImpl>::Create();
+    client_ = fidl::WireSyncClient(std::move(endpoints.client));
     loop_.StartThread("usb-fastboot-function test");
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), device_);
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), device_);
   }
 
   void TearDown() override {
diff --git a/src/firmware/gigaboot/src/mdns.c b/src/firmware/gigaboot/src/mdns.c
index 14fe230..9b7d1d0 100644
--- a/src/firmware/gigaboot/src/mdns.c
+++ b/src/firmware/gigaboot/src/mdns.c
@@ -9,12 +9,13 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
-#include <zircon/compiler.h>
 
 #include "device_id.h"
 #include "inet6.h"
 #include "netifc.h"
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 #define MDNS_FLAG_QUERY_RESPONSE 0x8000
 #define MDNS_FLAG_AUTHORITATIVE 0x400
 
@@ -219,7 +220,7 @@
 
 bool mdns_write_fastboot_packet(bool finished, bool tcp, struct mdns_buf* packet_buf) {
   // Clear name segment locations.
-  for (size_t i = 0; i < countof(name_segments); ++i) {
+  for (size_t i = 0; i < ARRAY_SIZE(name_segments); ++i) {
     name_segments[i].loc = 0;
   }
 
diff --git a/src/firmware/lib/fastboot/test/fastboot-test.cc b/src/firmware/lib/fastboot/test/fastboot-test.cc
index 7075413..3d3a70c 100644
--- a/src/firmware/lib/fastboot/test/fastboot-test.cc
+++ b/src/firmware/lib/fastboot/test/fastboot-test.cc
@@ -1137,14 +1137,13 @@
   FastbootRebootTest() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
     loop_.StartThread("fastboot-reboot-test-loop");
 
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-    zx::result svc_local = component::ConnectAt<fuchsia_io::Directory>(endpoints->client, "svc");
+    zx::result svc_local = component::ConnectAt<fuchsia_io::Directory>(endpoints.client, "svc");
     ASSERT_OK(svc_local);
 
     svc_local_ = std::move(svc_local.value());
-    mock_.emplace(std::move(endpoints->server), state_);
+    mock_.emplace(std::move(endpoints.server), state_);
   }
 
   fidl::ClientEnd<fuchsia_io::Directory>& svc_chan() { return svc_local_; }
@@ -1305,14 +1304,13 @@
 
   FastbootFshostTest() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
     loop_.StartThread("fastboot-fshost-test-loop");
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-    zx::result svc_local = component::ConnectAt<fuchsia_io::Directory>(endpoints->client, "svc");
+    zx::result svc_local = component::ConnectAt<fuchsia_io::Directory>(endpoints.client, "svc");
     ASSERT_OK(svc_local);
 
     svc_local_ = std::move(svc_local.value());
-    mock_.emplace(std::move(endpoints->server), state_);
+    mock_.emplace(std::move(endpoints.server), state_);
   }
 
   fidl::ClientEnd<fuchsia_io::Directory>& svc_chan() { return svc_local_; }
@@ -1530,14 +1528,13 @@
 
   FastbootBuildInfoTest() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
     loop_.StartThread("fastboot-build-info-test-loop");
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-    zx::result svc_local = component::ConnectAt<fuchsia_io::Directory>(endpoints->client, "svc");
+    zx::result svc_local = component::ConnectAt<fuchsia_io::Directory>(endpoints.client, "svc");
     ASSERT_OK(svc_local);
 
     svc_local_ = std::move(svc_local.value());
-    mock_.emplace(std::move(endpoints->server));
+    mock_.emplace(std::move(endpoints.server));
   }
 
   fidl::ClientEnd<fuchsia_io::Directory>& svc_chan() { return svc_local_; }
diff --git a/src/firmware/lib/fastboot/test/payload-streamer-test.cc b/src/firmware/lib/fastboot/test/payload-streamer-test.cc
index b1238e9..1d79e7f 100644
--- a/src/firmware/lib/fastboot/test/payload-streamer-test.cc
+++ b/src/firmware/lib/fastboot/test/payload-streamer-test.cc
@@ -14,9 +14,7 @@
 namespace {
 TEST(PayloadStreamerTest, RegisterVmo) {
   const char data[] = "payload streamer data";
-  auto streamer_endpoints = fidl::CreateEndpoints<fuchsia_paver::PayloadStream>();
-  ASSERT_TRUE(streamer_endpoints.is_ok());
-  auto [client_end, server_end] = std::move(*streamer_endpoints);
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_paver::PayloadStream>::Create();
 
   fidl::WireSyncClient<fuchsia_paver::PayloadStream> client =
       fidl::WireSyncClient(std::move(client_end));
@@ -35,9 +33,7 @@
 
 TEST(PayloadStreamerTest, RegisterVmoAgainErrorsOut) {
   const char data[] = "payload streamer data";
-  auto streamer_endpoints = fidl::CreateEndpoints<fuchsia_paver::PayloadStream>();
-  ASSERT_TRUE(streamer_endpoints.is_ok());
-  auto [client_end, server_end] = std::move(*streamer_endpoints);
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_paver::PayloadStream>::Create();
 
   fidl::WireSyncClient<fuchsia_paver::PayloadStream> client =
       fidl::WireSyncClient(std::move(client_end));
@@ -66,9 +62,7 @@
 
 TEST(PayloadStreamerTest, ReadData) {
   const char data[] = "payload streamer data";
-  auto streamer_endpoints = fidl::CreateEndpoints<fuchsia_paver::PayloadStream>();
-  ASSERT_TRUE(streamer_endpoints.is_ok());
-  auto [client_end, server_end] = std::move(*streamer_endpoints);
+  auto [client_end, server_end] = fidl::Endpoints<fuchsia_paver::PayloadStream>::Create();
 
   fidl::WireSyncClient<fuchsia_paver::PayloadStream> client =
       fidl::WireSyncClient(std::move(client_end));
diff --git a/src/graphics/display/drivers/amlogic-display/display-engine.cc b/src/graphics/display/drivers/amlogic-display/display-engine.cc
index ecb5404..7f6b016 100644
--- a/src/graphics/display/drivers/amlogic-display/display-engine.cc
+++ b/src/graphics/display/drivers/amlogic-display/display-engine.cc
@@ -505,8 +505,8 @@
       client_composition_opcodes[0] |= CLIENT_COMPOSITION_OPCODE_ALPHA;
     }
     success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY &&
-              layer.transform_mode == FRAME_TRANSFORM_IDENTITY && layer.image.width == width &&
-              layer.image.height == height &&
+              layer.transform_mode == FRAME_TRANSFORM_IDENTITY &&
+              layer.image_metadata.width == width && layer.image_metadata.height == height &&
               memcmp(&layer.dest_frame, &frame, sizeof(frame_t)) == 0 &&
               memcmp(&layer.src_frame, &frame, sizeof(frame_t)) == 0;
   }
diff --git a/src/graphics/display/drivers/amlogic-display/video-input-unit.cc b/src/graphics/display/drivers/amlogic-display/video-input-unit.cc
index 7d41caf..548618a 100644
--- a/src/graphics/display/drivers/amlogic-display/video-input-unit.cc
+++ b/src/graphics/display/drivers/amlogic-display/video-input-unit.cc
@@ -276,7 +276,7 @@
 
 void VideoInputUnit::FlipOnVsync(const display_config_t* config,
                                  display::ConfigStamp config_stamp) {
-  auto info = reinterpret_cast<ImageInfo*>(config[0].layer_list[0]->cfg.primary.image.handle);
+  auto info = reinterpret_cast<ImageInfo*>(config[0].layer_list[0]->cfg.primary.image_handle);
   const int next_table_idx = rdma_->GetNextAvailableRdmaTableIndex();
   if (next_table_idx < 0) {
     zxlogf(ERROR, "No table available!");
diff --git a/src/graphics/display/drivers/coordinator/client.cc b/src/graphics/display/drivers/coordinator/client.cc
index 0318f2a..8440cf1 100644
--- a/src/graphics/display/drivers/coordinator/client.cc
+++ b/src/graphics/display/drivers/coordinator/client.cc
@@ -245,7 +245,7 @@
   const display::DriverBufferCollectionId driver_buffer_collection_id =
       controller_->GetNextDriverBufferCollectionId();
   zx::result<> import_result = controller_->driver()->ImportBufferCollection(
-      driver_buffer_collection_id, request->buffer_collection_token.TakeChannel());
+      driver_buffer_collection_id, std::move(request->buffer_collection_token));
   if (import_result.is_error()) {
     zxlogf(WARNING, "Cannot import BufferCollection to display driver: %s",
            import_result.status_string());
@@ -594,13 +594,23 @@
     return;
   }
 
-  const image_t* cur_image = layer->pending_image();
-  // TODO(https://fxbug.dev/42076907): Warning: Currently we only compare size and usage
-  // type between `image` and `layer`. This implicitly assume that images can
-  // be applied to any layer as long as the format is negotiated by sysmem,
-  // which may not be true in the future. We should figure out a way to better
-  // indicate pixel format support of a Layer in display Controller API.
-  if (!image.HasSameDisplayPropertiesAsLayer(*cur_image)) {
+  // TODO(https://fxbug.dev/42076907): Currently this logic only compares size
+  // and usage type between current Image and a given Layer's accepted
+  // configuration.
+  //
+  // We don't set the pixel format a Layer can accept, and we don't compare the
+  // Image's pixel format against any accepted pixel format, assuming that all
+  // image buffers allocated by sysmem can always be used for scanout in any
+  // Layer. Currently, this assumption works for all our existing display engine
+  // drivers. However, switching pixel formats in a Layer may cause performance
+  // reduction, or might be not supported by new display engines / new display
+  // formats.
+  //
+  // We should figure out a mechanism to indicate pixel format / modifiers
+  // support for a Layer's image configuration (as opposed of using image_t),
+  // and compare this Image's sysmem buffer collection information against the
+  // Layer's format support.
+  if (image.metadata() != display::ImageMetadata(layer->pending_image_metadata())) {
     zxlogf(ERROR, "SetLayerImage with mismatching layer and image metadata");
     image.DiscardAcquire();
     TearDown();
@@ -919,8 +929,8 @@
         frame_t image_frame = {
             .x_pos = 0,
             .y_pos = 0,
-            .width = layer->image.width,
-            .height = layer->image.height,
+            .width = layer->image_metadata.width,
+            .height = layer->image_metadata.height,
         };
         invalid = (!frame_contains(image_frame, layer->src_frame) ||
                    !frame_contains(display_frame, layer->dest_frame));
diff --git a/src/graphics/display/drivers/coordinator/controller.cc b/src/graphics/display/drivers/coordinator/controller.cc
index 64821ab..3768637 100644
--- a/src/graphics/display/drivers/coordinator/controller.cc
+++ b/src/graphics/display/drivers/coordinator/controller.cc
@@ -119,8 +119,8 @@
     if (duplicate) {
       continue;
     }
-    test_layer.cfg.primary.image.width = width;
-    test_layer.cfg.primary.image.height = height;
+    test_layer.cfg.primary.image_metadata.width = width;
+    test_layer.cfg.primary.image_metadata.height = height;
     test_layer.cfg.primary.src_frame.width = width;
     test_layer.cfg.primary.src_frame.height = height;
     test_layer.cfg.primary.dest_frame.width = width;
diff --git a/src/graphics/display/drivers/coordinator/driver.cc b/src/graphics/display/drivers/coordinator/driver.cc
index 1bd55aa..eae599b 100644
--- a/src/graphics/display/drivers/coordinator/driver.cc
+++ b/src/graphics/display/drivers/coordinator/driver.cc
@@ -185,15 +185,16 @@
   return zx::ok(ToDriverCaptureImageId(banjo_capture_image_handle));
 }
 
-zx::result<> Driver::ImportBufferCollection(DriverBufferCollectionId collection_id,
-                                            zx::channel collection_token) {
+zx::result<> Driver::ImportBufferCollection(
+    DriverBufferCollectionId collection_id,
+    fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken> collection_token) {
   if (use_engine_) {
     return zx::error(ZX_ERR_NOT_SUPPORTED);
   }
 
   ZX_DEBUG_ASSERT(dc_.is_valid());
   zx_status_t banjo_status = dc_.ImportBufferCollection(
-      ToBanjoDriverBufferCollectionId(collection_id), std::move(collection_token));
+      ToBanjoDriverBufferCollectionId(collection_id), std::move(collection_token).TakeChannel());
   return zx::make_result(banjo_status);
 }
 
diff --git a/src/graphics/display/drivers/coordinator/driver.h b/src/graphics/display/drivers/coordinator/driver.h
index eb93e06..a912441 100644
--- a/src/graphics/display/drivers/coordinator/driver.h
+++ b/src/graphics/display/drivers/coordinator/driver.h
@@ -62,8 +62,9 @@
                                         DriverBufferCollectionId collection_id, uint32_t index);
   zx::result<DriverCaptureImageId> ImportImageForCapture(DriverBufferCollectionId collection_id,
                                                          uint32_t index);
-  zx::result<> ImportBufferCollection(DriverBufferCollectionId collection_id,
-                                      zx::channel collection_token);
+  zx::result<> ImportBufferCollection(
+      DriverBufferCollectionId collection_id,
+      fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken> collection_token);
   zx::result<> ReleaseBufferCollection(DriverBufferCollectionId collection_id);
   zx::result<> SetBufferCollectionConstraints(const ImageBufferUsage& usage,
                                               DriverBufferCollectionId collection_id);
diff --git a/src/graphics/display/drivers/coordinator/image.cc b/src/graphics/display/drivers/coordinator/image.cc
index dd43f84..fb2e8bb 100644
--- a/src/graphics/display/drivers/coordinator/image.cc
+++ b/src/graphics/display/drivers/coordinator/image.cc
@@ -162,29 +162,4 @@
   retire_fence_ = nullptr;
 }
 
-bool Image::HasSameDisplayPropertiesAsLayer(const image_t& layer_config) const {
-  // TODO(https://fxbug.dev/42076907): Currently this function only compares size and
-  // usage type between current Image and a given Layer's accepted
-  // configuration.
-  //
-  // We don't set the pixel format a Layer can accept, and we don't compare the
-  // Image's pixel format against any accepted pixel format, assuming that all
-  // image buffers allocated by sysmem can always be used for scanout in any
-  // Layer. Currently, this assumption works for all our existing display engine
-  // drivers. However, switching pixel formats in a Layer may cause performance
-  // reduction, or might be not supported by new display engines / new display
-  // formats.
-  //
-  // We should figure out a mechanism to indicate pixel format / modifiers
-  // support for a Layer's image configuration (as opposed of using image_t),
-  // and compare this Image's sysmem buffer collection information against the
-  // Layer's format support.
-
-  // The casts will not result in UB, because ImageMetadata's width and height
-  // are guaranteed to be non-negative.
-  return static_cast<uint32_t>(metadata_.width()) == layer_config.width &&
-         static_cast<uint32_t>(metadata_.height()) == layer_config.height &&
-         metadata_.tiling_type().ToBanjo() == layer_config.tiling_type;
-}
-
 }  // namespace display
diff --git a/src/graphics/display/drivers/coordinator/image.h b/src/graphics/display/drivers/coordinator/image.h
index df66ce4..989d45a 100644
--- a/src/graphics/display/drivers/coordinator/image.h
+++ b/src/graphics/display/drivers/coordinator/image.h
@@ -105,10 +105,6 @@
 
   bool IsReady() const { return wait_fence_ == nullptr; }
 
-  // True iff the image has the same display properties as the `layer_config`,
-  // which are properties of all images that the corresponding Layer can accept.
-  bool HasSameDisplayPropertiesAsLayer(const image_t& layer_config) const;
-
   const zx::vmo& vmo() { return vmo_; }
 
   void set_latest_controller_config_stamp(ConfigStamp stamp) {
diff --git a/src/graphics/display/drivers/coordinator/layer.cc b/src/graphics/display/drivers/coordinator/layer.cc
index 86f5591..7020b3b5 100644
--- a/src/graphics/display/drivers/coordinator/layer.cc
+++ b/src/graphics/display/drivers/coordinator/layer.cc
@@ -27,6 +27,7 @@
 #include "src/graphics/display/lib/api-types-cpp/driver-image-id.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-layer-id.h"
 #include "src/graphics/display/lib/api-types-cpp/event-id.h"
+#include "src/graphics/display/lib/api-types-cpp/image-metadata.h"
 
 namespace fhdt = fuchsia_hardware_display_types;
 
@@ -44,12 +45,6 @@
   }
 }
 
-static void populate_image(const fhdt::wire::ImageMetadata& image_metadata, image_t* image_out) {
-  image_out->width = image_metadata.width;
-  image_out->height = image_metadata.height;
-  image_out->tiling_type = image_metadata.tiling_type;
-}
-
 }  // namespace
 
 Layer::Layer(DriverLayerId id) {
@@ -129,7 +124,7 @@
 
   if (current_layer_.type == LAYER_TYPE_PRIMARY) {
     if (displayed_image_) {
-      current_layer_.cfg.primary.image.handle = ToBanjoDriverImageId(displayed_image_->driver_id());
+      current_layer_.cfg.primary.image_handle = ToBanjoDriverImageId(displayed_image_->driver_id());
     }
     return;
   }
@@ -220,7 +215,7 @@
 
   if (current_layer_.type == LAYER_TYPE_PRIMARY) {
     uint64_t handle = ToBanjoDriverImageId(displayed_image_->driver_id());
-    current_layer_.cfg.primary.image.handle = handle;
+    current_layer_.cfg.primary.image_handle = handle;
   } else {
     // type is validated in Client::CheckConfig, so something must be very wrong.
     ZX_ASSERT(false);
@@ -240,12 +235,12 @@
 
 void Layer::SetPrimaryConfig(fhdt::wire::ImageMetadata image_metadata) {
   pending_layer_.type = LAYER_TYPE_PRIMARY;
-  auto* primary = &pending_layer_.cfg.primary;
-  populate_image(image_metadata, &primary->image);
+  primary_layer_t& primary = pending_layer_.cfg.primary;
+  primary.image_metadata = ImageMetadata(image_metadata).ToBanjo();
   const frame_t new_frame = {
       .x_pos = 0, .y_pos = 0, .width = image_metadata.width, .height = image_metadata.height};
-  primary->src_frame = new_frame;
-  primary->dest_frame = new_frame;
+  primary.src_frame = new_frame;
+  primary.dest_frame = new_frame;
   pending_image_config_gen_++;
   pending_image_ = nullptr;
   config_change_ = true;
diff --git a/src/graphics/display/drivers/coordinator/layer.h b/src/graphics/display/drivers/coordinator/layer.h
index 8e46f97..0bed8cf 100644
--- a/src/graphics/display/drivers/coordinator/layer.h
+++ b/src/graphics/display/drivers/coordinator/layer.h
@@ -47,7 +47,12 @@
   friend LayerTest;
 
   bool in_use() const { return current_node_.InContainer() || pending_node_.InContainer(); }
-  const image_t* pending_image() const { return &pending_layer_.cfg.primary.image; }
+
+  const image_metadata_t& pending_image_metadata() const {
+    return pending_layer_.cfg.primary.image_metadata;
+  }
+  uint64_t pending_image_handle() const { return pending_layer_.cfg.primary.image_handle; }
+
   auto current_type() const { return current_layer_.type; }
   auto pending_type() const { return pending_layer_.type; }
 
diff --git a/src/graphics/display/drivers/fake/fake-display-test.cc b/src/graphics/display/drivers/fake/fake-display-test.cc
index aa4f919..3b735afc 100644
--- a/src/graphics/display/drivers/fake/fake-display-test.cc
+++ b/src/graphics/display/drivers/fake/fake-display-test.cc
@@ -302,7 +302,7 @@
 
 // Creates a primary layer config for an opaque layer that holds the `image`
 // on the top-left corner of the screen without any scaling.
-layer_t CreatePrimaryLayerConfig(const image_t& image) {
+layer_t CreatePrimaryLayerConfig(uint64_t image_handle, const image_metadata_t& image_metadata) {
   return layer_t{
       .type = LAYER_TYPE_PRIMARY,
       .z_index = 0,
@@ -310,7 +310,8 @@
           {
               .primary =
                   {
-                      .image = image,
+                      .image_handle = image_handle,
+                      .image_metadata = image_metadata,
                       .alpha_mode = ALPHA_DISABLE,
                       .alpha_layer_val = 1.0,
                       .transform_mode = FRAME_TRANSFORM_IDENTITY,
@@ -318,15 +319,15 @@
                           {
                               .x_pos = 0,
                               .y_pos = 0,
-                              .width = image.width,
-                              .height = image.height,
+                              .width = image_metadata.width,
+                              .height = image_metadata.height,
                           },
                       .dest_frame =
                           {
                               .x_pos = 0,
                               .y_pos = 0,
-                              .width = image.width,
-                              .height = image.height,
+                              .width = image_metadata.width,
+                              .height = image_metadata.height,
                           },
                   },
           },
@@ -683,13 +684,7 @@
   EXPECT_NE(framebuffer_image_handle, INVALID_ID);
 
   // Create display configuration.
-  const image_t framebuffer_image_config = {
-      .width = kDisplayWidth,
-      .height = kDisplayHeight,
-      .tiling_type = IMAGE_TILING_TYPE_LINEAR,
-      .handle = framebuffer_image_handle,
-  };
-  layer_t layer = CreatePrimaryLayerConfig(framebuffer_image_config);
+  layer_t layer = CreatePrimaryLayerConfig(framebuffer_image_handle, kFramebufferImageMetadata);
 
   constexpr size_t kNumLayers = 1;
   std::array<const layer_t*, kNumLayers> layers = {&layer};
diff --git a/src/graphics/display/drivers/fake/fake-display.cc b/src/graphics/display/drivers/fake/fake-display.cc
index cb73f8e..4e032cd 100644
--- a/src/graphics/display/drivers/fake/fake-display.cc
+++ b/src/graphics/display/drivers/fake/fake-display.cc
@@ -354,11 +354,12 @@
         .width = kWidth,
         .height = kHeight,
     };
-    success =
-        display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY &&
-        layer.transform_mode == FRAME_TRANSFORM_IDENTITY && layer.image.width == kWidth &&
-        layer.image.height == kHeight && memcmp(&layer.dest_frame, &frame, sizeof(frame_t)) == 0 &&
-        memcmp(&layer.src_frame, &frame, sizeof(frame_t)) == 0 && layer.alpha_mode == ALPHA_DISABLE;
+    success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY &&
+              layer.transform_mode == FRAME_TRANSFORM_IDENTITY &&
+              layer.image_metadata.width == kWidth && layer.image_metadata.height == kHeight &&
+              memcmp(&layer.dest_frame, &frame, sizeof(frame_t)) == 0 &&
+              memcmp(&layer.src_frame, &frame, sizeof(frame_t)) == 0 &&
+              layer.alpha_mode == ALPHA_DISABLE;
   }
   if (!success) {
     client_composition_opcodes[0] = CLIENT_COMPOSITION_OPCODE_MERGE_BASE;
@@ -379,7 +380,7 @@
     if (display_count == 1 && display_configs[0]->layer_count) {
       // Only support one display.
       current_image_to_capture_id_ =
-          display::ToDriverImageId(display_configs[0]->layer_list[0]->cfg.primary.image.handle);
+          display::ToDriverImageId(display_configs[0]->layer_list[0]->cfg.primary.image_handle);
     } else {
       current_image_to_capture_id_ = display::kInvalidDriverImageId;
     }
diff --git a/src/graphics/display/drivers/goldfish-display/BUILD.gn b/src/graphics/display/drivers/goldfish-display/BUILD.gn
index 1951b53..b9f3c33 100644
--- a/src/graphics/display/drivers/goldfish-display/BUILD.gn
+++ b/src/graphics/display/drivers/goldfish-display/BUILD.gn
@@ -19,14 +19,12 @@
     "//build/config:all_source",
     "//build/config/fuchsia:enable_zircon_asserts",
   ]
-  sources = [
-    "display.cc",
-    "display.h",
-  ]
+
   deps = [
     ":common",
     ":goldfish-display-bind",
-    "//src/devices/lib/driver",
+    "//src/devices/lib/driver:driver_runtime",
+    "//src/graphics/display/lib/driver-framework-migration-utils/logging:logging-dfv2",
   ]
 
   # TODO(https://fxbug.dev/42136089): delete the below and fix compiler warnings
@@ -48,21 +46,29 @@
   visibility = [ ":*" ]
   configs += [ "//build/config:all_source" ]
   sources = [
+    "display-driver.cc",
+    "display-driver.h",
+    "display-engine.cc",
+    "display-engine.h",
     "render_control.cc",
     "render_control.h",
   ]
   public_deps = [
     "//sdk/banjo/fuchsia.hardware.display.controller:fuchsia.hardware.display.controller_banjo_cpp",
-    "//sdk/banjo/fuchsia.hardware.goldfish.control:fuchsia.hardware.goldfish.control_banjo_cpp",
     "//sdk/fidl/fuchsia.hardware.goldfish:fuchsia.hardware.goldfish_cpp",
     "//sdk/fidl/fuchsia.hardware.goldfish.pipe:fuchsia.hardware.goldfish.pipe_cpp",
+    "//sdk/fidl/fuchsia.hardware.sysmem:fuchsia.hardware.sysmem_cpp",
     "//sdk/fidl/fuchsia.sysmem:fuchsia.sysmem_cpp",
+    "//sdk/lib/component/outgoing/cpp",
+    "//sdk/lib/driver/compat/cpp",
+    "//sdk/lib/driver/component/cpp",
+    "//sdk/lib/driver/logging/cpp",
+    "//src/devices/bin/driver_runtime",
+    "//src/devices/bind/fuchsia:fuchsia_cpp",
+    "//src/devices/bind/fuchsia.display:fuchsia.display_cpp",
     "//src/devices/lib/goldfish/pipe_headers",
     "//src/devices/lib/goldfish/pipe_io",
     "//src/graphics/display/lib/api-types-cpp",
-    "//src/lib/ddk",
-    "//src/lib/ddktl",
-    "//src/lib/fxl",
     "//zircon/system/ulib/async:async-cpp",
     "//zircon/system/ulib/async-loop:async-loop-cpp",
     "//zircon/system/ulib/fbl",
@@ -77,18 +83,16 @@
 
 test("goldfish-unittests") {
   configs += [ "//build/config:all_source" ]
-  sources = [
-    "display-test.cc",
-    "display.cc",
-    "display.h",
-  ]
+  sources = [ "display-engine-test.cc" ]
+
   deps = [
     ":common",
     ":goldfish-display-bind",
     "//sdk/fidl/fuchsia.sysmem:fuchsia.sysmem_cpp_testing",
+    "//sdk/lib/driver/testing/cpp",
     "//sdk/lib/fdio",
     "//src/devices/bus/lib/device-protocol-pdev",
-    "//src/devices/testing/no_ddk",
+    "//src/graphics/display/lib/driver-framework-migration-utils/logging:logging-dfv2",
     "//src/lib/fxl/test:gtest_main",
     "//src/lib/testing/predicates",
     "//third_party/googletest:gtest",
diff --git a/src/graphics/display/drivers/goldfish-display/display-driver.cc b/src/graphics/display/drivers/goldfish-display/display-driver.cc
new file mode 100644
index 0000000..00135d8
--- /dev/null
+++ b/src/graphics/display/drivers/goldfish-display/display-driver.cc
@@ -0,0 +1,205 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/graphics/display/drivers/goldfish-display/display-driver.h"
+
+#include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
+#include <fidl/fuchsia.hardware.sysmem/cpp/wire.h>
+#include <fidl/fuchsia.sysmem/cpp/wire.h>
+#include <fuchsia/hardware/display/controller/c/banjo.h>
+#include <lib/driver/compat/cpp/banjo_server.h>
+#include <lib/driver/compat/cpp/device_server.h>
+#include <lib/driver/component/cpp/driver_export.h>
+#include <lib/driver/logging/cpp/logger.h>
+#include <lib/fdf/cpp/dispatcher.h>
+#include <lib/zx/result.h>
+#include <zircon/errors.h>
+#include <zircon/process.h>
+#include <zircon/status.h>
+
+#include <memory>
+#include <string_view>
+
+#include <bind/fuchsia/cpp/bind.h>
+#include <bind/fuchsia/display/cpp/bind.h>
+#include <fbl/alloc_checker.h>
+
+#include "src/graphics/display/drivers/goldfish-display/display-engine.h"
+#include "src/graphics/display/drivers/goldfish-display/render_control.h"
+
+namespace goldfish {
+namespace {
+
+zx_koid_t GetKoid(zx_handle_t handle) {
+  zx_info_handle_basic_t info;
+  zx_status_t status =
+      zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
+  return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
+}
+
+zx::result<fidl::ClientEnd<fuchsia_sysmem::Allocator>> CreateAndInitializeSysmemAllocator(
+    fdf::Namespace* incoming) {
+  zx::result<fidl::ClientEnd<fuchsia_sysmem::Allocator>> connect_sysmem_service_result =
+      incoming->Connect<fuchsia_hardware_sysmem::Service::AllocatorV1>();
+  if (connect_sysmem_service_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to connect to the sysmem Allocator FIDL protocol: %s",
+            connect_sysmem_service_result.status_string());
+    return connect_sysmem_service_result.take_error();
+  }
+  fidl::ClientEnd<fuchsia_sysmem::Allocator> sysmem_allocator =
+      std::move(connect_sysmem_service_result).value();
+
+  const zx_koid_t pid = GetKoid(zx_process_self());
+  static constexpr std::string_view kDebugName = "goldfish-display";
+  fidl::OneWayStatus set_debug_status =
+      fidl::WireCall(sysmem_allocator)
+          ->SetDebugClientInfo(fidl::StringView::FromExternal(kDebugName), pid);
+  if (!set_debug_status.ok()) {
+    FDF_LOG(ERROR, "Failed to set sysmem allocator debug info: %s",
+            set_debug_status.status_string());
+    return zx::error(set_debug_status.status());
+  }
+
+  return zx::ok(std::move(sysmem_allocator));
+}
+
+zx::result<std::unique_ptr<RenderControl>> CreateAndInitializeRenderControl(
+    fdf::Namespace* incoming) {
+  zx::result<fidl::ClientEnd<fuchsia_hardware_goldfish_pipe::GoldfishPipe>>
+      render_control_connect_pipe_service_result =
+          incoming->Connect<fuchsia_hardware_goldfish_pipe::Service::Device>();
+  if (render_control_connect_pipe_service_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to connect to the goldfish pipe FIDL service: %s",
+            render_control_connect_pipe_service_result.status_string());
+    return render_control_connect_pipe_service_result.take_error();
+  }
+  fidl::ClientEnd<fuchsia_hardware_goldfish_pipe::GoldfishPipe> render_control_pipe =
+      std::move(render_control_connect_pipe_service_result).value();
+
+  fbl::AllocChecker alloc_checker;
+  auto render_control = fbl::make_unique_checked<RenderControl>(&alloc_checker);
+  if (!alloc_checker.check()) {
+    FDF_LOG(ERROR, "Failed to allocate memory for RenderControl");
+    return zx::error(ZX_ERR_NO_MEMORY);
+  }
+
+  zx_status_t status =
+      render_control->InitRcPipe(fidl::WireSyncClient(std::move(render_control_pipe)));
+  if (status != ZX_OK) {
+    FDF_LOG(ERROR, "Failed to initialize RenderControl: %d", status);
+    return zx::error(status);
+  }
+
+  return zx::ok(std::move(render_control));
+}
+
+}  // namespace
+
+DisplayDriver::DisplayDriver(fdf::DriverStartArgs start_args,
+                             fdf::UnownedSynchronizedDispatcher driver_dispatcher)
+    : fdf::DriverBase("goldfish-display", std::move(start_args), std::move(driver_dispatcher)) {}
+
+DisplayDriver::~DisplayDriver() = default;
+
+zx::result<> DisplayDriver::Start() {
+  zx::result<fidl::ClientEnd<fuchsia_hardware_goldfish::ControlDevice>>
+      connect_control_service_result =
+          incoming()->Connect<fuchsia_hardware_goldfish::ControlService::Device>();
+  if (connect_control_service_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to connect to the goldfish Control FIDL service: %s",
+            connect_control_service_result.status_string());
+    return connect_control_service_result.take_error();
+  }
+  fidl::ClientEnd<fuchsia_hardware_goldfish::ControlDevice> control =
+      std::move(connect_control_service_result).value();
+
+  zx::result<fidl::ClientEnd<fuchsia_hardware_goldfish_pipe::GoldfishPipe>>
+      connect_pipe_service_result =
+          incoming()->Connect<fuchsia_hardware_goldfish_pipe::Service::Device>();
+  if (connect_pipe_service_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to connect to the goldfish pipe FIDL service: %s",
+            connect_pipe_service_result.status_string());
+    return connect_pipe_service_result.take_error();
+  }
+  fidl::ClientEnd<fuchsia_hardware_goldfish_pipe::GoldfishPipe> pipe =
+      std::move(connect_pipe_service_result).value();
+
+  zx::result<fidl::ClientEnd<fuchsia_sysmem::Allocator>> create_sysmem_allocator_result =
+      CreateAndInitializeSysmemAllocator(incoming().get());
+  if (create_sysmem_allocator_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to create and initialize sysmem allocator: %s",
+            create_sysmem_allocator_result.status_string());
+    return create_sysmem_allocator_result.take_error();
+  }
+  fidl::ClientEnd<fuchsia_sysmem::Allocator> sysmem_allocator =
+      std::move(create_sysmem_allocator_result).value();
+
+  zx::result<std::unique_ptr<RenderControl>> create_render_control_result =
+      CreateAndInitializeRenderControl(incoming().get());
+  if (create_render_control_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to create and initialize RenderControl: %s",
+            create_render_control_result.status_string());
+    return create_render_control_result.take_error();
+  }
+  std::unique_ptr<RenderControl> render_control = std::move(create_render_control_result).value();
+
+  zx::result<fdf::SynchronizedDispatcher> create_dispatcher_result =
+      fdf::SynchronizedDispatcher::Create(fdf::SynchronizedDispatcher::Options{},
+                                          "display-event-dispatcher", /*shutdown_handler=*/{});
+  if (create_dispatcher_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to create display event dispatcher: %s",
+            create_dispatcher_result.status_string());
+    return create_dispatcher_result.take_error();
+  }
+  display_event_dispatcher_ = std::move(create_dispatcher_result).value();
+
+  fbl::AllocChecker alloc_checker;
+  display_engine_ = fbl::make_unique_checked<DisplayEngine>(
+      &alloc_checker, std::move(control), std::move(pipe), std::move(sysmem_allocator),
+      std::move(render_control), display_event_dispatcher_.async_dispatcher());
+  if (!alloc_checker.check()) {
+    FDF_LOG(ERROR, "Failed to allocate memory for DisplayEngine");
+    return zx::error(ZX_ERR_NO_MEMORY);
+  }
+
+  zx::result<> init_result = display_engine_->Initialize();
+  if (init_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to initialize DisplayEngine: %s", init_result.status_string());
+    return init_result.take_error();
+  }
+
+  // Serves the [`fuchsia.hardware.display.controller/ControllerImpl`] protocol
+  // over the compatibility server.
+  banjo_server_ =
+      compat::BanjoServer(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL, /*ctx=*/display_engine_.get(),
+                          /*ops=*/display_engine_->display_controller_impl_protocol_ops());
+  compat::DeviceServer::BanjoConfig banjo_config;
+  banjo_config.callbacks[ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL] = banjo_server_->callback();
+  zx::result<> compat_server_init_result =
+      compat_server_.Initialize(incoming(), outgoing(), node_name(), name(),
+                                /*forward_metadata=*/compat::ForwardMetadata::None(),
+                                /*banjo_config=*/std::move(banjo_config));
+  if (compat_server_init_result.is_error()) {
+    return compat_server_init_result.take_error();
+  }
+
+  const std::vector<fuchsia_driver_framework::NodeProperty> node_properties = {
+      fdf::MakeProperty(bind_fuchsia::PROTOCOL,
+                        bind_fuchsia_display::BIND_PROTOCOL_CONTROLLER_IMPL),
+  };
+  const std::vector<fuchsia_driver_framework::Offer> node_offers = compat_server_.CreateOffers2();
+  zx::result<fidl::ClientEnd<fuchsia_driver_framework::NodeController>> controller_client_result =
+      AddChild(name(), node_properties, node_offers);
+  if (controller_client_result.is_error()) {
+    FDF_LOG(ERROR, "Failed to add child node: %s", controller_client_result.status_string());
+    return controller_client_result.take_error();
+  }
+  controller_ = fidl::WireSyncClient(std::move(controller_client_result).value());
+
+  return zx::ok();
+}
+
+}  // namespace goldfish
+
+FUCHSIA_DRIVER_EXPORT(goldfish::DisplayDriver);
diff --git a/src/graphics/display/drivers/goldfish-display/display-driver.h b/src/graphics/display/drivers/goldfish-display/display-driver.h
new file mode 100644
index 0000000..6d03374
--- /dev/null
+++ b/src/graphics/display/drivers/goldfish-display/display-driver.h
@@ -0,0 +1,52 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_DRIVER_H_
+#define SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_DRIVER_H_
+
+#include <fidl/fuchsia.driver.framework/cpp/wire.h>
+#include <lib/driver/compat/cpp/banjo_server.h>
+#include <lib/driver/compat/cpp/device_server.h>
+#include <lib/driver/component/cpp/driver_base.h>
+#include <lib/fdf/cpp/dispatcher.h>
+#include <lib/zx/result.h>
+
+#include <memory>
+#include <optional>
+
+#include "src/graphics/display/drivers/goldfish-display/display-engine.h"
+
+namespace goldfish {
+
+class DisplayDriver : public fdf::DriverBase {
+ public:
+  explicit DisplayDriver(fdf::DriverStartArgs start_args,
+                         fdf::UnownedSynchronizedDispatcher driver_dispatcher);
+
+  DisplayDriver(const DisplayDriver&) = delete;
+  DisplayDriver(DisplayDriver&&) = delete;
+  DisplayDriver& operator=(const DisplayDriver&) = delete;
+  DisplayDriver& operator=(DisplayDriver&&) = delete;
+
+  ~DisplayDriver() override;
+
+  // fdf::DriverBase:
+  zx::result<> Start() override;
+
+ private:
+  compat::SyncInitializedDeviceServer compat_server_;
+  fidl::WireSyncClient<fuchsia_driver_framework::NodeController> controller_;
+
+  // Must outlive `display_engine_`.
+  fdf::SynchronizedDispatcher display_event_dispatcher_;
+
+  // Must outlive `banjo_server_`.
+  std::unique_ptr<DisplayEngine> display_engine_;
+
+  std::optional<compat::BanjoServer> banjo_server_;
+};
+
+}  // namespace goldfish
+
+#endif  // SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_DRIVER_H_
diff --git a/src/graphics/display/drivers/goldfish-display/display-test.cc b/src/graphics/display/drivers/goldfish-display/display-engine-test.cc
similarity index 72%
rename from src/graphics/display/drivers/goldfish-display/display-test.cc
rename to src/graphics/display/drivers/goldfish-display/display-engine-test.cc
index e3c2e95..8c929de 100644
--- a/src/graphics/display/drivers/goldfish-display/display-test.cc
+++ b/src/graphics/display/drivers/goldfish-display/display-engine-test.cc
@@ -2,13 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/graphics/display/drivers/goldfish-display/display.h"
+#include "src/graphics/display/drivers/goldfish-display/display-engine.h"
 
+#include <fidl/fuchsia.hardware.goldfish.pipe/cpp/wire.h>
+#include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
+#include <fidl/fuchsia.sysmem/cpp/wire.h>
 #include <fidl/fuchsia.sysmem/cpp/wire_test_base.h>
 #include <fuchsia/hardware/display/controller/c/banjo.h>
 #include <lib/async-loop/cpp/loop.h>
 #include <lib/async-loop/loop.h>
 #include <lib/ddk/device.h>
+#include <lib/driver/logging/cpp/logger.h>
+#include <lib/driver/testing/cpp/driver_runtime.h>
+#include <lib/fdf/cpp/dispatcher.h>
 
 #include <array>
 #include <cstdio>
@@ -44,12 +50,20 @@
 
 class FakePipe : public fidl::WireServer<fuchsia_hardware_goldfish_pipe::GoldfishPipe> {};
 
-class GoldfishDisplayTest : public testing::Test {
+class GoldfishDisplayEngineTest : public testing::Test {
  public:
-  GoldfishDisplayTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) {}
+  GoldfishDisplayEngineTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) {}
 
   void SetUp() override;
   void TearDown() override;
+
+ protected:
+  fdf_testing::DriverRuntime driver_runtime_;
+  fdf::UnownedSynchronizedDispatcher display_event_dispatcher_ =
+      driver_runtime_.StartBackgroundDispatcher();
+  fdf::Logger logger_{"test", FUCHSIA_LOG_TRACE, zx::socket{},
+                      fidl::WireClient<fuchsia_logger::LogSink>{}};
+
   std::array<std::array<layer_t, kMaxLayerCount>, kDisplayCount> layer_ = {};
   std::array<const layer_t*, kDisplayCount> layer_ptrs = {};
 
@@ -58,7 +72,7 @@
 
   std::array<client_composition_opcode_t, kMaxLayerCount * kDisplayCount> results_ = {};
 
-  std::unique_ptr<Display> display_ = {};
+  std::unique_ptr<DisplayEngine> display_engine_;
 
   std::optional<fidl::ServerBindingRef<fuchsia_hardware_goldfish_pipe::GoldfishPipe>> binding_;
   std::optional<fidl::ServerBindingRef<fuchsia_sysmem::Allocator>> allocator_binding_;
@@ -67,8 +81,20 @@
   FakeAllocator mock_allocator_;
 };
 
-void GoldfishDisplayTest::SetUp() {
-  display_ = std::make_unique<Display>(nullptr);
+void GoldfishDisplayEngineTest::SetUp() {
+  fdf::Logger::SetGlobalInstance(&logger_);
+
+  auto [control_client, control_server] =
+      fidl::Endpoints<fuchsia_hardware_goldfish::ControlDevice>::Create();
+  auto [pipe_client, pipe_server] =
+      fidl::Endpoints<fuchsia_hardware_goldfish_pipe::GoldfishPipe>::Create();
+  auto [sysmem_client, sysmem_server] = fidl::Endpoints<fuchsia_sysmem::Allocator>::Create();
+  allocator_binding_ =
+      fidl::BindServer(loop_.dispatcher(), std::move(sysmem_server), &mock_allocator_);
+
+  display_engine_ = std::make_unique<DisplayEngine>(
+      std::move(control_client), std::move(pipe_client), std::move(sysmem_client),
+      std::make_unique<RenderControl>(), display_event_dispatcher_->async_dispatcher());
 
   for (size_t i = 0; i < kDisplayCount; i++) {
     configs_ptrs_[i] = &configs_[i];
@@ -80,33 +106,32 @@
 
   // Call SetupPrimaryDisplayForTesting() so that we can set up the display
   // devices without any dependency on proper driver binding.
-  display_->SetupPrimaryDisplayForTesting(kDisplayWidthPx, kDisplayHeightPx, kDisplayRefreshRateHz);
-
-  auto endpoints = fidl::Endpoints<fuchsia_sysmem::Allocator>::Create();
-  allocator_binding_ =
-      fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &mock_allocator_);
-  display_->SetSysmemAllocatorForTesting(fidl::WireSyncClient(std::move(endpoints.client)));
+  display_engine_->SetupPrimaryDisplayForTesting(kDisplayWidthPx, kDisplayHeightPx,
+                                                 kDisplayRefreshRateHz);
 }
 
-void GoldfishDisplayTest::TearDown() { allocator_binding_->Unbind(); }
+void GoldfishDisplayEngineTest::TearDown() {
+  allocator_binding_->Unbind();
+  fdf::Logger::SetGlobalInstance(nullptr);
+}
 
-TEST_F(GoldfishDisplayTest, CheckConfigNoDisplay) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigNoDisplay) {
   // Test No display
   size_t client_composition_opcodes_actual = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), 0, results_.data(),
       results_.size(), &client_composition_opcodes_actual);
   EXPECT_OK(res);
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigMultiLayer) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigMultiLayer) {
   // ensure we fail correctly if layers more than 1
   for (size_t i = 0; i < kDisplayCount; i++) {
     configs_[i].layer_count = kMaxLayerCount;
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -122,7 +147,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigLayerColor) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigLayerColor) {
   constexpr int kNumLayersPerDisplay = 1;
   // First create layer for each device
   for (size_t i = 0; i < kDisplayCount; i++) {
@@ -130,7 +155,7 @@
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -141,7 +166,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigLayerPrimary) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigLayerPrimary) {
   constexpr int kNumLayersPerDisplay = 1;
   // First create layer for each device
   frame_t dest_frame = {
@@ -159,14 +184,14 @@
   for (size_t i = 0; i < kDisplayCount; i++) {
     layer_[i][0].cfg.primary.dest_frame = dest_frame;
     layer_[i][0].cfg.primary.src_frame = src_frame;
-    layer_[i][0].cfg.primary.image.width = 1024;
-    layer_[i][0].cfg.primary.image.height = 768;
+    layer_[i][0].cfg.primary.image_metadata.width = 1024;
+    layer_[i][0].cfg.primary.image_metadata.height = 768;
     layer_[i][0].cfg.primary.alpha_mode = 0;
     layer_[i][0].cfg.primary.transform_mode = 0;
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -176,7 +201,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigLayerDestFrame) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigLayerDestFrame) {
   constexpr int kNumLayersPerDisplay = 1;
   // First create layer for each device
   frame_t dest_frame = {
@@ -194,12 +219,12 @@
   for (size_t i = 0; i < kDisplayCount; i++) {
     layer_[i][0].cfg.primary.dest_frame = dest_frame;
     layer_[i][0].cfg.primary.src_frame = src_frame;
-    layer_[i][0].cfg.primary.image.width = 1024;
-    layer_[i][0].cfg.primary.image.height = 768;
+    layer_[i][0].cfg.primary.image_metadata.width = 1024;
+    layer_[i][0].cfg.primary.image_metadata.height = 768;
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -209,7 +234,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigLayerSrcFrame) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigLayerSrcFrame) {
   constexpr int kNumLayersPerDisplay = 1;
   // First create layer for each device
   frame_t dest_frame = {
@@ -227,12 +252,12 @@
   for (size_t i = 0; i < kDisplayCount; i++) {
     layer_[i][0].cfg.primary.dest_frame = dest_frame;
     layer_[i][0].cfg.primary.src_frame = src_frame;
-    layer_[i][0].cfg.primary.image.width = 1024;
-    layer_[i][0].cfg.primary.image.height = 768;
+    layer_[i][0].cfg.primary.image_metadata.width = 1024;
+    layer_[i][0].cfg.primary.image_metadata.height = 768;
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -242,7 +267,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigLayerAlpha) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigLayerAlpha) {
   constexpr int kNumLayersPerDisplay = 1;
   // First create layer for each device
   frame_t dest_frame = {
@@ -260,13 +285,13 @@
   for (size_t i = 0; i < kDisplayCount; i++) {
     layer_[i][0].cfg.primary.dest_frame = dest_frame;
     layer_[i][0].cfg.primary.src_frame = src_frame;
-    layer_[i][0].cfg.primary.image.width = 1024;
-    layer_[i][0].cfg.primary.image.height = 768;
+    layer_[i][0].cfg.primary.image_metadata.width = 1024;
+    layer_[i][0].cfg.primary.image_metadata.height = 768;
     layer_[i][0].cfg.primary.alpha_mode = ALPHA_HW_MULTIPLY;
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -276,7 +301,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigLayerTransform) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigLayerTransform) {
   constexpr int kNumLayersPerDisplay = 1;
   // First create layer for each device
   frame_t dest_frame = {
@@ -294,13 +319,13 @@
   for (size_t i = 0; i < kDisplayCount; i++) {
     layer_[i][0].cfg.primary.dest_frame = dest_frame;
     layer_[i][0].cfg.primary.src_frame = src_frame;
-    layer_[i][0].cfg.primary.image.width = 1024;
-    layer_[i][0].cfg.primary.image.height = 768;
+    layer_[i][0].cfg.primary.image_metadata.width = 1024;
+    layer_[i][0].cfg.primary.image_metadata.height = 768;
     layer_[i][0].cfg.primary.transform_mode = FRAME_TRANSFORM_REFLECT_X;
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -310,7 +335,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigLayerColorCoversion) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigLayerColorCoversion) {
   constexpr int kNumLayersPerDisplay = 1;
   // First create layer for each device
   frame_t dest_frame = {
@@ -328,13 +353,13 @@
   for (size_t i = 0; i < kDisplayCount; i++) {
     layer_[i][0].cfg.primary.dest_frame = dest_frame;
     layer_[i][0].cfg.primary.src_frame = src_frame;
-    layer_[i][0].cfg.primary.image.width = 1024;
-    layer_[i][0].cfg.primary.image.height = 768;
+    layer_[i][0].cfg.primary.image_metadata.width = 1024;
+    layer_[i][0].cfg.primary.image_metadata.height = 768;
     configs_[i].cc_flags = COLOR_CONVERSION_POSTOFFSET;
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -346,7 +371,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, CheckConfigAllFeatures) {
+TEST_F(GoldfishDisplayEngineTest, CheckConfigAllFeatures) {
   constexpr int kNumLayersPerDisplay = 1;
   // First create layer for each device
   frame_t dest_frame = {
@@ -364,15 +389,15 @@
   for (size_t i = 0; i < kDisplayCount; i++) {
     layer_[i][0].cfg.primary.dest_frame = dest_frame;
     layer_[i][0].cfg.primary.src_frame = src_frame;
-    layer_[i][0].cfg.primary.image.width = 1024;
-    layer_[i][0].cfg.primary.image.height = 768;
+    layer_[i][0].cfg.primary.image_metadata.width = 1024;
+    layer_[i][0].cfg.primary.image_metadata.height = 768;
     layer_[i][0].cfg.primary.alpha_mode = ALPHA_HW_MULTIPLY;
     layer_[i][0].cfg.primary.transform_mode = FRAME_TRANSFORM_ROT_180;
     configs_[i].cc_flags = COLOR_CONVERSION_POSTOFFSET;
   }
 
   size_t actual_result_size = 0;
-  config_check_result_t res = display_->DisplayControllerImplCheckConfiguration(
+  config_check_result_t res = display_engine_->DisplayControllerImplCheckConfiguration(
       const_cast<const display_config_t**>(configs_ptrs_.data()), kDisplayCount, results_.data(),
       results_.size(), &actual_result_size);
   EXPECT_OK(res);
@@ -387,7 +412,7 @@
   }
 }
 
-TEST_F(GoldfishDisplayTest, ImportBufferCollection) {
+TEST_F(GoldfishDisplayEngineTest, ImportBufferCollection) {
   zx::result token1_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
   ASSERT_TRUE(token1_endpoints.is_ok());
   zx::result token2_endpoints = fidl::CreateEndpoints<fuchsia_sysmem::BufferCollectionToken>();
@@ -397,11 +422,11 @@
   constexpr display::DriverBufferCollectionId kValidCollectionId(1);
   constexpr uint64_t kBanjoValidCollectionId =
       display::ToBanjoDriverBufferCollectionId(kValidCollectionId);
-  EXPECT_OK(display_->DisplayControllerImplImportBufferCollection(
+  EXPECT_OK(display_engine_->DisplayControllerImplImportBufferCollection(
       kBanjoValidCollectionId, token1_endpoints->client.TakeChannel()));
 
   // `collection_id` must be unused.
-  EXPECT_EQ(display_->DisplayControllerImplImportBufferCollection(
+  EXPECT_EQ(display_engine_->DisplayControllerImplImportBufferCollection(
                 kBanjoValidCollectionId, token2_endpoints->client.TakeChannel()),
             ZX_ERR_ALREADY_EXISTS);
 
@@ -409,9 +434,10 @@
   constexpr display::DriverBufferCollectionId kInvalidCollectionId(2);
   constexpr uint64_t kBanjoInvalidCollectionId =
       display::ToBanjoDriverBufferCollectionId(kInvalidCollectionId);
-  EXPECT_EQ(display_->DisplayControllerImplReleaseBufferCollection(kBanjoInvalidCollectionId),
-            ZX_ERR_NOT_FOUND);
-  EXPECT_OK(display_->DisplayControllerImplReleaseBufferCollection(kBanjoValidCollectionId));
+  EXPECT_EQ(
+      display_engine_->DisplayControllerImplReleaseBufferCollection(kBanjoInvalidCollectionId),
+      ZX_ERR_NOT_FOUND);
+  EXPECT_OK(display_engine_->DisplayControllerImplReleaseBufferCollection(kBanjoValidCollectionId));
 
   loop_.Shutdown();
 }
diff --git a/src/graphics/display/drivers/goldfish-display/display.cc b/src/graphics/display/drivers/goldfish-display/display-engine.cc
similarity index 68%
rename from src/graphics/display/drivers/goldfish-display/display.cc
rename to src/graphics/display/drivers/goldfish-display/display-engine.cc
index c6ed43a..449bbce 100644
--- a/src/graphics/display/drivers/goldfish-display/display.cc
+++ b/src/graphics/display/drivers/goldfish-display/display-engine.cc
@@ -2,50 +2,35 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/graphics/display/drivers/goldfish-display/display.h"
+#include "src/graphics/display/drivers/goldfish-display/display-engine.h"
 
 #include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
-#include <fidl/fuchsia.sysmem/cpp/fidl.h>
+#include <fidl/fuchsia.hardware.sysmem/cpp/wire.h>
 #include <fidl/fuchsia.sysmem/cpp/wire.h>
 #include <fuchsia/hardware/display/controller/c/banjo.h>
-#include <fuchsia/hardware/goldfish/control/cpp/banjo.h>
 #include <lib/async/cpp/task.h>
 #include <lib/async/cpp/time.h>
 #include <lib/async/cpp/wait.h>
-#include <lib/ddk/binding_driver.h>
-#include <lib/ddk/debug.h>
-#include <lib/ddk/driver.h>
-#include <lib/ddk/trace/event.h>
-#include <lib/fidl/cpp/channel.h>
-#include <lib/fidl/cpp/wire/channel.h>
-#include <lib/fidl/cpp/wire/connect_service.h>
-#include <lib/fit/defer.h>
+#include <lib/driver/logging/cpp/logger.h>
 #include <lib/image-format/image_format.h>
-#include <lib/zircon-internal/align.h>
+#include <lib/trace/event.h>
 #include <lib/zx/result.h>
-#include <zircon/process.h>
 #include <zircon/status.h>
-#include <zircon/threads.h>
 
 #include <algorithm>
-#include <limits>
 #include <memory>
 #include <numeric>
-#include <optional>
-#include <sstream>
 #include <vector>
 
 #include <fbl/algorithm.h>
 #include <fbl/auto_lock.h>
 
-#include "src/devices/lib/goldfish/pipe_headers/include/base.h"
 #include "src/graphics/display/drivers/goldfish-display/render_control.h"
 #include "src/graphics/display/lib/api-types-cpp/config-stamp.h"
 #include "src/graphics/display/lib/api-types-cpp/display-id.h"
 #include "src/graphics/display/lib/api-types-cpp/display-timing.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-buffer-collection-id.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-image-id.h"
-#include "src/lib/fxl/strings/string_printf.h"
 
 namespace goldfish {
 namespace {
@@ -68,120 +53,58 @@
 constexpr uint32_t GL_RGBA = 0x1908;
 constexpr uint32_t GL_BGRA_EXT = 0x80E1;
 
-zx_koid_t GetKoid(zx_handle_t handle) {
-  zx_info_handle_basic_t info;
-  zx_status_t status =
-      zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
-  return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
-}
-
 }  // namespace
 
-// static
-zx_status_t Display::Create(void* ctx, zx_device_t* device) {
-  auto display = std::make_unique<Display>(device);
-
-  zx_status_t status = display->Bind();
-  if (status == ZX_OK) {
-    // devmgr now owns device.
-    [[maybe_unused]] auto* dev = display.release();
-  }
-  return status;
+DisplayEngine::DisplayEngine(fidl::ClientEnd<fuchsia_hardware_goldfish::ControlDevice> control,
+                             fidl::ClientEnd<fuchsia_hardware_goldfish_pipe::GoldfishPipe> pipe,
+                             fidl::ClientEnd<fuchsia_sysmem::Allocator> sysmem_allocator,
+                             std::unique_ptr<RenderControl> render_control,
+                             async_dispatcher_t* display_event_dispatcher)
+    : control_(std::move(control)),
+      pipe_(std::move(pipe)),
+      sysmem_allocator_client_(std::move(sysmem_allocator)),
+      rc_(std::move(render_control)),
+      display_event_dispatcher_(std::move(display_event_dispatcher)) {
+  ZX_DEBUG_ASSERT(control_.is_valid());
+  ZX_DEBUG_ASSERT(pipe_.is_valid());
+  ZX_DEBUG_ASSERT(sysmem_allocator_client_.is_valid());
+  ZX_DEBUG_ASSERT(rc_ != nullptr);
 }
 
-Display::Display(zx_device_t* parent)
-    : DisplayType(parent), loop_(&kAsyncLoopConfigNeverAttachToThread) {
-  if (parent) {
-    control_ = parent;
-  }
-}
+DisplayEngine::~DisplayEngine() {}
 
-Display::~Display() { loop_.Shutdown(); }
-
-zx_status_t Display::Bind() {
+zx::result<> DisplayEngine::Initialize() {
   fbl::AutoLock lock(&lock_);
 
-  if (!control_.is_valid()) {
-    zxlogf(ERROR, "%s: no control protocol", kTag);
-    return ZX_ERR_NOT_SUPPORTED;
-  }
-
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_goldfish_pipe::GoldfishPipe>();
-  if (endpoints.is_error()) {
-    return endpoints.status_value();
-  }
-
-  auto channel = endpoints->server.TakeChannel();
-
-  zx_status_t status = control_.ConnectToPipeDevice(std::move(channel));
-  if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: could not connect to pipe device: %s", kTag, zx_status_get_string(status));
-    return status;
-  }
-
-  pipe_ = fidl::WireSyncClient(std::move(endpoints->client));
-  if (!pipe_.is_valid()) {
-    zxlogf(ERROR, "%s: no pipe protocol", kTag);
-    return ZX_ERR_NOT_SUPPORTED;
-  }
-
-  status = InitSysmemAllocatorClientLocked();
-  if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: cannot initialize sysmem allocator: %s", kTag, zx_status_get_string(status));
-    return status;
-  }
-
-  // Create a second FIDL connection for use by RenderControl.
-  endpoints = fidl::CreateEndpoints<fuchsia_hardware_goldfish_pipe::GoldfishPipe>();
-  if (endpoints.is_error()) {
-    return endpoints.status_value();
-  }
-
-  channel = endpoints->server.TakeChannel();
-
-  status = control_.ConnectToPipeDevice(std::move(channel));
-  if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: could not connect to pipe device: %s", kTag, zx_status_get_string(status));
-    return status;
-  }
-
-  fidl::WireSyncClient pipe_client{std::move(endpoints->client)};
-
-  rc_ = std::make_unique<RenderControl>();
-  status = rc_->InitRcPipe(std::move(pipe_client));
-  if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: RenderControl failed to initialize: %d", kTag, status);
-    return ZX_ERR_NOT_SUPPORTED;
-  }
-
   // Create primary display device.
   static constexpr int32_t kFallbackWidthPx = 1024;
   static constexpr int32_t kFallbackHeightPx = 768;
   static constexpr int32_t kFallbackRefreshRateHz = 60;
-  primary_display_device_ = DisplayDevice{
+  primary_display_device_ = DisplayState{
       .width_px = rc_->GetFbParam(FB_WIDTH, kFallbackWidthPx),
       .height_px = rc_->GetFbParam(FB_HEIGHT, kFallbackHeightPx),
       .refresh_rate_hz = rc_->GetFbParam(FB_FPS, kFallbackRefreshRateHz),
   };
 
   // Set up display and set up flush task for each device.
-  status = SetupPrimaryDisplay();
+  zx_status_t status = SetupPrimaryDisplay();
   if (status != ZX_OK) {
-    zxlogf(ERROR, "Failed to set up the primary display: %s", zx_status_get_string(status));
-    return status;
+    FDF_LOG(ERROR, "Failed to set up the primary display: %s", zx_status_get_string(status));
+    return zx::error(status);
   }
 
-  async::PostTask(loop_.dispatcher(), [this] { FlushPrimaryDisplay(loop_.dispatcher()); });
+  status = async::PostTask(display_event_dispatcher_,
+                           [this] { FlushPrimaryDisplay(display_event_dispatcher_); });
+  if (status != ZX_OK) {
+    FDF_LOG(ERROR, "Failed to post display flush task on the display event loop: %s",
+            zx_status_get_string(status));
+    return zx::error(status);
+  }
 
-  // Start async event thread.
-  loop_.StartThread("goldfish_display_event_thread");
-
-  return DdkAdd("goldfish-display");
+  return zx::ok();
 }
 
-void Display::DdkRelease() { delete this; }
-
-void Display::DisplayControllerImplSetDisplayControllerInterface(
+void DisplayEngine::DisplayControllerImplSetDisplayControllerInterface(
     const display_controller_interface_protocol_t* interface) {
   std::vector<added_display_args_t> args;
 
@@ -229,32 +152,11 @@
   }
 }
 
-void Display::DisplayControllerImplResetDisplayControllerInterface() {
+void DisplayEngine::DisplayControllerImplResetDisplayControllerInterface() {
   fbl::AutoLock lock(&flush_lock_);
   dc_intf_ = ddk::DisplayControllerInterfaceProtocolClient();
 }
 
-zx_status_t Display::InitSysmemAllocatorClientLocked() {
-  auto [client, server] = fidl::Endpoints<fuchsia_sysmem::Allocator>::Create();
-  auto connect_result = pipe_->ConnectSysmem(server.TakeChannel());
-  if (!connect_result.ok()) {
-    zxlogf(ERROR, "Cannot connect to sysmem Allocator protocol: %s",
-           connect_result.status_string());
-    return connect_result.status();
-  }
-  sysmem_allocator_client_ = fidl::WireSyncClient(std::move(client));
-  auto pid = GetKoid(zx_process_self());
-  std::string debug_name = fxl::StringPrintf("goldfish-display");
-  auto set_debug_status =
-      sysmem_allocator_client_->SetDebugClientInfo(fidl::StringView::FromExternal(debug_name), pid);
-  if (!set_debug_status.ok()) {
-    zxlogf(ERROR, "Cannot set sysmem allocator debug info: %s", set_debug_status.status_string());
-    return set_debug_status.status();
-  }
-
-  return ZX_OK;
-}
-
 namespace {
 
 uint32_t GetColorBufferFormatFromSysmemPixelFormat(
@@ -273,7 +175,7 @@
 
 }  // namespace
 
-zx::result<display::DriverImageId> Display::ImportVmoImage(
+zx::result<display::DriverImageId> DisplayEngine::ImportVmoImage(
     const image_metadata_t& image_metadata, const fuchsia_sysmem::PixelFormat& pixel_format,
     zx::vmo vmo, size_t offset) {
   auto color_buffer = std::make_unique<ColorBuffer>();
@@ -298,7 +200,7 @@
   zx::result<HostColorBufferId> create_result =
       rc_->CreateColorBuffer(image_metadata.width, image_metadata.height, color_buffer_format);
   if (create_result.is_error()) {
-    zxlogf(ERROR, "%s: failed to create color buffer: %s", kTag, create_result.status_string());
+    FDF_LOG(ERROR, "%s: failed to create color buffer: %s", kTag, create_result.status_string());
     return create_result.take_error();
   }
   color_buffer->host_color_buffer_id = create_result.value();
@@ -307,12 +209,13 @@
   return zx::ok(image_id);
 }
 
-zx_status_t Display::DisplayControllerImplImportBufferCollection(
+zx_status_t DisplayEngine::DisplayControllerImplImportBufferCollection(
     uint64_t banjo_driver_buffer_collection_id, zx::channel collection_token) {
   const display::DriverBufferCollectionId driver_buffer_collection_id =
       display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
   if (buffer_collections_.find(driver_buffer_collection_id) != buffer_collections_.end()) {
-    zxlogf(ERROR, "Buffer Collection (id=%lu) already exists", driver_buffer_collection_id.value());
+    FDF_LOG(ERROR, "Buffer Collection (id=%lu) already exists",
+            driver_buffer_collection_id.value());
     return ZX_ERR_ALREADY_EXISTS;
   }
 
@@ -325,8 +228,8 @@
       fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken>(std::move(collection_token)),
       std::move(collection_server_endpoint));
   if (!bind_result.ok()) {
-    zxlogf(ERROR, "Cannot complete FIDL call BindSharedCollection: %s",
-           bind_result.status_string());
+    FDF_LOG(ERROR, "Cannot complete FIDL call BindSharedCollection: %s",
+            bind_result.status_string());
     return ZX_ERR_INTERNAL;
   }
 
@@ -335,28 +238,28 @@
   return ZX_OK;
 }
 
-zx_status_t Display::DisplayControllerImplReleaseBufferCollection(
+zx_status_t DisplayEngine::DisplayControllerImplReleaseBufferCollection(
     uint64_t banjo_driver_buffer_collection_id) {
   const display::DriverBufferCollectionId driver_buffer_collection_id =
       display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
   if (buffer_collections_.find(driver_buffer_collection_id) == buffer_collections_.end()) {
-    zxlogf(ERROR, "Cannot release buffer collection %lu: buffer collection doesn't exist",
-           driver_buffer_collection_id.value());
+    FDF_LOG(ERROR, "Cannot release buffer collection %lu: buffer collection doesn't exist",
+            driver_buffer_collection_id.value());
     return ZX_ERR_NOT_FOUND;
   }
   buffer_collections_.erase(driver_buffer_collection_id);
   return ZX_OK;
 }
 
-zx_status_t Display::DisplayControllerImplImportImage(const image_metadata_t* image_metadata,
-                                                      uint64_t banjo_driver_buffer_collection_id,
-                                                      uint32_t index, uint64_t* out_image_handle) {
+zx_status_t DisplayEngine::DisplayControllerImplImportImage(
+    const image_metadata_t* image_metadata, uint64_t banjo_driver_buffer_collection_id,
+    uint32_t index, uint64_t* out_image_handle) {
   const display::DriverBufferCollectionId driver_buffer_collection_id =
       display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
   const auto it = buffer_collections_.find(driver_buffer_collection_id);
   if (it == buffer_collections_.end()) {
-    zxlogf(ERROR, "ImportImage: Cannot find imported buffer collection (id=%lu)",
-           driver_buffer_collection_id.value());
+    FDF_LOG(ERROR, "ImportImage: Cannot find imported buffer collection (id=%lu)",
+            driver_buffer_collection_id.value());
     return ZX_ERR_NOT_FOUND;
   }
 
@@ -396,12 +299,12 @@
   }
 
   if (!vmo.is_valid()) {
-    zxlogf(ERROR, "%s: invalid index", kTag);
+    FDF_LOG(ERROR, "%s: invalid index", kTag);
     return ZX_ERR_OUT_OF_RANGE;
   }
 
   if (!collection_info.settings().has_image_format_constraints()) {
-    zxlogf(ERROR, "Buffer collection doesn't have valid image format constraints");
+    FDF_LOG(ERROR, "Buffer collection doesn't have valid image format constraints");
     return ZX_ERR_NOT_SUPPORTED;
   }
 
@@ -419,7 +322,8 @@
   }
 
   if (offset != 0) {
-    zxlogf(ERROR, "VMO offset (%lu) not supported for Goldfish device local color buffers", offset);
+    FDF_LOG(ERROR, "VMO offset (%lu) not supported for Goldfish device local color buffers",
+            offset);
     return ZX_ERR_NOT_SUPPORTED;
   }
 
@@ -431,7 +335,7 @@
   return ZX_OK;
 }
 
-void Display::DisplayControllerImplReleaseImage(uint64_t image_handle) {
+void DisplayEngine::DisplayControllerImplReleaseImage(uint64_t image_handle) {
   auto color_buffer = reinterpret_cast<ColorBuffer*>(image_handle);
 
   // Color buffer is owned by image in the linear case.
@@ -439,7 +343,7 @@
     rc_->CloseColorBuffer(color_buffer->host_color_buffer_id);
   }
 
-  async::PostTask(loop_.dispatcher(), [this, color_buffer] {
+  async::PostTask(display_event_dispatcher_, [this, color_buffer] {
     if (primary_display_device_.incoming_config.has_value() &&
         primary_display_device_.incoming_config->color_buffer == color_buffer) {
       primary_display_device_.incoming_config = std::nullopt;
@@ -448,7 +352,7 @@
   });
 }
 
-config_check_result_t Display::DisplayControllerImplCheckConfiguration(
+config_check_result_t DisplayEngine::DisplayControllerImplCheckConfiguration(
     const display_config_t** display_configs, size_t display_count,
     client_composition_opcode_t* out_client_composition_opcodes_list,
     size_t client_composition_opcodes_count, size_t* out_client_composition_opcodes_actual) {
@@ -486,7 +390,7 @@
         // TODO(https://fxbug.dev/42111684): Returning error will cause blank screen if scenic
         // requests color correction. For now, lets pretend we support it, until a proper fix is
         // done (either from scenic or from core display)
-        zxlogf(WARNING, "%s: Color Correction not support. No error reported", __func__);
+        FDF_LOG(WARNING, "%s: Color Correction not support. No error reported", __func__);
       }
 
       if (display_configs[i]->layer_list[0]->type != LAYER_TYPE_PRIMARY) {
@@ -506,8 +410,8 @@
         frame_t src_frame = {
             .x_pos = 0,
             .y_pos = 0,
-            .width = layer->image.width,
-            .height = layer->image.height,
+            .width = layer->image_metadata.width,
+            .height = layer->image_metadata.height,
         };
         if (memcmp(&layer->dest_frame, &dest_frame, sizeof(frame_t)) != 0) {
           // TODO(https://fxbug.dev/42111727): Need to provide proper flag to indicate driver only
@@ -541,7 +445,7 @@
   return CONFIG_CHECK_RESULT_OK;
 }
 
-zx_status_t Display::PresentPrimaryDisplayConfig(const DisplayConfig& display_config) {
+zx_status_t DisplayEngine::PresentPrimaryDisplayConfig(const DisplayConfig& display_config) {
   ColorBuffer* color_buffer = display_config.color_buffer;
   if (!color_buffer) {
     return ZX_OK;
@@ -550,7 +454,7 @@
   zx::eventpair event_display, event_sync_device;
   zx_status_t status = zx::eventpair::create(0u, &event_display, &event_sync_device);
   if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: zx_eventpair_create failed: %d", kTag, status);
+    FDF_LOG(ERROR, "%s: zx_eventpair_create failed: %d", kTag, status);
     return status;
   }
 
@@ -561,42 +465,43 @@
                                                             ZX_EVENTPAIR_SIGNALED, 0);
   async::WaitOnce& wait = primary_display_device_.pending_config_waits.back();
 
-  wait.Begin(loop_.dispatcher(), [this, event = std::move(event_display),
-                                  pending_config_stamp = display_config.config_stamp](
-                                     async_dispatcher_t* dispatcher, async::WaitOnce* current_wait,
-                                     zx_status_t status, const zx_packet_signal_t*) {
-    TRACE_DURATION("gfx", "Display::SyncEventHandler", "config_stamp",
-                   pending_config_stamp.value());
-    if (status == ZX_ERR_CANCELED) {
-      zxlogf(INFO, "Wait for config stamp %lu cancelled.", pending_config_stamp.value());
-      return;
-    }
-    ZX_DEBUG_ASSERT_MSG(status == ZX_OK, "Invalid wait status: %d\n", status);
+  wait.Begin(
+      display_event_dispatcher_,
+      [this, event = std::move(event_display), pending_config_stamp = display_config.config_stamp](
+          async_dispatcher_t* dispatcher, async::WaitOnce* current_wait, zx_status_t status,
+          const zx_packet_signal_t*) {
+        TRACE_DURATION("gfx", "DisplayEngine::SyncEventHandler", "config_stamp",
+                       pending_config_stamp.value());
+        if (status == ZX_ERR_CANCELED) {
+          FDF_LOG(INFO, "Wait for config stamp %lu cancelled.", pending_config_stamp.value());
+          return;
+        }
+        ZX_DEBUG_ASSERT_MSG(status == ZX_OK, "Invalid wait status: %d\n", status);
 
-    // When the eventpair in |current_wait| is signalled, all the pending waits
-    // that are queued earlier than that eventpair will be removed from the list
-    // and the async WaitOnce will be cancelled.
-    // Note that the cancelled waits will return early and will not reach here.
-    ZX_DEBUG_ASSERT(std::any_of(primary_display_device_.pending_config_waits.begin(),
-                                primary_display_device_.pending_config_waits.end(),
-                                [current_wait](const async::WaitOnce& wait) {
-                                  return wait.object() == current_wait->object();
-                                }));
-    // Remove all the pending waits that are queued earlier than the current
-    // wait, and the current wait itself. In WaitOnce, the callback is moved to
-    // stack before current wait is removed, so it's safe to remove any item in
-    // the list.
-    for (auto it = primary_display_device_.pending_config_waits.begin();
-         it != primary_display_device_.pending_config_waits.end();) {
-      if (it->object() == current_wait->object()) {
-        primary_display_device_.pending_config_waits.erase(it);
-        break;
-      }
-      it = primary_display_device_.pending_config_waits.erase(it);
-    }
-    primary_display_device_.latest_config_stamp =
-        std::max(primary_display_device_.latest_config_stamp, pending_config_stamp);
-  });
+        // When the eventpair in |current_wait| is signalled, all the pending waits
+        // that are queued earlier than that eventpair will be removed from the list
+        // and the async WaitOnce will be cancelled.
+        // Note that the cancelled waits will return early and will not reach here.
+        ZX_DEBUG_ASSERT(std::any_of(primary_display_device_.pending_config_waits.begin(),
+                                    primary_display_device_.pending_config_waits.end(),
+                                    [current_wait](const async::WaitOnce& wait) {
+                                      return wait.object() == current_wait->object();
+                                    }));
+        // Remove all the pending waits that are queued earlier than the current
+        // wait, and the current wait itself. In WaitOnce, the callback is moved to
+        // stack before current wait is removed, so it's safe to remove any item in
+        // the list.
+        for (auto it = primary_display_device_.pending_config_waits.begin();
+             it != primary_display_device_.pending_config_waits.end();) {
+          if (it->object() == current_wait->object()) {
+            primary_display_device_.pending_config_waits.erase(it);
+            break;
+          }
+          it = primary_display_device_.pending_config_waits.erase(it);
+        }
+        primary_display_device_.latest_config_stamp =
+            std::max(primary_display_device_.latest_config_stamp, pending_config_stamp);
+      });
 
   // Update host-writeable display buffers before presenting.
   if (color_buffer->pinned_vmo.region_count() > 0) {
@@ -604,8 +509,8 @@
         color_buffer->host_color_buffer_id, color_buffer->pinned_vmo, color_buffer->width,
         color_buffer->height, color_buffer->format, color_buffer->size);
     if (status.is_error() || status.value()) {
-      zxlogf(ERROR, "%s : color buffer update failed: %d:%u", kTag, status.status_value(),
-             status.value_or(0));
+      FDF_LOG(ERROR, "%s : color buffer update failed: %d:%u", kTag, status.status_value(),
+              status.value_or(0));
       return status.is_error() ? status.status_value() : ZX_ERR_INTERNAL;
     }
   }
@@ -614,26 +519,31 @@
   {
     zx_status_t status = rc_->FbPost(color_buffer->host_color_buffer_id);
     if (status != ZX_OK) {
-      zxlogf(ERROR, "Failed to call render control command FbPost: %s",
-             zx_status_get_string(status));
+      FDF_LOG(ERROR, "Failed to call render control command FbPost: %s",
+              zx_status_get_string(status));
       return status;
     }
 
     fbl::AutoLock lock(&lock_);
-    status = control_.CreateSyncFence(std::move(event_sync_device));
-    if (status != ZX_OK) {
-      zxlogf(ERROR, "Failed to call render control command CreateSyncFence: %s",
-             zx_status_get_string(status));
+    fidl::WireResult result = control_->CreateSyncFence(std::move(event_sync_device));
+    if (!result.ok()) {
+      FDF_LOG(ERROR, "Failed to call FIDL CreateSyncFence: %s",
+              result.error().FormatDescription().c_str());
       return status;
     }
+    if (result.value().is_error()) {
+      FDF_LOG(ERROR, "Failed to create SyncFence: %s",
+              zx_status_get_string(result.value().error_value()));
+      return result.value().error_value();
+    }
   }
 
   return ZX_OK;
 }
 
-void Display::DisplayControllerImplApplyConfiguration(const display_config_t** display_configs,
-                                                      size_t display_count,
-                                                      const config_stamp_t* banjo_config_stamp) {
+void DisplayEngine::DisplayControllerImplApplyConfiguration(
+    const display_config_t** display_configs, size_t display_count,
+    const config_stamp_t* banjo_config_stamp) {
   ZX_DEBUG_ASSERT(banjo_config_stamp != nullptr);
   display::ConfigStamp config_stamp = display::ToConfigStamp(*banjo_config_stamp);
   display::DriverImageId driver_image_id = display::kInvalidDriverImageId;
@@ -643,7 +553,7 @@
     if (display::ToDisplayId(display_config->display_id) == kPrimaryDisplayId) {
       if (display_config->layer_count) {
         driver_image_id =
-            display::ToDriverImageId(display_config->layer_list[0]->cfg.primary.image.handle);
+            display::ToDriverImageId(display_config->layer_list[0]->cfg.primary.image_handle);
       }
       break;
     }
@@ -654,7 +564,7 @@
     // previously existed, we should cancel waiting events on the pending
     // color buffer and remove references to both pending and current color
     // buffers.
-    async::PostTask(loop_.dispatcher(), [this, config_stamp] {
+    async::PostTask(display_event_dispatcher_, [this, config_stamp] {
       primary_display_device_.pending_config_waits.clear();
       primary_display_device_.incoming_config = std::nullopt;
       primary_display_device_.latest_config_stamp =
@@ -671,20 +581,31 @@
 
     zx_status_t status = color_buffer->vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo);
     if (status != ZX_OK) {
-      zxlogf(ERROR, "Failed to duplicate vmo: %s", zx_status_get_string(status));
+      FDF_LOG(ERROR, "Failed to duplicate vmo: %s", zx_status_get_string(status));
       return;
     }
 
     {
       fbl::AutoLock lock(&lock_);
 
-      uint32_t render_control_encoded_color_buffer_id = kInvalidHostColorBufferId.value();
-      zx_status_t status =
-          control_.GetColorBuffer(std::move(vmo), &render_control_encoded_color_buffer_id);
-      if (status != ZX_OK) {
-        zxlogf(ERROR, "Failed to get color buffer: %s", zx_status_get_string(status));
+      fidl::WireResult result = control_->GetBufferHandle(std::move(vmo));
+      if (!result.ok()) {
+        FDF_LOG(ERROR, "Failed to call FIDL GetBufferHandle: %s",
+                result.error().FormatDescription().c_str());
         return;
       }
+      if (result.value().res != ZX_OK) {
+        FDF_LOG(ERROR, "Failed to get ColorBuffer handle: %s",
+                zx_status_get_string(result.value().res));
+        return;
+      }
+      if (result.value().type != fuchsia_hardware_goldfish::BufferHandleType::kColorBuffer) {
+        FDF_LOG(ERROR, "Buffer handle type invalid. Expected ColorBuffer, actual %" PRIu32,
+                static_cast<uint32_t>(result.value().type));
+        return;
+      }
+
+      uint32_t render_control_encoded_color_buffer_id = result.value().id;
       color_buffer->host_color_buffer_id =
           ToHostColorBufferId(render_control_encoded_color_buffer_id);
 
@@ -697,17 +618,17 @@
         zx::result<RenderControl::RcResult> status = rc_->SetColorBufferVulkanMode(
             color_buffer->host_color_buffer_id, /*mode=*/kVulkanGlSharedMode);
         if (status.is_error()) {
-          zxlogf(ERROR, "Failed to call render control SetColorBufferVulkanMode: %s",
-                 status.status_string());
+          FDF_LOG(ERROR, "Failed to call render control SetColorBufferVulkanMode: %s",
+                  status.status_string());
         }
         if (status.value() != 0) {
-          zxlogf(ERROR, "Render control host failed to set vulkan mode: %d", status.value());
+          FDF_LOG(ERROR, "Render control host failed to set vulkan mode: %d", status.value());
         }
       }
     }
   }
 
-  async::PostTask(loop_.dispatcher(), [this, config_stamp, color_buffer] {
+  async::PostTask(display_event_dispatcher_, [this, config_stamp, color_buffer] {
     primary_display_device_.incoming_config = {
         .color_buffer = color_buffer,
         .config_stamp = config_stamp,
@@ -715,14 +636,14 @@
   });
 }
 
-zx_status_t Display::DisplayControllerImplSetBufferCollectionConstraints(
+zx_status_t DisplayEngine::DisplayControllerImplSetBufferCollectionConstraints(
     const image_buffer_usage_t* usage, uint64_t banjo_driver_buffer_collection_id) {
   const display::DriverBufferCollectionId driver_buffer_collection_id =
       display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
   const auto it = buffer_collections_.find(driver_buffer_collection_id);
   if (it == buffer_collections_.end()) {
-    zxlogf(ERROR, "ImportImage: Cannot find imported buffer collection (id=%lu)",
-           driver_buffer_collection_id.value());
+    FDF_LOG(ERROR, "ImportImage: Cannot find imported buffer collection (id=%lu)",
+            driver_buffer_collection_id.value());
     return ZX_ERR_NOT_FOUND;
   }
   const fidl::SyncClient<fuchsia_sysmem::BufferCollection>& collection = it->second;
@@ -770,14 +691,14 @@
 
   auto set_result = collection->SetConstraints({true, std::move(constraints)});
   if (set_result.is_error()) {
-    zxlogf(ERROR, "%s: failed to set constraints", kTag);
+    FDF_LOG(ERROR, "%s: failed to set constraints", kTag);
     return set_result.error_value().status();
   }
 
   return ZX_OK;
 }
 
-zx_status_t Display::SetupPrimaryDisplay() {
+zx_status_t DisplayEngine::SetupPrimaryDisplay() {
   // On the host render control protocol, the "invalid" host display ID is used
   // to configure the primary display device.
   const HostDisplayId kPrimaryHostDisplayId = kInvalidHostDisplayId;
@@ -785,20 +706,20 @@
       rc_->SetDisplayPose(kPrimaryHostDisplayId, /*x=*/0, /*y=*/0, primary_display_device_.width_px,
                           primary_display_device_.height_px);
   if (status.is_error()) {
-    zxlogf(ERROR, "Failed to call render control SetDisplayPose command: %s",
-           status.status_string());
+    FDF_LOG(ERROR, "Failed to call render control SetDisplayPose command: %s",
+            status.status_string());
     return status.error_value();
   }
   if (status.value() != 0) {
-    zxlogf(ERROR, "Render control host failed to set display pose: %d", status.value());
+    FDF_LOG(ERROR, "Render control host failed to set display pose: %d", status.value());
     return ZX_ERR_INTERNAL;
   }
-  primary_display_device_.expected_next_flush = async::Now(loop_.dispatcher());
+  primary_display_device_.expected_next_flush = async::Now(display_event_dispatcher_);
 
   return ZX_OK;
 }
 
-void Display::FlushPrimaryDisplay(async_dispatcher_t* dispatcher) {
+void DisplayEngine::FlushPrimaryDisplay(async_dispatcher_t* dispatcher) {
   zx::duration period = zx::sec(1) / primary_display_device_.refresh_rate_hz;
   zx::time expected_next_flush = primary_display_device_.expected_next_flush + period;
 
@@ -832,8 +753,8 @@
       dispatcher, [this, dispatcher] { FlushPrimaryDisplay(dispatcher); }, expected_next_flush);
 }
 
-void Display::SetupPrimaryDisplayForTesting(int32_t width_px, int32_t height_px,
-                                            int32_t refresh_rate_hz) {
+void DisplayEngine::SetupPrimaryDisplayForTesting(int32_t width_px, int32_t height_px,
+                                                  int32_t refresh_rate_hz) {
   primary_display_device_ = {
       .width_px = width_px,
       .height_px = height_px,
@@ -842,12 +763,3 @@
 }
 
 }  // namespace goldfish
-
-static constexpr zx_driver_ops_t goldfish_display_driver_ops = []() -> zx_driver_ops_t {
-  zx_driver_ops_t ops = {};
-  ops.version = DRIVER_OPS_VERSION;
-  ops.bind = goldfish::Display::Create;
-  return ops;
-}();
-
-ZIRCON_DRIVER(goldfish_display, goldfish_display_driver_ops, "zircon", "0.1");
diff --git a/src/graphics/display/drivers/goldfish-display/display.h b/src/graphics/display/drivers/goldfish-display/display-engine.h
similarity index 79%
rename from src/graphics/display/drivers/goldfish-display/display.h
rename to src/graphics/display/drivers/goldfish-display/display-engine.h
index b502881..b87ccf0 100644
--- a/src/graphics/display/drivers/goldfish-display/display.h
+++ b/src/graphics/display/drivers/goldfish-display/display-engine.h
@@ -2,17 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_H_
-#define SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_H_
+#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_ENGINE_H_
+#define SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_ENGINE_H_
 
 #include <fidl/fuchsia.hardware.goldfish.pipe/cpp/wire.h>
+#include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
 #include <fidl/fuchsia.sysmem/cpp/fidl.h>
 #include <fuchsia/hardware/display/controller/cpp/banjo.h>
-#include <fuchsia/hardware/goldfish/control/cpp/banjo.h>
-#include <lib/async-loop/cpp/loop.h>
 #include <lib/async/cpp/wait.h>
-#include <lib/ddk/device.h>
-#include <lib/fidl/cpp/wire/channel.h>
+#include <lib/fdf/cpp/dispatcher.h>
 #include <lib/fzl/pinned-vmo.h>
 #include <lib/zircon-internal/thread_annotations.h>
 #include <lib/zx/result.h>
@@ -20,39 +18,37 @@
 #include <zircon/types.h>
 
 #include <list>
-#include <map>
 #include <memory>
 
-#include <ddktl/device.h>
-#include <fbl/auto_lock.h>
-#include <fbl/condition_variable.h>
 #include <fbl/mutex.h>
 
-#include "src/devices/lib/goldfish/pipe_io/pipe_io.h"
 #include "src/graphics/display/drivers/goldfish-display/render_control.h"
 #include "src/graphics/display/lib/api-types-cpp/config-stamp.h"
-#include "src/graphics/display/lib/api-types-cpp/display-id.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-buffer-collection-id.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-image-id.h"
 
 namespace goldfish {
 
-class Display;
-using DisplayType = ddk::Device<Display>;
-
-class Display : public DisplayType,
-                public ddk::DisplayControllerImplProtocol<Display, ddk::base_protocol> {
+class DisplayEngine : public ddk::DisplayControllerImplProtocol<DisplayEngine> {
  public:
-  static zx_status_t Create(void* ctx, zx_device_t* parent);
+  // `control`, `pipe`, `sysmem_allocator` must be valid.
+  // `render_control` must not be null.
+  // `display_event_dispatcher` must be non-null and outlive `DisplayEngine`.
+  explicit DisplayEngine(fidl::ClientEnd<fuchsia_hardware_goldfish::ControlDevice> control,
+                         fidl::ClientEnd<fuchsia_hardware_goldfish_pipe::GoldfishPipe> pipe,
+                         fidl::ClientEnd<fuchsia_sysmem::Allocator> sysmem_allocator,
+                         std::unique_ptr<RenderControl> render_control,
+                         async_dispatcher_t* display_event_dispatcher);
 
-  explicit Display(zx_device_t* parent);
+  DisplayEngine(const DisplayEngine&) = delete;
+  DisplayEngine(DisplayEngine&&) = delete;
+  DisplayEngine& operator=(const DisplayEngine&) = delete;
+  DisplayEngine& operator=(DisplayEngine&&) = delete;
 
-  ~Display();
+  ~DisplayEngine();
 
-  zx_status_t Bind();
-
-  // Device protocol implementation.
-  void DdkRelease();
+  // Performs initialization that cannot be done in the constructor.
+  zx::result<> Initialize();
 
   // Display controller protocol implementation.
   void DisplayControllerImplSetDisplayControllerInterface(
@@ -97,13 +93,12 @@
     return ZX_ERR_NOT_SUPPORTED;
   }
 
-  void SetSysmemAllocatorForTesting(
-      fidl::WireSyncClient<fuchsia_sysmem::Allocator> sysmem_allocator_client) {
-    sysmem_allocator_client_ = std::move(sysmem_allocator_client);
-  }
-
   void SetupPrimaryDisplayForTesting(int32_t width_px, int32_t height_px, int32_t refresh_rate_hz);
 
+  const display_controller_impl_protocol_ops_t* display_controller_impl_protocol_ops() const {
+    return &display_controller_impl_protocol_ops_;
+  }
+
  private:
   struct ColorBuffer {
     ~ColorBuffer() = default;
@@ -137,7 +132,9 @@
     display::ConfigStamp config_stamp = display::kInvalidConfigStamp;
   };
 
-  struct DisplayDevice {
+  // TODO(https://fxbug.dev/335324453): Define DisplayState as a class with
+  // proper rep invariants on each config update / config flush.
+  struct DisplayState {
     int32_t width_px = 0;
     int32_t height_px = 0;
     int32_t refresh_rate_hz = 60;
@@ -165,7 +162,7 @@
   //
   // On success, returns ZX_OK and the sysmem allocator client will be open
   // until the device is released.
-  zx_status_t InitSysmemAllocatorClientLocked() TA_REQ(lock_);
+  zx_status_t InitSysmemAllocatorClient();
 
   zx::result<display::DriverImageId> ImportVmoImage(const image_metadata_t& image_metadata,
                                                     const fuchsia_sysmem::PixelFormat& pixel_format,
@@ -176,7 +173,7 @@
   void FlushPrimaryDisplay(async_dispatcher_t* dispatcher);
 
   fbl::Mutex lock_;
-  ddk::GoldfishControlProtocolClient control_ TA_GUARDED(lock_);
+  fidl::WireSyncClient<fuchsia_hardware_goldfish::ControlDevice> control_ TA_GUARDED(lock_);
   fidl::WireSyncClient<fuchsia_hardware_goldfish_pipe::GoldfishPipe> pipe_ TA_GUARDED(lock_);
 
   // The sysmem allocator client used to bind incoming buffer collection tokens.
@@ -188,18 +185,13 @@
       buffer_collections_;
 
   std::unique_ptr<RenderControl> rc_;
-  zx::bti bti_;
-  ddk::IoBuffer cmd_buffer_ TA_GUARDED(lock_);
-  ddk::IoBuffer io_buffer_ TA_GUARDED(lock_);
-  DisplayDevice primary_display_device_ = {};
+  DisplayState primary_display_device_ = {};
   fbl::Mutex flush_lock_;
   ddk::DisplayControllerInterfaceProtocolClient dc_intf_ TA_GUARDED(flush_lock_);
 
-  async::Loop loop_;
-
-  DISALLOW_COPY_ASSIGN_AND_MOVE(Display);
+  async_dispatcher_t* const display_event_dispatcher_;
 };
 
 }  // namespace goldfish
 
-#endif  // SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_H_
+#endif  // SRC_GRAPHICS_DISPLAY_DRIVERS_GOLDFISH_DISPLAY_DISPLAY_ENGINE_H_
diff --git a/src/graphics/display/drivers/goldfish-display/meta/goldfish-display.cml b/src/graphics/display/drivers/goldfish-display/meta/goldfish-display.cml
index 1476934..6c059b6 100644
--- a/src/graphics/display/drivers/goldfish-display/meta/goldfish-display.cml
+++ b/src/graphics/display/drivers/goldfish-display/meta/goldfish-display.cml
@@ -3,17 +3,21 @@
 // found in the LICENSE file.
 {
     include: [
-        "//sdk/lib/driver/compat/compat.shard.cml",
+        "driver_component/driver.shard.cml",
         "inspect/client.shard.cml",
         "syslog/client.shard.cml",
     ],
     program: {
         runner: "driver",
+        binary: "driver/goldfish-display.so",
         bind: "meta/bind/goldfish-display-bind.bindbc",
-        colocate: "true",
-        compat: "driver/goldfish-display.so",
+        colocate: "false",
         default_dispatcher_opts: [ "allow_sync_calls" ],
         fallback: "false",
     },
-    use: [],
+    use: [
+        { service: "fuchsia.hardware.goldfish.ControlService" },
+        { service: "fuchsia.hardware.goldfish.pipe.Service" },
+        { service: "fuchsia.hardware.sysmem.Service" },
+    ],
 }
diff --git a/src/graphics/display/drivers/goldfish-display/render_control.cc b/src/graphics/display/drivers/goldfish-display/render_control.cc
index 4a6a8f1..88b9972 100644
--- a/src/graphics/display/drivers/goldfish-display/render_control.cc
+++ b/src/graphics/display/drivers/goldfish-display/render_control.cc
@@ -5,8 +5,9 @@
 #include "src/graphics/display/drivers/goldfish-display/render_control.h"
 
 #include <fidl/fuchsia.hardware.goldfish.pipe/cpp/wire.h>
-#include <lib/ddk/trace/event.h>
+#include <lib/driver/logging/cpp/logger.h>
 #include <lib/fidl/cpp/wire/channel.h>
+#include <lib/trace/event.h>
 
 #include <memory>
 
@@ -128,7 +129,7 @@
     fidl::WireSyncClient<fuchsia_hardware_goldfish_pipe::GoldfishPipe> pipe) {
   pipe_io_ = std::make_unique<PipeIo>(std::move(pipe), kPipeName);
   if (!pipe_io_->valid()) {
-    zxlogf(ERROR, "PipeIo failed to initialize");
+    FDF_LOG(ERROR, "PipeIo failed to initialize");
     return ZX_ERR_NOT_SUPPORTED;
   }
 
@@ -136,7 +137,7 @@
   PipeIo::WriteSrc src[] = {{.data = ToByteSpan(kClientFlags)}};
   auto status = pipe_io_->Write(src, true);
   if (status != ZX_OK) {
-    zxlogf(ERROR, "Write client flags failed");
+    FDF_LOG(ERROR, "Write client flags failed");
     return ZX_ERR_NOT_SUPPORTED;
   }
 
diff --git a/src/graphics/display/drivers/goldfish-display/render_control.h b/src/graphics/display/drivers/goldfish-display/render_control.h
index ff2774c..60ea7f8 100644
--- a/src/graphics/display/drivers/goldfish-display/render_control.h
+++ b/src/graphics/display/drivers/goldfish-display/render_control.h
@@ -12,7 +12,6 @@
 #include <map>
 #include <memory>
 
-#include <ddktl/device.h>
 #include <fbl/strong_int.h>
 
 #include "src/devices/lib/goldfish/pipe_io/pipe_io.h"
diff --git a/src/graphics/display/drivers/intel-i915/display-device.cc b/src/graphics/display/drivers/intel-i915/display-device.cc
index a1e266e..299f905 100644
--- a/src/graphics/display/drivers/intel-i915/display-device.cc
+++ b/src/graphics/display/drivers/intel-i915/display-device.cc
@@ -242,11 +242,12 @@
   if (pipe_) {
     pipe_->ApplyConfiguration(
         banjo_display_config, config_stamp,
-        [controller = controller_](const image_t* image, uint32_t rotation) -> const GttRegion& {
-          return controller->SetupGttImage(image, rotation);
+        [controller = controller_](const image_metadata_t& image_metadata, uint64_t image_handle,
+                                   uint32_t rotation) -> const GttRegion& {
+          return controller->SetupGttImage(image_metadata, image_handle, rotation);
         },
-        [controller = controller_](const image_t* image) -> PixelFormatAndModifier {
-          const display::DriverImageId image_id(image->handle);
+        [controller = controller_](uint64_t image_handle) -> PixelFormatAndModifier {
+          const display::DriverImageId image_id = display::ToDriverImageId(image_handle);
           return controller->GetImportedImagePixelFormat(image_id);
         });
   }
diff --git a/src/graphics/display/drivers/intel-i915/gtt.cc b/src/graphics/display/drivers/intel-i915/gtt.cc
index 73d5a84..842ef3e 100644
--- a/src/graphics/display/drivers/intel-i915/gtt.cc
+++ b/src/graphics/display/drivers/intel-i915/gtt.cc
@@ -238,7 +238,7 @@
   vmo_ = ZX_HANDLE_INVALID;
 }
 
-void GttRegionImpl::SetRotation(uint32_t rotation, const image_t& image) {
+void GttRegionImpl::SetRotation(uint32_t rotation, const image_metadata_t& image_metadata) {
   bool rotated = (rotation == FRAME_TRANSFORM_ROT_90 || rotation == FRAME_TRANSFORM_ROT_270);
   if (rotated == is_rotated_) {
     return;
@@ -253,12 +253,12 @@
 
   uint64_t mask = is_rotated_ ? kRotatedFlag : 0;
   uint32_t width = [&]() {
-    uint64_t width = bytes_per_row() / get_tile_byte_width(image.tiling_type);
+    uint64_t width = bytes_per_row() / get_tile_byte_width(image_metadata.tiling_type);
     ZX_DEBUG_ASSERT_MSG(width <= std::numeric_limits<uint32_t>::max(), "%lu overflows uint32_t",
                         width);
     return static_cast<uint32_t>(width);
   }();
-  uint32_t height = height_in_tiles(image.tiling_type, image.height);
+  uint32_t height = height_in_tiles(image_metadata.tiling_type, image_metadata.height);
 
   auto mmio_space = &gtt_->buffer_.value();
   uint32_t pte_offset = static_cast<uint32_t>(base() / PAGE_SIZE);
diff --git a/src/graphics/display/drivers/intel-i915/gtt.h b/src/graphics/display/drivers/intel-i915/gtt.h
index 3b8e81a..10d3b58 100644
--- a/src/graphics/display/drivers/intel-i915/gtt.h
+++ b/src/graphics/display/drivers/intel-i915/gtt.h
@@ -43,7 +43,7 @@
   GttRegionImpl(Gtt* gtt, RegionAllocator::Region::UPtr region);
   ~GttRegionImpl() override;
 
-  void SetRotation(uint32_t rotation, const image_t& image);
+  void SetRotation(uint32_t rotation, const image_metadata_t& image_metadata);
 
   zx_status_t PopulateRegion(zx_handle_t vmo, uint64_t page_offset, uint64_t length,
                              bool writable = false);
diff --git a/src/graphics/display/drivers/intel-i915/intel-i915-test.cc b/src/graphics/display/drivers/intel-i915/intel-i915-test.cc
index 0d59bb1..a131d50 100644
--- a/src/graphics/display/drivers/intel-i915/intel-i915-test.cc
+++ b/src/graphics/display/drivers/intel-i915/intel-i915-test.cc
@@ -651,14 +651,9 @@
         &kDisplayImageMetadata, kBanjoBufferCollectionId, /*index=*/0, &image_handle));
   });
 
-  const image_t image = {
-      .width = 128,
-      .height = kImageHeight,
-      .tiling_type = IMAGE_TILING_TYPE_LINEAR,
-      .handle = image_handle,
-  };
-  const GttRegion& region = ctx->SetupGttImage(&image, FRAME_TRANSFORM_IDENTITY);
-  EXPECT_LT(image.width * 4, kBytesPerRowDivisor);
+  const GttRegion& region =
+      ctx->SetupGttImage(kDisplayImageMetadata, image_handle, FRAME_TRANSFORM_IDENTITY);
+  EXPECT_LT(kDisplayImageMetadata.width * 4, kBytesPerRowDivisor);
   EXPECT_EQ(kBytesPerRowDivisor, region.bytes_per_row());
   ctx->DisplayControllerImplReleaseImage(image_handle);
 }
@@ -710,14 +705,9 @@
   });
 
   // Check that rotating the image doesn't hang.
-  const image_t image = {
-      .width = 128,
-      .height = kImageHeight,
-      .tiling_type = IMAGE_TILING_TYPE_Y_LEGACY_TILED,
-      .handle = image_handle,
-  };
-  const GttRegion& region = ctx->SetupGttImage(&image, FRAME_TRANSFORM_ROT_90);
-  EXPECT_LT(image.width * 4, kBytesPerRowDivisor);
+  const GttRegion& region =
+      ctx->SetupGttImage(kTiledImageMetadata, image_handle, FRAME_TRANSFORM_ROT_90);
+  EXPECT_LT(kTiledImageMetadata.width * 4, kBytesPerRowDivisor);
   EXPECT_EQ(kBytesPerRowDivisor, region.bytes_per_row());
   ctx->DisplayControllerImplReleaseImage(image_handle);
 }
diff --git a/src/graphics/display/drivers/intel-i915/intel-i915.cc b/src/graphics/display/drivers/intel-i915/intel-i915.cc
index 1254cca..25cc049 100644
--- a/src/graphics/display/drivers/intel-i915/intel-i915.cc
+++ b/src/graphics/display/drivers/intel-i915/intel-i915.cc
@@ -517,10 +517,11 @@
   return gtt_.Init(pci, std::move(buffer), fb_offset);
 }
 
-const GttRegion& Controller::SetupGttImage(const image_t* image, uint32_t rotation) {
-  const std::unique_ptr<GttRegionImpl>& region = GetGttRegionImpl(image->handle);
+const GttRegion& Controller::SetupGttImage(const image_metadata_t& image_metadata,
+                                           uint64_t image_handle, uint32_t rotation) {
+  const std::unique_ptr<GttRegionImpl>& region = GetGttRegionImpl(image_handle);
   ZX_DEBUG_ASSERT(region);
-  region->SetRotation(rotation, *image);
+  region->SetRotation(rotation, image_metadata);
   return *region;
 }
 
@@ -1168,8 +1169,8 @@
       ZX_ASSERT(layer->type == LAYER_TYPE_PRIMARY);
       const primary_layer_t* primary = &layer->cfg.primary;
 
-      if (primary->image.tiling_type == IMAGE_TILING_TYPE_LINEAR ||
-          primary->image.tiling_type == IMAGE_TILING_TYPE_X_TILED) {
+      if (primary->image_metadata.tiling_type == IMAGE_TILING_TYPE_LINEAR ||
+          primary->image_metadata.tiling_type == IMAGE_TILING_TYPE_X_TILED) {
         min_allocs[pipe_id][plane_num] = 8;
       } else {
         uint32_t plane_source_width;
@@ -1184,7 +1185,7 @@
         // need to populate the image_t.handle of pending layers first so that
         // the image of primary layer can be correctly resolved.
         constexpr int bytes_per_pixel = 4;
-        const display::DriverImageId primary_image_id(primary->image.handle);
+        const display::DriverImageId primary_image_id(primary->image_handle);
         if (primary_image_id != display::kInvalidDriverImageId) {
           ZX_DEBUG_ASSERT(bytes_per_pixel == ImageFormatStrideBytesPerWidthPixel(
                                                  GetImportedImagePixelFormat(primary_image_id)));
@@ -1361,7 +1362,7 @@
         constexpr int bytes_per_pixel = 4;
         // Plane buffers are recalculated only on valid configurations. So all
         // images must be valid.
-        const display::DriverImageId primary_image_id(primary->image.handle);
+        const display::DriverImageId primary_image_id(primary->image_handle);
         ZX_DEBUG_ASSERT(primary_image_id != display::kInvalidDriverImageId);
         ZX_DEBUG_ASSERT(bytes_per_pixel == ImageFormatStrideBytesPerWidthPixel(
                                                GetImportedImagePixelFormat(primary_image_id)));
@@ -1673,8 +1674,8 @@
           if (primary->transform_mode == FRAME_TRANSFORM_ROT_90 ||
               primary->transform_mode == FRAME_TRANSFORM_ROT_270) {
             // Linear and x tiled images don't support 90/270 rotation
-            if (primary->image.tiling_type == IMAGE_TILING_TYPE_LINEAR ||
-                primary->image.tiling_type == IMAGE_TILING_TYPE_X_TILED) {
+            if (primary->image_metadata.tiling_type == IMAGE_TILING_TYPE_LINEAR ||
+                primary->image_metadata.tiling_type == IMAGE_TILING_TYPE_X_TILED) {
               current_display_client_composition_opcodes[j] |= CLIENT_COMPOSITION_OPCODE_TRANSFORM;
             }
           } else if (primary->transform_mode != FRAME_TRANSFORM_IDENTITY &&
@@ -1689,8 +1690,8 @@
           // If the plane is too wide, force the client to do all composition
           // and just give us a simple configuration.
           uint32_t max_width;
-          if (primary->image.tiling_type == IMAGE_TILING_TYPE_LINEAR ||
-              primary->image.tiling_type == IMAGE_TILING_TYPE_X_TILED) {
+          if (primary->image_metadata.tiling_type == IMAGE_TILING_TYPE_LINEAR ||
+              primary->image_metadata.tiling_type == IMAGE_TILING_TYPE_X_TILED) {
             max_width = 8192;
           } else {
             max_width = 4096;
diff --git a/src/graphics/display/drivers/intel-i915/intel-i915.h b/src/graphics/display/drivers/intel-i915/intel-i915.h
index e5c62ba..8a3b933 100644
--- a/src/graphics/display/drivers/intel-i915/intel-i915.h
+++ b/src/graphics/display/drivers/intel-i915/intel-i915.h
@@ -177,7 +177,8 @@
   // For every frame, in order to use the imported image, it is required to set
   // up the image based on given rotation in GTT and use the handle offset in
   // GTT. Returns the Gtt region representing the image.
-  const GttRegion& SetupGttImage(const image_t* image, uint32_t rotation);
+  const GttRegion& SetupGttImage(const image_metadata_t& image_metadata, uint64_t image_handle,
+                                 uint32_t rotation);
 
   // The pixel format negotiated by sysmem for an imported image.
   //
diff --git a/src/graphics/display/drivers/intel-i915/pipe-unittest.cc b/src/graphics/display/drivers/intel-i915/pipe-unittest.cc
index 89b7e6f..7524be4 100644
--- a/src/graphics/display/drivers/intel-i915/pipe-unittest.cc
+++ b/src/graphics/display/drivers/intel-i915/pipe-unittest.cc
@@ -49,18 +49,19 @@
 
 std::map<uint64_t, TestGttRegionImpl> region_map;
 
-PixelFormatAndModifier GetPixelFormat(const image_t* image) {
+PixelFormatAndModifier GetPixelFormat(uint64_t image_handle) {
   return PixelFormatAndModifier(
       fuchsia_images2::PixelFormat::kB8G8R8A8,
       /*pixel_format_modifier_param=*/fuchsia_images2::PixelFormatModifier::kLinear);
 }
 
-const GttRegion& GetGttImageHandle(const image_t* image, uint32_t rotation) {
-  auto it = region_map.find(image->handle);
+const GttRegion& GetGttImageHandle(const image_metadata_t& image_metadata, uint64_t image_handle,
+                                   uint32_t rotation) {
+  auto it = region_map.find(image_handle);
   if (it != region_map.end()) {
     return it->second;
   }
-  return region_map.try_emplace(image->handle, image->handle).first->second;
+  return region_map.try_emplace(image_handle, image_handle).first->second;
 }
 
 layer_t CreatePrimaryLayerConfig(uint64_t handle, uint32_t z_index = 1u) {
@@ -71,12 +72,12 @@
   layer.type = LAYER_TYPE_PRIMARY;
   layer.z_index = z_index;
   layer.cfg.primary = {
-      .image =
+      .image_handle = handle,
+      .image_metadata =
           {
               .width = kWidth,
               .height = kHeight,
               .tiling_type = IMAGE_TILING_TYPE_LINEAR,
-              .handle = handle,
           },
       .alpha_mode = ALPHA_DISABLE,
       .transform_mode = FRAME_TRANSFORM_IDENTITY,
diff --git a/src/graphics/display/drivers/intel-i915/pipe.cc b/src/graphics/display/drivers/intel-i915/pipe.cc
index 53643d9..925cc50 100644
--- a/src/graphics/display/drivers/intel-i915/pipe.cc
+++ b/src/graphics/display/drivers/intel-i915/pipe.cc
@@ -5,6 +5,7 @@
 #include "src/graphics/display/drivers/intel-i915/pipe.h"
 
 #include <fidl/fuchsia.images2/cpp/wire.h>
+#include <fuchsia/hardware/display/controller/c/banjo.h>
 #include <lib/ddk/debug.h>
 #include <lib/sysmem-version/sysmem-version.h>
 #include <lib/zx/time.h>
@@ -514,9 +515,9 @@
   plane_ctrl.set_decompress_render_compressed_surfaces(false)
       .set_double_buffer_update_disabling_allowed(true);
 
-  const image_t* image = &primary->image;
-
-  const GttRegion& region = setup_gtt_image(image, primary->transform_mode);
+  const image_metadata_t& image_metadata = primary->image_metadata;
+  const GttRegion& region =
+      setup_gtt_image(primary->image_metadata, primary->image_handle, primary->transform_mode);
   uint32_t base_address = static_cast<uint32_t>(region.base());
   uint32_t plane_width;
   uint32_t plane_height;
@@ -529,7 +530,8 @@
     plane_height = primary->src_frame.height;
     stride =
         [&]() {
-          uint64_t stride = region.bytes_per_row() / get_tile_byte_width(image->tiling_type);
+          uint64_t stride =
+              region.bytes_per_row() / get_tile_byte_width(image_metadata.tiling_type);
           ZX_DEBUG_ASSERT_MSG(stride <= std::numeric_limits<uint32_t>::max(),
                               "%lu overflows uint32_t", stride);
           return static_cast<uint32_t>(stride);
@@ -537,8 +539,8 @@
     x_offset = primary->src_frame.x_pos;
     y_offset = primary->src_frame.y_pos;
   } else {
-    uint32_t tile_height = height_in_tiles(image->tiling_type, image->height);
-    uint32_t tile_px_height = get_tile_px_height(image->tiling_type);
+    uint32_t tile_height = height_in_tiles(image_metadata.tiling_type, image_metadata.height);
+    uint32_t tile_px_height = get_tile_px_height(image_metadata.tiling_type);
     uint32_t total_height = tile_height * tile_px_height;
 
     plane_width = primary->src_frame.height;
@@ -664,7 +666,7 @@
         registers::PlaneControl::ColorFormatKabyLake::kRgb8888);
   }
 
-  PixelFormatAndModifier pixel_format = get_pixel_format(&primary->image);
+  PixelFormatAndModifier pixel_format = get_pixel_format(primary->image_handle);
   switch (pixel_format.pixel_format) {
     case fuchsia_images2::PixelFormat::kR8G8B8A8:
       plane_ctrl.set_rgb_color_order(registers::PlaneControl::RgbColorOrder::kRgbx);
@@ -681,14 +683,14 @@
                     static_cast<uint32_t>(pixel_format.pixel_format));
   }
 
-  if (primary->image.tiling_type == IMAGE_TILING_TYPE_LINEAR) {
+  if (image_metadata.tiling_type == IMAGE_TILING_TYPE_LINEAR) {
     plane_ctrl.set_surface_tiling(registers::PlaneControl::SurfaceTiling::kLinear);
-  } else if (primary->image.tiling_type == IMAGE_TILING_TYPE_X_TILED) {
+  } else if (image_metadata.tiling_type == IMAGE_TILING_TYPE_X_TILED) {
     plane_ctrl.set_surface_tiling(registers::PlaneControl::SurfaceTiling::kTilingX);
-  } else if (primary->image.tiling_type == IMAGE_TILING_TYPE_Y_LEGACY_TILED) {
+  } else if (image_metadata.tiling_type == IMAGE_TILING_TYPE_Y_LEGACY_TILED) {
     plane_ctrl.set_surface_tiling(registers::PlaneControl::SurfaceTiling::kTilingYLegacy);
   } else {
-    ZX_ASSERT(primary->image.tiling_type == IMAGE_TILING_TYPE_YF_TILED);
+    ZX_ASSERT(image_metadata.tiling_type == IMAGE_TILING_TYPE_YF_TILED);
     if (platform_ == registers::Platform::kTigerLake) {
       // TODO(https://fxbug.dev/42062668): Remove this warning or turn it into an error.
       zxlogf(ERROR, "The Tiger Lake display engine may not support YF tiling.");
@@ -711,7 +713,7 @@
   plane_surface.set_surface_base_addr(base_address >> plane_surface.kRShiftCount);
   regs->plane_surf[plane_num] = plane_surface.reg_value();
 
-  latest_config_stamp_with_image_[image->handle] = config_stamp;
+  latest_config_stamp_with_image_[primary->image_handle] = config_stamp;
 }
 
 void Pipe::DisableCursorPlane(registers::pipe_arming_regs* regs,
diff --git a/src/graphics/display/drivers/intel-i915/pipe.h b/src/graphics/display/drivers/intel-i915/pipe.h
index 793ad66..8d6e73f 100644
--- a/src/graphics/display/drivers/intel-i915/pipe.h
+++ b/src/graphics/display/drivers/intel-i915/pipe.h
@@ -50,9 +50,9 @@
 
   void ApplyModeConfig(const display::DisplayTiming& mode);
 
-  using GetImagePixelFormatFunc = fit::function<PixelFormatAndModifier(const image_t* image)>;
-  using SetupGttImageFunc =
-      fit::function<const GttRegion&(const image_t* image, uint32_t rotation)>;
+  using GetImagePixelFormatFunc = fit::function<PixelFormatAndModifier(uint64_t image_id)>;
+  using SetupGttImageFunc = fit::function<const GttRegion&(
+      const image_metadata_t& image_metadata, uint64_t image_handle, uint32_t rotation)>;
   void ApplyConfiguration(const display_config_t* banjo_display_config,
                           display::ConfigStamp config_stamp,
                           const SetupGttImageFunc& setup_gtt_image,
diff --git a/src/graphics/display/drivers/simple/simple-display.cc b/src/graphics/display/drivers/simple/simple-display.cc
index 0734934..71e6779 100644
--- a/src/graphics/display/drivers/simple/simple-display.cc
+++ b/src/graphics/display/drivers/simple/simple-display.cc
@@ -318,8 +318,8 @@
         .height = height_,
     };
     success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY &&
-              layer->transform_mode == FRAME_TRANSFORM_IDENTITY && layer->image.width == width_ &&
-              layer->image.height == height_ &&
+              layer->transform_mode == FRAME_TRANSFORM_IDENTITY &&
+              layer->image_metadata.width == width_ && layer->image_metadata.height == height_ &&
               memcmp(&layer->dest_frame, &frame, sizeof(frame_t)) == 0 &&
               memcmp(&layer->src_frame, &frame, sizeof(frame_t)) == 0 &&
               display_configs[0]->cc_flags == 0 && layer->alpha_mode == ALPHA_DISABLE;
diff --git a/src/graphics/display/drivers/virtio-guest/v1/BUILD.gn b/src/graphics/display/drivers/virtio-guest/v1/BUILD.gn
index 0ec2147..87eb75d 100644
--- a/src/graphics/display/drivers/virtio-guest/v1/BUILD.gn
+++ b/src/graphics/display/drivers/virtio-guest/v1/BUILD.gn
@@ -43,6 +43,12 @@
 source_set("common_srcs") {
   configs += [ "//build/config:all_source" ]
   sources = [
+    "display-controller-banjo.cc",
+    "display-controller-banjo.h",
+    "display-coordinator-events-banjo.cc",
+    "display-coordinator-events-banjo.h",
+    "display-coordinator-events-interface.h",
+    "display-engine-interface.h",
     "display-engine.cc",
     "display-engine.h",
     "gpu-device-driver.cc",
@@ -55,6 +61,7 @@
   public_deps = [
     ":gpu_control_server",
     "//sdk/banjo/fuchsia.hardware.display.controller:fuchsia.hardware.display.controller_banjo_cpp",
+    "//sdk/fidl/fuchsia.hardware.display.engine:fuchsia.hardware.display.engine_cpp",
     "//sdk/fidl/fuchsia.hardware.sysmem:fuchsia.hardware.sysmem_cpp",
     "//sdk/fidl/fuchsia.sysmem:fuchsia.sysmem_cpp",
     "//src/devices/bus/lib/virtio",
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.cc b/src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.cc
new file mode 100644
index 0000000..6aad7bc
--- /dev/null
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.cc
@@ -0,0 +1,195 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.h"
+
+#include <fidl/fuchsia.hardware.display.engine/cpp/wire.h>
+#include <fidl/fuchsia.hardware.display.types/cpp/wire.h>
+#include <fidl/fuchsia.sysmem/cpp/wire.h>
+#include <fuchsia/hardware/display/controller/c/banjo.h>
+#include <lib/zx/channel.h>
+#include <lib/zx/result.h>
+#include <zircon/assert.h>
+#include <zircon/errors.h>
+#include <zircon/types.h>
+
+#include <cstdint>
+#include <utility>
+
+#include <fbl/alloc_checker.h>
+#include <fbl/vector.h>
+
+#include "src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h"
+#include "src/graphics/display/lib/api-types-cpp/display-id.h"
+#include "src/graphics/display/lib/api-types-cpp/driver-buffer-collection-id.h"
+#include "src/graphics/display/lib/api-types-cpp/driver-capture-image-id.h"
+#include "src/graphics/display/lib/api-types-cpp/driver-image-id.h"
+#include "src/graphics/display/lib/api-types-cpp/image-buffer-usage.h"
+#include "src/graphics/display/lib/api-types-cpp/image-metadata.h"
+
+namespace virtio_display {
+
+DisplayControllerBanjo::DisplayControllerBanjo(DisplayEngine* engine,
+                                               DisplayCoordinatorEventsBanjo* coordinator_events)
+    : engine_(*engine), coordinator_events_(*coordinator_events) {
+  ZX_DEBUG_ASSERT(engine != nullptr);
+  ZX_DEBUG_ASSERT(coordinator_events != nullptr);
+}
+
+DisplayControllerBanjo::~DisplayControllerBanjo() = default;
+
+void DisplayControllerBanjo::DisplayControllerImplSetDisplayControllerInterface(
+    const display_controller_interface_protocol_t* display_controller_interface) {
+  ZX_DEBUG_ASSERT(display_controller_interface);
+  coordinator_events_.SetDisplayControllerInterface(display_controller_interface);
+  if (display_controller_interface != nullptr) {
+    engine_.OnCoordinatorConnected();
+  }
+}
+
+void DisplayControllerBanjo::DisplayControllerImplResetDisplayControllerInterface() {
+  coordinator_events_.SetDisplayControllerInterface(nullptr);
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplImportBufferCollection(
+    uint64_t banjo_driver_buffer_collection_id, zx::channel banjo_buffer_collection_token) {
+  const display::DriverBufferCollectionId driver_buffer_collection_id =
+      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+  fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken> buffer_collection_token(
+      std::move(banjo_buffer_collection_token));
+
+  zx::result<> result = engine_.ImportBufferCollection(driver_buffer_collection_id,
+                                                       std::move(buffer_collection_token));
+  return result.status_value();
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplReleaseBufferCollection(
+    uint64_t banjo_driver_buffer_collection_id) {
+  const display::DriverBufferCollectionId driver_buffer_collection_id =
+      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+  zx::result<> result = engine_.ReleaseBufferCollection(driver_buffer_collection_id);
+  return result.status_value();
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplImportImage(
+    const image_metadata_t* banjo_image_metadata, uint64_t banjo_driver_buffer_collection_id,
+    uint32_t index, uint64_t* out_image_handle) {
+  const display::ImageMetadata image_metadata(*banjo_image_metadata);
+  const display::DriverBufferCollectionId driver_buffer_collection_id =
+      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+  zx::result<display::DriverImageId> result =
+      engine_.ImportImage(image_metadata, driver_buffer_collection_id, index);
+  if (result.is_error()) {
+    return result.error_value();
+  }
+  *out_image_handle = display::ToBanjoDriverImageId(result.value());
+  return ZX_OK;
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplImportImageForCapture(
+    uint64_t banjo_driver_buffer_collection_id, uint32_t index, uint64_t* out_capture_handle) {
+  const display::DriverBufferCollectionId driver_buffer_collection_id =
+      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+  zx::result<display::DriverCaptureImageId> result =
+      engine_.ImportImageForCapture(driver_buffer_collection_id, index);
+  if (result.is_error()) {
+    return result.error_value();
+  }
+  *out_capture_handle = display::ToBanjoDriverCaptureImageId(result.value());
+  return ZX_OK;
+}
+
+void DisplayControllerBanjo::DisplayControllerImplReleaseImage(uint64_t banjo_image_handle) {
+  const display::DriverImageId driver_image_id = display::ToDriverImageId(banjo_image_handle);
+  engine_.ReleaseImage(driver_image_id);
+}
+
+config_check_result_t DisplayControllerBanjo::DisplayControllerImplCheckConfiguration(
+    const display_config_t** banjo_display_configs, size_t banjo_display_configs_count,
+    client_composition_opcode_t* out_client_composition_opcodes_list,
+    size_t out_client_composition_opcodes_size, size_t* out_client_composition_opcodes_actual) {
+  cpp20::span<const display_config_t*> display_configs(banjo_display_configs,
+                                                       banjo_display_configs_count);
+  cpp20::span<client_composition_opcode_t> out_client_composition_opcodes(
+      out_client_composition_opcodes_list, out_client_composition_opcodes_size);
+
+  return engine_.CheckConfiguration(display_configs, out_client_composition_opcodes,
+                                    out_client_composition_opcodes_actual);
+}
+
+void DisplayControllerBanjo::DisplayControllerImplApplyConfiguration(
+    const display_config_t** banjo_display_configs, size_t banjo_display_configs_count,
+    const config_stamp_t* banjo_config_stamp) {
+  cpp20::span<const display_config_t*> display_configs(banjo_display_configs,
+                                                       banjo_display_configs_count);
+  return engine_.ApplyConfiguration(display_configs, banjo_config_stamp);
+}
+
+void DisplayControllerBanjo::DisplayControllerImplSetEld(uint64_t banjo_display_id,
+                                                         const uint8_t* raw_eld_list,
+                                                         size_t raw_eld_count) {
+  const display::DisplayId display_id = display::ToDisplayId(banjo_display_id);
+  const cpp20::span<const uint8_t> raw_eld(raw_eld_list, raw_eld_count);
+  engine_.SetEld(display_id, raw_eld);
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplSetBufferCollectionConstraints(
+    const image_buffer_usage_t* banjo_image_buffer_usage,
+    uint64_t banjo_driver_buffer_collection_id) {
+  display::ImageBufferUsage image_buffer_usage =
+      display::ToImageBufferUsage(*banjo_image_buffer_usage);
+  const display::DriverBufferCollectionId driver_buffer_collection_id =
+      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+  zx::result<> result =
+      engine_.SetBufferCollectionConstraints(image_buffer_usage, driver_buffer_collection_id);
+  return result.status_value();
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplSetDisplayPower(uint64_t banjo_display_id,
+                                                                         bool power_on) {
+  const display::DisplayId display_id = display::ToDisplayId(banjo_display_id);
+  zx::result<> result = engine_.SetDisplayPower(display_id, power_on);
+  return result.status_value();
+}
+
+bool DisplayControllerBanjo::DisplayControllerImplIsCaptureSupported() {
+  return engine_.IsCaptureSupported();
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplStartCapture(
+    uint64_t banjo_capture_handle) {
+  const display::DriverCaptureImageId capture_image_id =
+      display::ToDriverCaptureImageId(banjo_capture_handle);
+  zx::result<> result = engine_.StartCapture(capture_image_id);
+  return result.status_value();
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplReleaseCapture(
+    uint64_t banjo_capture_handle) {
+  const display::DriverCaptureImageId capture_image_id =
+      display::ToDriverCaptureImageId(banjo_capture_handle);
+  zx::result<> result = engine_.ReleaseCapture(capture_image_id);
+  return result.status_value();
+}
+
+bool DisplayControllerBanjo::DisplayControllerImplIsCaptureCompleted() {
+  return engine_.IsCaptureCompleted();
+}
+
+zx_status_t DisplayControllerBanjo::DisplayControllerImplSetMinimumRgb(uint8_t minimum_rgb) {
+  zx::result<> result = engine_.SetMinimumRgb(minimum_rgb);
+  return result.status_value();
+}
+
+zx_status_t DisplayControllerBanjo::DdkGetProtocol(uint32_t proto_id, void* out) {
+  auto* proto = static_cast<ddk::AnyProtocol*>(out);
+  proto->ctx = this;
+  if (proto_id == ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL) {
+    proto->ops = &display_controller_impl_protocol_ops_;
+    return ZX_OK;
+  }
+  return ZX_ERR_NOT_SUPPORTED;
+}
+
+}  // namespace virtio_display
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.h b/src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.h
new file mode 100644
index 0000000..8fa23d7
--- /dev/null
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.h
@@ -0,0 +1,82 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_CONTROLLER_BANJO_H_
+#define SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_CONTROLLER_BANJO_H_
+
+#include <fuchsia/hardware/display/controller/cpp/banjo.h>
+#include <lib/stdcompat/span.h>
+#include <zircon/compiler.h>
+#include <zircon/types.h>
+
+#include <cstdint>
+
+#include "src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h"
+#include "src/graphics/display/drivers/virtio-guest/v1/display-engine.h"
+
+namespace virtio_display {
+
+// Banjo <-> C++ bridge for the methods interface with the Display Coordinator.
+//
+// Instances are thread-safe, because Banjo does not make any threading
+// guarantees.
+class DisplayControllerBanjo : public ddk::DisplayControllerImplProtocol<DisplayControllerBanjo> {
+ public:
+  // `engine` and `coordinator_events` must not be null, and must outlive the
+  // newly created instance.
+  explicit DisplayControllerBanjo(DisplayEngine* engine,
+                                  DisplayCoordinatorEventsBanjo* coordinator_events);
+
+  DisplayControllerBanjo(const DisplayControllerBanjo&) = delete;
+  DisplayControllerBanjo& operator=(const DisplayControllerBanjo&) = delete;
+
+  ~DisplayControllerBanjo();
+
+  // ddk::DisplayControllerImplProtocol
+  void DisplayControllerImplSetDisplayControllerInterface(
+      const display_controller_interface_protocol_t* display_controller_interface);
+  void DisplayControllerImplResetDisplayControllerInterface();
+  zx_status_t DisplayControllerImplImportBufferCollection(
+      uint64_t banjo_driver_buffer_collection_id, zx::channel buffer_collection_token);
+  zx_status_t DisplayControllerImplReleaseBufferCollection(
+      uint64_t banjo_driver_buffer_collection_id);
+  zx_status_t DisplayControllerImplImportImage(const image_metadata_t* banjo_image_metadata,
+                                               uint64_t banjo_driver_buffer_collection_id,
+                                               uint32_t index, uint64_t* out_image_handle);
+  zx_status_t DisplayControllerImplImportImageForCapture(uint64_t banjo_driver_buffer_collection_id,
+                                                         uint32_t index,
+                                                         uint64_t* out_capture_handle);
+  void DisplayControllerImplReleaseImage(uint64_t banjo_image_handle);
+  config_check_result_t DisplayControllerImplCheckConfiguration(
+      const display_config_t** banjo_display_configs, size_t banjo_display_configs_count,
+      client_composition_opcode_t* out_client_composition_opcodes_list,
+      size_t out_client_composition_opcodes_size, size_t* out_client_composition_opcodes_actual);
+  void DisplayControllerImplApplyConfiguration(const display_config_t** banjo_display_configs,
+                                               size_t banjo_display_configs_count,
+                                               const config_stamp_t* banjo_config_stamp);
+  void DisplayControllerImplSetEld(uint64_t banjo_display_id, const uint8_t* raw_eld_list,
+                                   size_t raw_eld_count);
+  zx_status_t DisplayControllerImplSetBufferCollectionConstraints(
+      const image_buffer_usage_t* banjo_image_buffer_usage,
+      uint64_t banjo_driver_buffer_collection_id);
+  zx_status_t DisplayControllerImplSetDisplayPower(uint64_t banjo_display_id, bool power_on);
+  bool DisplayControllerImplIsCaptureSupported();
+  zx_status_t DisplayControllerImplStartCapture(uint64_t capture_handle);
+  zx_status_t DisplayControllerImplReleaseCapture(uint64_t capture_handle);
+  bool DisplayControllerImplIsCaptureCompleted();
+  zx_status_t DisplayControllerImplSetMinimumRgb(uint8_t minimum_rgb);
+
+  zx_status_t DdkGetProtocol(uint32_t proto_id, void* out);
+
+ private:
+  // This data member is thread-safe because it is immutable.
+  DisplayEngine& engine_;
+
+  // This data member is thread-safe because it is immutable.
+  DisplayCoordinatorEventsBanjo& coordinator_events_;
+};
+
+}  // namespace virtio_display
+
+#endif  // SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_CONTROLLER_BANJO_H_
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.cc b/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.cc
new file mode 100644
index 0000000..f6f0811
--- /dev/null
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.cc
@@ -0,0 +1,86 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h"
+
+#include <zircon/assert.h>
+#include <zircon/time.h>
+
+#include <cstdint>
+
+#include <fbl/alloc_checker.h>
+#include <fbl/auto_lock.h>
+#include <fbl/vector.h>
+
+#include "src/graphics/display/lib/api-types-cpp/config-stamp.h"
+#include "src/graphics/display/lib/api-types-cpp/display-id.h"
+
+namespace virtio_display {
+
+DisplayCoordinatorEventsBanjo::DisplayCoordinatorEventsBanjo() = default;
+DisplayCoordinatorEventsBanjo::~DisplayCoordinatorEventsBanjo() = default;
+
+void DisplayCoordinatorEventsBanjo::SetDisplayControllerInterface(
+    const display_controller_interface_protocol_t* display_controller_interface) {
+  fbl::AutoLock event_lock(&event_mutex_);
+  if (display_controller_interface == nullptr) {
+    display_controller_interface = {};
+    return;
+  }
+
+  display_controller_interface_ = *display_controller_interface;
+}
+
+void DisplayCoordinatorEventsBanjo::OnDisplaysChanged(
+    cpp20::span<const added_display_args_t> added_displays,
+    cpp20::span<const display::DisplayId> removed_display_ids) {
+  fbl::Vector<uint64_t> banjo_removed_display_ids;
+
+  fbl::AllocChecker alloc_checker;
+  banjo_removed_display_ids.reserve(removed_display_ids.size(), &alloc_checker);
+  if (!alloc_checker.check()) {
+    return;
+  }
+
+  for (display::DisplayId removed_display_id : removed_display_ids) {
+    banjo_removed_display_ids.push_back(display::ToBanjoDisplayId(removed_display_id),
+                                        &alloc_checker);
+    ZX_DEBUG_ASSERT(banjo_removed_display_ids.size() <= removed_display_ids.size());
+    ZX_DEBUG_ASSERT_MSG(alloc_checker.check(),
+                        "push_back() failed despite having the required capacity reserve()d");
+  }
+
+  fbl::AutoLock event_lock(&event_mutex_);
+  if (display_controller_interface_.ops == nullptr) {
+    return;
+  }
+  display_controller_interface_on_displays_changed(
+      &display_controller_interface_, added_displays.data(), added_displays.size(),
+      banjo_removed_display_ids.data(), banjo_removed_display_ids.size());
+}
+
+void DisplayCoordinatorEventsBanjo::OnDisplayVsync(display::DisplayId display_id,
+                                                   zx::time timestamp,
+                                                   display::ConfigStamp config_stamp) {
+  const uint64_t banjo_display_id = display::ToBanjoDisplayId(display_id);
+  const zx_time_t banjo_timestamp = timestamp.get();
+  const config_stamp_t banjo_config_stamp = display::ToBanjoConfigStamp(config_stamp);
+
+  fbl::AutoLock event_lock(&event_mutex_);
+  if (display_controller_interface_.ops == nullptr) {
+    return;
+  }
+  display_controller_interface_on_display_vsync(&display_controller_interface_, banjo_display_id,
+                                                banjo_timestamp, &banjo_config_stamp);
+}
+
+void DisplayCoordinatorEventsBanjo::OnCaptureComplete() {
+  fbl::AutoLock event_lock(&event_mutex_);
+  if (display_controller_interface_.ops == nullptr) {
+    return;
+  }
+  display_controller_interface_on_capture_complete(&display_controller_interface_);
+}
+
+}  // namespace virtio_display
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h b/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h
new file mode 100644
index 0000000..c12fa58
--- /dev/null
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h
@@ -0,0 +1,51 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_COORDINATOR_EVENTS_BANJO_H_
+#define SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_COORDINATOR_EVENTS_BANJO_H_
+
+#include <fuchsia/hardware/display/controller/c/banjo.h>
+#include <lib/stdcompat/span.h>
+#include <zircon/compiler.h>
+
+#include <ddktl/device.h>
+#include <fbl/mutex.h>
+
+#include "src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-interface.h"
+
+namespace virtio_display {
+
+// Banjo <-> C++ bridge for the events interface with the Display Coordinator.
+//
+// Instances are thread-safe, because Banjo does not make any threading
+// guarantees.
+class DisplayCoordinatorEventsBanjo final : public DisplayCoordinatorEventsInterface {
+ public:
+  explicit DisplayCoordinatorEventsBanjo();
+
+  DisplayCoordinatorEventsBanjo(const DisplayCoordinatorEventsBanjo&) = delete;
+  DisplayCoordinatorEventsBanjo& operator=(const DisplayCoordinatorEventsBanjo&) = delete;
+
+  ~DisplayCoordinatorEventsBanjo();
+
+  // `display_controller_interface` may be null.
+  void SetDisplayControllerInterface(
+      const display_controller_interface_protocol_t* display_controller_interface);
+
+  // DisplayCoordinatorEventsInterface:
+  void OnDisplaysChanged(cpp20::span<const added_display_args_t> added_displays,
+                         cpp20::span<const display::DisplayId> removed_display_ids) override;
+  void OnDisplayVsync(display::DisplayId display_id, zx::time timestamp,
+                      display::ConfigStamp config_stamp) override;
+  void OnCaptureComplete() override;
+
+ private:
+  fbl::Mutex event_mutex_;
+  display_controller_interface_protocol_t display_controller_interface_
+      __TA_GUARDED(event_mutex_) = {};
+};
+
+}  // namespace virtio_display
+
+#endif  // SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_COORDINATOR_EVENTS_BANJO_H_
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-interface.h b/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-interface.h
new file mode 100644
index 0000000..0c2a3a8
--- /dev/null
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-interface.h
@@ -0,0 +1,55 @@
+
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_COORDINATOR_EVENTS_INTERFACE_H_
+#define SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_COORDINATOR_EVENTS_INTERFACE_H_
+
+#include <fidl/fuchsia.sysmem/cpp/wire.h>
+// TODO(https://fxbug.dev/42079190): Switch from Banjo to FIDL or api-types-cpp types.
+#include <fuchsia/hardware/display/controller/c/banjo.h>
+#include <lib/stdcompat/span.h>
+#include <lib/zx/result.h>
+#include <lib/zx/time.h>
+
+#include "src/graphics/display/lib/api-types-cpp/config-stamp.h"
+#include "src/graphics/display/lib/api-types-cpp/display-id.h"
+
+namespace virtio_display {
+
+// The events in the [`fuchsia.hardware.display.engine/Engine`] FIDL interface.
+//
+// This abstract base class only represents the events in the FIDL interface.
+// The methods are represented by `DisplayEngineInterface`.
+//
+// This abstract base class also represents the
+// [`fuchsia.hardware.display.controller/DisplayControllerInterface`] Banjo
+// interface.
+class DisplayCoordinatorEventsInterface {
+ public:
+  DisplayCoordinatorEventsInterface() = default;
+
+  DisplayCoordinatorEventsInterface(const DisplayCoordinatorEventsInterface&) = delete;
+  DisplayCoordinatorEventsInterface(DisplayCoordinatorEventsInterface&&) = delete;
+  DisplayCoordinatorEventsInterface& operator=(const DisplayCoordinatorEventsInterface&) = delete;
+  DisplayCoordinatorEventsInterface& operator=(DisplayCoordinatorEventsInterface&&) = delete;
+
+  // TODO(https://fxbug.dev/42079190): Switch from Banjo to FIDL or api-types-cpp types.
+  virtual void OnDisplaysChanged(cpp20::span<const added_display_args_t> added_displays,
+                                 cpp20::span<const display::DisplayId> removed_ids) = 0;
+
+  virtual void OnDisplayVsync(display::DisplayId display_id, zx::time timestamp,
+                              display::ConfigStamp config_stamp) = 0;
+
+  virtual void OnCaptureComplete() = 0;
+
+ protected:
+  // Destruction via base class pointer is not supported intentionally.
+  // Instances are not expected to be owned by pointers to base classes.
+  ~DisplayCoordinatorEventsInterface() = default;
+};
+
+}  // namespace virtio_display
+
+#endif  // SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_COORDINATOR_EVENTS_INTERFACE_H_
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-engine-interface.h b/src/graphics/display/drivers/virtio-guest/v1/display-engine-interface.h
new file mode 100644
index 0000000..1169bd5
--- /dev/null
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-engine-interface.h
@@ -0,0 +1,89 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_ENGINE_INTERFACE_H_
+#define SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_ENGINE_INTERFACE_H_
+
+#include <fidl/fuchsia.sysmem/cpp/wire.h>
+// TODO(https://fxbug.dev/42079190): Switch from Banjo to FIDL or api-types-cpp types.
+#include <fuchsia/hardware/display/controller/c/banjo.h>
+#include <lib/zx/result.h>
+
+#include <cstdint>
+
+#include "src/graphics/display/lib/api-types-cpp/display-id.h"
+#include "src/graphics/display/lib/api-types-cpp/driver-buffer-collection-id.h"
+#include "src/graphics/display/lib/api-types-cpp/driver-capture-image-id.h"
+#include "src/graphics/display/lib/api-types-cpp/driver-image-id.h"
+#include "src/graphics/display/lib/api-types-cpp/image-buffer-usage.h"
+#include "src/graphics/display/lib/api-types-cpp/image-metadata.h"
+
+namespace virtio_display {
+
+// The methods in the [`fuchsia.hardware.display.engine/Engine`] FIDL interface.
+//
+// This abstract base class only represents the methods in the FIDL interface.
+// The events are represented by `CoordinatorEventsInterface`.
+//
+// This abstract base class also represents the
+// [`fuchsia.hardware.display.controller/DisplayControllerImpl`] Banjo
+// interface.
+class DisplayEngineInterface {
+ public:
+  DisplayEngineInterface() = default;
+
+  DisplayEngineInterface(const DisplayEngineInterface&) = delete;
+  DisplayEngineInterface(DisplayEngineInterface&&) = delete;
+  DisplayEngineInterface& operator=(const DisplayEngineInterface&) = delete;
+  DisplayEngineInterface& operator=(DisplayEngineInterface&&) = delete;
+
+  virtual void OnCoordinatorConnected() = 0;
+
+  virtual zx::result<> ImportBufferCollection(
+      display::DriverBufferCollectionId driver_buffer_collection_id,
+      fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken> buffer_collection_token) = 0;
+  virtual zx::result<> ReleaseBufferCollection(
+      display::DriverBufferCollectionId driver_buffer_collection_id) = 0;
+
+  virtual zx::result<display::DriverImageId> ImportImage(
+      const display::ImageMetadata& image_metadata,
+      display::DriverBufferCollectionId driver_buffer_collection_id, uint32_t index) = 0;
+  virtual zx::result<display::DriverCaptureImageId> ImportImageForCapture(
+      display::DriverBufferCollectionId driver_buffer_collection_id, uint32_t index) = 0;
+  virtual void ReleaseImage(display::DriverImageId driver_image_id) = 0;
+
+  // TODO(costan): Switch from Banjo to FIDL or api-types-cpp types.
+  virtual config_check_result_t CheckConfiguration(
+      cpp20::span<const display_config_t*> display_configs,
+      cpp20::span<client_composition_opcode_t> out_client_composition_opcodes,
+      size_t* out_client_composition_opcodes_actual) = 0;
+
+  // TODO(costan): Switch from Banjo to FIDL or api-types-cpp types.
+  virtual void ApplyConfiguration(cpp20::span<const display_config_t*> display_configs,
+                                  const config_stamp_t* banjo_config_stamp) = 0;
+
+  virtual void SetEld(display::DisplayId display_id, cpp20::span<const uint8_t> raw_eld) = 0;
+
+  virtual zx::result<> SetBufferCollectionConstraints(
+      const display::ImageBufferUsage& image_buffer_usage,
+      display::DriverBufferCollectionId driver_buffer_collection_id) = 0;
+
+  virtual zx::result<> SetDisplayPower(display::DisplayId display_id, bool power_on) = 0;
+
+  virtual bool IsCaptureSupported() = 0;
+  virtual zx::result<> StartCapture(display::DriverCaptureImageId capture_image_id) = 0;
+  virtual zx::result<> ReleaseCapture(display::DriverCaptureImageId capture_image_id) = 0;
+  virtual bool IsCaptureCompleted() = 0;
+
+  virtual zx::result<> SetMinimumRgb(uint8_t minimum_rgb) = 0;
+
+ protected:
+  // Destruction via base class pointer is not supported intentionally.
+  // Instances are not expected to be owned by pointers to base classes.
+  ~DisplayEngineInterface() = default;
+};
+
+}  // namespace virtio_display
+
+#endif  // SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_ENGINE_INTERFACE_H_
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-engine-test.cc b/src/graphics/display/drivers/virtio-guest/v1/display-engine-test.cc
index f023065..6e7c11d 100644
--- a/src/graphics/display/drivers/virtio-guest/v1/display-engine-test.cc
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-engine-test.cc
@@ -22,8 +22,12 @@
 
 #include <virtio/virtio.h>
 
+#include "src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.h"
+#include "src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h"
 #include "src/graphics/display/drivers/virtio-guest/v1/virtio-pci-device.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-buffer-collection-id.h"
+#include "src/graphics/display/lib/api-types-cpp/image-metadata.h"
+#include "src/graphics/display/lib/api-types-cpp/image-tiling-type.h"
 #include "src/graphics/lib/virtio/virtio-abi.h"
 
 #define USE_GTEST
@@ -207,8 +211,11 @@
     auto [sysmem_client, sysmem_server] = fidl::Endpoints<fuchsia_sysmem::Allocator>::Create();
     fidl::BindServer(dispatcher(), std::move(sysmem_server), fake_sysmem_.get());
 
-    device_ =
-        std::make_unique<DisplayEngine>(nullptr, std::move(sysmem_client), std::move(gpu_device));
+    device_ = std::make_unique<DisplayEngine>(nullptr, &coordinator_events_,
+                                              std::move(sysmem_client), std::move(gpu_device));
+
+    banjo_controller_ =
+        std::make_unique<DisplayControllerBanjo>(device_.get(), &coordinator_events_);
 
     RunLoopUntilIdle();
   }
@@ -220,7 +227,7 @@
 
   void ImportBufferCollection(display::DriverBufferCollectionId buffer_collection_id) {
     auto token_endpoints = fidl::Endpoints<sysmem::BufferCollectionToken>::Create();
-    EXPECT_OK(device_->DisplayControllerImplImportBufferCollection(
+    EXPECT_OK(banjo_controller_->DisplayControllerImplImportBufferCollection(
         display::ToBanjoDriverBufferCollectionId(buffer_collection_id),
         token_endpoints.client.TakeChannel()));
   }
@@ -229,13 +236,16 @@
   std::vector<uint8_t> virtio_control_queue_buffer_pool_;
   std::vector<uint8_t> virtio_cursor_queue_buffer_pool_;
   std::unique_ptr<MockAllocator> fake_sysmem_;
+
+  DisplayCoordinatorEventsBanjo coordinator_events_;
   std::unique_ptr<DisplayEngine> device_;
+  std::unique_ptr<DisplayControllerBanjo> banjo_controller_;
 };
 
 TEST_F(VirtioGpuTest, ImportVmo) {
   display_controller_impl_protocol_t proto;
-  EXPECT_OK(device_->DdkGetProtocol(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL,
-                                    reinterpret_cast<void*>(&proto)));
+  EXPECT_OK(banjo_controller_->DdkGetProtocol(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL,
+                                              reinterpret_cast<void*>(&proto)));
 
   // Import buffer collection.
   constexpr display::DriverBufferCollectionId kBufferCollectionId(1);
@@ -247,15 +257,15 @@
   static constexpr image_buffer_usage_t kDisplayUsage = {
       .tiling_type = IMAGE_TILING_TYPE_LINEAR,
   };
-  EXPECT_OK(proto.ops->set_buffer_collection_constraints(device_.get(), &kDisplayUsage,
+  EXPECT_OK(proto.ops->set_buffer_collection_constraints(banjo_controller_.get(), &kDisplayUsage,
                                                          kBanjoBufferCollectionId));
   RunLoopUntilIdle();
 
-  static constexpr image_metadata_t kDefaultImageMetadata = {
+  static constexpr display::ImageMetadata kDefaultImageMetadata({
       .width = 4,
       .height = 4,
-      .tiling_type = IMAGE_TILING_TYPE_LINEAR,
-  };
+      .tiling_type = display::kImageTilingTypeLinear,
+  });
   PerformBlockingWork([&] {
     zx::result<DisplayEngine::BufferInfo> buffer_info_result =
         device_->GetAllocatedBufferInfoForImage(kBufferCollectionId, /*index=*/0,
@@ -270,8 +280,8 @@
 
 TEST_F(VirtioGpuTest, SetConstraints) {
   display_controller_impl_protocol_t proto;
-  EXPECT_OK(device_->DdkGetProtocol(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL,
-                                    reinterpret_cast<void*>(&proto)));
+  EXPECT_OK(banjo_controller_->DdkGetProtocol(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL,
+                                              reinterpret_cast<void*>(&proto)));
 
   // Import buffer collection.
   zx::result token_endpoints = fidl::CreateEndpoints<sysmem::BufferCollectionToken>();
@@ -279,7 +289,7 @@
   constexpr display::DriverBufferCollectionId kBufferCollectionId(1);
   constexpr uint64_t kBanjoBufferCollectionId =
       display::ToBanjoDriverBufferCollectionId(kBufferCollectionId);
-  EXPECT_OK(proto.ops->import_buffer_collection(device_.get(), kBanjoBufferCollectionId,
+  EXPECT_OK(proto.ops->import_buffer_collection(banjo_controller_.get(), kBanjoBufferCollectionId,
                                                 token_endpoints->client.handle()->get()));
   RunLoopUntilIdle();
 
@@ -287,7 +297,7 @@
   static constexpr image_buffer_usage_t kDisplayUsage = {
       .tiling_type = IMAGE_TILING_TYPE_LINEAR,
   };
-  EXPECT_OK(proto.ops->set_buffer_collection_constraints(device_.get(), &kDisplayUsage,
+  EXPECT_OK(proto.ops->set_buffer_collection_constraints(banjo_controller_.get(), &kDisplayUsage,
                                                          kBanjoBufferCollectionId));
   RunLoopUntilIdle();
 }
@@ -320,20 +330,22 @@
   ASSERT_TRUE(token2_endpoints.is_ok());
 
   display_controller_impl_protocol_t proto;
-  EXPECT_OK(device_->DdkGetProtocol(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL,
-                                    reinterpret_cast<void*>(&proto)));
+  EXPECT_OK(banjo_controller_->DdkGetProtocol(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL,
+                                              reinterpret_cast<void*>(&proto)));
 
   // Test ImportBufferCollection().
   constexpr display::DriverBufferCollectionId kValidBufferCollectionId(1);
   constexpr uint64_t kBanjoValidBufferCollectionId =
       display::ToBanjoDriverBufferCollectionId(kValidBufferCollectionId);
-  EXPECT_OK(proto.ops->import_buffer_collection(device_.get(), kBanjoValidBufferCollectionId,
+  EXPECT_OK(proto.ops->import_buffer_collection(banjo_controller_.get(),
+                                                kBanjoValidBufferCollectionId,
                                                 token1_endpoints.client.handle()->get()));
 
   // `collection_id` must be unused.
-  EXPECT_EQ(proto.ops->import_buffer_collection(device_.get(), kBanjoValidBufferCollectionId,
-                                                token2_endpoints->client.handle()->get()),
-            ZX_ERR_ALREADY_EXISTS);
+  EXPECT_EQ(
+      proto.ops->import_buffer_collection(banjo_controller_.get(), kBanjoValidBufferCollectionId,
+                                          token2_endpoints->client.handle()->get()),
+      ZX_ERR_ALREADY_EXISTS);
 
   RunLoopUntilIdle();
   EXPECT_TRUE(!allocator->GetActiveBufferCollectionTokenClients().empty());
@@ -354,9 +366,11 @@
   constexpr display::DriverBufferCollectionId kInvalidBufferCollectionId(2);
   constexpr uint64_t kBanjoInvalidBufferCollectionId =
       display::ToBanjoDriverBufferCollectionId(kInvalidBufferCollectionId);
-  EXPECT_EQ(proto.ops->release_buffer_collection(device_.get(), kBanjoInvalidBufferCollectionId),
+  EXPECT_EQ(proto.ops->release_buffer_collection(banjo_controller_.get(),
+                                                 kBanjoInvalidBufferCollectionId),
             ZX_ERR_NOT_FOUND);
-  EXPECT_OK(proto.ops->release_buffer_collection(device_.get(), kBanjoValidBufferCollectionId));
+  EXPECT_OK(
+      proto.ops->release_buffer_collection(banjo_controller_.get(), kBanjoValidBufferCollectionId));
 
   RunLoopUntilIdle();
   EXPECT_TRUE(allocator->GetActiveBufferCollectionTokenClients().empty());
@@ -383,14 +397,14 @@
   ASSERT_TRUE(token1_endpoints.is_ok());
 
   display_controller_impl_protocol_t proto;
-  EXPECT_OK(device_->DdkGetProtocol(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL,
-                                    reinterpret_cast<void*>(&proto)));
+  EXPECT_OK(banjo_controller_->DdkGetProtocol(ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL,
+                                              reinterpret_cast<void*>(&proto)));
 
   // Import buffer collection.
   constexpr display::DriverBufferCollectionId kBufferCollectionId(1);
   constexpr uint64_t kBanjoBufferCollectionId =
       display::ToBanjoDriverBufferCollectionId(kBufferCollectionId);
-  EXPECT_OK(proto.ops->import_buffer_collection(device_.get(), kBanjoBufferCollectionId,
+  EXPECT_OK(proto.ops->import_buffer_collection(banjo_controller_.get(), kBanjoBufferCollectionId,
                                                 token1_endpoints->client.handle()->get()));
 
   RunLoopUntilIdle();
@@ -400,7 +414,7 @@
   static constexpr image_buffer_usage_t kDisplayUsage = {
       .tiling_type = IMAGE_TILING_TYPE_LINEAR,
   };
-  EXPECT_OK(proto.ops->set_buffer_collection_constraints(device_.get(), &kDisplayUsage,
+  EXPECT_OK(proto.ops->set_buffer_collection_constraints(banjo_controller_.get(), &kDisplayUsage,
                                                          kBanjoBufferCollectionId));
   RunLoopUntilIdle();
 
@@ -415,16 +429,16 @@
       display::ToBanjoDriverBufferCollectionId(kInvalidCollectionId);
   uint64_t image_handle = 0;
   PerformBlockingWork([&] {
-    EXPECT_EQ(
-        proto.ops->import_image(device_.get(), &kDefaultImageMetadata, kBanjoInvalidCollectionId,
-                                /*index=*/0, &image_handle),
-        ZX_ERR_NOT_FOUND);
+    EXPECT_EQ(proto.ops->import_image(banjo_controller_.get(), &kDefaultImageMetadata,
+                                      kBanjoInvalidCollectionId,
+                                      /*index=*/0, &image_handle),
+              ZX_ERR_NOT_FOUND);
   });
 
   // Invalid import: bad index
   uint32_t kInvalidIndex = 100;
   PerformBlockingWork([&] {
-    EXPECT_EQ(proto.ops->import_image(device_.get(), &kDefaultImageMetadata,
+    EXPECT_EQ(proto.ops->import_image(banjo_controller_.get(), &kDefaultImageMetadata,
                                       kBanjoBufferCollectionId, kInvalidIndex, &image_handle),
               ZX_ERR_OUT_OF_RANGE);
   });
@@ -433,7 +447,8 @@
   // can test the valid import case.
 
   // Release buffer collection.
-  EXPECT_OK(proto.ops->release_buffer_collection(device_.get(), kBanjoBufferCollectionId));
+  EXPECT_OK(
+      proto.ops->release_buffer_collection(banjo_controller_.get(), kBanjoBufferCollectionId));
 
   RunLoopUntilIdle();
   EXPECT_TRUE(allocator->GetActiveBufferCollectionTokenClients().empty());
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-engine.cc b/src/graphics/display/drivers/virtio-guest/v1/display-engine.cc
index 351f80d..8dc8f7f 100644
--- a/src/graphics/display/drivers/virtio-guest/v1/display-engine.cc
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-engine.cc
@@ -28,6 +28,7 @@
 
 #include <algorithm>
 #include <cinttypes>
+#include <cstdint>
 #include <cstring>
 #include <memory>
 #include <utility>
@@ -43,6 +44,9 @@
 #include "src/graphics/display/lib/api-types-cpp/display-timing.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-buffer-collection-id.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-image-id.h"
+#include "src/graphics/display/lib/api-types-cpp/image-buffer-usage.h"
+#include "src/graphics/display/lib/api-types-cpp/image-metadata.h"
+#include "src/graphics/display/lib/api-types-cpp/image-tiling-type.h"
 #include "src/graphics/lib/virtio/virtio-abi.h"
 #include "src/lib/fxl/strings/string_printf.h"
 
@@ -55,30 +59,12 @@
 
 }  // namespace
 
-// DDK level ops
-
 using imported_image_t = struct imported_image {
   uint32_t resource_id;
   zx::pmt pmt;
 };
 
-zx_status_t DisplayEngine::DdkGetProtocol(uint32_t proto_id, void* out) {
-  auto* proto = static_cast<ddk::AnyProtocol*>(out);
-  proto->ctx = this;
-  if (proto_id == ZX_PROTOCOL_DISPLAY_CONTROLLER_IMPL) {
-    proto->ops = &display_controller_impl_protocol_ops_;
-    return ZX_OK;
-  }
-  return ZX_ERR_NOT_SUPPORTED;
-}
-
-void DisplayEngine::DisplayControllerImplSetDisplayControllerInterface(
-    const display_controller_interface_protocol_t* intf) {
-  {
-    fbl::AutoLock al(&flush_lock_);
-    dc_intf_ = *intf;
-  }
-
+void DisplayEngine::OnCoordinatorConnected() {
   const uint32_t width = current_display_.scanout_info.geometry.width;
   const uint32_t height = current_display_.scanout_info.geometry.height;
 
@@ -113,20 +99,15 @@
       .pixel_format_list = kSupportedFormats.data(),
       .pixel_format_count = kSupportedFormats.size(),
   };
-  display_controller_interface_on_displays_changed(intf, &args, 1, nullptr, 0);
-}
 
-void DisplayEngine::DisplayControllerImplResetDisplayControllerInterface() {
-  fbl::AutoLock al(&flush_lock_);
-  dc_intf_ = display_controller_interface_protocol_t{
-      .ops = nullptr,
-      .ctx = nullptr,
-  };
+  cpp20::span<const added_display_args_t> added_displays(&args, 1);
+  cpp20::span<const display::DisplayId> removed_display_ids;
+  coordinator_events_.OnDisplaysChanged(added_displays, removed_display_ids);
 }
 
 zx::result<DisplayEngine::BufferInfo> DisplayEngine::GetAllocatedBufferInfoForImage(
     display::DriverBufferCollectionId driver_buffer_collection_id, uint32_t index,
-    const image_metadata_t& image_metadata) const {
+    const display::ImageMetadata& image_metadata) const {
   const fidl::WireSyncClient<fuchsia_sysmem::BufferCollection>& client =
       buffer_collections_.at(driver_buffer_collection_id);
   fidl::WireResult check_result = client->CheckBuffersAllocated();
@@ -183,8 +164,8 @@
 
   const auto& format_constraints = collection_info.settings.image_format_constraints;
   uint32_t minimum_row_bytes;
-  if (!ImageFormatMinimumRowBytes(format_constraints, image_metadata.width, &minimum_row_bytes)) {
-    zxlogf(ERROR, "Invalid image width %" PRIu32 " for collection", image_metadata.width);
+  if (!ImageFormatMinimumRowBytes(format_constraints, image_metadata.width(), &minimum_row_bytes)) {
+    zxlogf(ERROR, "Invalid image width %" PRId32 " for collection", image_metadata.width());
     return zx::error(ZX_ERR_INVALID_ARGS);
   }
 
@@ -197,13 +178,12 @@
   });
 }
 
-zx_status_t DisplayEngine::DisplayControllerImplImportBufferCollection(
-    uint64_t banjo_driver_buffer_collection_id, zx::channel collection_token) {
-  const display::DriverBufferCollectionId driver_buffer_collection_id =
-      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+zx::result<> DisplayEngine::ImportBufferCollection(
+    display::DriverBufferCollectionId driver_buffer_collection_id,
+    fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken> buffer_collection_token) {
   if (buffer_collections_.find(driver_buffer_collection_id) != buffer_collections_.end()) {
     zxlogf(ERROR, "Buffer Collection (id=%lu) already exists", driver_buffer_collection_id.value());
-    return ZX_ERR_ALREADY_EXISTS;
+    return zx::error(ZX_ERR_ALREADY_EXISTS);
   }
 
   ZX_DEBUG_ASSERT_MSG(sysmem_.is_valid(), "sysmem allocator is not initialized");
@@ -212,64 +192,54 @@
       fidl::Endpoints<fuchsia_sysmem::BufferCollection>::Create();
 
   auto bind_result = sysmem_->BindSharedCollection(
-      fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken>(std::move(collection_token)),
+      fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken>(std::move(buffer_collection_token)),
       std::move(collection_server_endpoint));
   if (!bind_result.ok()) {
     zxlogf(ERROR, "Cannot complete FIDL call BindSharedCollection: %s",
            bind_result.status_string());
-    return ZX_ERR_INTERNAL;
+    return zx::error(ZX_ERR_INTERNAL);
   }
 
   buffer_collections_[driver_buffer_collection_id] =
       fidl::WireSyncClient(std::move(collection_client_endpoint));
-  return ZX_OK;
+  return zx::ok();
 }
 
-zx_status_t DisplayEngine::DisplayControllerImplReleaseBufferCollection(
-    uint64_t banjo_driver_buffer_collection_id) {
-  const display::DriverBufferCollectionId driver_buffer_collection_id =
-      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+zx::result<> DisplayEngine::ReleaseBufferCollection(
+    display::DriverBufferCollectionId driver_buffer_collection_id) {
   if (buffer_collections_.find(driver_buffer_collection_id) == buffer_collections_.end()) {
     zxlogf(ERROR, "Cannot release buffer collection %lu: buffer collection doesn't exist",
            driver_buffer_collection_id.value());
-    return ZX_ERR_NOT_FOUND;
+    return zx::error(ZX_ERR_NOT_FOUND);
   }
   buffer_collections_.erase(driver_buffer_collection_id);
-  return ZX_OK;
+  return zx::ok();
 }
 
-zx_status_t DisplayEngine::DisplayControllerImplImportImage(
-    const image_metadata_t* image_metadata, uint64_t banjo_driver_buffer_collection_id,
-    uint32_t index, uint64_t* out_image_handle) {
-  const display::DriverBufferCollectionId driver_buffer_collection_id =
-      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+zx::result<display::DriverImageId> DisplayEngine::ImportImage(
+    const display::ImageMetadata& image_metadata,
+    display::DriverBufferCollectionId driver_buffer_collection_id, uint32_t index) {
   const auto it = buffer_collections_.find(driver_buffer_collection_id);
   if (it == buffer_collections_.end()) {
     zxlogf(ERROR, "ImportImage: Cannot find imported buffer collection (id=%lu)",
            driver_buffer_collection_id.value());
-    return ZX_ERR_NOT_FOUND;
+    return zx::error(ZX_ERR_NOT_FOUND);
   }
 
   zx::result<BufferInfo> buffer_info_result =
-      GetAllocatedBufferInfoForImage(driver_buffer_collection_id, index, *image_metadata);
+      GetAllocatedBufferInfoForImage(driver_buffer_collection_id, index, image_metadata);
   if (!buffer_info_result.is_ok()) {
-    return buffer_info_result.error_value();
+    return buffer_info_result.take_error();
   }
   BufferInfo& buffer_info = buffer_info_result.value();
-  zx::result<display::DriverImageId> import_result =
-      Import(std::move(buffer_info.vmo), *image_metadata, buffer_info.offset,
-             buffer_info.bytes_per_pixel, buffer_info.bytes_per_row, buffer_info.pixel_format);
-  if (import_result.is_ok()) {
-    *out_image_handle = display::ToBanjoDriverImageId(import_result.value());
-    return ZX_OK;
-  }
-  return import_result.error_value();
+  return Import(std::move(buffer_info.vmo), image_metadata, buffer_info.offset,
+                buffer_info.bytes_per_pixel, buffer_info.bytes_per_row, buffer_info.pixel_format);
 }
 
 zx::result<display::DriverImageId> DisplayEngine::Import(
-    zx::vmo vmo, const image_metadata_t& image_metadata, size_t offset, uint32_t pixel_size,
+    zx::vmo vmo, const display::ImageMetadata& image_metadata, size_t offset, uint32_t pixel_size,
     uint32_t row_bytes, fuchsia_images2::wire::PixelFormat pixel_format) {
-  if (image_metadata.tiling_type != IMAGE_TILING_TYPE_LINEAR) {
+  if (image_metadata.tiling_type() != display::kImageTilingTypeLinear) {
     return zx::error(ZX_ERR_INVALID_ARGS);
   }
 
@@ -279,7 +249,7 @@
     return zx::error(ZX_ERR_NO_MEMORY);
   }
 
-  unsigned size = ZX_ROUNDUP(row_bytes * image_metadata.height, zx_system_get_page_size());
+  unsigned size = ZX_ROUNDUP(row_bytes * image_metadata.height(), zx_system_get_page_size());
   zx_paddr_t paddr;
   zx_status_t status = gpu_device_->bti().pin(ZX_BTI_PERM_READ | ZX_BTI_CONTIGUOUS, vmo, offset,
                                               size, &paddr, 1, &import_data->pmt);
@@ -289,7 +259,7 @@
   }
 
   zx::result<uint32_t> create_resource_result =
-      gpu_device_->Create2DResource(row_bytes / pixel_size, image_metadata.height, pixel_format);
+      gpu_device_->Create2DResource(row_bytes / pixel_size, image_metadata.height(), pixel_format);
   if (create_resource_result.is_error()) {
     zxlogf(ERROR, "Failed to allocate 2D resource: %s", create_resource_result.status_string());
     return create_resource_result.take_error();
@@ -307,30 +277,33 @@
   return zx::ok(image_id);
 }
 
-void DisplayEngine::DisplayControllerImplReleaseImage(uint64_t image_handle) {
-  delete reinterpret_cast<imported_image_t*>(image_handle);
+zx::result<display::DriverCaptureImageId> DisplayEngine::ImportImageForCapture(
+    display::DriverBufferCollectionId driver_buffer_collection_id, uint32_t index) {
+  return zx::error(ZX_ERR_NOT_SUPPORTED);
 }
 
-config_check_result_t DisplayEngine::DisplayControllerImplCheckConfiguration(
-    const display_config_t** display_configs, size_t display_count,
-    client_composition_opcode_t* out_client_composition_opcodes_list,
-    size_t client_composition_opcodes_count, size_t* out_client_composition_opcodes_actual) {
+void DisplayEngine::ReleaseImage(display::DriverImageId driver_image_id) {
+  delete reinterpret_cast<imported_image_t*>(driver_image_id.value());
+}
+
+config_check_result_t DisplayEngine::CheckConfiguration(
+    cpp20::span<const display_config_t*> display_configs,
+    cpp20::span<client_composition_opcode_t> out_client_composition_opcodes,
+    size_t* out_client_composition_opcodes_actual) {
   if (out_client_composition_opcodes_actual != nullptr) {
     *out_client_composition_opcodes_actual = 0;
   }
 
-  if (display_count != 1) {
-    ZX_DEBUG_ASSERT(display_count == 0);
+  if (display_configs.size() != 1) {
+    ZX_DEBUG_ASSERT(display_configs.size() == 0);
     return CONFIG_CHECK_RESULT_OK;
   }
   ZX_DEBUG_ASSERT(display::ToDisplayId(display_configs[0]->display_id) == kDisplayId);
 
-  ZX_DEBUG_ASSERT(client_composition_opcodes_count >= display_configs[0]->layer_count);
-  cpp20::span<client_composition_opcode_t> client_composition_opcodes(
-      out_client_composition_opcodes_list, display_configs[0]->layer_count);
-  std::fill(client_composition_opcodes.begin(), client_composition_opcodes.end(), 0);
+  ZX_DEBUG_ASSERT(out_client_composition_opcodes.size() >= display_configs[0]->layer_count);
+  std::fill(out_client_composition_opcodes.begin(), out_client_composition_opcodes.end(), 0);
   if (out_client_composition_opcodes_actual != nullptr) {
-    *out_client_composition_opcodes_actual = client_composition_opcodes.size();
+    *out_client_composition_opcodes_actual = out_client_composition_opcodes.size();
   }
 
   bool success;
@@ -346,29 +319,28 @@
     };
     success = display_configs[0]->layer_list[0]->type == LAYER_TYPE_PRIMARY &&
               layer->transform_mode == FRAME_TRANSFORM_IDENTITY &&
-              layer->image.width == current_display_.scanout_info.geometry.width &&
-              layer->image.height == current_display_.scanout_info.geometry.height &&
+              layer->image_metadata.width == current_display_.scanout_info.geometry.width &&
+              layer->image_metadata.height == current_display_.scanout_info.geometry.height &&
               memcmp(&layer->dest_frame, &frame, sizeof(frame_t)) == 0 &&
               memcmp(&layer->src_frame, &frame, sizeof(frame_t)) == 0 &&
               display_configs[0]->cc_flags == 0 && layer->alpha_mode == ALPHA_DISABLE;
   }
   if (!success) {
-    client_composition_opcodes[0] = CLIENT_COMPOSITION_OPCODE_MERGE_BASE;
+    out_client_composition_opcodes[0] = CLIENT_COMPOSITION_OPCODE_MERGE_BASE;
     for (unsigned i = 1; i < display_configs[0]->layer_count; i++) {
-      client_composition_opcodes[i] = CLIENT_COMPOSITION_OPCODE_MERGE_SRC;
+      out_client_composition_opcodes[i] = CLIENT_COMPOSITION_OPCODE_MERGE_SRC;
     }
   }
   return CONFIG_CHECK_RESULT_OK;
 }
 
-void DisplayEngine::DisplayControllerImplApplyConfiguration(
-    const display_config_t** display_configs, size_t display_count,
-    const config_stamp_t* banjo_config_stamp) {
+void DisplayEngine::ApplyConfiguration(cpp20::span<const display_config_t*> display_configs,
+                                       const config_stamp_t* banjo_config_stamp) {
   ZX_DEBUG_ASSERT(banjo_config_stamp);
   display::ConfigStamp config_stamp = display::ToConfigStamp(*banjo_config_stamp);
-  uint64_t handle = display_count == 0 || display_configs[0]->layer_count == 0
+  uint64_t handle = display_configs.empty() || display_configs[0]->layer_count == 0
                         ? 0
-                        : display_configs[0]->layer_list[0]->cfg.primary.image.handle;
+                        : display_configs[0]->layer_list[0]->cfg.primary.image_handle;
 
   {
     fbl::AutoLock al(&flush_lock_);
@@ -377,15 +349,19 @@
   }
 }
 
-zx_status_t DisplayEngine::DisplayControllerImplSetBufferCollectionConstraints(
-    const image_buffer_usage_t* usage, uint64_t banjo_driver_buffer_collection_id) {
-  const display::DriverBufferCollectionId driver_buffer_collection_id =
-      display::ToDriverBufferCollectionId(banjo_driver_buffer_collection_id);
+void DisplayEngine::SetEld(display::DisplayId display_id, cpp20::span<const uint8_t> raw_eld) {
+  // No ELD required for non-HDA systems.
+  return;
+}
+
+zx::result<> DisplayEngine::SetBufferCollectionConstraints(
+    const display::ImageBufferUsage& image_buffer_usage,
+    display::DriverBufferCollectionId driver_buffer_collection_id) {
   const auto it = buffer_collections_.find(driver_buffer_collection_id);
   if (it == buffer_collections_.end()) {
     zxlogf(ERROR, "SetBufferCollectionConstraints: Cannot find imported buffer collection (id=%lu)",
            driver_buffer_collection_id.value());
-    return ZX_ERR_NOT_FOUND;
+    return zx::error(ZX_ERR_NOT_FOUND);
   }
 
   fuchsia_sysmem::wire::BufferCollectionConstraints constraints;
@@ -428,30 +404,49 @@
 
   if (status != ZX_OK) {
     zxlogf(ERROR, "virtio::DisplayEngine: Failed to set constraints");
-    return status;
+    return zx::error(status);
   }
 
-  return ZX_OK;
+  return zx::ok();
 }
 
-zx_status_t DisplayEngine::DisplayControllerImplSetDisplayPower(uint64_t display_id,
-                                                                bool power_on) {
-  return ZX_ERR_NOT_SUPPORTED;
+bool DisplayEngine::IsCaptureSupported() { return false; }
+
+zx::result<> DisplayEngine::SetDisplayPower(display::DisplayId display_id, bool power_on) {
+  return zx::error(ZX_ERR_NOT_SUPPORTED);
+}
+
+zx::result<> DisplayEngine::StartCapture(display::DriverCaptureImageId capture_image_id) {
+  return zx::error(ZX_ERR_NOT_SUPPORTED);
+}
+
+zx::result<> DisplayEngine::ReleaseCapture(display::DriverCaptureImageId capture_image_id) {
+  return zx::error(ZX_ERR_NOT_SUPPORTED);
+}
+
+bool DisplayEngine::IsCaptureCompleted() { return false; }
+
+zx::result<> DisplayEngine::SetMinimumRgb(uint8_t minimum_rgb) {
+  return zx::error(ZX_ERR_NOT_SUPPORTED);
 }
 
 DisplayEngine::DisplayEngine(zx_device_t* bus_device,
+                             DisplayCoordinatorEventsInterface* coordinator_events,
                              fidl::ClientEnd<fuchsia_sysmem::Allocator> sysmem_client,
                              std::unique_ptr<VirtioGpuDevice> gpu_device)
     : sysmem_(std::move(sysmem_client)),
       bus_device_(bus_device),
+      coordinator_events_(*coordinator_events),
       gpu_device_(std::move(gpu_device)) {
+  ZX_DEBUG_ASSERT(coordinator_events != nullptr);
   ZX_DEBUG_ASSERT(gpu_device_);
 }
 
 DisplayEngine::~DisplayEngine() { io_buffer_release(&gpu_req_); }
 
 // static
-zx::result<std::unique_ptr<DisplayEngine>> DisplayEngine::Create(zx_device_t* bus_device) {
+zx::result<std::unique_ptr<DisplayEngine>> DisplayEngine::Create(
+    zx_device_t* bus_device, DisplayCoordinatorEventsInterface* coordinator_events) {
   zx::result<fidl::ClientEnd<fuchsia_sysmem::Allocator>> sysmem_client_result =
       DdkDeviceType::DdkConnectFragmentFidlProtocol<fuchsia_hardware_sysmem::Service::AllocatorV1>(
           bus_device, "sysmem");
@@ -484,7 +479,8 @@
   }
 
   auto display_engine = fbl::make_unique_checked<DisplayEngine>(
-      &alloc_checker, bus_device, std::move(sysmem_client_result).value(), std::move(gpu_device));
+      &alloc_checker, bus_device, coordinator_events, std::move(sysmem_client_result).value(),
+      std::move(gpu_device));
   if (!alloc_checker.check()) {
     zxlogf(ERROR, "Failed to allocate memory for DisplayEngine");
     return zx::error(ZX_ERR_NO_MEMORY);
@@ -549,13 +545,8 @@
 
     {
       fbl::AutoLock al(&flush_lock_);
-      if (dc_intf_.ops) {
-        const uint64_t banjo_display_id = display::ToBanjoDisplayId(kDisplayId);
-        const config_stamp_t banjo_config_stamp =
-            display::ToBanjoConfigStamp(displayed_config_stamp_);
-        display_controller_interface_on_display_vsync(&dc_intf_, banjo_display_id, next_deadline,
-                                                      &banjo_config_stamp);
-      }
+      coordinator_events_.OnDisplayVsync(kDisplayId, zx::time(next_deadline),
+                                         displayed_config_stamp_);
     }
     next_deadline = zx_time_add_duration(next_deadline, period);
   }
diff --git a/src/graphics/display/drivers/virtio-guest/v1/display-engine.h b/src/graphics/display/drivers/virtio-guest/v1/display-engine.h
index a749ae1..41e01b6 100644
--- a/src/graphics/display/drivers/virtio-guest/v1/display-engine.h
+++ b/src/graphics/display/drivers/virtio-guest/v1/display-engine.h
@@ -5,6 +5,8 @@
 #ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_ENGINE_H_
 #define SRC_GRAPHICS_DISPLAY_DRIVERS_VIRTIO_GUEST_V1_DISPLAY_ENGINE_H_
 
+#include <fidl/fuchsia.hardware.display.engine/cpp/wire.h>
+#include <fidl/fuchsia.hardware.display.types/cpp/wire.h>
 #include <fidl/fuchsia.hardware.sysmem/cpp/wire.h>
 #include <fidl/fuchsia.images2/cpp/wire.h>
 #include <fidl/fuchsia.sysmem/cpp/wire.h>
@@ -27,17 +29,23 @@
 #include <fbl/condition_variable.h>
 #include <fbl/mutex.h>
 
+#include "src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-interface.h"
+#include "src/graphics/display/drivers/virtio-guest/v1/display-engine-interface.h"
 #include "src/graphics/display/drivers/virtio-guest/v1/virtio-gpu-device.h"
 #include "src/graphics/display/lib/api-types-cpp/config-stamp.h"
+#include "src/graphics/display/lib/api-types-cpp/display-id.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-buffer-collection-id.h"
+#include "src/graphics/display/lib/api-types-cpp/driver-capture-image-id.h"
 #include "src/graphics/display/lib/api-types-cpp/driver-image-id.h"
+#include "src/graphics/display/lib/api-types-cpp/image-buffer-usage.h"
+#include "src/graphics/display/lib/api-types-cpp/image-metadata.h"
 #include "src/graphics/lib/virtio/virtio-abi.h"
 
 namespace virtio_display {
 
 class Ring;
 
-class DisplayEngine : public ddk::DisplayControllerImplProtocol<DisplayEngine, ddk::base_protocol> {
+class DisplayEngine final : public DisplayEngineInterface {
  public:
   struct BufferInfo {
     zx::vmo vmo = {};
@@ -47,17 +55,51 @@
     fuchsia_images2::wire::PixelFormat pixel_format;
   };
 
-  static zx::result<std::unique_ptr<DisplayEngine>> Create(zx_device_t* bus_device);
+  static zx::result<std::unique_ptr<DisplayEngine>> Create(
+      zx_device_t* bus_device, DisplayCoordinatorEventsInterface* coordinator_events);
 
   // Exposed for testing. Production code must use the Create() factory method.
-  DisplayEngine(zx_device_t* bus_device, fidl::ClientEnd<fuchsia_sysmem::Allocator> sysmem_client,
+  //
+  // `bus_device` and `coordinator_events` must not be null, and must outlive
+  // the newly created instance. `gpu_device` must not be null.
+  DisplayEngine(zx_device_t* bus_device, DisplayCoordinatorEventsInterface* coordinator_events,
+                fidl::ClientEnd<fuchsia_sysmem::Allocator> sysmem_client,
                 std::unique_ptr<VirtioGpuDevice> gpu_device);
   ~DisplayEngine();
 
   zx_status_t Init();
-  zx_status_t DdkGetProtocol(uint32_t proto_id, void* out);
   zx_status_t Start();
 
+  // DisplayEngineInterface:
+  void OnCoordinatorConnected() override;
+  zx::result<> ImportBufferCollection(
+      display::DriverBufferCollectionId driver_buffer_collection_id,
+      fidl::ClientEnd<fuchsia_sysmem::BufferCollectionToken> buffer_collection_token) override;
+  zx::result<> ReleaseBufferCollection(
+      display::DriverBufferCollectionId driver_buffer_collection_id) override;
+  zx::result<display::DriverImageId> ImportImage(
+      const display::ImageMetadata& image_metadata,
+      display::DriverBufferCollectionId driver_buffer_collection_id, uint32_t index) override;
+  zx::result<display::DriverCaptureImageId> ImportImageForCapture(
+      display::DriverBufferCollectionId driver_buffer_collection_id, uint32_t index) override;
+  void ReleaseImage(display::DriverImageId driver_image_id) override;
+  config_check_result_t CheckConfiguration(
+      cpp20::span<const display_config_t*> display_configs,
+      cpp20::span<client_composition_opcode_t> out_client_composition_opcodes,
+      size_t* out_client_composition_opcodes_actual) override;
+  void ApplyConfiguration(cpp20::span<const display_config_t*> display_configs,
+                          const config_stamp_t* banjo_config_stamp) override;
+  void SetEld(display::DisplayId display_id, cpp20::span<const uint8_t> raw_eld) override;
+  zx::result<> SetBufferCollectionConstraints(
+      const display::ImageBufferUsage& image_buffer_usage,
+      display::DriverBufferCollectionId driver_buffer_collection_id) override;
+  zx::result<> SetDisplayPower(display::DisplayId display_id, bool power_on) override;
+  bool IsCaptureSupported() override;
+  zx::result<> StartCapture(display::DriverCaptureImageId capture_image_id) override;
+  zx::result<> ReleaseCapture(display::DriverCaptureImageId capture_image_id) override;
+  bool IsCaptureCompleted() override;
+  zx::result<> SetMinimumRgb(uint8_t minimum_rgb) override;
+
   // Finds the first display usable by this driver, in the `display_infos` list.
   //
   // Returns nullptr if the list does not contain a usable display.
@@ -67,60 +109,7 @@
 
   zx::result<BufferInfo> GetAllocatedBufferInfoForImage(
       display::DriverBufferCollectionId driver_buffer_collection_id, uint32_t index,
-      const image_metadata_t& image_metadata) const;
-
-  void DisplayControllerImplSetDisplayControllerInterface(
-      const display_controller_interface_protocol_t* intf);
-  void DisplayControllerImplResetDisplayControllerInterface();
-
-  zx_status_t DisplayControllerImplImportBufferCollection(
-      uint64_t banjo_driver_buffer_collection_id, zx::channel collection_token);
-  zx_status_t DisplayControllerImplReleaseBufferCollection(
-      uint64_t banjo_driver_buffer_collection_id);
-
-  zx_status_t DisplayControllerImplImportImage(const image_metadata_t* image_metadata,
-                                               uint64_t banjo_driver_buffer_collection_id,
-                                               uint32_t index, uint64_t* out_image_handle);
-
-  zx_status_t DisplayControllerImplImportImageForCapture(uint64_t banjo_driver_buffer_collection_id,
-                                                         uint32_t index,
-                                                         uint64_t* out_capture_handle) {
-    return ZX_ERR_NOT_SUPPORTED;
-  }
-
-  void DisplayControllerImplReleaseImage(uint64_t image_handle);
-
-  config_check_result_t DisplayControllerImplCheckConfiguration(
-      const display_config_t** display_configs, size_t display_count,
-      client_composition_opcode_t* out_client_composition_opcodes_list,
-      size_t client_composition_opcodes_count, size_t* out_client_composition_opcodes_actual);
-
-  void DisplayControllerImplApplyConfiguration(const display_config_t** display_configs,
-                                               size_t display_count,
-                                               const config_stamp_t* banjo_config_stamp);
-
-  void DisplayControllerImplSetEld(uint64_t display_id, const uint8_t* raw_eld_list,
-                                   size_t raw_eld_count) {}  // No ELD required for non-HDA systems.
-
-  zx_status_t DisplayControllerImplSetBufferCollectionConstraints(
-      const image_buffer_usage_t* usage, uint64_t banjo_driver_buffer_collection_id);
-  zx_status_t DisplayControllerImplSetDisplayPower(uint64_t display_id, bool power_on);
-
-  bool DisplayControllerImplIsCaptureSupported() { return false; }
-
-  zx_status_t DisplayControllerImplStartCapture(uint64_t capture_handle) {
-    return ZX_ERR_NOT_SUPPORTED;
-  }
-
-  zx_status_t DisplayControllerImplReleaseCapture(uint64_t capture_handle) {
-    return ZX_ERR_NOT_SUPPORTED;
-  }
-
-  bool DisplayControllerImplIsCaptureCompleted() { return false; }
-
-  zx_status_t DisplayControllerImplSetMinimumRgb(uint8_t minimum_rgb) {
-    return ZX_ERR_NOT_SUPPORTED;
-  }
+      const display::ImageMetadata& image_metadata) const;
 
   VirtioPciDevice& pci_device() { return gpu_device_->pci_device(); }
 
@@ -131,7 +120,8 @@
           fuchsia_images2::wire::PixelFormat::kB8G8R8A8),
   };
 
-  zx::result<display::DriverImageId> Import(zx::vmo vmo, const image_metadata& image_metadata,
+  zx::result<display::DriverImageId> Import(zx::vmo vmo,
+                                            const display::ImageMetadata& image_metadata,
                                             size_t offset, uint32_t pixel_size, uint32_t row_bytes,
                                             fuchsia_images2::wire::PixelFormat pixel_format);
 
@@ -152,11 +142,11 @@
   thrd_t flush_thread_ = {};
   fbl::Mutex flush_lock_;
 
-  display_controller_interface_protocol_t dc_intf_ = {};
   // The sysmem allocator client used to bind incoming buffer collection tokens.
   fidl::WireSyncClient<fuchsia_sysmem::Allocator> sysmem_;
 
   zx_device_t* const bus_device_;
+  DisplayCoordinatorEventsInterface& coordinator_events_;
 
   // Imported sysmem buffer collections.
   std::unordered_map<display::DriverBufferCollectionId,
diff --git a/src/graphics/display/drivers/virtio-guest/v1/gpu-device-driver.cc b/src/graphics/display/drivers/virtio-guest/v1/gpu-device-driver.cc
index 8c3eb37..0fac337 100644
--- a/src/graphics/display/drivers/virtio-guest/v1/gpu-device-driver.cc
+++ b/src/graphics/display/drivers/virtio-guest/v1/gpu-device-driver.cc
@@ -21,20 +21,30 @@
 #include <ddktl/init-txn.h>
 #include <fbl/alloc_checker.h>
 
+#include "src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.h"
+#include "src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h"
 #include "src/graphics/display/drivers/virtio-guest/v1/display-engine.h"
 
 namespace virtio_display {
 
 // static
 zx_status_t GpuDeviceDriver::Create(zx_device_t* parent) {
-  zx::result<std::unique_ptr<DisplayEngine>> display_engine_result = DisplayEngine::Create(parent);
+  fbl::AllocChecker alloc_checker;
+  auto coordinator_events = fbl::make_unique_checked<DisplayCoordinatorEventsBanjo>(&alloc_checker);
+  if (!alloc_checker.check()) {
+    zxlogf(ERROR, "Failed to allocate memory for DisplayCoordinatorEventsBanjo");
+    return ZX_ERR_NO_MEMORY;
+  }
+
+  zx::result<std::unique_ptr<DisplayEngine>> display_engine_result =
+      DisplayEngine::Create(parent, coordinator_events.get());
   if (display_engine_result.is_error()) {
     // DisplayEngine::Create() logs on error.
     return display_engine_result.error_value();
   }
 
-  fbl::AllocChecker alloc_checker;
   auto driver = fbl::make_unique_checked<GpuDeviceDriver>(&alloc_checker, parent,
+                                                          std::move(coordinator_events),
                                                           std::move(display_engine_result).value());
   if (!alloc_checker.check()) {
     zxlogf(ERROR, "Failed to allocate memory for GpuDeviceDriver");
@@ -53,8 +63,13 @@
 }
 
 GpuDeviceDriver::GpuDeviceDriver(zx_device_t* bus_device,
+                                 std::unique_ptr<DisplayCoordinatorEventsBanjo> coordinator_events,
                                  std::unique_ptr<DisplayEngine> display_engine)
-    : DdkDeviceType(bus_device), display_engine_(std::move(display_engine)) {
+    : DdkDeviceType(bus_device),
+      coordinator_events_(std::move(coordinator_events)),
+      display_engine_(std::move(display_engine)),
+      display_controller_banjo_(display_engine_.get(), coordinator_events_.get()) {
+  ZX_DEBUG_ASSERT(coordinator_events_);
   ZX_DEBUG_ASSERT(display_engine_);
 }
 
@@ -87,7 +102,7 @@
 }
 
 zx_status_t GpuDeviceDriver::DdkGetProtocol(uint32_t proto_id, void* out) {
-  return display_engine_->DdkGetProtocol(proto_id, out);
+  return display_controller_banjo_.DdkGetProtocol(proto_id, out);
 }
 
 void GpuDeviceDriver::DdkInit(ddk::InitTxn txn) {
diff --git a/src/graphics/display/drivers/virtio-guest/v1/gpu-device-driver.h b/src/graphics/display/drivers/virtio-guest/v1/gpu-device-driver.h
index e35f651..c0767a53 100644
--- a/src/graphics/display/drivers/virtio-guest/v1/gpu-device-driver.h
+++ b/src/graphics/display/drivers/virtio-guest/v1/gpu-device-driver.h
@@ -15,6 +15,8 @@
 
 #include <ddktl/device.h>
 
+#include "src/graphics/display/drivers/virtio-guest/v1/display-controller-banjo.h"
+#include "src/graphics/display/drivers/virtio-guest/v1/display-coordinator-events-banjo.h"
 #include "src/graphics/display/drivers/virtio-guest/v1/display-engine.h"
 #include "src/graphics/display/drivers/virtio-guest/v1/gpu-control-server.h"
 
@@ -30,7 +32,13 @@
   static zx_status_t Create(zx_device_t* parent);
 
   // Exposed for testing. Production code must use the Create() factory method.
-  explicit GpuDeviceDriver(zx_device_t* bus_device, std::unique_ptr<DisplayEngine> display_engine);
+  //
+  // `coordinator_events` must own the instance passed to the `display_engine`
+  // constructor. It follows that `coordinator_events` must be non-null and must
+  // outlive `display_engine`.
+  explicit GpuDeviceDriver(zx_device_t* bus_device,
+                           std::unique_ptr<DisplayCoordinatorEventsBanjo> coordinator_events,
+                           std::unique_ptr<DisplayEngine> display_engine);
 
   GpuDeviceDriver(const GpuDeviceDriver&) = delete;
   GpuDeviceDriver& operator=(const GpuDeviceDriver&) = delete;
@@ -54,7 +62,14 @@
                            std::function<void(cpp20::span<uint8_t>)> callback) override;
 
  private:
-  std::unique_ptr<DisplayEngine> display_engine_;
+  // Guaranteed to be non-null. Must outlive `display_engine_`.
+  const std::unique_ptr<DisplayCoordinatorEventsBanjo> coordinator_events_;
+
+  // Guaranteed to be non-null. Must outlive `display_controller_banjo_`.
+  const std::unique_ptr<DisplayEngine> display_engine_;
+
+  DisplayControllerBanjo display_controller_banjo_;
+
   std::unique_ptr<GpuControlServer> gpu_control_server_;
 
   // Used by DdkInit() for deferred initialization.
diff --git a/src/graphics/display/testing/software-compositor/software-compositor-tests.cc b/src/graphics/display/testing/software-compositor/software-compositor-tests.cc
index 69a8ebc884..479462f 100644
--- a/src/graphics/display/testing/software-compositor/software-compositor-tests.cc
+++ b/src/graphics/display/testing/software-compositor/software-compositor-tests.cc
@@ -70,7 +70,12 @@
   for (size_t bytes_index = 0; bytes_index < canvas_bytes.size(); bytes_index += 4) {
     cpp20::span<uint8_t> pixel_actual(canvas_bytes.begin() + bytes_index, 4);
     std::array<uint8_t, 4> pixel_expected = {1, 2, 3, 255};
-    EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected));
+    // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+    // figured out.
+    EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+    EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+    EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+    EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
   }
 }
 
@@ -98,7 +103,12 @@
   for (size_t bytes_index = 0; bytes_index < canvas_bytes.size(); bytes_index += 4) {
     cpp20::span<uint8_t> pixel_actual(canvas_bytes.begin() + bytes_index, 4);
     std::array<uint8_t, 4> pixel_expected = {3, 2, 1, 255};
-    EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected));
+    // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+    // figured out.
+    EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+    EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+    EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+    EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
   }
 }
 
@@ -126,7 +136,12 @@
   for (size_t bytes_index = 0; bytes_index < canvas_bytes.size(); bytes_index += 4) {
     cpp20::span<uint8_t> pixel_actual(canvas_bytes.begin() + bytes_index, 4);
     std::array<uint8_t, 4> pixel_expected = {3, 2, 1, 255};
-    EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected));
+    // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+    // figured out.
+    EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+    EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+    EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+    EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
   }
 }
 
@@ -194,7 +209,12 @@
   for (size_t bytes_index = 0; bytes_index < canvas_bytes.size(); bytes_index += 4) {
     cpp20::span<uint8_t> pixel_actual(canvas_bytes.begin() + bytes_index, 4);
     std::array<uint8_t, 4> pixel_expected = {0, 0, 255, 255};
-    EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected));
+    // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+    // figured out.
+    EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+    EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+    EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+    EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
   }
 }
 
@@ -262,7 +282,12 @@
   for (size_t bytes_index = 0; bytes_index < canvas_bytes.size(); bytes_index += 4) {
     cpp20::span<uint8_t> pixel_actual(canvas_bytes.begin() + bytes_index, 4);
     std::array<uint8_t, 4> pixel_expected = {255, 0, 0, 255};
-    EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected));
+    // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+    // figured out.
+    EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+    EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+    EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+    EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
   }
 }
 
@@ -330,7 +355,12 @@
   for (size_t bytes_index = 0; bytes_index < canvas_bytes.size(); bytes_index += 4) {
     cpp20::span<uint8_t> pixel_actual(canvas_bytes.begin() + bytes_index, 4);
     std::array<uint8_t, 4> pixel_expected = {255, 0, 0, 255};
-    EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected));
+    // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+    // figured out.
+    EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+    EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+    EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+    EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
   }
 }
 
@@ -411,8 +441,13 @@
                           (col >= kImageLeft) && (col < kImageLeft + kImageWidth);
       std::array<uint8_t, 4> pixel_expected = in_rectangle ? std::array<uint8_t, 4>{255, 0, 0, 255}
                                                            : std::array<uint8_t, 4>{0, 0, 0, 255};
-      EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected))
-          << "Pixels differ at row " << row << " column " << col;
+      // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+      // figured out.
+      SCOPED_TRACE(testing::Message() << "Pixels differ at row" << row << " column " << col);
+      EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+      EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+      EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+      EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
     }
   }
 }
@@ -526,8 +561,12 @@
       bool is_blue = col < 640;
       std::array<uint8_t, 4> pixel_expected =
           is_blue ? std::array<uint8_t, 4>{0, 0, 255, 255} : std::array<uint8_t, 4>{255, 0, 0, 255};
-      EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected))
-          << "Pixels differ at row " << row << " column " << col;
+      // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+      // figured out.
+      EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+      EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+      EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+      EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
     }
   }
 }
@@ -645,8 +684,12 @@
       std::array<uint8_t, 4> pixel_expected = is_blue  ? std::array<uint8_t, 4>{0, 0, 255, 255}
                                               : is_red ? std::array<uint8_t, 4>{255, 0, 0, 255}
                                                        : std::array<uint8_t, 4>{0, 0, 0, 255};
-      EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected))
-          << "Pixels differ at row " << row << " column " << col;
+      // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+      // figured out.
+      EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+      EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+      EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+      EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
     }
   }
 }
@@ -762,8 +805,12 @@
       bool is_blue = col < 640;
       std::array<uint8_t, 4> pixel_expected =
           is_blue ? std::array<uint8_t, 4>{0, 0, 255, 255} : std::array<uint8_t, 4>{255, 0, 0, 255};
-      EXPECT_THAT(pixel_actual, testing::ElementsAreArray(pixel_expected))
-          << "Pixels differ at row " << row << " column " << col;
+      // TODO(https://fxbug.dev/333768776): Revert back to EXPECT_THAT once the clang regression is
+      // figured out.
+      EXPECT_EQ(pixel_actual[0], pixel_expected[0]);
+      EXPECT_EQ(pixel_actual[1], pixel_expected[1]);
+      EXPECT_EQ(pixel_actual[2], pixel_expected[2]);
+      EXPECT_EQ(pixel_actual[3], pixel_expected[3]);
     }
   }
 }
diff --git a/src/graphics/drivers/misc/goldfish/goldfish.bind b/src/graphics/drivers/misc/goldfish/goldfish.bind
index ceee2b7..a297ba2 100644
--- a/src/graphics/drivers/misc/goldfish/goldfish.bind
+++ b/src/graphics/drivers/misc/goldfish/goldfish.bind
@@ -17,6 +17,6 @@
   fuchsia.hardware.interrupt.Service == fuchsia.hardware.interrupt.Service.ZirconTransport;
 }
 
-node "sysmem" {
+optional node "sysmem" {
   fuchsia.hardware.sysmem.Service == fuchsia.hardware.sysmem.Service.ZirconTransport;
 }
diff --git a/src/graphics/drivers/misc/goldfish/meta/goldfish.cml b/src/graphics/drivers/misc/goldfish/meta/goldfish.cml
index 0704213..d8306c0 100644
--- a/src/graphics/drivers/misc/goldfish/meta/goldfish.cml
+++ b/src/graphics/drivers/misc/goldfish/meta/goldfish.cml
@@ -19,7 +19,6 @@
     ],
     use: [
         { service: "fuchsia.hardware.acpi.Service" },
-        { service: "fuchsia.hardware.sysmem.Service" },
     ],
     expose: [
         {
diff --git a/src/graphics/drivers/misc/goldfish/pipe_device.cc b/src/graphics/drivers/misc/goldfish/pipe_device.cc
index 0ac8946..f723089 100644
--- a/src/graphics/drivers/misc/goldfish/pipe_device.cc
+++ b/src/graphics/drivers/misc/goldfish/pipe_device.cc
@@ -80,13 +80,8 @@
   }
   auto pipe_device = std::make_unique<goldfish::PipeDevice>(
       parent, std::move(acpi.value()), fdf::Dispatcher::GetCurrent()->async_dispatcher());
-  zx_status_t status = pipe_device->ConnectToSysmem();
-  if (status != ZX_OK) {
-    zxlogf(ERROR, "Failed to connect to sysmem fidl: %s", zx_status_get_string(status));
-    return status;
-  }
 
-  status = pipe_device->Bind();
+  zx_status_t status = pipe_device->Bind();
   if (status != ZX_OK) {
     return status;
   }
@@ -314,27 +309,6 @@
   return bti_.duplicate(ZX_RIGHT_SAME_RIGHTS, out_bti);
 }
 
-zx_status_t PipeDevice::ConnectSysmem(zx::channel connection) {
-  TRACE_DURATION("gfx", "PipeDevice::ConnectSysmem");
-  // We can't use DdkConnectFragmentFidlProtocol here because it wants to create the endpoints but
-  // we only have the server_end here.
-  using ServiceMember = fuchsia_hardware_sysmem::Service::AllocatorV1;
-  auto status = device_connect_fragment_fidl_protocol(parent_, "sysmem", ServiceMember::ServiceName,
-                                                      ServiceMember::Name, connection.release());
-  if (status != ZX_OK) {
-    return status;
-  }
-  return ZX_OK;
-}
-
-zx_status_t PipeDevice::RegisterSysmemHeap(uint64_t heap, zx::channel connection) {
-  TRACE_DURATION("gfx", "PipeDevice::RegisterSysmemHeap");
-
-  auto result = hardware_sysmem_->RegisterHeap(
-      heap, fidl::ClientEnd<fuchsia_hardware_sysmem::Heap>(std::move(connection)));
-  return result.status();
-}
-
 int PipeDevice::IrqHandler() {
   while (true) {
     zx_status_t status = irq_.wait(nullptr);
@@ -369,16 +343,6 @@
   return 0;
 }
 
-zx_status_t PipeDevice::ConnectToSysmem() {
-  zx::result hardware_sysmem_result =
-      DdkConnectFragmentFidlProtocol<fuchsia_hardware_sysmem::Service::Sysmem>("sysmem");
-  if (hardware_sysmem_result.is_error()) {
-    return hardware_sysmem_result.status_value();
-  }
-  hardware_sysmem_ = fidl::WireSyncClient(std::move(*hardware_sysmem_result));
-  return ZX_OK;
-}
-
 PipeDevice::Pipe::Pipe(zx_paddr_t paddr, zx::pmt pmt, zx::event pipe_event)
     : paddr(paddr), pmt(std::move(pmt)), pipe_event(std::move(pipe_event)) {}
 
@@ -521,26 +485,6 @@
   }
 }
 
-void PipeChildDevice::ConnectSysmem(ConnectSysmemRequestView request,
-                                    ConnectSysmemCompleter::Sync& completer) {
-  zx_status_t status = parent_->ConnectSysmem(std::move(request->connection));
-  if (status == ZX_OK) {
-    completer.ReplySuccess();
-  } else {
-    completer.Close(status);
-  }
-}
-
-void PipeChildDevice::RegisterSysmemHeap(RegisterSysmemHeapRequestView request,
-                                         RegisterSysmemHeapCompleter::Sync& completer) {
-  zx_status_t status = parent_->RegisterSysmemHeap(request->heap, std::move(request->connection));
-  if (status == ZX_OK) {
-    completer.ReplySuccess();
-  } else {
-    completer.Close(status);
-  }
-}
-
 }  // namespace goldfish
 
 static constexpr zx_driver_ops_t goldfish_driver_ops = []() -> zx_driver_ops_t {
diff --git a/src/graphics/drivers/misc/goldfish/pipe_device.h b/src/graphics/drivers/misc/goldfish/pipe_device.h
index 947acff..a1be59f 100644
--- a/src/graphics/drivers/misc/goldfish/pipe_device.h
+++ b/src/graphics/drivers/misc/goldfish/pipe_device.h
@@ -7,7 +7,6 @@
 
 #include <fidl/fuchsia.hardware.goldfish.pipe/cpp/wire.h>
 #include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
-#include <fidl/fuchsia.hardware.sysmem/cpp/wire.h>
 #include <lib/component/outgoing/cpp/outgoing_directory.h>
 #include <lib/ddk/device.h>
 #include <lib/ddk/io-buffer.h>
@@ -56,14 +55,9 @@
   void Open(int32_t id);
   void Exec(int32_t id);
   zx_status_t GetBti(zx::bti* out_bti);
-  zx_status_t ConnectSysmem(zx::channel connection);
-  zx_status_t RegisterSysmemHeap(uint64_t heap, zx::channel connection);
 
   int IrqHandler();
 
-  // Connect to the sysmem fidl protocol.
-  zx_status_t ConnectToSysmem();
-
  private:
   struct Pipe {
     Pipe(zx_paddr_t paddr, zx::pmt pmt, zx::event pipe_event);
@@ -76,7 +70,6 @@
     zx::event pipe_event;
   };
 
-  fidl::WireSyncClient<fuchsia_hardware_sysmem::Sysmem> hardware_sysmem_;
   acpi::Client acpi_fidl_;
   zx::interrupt irq_;
   zx::bti bti_;
@@ -126,10 +119,6 @@
   void Open(OpenRequestView request, OpenCompleter::Sync& completer) override;
   void Exec(ExecRequestView request, ExecCompleter::Sync& completer) override;
   void GetBti(GetBtiCompleter::Sync& completer) override;
-  void ConnectSysmem(ConnectSysmemRequestView request,
-                     ConnectSysmemCompleter::Sync& completer) override;
-  void RegisterSysmemHeap(RegisterSysmemHeapRequestView request,
-                          RegisterSysmemHeapCompleter::Sync& completer) override;
 
  private:
   PipeDevice* const parent_;
diff --git a/src/graphics/drivers/misc/goldfish/pipe_device_test.cc b/src/graphics/drivers/misc/goldfish/pipe_device_test.cc
index 791b5be..0b8a27c 100644
--- a/src/graphics/drivers/misc/goldfish/pipe_device_test.cc
+++ b/src/graphics/drivers/misc/goldfish/pipe_device_test.cc
@@ -6,8 +6,6 @@
 
 #include <fidl/fuchsia.hardware.goldfish.pipe/cpp/wire.h>
 #include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
-#include <fidl/fuchsia.hardware.sysmem/cpp/wire_test_base.h>
-#include <fidl/fuchsia.sysmem/cpp/wire.h>
 #include <lib/async-loop/cpp/loop.h>
 #include <lib/async-loop/default.h>
 #include <lib/async/default.h>
@@ -49,13 +47,6 @@
 };
 constexpr const char* kDefaultPipeDeviceName = "goldfish-pipe";
 
-using fuchsia_sysmem::wire::HeapType;
-constexpr HeapType kSysmemHeaps[] = {
-    HeapType::kSystemRam,
-    HeapType::kGoldfishDeviceLocal,
-    HeapType::kGoldfishHostVisible,
-};
-
 // MMIO Registers of goldfish pipe.
 // The layout should match the register offsets defined in pipe_device.cc.
 struct Registers {
@@ -115,42 +106,6 @@
   void* ptr_ = nullptr;
 };
 
-class FakeSysmem : public fidl::testing::WireTestBase<fuchsia_hardware_sysmem::Sysmem> {
- public:
-  FakeSysmem() = default;
-
-  void RegisterHeap(RegisterHeapRequestView request,
-                    RegisterHeapCompleter::Sync& completer) override {
-    if (heap_request_koids_.find(request->heap) != heap_request_koids_.end()) {
-      completer.Close(ZX_ERR_ALREADY_BOUND);
-      return;
-    }
-
-    if (!request->heap_connection.is_valid()) {
-      completer.Close(ZX_ERR_BAD_HANDLE);
-      return;
-    }
-
-    zx_info_handle_basic_t info;
-    request->heap_connection.handle()->get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr,
-                                                nullptr);
-    heap_request_koids_[request->heap] = info.koid;
-  }
-
-  void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) final {
-    completer.Close(ZX_ERR_NOT_SUPPORTED);
-  }
-
-  std::map<uint64_t, zx_koid_t> heap_request_koids_;
-};
-
-struct IncomingNamespace {
-  IncomingNamespace() : outgoing(async_get_default_dispatcher()) {}
-
-  FakeSysmem fake_sysmem;
-  component::OutgoingDirectory outgoing;
-};
-
 // Test suite creating fake PipeDevice on a mock ACPI bus.
 class PipeDeviceTest : public zxtest::Test {
  public:
@@ -158,7 +113,6 @@
       // The IncomingNamespace must live on a different thread because the
       // pipe-device makes synchronous FIDL calls to it.
       : ns_loop_(&kAsyncLoopConfigNoAttachToCurrentThread),
-        ns_(ns_loop_.dispatcher(), std::in_place),
         fake_root_(MockDevice::FakeRootParent()),
         test_loop_(&kAsyncLoopConfigAttachToCurrentThread) {}
 
@@ -208,24 +162,8 @@
 
     fake_root_->AddProtocol(ZX_PROTOCOL_ACPI, nullptr, nullptr, "acpi");
 
-    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
-
-    ns_.SyncCall([&endpoints](IncomingNamespace* ns) {
-      zx::result service_result = ns->outgoing.AddService<fuchsia_hardware_sysmem::Service>(
-          fuchsia_hardware_sysmem::Service::InstanceHandler({
-              .sysmem = ns->fake_sysmem.bind_handler(async_get_default_dispatcher()),
-          }));
-      ASSERT_EQ(service_result.status_value(), ZX_OK);
-
-      ASSERT_OK(ns->outgoing.Serve(std::move(endpoints.server)).status_value());
-    });
-
-    fake_root_->AddFidlService(fuchsia_hardware_sysmem::Service::Name, std::move(endpoints.client),
-                               "sysmem");
-
     auto dut = std::make_unique<PipeDevice>(fake_root_.get(), std::move(acpi_client.value()),
                                             test_loop_.dispatcher());
-    ASSERT_OK(dut->ConnectToSysmem());
     ASSERT_OK(dut->Bind());
     dut_ = dut.release();
 
@@ -258,7 +196,6 @@
 
  protected:
   async::Loop ns_loop_;
-  async_patterns::TestDispatcherBound<IncomingNamespace> ns_;
   acpi::mock::Device mock_acpi_fidl_;
 
   std::shared_ptr<MockDevice> fake_root_;
@@ -409,45 +346,6 @@
   ASSERT_FALSE(memcmp(&goldfish_bti_info, &acpi_bti_info, sizeof(zx_info_bti_t)));
 }
 
-// TODO(https://fxbug.dev/42073955): Re-enable the test once the flake is fixed.
-TEST_F(PipeDeviceTest, DISABLED_ConnectToSysmem) {
-  ASSERT_OK(dut_child_->Bind(kDefaultPipeDeviceProps, kDefaultPipeDeviceName));
-  dut_child_.release();
-
-  zx::channel sysmem_server, sysmem_client;
-  ASSERT_OK(zx::channel::create(0u, &sysmem_server, &sysmem_client));
-
-  zx::bti bti;
-  client_->ConnectSysmem(std::move(sysmem_server)).Then([&](auto& result) {
-    ASSERT_OK(result.status());
-  });
-  test_loop_.RunUntilIdle();
-
-  ASSERT_NO_FATAL_FAILURE();
-
-  for (const auto& heap : kSysmemHeaps) {
-    zx::channel heap_server, heap_client;
-    zx_koid_t server_koid = ZX_KOID_INVALID;
-    ASSERT_OK(zx::channel::create(0u, &heap_server, &heap_client));
-
-    zx_info_handle_basic_t info;
-    ASSERT_OK(heap_server.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr));
-    server_koid = info.koid;
-
-    uint64_t heap_id = static_cast<uint64_t>(heap);
-    client_->RegisterSysmemHeap(heap_id, std::move(heap_server)).Then([](auto& result) {
-      ASSERT_OK(result.status());
-    });
-    test_loop_.RunUntilIdle();
-    ns_.SyncCall([heap_id, server_koid](IncomingNamespace* ns) {
-      ASSERT_TRUE(ns->fake_sysmem.heap_request_koids_.find(heap_id) !=
-                  ns->fake_sysmem.heap_request_koids_.end());
-      ASSERT_NE(ns->fake_sysmem.heap_request_koids_.at(heap_id), ZX_KOID_INVALID);
-      ASSERT_EQ(ns->fake_sysmem.heap_request_koids_.at(heap_id), server_koid);
-    });
-  }
-}
-
 TEST_F(PipeDeviceTest, ChildDevice) {
   // Test creating multiple child devices. Each child device can access the
   // GoldfishPipe FIDL protocol, and they should share the same parent device.
diff --git a/src/graphics/drivers/misc/goldfish_control/BUILD.gn b/src/graphics/drivers/misc/goldfish_control/BUILD.gn
index 381ec05..8a2ee8f 100644
--- a/src/graphics/drivers/misc/goldfish_control/BUILD.gn
+++ b/src/graphics/drivers/misc/goldfish_control/BUILD.gn
@@ -20,13 +20,15 @@
 
 common_deps = [
   ":goldfish_control_composite-bind",
-  "//sdk/banjo/fuchsia.hardware.goldfish.control:fuchsia.hardware.goldfish.control_banjo_cpp",
   "//sdk/fidl/fuchsia.hardware.goldfish:fuchsia.hardware.goldfish_cpp",
   "//sdk/fidl/fuchsia.hardware.goldfish.pipe:fuchsia.hardware.goldfish.pipe_cpp",
   "//sdk/fidl/fuchsia.hardware.sysmem:fuchsia.hardware.sysmem_cpp",
   "//sdk/fidl/fuchsia.sysmem2:fuchsia.sysmem2_cpp",
+  "//sdk/lib/component/outgoing/cpp",
+  "//sdk/lib/driver/runtime:driver_runtime_cpp",
   "//sdk/lib/fit-promise",
   "//src/devices/lib/driver",
+  "//src/devices/lib/driver:driver_runtime",
   "//src/devices/lib/goldfish/pipe_headers",
   "//src/lib/ddk",
   "//src/lib/ddktl",
@@ -103,6 +105,7 @@
            "//zircon/system/ulib/fzl",
            "//zircon/system/ulib/mmio-ptr:mmio-ptr-fake",
            "//zircon/system/ulib/sync",
+           "//zircon/system/ulib/sync:sync-cpp",
            "//zircon/system/ulib/zircon-internal",
            "//zircon/system/ulib/zx",
          ]
diff --git a/src/graphics/drivers/misc/goldfish_control/control_device.cc b/src/graphics/drivers/misc/goldfish_control/control_device.cc
index 3b8de30..9759344 100644
--- a/src/graphics/drivers/misc/goldfish_control/control_device.cc
+++ b/src/graphics/drivers/misc/goldfish_control/control_device.cc
@@ -4,6 +4,7 @@
 
 #include "src/graphics/drivers/misc/goldfish_control/control_device.h"
 
+#include <fidl/fuchsia.hardware.goldfish.pipe/cpp/wire.h>
 #include <fidl/fuchsia.hardware.goldfish/cpp/markers.h>
 #include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
 #include <fidl/fuchsia.hardware.sysmem/cpp/fidl.h>
@@ -12,6 +13,7 @@
 #include <lib/ddk/driver.h>
 #include <lib/ddk/platform-defs.h>
 #include <lib/ddk/trace/event.h>
+#include <lib/fdf/cpp/dispatcher.h>
 #include <lib/fit/defer.h>
 #include <lib/sysmem-version/sysmem-version.h>
 #include <zircon/syscalls.h>
@@ -39,11 +41,30 @@
 
 constexpr uint32_t kInvalidBufferHandle = 0U;
 
+zx::result<> RegisterAndBindHeap(
+    fidl::UnownedClientEnd<fuchsia_hardware_sysmem::Sysmem> hardware_sysmem,
+    fuchsia_sysmem::wire::HeapType heap_type, Heap* heap) {
+  auto [heap_client, heap_server] = fidl::Endpoints<fuchsia_hardware_sysmem::Heap>::Create();
+
+  fidl::OneWayStatus register_result =
+      fidl::WireCall(hardware_sysmem)
+          ->RegisterHeap(static_cast<uint64_t>(heap_type), std::move(heap_client));
+  if (!register_result.ok()) {
+    zxlogf(ERROR, "Failed to register Heap to sysmem: %s",
+           register_result.FormatDescription().c_str());
+    return zx::error(register_result.status());
+  }
+
+  heap->Bind(std::move(heap_server).TakeChannel());
+  return zx::ok();
+}
+
 }  // namespace
 
 // static
 zx_status_t Control::Create(void* ctx, zx_device_t* device) {
-  auto control = std::make_unique<Control>(device);
+  async_dispatcher_t* async_dispatcher = fdf::Dispatcher::GetCurrent()->async_dispatcher();
+  auto control = std::make_unique<Control>(device, async_dispatcher);
 
   zx_status_t status = control->Bind();
   if (status == ZX_OK) {
@@ -53,12 +74,10 @@
   return status;
 }
 
-Control::Control(zx_device_t* parent) : ControlType(parent) {
+Control::Control(zx_device_t* parent, async_dispatcher_t* dispatcher)
+    : ControlType(parent), dispatcher_(dispatcher), outgoing_(dispatcher_) {
   // Initialize parent protocols.
   Init();
-
-  goldfish_control_protocol_t self{&goldfish_control_protocol_ops_, this};
-  control_ = ddk::GoldfishControlProtocolClient(&self);
 }
 
 Control::~Control() {
@@ -267,23 +286,6 @@
   return ZX_OK;
 }
 
-zx_status_t Control::RegisterAndBindHeap(fuchsia_sysmem::wire::HeapType heap_type, Heap* heap) {
-  zx::channel heap_request, heap_connection;
-  zx_status_t status = zx::channel::create(0, &heap_request, &heap_connection);
-  if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: zx::channel:create() failed: %d", kTag, status);
-    return status;
-  }
-  auto result =
-      pipe_->RegisterSysmemHeap(static_cast<uint64_t>(heap_type), std::move(heap_connection));
-  if (!result.ok()) {
-    zxlogf(ERROR, "%s: failed to register sysmem heap: %s", kTag, result.status_string());
-    return result.status();
-  }
-  heap->Bind(std::move(heap_request));
-  return ZX_OK;
-}
-
 zx_status_t Control::Bind() {
   fbl::AutoLock lock(&lock_);
 
@@ -305,20 +307,117 @@
     return status;
   }
 
+  zx::result<fidl::ClientEnd<fuchsia_hardware_sysmem::Sysmem>> connect_hardware_sysmem_result =
+      DdkConnectFragmentFidlProtocol<fuchsia_hardware_sysmem::Service::Sysmem>("sysmem");
+  if (connect_hardware_sysmem_result.is_error()) {
+    zxlogf(ERROR, "Failed to connect to fuchsia.hardware.sysmem/Sysmem protocol: %s",
+           connect_hardware_sysmem_result.status_string());
+    return connect_hardware_sysmem_result.status_value();
+  }
+  fidl::ClientEnd<fuchsia_hardware_sysmem::Sysmem> hardware_sysmem =
+      std::move(connect_hardware_sysmem_result).value();
+
   // Serve goldfish device-local heap allocations.
   std::unique_ptr<DeviceLocalHeap> device_local_heap = DeviceLocalHeap::Create(this);
   DeviceLocalHeap* device_local_heap_ptr = device_local_heap.get();
+  zx::result<> bind_device_local_heap_result = RegisterAndBindHeap(
+      hardware_sysmem, fuchsia_sysmem::wire::HeapType::kGoldfishDeviceLocal, device_local_heap_ptr);
+  if (bind_device_local_heap_result.is_error()) {
+    zxlogf(ERROR, "Failed to bind Goldfish Device Local heap: %s",
+           bind_device_local_heap_result.status_string());
+    return bind_device_local_heap_result.status_value();
+  }
   heaps_.push_back(std::move(device_local_heap));
-  RegisterAndBindHeap(fuchsia_sysmem::wire::HeapType::kGoldfishDeviceLocal, device_local_heap_ptr);
 
   // Serve goldfish host-visible heap allocations.
   std::unique_ptr<HostVisibleHeap> host_visible_heap = HostVisibleHeap::Create(this);
   HostVisibleHeap* host_visible_heap_ptr = host_visible_heap.get();
+  zx::result<> bind_host_visible_heap_result = RegisterAndBindHeap(
+      hardware_sysmem, fuchsia_sysmem::wire::HeapType::kGoldfishHostVisible, host_visible_heap_ptr);
+  if (bind_host_visible_heap_result.is_error()) {
+    zxlogf(ERROR, "Failed to bind Goldfish Host Visible heap: %s",
+           bind_host_visible_heap_result.status_string());
+    return bind_host_visible_heap_result.status_value();
+  }
   heaps_.push_back(std::move(host_visible_heap));
-  RegisterAndBindHeap(fuchsia_sysmem::wire::HeapType::kGoldfishHostVisible, host_visible_heap_ptr);
 
-  status =
-      DdkAdd(ddk::DeviceAddArgs("goldfish-control").set_proto_id(ZX_PROTOCOL_GOLDFISH_CONTROL));
+  zx::result<> add_control_service_result =
+      outgoing_.AddService<fuchsia_hardware_goldfish::ControlService>(
+          fuchsia_hardware_goldfish::ControlService::InstanceHandler({
+              .device = bindings_.CreateHandler(this, dispatcher_, fidl::kIgnoreBindingClosure),
+          }));
+  if (add_control_service_result.is_error()) {
+    zxlogf(ERROR, "Failed to add goldfish ControlService to the outgoing directory: %s",
+           add_control_service_result.status_string());
+    return add_control_service_result.status_value();
+  }
+
+  zx::result<> add_pipe_service_result =
+      outgoing_.AddService<fuchsia_hardware_goldfish_pipe::Service>(
+          CreateGoldfishPipeServiceInstanceHandler());
+  if (add_pipe_service_result.is_error()) {
+    zxlogf(ERROR, "Failed to add goldfish pipe Service to the outgoing directory: %s",
+           add_pipe_service_result.status_string());
+    return add_pipe_service_result.status_value();
+  }
+
+  zx::result<> add_sysmem_service_result =
+      outgoing_.AddService<fuchsia_hardware_sysmem::Service>(CreateSysmemServiceInstanceHandler());
+  if (add_sysmem_service_result.is_error()) {
+    zxlogf(ERROR, "Failed to add sysmem Service to the outgoing directory: %s",
+           add_sysmem_service_result.status_string());
+    return add_sysmem_service_result.status_value();
+  }
+
+  zx::result directory_endpoints_result = fidl::CreateEndpoints<fuchsia_io::Directory>();
+  if (directory_endpoints_result.is_error()) {
+    zxlogf(ERROR, "Failed to create fuchsia.io/Directory endpoints: %s",
+           directory_endpoints_result.status_string());
+    return directory_endpoints_result.status_value();
+  }
+  auto [directory_client, directory_server] = std::move(directory_endpoints_result).value();
+
+  zx::result<> serve_result = outgoing_.Serve(std::move(directory_server));
+  if (serve_result.is_error()) {
+    zxlogf(ERROR, "Failed to serve the outgoing directory: %s", serve_result.status_string());
+    return serve_result.status_value();
+  }
+
+  const char* kOffersArray[] = {
+      fuchsia_hardware_goldfish::ControlService::Name,
+      fuchsia_hardware_goldfish_pipe::Service::Name,
+  };
+  const cpp20::span<const char*> kOffers(kOffersArray);
+
+  // TODO(https://fxbug.dev/334988762): This is a hack to support dynamic
+  // routing of the sysmem service.
+  //
+  // Currently, the driver framework adds both dynamically offered capabilities
+  // and the device bind properties using information provided in
+  // `set_fidl_service_offers()` and `set_runtime_service_offers()`.
+  // If we add the sysmem service to `set_fidl_service_offers()`, there'll be
+  // two device nodes (the original "sysmem" device and the goldfish-control
+  // node) with the same sysmem bind properties:
+  // fuchsia.hardware.sysmem.Service == fuchsia.hardware.sysmem.Service.ZirconTransport,
+  // which causes a failure in `driver-index`.
+  //
+  // Adding the sysmem service to `kRuntimeOffers` makes it possible for the
+  // goldfish-control driver to dynamically offer capabilities, while keeps the
+  // bind properties different from the platform sysmem device so there won't
+  // be any system-wide binding failure.
+  //
+  // Note that the sysmem service provided by this component still runs over
+  // Zircon transport rather than Driver transport.
+  const char* kRuntimeOffersArray[] = {
+      fuchsia_hardware_sysmem::Service::Name,
+  };
+  const cpp20::span<const char*> kRuntimeOffers(kRuntimeOffersArray);
+
+  status = DdkAdd(ddk::DeviceAddArgs("goldfish-control")
+                      .set_fidl_service_offers(kOffers)
+                      .set_runtime_service_offers(kRuntimeOffers)
+                      .set_outgoing_dir(directory_client.TakeChannel())
+                      .set_proto_id(ZX_PROTOCOL_GOLDFISH_CONTROL));
   if (status != ZX_OK) {
     zxlogf(ERROR, "%s: DdkAdd() failed: %s", kTag, zx_status_get_string(status));
   }
@@ -560,12 +659,24 @@
 
 void Control::CreateSyncFence(CreateSyncFenceRequestView request,
                               CreateSyncFenceCompleter::Sync& completer) {
-  zx_status_t status = GoldfishControlCreateSyncFence(std::move(request->event));
+  fbl::AutoLock lock(&lock_);
+  uint64_t glsync = 0;
+  uint64_t syncthread = 0;
+  zx_status_t status = CreateSyncKHRLocked(&glsync, &syncthread);
   if (status != ZX_OK) {
-    completer.ReplyError(status);
-  } else {
-    completer.ReplySuccess();
+    zxlogf(ERROR, "CreateSyncFence: cannot call rcCreateSyncKHR, status=%d", status);
+    completer.ReplyError(ZX_ERR_INTERNAL);
+    return;
   }
+
+  auto result = sync_timeline_->TriggerHostWait(glsync, syncthread, std::move(request->event));
+  if (!result.ok()) {
+    zxlogf(ERROR, "TriggerHostWait: FIDL call failed, status=%d", result.status());
+    completer.ReplyError(ZX_ERR_INTERNAL);
+    return;
+  }
+
+  completer.ReplySuccess();
 }
 
 void Control::GetBufferHandle(GetBufferHandleRequestView request,
@@ -666,65 +777,6 @@
 
 void Control::DdkRelease() { delete this; }
 
-zx_status_t Control::DdkGetProtocol(uint32_t proto_id, void* out_protocol) {
-  fbl::AutoLock lock(&lock_);
-
-  switch (proto_id) {
-    case ZX_PROTOCOL_GOLDFISH_CONTROL: {
-      control_.GetProto(static_cast<goldfish_control_protocol_t*>(out_protocol));
-      return ZX_OK;
-    }
-    default:
-      return ZX_ERR_NOT_SUPPORTED;
-  }
-}
-
-zx_status_t Control::GoldfishControlGetColorBuffer(zx::vmo vmo, uint32_t* out_id) {
-  auto buffer_key_result = GetBufferKeyForVmo(vmo);
-  if (!buffer_key_result.is_ok()) {
-    return buffer_key_result.error_value();
-  }
-  auto& buffer_key = buffer_key_result.value();
-
-  fbl::AutoLock lock(&lock_);
-
-  auto it = buffer_handles_.find(buffer_key);
-  if (it == buffer_handles_.end()) {
-    return ZX_ERR_INVALID_ARGS;
-  }
-
-  *out_id = it->second;
-  return ZX_OK;
-}
-
-zx_status_t Control::GoldfishControlCreateSyncFence(zx::eventpair event) {
-  fbl::AutoLock lock(&lock_);
-  uint64_t glsync = 0;
-  uint64_t syncthread = 0;
-  zx_status_t status = CreateSyncKHRLocked(&glsync, &syncthread);
-  if (status != ZX_OK) {
-    zxlogf(ERROR, "CreateSyncFence: cannot call rcCreateSyncKHR, status=%d", status);
-    return ZX_ERR_INTERNAL;
-  }
-
-  auto result = sync_timeline_->TriggerHostWait(glsync, syncthread, std::move(event));
-  if (!result.ok()) {
-    zxlogf(ERROR, "TriggerHostWait: FIDL call failed, status=%d", result.status());
-    return ZX_ERR_INTERNAL;
-  }
-  return ZX_OK;
-}
-
-zx_status_t Control::GoldfishControlConnectToPipeDevice(zx::channel channel) {
-  zx_status_t status = device_connect_fragment_fidl_protocol(
-      parent(), "goldfish-pipe", fuchsia_hardware_goldfish_pipe::Service::Name,
-      fuchsia_hardware_goldfish_pipe::Service::Device::Name, channel.release());
-  if (status != ZX_OK) {
-    zxlogf(ERROR, "%s: failed to bind channel: %s", kTag, zx_status_get_string(status));
-  }
-  return status;
-}
-
 int32_t Control::WriteLocked(uint32_t cmd_size, int32_t* consumed_size) {
   TRACE_DURATION("gfx", "Control::Write", "cmd_size", cmd_size);
 
@@ -996,6 +1048,63 @@
   });
 }
 
+fuchsia_hardware_goldfish_pipe::Service::InstanceHandler
+Control::CreateGoldfishPipeServiceInstanceHandler() {
+  return fuchsia_hardware_goldfish_pipe::Service::InstanceHandler{{
+      .device =
+          [parent =
+               parent()](fidl::ServerEnd<fuchsia_hardware_goldfish_pipe::GoldfishPipe> server_end) {
+            static constexpr const char kGoldfishPipeFragmentName[] = "goldfish-pipe";
+            zx_status_t status = device_connect_fragment_fidl_protocol(
+                parent, kGoldfishPipeFragmentName, fuchsia_hardware_goldfish_pipe::Service::Name,
+                fuchsia_hardware_goldfish_pipe::Service::Device::Name,
+                server_end.TakeChannel().release());
+            if (status != ZX_OK) {
+              zxlogf(ERROR, "Failed to connect to the GoldfishPipe protocol: %s",
+                     zx_status_get_string(status));
+            }
+          },
+  }};
+}
+
+fuchsia_hardware_sysmem::Service::InstanceHandler Control::CreateSysmemServiceInstanceHandler() {
+  static constexpr const char kSysmemFragmentName[] = "sysmem";
+  return fuchsia_hardware_sysmem::Service::InstanceHandler{{
+      .sysmem =
+          [parent = parent()](fidl::ServerEnd<fuchsia_hardware_sysmem::Sysmem> server_end) {
+            zx_status_t status = device_connect_fragment_fidl_protocol(
+                parent, kSysmemFragmentName, fuchsia_hardware_sysmem::Service::Name,
+                fuchsia_hardware_sysmem::Service::Sysmem::Name, server_end.TakeChannel().release());
+            if (status != ZX_OK) {
+              zxlogf(ERROR, "Failed to connect to the Sysmem protocol: %s",
+                     zx_status_get_string(status));
+            }
+          },
+      .allocator_v1 =
+          [parent = parent()](fidl::ServerEnd<fuchsia_sysmem::Allocator> server_end) {
+            zx_status_t status = device_connect_fragment_fidl_protocol(
+                parent, kSysmemFragmentName, fuchsia_hardware_sysmem::Service::Name,
+                fuchsia_hardware_sysmem::Service::AllocatorV1::Name,
+                server_end.TakeChannel().release());
+            if (status != ZX_OK) {
+              zxlogf(ERROR, "Failed to connect to the AllocatorV1 protocol: %s",
+                     zx_status_get_string(status));
+            }
+          },
+      .allocator_v2 =
+          [parent = parent()](fidl::ServerEnd<fuchsia_sysmem2::Allocator> server_end) {
+            zx_status_t status = device_connect_fragment_fidl_protocol(
+                parent, kSysmemFragmentName, fuchsia_hardware_sysmem::Service::Name,
+                fuchsia_hardware_sysmem::Service::AllocatorV2::Name,
+                server_end.TakeChannel().release());
+            if (status != ZX_OK) {
+              zxlogf(ERROR, "Failed to connect to the AllocatorV2 protocol: %s",
+                     zx_status_get_string(status));
+            }
+          },
+  }};
+}
+
 }  // namespace goldfish
 
 static constexpr zx_driver_ops_t goldfish_control_driver_ops = []() -> zx_driver_ops_t {
diff --git a/src/graphics/drivers/misc/goldfish_control/control_device.h b/src/graphics/drivers/misc/goldfish_control/control_device.h
index 6e8e218..d9205ee 100644
--- a/src/graphics/drivers/misc/goldfish_control/control_device.h
+++ b/src/graphics/drivers/misc/goldfish_control/control_device.h
@@ -9,7 +9,7 @@
 #include <fidl/fuchsia.hardware.goldfish/cpp/markers.h>
 #include <fidl/fuchsia.hardware.goldfish/cpp/wire.h>
 #include <fidl/fuchsia.sysmem2/cpp/fidl.h>
-#include <fuchsia/hardware/goldfish/control/cpp/banjo.h>
+#include <lib/component/outgoing/cpp/outgoing_directory.h>
 #include <lib/ddk/device.h>
 #include <lib/ddk/io-buffer.h>
 #include <lib/fpromise/result.h>
@@ -30,15 +30,13 @@
 
 class Control;
 using ControlType =
-    ddk::Device<Control, ddk::Messageable<fuchsia_hardware_goldfish::ControlDevice>::Mixin,
-                ddk::GetProtocolable>;
+    ddk::Device<Control, ddk::Messageable<fuchsia_hardware_goldfish::ControlDevice>::Mixin>;
 
-class Control : public ControlType,
-                public ddk::GoldfishControlProtocol<Control, ddk::base_protocol> {
+class Control : public ControlType {
  public:
   static zx_status_t Create(void* ctx, zx_device_t* parent);
 
-  explicit Control(zx_device_t* parent);
+  explicit Control(zx_device_t* parent, async_dispatcher_t* dispatcher);
   ~Control();
 
   zx_status_t Bind();
@@ -84,10 +82,6 @@
 
   // Device protocol implementation.
   void DdkRelease();
-  zx_status_t DdkGetProtocol(uint32_t proto_id, void* out_protocol);
-  zx_status_t GoldfishControlGetColorBuffer(zx::vmo vmo, uint32_t* out_id);
-  zx_status_t GoldfishControlCreateSyncFence(zx::eventpair event);
-  zx_status_t GoldfishControlConnectToPipeDevice(zx::channel channel);
 
   // Used by heaps. Removes a specific heap from the linked list.
   void RemoveHeap(Heap* heap);
@@ -103,11 +97,6 @@
   zx_status_t InitPipeDeviceLocked() TA_REQ(lock_);
   zx_status_t InitSyncDeviceLocked() TA_REQ(lock_);
 
-  // Create a pair of channel and register a sysmem Heap of |heap_type| using
-  // the channel pair. The client-side channel is sent to sysmem, and the
-  // server-side channel is bound to |heap|.
-  zx_status_t RegisterAndBindHeap(fuchsia_sysmem::wire::HeapType heap_type, Heap* heap);
-
   // TODO(https://fxbug.dev/42161642): Remove these pipe IO functions and use
   // //src/devices/lib/goldfish/pipe_io instead.
   int32_t WriteLocked(uint32_t cmd_size, int32_t* consumed_size) TA_REQ(lock_);
@@ -134,9 +123,13 @@
 
   fit::result<zx_status_t, BufferKey> GetBufferKeyForVmo(const zx::vmo& vmo);
 
+  fuchsia_hardware_goldfish_pipe::Service::InstanceHandler
+  CreateGoldfishPipeServiceInstanceHandler();
+
+  fuchsia_hardware_sysmem::Service::InstanceHandler CreateSysmemServiceInstanceHandler();
+
   fbl::Mutex lock_;
   fidl::WireSyncClient<fuchsia_hardware_goldfish_pipe::GoldfishPipe> pipe_;
-  ddk::GoldfishControlProtocolClient control_;
   fidl::WireSyncClient<fuchsia_hardware_goldfish::AddressSpaceDevice> address_space_;
   fidl::WireSyncClient<fuchsia_hardware_goldfish::SyncDevice> sync_;
   fidl::SyncClient<fuchsia_sysmem2::Allocator> sysmem_;
@@ -164,6 +157,12 @@
   };
   std::map<uint32_t, BufferHandleInfo> buffer_handle_info_ TA_GUARDED(lock_);
 
+  // The outgoing services are dispatched onto `dispatcher_`.
+  async_dispatcher_t* dispatcher_;
+
+  component::OutgoingDirectory outgoing_;
+  fidl::ServerBindingGroup<fuchsia_hardware_goldfish::ControlDevice> bindings_;
+
   DISALLOW_COPY_ASSIGN_AND_MOVE(Control);
 };
 
diff --git a/src/graphics/drivers/misc/goldfish_control/meta/control_driver.cml b/src/graphics/drivers/misc/goldfish_control/meta/control_driver.cml
index c451af4..7b59d6a 100644
--- a/src/graphics/drivers/misc/goldfish_control/meta/control_driver.cml
+++ b/src/graphics/drivers/misc/goldfish_control/meta/control_driver.cml
@@ -15,10 +15,29 @@
         default_dispatcher_opts: [ "allow_sync_calls" ],
         fallback: "false",
     },
+    capabilities: [
+        { service: 'fuchsia.hardware.goldfish.ControlService' },
+        { service: 'fuchsia.hardware.goldfish.pipe.Service' },
+        { service: 'fuchsia.hardware.sysmem.Service' },
+    ],
     use: [
         { service: "fuchsia.hardware.goldfish.pipe.Service" },
         { service: "fuchsia.hardware.goldfish.SyncService" },
         { service: "fuchsia.hardware.goldfish.AddressSpaceService" },
         { service: "fuchsia.hardware.sysmem.Service" },
     ],
+    expose: [
+        {
+            service: 'fuchsia.hardware.goldfish.ControlService',
+            from: 'self',
+        },
+        {
+            service: 'fuchsia.hardware.goldfish.pipe.Service',
+            from: 'self',
+        },
+        {
+            service: 'fuchsia.hardware.sysmem.Service',
+            from: 'self',
+        },
+    ],
 }
diff --git a/src/graphics/drivers/misc/goldfish_control/tests/control_device_test.cc b/src/graphics/drivers/misc/goldfish_control/tests/control_device_test.cc
index 7020f27..8609a39 100644
--- a/src/graphics/drivers/misc/goldfish_control/tests/control_device_test.cc
+++ b/src/graphics/drivers/misc/goldfish_control/tests/control_device_test.cc
@@ -11,21 +11,24 @@
 #include <fidl/fuchsia.hardware.sysmem/cpp/wire_test_base.h>
 #include <fidl/fuchsia.sysmem2/cpp/wire.h>
 #include <fidl/fuchsia.sysmem2/cpp/wire_test_base.h>
-#include <fuchsia/hardware/goldfish/control/cpp/banjo.h>
 #include <lib/async-loop/loop.h>
 #include <lib/async-loop/testing/cpp/real_loop.h>
+#include <lib/async/cpp/task.h>
 #include <lib/component/outgoing/cpp/outgoing_directory.h>
 #include <lib/fake-bti/bti.h>
 #include <lib/fidl/cpp/wire/connect_service.h>
 #include <lib/fzl/vmo-mapper.h>
+#include <lib/sync/cpp/completion.h>
 #include <lib/zx/bti.h>
 #include <lib/zx/vmar.h>
 #include <lib/zx/vmo.h>
+#include <zircon/compiler.h>
 #include <zircon/errors.h>
 #include <zircon/rights.h>
 
 #include <cstdlib>
 #include <memory>
+#include <mutex>
 #include <string>
 #include <unordered_map>
 
@@ -47,14 +50,6 @@
 // TODO(https://fxbug.dev/42161009): Use //src/devices/lib/goldfish/fake_pipe instead.
 class FakePipe : public fidl::WireServer<fuchsia_hardware_goldfish_pipe::GoldfishPipe> {
  public:
-  struct HeapInfo {
-    fidl::ClientEnd<fuchsia_hardware_sysmem::Heap> heap_client_end;
-    bool is_registered = false;
-    bool cpu_supported = false;
-    bool ram_supported = false;
-    bool inaccessible_supported = false;
-  };
-
   void Create(CreateCompleter::Sync& completer) override {
     zx::vmo vmo;
     zx_status_t status = zx::vmo::create(PAGE_SIZE, 0u, &vmo);
@@ -145,27 +140,9 @@
     completer.ReplySuccess(std::move(bti));
   }
 
-  void ConnectSysmem(ConnectSysmemRequestView request,
-                     ConnectSysmemCompleter::Sync& completer) override {
-    completer.ReplySuccess();
-  }
-
-  void RegisterSysmemHeap(RegisterSysmemHeapRequestView request,
-                          RegisterSysmemHeapCompleter::Sync& completer) override {
-    heap_info_[request->heap] = {};
-    heap_info_[request->heap].heap_client_end =
-        fidl::ClientEnd<fuchsia_hardware_sysmem::Heap>(std::move(request->connection));
-    completer.ReplySuccess();
-  }
-
   zx_status_t SetUpPipeDevice() {
-    zx_status_t status = HandleSysmemEvents();
-    if (status != ZX_OK) {
-      return status;
-    }
-
     if (!pipe_io_buffer_.is_valid()) {
-      status = PrepareIoBuffer();
+      zx_status_t status = PrepareIoBuffer();
       if (status != ZX_OK) {
         return status;
       }
@@ -192,55 +169,11 @@
 
   uint32_t CurrentBufferHandle() { return buffer_id_; }
 
-  const std::unordered_map<uint64_t, HeapInfo>& heap_info() const { return heap_info_; }
-
   const std::vector<std::vector<uint8_t>>& io_buffer_contents() const {
     return io_buffer_contents_;
   }
 
  private:
-  class SysmemHeapEventHandler : public fidl::WireSyncEventHandler<fuchsia_hardware_sysmem::Heap> {
-   public:
-    SysmemHeapEventHandler() = default;
-    void OnRegister(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>* message) override {
-      if (handler != nullptr) {
-        handler(message);
-      }
-    }
-    void SetOnRegisterHandler(
-        fit::function<void(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>*)>
-            new_handler) {
-      handler = std::move(new_handler);
-    }
-
-   private:
-    fit::function<void(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>*)> handler;
-  };
-
-  zx_status_t HandleSysmemEvents() {
-    zx_status_t status = ZX_OK;
-    for (auto& kv : heap_info_) {
-      SysmemHeapEventHandler handler;
-      handler.SetOnRegisterHandler(
-          [this,
-           heap = kv.first](fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>* message) {
-            auto& heap_info = heap_info_[heap];
-            heap_info.is_registered = true;
-            heap_info.cpu_supported =
-                message->properties.coherency_domain_support().cpu_supported();
-            heap_info.ram_supported =
-                message->properties.coherency_domain_support().ram_supported();
-            heap_info.inaccessible_supported =
-                message->properties.coherency_domain_support().inaccessible_supported();
-          });
-      status = handler.HandleOneEvent(kv.second.heap_client_end).status();
-      if (status != ZX_OK) {
-        break;
-      }
-    }
-    return status;
-  }
-
   zx_status_t PrepareIoBuffer() {
     uint64_t num_pinned_vmos = 0u;
     std::vector<fake_bti_pinned_vmo_info_t> pinned_vmos;
@@ -283,7 +216,6 @@
 
   int32_t buffer_id_ = 0;
 
-  std::unordered_map<uint64_t, HeapInfo> heap_info_;
   std::vector<std::vector<uint8_t>> io_buffer_contents_;
 };
 
@@ -329,8 +261,70 @@
   FakeHardwareSysmem& parent_;
 };
 
+class SysmemHeapEventHandler : public fidl::WireSyncEventHandler<fuchsia_hardware_sysmem::Heap> {
+ public:
+  SysmemHeapEventHandler() = default;
+  void OnRegister(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>* message) override {
+    if (handler != nullptr) {
+      handler(message);
+    }
+  }
+  void SetOnRegisterHandler(
+      fit::function<void(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>*)>
+          new_handler) {
+    handler = std::move(new_handler);
+  }
+
+ private:
+  fit::function<void(fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>*)> handler;
+};
+
 class FakeHardwareSysmem : public fidl::testing::WireTestBase<fuchsia_hardware_sysmem::Sysmem> {
  public:
+  struct HeapInfo {
+    bool is_registered = false;
+    bool cpu_supported = false;
+    bool ram_supported = false;
+    bool inaccessible_supported = false;
+  };
+
+  // Blocks until all heaps listed in `heaps` are connected with a Heap server
+  // connection.
+  //
+  // Must run on a dispatcher different from the one `FakeHardwareSysmem` is
+  // bound to.
+  void WaitUntilAllHeapsAreConnected(const std::vector<fuchsia_sysmem::HeapType>& heaps) {
+    for (const fuchsia_sysmem::HeapType heap_type : heaps) {
+      while (!IsHeapConnected(static_cast<uint64_t>(heap_type))) {
+        static constexpr zx::duration kStep = zx::msec(1);
+        zx::nanosleep(zx::deadline_after(kStep));
+      }
+    }
+  }
+
+  // Must be called after `WaitUntilAllHeapsAreConnected()`.
+  zx_status_t SetupHeaps() {
+    std::lock_guard lock(mutex_);
+    for (const auto& [heap_type, heap_client] : heap_clients_) {
+      HeapInfo& heap = heap_info_[heap_type];
+      SysmemHeapEventHandler handler;
+      handler.SetOnRegisterHandler(
+          [&heap](fidl::WireEvent<fuchsia_hardware_sysmem::Heap::OnRegister>* message) {
+            heap.is_registered = true;
+            heap.cpu_supported = message->properties.coherency_domain_support().cpu_supported();
+            heap.ram_supported = message->properties.coherency_domain_support().ram_supported();
+            heap.inaccessible_supported =
+                message->properties.coherency_domain_support().inaccessible_supported();
+          });
+
+      zx_status_t status = handler.HandleOneEvent(heap_client).status();
+      if (status != ZX_OK) {
+        return status;
+      }
+    }
+    return ZX_OK;
+  }
+
   void AddFakeVmoInfo(const zx::vmo& vmo, BufferKey buffer_key) {
     zx_koid_t koid = fsl::GetKoid(vmo.get());
     ZX_ASSERT(koid != ZX_KOID_INVALID);
@@ -347,14 +341,36 @@
     return iter->second;
   }
 
+  void RegisterHeap(RegisterHeapRequestView request,
+                    RegisterHeapCompleter::Sync& completer) override {
+    std::lock_guard lock(mutex_);
+    heap_clients_[request->heap] = std::move(request->heap_connection);
+  }
+
   void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override {
     ADD_FAILURE() << "unexpected call to " << name;
     completer.Close(ZX_ERR_NOT_SUPPORTED);
   }
 
+  std::unordered_map<uint64_t, HeapInfo> CloneHeapInfo() const {
+    std::lock_guard lock(mutex_);
+    return heap_info_;
+  }
+
  private:
+  bool IsHeapConnected(uint64_t heap) {
+    std::lock_guard lock(mutex_);
+    return heap_clients_.find(heap) != heap_clients_.end();
+  }
+
   using VmoInfoMap = std::unordered_map<zx_koid_t, BufferKey>;
+
+  mutable std::mutex mutex_;
   VmoInfoMap vmo_infos_;
+
+  std::unordered_map<uint64_t, fidl::ClientEnd<fuchsia_hardware_sysmem::Heap>> heap_clients_
+      __TA_GUARDED(mutex_);
+  std::unordered_map<uint64_t, HeapInfo> heap_info_ __TA_GUARDED(mutex_);
 };
 
 void FakeSysmemAllocator::GetVmoInfo(::fuchsia_sysmem2::wire::AllocatorGetVmoInfoRequest* request,
@@ -375,6 +391,7 @@
  public:
   ControlDeviceTest()
       : loop_(&kAsyncLoopConfigNeverAttachToThread),
+        device_loop_(&kAsyncLoopConfigNeverAttachToThread),
         pipe_server_loop_(&kAsyncLoopConfigNeverAttachToThread),
         address_space_server_loop_(&kAsyncLoopConfigNeverAttachToThread),
         sync_server_loop_(&kAsyncLoopConfigNeverAttachToThread),
@@ -440,20 +457,31 @@
     fake_parent_->AddFidlService(fuchsia_hardware_sysmem::Service::Name,
                                  std::move(endpoints->client), "sysmem");
 
+    device_loop_.StartThread("device-loop");
     pipe_server_loop_.StartThread("goldfish-pipe-fidl-server");
     address_space_server_loop_.StartThread("goldfish-address-space-fidl-server");
     sync_server_loop_.StartThread("goldfish-sync-fidl-server");
     sysmem_server_loop_.StartThread("sysmem-fidl-server");
 
-    auto dut = std::make_unique<Control>(fake_parent_.get());
-    PerformBlockingWork([&]() { ASSERT_EQ(dut->Bind(), ZX_OK); });
-    // The device will be deleted by MockDevice when the test ends.
-    dut.release();
+    libsync::Completion device_bound;
+    async::PostTask(device_loop_.dispatcher(), [this, &device_bound] {
+      auto dut = std::make_unique<Control>(fake_parent_.get(), device_loop_.dispatcher());
+      ZX_ASSERT(dut->Bind() == ZX_OK);
+      // The device will be deleted by MockDevice when the test ends.
+      dut.release();
+      device_bound.Signal();
+    });
+    PerformBlockingWork([&device_bound] { device_bound.Wait(); });
 
     ASSERT_EQ(fake_parent_->child_count(), 1u);
     auto fake_dut = fake_parent_->GetLatestChild();
     dut_ = fake_dut->GetDeviceContext<Control>();
 
+    hardware_sysmem_.WaitUntilAllHeapsAreConnected({
+        fuchsia_sysmem::wire::HeapType::kGoldfishDeviceLocal,
+        fuchsia_sysmem::wire::HeapType::kGoldfishHostVisible,
+    });
+    ASSERT_OK(hardware_sysmem_.SetupHeaps());
     ASSERT_OK(pipe_.SetUpPipeDevice());
     ASSERT_TRUE(pipe_.IsPipeReady());
 
@@ -472,13 +500,19 @@
 
   void TearDown() override {
     device_async_remove(dut_->zxdev());
-    mock_ddk::ReleaseFlaggedDevices(fake_parent_.get());
+    libsync::Completion device_released;
+    async::PostTask(device_loop_.dispatcher(), [this, &device_released] {
+      mock_ddk::ReleaseFlaggedDevices(fake_parent_.get());
+      device_released.Signal();
+    });
+    device_released.Wait();
   }
 
  protected:
   Control* dut_ = nullptr;
 
   async::Loop loop_;
+  async::Loop device_loop_;
   async::Loop pipe_server_loop_;
   async::Loop address_space_server_loop_;
   async::Loop sync_server_loop_;
@@ -500,7 +534,8 @@
 };
 
 TEST_F(ControlDeviceTest, Bind) {
-  const auto& heaps = pipe_.heap_info();
+  const std::unordered_map<uint64_t, FakeHardwareSysmem::HeapInfo> heaps =
+      hardware_sysmem_.CloneHeapInfo();
   ASSERT_EQ(heaps.size(), 2u);
   ASSERT_TRUE(heaps.find(static_cast<uint64_t>(
                   fuchsia_sysmem::wire::HeapType::kGoldfishDeviceLocal)) != heaps.end());
@@ -509,13 +544,11 @@
 
   const auto& device_local_heap_info =
       heaps.at(static_cast<uint64_t>(fuchsia_sysmem::wire::HeapType::kGoldfishDeviceLocal));
-  EXPECT_TRUE(device_local_heap_info.heap_client_end.is_valid());
   EXPECT_TRUE(device_local_heap_info.is_registered);
   EXPECT_TRUE(device_local_heap_info.inaccessible_supported);
 
   const auto& host_visible_heap_info =
       heaps.at(static_cast<uint64_t>(fuchsia_sysmem::wire::HeapType::kGoldfishHostVisible));
-  EXPECT_TRUE(host_visible_heap_info.heap_client_end.is_valid());
   EXPECT_TRUE(host_visible_heap_info.is_registered);
   EXPECT_TRUE(host_visible_heap_info.cpu_supported);
 }
diff --git a/src/graphics/drivers/msd-intel-gen/BUILD.gn b/src/graphics/drivers/msd-intel-gen/BUILD.gn
index ffa48cd..d4255e2 100644
--- a/src/graphics/drivers/msd-intel-gen/BUILD.gn
+++ b/src/graphics/drivers/msd-intel-gen/BUILD.gn
@@ -62,7 +62,8 @@
 }
 
 source_set("msd_intel_entry") {
-  public_configs = [ "$msd_intel_gen_build_root:msd_src_include_config" ]
+  public_configs =
+      [ "//src/graphics/drivers/msd-intel-gen:msd_src_include_config" ]
   sources = [ "src/driver_entry.cc" ]
 
   deps = [
@@ -86,7 +87,8 @@
 source_set("msd_intel_test_entry") {
   testonly = true
 
-  public_configs = [ "$msd_intel_gen_build_root:msd_src_include_config" ]
+  public_configs =
+      [ "//src/graphics/drivers/msd-intel-gen:msd_src_include_config" ]
   sources = [ "src/driver_entry.cc" ]
   defines = [ "MAGMA_TEST_DRIVER=1" ]
 
diff --git a/src/graphics/drivers/msd-intel-gen/src/BUILD.gn b/src/graphics/drivers/msd-intel-gen/src/BUILD.gn
index 393bd14..9bb32e6 100644
--- a/src/graphics/drivers/msd-intel-gen/src/BUILD.gn
+++ b/src/graphics/drivers/msd-intel-gen/src/BUILD.gn
@@ -10,7 +10,8 @@
 }
 
 source_set("src") {
-  public_configs = [ "$msd_intel_gen_build_root:msd_src_include_config" ]
+  public_configs =
+      [ "//src/graphics/drivers/msd-intel-gen:msd_src_include_config" ]
 
   if (hangcheck_timeout_ms != 0) {
     defines = [ "HANGCHECK_TIMEOUT_MS=$hangcheck_timeout_ms" ]
diff --git a/src/graphics/drivers/msd-intel-gen/tests/integration/BUILD.gn b/src/graphics/drivers/msd-intel-gen/tests/integration/BUILD.gn
index 525a1f5..b4f320f 100644
--- a/src/graphics/drivers/msd-intel-gen/tests/integration/BUILD.gn
+++ b/src/graphics/drivers/msd-intel-gen/tests/integration/BUILD.gn
@@ -30,9 +30,9 @@
   ]
 
   deps = [
-    "$magma_build_root/src/libmagma",
     "../../include",
     "//sdk/fidl/fuchsia.gpu.magma:fuchsia.gpu.magma_cpp",
+    "//src/graphics/lib/magma/src/libmagma",
     "//src/graphics/magma/lib/magma/test_util:logger_init_helper",
     "//src/graphics/magma/lib/magma/util:short_macros",
     "//src/graphics/magma/lib/magma_client/test_util:inflight_list",
diff --git a/src/graphics/drivers/msd-intel-gen/tests/mock/BUILD.gn b/src/graphics/drivers/msd-intel-gen/tests/mock/BUILD.gn
index 297bb55..16dbde9 100644
--- a/src/graphics/drivers/msd-intel-gen/tests/mock/BUILD.gn
+++ b/src/graphics/drivers/msd-intel-gen/tests/mock/BUILD.gn
@@ -6,12 +6,12 @@
 
 source_set("mock") {
   public_configs = [
-    "$msd_intel_gen_build_root:msd_tests_include_config",
-    "$msd_intel_gen_build_root:msd_src_include_config",
+    "//src/graphics/drivers/msd-intel-gen:msd_tests_include_config",
+    "//src/graphics/drivers/msd-intel-gen:msd_src_include_config",
   ]
 
   public_deps = [
-    "$msd_intel_gen_build_root/src",
+    "//src/graphics/drivers/msd-intel-gen/src",
     "//src/graphics/magma:msd",
     "//src/graphics/magma/lib/magma/platform:buffer",
     "//src/graphics/magma/lib/magma/util:macros",
diff --git a/src/graphics/lib/magma/gnbuild/magma.gni b/src/graphics/lib/magma/gnbuild/magma.gni
index 24670deb..b1a60d0 100644
--- a/src/graphics/lib/magma/gnbuild/magma.gni
+++ b/src/graphics/lib/magma/gnbuild/magma.gni
@@ -8,19 +8,9 @@
 import("//build/testing/environments.gni")
 
 declare_args() {
-  magma_build_root = "//src/graphics/lib/magma"
-  expat_build_root = "//third_party/expat"
-  msd_build_root = "//src/graphics/drivers"
-  msd_intel_gen_build_root = "$msd_build_root/msd-intel-gen"
-
-  magma_python_path = rebase_path("//third_party/mako")
-
   # Enable this to include fuchsia tracing capability
   magma_enable_tracing = true
 
-  # The path to a prebuilt libvulkan.so for an IMG GPU.
-  prebuilt_libvulkan_img_path = ""
-
   # The path to OpenVX headers
   magma_openvx_include = ""
 
@@ -28,18 +18,6 @@
   magma_openvx_package = ""
 }
 
-declare_args() {
-  # Targets that will be built as verisilicon vulkan ICDS.
-  build_libvulkan_vsi_vip = []
-
-  # Targets that will be built as IMG vulkan ICDS.
-  build_libvulkan_img_rgx = []
-}
-
-have_prebuilt_libvulkan_img = prebuilt_libvulkan_img_path != ""
-build_libvulkan = build_libvulkan_vsi_vip + build_libvulkan_img_rgx
-have_libvulkan = build_libvulkan != [] || have_prebuilt_libvulkan_img
-
 # Target environments with an Intel GPU.
 magma_intel_gpu_envs = [ nuc_env ]
 
diff --git a/src/graphics/magma/lib/magma/platform/BUILD.gn b/src/graphics/magma/lib/magma/platform/BUILD.gn
index b1466b7..dffab73 100644
--- a/src/graphics/magma/lib/magma/platform/BUILD.gn
+++ b/src/graphics/magma/lib/magma/platform/BUILD.gn
@@ -435,7 +435,7 @@
 }
 
 source_set("sysmem_connection_header") {
-  public_configs = [ "$magma_build_root:magma_src_include_config" ]
+  public_configs = [ "//src/graphics/lib/magma:magma_src_include_config" ]
 
   sources = [ "platform_sysmem_connection.h" ]
 
diff --git a/src/graphics/magma/lib/magma/util/BUILD.gn b/src/graphics/magma/lib/magma/util/BUILD.gn
index de559f0..e3aab73 100644
--- a/src/graphics/magma/lib/magma/util/BUILD.gn
+++ b/src/graphics/magma/lib/magma/util/BUILD.gn
@@ -29,7 +29,7 @@
 
   public_configs = [
     ":magma_util_config",
-    "$magma_build_root:magma_src_include_config",
+    "//src/graphics/lib/magma:magma_src_include_config",
   ]
   public_deps = [ "//src/graphics/magma/lib/magma/platform:logger" ]
 
@@ -43,7 +43,7 @@
 source_set("status") {
   visibility = visibility_list
 
-  public_configs = [ "$magma_build_root:magma_src_include_config" ]
+  public_configs = [ "//src/graphics/lib/magma:magma_src_include_config" ]
 
   sources = [ "status.h" ]
 
@@ -53,7 +53,7 @@
 source_set("thread") {
   visibility = visibility_list
 
-  public_configs = [ "$magma_build_root:magma_src_include_config" ]
+  public_configs = [ "//src/graphics/lib/magma:magma_src_include_config" ]
 
   sources = [ "thread.h" ]
 
diff --git a/src/graphics/magma/tests/integration/BUILD.gn b/src/graphics/magma/tests/integration/BUILD.gn
index 253b9f1..c0f7a16 100644
--- a/src/graphics/magma/tests/integration/BUILD.gn
+++ b/src/graphics/magma/tests/integration/BUILD.gn
@@ -70,10 +70,10 @@
 
   deps = [
     ":conformance-config",
-    "$magma_build_root/src/libmagma",
     "//sdk/lib/magma_client:magma_headers",
     "//src/graphics/drivers/msd-arm-mali/include",
     "//src/graphics/drivers/msd-intel-gen/include",
+    "//src/graphics/lib/magma/src/libmagma",
     "//src/graphics/magma/lib/magma_client/test_util:magma_map_cpu",
     "//src/lib/fsl",
     "//src/lib/fxl:fxl_cli",
@@ -110,10 +110,10 @@
 
   deps = [
     ":conformance-config",
-    "$magma_build_root/src/libmagma:magma_hermetic",
     "//sdk/lib/magma_client:magma_headers",
     "//src/graphics/drivers/msd-arm-mali/include",
     "//src/graphics/drivers/msd-intel-gen/include",
+    "//src/graphics/lib/magma/src/libmagma:magma_hermetic",
     "//src/graphics/magma/lib/magma_client/test_util:magma_map_cpu",
     "//src/lib/fsl",
     "//src/lib/fxl:fxl_cli",
@@ -147,10 +147,10 @@
   ]
 
   deps = [
-    "$magma_build_root/src/libmagma_virt",
     "//sdk/lib/magma_client:magma_headers",
     "//src/graphics/drivers/msd-arm-mali/include",
     "//src/graphics/drivers/msd-intel-gen/include",
+    "//src/graphics/lib/magma/src/libmagma_virt",
     "//src/graphics/magma/lib/magma_client/test_util:magma_map_cpu",
     "//src/lib/fxl:fxl_cli",
     "//third_party/googletest:gtest",
@@ -173,8 +173,8 @@
   ]
 
   deps = [
-    "$magma_build_root/src/libmagma_virt",
     "//sdk/lib/magma_client:magma_headers",
+    "//src/graphics/lib/magma/src/libmagma_virt",
   ]
 
   disable_syslog_backend = true
@@ -191,8 +191,8 @@
   sources = [ "test_magma_sync_file.cc" ]
 
   deps = [
-    "$magma_build_root/src/libmagma_virt",
     "//sdk/lib/magma_client:magma_headers",
+    "//src/graphics/lib/magma/src/libmagma_virt",
     "//src/lib/fxl/test:gtest_main",
   ]
   include_dirs = [
diff --git a/src/graphics/tests/vkext/vk_ext_buffer_collection.cc b/src/graphics/tests/vkext/vk_ext_buffer_collection.cc
index 2592b0d9..836641d 100644
--- a/src/graphics/tests/vkext/vk_ext_buffer_collection.cc
+++ b/src/graphics/tests/vkext/vk_ext_buffer_collection.cc
@@ -862,8 +862,9 @@
 
   auto [vulkan_token] = MakeSharedCollection<1>();
 
-  // TODO(fxbug.dev/321072153): Lavapipe doesn't support `VK_FORMAT_G8_B8R8_2PLANE_420_UNORM`, so
-  // we use RGBA when Lavapipe is detected via `UseCpuGpu()`.
+  // TODO(https://fxbug.dev/321072153): Lavapipe doesn't support
+  // `VK_FORMAT_G8_B8R8_2PLANE_420_UNORM`, so we use RGBA when Lavapipe is detected via
+  // `UseCpuGpu()`.
   const VkFormat kFormat =
       !SupportsSysmemYuv() ? VK_FORMAT_R8G8B8A8_UNORM : VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
   bool is_yuv = kFormat == VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
@@ -1728,4 +1729,260 @@
   CheckLinearImage(dst_memory.get(), dst_is_coherent, kDefaultWidth, kDefaultHeight, kPattern);
 }
 
+// Test that the correct pixels are written to with linear images with non-packed strides.
+TEST_F(VulkanExtensionTest, LinearNonPackedStride) {
+  ASSERT_TRUE(Initialize());
+
+  if (!SupportsSysmemRenderableLinear()) {
+    GTEST_SKIP();
+  }
+
+  constexpr bool kUseProtectedMemory = false;
+  constexpr uint32_t kPattern = 0xaabbccdd;
+  constexpr size_t kBytesPerPixel = 4;
+
+  vk::UniqueImage image;
+  vk::UniqueDeviceMemory memory;
+  bool src_is_coherent;
+
+  fuchsia::sysmem::BufferCollectionInfo_2 sysmem_collection;
+  {
+    auto [vulkan_token, sysmem_token] = MakeSharedCollection<2>();
+    constexpr bool kUseLinear = true;
+
+    vk::ImageCreateInfo image_create_info = GetDefaultImageCreateInfo(
+        kUseProtectedMemory, kDefaultFormat, kDefaultWidth, kDefaultHeight, kUseLinear);
+    image_create_info.setUsage(vk::ImageUsageFlagBits::eTransferSrc |
+                               vk::ImageUsageFlagBits::eColorAttachment);
+    image_create_info.setInitialLayout(vk::ImageLayout::ePreinitialized);
+
+    vk::ImageFormatConstraintsInfoFUCHSIA format_constraints =
+        GetDefaultRgbImageFormatConstraintsInfo();
+    format_constraints.imageCreateInfo = image_create_info;
+
+    UniqueBufferCollection collection = CreateVkBufferCollectionForImage(
+        std::move(vulkan_token), format_constraints,
+        vk::ImageConstraintsInfoFlagBitsFUCHSIA::eCpuReadOften |
+            vk::ImageConstraintsInfoFlagBitsFUCHSIA::eCpuWriteOften);
+
+    fuchsia::sysmem::ImageFormatConstraints bgra_image_constraints;
+    bgra_image_constraints.required_min_coded_width = 64;
+    bgra_image_constraints.required_min_coded_height = 64;
+    bgra_image_constraints.required_max_coded_width = 64;
+    bgra_image_constraints.required_max_coded_height = 64;
+    bgra_image_constraints.max_coded_width = 8192;
+    bgra_image_constraints.max_coded_height = 8192;
+    bgra_image_constraints.max_bytes_per_row = 0xffffffff;
+    bgra_image_constraints.bytes_per_row_divisor = 1024;
+    bgra_image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::R8G8B8A8;
+    bgra_image_constraints.pixel_format.has_format_modifier = true;
+    bgra_image_constraints.pixel_format.format_modifier.value =
+        fuchsia::sysmem::FORMAT_MODIFIER_LINEAR;
+    bgra_image_constraints.color_spaces_count = 1;
+    bgra_image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::SRGB;
+
+    EXPECT_LT(kDefaultWidth * 4, bgra_image_constraints.bytes_per_row_divisor);
+    fuchsia::sysmem::BufferCollectionConstraints constraints;
+    constraints.usage.cpu = fuchsia::sysmem::cpuUsageRead;
+    constraints.has_buffer_memory_constraints = true;
+    constraints.buffer_memory_constraints.cpu_domain_supported = true;
+    constraints.buffer_memory_constraints.ram_domain_supported = true;
+    constraints.image_format_constraints_count = 1;
+    constraints.image_format_constraints[0] = bgra_image_constraints;
+    sysmem_collection = AllocateSysmemCollection(constraints, std::move(sysmem_token));
+
+    ASSERT_TRUE(InitializeDirectImage(*collection, image_create_info));
+
+    std::optional<uint32_t> init_img_memory_result = InitializeDirectImageMemory(*collection);
+    ASSERT_TRUE(init_img_memory_result);
+    uint32_t memoryTypeIndex = init_img_memory_result.value();
+    src_is_coherent = IsMemoryTypeCoherent(memoryTypeIndex);
+
+    image = std::move(vk_image_);
+    memory = std::move(vk_device_memory_);
+
+    WriteLinearColorImageComplete(memory.get(), image.get(), src_is_coherent, kDefaultWidth,
+                                  kDefaultHeight, kPattern);
+  }
+
+  size_t bytes_per_row = fbl::round_up(
+      std::max(kDefaultWidth * kBytesPerPixel,
+               static_cast<size_t>(
+                   sysmem_collection.settings.image_format_constraints.min_bytes_per_row)),
+      sysmem_collection.settings.image_format_constraints.bytes_per_row_divisor);
+  auto layout = vulkan_context().device()->getImageSubresourceLayout(
+      image.get(), vk::ImageSubresource(vk::ImageAspectFlagBits::eColor, 0, 0));
+  EXPECT_EQ(bytes_per_row, layout.rowPitch);
+  vk::UniqueCommandPool command_pool;
+  {
+    auto info =
+        vk::CommandPoolCreateInfo().setQueueFamilyIndex(vulkan_context().queue_family_index());
+    auto result = vulkan_context().device()->createCommandPoolUnique(info);
+    ASSERT_EQ(vk::Result::eSuccess, result.result);
+    command_pool = std::move(result.value);
+  }
+
+  std::vector<vk::UniqueCommandBuffer> command_buffers;
+  {
+    auto info = vk::CommandBufferAllocateInfo()
+                    .setCommandPool(command_pool.get())
+                    .setLevel(vk::CommandBufferLevel::ePrimary)
+                    .setCommandBufferCount(1);
+    auto result = vulkan_context().device()->allocateCommandBuffersUnique(info);
+    ASSERT_EQ(vk::Result::eSuccess, result.result);
+    command_buffers = std::move(result.value);
+  }
+
+  {
+    auto info = vk::CommandBufferBeginInfo();
+    EXPECT_EQ(vk::Result::eSuccess, command_buffers[0]->begin(&info));
+  }
+
+  vk::UniqueRenderPass render_pass;
+  {
+    std::array<vk::AttachmentDescription, 1> attachments;
+    auto &color_attachment = attachments[0];
+    color_attachment.format = static_cast<vk::Format>(kDefaultFormat);
+    color_attachment.initialLayout = vk::ImageLayout::ePreinitialized;
+    color_attachment.loadOp = vk::AttachmentLoadOp::eClear;
+    color_attachment.samples = vk::SampleCountFlagBits::e1;
+    color_attachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
+    color_attachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
+    color_attachment.storeOp = vk::AttachmentStoreOp::eStore;
+    color_attachment.finalLayout = vk::ImageLayout::eColorAttachmentOptimal;
+
+    vk::AttachmentReference color_attachment_ref;
+    color_attachment_ref.attachment = 0;
+    color_attachment_ref.layout = vk::ImageLayout::eColorAttachmentOptimal;
+    vk::SubpassDescription subpass;
+    subpass.colorAttachmentCount = 1;
+    subpass.pColorAttachments = &color_attachment_ref;
+    subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
+
+    vk::RenderPassCreateInfo render_pass_info;
+    render_pass_info.attachmentCount = 1;
+    render_pass_info.pAttachments = &color_attachment;
+    render_pass_info.pSubpasses = &subpass;
+    render_pass_info.subpassCount = 1;
+    auto result = vulkan_context().device()->createRenderPassUnique(render_pass_info);
+    ASSERT_EQ(vk::Result::eSuccess, result.result);
+    render_pass = std::move(result.value);
+  }
+  vk::UniqueImageView image_view;
+  {
+    vk::ImageSubresourceRange range;
+    range.aspectMask = vk::ImageAspectFlagBits::eColor;
+    range.layerCount = 1;
+    range.levelCount = 1;
+    vk::ImageViewCreateInfo info;
+    info.image = *image;
+    info.viewType = vk::ImageViewType::e2D;
+    info.format = static_cast<vk::Format>(kDefaultFormat);
+    info.subresourceRange = range;
+
+    auto result = vulkan_context().device()->createImageViewUnique(info);
+    ASSERT_EQ(vk::Result::eSuccess, result.result);
+    image_view = std::move(result.value);
+  }
+  vk::UniqueFramebuffer frame_buffer;
+  {
+    vk::FramebufferCreateInfo create_info;
+    create_info.renderPass = *render_pass;
+    create_info.attachmentCount = 1;
+    std::array<vk::ImageView, 1> attachments{*image_view};
+    create_info.setAttachments(attachments);
+    create_info.width = kDefaultWidth;
+    create_info.height = kDefaultHeight;
+    create_info.layers = 1;
+    auto result = vulkan_context().device()->createFramebufferUnique(create_info);
+    ASSERT_EQ(vk::Result::eSuccess, result.result);
+    frame_buffer = std::move(result.value);
+  }
+
+  // Clear everything but the first line (which should stay the same).
+  vk::RenderPassBeginInfo render_pass_info;
+  vk::ClearValue clear_color;
+  clear_color.color = std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f};
+  render_pass_info.renderPass = *render_pass;
+  render_pass_info.renderArea =
+      vk::Rect2D(vk::Offset2D(0, 1), vk::Extent2D(kDefaultWidth, kDefaultHeight - 1));
+  render_pass_info.clearValueCount = 1;
+  render_pass_info.pClearValues = &clear_color;
+  render_pass_info.framebuffer = *frame_buffer;
+
+  // Clears and stores the framebuffer.
+  command_buffers[0]->beginRenderPass(render_pass_info, vk::SubpassContents::eInline);
+  command_buffers[0]->endRenderPass();
+
+  {
+    auto range = vk::ImageSubresourceRange()
+                     .setAspectMask(vk::ImageAspectFlagBits::eColor)
+                     .setLevelCount(1)
+                     .setLayerCount(1);
+    auto barrier = vk::ImageMemoryBarrier()
+                       .setImage(image.get())
+                       .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
+                       .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead |
+                                         vk::AccessFlagBits::eColorAttachmentWrite)
+                       .setOldLayout(vk::ImageLayout::eColorAttachmentOptimal)
+                       .setNewLayout(vk::ImageLayout::eGeneral)
+                       .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_FOREIGN_EXT)
+                       .setSubresourceRange(range);
+    command_buffers[0]->pipelineBarrier(
+        vk::PipelineStageFlagBits::eColorAttachmentOutput, /* srcStageMask */
+        vk::PipelineStageFlagBits::eColorAttachmentOutput, /* dstStageMask */
+        vk::DependencyFlagBits::eByRegion, 0 /* memoryBarrierCount */,
+        nullptr /* pMemoryBarriers */, 0 /* bufferMemoryBarrierCount */,
+        nullptr /* pBufferMemoryBarriers */, 1 /* imageMemoryBarrierCount */, &barrier);
+  }
+
+  EXPECT_EQ(vk::Result::eSuccess, command_buffers[0]->end());
+
+  {
+    auto command_buffer_temp = command_buffers[0].get();
+    auto info = vk::SubmitInfo().setCommandBufferCount(1).setPCommandBuffers(&command_buffer_temp);
+    EXPECT_EQ(vk::Result::eSuccess, vulkan_context().queue().submit(1, &info, vk::Fence()));
+  }
+
+  EXPECT_EQ(vk::Result::eSuccess, vulkan_context().queue().waitIdle());
+
+  ASSERT_TRUE(sysmem_collection.settings.has_image_format_constraints);
+  {
+    void *addr;
+    vk::Result result = ctx_->device()->mapMemory(*memory, 0 /* offset */, VK_WHOLE_SIZE,
+                                                  vk::MemoryMapFlags{}, &addr);
+    ASSERT_EQ(vk::Result::eSuccess, result);
+
+    if (!src_is_coherent) {
+      auto range = vk::MappedMemoryRange().setMemory(*memory).setSize(VK_WHOLE_SIZE);
+      EXPECT_EQ(vk::Result::eSuccess, ctx_->device()->invalidateMappedMemoryRanges(1, &range));
+    }
+
+    uint32_t error_count = 0;
+    constexpr uint32_t kMaxErrors = 10;
+    bool skip = false;
+    for (size_t y = 0; (y < kDefaultHeight) && !skip; y++) {
+      for (size_t x = 0; (x < kDefaultWidth) && !skip; x++) {
+        size_t byte_offset =
+            GetImageByteOffset(x, y, sysmem_collection, kDefaultWidth, kDefaultHeight);
+        uint32_t *pixel_addr =
+            reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(addr) + byte_offset);
+        // The first line should keep the original pattern, but everything else should be filled to
+        // all 1s. If the row pitch is calculated incorrectly by the driver then it will write to
+        // the wrong bytes.
+        uint32_t fill = (y == 0) ? kPattern : 0xffffffff;
+        EXPECT_EQ(fill, *pixel_addr) << "byte_offset " << byte_offset << " x " << x << " y " << y;
+        if (*pixel_addr != fill) {
+          error_count++;
+          if (error_count > kMaxErrors) {
+            printf("Skipping reporting remaining errors\n");
+            skip = true;
+          }
+        }
+      }
+    }
+    ctx_->device()->unmapMemory(*memory);
+  }
+}
+
 }  // namespace
diff --git a/src/graphics/tests/vkext/vulkan_extension_test.cc b/src/graphics/tests/vkext/vulkan_extension_test.cc
index 10f756d..a6aca16 100644
--- a/src/graphics/tests/vkext/vulkan_extension_test.cc
+++ b/src/graphics/tests/vkext/vulkan_extension_test.cc
@@ -6,6 +6,8 @@
 
 #include <lib/fdio/directory.h>
 
+#include <cstddef>
+
 #include <fbl/algorithm.h>
 
 #include "src/graphics/tests/common/utils.h"
@@ -547,6 +549,33 @@
   ctx_->device()->unmapMemory(memory);
 }
 
+void VulkanExtensionTest::WriteLinearColorImageComplete(vk::DeviceMemory memory, vk::Image image,
+                                                        bool is_coherent, uint32_t width,
+                                                        uint32_t height, uint32_t fill) {
+  void *addr;
+  vk::Result result =
+      ctx_->device()->mapMemory(memory, 0 /* offset */, VK_WHOLE_SIZE, vk::MemoryMapFlags{}, &addr);
+  ASSERT_EQ(vk::Result::eSuccess, result);
+
+  auto layout = ctx_->device()->getImageSubresourceLayout(
+      image, vk::ImageSubresource(vk::ImageAspectFlagBits::eColor, 0, 0));
+
+  for (uint32_t y = 0; y < height; y++) {
+    for (uint32_t x = 0; x < width; x++) {
+      uint8_t *ptr =
+          static_cast<uint8_t *>(addr) + static_cast<size_t>(x * 4) + y * layout.rowPitch;
+      *reinterpret_cast<uint32_t *>(ptr) = fill;
+    }
+  }
+
+  if (!is_coherent) {
+    auto range = vk::MappedMemoryRange().setMemory(memory).setSize(VK_WHOLE_SIZE);
+    EXPECT_EQ(vk::Result::eSuccess, ctx_->device()->flushMappedMemoryRanges(1, &range));
+  }
+
+  ctx_->device()->unmapMemory(memory);
+}
+
 void VulkanExtensionTest::CheckLinearImage(vk::DeviceMemory memory, bool is_coherent,
                                            uint32_t width, uint32_t height, uint32_t fill) {
   void *addr;
diff --git a/src/graphics/tests/vkext/vulkan_extension_test.h b/src/graphics/tests/vkext/vulkan_extension_test.h
index b579d74..58ae114 100644
--- a/src/graphics/tests/vkext/vulkan_extension_test.h
+++ b/src/graphics/tests/vkext/vulkan_extension_test.h
@@ -43,6 +43,9 @@
   bool IsMemoryTypeCoherent(uint32_t memoryTypeIndex);
   void WriteLinearImage(vk::DeviceMemory memory, bool is_coherent, uint32_t width, uint32_t height,
                         uint32_t fill);
+  // Completely fill miplevel 0, array layer 0 of a 4 byte-per-pixel color image.
+  void WriteLinearColorImageComplete(vk::DeviceMemory memory, vk::Image image, bool is_coherent,
+                                     uint32_t width, uint32_t height, uint32_t fill);
   void CheckLinearImage(vk::DeviceMemory memory, bool is_coherent, uint32_t width, uint32_t height,
                         uint32_t fill);
 
diff --git a/src/lib/BUILD.gn b/src/lib/BUILD.gn
index 8f20cb1..44a999b 100644
--- a/src/lib/BUILD.gn
+++ b/src/lib/BUILD.gn
@@ -95,6 +95,7 @@
     "trace:tests",
     "transfer_manifest:tests",
     "trivial-allocator:tests",
+    "ubsan-custom:tests",
     "ui:tests",
     "unwinder:tests",
     "usb_bulk:tests",
diff --git a/src/lib/assembly/component_manager_config/src/compile.rs b/src/lib/assembly/component_manager_config/src/compile.rs
index 42ad7fe..fb47c56 100644
--- a/src/lib/assembly/component_manager_config/src/compile.rs
+++ b/src/lib/assembly/component_manager_config/src/compile.rs
@@ -812,14 +812,14 @@
                     {
                         source_moniker: "<component_manager>",
                         source: "component",
-                        source_name: "fuchsia.boot.RootResource",
+                        source_name: "fuchsia.kernel.MmioResource",
                         capability: "protocol",
                         target_monikers: ["/root", "/root/bootstrap", "/root/core"],
                     },
                 ],
                 debug_registration_policy: [
                     {
-                        name: "fuchsia.boot.RootResource",
+                        name: "fuchsia.kernel.MmioResource",
                         debug: "protocol",
                         moniker: "/foo",
                         environment_name: "my_env",
@@ -888,7 +888,7 @@
                     capability_policy: Some(component_internal::CapabilityPolicyAllowlists {
                         allowlist: Some(vec![component_internal::CapabilityAllowlistEntry {
                             source_moniker: Some("<component_manager>".to_string()),
-                            source_name: Some("fuchsia.boot.RootResource".to_string()),
+                            source_name: Some("fuchsia.kernel.MmioResource".to_string()),
                             source: Some(fdecl::Ref::Self_(fdecl::SelfRef {})),
                             capability: Some(component_internal::AllowlistedCapability::Protocol(
                                 component_internal::AllowlistedProtocol::default()
@@ -906,7 +906,7 @@
                         component_internal::DebugRegistrationPolicyAllowlists {
                             allowlist: Some(vec![
                                 component_internal::DebugRegistrationAllowlistEntry {
-                                    name: Some("fuchsia.boot.RootResource".to_string()),
+                                    name: Some("fuchsia.kernel.MmioResource".to_string()),
                                     debug: Some(
                                         component_internal::AllowlistedDebugRegistration::Protocol(
                                             component_internal::AllowlistedProtocol::default()
diff --git a/src/lib/assembly/components/src/components.rs b/src/lib/assembly/components/src/components.rs
index f436e69..8415cc7 100644
--- a/src/lib/assembly/components/src/components.rs
+++ b/src/lib/assembly/components/src/components.rs
@@ -59,6 +59,7 @@
         let args = vec![
             "compile".into(),
             "--features=allow_long_names".into(),
+            "--features=dictionaries".into(),
             "--includeroot".into(),
             include_path.as_ref().to_string(),
             "--includepath".into(),
@@ -126,6 +127,7 @@
                     "args": [
                         "compile",
                         "--features=allow_long_names",
+                        "--features=dictionaries",
                         "--includeroot",
                         "include/path",
                         "--includepath",
diff --git a/src/lib/assembly/config_schema/BUILD.gn b/src/lib/assembly/config_schema/BUILD.gn
index 41aaab4..31166f6 100644
--- a/src/lib/assembly/config_schema/BUILD.gn
+++ b/src/lib/assembly/config_schema/BUILD.gn
@@ -45,6 +45,8 @@
     "//third_party/rust_crates:serde_json",
   ]
 
+  test_deps = [ "//third_party/rust_crates:serde_json5" ]
+
   non_rust_deps = [ ":git_info_json" ]
 
   sources = [
@@ -54,6 +56,7 @@
     "src/developer_overrides.rs",
     "src/image_assembly_config.rs",
     "src/lib.rs",
+    "src/merge.rs",
     "src/platform_config.rs",
     "src/platform_config/battery_config.rs",
     "src/platform_config/bluetooth_config.rs",
diff --git a/src/lib/assembly/config_schema/src/assembly_config.rs b/src/lib/assembly/config_schema/src/assembly_config.rs
index 853764c..bd5e857 100644
--- a/src/lib/assembly/config_schema/src/assembly_config.rs
+++ b/src/lib/assembly/config_schema/src/assembly_config.rs
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 use crate::image_assembly_config::PartialKernelConfig;
+use crate::platform_config::PlatformConfig;
 use crate::PackageDetails;
 use assembly_package_utils::PackageInternalPathBuf;
 use assembly_util::{CompiledPackageDestination, FileEntry};
@@ -11,7 +12,6 @@
 use std::collections::{BTreeMap, BTreeSet};
 
 use crate::common::{DriverDetails, PackageName};
-use crate::platform_config::PlatformConfig;
 use crate::product_config::ProductConfig;
 
 /// Configuration for a Product Assembly operation.  This is a high-level operation
@@ -25,6 +25,20 @@
     pub product: ProductConfig,
 }
 
+/// Configuration for Product Assembly, when developer overrides are in use.
+///
+/// This deserializes to intermediate types that can be manipulated in order to
+/// apply developer overrides, before being parsed into the PlatformConfig
+/// and ProductConfig types.
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(deny_unknown_fields)]
+pub struct AssemblyConfigWrapperForOverrides {
+    // The platform config is deserialized as a Value before it is parsed into
+    // a 'PlatformConfig``
+    pub platform: serde_json::Value,
+    pub product: ProductConfig,
+}
+
 /// A typename to represent a package that contains shell command binaries,
 /// and the paths to those binaries
 pub type ShellCommands = BTreeMap<PackageName, BTreeSet<PackageInternalPathBuf>>;
@@ -150,6 +164,7 @@
 mod tests {
     use super::*;
     use crate::common::{FeatureControl, PackageSet};
+    use crate::platform_config::media_config::{AudioConfig, PlatformMediaConfig};
     use crate::platform_config::{BuildType, FeatureSupportLevel};
     use crate::product_config::ProductPackageDetails;
     use assembly_file_relative_path::FileRelativePathBuf;
@@ -168,8 +183,9 @@
 
         let mut cursor = std::io::Cursor::new(json5);
         let config: AssemblyConfig = util::from_reader(&mut cursor).unwrap();
-        assert_eq!(config.platform.build_type, BuildType::Eng);
-        assert_eq!(config.platform.feature_set_level, FeatureSupportLevel::Standard);
+        let platform = config.platform;
+        assert_eq!(platform.build_type, BuildType::Eng);
+        assert_eq!(platform.feature_set_level, FeatureSupportLevel::Standard);
     }
 
     #[test]
@@ -186,8 +202,9 @@
 
         let mut cursor = std::io::Cursor::new(json5);
         let config: AssemblyConfig = util::from_reader(&mut cursor).unwrap();
-        assert_eq!(config.platform.build_type, BuildType::Eng);
-        assert_eq!(config.platform.feature_set_level, FeatureSupportLevel::Bootstrap);
+        let platform = config.platform;
+        assert_eq!(platform.build_type, BuildType::Eng);
+        assert_eq!(platform.feature_set_level, FeatureSupportLevel::Bootstrap);
     }
 
     #[test]
@@ -203,8 +220,9 @@
 
         let mut cursor = std::io::Cursor::new(json5);
         let config: AssemblyConfig = util::from_reader(&mut cursor).unwrap();
-        assert_eq!(config.platform.build_type, BuildType::Eng);
-        assert_eq!(config.platform.feature_set_level, FeatureSupportLevel::Standard);
+        let platform = config.platform;
+        assert_eq!(platform.build_type, BuildType::Eng);
+        assert_eq!(platform.feature_set_level, FeatureSupportLevel::Standard);
     }
 
     #[test]
@@ -221,8 +239,9 @@
 
         let mut cursor = std::io::Cursor::new(json5);
         let config: AssemblyConfig = util::from_reader(&mut cursor).unwrap();
-        assert_eq!(config.platform.build_type, BuildType::Eng);
-        assert_eq!(config.platform.feature_set_level, FeatureSupportLevel::Empty);
+        let platform = config.platform;
+        assert_eq!(platform.build_type, BuildType::Eng);
+        assert_eq!(platform.feature_set_level, FeatureSupportLevel::Empty);
     }
 
     #[test]
@@ -238,7 +257,8 @@
 
         let mut cursor = std::io::Cursor::new(json5);
         let config: AssemblyConfig = util::from_reader(&mut cursor).unwrap();
-        assert_eq!(config.platform.build_type, BuildType::UserDebug);
+        let platform = config.platform;
+        assert_eq!(platform.build_type, BuildType::UserDebug);
     }
 
     #[test]
@@ -254,7 +274,8 @@
 
         let mut cursor = std::io::Cursor::new(json5);
         let config: AssemblyConfig = util::from_reader(&mut cursor).unwrap();
-        assert_eq!(config.platform.build_type, BuildType::User);
+        let platform = config.platform;
+        assert_eq!(platform.build_type, BuildType::User);
     }
 
     #[test]
@@ -288,7 +309,8 @@
 
         let mut cursor = std::io::Cursor::new(json5);
         let config: AssemblyConfig = util::from_reader(&mut cursor).unwrap();
-        assert_eq!(config.platform.build_type, BuildType::Eng);
+        let platform = config.platform;
+        assert_eq!(platform.build_type, BuildType::Eng);
         assert_eq!(
             config.product.packages.base,
             vec![ProductPackageDetails {
@@ -303,7 +325,7 @@
                 config_data: Vec::default()
             }]
         );
-        assert_eq!(config.platform.identity.password_pinweaver, FeatureControl::Allowed);
+        assert_eq!(platform.identity.password_pinweaver, FeatureControl::Allowed);
         assert_eq!(
             config.product.base_drivers,
             vec![DriverDetails {
@@ -437,4 +459,53 @@
             ])
         );
     }
+
+    #[test]
+    fn test_assembly_config_wrapper_for_overrides() {
+        let json5 = r#"
+        {
+          platform: {
+            build_type: "eng",
+          },
+          product: {},
+        }
+        "#;
+
+        let overrides = serde_json::json!({
+            "media": {
+                "audio": {
+                    "partial_stack": {}
+                }
+            }
+        });
+
+        let mut cursor = std::io::Cursor::new(json5);
+        let AssemblyConfigWrapperForOverrides { platform, product: _ } =
+            util::from_reader(&mut cursor).unwrap();
+
+        // serde_json and serde_json5 have an incompatible handling of how they
+        // serialize / deserialize enums.  So this test validates both the
+        // value merging method but also that the problematic enum syntax is
+        // correctly parsed when bounced through a string as it's done in the
+        // product assembly binary itself.
+
+        // 1. Merge to a 'value', not to the final type, as we need serde_json5
+        //    to do the parsing, not serde_json.
+        let merged_platform_value: serde_json::Value =
+            crate::try_merge_into(platform, overrides).unwrap();
+
+        // 2. Write the value out to a string, using pretty-printing so that
+        // line numbers and such are all sensical.
+        let merged_platform_string = serde_json::to_string_pretty(&merged_platform_value).unwrap();
+
+        // 3. Parse the string using serde_json5, so that enums are handled
+        //    consistently.
+        let merged_platform: PlatformConfig =
+            serde_json5::from_str(&merged_platform_string).unwrap();
+
+        assert_eq!(
+            merged_platform.media,
+            PlatformMediaConfig { audio: Some(AudioConfig::PartialStack), ..Default::default() },
+        );
+    }
 }
diff --git a/src/lib/assembly/config_schema/src/developer_overrides.rs b/src/lib/assembly/config_schema/src/developer_overrides.rs
index cd607c6..cd06209 100644
--- a/src/lib/assembly/config_schema/src/developer_overrides.rs
+++ b/src/lib/assembly/config_schema/src/developer_overrides.rs
@@ -25,6 +25,13 @@
     /// Using these will generate warnings.
     #[serde(default)]
     pub kernel: KernelOptions,
+
+    /// Developer overrides for the platform configuration.
+    ///
+    /// This is a 'Value' so that it can be be used to overlay the product's
+    /// platform configuration before that's parsed into it's real type.
+    #[serde(default)]
+    pub platform: serde_json::Value,
 }
 
 /// Special flags for assembly that can only be used in the context of developer
@@ -38,6 +45,7 @@
     /// This feature exists to enable the use of a product image that has cache
     /// or universe packages in a context where networking is unavailable or
     /// a package server cannot be run.
+    #[serde(default)]
     pub all_packages_in_base: bool,
 }
 
@@ -47,5 +55,6 @@
 #[serde(deny_unknown_fields)]
 pub struct KernelOptions {
     /// Additional kernel command line args to add to the assembled ZBI.
+    #[serde(default)]
     pub command_line_args: Vec<String>,
 }
diff --git a/src/lib/assembly/config_schema/src/image_assembly_config.rs b/src/lib/assembly/config_schema/src/image_assembly_config.rs
index 923087f..5d282eb 100644
--- a/src/lib/assembly/config_schema/src/image_assembly_config.rs
+++ b/src/lib/assembly/config_schema/src/image_assembly_config.rs
@@ -32,6 +32,12 @@
     #[serde(default)]
     pub cache: Vec<Utf8PathBuf>,
 
+    /// The packages that are in the on_demand package list, which is not part
+    /// of the image itself, but is to be published alongside those packages in
+    /// the image.
+    #[serde(default)]
+    pub on_demand: Vec<Utf8PathBuf>,
+
     /// The parameters that specify which kernel to put into the ZBI.
     pub kernel: KernelConfig,
 
@@ -71,6 +77,7 @@
             system: Vec::default(),
             base: Vec::default(),
             cache: Vec::default(),
+            on_demand: Vec::default(),
             boot_args: Vec::default(),
             bootfs_files: Vec::default(),
             bootfs_packages: Vec::default(),
@@ -145,6 +152,7 @@
               "system": ["package0"],
               "base": ["package1", "package2"],
               "cache": ["package3", "package4"],
+              "on_demand": ["package5", "package6"],
               "kernel": {
                 "path": "path/to/kernel",
                 "args": ["arg1", "arg2"],
diff --git a/src/lib/assembly/config_schema/src/lib.rs b/src/lib/assembly/config_schema/src/lib.rs
index 8dfea77..99accde 100644
--- a/src/lib/assembly/config_schema/src/lib.rs
+++ b/src/lib/assembly/config_schema/src/lib.rs
@@ -10,6 +10,7 @@
 pub mod common;
 pub mod developer_overrides;
 pub mod image_assembly_config;
+pub mod merge;
 pub mod platform_config;
 pub mod product_config;
 
@@ -19,6 +20,7 @@
     DriverDetails, FeatureControl, PackageDetails, PackageSet, PackagedDriverDetails,
 };
 pub use image_assembly_config::{BoardDriverArguments, ImageAssemblyConfig};
+pub use merge::try_merge_into;
 pub use platform_config::{
     example_config::ExampleConfig,
     icu_config::{ICUConfig, Revision},
diff --git a/src/lib/assembly/config_schema/src/merge.rs b/src/lib/assembly/config_schema/src/merge.rs
new file mode 100644
index 0000000..9722001
--- /dev/null
+++ b/src/lib/assembly/config_schema/src/merge.rs
@@ -0,0 +1,203 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use anyhow::Result;
+use serde::de::DeserializeOwned;
+use serde_json::Value;
+
+pub fn try_merge_into<T: DeserializeOwned>(base: Value, overrides: Value) -> Result<T> {
+    let merged = merge(base, overrides);
+    Ok(serde_json::from_value(merged)?)
+}
+
+fn merge(base: Value, value: Value) -> Value {
+    match (base, value) {
+        (base @ _, Value::Null) => {
+            // Override value is nothing, so nothing to do.
+            base
+        }
+        (Value::Object(mut merged), Value::Object(overrides)) => {
+            // Both are maps/dicts, so do a key-wise merging.
+            for (key, value) in overrides {
+                // Remove the existing value, so that it can be merged before re-inserting.
+                let existing = merged.remove(&key);
+                match existing {
+                    Some(existing) => {
+                        // If there's already a value, recursively merge the override value.
+                        merged.insert(key, merge(existing, value));
+                    }
+                    None => {
+                        // If there's not an existing value, just use the override value.
+                        merged.insert(key, value);
+                    }
+                }
+            }
+            Value::Object(merged)
+        }
+        (_, value) => {
+            // Either the override or the base value is a non-mergeable type,
+            // so just return the override value.
+            value
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use serde_json::json;
+
+    #[test]
+    fn test_both_null() {
+        let base = Value::Null;
+        let value = Value::Null;
+
+        assert_eq!(Value::Null, merge(base, value))
+    }
+
+    #[test]
+    fn test_null_override_is_no_op() {
+        let base = json!("a string");
+        assert_eq!("a string", merge(base, Value::Null));
+
+        let base = json!(1);
+        assert_eq!(1, merge(base, Value::Null));
+
+        let base = json!(true);
+        assert_eq!(true, merge(base, Value::Null));
+
+        let base = json!(["item1", "item2"]);
+        assert_eq!(json!(["item1", "item2"]), merge(base, Value::Null));
+    }
+
+    #[test]
+    fn test_null_base_is_overridden() {
+        let value = json!("a string");
+        assert_eq!("a string", merge(Value::Null, value));
+    }
+
+    #[test]
+    fn test_scalar_value_is_overriden_by_scalar() {
+        assert_eq!(json!("override"), merge(json!(42), json!("override")));
+        assert_eq!(json!(36), merge(json!(4), json!(36)));
+        assert_eq!(json!(42), merge(json!(false), json!(42)));
+        assert_eq!(json!(false), merge(json!(3), json!(false)));
+        assert_eq!(json!(["item1", "item2"]), merge(json!(39), json!(["item1", "item2"])));
+    }
+
+    #[test]
+    fn test_object_overrides_scalar_or_list() {
+        let value = json!({
+          "key": "value"
+        });
+
+        assert_eq!(value, merge(Value::Null, value.clone()));
+        assert_eq!(value, merge(json!(true), value.clone()));
+        assert_eq!(value, merge(json!(42), value.clone()));
+        assert_eq!(value, merge(json!("a string"), value.clone()));
+        assert_eq!(value, merge(json!(["item1", "item2"]), value.clone()));
+    }
+
+    #[test]
+    fn test_merged_keys() {
+        assert_eq!(
+            json!({
+              "base_key": "a string",
+              "added_key": "some value"
+            }),
+            merge(
+                json!({
+                  "base_key": "a string"
+                }),
+                json!({
+                  "added_key": "some value"
+                })
+            )
+        );
+    }
+
+    #[test]
+    fn test_merged_keys_adds_object() {
+        assert_eq!(
+            json!({
+              "base_key": "a string",
+              "added_key": {
+                "inner_key": "some value"
+              }
+            }),
+            merge(
+                json!({
+                  "base_key": "a string"
+                }),
+                json!({
+                  "added_key": {
+                    "inner_key": "some value"
+                  }
+                })
+            )
+        );
+    }
+
+    #[test]
+    fn test_merge_overrides_values() {
+        assert_eq!(
+            json!({
+              "key1": "key1 value",
+              "key2": "key2 new value"
+            }),
+            merge(
+                json!({
+                  "key1": "key1 value",
+                  "key2": "key2 value"
+                }),
+                json!({
+                  "key2": "key2 new value"
+                })
+            )
+        );
+    }
+
+    #[test]
+    fn test_merge_overrides_nested_value() {
+        assert_eq!(
+            json!({
+              "key1": "key1 value",
+              "key2": {
+                "inner1": "inner 1 value",
+                "inner2": "inner 2 new value"
+              }
+            }),
+            merge(
+                json!({
+                  "key1": "key1 value",
+                  "key2": {
+                    "inner1": "inner 1 value",
+                    "inner2": "inner 2 value"
+                  }
+                }),
+                json!({
+                  "key2": { "inner2": "inner 2 new value" }
+                })
+            )
+        );
+    }
+
+    #[test]
+    fn test_merge_adds_empty_objects() {
+        assert_eq!(
+            json!({
+              "key1": "key1 value",
+              "key2": {}
+            }),
+            merge(
+                json!({
+                  "key1": "key1 value"
+                }),
+                json!({
+                  "key2": {}
+                })
+            )
+        );
+    }
+}
diff --git a/src/lib/assembly/config_schema/src/platform_config/connectivity_config.rs b/src/lib/assembly/config_schema/src/platform_config/connectivity_config.rs
index f9b7da7..cdc7a13 100644
--- a/src/lib/assembly/config_schema/src/platform_config/connectivity_config.rs
+++ b/src/lib/assembly/config_schema/src/platform_config/connectivity_config.rs
@@ -41,9 +41,16 @@
     #[serde(default)]
     pub google_maps_api_key_path: Option<Utf8PathBuf>,
 
+    /// Controls how long the http client will wait when it is idle before it
+    /// escrows its FIDL connections back to the component framework and exits.
+    /// If the value is negative or left out, then the http client will not
+    /// stop after it idles.
+    #[serde(default)]
+    pub http_client_stop_on_idle_timeout_millis: Option<i64>,
+
     /// Controls whether the unified binary for networking should be used.
     ///
-    /// The unified binary provides space savings for space-constrainted
+    /// The unified binary provides space savings for space-constrained
     /// products, trading off multiple small binaries for one large binary that
     /// is smaller than the sum of its separate parts thanks to linking
     /// optimizations.
diff --git a/src/lib/assembly/config_schema/src/platform_config/kernel_config.rs b/src/lib/assembly/config_schema/src/platform_config/kernel_config.rs
index 5110e6e..4bd4958 100644
--- a/src/lib/assembly/config_schema/src/platform_config/kernel_config.rs
+++ b/src/lib/assembly/config_schema/src/platform_config/kernel_config.rs
@@ -12,4 +12,6 @@
     pub memory_compression: bool,
     #[serde(default)]
     pub lru_memory_compression: bool,
+    #[serde(default)]
+    pub continuous_eviction: bool,
 }
diff --git a/src/lib/assembly/config_schema/src/platform_config/setui_config.rs b/src/lib/assembly/config_schema/src/platform_config/setui_config.rs
index c5fed42..7d1b2d1 100644
--- a/src/lib/assembly/config_schema/src/platform_config/setui_config.rs
+++ b/src/lib/assembly/config_schema/src/platform_config/setui_config.rs
@@ -40,8 +40,5 @@
     pub interface: Option<Utf8PathBuf>,
 
     #[serde(default)]
-    pub light_sensor: Option<Utf8PathBuf>,
-
-    #[serde(default)]
     pub agent: Option<Utf8PathBuf>,
 }
diff --git a/src/lib/assembly/config_schema/src/platform_config/storage_config.rs b/src/lib/assembly/config_schema/src/platform_config/storage_config.rs
index 2b22f0b..3af8c5b 100644
--- a/src/lib/assembly/config_schema/src/platform_config/storage_config.rs
+++ b/src/lib/assembly/config_schema/src/platform_config/storage_config.rs
@@ -14,9 +14,6 @@
     pub live_usb_enabled: bool,
 
     #[serde(default)]
-    pub configure_fshost: bool,
-
-    #[serde(default)]
     pub component_id_index: ComponentIdIndexConfig,
 
     #[serde(default)]
diff --git a/src/lib/assembly/file_relative_path/src/macro.rs b/src/lib/assembly/file_relative_path/src/macro.rs
index 92acec4..cd58601 100644
--- a/src/lib/assembly/file_relative_path/src/macro.rs
+++ b/src/lib/assembly/file_relative_path/src/macro.rs
@@ -29,11 +29,12 @@
                 handle_struct_with_named_fields(fields, Operation::Resolve),
                 handle_struct_with_named_fields(fields, Operation::MakeFileRelative),
             ),
+            syn::Fields::Unnamed(fields) => (
+                handle_struct_with_unnamed_fields(fields, Operation::Resolve),
+                handle_struct_with_unnamed_fields(fields, Operation::MakeFileRelative),
+            ),
             // Unit structs just are themselves.
             syn::Fields::Unit => (quote! {Self}, quote! {Self}),
-            syn::Fields::Unnamed(_) => {
-                panic!("Structs with unnamed fields are not supported.");
-            }
         },
         syn::Data::Enum(data) => {
             (handle_enum(data, Operation::Resolve), handle_enum(data, Operation::MakeFileRelative))
@@ -84,6 +85,20 @@
     }
 }
 
+fn handle_struct_with_unnamed_fields(fields: &FieldsUnnamed, operation: Operation) -> TokenStream {
+    let indexes = get_field_indexes(fields);
+    let impls = handle_unnamed_fields(fields, operation);
+
+    quote! {
+      {
+        // destructure
+        let Self( #indexes ) = self;
+        // restructure with result of implementations
+        Self ( #impls )
+      }
+    }
+}
+
 fn handle_enum(data_enum: &DataEnum, operation: Operation) -> TokenStream {
     let variants = TokenStream::from_iter(data_enum.variants.iter().map(|variant| {
         let name = &variant.ident;
diff --git a/src/lib/assembly/file_relative_path/src/macro_test.rs b/src/lib/assembly/file_relative_path/src/macro_test.rs
index 686fb02..c5afebe 100644
--- a/src/lib/assembly/file_relative_path/src/macro_test.rs
+++ b/src/lib/assembly/file_relative_path/src/macro_test.rs
@@ -286,3 +286,34 @@
         }
     )
 }
+
+#[derive(SupportsFileRelativePaths, Debug, Deserialize, Serialize, PartialEq)]
+struct SimpleUnnamed(i64, FileRelativePathBuf);
+
+#[test]
+fn test_simple_unnamed() {
+    let json = serde_json::json!([42, "foo/file_3.txt"]);
+    let parsed: SimpleUnnamed = serde_json::from_value(json).unwrap();
+    let resolved = parsed.resolve_paths_from_file("some/file").unwrap();
+    assert_eq!(
+        resolved,
+        SimpleUnnamed(42, FileRelativePathBuf::Resolved("some/foo/file_3.txt".into()))
+    );
+}
+
+#[derive(SupportsFileRelativePaths, Debug, Deserialize, Serialize, PartialEq)]
+struct NestedUnnamed(i64, #[file_relative_paths] SimpleUnnamed);
+
+#[test]
+fn test_nested_unnamed() {
+    let json = serde_json::json!([42, [84, "bar/other.txt"]]);
+    let parsed: NestedUnnamed = serde_json::from_value(json).unwrap();
+    let resolved = parsed.resolve_paths_from_file("some/file").unwrap();
+    assert_eq!(
+        resolved,
+        NestedUnnamed(
+            42,
+            SimpleUnnamed(84, FileRelativePathBuf::Resolved("some/bar/other.txt".into()))
+        )
+    );
+}
diff --git a/src/lib/assembly/platform_configuration/src/subsystems.rs b/src/lib/assembly/platform_configuration/src/subsystems.rs
index 815ff19..8150d53 100644
--- a/src/lib/assembly/platform_configuration/src/subsystems.rs
+++ b/src/lib/assembly/platform_configuration/src/subsystems.rs
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 use anyhow::{bail, Context};
-use assembly_config_schema::{AssemblyConfig, BoardInformation, BuildType, ExampleConfig};
+use assembly_config_schema::platform_config::PlatformConfig;
+use assembly_config_schema::product_config::ProductConfig;
+use assembly_config_schema::{BoardInformation, BuildType, ExampleConfig};
 use camino::Utf8Path;
 
 use crate::common::{CompletedConfiguration, ConfigurationBuilderImpl};
@@ -67,24 +69,24 @@
 ///
 /// Returns a map from package names to configuration updates.
 pub fn define_configuration(
-    config: &AssemblyConfig,
+    platform: &PlatformConfig,
+    product: &ProductConfig,
     board_info: &BoardInformation,
     ramdisk_image: bool,
     gendir: impl AsRef<Utf8Path>,
     resource_dir: impl AsRef<Utf8Path>,
 ) -> anyhow::Result<CompletedConfiguration> {
-    let icu_config = &config.platform.icu;
+    let icu_config = &platform.icu;
     let mut builder = ConfigurationBuilderImpl::new(icu_config.clone());
 
     // The emulator support bundle is always added, even to an empty build.
     builder.platform_bundle("emulator_support");
 
-    let feature_set_level =
-        FeatureSupportLevel::from_deserialized(&config.platform.feature_set_level);
+    let feature_set_level = FeatureSupportLevel::from_deserialized(&platform.feature_set_level);
 
     // Only perform configuration if the feature_set_level is not None (ie, Empty).
     if let Some(feature_set_level) = &feature_set_level {
-        let build_type = &config.platform.build_type;
+        let build_type = &platform.build_type;
         let gendir = gendir.as_ref().to_path_buf();
         let resource_dir = resource_dir.as_ref().to_path_buf();
 
@@ -100,7 +102,7 @@
         };
 
         // Call the configuration functions for each subsystem.
-        configure_subsystems(&context, config, &mut builder)?;
+        configure_subsystems(&context, platform, product, &mut builder)?;
     }
 
     Ok(builder.build())
@@ -185,7 +187,8 @@
 
 fn configure_subsystems(
     context: &ConfigurationContext<'_>,
-    config: &AssemblyConfig,
+    platform: &PlatformConfig,
+    product: &ProductConfig,
     builder: &mut dyn ConfigurationBuilder,
 ) -> anyhow::Result<()> {
     // Define the common platform bundles for this platform configuration.
@@ -196,108 +199,92 @@
     if should_configure_example() {
         example::ExampleSubsystemConfig::define_configuration(
             context,
-            &config.platform.example_config,
+            &platform.example_config,
             builder,
         )?;
-    } else if config.platform.example_config != ExampleConfig::default() {
+    } else if platform.example_config != ExampleConfig::default() {
         bail!("Config options were set for the example subsystem, but the example is not enabled to be configured.");
     }
 
     // The real platform subsystems
 
-    battery::BatterySubsystemConfig::define_configuration(
-        context,
-        &config.platform.battery,
-        builder,
-    )
-    .context("Configuring the 'battery' subsystem")?;
+    battery::BatterySubsystemConfig::define_configuration(context, &platform.battery, builder)
+        .context("Configuring the 'battery' subsystem")?;
 
     bluetooth::BluetoothSubsystemConfig::define_configuration(
         context,
-        &config.platform.bluetooth,
+        &platform.bluetooth,
         builder,
     )
     .context("Configuring the `bluetooth` subsystem")?;
 
-    build_info::BuildInfoSubsystem::define_configuration(
-        context,
-        &config.product.build_info,
-        builder,
-    )
-    .context("Configuring the 'build_info' subsystem")?;
+    build_info::BuildInfoSubsystem::define_configuration(context, &product.build_info, builder)
+        .context("Configuring the 'build_info' subsystem")?;
 
     let component_config = component::ComponentConfig {
-        policy: &config.product.component_policy,
-        development_support: &config.platform.development_support,
-        starnix: &config.platform.starnix,
+        policy: &product.component_policy,
+        development_support: &platform.development_support,
+        starnix: &platform.starnix,
     };
     component::ComponentSubsystem::define_configuration(context, &component_config, builder)
         .context("Configuring the 'component' subsystem")?;
 
     connectivity::ConnectivitySubsystemConfig::define_configuration(
         context,
-        &config.platform.connectivity,
+        &platform.connectivity,
         builder,
     )
     .context("Configuring the 'connectivity' subsystem")?;
 
     development::DevelopmentConfig::define_configuration(
         context,
-        &config.platform.development_support,
+        &platform.development_support,
         builder,
     )
     .context("Configuring the 'development' subsystem")?;
 
     diagnostics::DiagnosticsSubsystem::define_configuration(
         context,
-        &config.platform.diagnostics,
+        &platform.diagnostics,
         builder,
     )
     .context("Configuring the 'diagnostics' subsystem")?;
 
     driver_framework::DriverFrameworkSubsystemConfig::define_configuration(
         context,
-        &config.platform.driver_framework,
+        &platform.driver_framework,
         builder,
     )
     .context("Configuring the 'driver_framework' subsystem")?;
 
-    graphics::GraphicsSubsystemConfig::define_configuration(
-        context,
-        &config.platform.graphics,
-        builder,
-    )
-    .context("Configuring the 'graphics' subsystem")?;
+    graphics::GraphicsSubsystemConfig::define_configuration(context, &platform.graphics, builder)
+        .context("Configuring the 'graphics' subsystem")?;
 
-    hwinfo::HwinfoSubsystem::define_configuration(context, &config.product.info, builder)
+    hwinfo::HwinfoSubsystem::define_configuration(context, &product.info, builder)
         .context("Configuring the 'hwinfo' subsystem")?;
 
-    icu::IcuSubsystem::define_configuration(context, &config.platform.icu, builder)
+    icu::IcuSubsystem::define_configuration(context, &platform.icu, builder)
         .context("Configuring the 'icu' subsystem")?;
 
-    identity::IdentitySubsystemConfig::define_configuration(
-        context,
-        &config.platform.identity,
-        builder,
-    )
-    .context("Configuring the 'identity' subsystem")?;
+    identity::IdentitySubsystemConfig::define_configuration(context, &platform.identity, builder)
+        .context("Configuring the 'identity' subsystem")?;
 
     input_groups::InputGroupsSubsystem::define_configuration(
         context,
-        &config.platform.input_groups,
+        &platform.input_groups,
         builder,
     )
     .context("Configuring the 'input_groups' subsystem")?;
 
-    media::MediaSubsystem::define_configuration(context, &config.platform.media, builder)
+    media::MediaSubsystem::define_configuration(context, &platform.media, builder)
         .context("Configuring the 'media' subsystem")?;
 
-    power::PowerManagementSubsystem::define_configuration(context, &config.platform.power, builder)
+    power::PowerManagementSubsystem::define_configuration(context, &platform.power, builder)
         .context("Configuring the 'power' subsystem")?;
 
     paravirtualization::ParavirtualizationSubsystem::define_configuration(
         context,
-        &config.platform.paravirtualization,
+        &platform.paravirtualization,
         builder,
     )
     .context("Configuring the 'paravirtualization' subsystem")?;
@@ -305,83 +292,63 @@
     radar::RadarSubsystemConfig::define_configuration(context, &(), builder)
         .context("Configuring the 'radar' subsystem")?;
 
-    recovery::RecoverySubsystem::define_configuration(context, &config.platform.recovery, builder)
+    recovery::RecoverySubsystem::define_configuration(context, &platform.recovery, builder)
         .context("Configuring the 'recovery' subsystem")?;
 
     rcs::RcsSubsystemConfig::define_configuration(context, &(), builder)
         .context("Configuring the 'rcs' subsystem")?;
 
-    sensors::SensorsSubsystemConfig::define_configuration(
-        context,
-        &config.platform.starnix,
-        builder,
-    )
-    .context("Configuring the 'sensors' subsystem")?;
+    sensors::SensorsSubsystemConfig::define_configuration(context, &platform.starnix, builder)
+        .context("Configuring the 'sensors' subsystem")?;
 
     session::SessionConfig::define_configuration(
         context,
-        &(&config.platform.session, &config.product.session_url),
+        &(&platform.session, &product.session_url),
         builder,
     )
     .context("Configuring the 'session' subsystem")?;
 
-    starnix::StarnixSubsystem::define_configuration(context, &config.platform.starnix, builder)
+    starnix::StarnixSubsystem::define_configuration(context, &platform.starnix, builder)
         .context("Configuring the starnix subsystem")?;
 
-    storage::StorageSubsystemConfig::define_configuration(
-        context,
-        &config.platform.storage,
-        builder,
-    )
-    .context("Configuring the 'storage' subsystem")?;
+    storage::StorageSubsystemConfig::define_configuration(context, &platform.storage, builder)
+        .context("Configuring the 'storage' subsystem")?;
 
-    swd::SwdSubsystemConfig::define_configuration(
-        context,
-        &config.platform.software_delivery,
-        builder,
-    )
-    .context("Configuring the 'software_delivery' subsystem")?;
+    swd::SwdSubsystemConfig::define_configuration(context, &platform.software_delivery, builder)
+        .context("Configuring the 'software_delivery' subsystem")?;
 
     thermal::ThermalSubsystem::define_configuration(context, &(), builder)
         .context("Configuring the 'thermal' subsystem")?;
 
-    ui::UiSubsystem::define_configuration(context, &config.platform.ui, builder)
+    ui::UiSubsystem::define_configuration(context, &platform.ui, builder)
         .context("Configuring the 'ui' subsystem")?;
 
     virtualization::VirtualizationSubsystem::define_configuration(
         context,
-        &config.platform.virtualization,
+        &platform.virtualization,
         builder,
     )
     .context("Configuring the 'virtualization' subsystem")?;
 
-    fonts::FontsSubsystem::define_configuration(context, &config.platform.fonts, builder)
+    fonts::FontsSubsystem::define_configuration(context, &platform.fonts, builder)
         .context("Configuring the 'fonts' subsystem")?;
 
-    intl::IntlSubsystem::define_configuration(context, &config.platform.intl, builder)
+    intl::IntlSubsystem::define_configuration(context, &platform.intl, builder)
         .context("Confguring the 'intl' subsystem")?;
 
-    setui::SetUiSubsystem::define_configuration(context, &config.platform.setui, builder)
+    setui::SetUiSubsystem::define_configuration(context, &platform.setui, builder)
         .context("Confguring the 'SetUI' subsystem")?;
 
-    kernel::KernelSubsystem::define_configuration(context, &config.platform.kernel, builder)
+    kernel::KernelSubsystem::define_configuration(context, &platform.kernel, builder)
         .context("Configuring the 'kernel' subsystem")?;
 
-    forensics::ForensicsSubsystem::define_configuration(
-        context,
-        &config.platform.forensics,
-        builder,
-    )
-    .context("Configuring the 'Forensics' subsystem")?;
+    forensics::ForensicsSubsystem::define_configuration(context, &platform.forensics, builder)
+        .context("Configuring the 'Forensics' subsystem")?;
 
-    timekeeper::TimekeeperSubsystem::define_configuration(
-        context,
-        &config.platform.timekeeper,
-        builder,
-    )
-    .context("Configuring the 'timekeeper' subsystem")?;
+    timekeeper::TimekeeperSubsystem::define_configuration(context, &platform.timekeeper, builder)
+        .context("Configuring the 'timekeeper' subsystem")?;
 
-    usb::UsbSubsystemConfig::define_configuration(context, &config.platform.usb, builder)
+    usb::UsbSubsystemConfig::define_configuration(context, &platform.usb, builder)
         .context("Configuring the 'usb' subsystem")?;
 
     Ok(())
@@ -396,6 +363,7 @@
 #[cfg(test)]
 mod tests {
     use super::*;
+    use assembly_config_schema::AssemblyConfig;
     use assembly_util as util;
 
     #[test]
@@ -413,8 +381,9 @@
         "#;
 
         let mut cursor = std::io::Cursor::new(json5);
-        let config: AssemblyConfig = util::from_reader(&mut cursor).unwrap();
-        let result = define_configuration(&config, &BoardInformation::default(), false, "", "");
+        let AssemblyConfig { platform, product } = util::from_reader(&mut cursor).unwrap();
+        let result =
+            define_configuration(&platform, &product, &BoardInformation::default(), false, "", "");
 
         assert!(result.is_err());
     }
diff --git a/src/lib/assembly/platform_configuration/src/subsystems/connectivity.rs b/src/lib/assembly/platform_configuration/src/subsystems/connectivity.rs
index 7fc054d..5118f25 100644
--- a/src/lib/assembly/platform_configuration/src/subsystems/connectivity.rs
+++ b/src/lib/assembly/platform_configuration/src/subsystems/connectivity.rs
@@ -127,6 +127,15 @@
                 })?;
             }
 
+            if let Some(timeout) =
+                connectivity_config.network.http_client_stop_on_idle_timeout_millis
+            {
+                builder.set_config_capability(
+                    "fuchsia.http-client.StopOnIdleTimeoutMillis",
+                    Config::new(ConfigValueType::Int64, timeout.into()),
+                )?;
+            }
+
             // The use of netstack3 can be forcibly required by the board,
             // otherwise it's selectable by the product.
             match (
diff --git a/src/lib/assembly/platform_configuration/src/subsystems/kernel.rs b/src/lib/assembly/platform_configuration/src/subsystems/kernel.rs
index fd9d6aa..0dd3d5c 100644
--- a/src/lib/assembly/platform_configuration/src/subsystems/kernel.rs
+++ b/src/lib/assembly/platform_configuration/src/subsystems/kernel.rs
@@ -22,6 +22,9 @@
         if kernel_config.lru_memory_compression {
             builder.platform_bundle("kernel_anonymous_memory_compression_eager_lru");
         }
+        if kernel_config.continuous_eviction {
+            builder.platform_bundle("kernel_evict_continuous");
+        }
 
         // If the board supports the PMM checker, and this is an eng build-type
         // build, enable the pmm checker.
diff --git a/src/lib/assembly/platform_configuration/src/subsystems/session.rs b/src/lib/assembly/platform_configuration/src/subsystems/session.rs
index 7f4d38c..4797beb 100644
--- a/src/lib/assembly/platform_configuration/src/subsystems/session.rs
+++ b/src/lib/assembly/platform_configuration/src/subsystems/session.rs
@@ -14,8 +14,7 @@
         config: &(&PlatformSessionConfig, &String),
         builder: &mut dyn ConfigurationBuilder,
     ) -> anyhow::Result<()> {
-        let session_config = config.0;
-        let session_url = config.1;
+        let (session_config, session_url) = *config;
 
         if session_config.enabled {
             ensure!(
diff --git a/src/lib/assembly/platform_configuration/src/subsystems/setui.rs b/src/lib/assembly/platform_configuration/src/subsystems/setui.rs
index 42a96db..16342df 100644
--- a/src/lib/assembly/platform_configuration/src/subsystems/setui.rs
+++ b/src/lib/assembly/platform_configuration/src/subsystems/setui.rs
@@ -42,13 +42,6 @@
                 })?;
             }
 
-            if let Some(light_sensor) = &config.light_sensor {
-                builder.package("setui_service").config_data(FileEntry {
-                    source: light_sensor.clone(),
-                    destination: "light_sensor_configuration.json".into(),
-                })?;
-            }
-
             if let Some(agent) = &config.agent {
                 builder.package("setui_service").config_data(FileEntry {
                     source: agent.clone(),
diff --git a/src/lib/assembly/platform_configuration/src/subsystems/storage.rs b/src/lib/assembly/platform_configuration/src/subsystems/storage.rs
index bc6b930..3bde92f 100644
--- a/src/lib/assembly/platform_configuration/src/subsystems/storage.rs
+++ b/src/lib/assembly/platform_configuration/src/subsystems/storage.rs
@@ -22,6 +22,11 @@
             builder.platform_bundle("live_usb");
         }
 
+        // Include legacy paver implementation if the board doesn't include it.
+        if !context.board_info.provides_feature("fuchsia::paver") {
+            builder.platform_bundle("paver_legacy");
+        }
+
         // Build and add the component id index.
         let mut index_builder = ComponentIdIndexBuilder::default();
 
@@ -73,109 +78,102 @@
             builder.platform_bundle("factory_data");
         }
 
-        if storage_config.configure_fshost {
-            // Collect the arguments from the board.
-            let blobfs_max_bytes =
-                context.board_info.filesystems.fvm.blobfs.maximum_bytes.unwrap_or(0);
-            let blobfs_initial_inodes =
-                context.board_info.filesystems.fvm.blobfs.minimum_inodes.unwrap_or(0);
-            let data_max_bytes =
-                context.board_info.filesystems.fvm.minfs.maximum_bytes.unwrap_or(0);
-            let fvm_slice_size = context.board_info.filesystems.fvm.slice_size.0;
-            let gpt_all = context.board_info.filesystems.gpt_all;
+        // Collect the arguments from the board.
+        let blobfs_max_bytes = context.board_info.filesystems.fvm.blobfs.maximum_bytes.unwrap_or(0);
+        let blobfs_initial_inodes =
+            context.board_info.filesystems.fvm.blobfs.minimum_inodes.unwrap_or(0);
+        let data_max_bytes = context.board_info.filesystems.fvm.minfs.maximum_bytes.unwrap_or(0);
+        let fvm_slice_size = context.board_info.filesystems.fvm.slice_size.0;
+        let gpt_all = context.board_info.filesystems.gpt_all;
 
-            // Collect the arguments from the product.
-            let ramdisk_image = context.ramdisk_image;
-            let no_zxcrypt = storage_config.filesystems.no_zxcrypt;
-            let format_data_on_corruption = storage_config.filesystems.format_data_on_corruption.0;
-            let nand = storage_config.filesystems.watch_for_nand;
+        // Collect the arguments from the product.
+        let ramdisk_image = context.ramdisk_image;
+        let no_zxcrypt = storage_config.filesystems.no_zxcrypt;
+        let format_data_on_corruption = storage_config.filesystems.format_data_on_corruption.0;
+        let nand = storage_config.filesystems.watch_for_nand;
 
-            // Prepare some default arguments that may get overriden by the product config.
-            let mut blob_deprecated_padded = false;
-            let mut use_disk_migration = false;
-            let mut data_filesystem_format_str = "fxfs";
-            let mut fxfs_blob = false;
-            let mut has_data = false;
+        // Prepare some default arguments that may get overridden by the product config.
+        let mut blob_deprecated_padded = false;
+        let mut use_disk_migration = false;
+        let mut data_filesystem_format_str = "fxfs";
+        let mut fxfs_blob = false;
+        let mut has_data = false;
 
-            // Add all the AIBs and collect some argument values.
-            builder.platform_bundle("fshost_common");
-            builder.platform_bundle("fshost_storage");
-            match &storage_config.filesystems.volume {
-                VolumeConfig::Fxfs => {
-                    builder.platform_bundle("fshost_fxfs");
-                    fxfs_blob = true;
+        // Add all the AIBs and collect some argument values.
+        builder.platform_bundle("fshost_common");
+        builder.platform_bundle("fshost_storage");
+        match &storage_config.filesystems.volume {
+            VolumeConfig::Fxfs => {
+                builder.platform_bundle("fshost_fxfs");
+                fxfs_blob = true;
+            }
+            VolumeConfig::Fvm(FvmVolumeConfig { blob, data, .. }) => {
+                if let Some(blob) = blob {
+                    builder.platform_bundle("fshost_fvm");
+                    blob_deprecated_padded = blob.blob_layout == BlobfsLayout::DeprecatedPadded;
                 }
-                VolumeConfig::Fvm(FvmVolumeConfig { blob, data, .. }) => {
-                    if let Some(blob) = blob {
-                        builder.platform_bundle("fshost_fvm");
-                        blob_deprecated_padded = blob.blob_layout == BlobfsLayout::DeprecatedPadded;
-                    }
-                    if let Some(DataFvmVolumeConfig {
-                        use_disk_based_minfs_migration,
-                        data_filesystem_format,
-                    }) = data
-                    {
-                        has_data = true;
-                        match data_filesystem_format {
-                            DataFilesystemFormat::Fxfs => {
-                                builder.platform_bundle("fshost_fvm_fxfs")
-                            }
-                            DataFilesystemFormat::F2fs => {
-                                data_filesystem_format_str = "f2fs";
-                                builder.platform_bundle("fshost_fvm_f2fs");
-                            }
-                            DataFilesystemFormat::Minfs => {
-                                data_filesystem_format_str = "minfs";
-                                if *use_disk_based_minfs_migration {
-                                    use_disk_migration = true;
-                                    builder.platform_bundle("fshost_fvm_minfs_migration");
-                                } else {
-                                    builder.platform_bundle("fshost_fvm_minfs");
-                                }
+                if let Some(DataFvmVolumeConfig {
+                    use_disk_based_minfs_migration,
+                    data_filesystem_format,
+                }) = data
+                {
+                    has_data = true;
+                    match data_filesystem_format {
+                        DataFilesystemFormat::Fxfs => builder.platform_bundle("fshost_fvm_fxfs"),
+                        DataFilesystemFormat::F2fs => {
+                            data_filesystem_format_str = "f2fs";
+                            builder.platform_bundle("fshost_fvm_f2fs");
+                        }
+                        DataFilesystemFormat::Minfs => {
+                            data_filesystem_format_str = "minfs";
+                            if *use_disk_based_minfs_migration {
+                                use_disk_migration = true;
+                                builder.platform_bundle("fshost_fvm_minfs_migration");
+                            } else {
+                                builder.platform_bundle("fshost_fvm_minfs");
                             }
                         }
                     }
                 }
             }
-
-            // Inform pkg-cache when fxfs_blob should be used.
-            builder
-                .package("pkg-cache")
-                .component("meta/pkg-cache.cm")?
-                .field("all_packages_executable", context.build_type == &BuildType::Eng)?
-                .field("use_fxblob", fxfs_blob)?
-                .field("use_system_image", true)?;
-
-            let mut fshost_config_builder =
-                builder.package("fshost").component("meta/fshost.cm")?;
-            fshost_config_builder
-                .field("blobfs", true)?
-                .field("blobfs_max_bytes", blobfs_max_bytes)?
-                .field("bootpart", true)?
-                .field("check_filesystems", true)?
-                .field("data", has_data)?
-                .field("data_max_bytes", data_max_bytes)?
-                .field("disable_block_watcher", false)?
-                .field("factory", false)?
-                .field("fvm", true)?
-                .field("ramdisk_image", ramdisk_image)?
-                .field("gpt", true)?
-                .field("gpt_all", gpt_all)?
-                .field("mbr", false)?
-                .field("netboot", false)?
-                .field("no_zxcrypt", no_zxcrypt)?
-                .field("format_data_on_corruption", format_data_on_corruption)?
-                .field("blobfs_initial_inodes", blobfs_initial_inodes)?
-                .field("blobfs_use_deprecated_padded_format", blob_deprecated_padded)?
-                .field("use_disk_migration", use_disk_migration)?
-                .field("nand", nand)?
-                .field("fxfs_blob", fxfs_blob)?
-                .field("fxfs_crypt_url", "fuchsia-boot:///fxfs-crypt#meta/fxfs-crypt.cm")?
-                .field("fvm_slice_size", fvm_slice_size)?;
-
-            fshost_config_builder.field("data_filesystem_format", data_filesystem_format_str)?;
         }
 
+        // Inform pkg-cache when fxfs_blob should be used.
+        builder
+            .package("pkg-cache")
+            .component("meta/pkg-cache.cm")?
+            .field("all_packages_executable", context.build_type == &BuildType::Eng)?
+            .field("use_fxblob", fxfs_blob)?
+            .field("use_system_image", true)?;
+
+        let mut fshost_config_builder = builder.package("fshost").component("meta/fshost.cm")?;
+        fshost_config_builder
+            .field("blobfs", true)?
+            .field("blobfs_max_bytes", blobfs_max_bytes)?
+            .field("bootpart", true)?
+            .field("check_filesystems", true)?
+            .field("data", has_data)?
+            .field("data_max_bytes", data_max_bytes)?
+            .field("disable_block_watcher", false)?
+            .field("factory", false)?
+            .field("fvm", true)?
+            .field("ramdisk_image", ramdisk_image)?
+            .field("gpt", true)?
+            .field("gpt_all", gpt_all)?
+            .field("mbr", false)?
+            .field("netboot", false)?
+            .field("no_zxcrypt", no_zxcrypt)?
+            .field("format_data_on_corruption", format_data_on_corruption)?
+            .field("blobfs_initial_inodes", blobfs_initial_inodes)?
+            .field("blobfs_use_deprecated_padded_format", blob_deprecated_padded)?
+            .field("use_disk_migration", use_disk_migration)?
+            .field("nand", nand)?
+            .field("fxfs_blob", fxfs_blob)?
+            .field("fxfs_crypt_url", "fuchsia-boot:///fxfs-crypt#meta/fxfs-crypt.cm")?
+            .field("fvm_slice_size", fvm_slice_size)?;
+
+        fshost_config_builder.field("data_filesystem_format", data_filesystem_format_str)?;
+
         Ok(())
     }
 }
diff --git a/src/lib/assembly/util/src/lib.rs b/src/lib/assembly/util/src/lib.rs
index cf973a1..dff22f8 100644
--- a/src/lib/assembly/util/src/lib.rs
+++ b/src/lib/assembly/util/src/lib.rs
@@ -57,7 +57,7 @@
         .with_context(|| format!("cannot serialize {}", json_path.display()))
 }
 
-/// Deserialize an instance of type T from an IO stream of JSON5.
+/// Deserialize an instance of type T from an IO stream of JSON or JSON5
 pub fn from_reader<R, T>(reader: &mut R) -> Result<T>
 where
     R: Read,
@@ -65,7 +65,21 @@
 {
     let mut data = String::default();
     reader.read_to_string(&mut data).context("Cannot read the config")?;
-    serde_json5::from_str(&data).context("Cannot parse the config")
+
+    // First parse the json5 to a `serde_json::Value`, which handles the syntax
+    // differences between json5 and json.
+    let value: serde_json::Value =
+        serde_json5::from_str(&data).context("Cannot parse the json5 config")?;
+
+    // Dump the Value into a JSON string.
+    let json = serde_json::to_string_pretty(&value)?;
+
+    // Re-parse using serde_json, which will throw errors when encountering
+    // maps when deserializing unit-type enum variants (serde_json5 doesn't do
+    // this).
+    // TODO: Remove this series of transformations after the following issue
+    // is fixed: https://github.com/google/serde_json5/issues/10
+    serde_json::from_str(&json).context("cannot parse the config using serde_json")
 }
 
 /// Helper fn to insert into an empty Option, or return an Error.
diff --git a/src/lib/async-utils/BUILD.gn b/src/lib/async-utils/BUILD.gn
index a496295..4cb536e 100644
--- a/src/lib/async-utils/BUILD.gn
+++ b/src/lib/async-utils/BUILD.gn
@@ -17,7 +17,6 @@
     "//third_party/rust_crates:futures",
     "//third_party/rust_crates:once_cell",
     "//third_party/rust_crates:pin-project",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:slab",
     "//third_party/rust_crates:thiserror",
   ]
diff --git a/src/lib/async-utils/src/stream.rs b/src/lib/async-utils/src/stream.rs
index 24f90f1..36f7ec5f7 100644
--- a/src/lib/async-utils/src/stream.rs
+++ b/src/lib/async-utils/src/stream.rs
@@ -19,7 +19,7 @@
         stream::{FusedStream, Stream},
         Future,
     },
-    pin_utils::unsafe_pinned,
+    pin_project::pin_project,
 };
 
 mod flatten_unordered;
@@ -131,22 +131,13 @@
 /// BUT the Tagged type combinator provides a statically nameable type that can easily be expressed
 /// in type signatures such as `IndexedStreams` below.
 #[cfg_attr(test, derive(Debug))]
+#[pin_project]
 pub struct Tagged<K, St> {
     tag: K,
+    #[pin]
     stream: St,
 }
 
-impl<K, St: Unpin> Unpin for Tagged<K, St> {}
-
-impl<K, St> Tagged<K, St> {
-    // It is safe to take a pinned projection to `stream` as:
-    // * Tagged does not implement `Drop`
-    // * Tagged only implements Unpin if `stream` is Unpin.
-    // * Tagged is not #[repr(packed)].
-    // see: pin_utils::unsafe_pinned docs for details
-    unsafe_pinned!(stream: St);
-}
-
 impl<K: Clone, St> Tagged<K, St> {
     /// Get a clone of the tag associated with this `Stream`.
     pub fn tag(&self) -> K {
@@ -171,7 +162,7 @@
 
     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
         let k = self.tag.clone();
-        match self.stream().poll(cx) {
+        match self.project().stream.poll(cx) {
             Poll::Ready(out) => Poll::Ready((k, out)),
             Poll::Pending => Poll::Pending,
         }
@@ -183,7 +174,7 @@
 
     fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
         let k = self.tag.clone();
-        match self.stream().poll_next(cx) {
+        match self.project().stream.poll_next(cx) {
             Poll::Ready(Some(item)) => Poll::Ready(Some((k, item))),
             Poll::Ready(None) => Poll::Ready(None),
             Poll::Pending => Poll::Pending,
diff --git a/src/lib/ddk/BUILD.bazel b/src/lib/ddk/BUILD.bazel
new file mode 100644
index 0000000..ee6f20d
--- /dev/null
+++ b/src/lib/ddk/BUILD.bazel
@@ -0,0 +1,22 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Library that exports the metadata.h file  to support the transition
+# to DFv2.
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+    name = "ddk_metadata",
+    hdrs = [
+        "include/lib/ddk/metadata.h",
+    ],
+    includes = [
+        "include",
+    ],
+    target_compatible_with = ["@platforms//os:fuchsia"],
+    deps = [
+        "@fuchsia_sdk//pkg/zbi-format",
+    ],
+)
diff --git a/src/lib/ddk/BUILD.gn b/src/lib/ddk/BUILD.gn
index 78cf654..2ab2fee 100644
--- a/src/lib/ddk/BUILD.gn
+++ b/src/lib/ddk/BUILD.gn
@@ -277,7 +277,6 @@
     "//src/devices/tests/ddk-firmware-test:*",
     "//src/devices/tests/ddk-lifecycle:*",
     "//src/devices/tests/ddk-metadata-test:*",
-    "//src/devices/tests/ddk-power:*",
     "//src/devices/tests/ddk-topology-test:*",
     "//src/devices/tests/device-watcher:*",
     "//src/devices/tests/driver-inspect-test:*",
diff --git a/src/lib/ddktl/BUILD.gn b/src/lib/ddktl/BUILD.gn
index 89998f8..05b4963 100644
--- a/src/lib/ddktl/BUILD.gn
+++ b/src/lib/ddktl/BUILD.gn
@@ -221,7 +221,6 @@
     "//src/devices/tests/ddk-firmware-test:*",
     "//src/devices/tests/ddk-lifecycle:*",
     "//src/devices/tests/ddk-metadata-test:*",
-    "//src/devices/tests/ddk-power:*",
     "//src/devices/tests/ddk-topology-test:*",
     "//src/devices/tests/device-watcher:*",
     "//src/devices/tests/driver-inspect-test:*",
diff --git a/src/lib/ddktl/include/ddktl/metadata/audio.h b/src/lib/ddktl/include/ddktl/metadata/audio.h
deleted file mode 100644
index 71f922d..0000000
--- a/src/lib/ddktl/include/ddktl/metadata/audio.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#ifndef SRC_LIB_DDKTL_INCLUDE_DDKTL_METADATA_AUDIO_H_
-#define SRC_LIB_DDKTL_INCLUDE_DDKTL_METADATA_AUDIO_H_
-
-#include <stdint.h>
-
-namespace metadata {
-
-static constexpr uint32_t kMaxNumberOfChannelsInRingBuffer = 64;
-static constexpr uint32_t kMaxNumberOfCodecs = 8;
-static constexpr uint32_t kMaxNumberOfExternalDelays = 8;
-
-enum class CodecType : uint32_t {
-  Tas27xx,
-  Tas5782,
-  Tas58xx,
-  Tas5720,
-  Tas5707,
-};
-
-// Same as //sdk/fidl/fuchsia.hardware.audio/dai_format.fidl
-enum class DaiType : uint32_t {
-  I2s,
-  StereoLeftJustified,
-  Tdm1,
-  Tdm2,
-  Tdm3,
-};
-
-enum class SampleFormat : uint32_t {
-  PcmSigned,  // Default for zeroed out metadata.
-  PcmUnsigned,
-  PcmFloat,
-};
-
-struct ExternalDelay {
-  uint32_t frequency;
-  int64_t nsecs;
-};
-
-struct FrequencyRange {
-  uint32_t min_frequency;
-  uint32_t max_frequency;
-};
-
-struct RingBuffer {
-  uint8_t number_of_channels;
-  uint8_t bytes_per_sample;  // If not specified (set to 0), then 2 bytes.
-  FrequencyRange frequency_ranges[kMaxNumberOfChannelsInRingBuffer];  // Optional.
-};
-
-struct Dai {
-  DaiType type;
-  uint8_t number_of_channels;  // If not specified (set to 0), then 2 for stereo types like I2S.
-  SampleFormat sample_format;  // Defaults to PcmSigned.
-  uint8_t bits_per_sample;     // If not specified (set to 0), then 16 bits.
-  uint8_t bits_per_slot;       // If not specified (set to 0), then 32 bits.
-  bool sclk_on_raising;        // Invert the usual clocking out on falling edge.
-};
-
-struct Codecs {
-  uint8_t number_of_codecs;
-  CodecType types[kMaxNumberOfCodecs];
-  float delta_gains[kMaxNumberOfCodecs];
-  uint32_t number_of_external_delays;
-  ExternalDelay external_delays[kMaxNumberOfExternalDelays];
-  // Channels to enable in each codec as a bitmask of the channels in the DAI.
-  // The least significant bit correspond to the left most channel in the DAI.
-  uint8_t channels_to_use_bitmask[kMaxNumberOfCodecs];
-  // Defines mapping between ring buffer channels and codecs using them.
-  // Used for stopping codecs corresponding to the ring buffer channels to use bitmask.
-  // Each ring buffer channel to use is represented as a bit, the least significant bit
-  // corresponds to index 0.
-  uint64_t ring_buffer_channels_to_use_bitmask[kMaxNumberOfCodecs];
-};
-
-}  // namespace metadata
-
-#endif  // SRC_LIB_DDKTL_INCLUDE_DDKTL_METADATA_AUDIO_H_
diff --git a/src/lib/diagnostics/inspect/contrib/rust/BUILD.gn b/src/lib/diagnostics/inspect/contrib/rust/BUILD.gn
index b2f120b..e049c1d 100644
--- a/src/lib/diagnostics/inspect/contrib/rust/BUILD.gn
+++ b/src/lib/diagnostics/inspect/contrib/rust/BUILD.gn
@@ -32,7 +32,6 @@
     "//src/lib/fuchsia-async",
     "//src/lib/test_util",
     "//third_party/rust_crates:assert_matches",
-    "//third_party/rust_crates:pin-utils",
   ]
 
   sources = [
diff --git a/src/lib/diagnostics/inspect/contrib/rust/src/auto_persist.rs b/src/lib/diagnostics/inspect/contrib/rust/src/auto_persist.rs
index 6b5d073..6fac131 100644
--- a/src/lib/diagnostics/inspect/contrib/rust/src/auto_persist.rs
+++ b/src/lib/diagnostics/inspect/contrib/rust/src/auto_persist.rs
@@ -158,9 +158,13 @@
 #[cfg(test)]
 mod tests {
     use {
-        super::*, fidl::endpoints::create_proxy_and_stream,
-        fidl_fuchsia_diagnostics_persist::DataPersistenceRequest, fuchsia_async as fasync,
-        fuchsia_inspect::Inspector, futures::task::Poll, pin_utils::pin_mut, std::cell::RefCell,
+        super::*,
+        fidl::endpoints::create_proxy_and_stream,
+        fidl_fuchsia_diagnostics_persist::DataPersistenceRequest,
+        fuchsia_async as fasync,
+        fuchsia_inspect::Inspector,
+        futures::task::Poll,
+        std::{cell::RefCell, pin::pin},
     };
 
     #[fuchsia::test]
@@ -191,7 +195,7 @@
                 .expect("creating persistence proxy and stream should succeed");
         let (mut req_sender, req_forwarder_fut) = create_persistence_req_sender(persistence_proxy);
 
-        pin_mut!(req_forwarder_fut);
+        let mut req_forwarder_fut = pin!(req_forwarder_fut);
 
         // Nothing has happened yet, so these futures should be Pending
         match exec.run_until_stalled(&mut req_forwarder_fut) {
diff --git a/src/lib/diagnostics/inspect/contrib/rust/src/nodes/list.rs b/src/lib/diagnostics/inspect/contrib/rust/src/nodes/list.rs
index c47b717..c31277a 100644
--- a/src/lib/diagnostics/inspect/contrib/rust/src/nodes/list.rs
+++ b/src/lib/diagnostics/inspect/contrib/rust/src/nodes/list.rs
@@ -30,6 +30,16 @@
         }
     }
 
+    /// Returns how many children are in the `BoundedListNode`.
+    pub fn len(&self) -> usize {
+        self.items.len()
+    }
+
+    /// Returns the capacity of the `BoundedListNode`, the maximum number of child nodes.
+    pub fn capacity(&self) -> usize {
+        self.capacity
+    }
+
     /// Create a new entry within a list and return a writer that creates properties or children
     /// for this entry. The writer does not have to be kept for the created properties and
     /// children to be maintained in the list.
@@ -74,9 +84,13 @@
         let inspector = Inspector::default();
         let list_node = inspector.root().create_child("list_node");
         let mut list_node = BoundedListNode::new(list_node, 3);
+        assert_eq!(list_node.capacity(), 3);
+        assert_eq!(list_node.len(), 0);
         let _ = list_node.add_entry(|_| {});
+        assert_eq!(list_node.len(), 1);
         assert_data_tree!(inspector, root: { list_node: { "0": {} } });
         let _ = list_node.add_entry(|_| {});
+        assert_eq!(list_node.len(), 2);
         assert_data_tree!(inspector, root: { list_node: { "0": {}, "1": {} } });
     }
 
@@ -90,12 +104,15 @@
         let _ = list_node.add_entry(|_| {});
 
         assert_data_tree!(inspector, root: { list_node: { "0": {}, "1": {}, "2": {} } });
+        assert_eq!(list_node.len(), 3);
 
         let _ = list_node.add_entry(|_| {});
         assert_data_tree!(inspector, root: { list_node: { "1": {}, "2": {}, "3": {} } });
+        assert_eq!(list_node.len(), 3);
 
         let _ = list_node.add_entry(|_| {});
         assert_data_tree!(inspector, root: { list_node: { "2": {}, "3": {}, "4": {} } });
+        assert_eq!(list_node.len(), 3);
     }
 
     #[fuchsia::test]
diff --git a/src/lib/diagnostics/inspect/contrib/self_profiles_report/tests/src/main.rs b/src/lib/diagnostics/inspect/contrib/self_profiles_report/tests/src/main.rs
index 4c669b9..75306c4 100644
--- a/src/lib/diagnostics/inspect/contrib/self_profiles_report/tests/src/main.rs
+++ b/src/lib/diagnostics/inspect/contrib/self_profiles_report/tests/src/main.rs
@@ -147,7 +147,7 @@
     );
 }
 
-const MARGIN_PERCENT: f64 = 5.0;
+const MARGIN_PERCENT: f64 = 6.1;
 
 #[track_caller]
 fn assert_approx_eq(lhs: i64, rhs: i64) {
diff --git a/src/lib/diagnostics/log/encoding/rust/BUILD.gn b/src/lib/diagnostics/log/encoding/rust/BUILD.gn
index 80f0990..5500215 100644
--- a/src/lib/diagnostics/log/encoding/rust/BUILD.gn
+++ b/src/lib/diagnostics/log/encoding/rust/BUILD.gn
@@ -37,6 +37,7 @@
 
   visibility = [
     "//src/diagnostics/archivist:*",
+    "//src/diagnostics/archivist/tests/integration/realm_factory/puppet:*",
     "//src/diagnostics/validator/logs/*",
     "//src/lib/diagnostics/log/*",
   ]
diff --git a/src/lib/diagnostics/log/rust/src/fuchsia/mod.rs b/src/lib/diagnostics/log/rust/src/fuchsia/mod.rs
index 0f331ac..0a91ed2 100644
--- a/src/lib/diagnostics/log/rust/src/fuchsia/mod.rs
+++ b/src/lib/diagnostics/log/rust/src/fuchsia/mod.rs
@@ -142,7 +142,7 @@
     }
 
     if opts.install_panic_hook {
-        crate::install_panic_hook();
+        crate::install_panic_hook(opts.panic_prefix);
     }
 
     Ok(publisher)
@@ -216,6 +216,7 @@
             },
         ingest_log_events,
         install_panic_hook,
+        panic_prefix,
     } = opts;
     let tags = tags.into_iter().map(|s| s.to_string()).collect::<Vec<_>>();
 
@@ -232,6 +233,7 @@
             },
             ingest_log_events,
             install_panic_hook,
+            panic_prefix,
         };
         let mut exec = fuchsia_async::LocalExecutor::new();
         let mut publisher = initialize_publishing(options).expect("initialize logging");
diff --git a/src/lib/diagnostics/log/rust/src/lib.rs b/src/lib/diagnostics/log/rust/src/lib.rs
index 91f7ca7c..f9f8b58 100644
--- a/src/lib/diagnostics/log/rust/src/lib.rs
+++ b/src/lib/diagnostics/log/rust/src/lib.rs
@@ -55,10 +55,11 @@
 }
 
 /// Adds a panic hook which will log an `ERROR` log with the panic information.
-pub(crate) fn install_panic_hook() {
+pub(crate) fn install_panic_hook(prefix: Option<&'static str>) {
     let previous_hook = std::panic::take_hook();
     std::panic::set_hook(Box::new(move |info| {
-        tracing::error!({ %info }, "PANIC");
+        let prefix = prefix.unwrap_or("PANIC");
+        tracing::error!({ %info }, "{prefix}");
         previous_hook(info);
     }));
 }
@@ -69,6 +70,7 @@
     pub(crate) publisher: PublisherOptions<'t>,
     pub(crate) ingest_log_events: bool,
     pub(crate) install_panic_hook: bool,
+    pub(crate) panic_prefix: Option<&'static str>,
 }
 
 impl<'t> Default for PublishOptions<'t> {
@@ -77,6 +79,7 @@
             publisher: PublisherOptions::default(),
             ingest_log_events: true,
             install_panic_hook: true,
+            panic_prefix: None,
         }
     }
 }
@@ -97,6 +100,12 @@
         self.ingest_log_events = enable;
         self
     }
+
+    /// Override the default string prefix for a logged panic message.
+    pub fn panic_prefix(mut self, prefix: &'static str) -> Self {
+        self.panic_prefix = Some(prefix);
+        self
+    }
 }
 
 macro_rules! publisher_options {
diff --git a/src/lib/diagnostics/log/rust/src/portable/mod.rs b/src/lib/diagnostics/log/rust/src/portable/mod.rs
index 7bdccbd..5c0feaa 100644
--- a/src/lib/diagnostics/log/rust/src/portable/mod.rs
+++ b/src/lib/diagnostics/log/rust/src/portable/mod.rs
@@ -60,7 +60,7 @@
             crate::ingest_log_events().expect("ingest log events");
         }
         if opts.install_panic_hook {
-            crate::install_panic_hook();
+            crate::install_panic_hook(opts.panic_prefix);
         }
     });
     Ok(())
diff --git a/src/lib/elfldltl/BUILD.gn b/src/lib/elfldltl/BUILD.gn
index b5f9281..a07732f 100644
--- a/src/lib/elfldltl/BUILD.gn
+++ b/src/lib/elfldltl/BUILD.gn
@@ -47,6 +47,7 @@
   headers = [
     "lib/elfldltl/abi-ptr.h",
     "lib/elfldltl/abi-span.h",
+    "lib/elfldltl/alloc-checker-container.h",
     "lib/elfldltl/compat-hash.h",
     "lib/elfldltl/constants.h",
     "lib/elfldltl/container.h",
diff --git a/src/lib/elfldltl/include/lib/elfldltl/alloc-checker-container.h b/src/lib/elfldltl/include/lib/elfldltl/alloc-checker-container.h
new file mode 100644
index 0000000..2f60200
--- /dev/null
+++ b/src/lib/elfldltl/include/lib/elfldltl/alloc-checker-container.h
@@ -0,0 +1,77 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_ALLOC_CHECKER_CONTAINER_H_
+#define SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_ALLOC_CHECKER_CONTAINER_H_
+
+#include <string_view>
+
+#include <fbl/alloc_checker.h>
+
+namespace elfldltl {
+
+// Similar to elfldltl::StdContainer (see container.h), except
+// AllocCheckerContainer leverages fbl::AllocChecker to check the allocations
+// performed by the underlying type method. The string_view error parameter
+// should contain a description of the allocation and is included in the
+// diagnostics error message. The boolean return value indicates allocation
+// success or failure. If allocation fails the Diagnostic's object's OutofMemory
+// error is called.
+template <template <typename, typename...> class C, typename... P>
+struct AllocCheckerContainer {
+  template <typename T>
+  class Container : public C<T, P...> {
+   public:
+    using Base = C<T, P...>;
+
+    using Base::Base;
+
+    constexpr Container(Container&&) noexcept = default;
+
+    constexpr Container& operator=(Container&&) noexcept = default;
+
+    template <class Diagnostics, typename U>
+    bool push_back(Diagnostics& diagnostics, std::string_view error, U&& value) {
+      fbl::AllocChecker ac;
+      Base::push_back(std::forward<U>(value), &ac);
+      if (!ac.check()) {
+        diagnostics.OutOfMemory(error, sizeof(U));
+        return false;
+      }
+      return true;
+    }
+
+    template <class Diagnostics, typename U>
+    bool insert(Diagnostics& diagnostics, std::string_view error, size_t index, U&& value) {
+      fbl::AllocChecker ac;
+      Base::insert(index, std::forward<U>(value), &ac);
+      if (!ac.check()) {
+        diagnostics.OutOfMemory(error, sizeof(U));
+        return false;
+      }
+      return true;
+    }
+
+    template <class Diagnostics>
+    bool reserve(Diagnostics& diagnostics, std::string_view error, size_t capacity) {
+      fbl::AllocChecker ac;
+      Base::reserve(capacity, &ac);
+      if (!ac.check()) {
+        diagnostics.OutOfMemory(error, capacity);
+        return false;
+      }
+      return true;
+    }
+
+   private:
+    // Make the original methods unavailable.
+    using Base::insert;
+    using Base::push_back;
+    using Base::reserve;
+  };
+};
+
+}  // namespace elfldltl
+
+#endif  // SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_ALLOC_CHECKER_CONTAINER_H_
diff --git a/src/lib/elfldltl/include/lib/elfldltl/container.h b/src/lib/elfldltl/include/lib/elfldltl/container.h
index 057fc4d..9b1c118 100644
--- a/src/lib/elfldltl/include/lib/elfldltl/container.h
+++ b/src/lib/elfldltl/include/lib/elfldltl/container.h
@@ -18,13 +18,11 @@
 // Container<T> types it needs.  These are used like normal containers, except
 // that the methods that can need to allocate (push_back, emplace_back,
 // emplace, and insert) take additional Diagnostics& and std::string_view
-// parameters first.  For an allocation failure, the Diagnostics object's
-// ResourceLimit<N> method will be called with the error string (the
-// std::string_view parameter).  The methods that usually return void
-// (push_back, emplace_back) instead return bool, with false indicating
-// allocation failure.  The methods that usually return an iterator (emplace,
-// insert) instead return std::optional<iterator>, with std::nullopt
-// indicating allocation failure.
+// parameters first.  This parameter is a requirement for the Container API, but
+// is not used by the StdContainer. The methods that usually return void
+// (push_back, emplace_back) instead return an std::true_type to always indicate
+// success. The methods that usually return an iterator (emplace, insert)
+// wraps the underlying method's return value with an std::optional<...>.
 
 namespace elfldltl {
 
diff --git a/src/lib/elfldltl/include/lib/elfldltl/diagnostics.h b/src/lib/elfldltl/include/lib/elfldltl/diagnostics.h
index ebd6acc..d6b1027 100644
--- a/src/lib/elfldltl/include/lib/elfldltl/diagnostics.h
+++ b/src/lib/elfldltl/include/lib/elfldltl/diagnostics.h
@@ -102,6 +102,12 @@
 //
 //    MissingDependency is used when a DT_NEEDED dependency cannot be found.
 //
+// * `bool OutOfMemory(std::string_view error, size_t bytes)`
+//
+//    OutofMemory is used when a memory allocation failure occurs. In contrast
+//    to a ResourceLimit error, an OutOfMemory error arises from memory pressure
+//    on the system instead of a exceeding a predefined fixed limit capacity.
+//
 // * `bool SystemError(std::string_view error, ...)`
 //
 //    SystemError is used when the system cannot fulfill an otherwise valid
@@ -303,6 +309,10 @@
     return SystemError("cannot open dependency: ", soname);
   }
 
+  constexpr bool OutOfMemory(std::string_view error, size_t bytes) {
+    return SystemError("cannot allocate ", bytes, " bytes for ", error);
+  }
+
  private:
   // This is either a wrapper around an integer, or is an empty object.
   // The tag is unused but makes the two Count types always distinct so
diff --git a/src/lib/elfldltl/include/lib/elfldltl/preallocated-vector.h b/src/lib/elfldltl/include/lib/elfldltl/preallocated-vector.h
index a5d731c..6656757 100644
--- a/src/lib/elfldltl/include/lib/elfldltl/preallocated-vector.h
+++ b/src/lib/elfldltl/include/lib/elfldltl/preallocated-vector.h
@@ -17,6 +17,12 @@
 // elfldltl::PreallocatedVector<T> wraps a previously allocated but
 // uninitialized span of T with a container interface that looks like a
 // std::vector but provides the container.h API for the allocating methods.
+// For an allocation failure, the Diagnostics object's ResourceLimit<N> method
+// will be called with the error string (the std::string_view parameter).  The
+// methods that usually return void (push_back, emplace_back) instead return
+// bool, with false indicating allocation failure.  The methods that usually
+// return an iterator (emplace, insert) instead return std::optional<iterator>,
+// with std::nullopt indicating allocation failure.
 //
 // This can be default-constructed (with zero capacity) and then move-assigned
 // from another object constructed with storage.  It's usually constructed via
diff --git a/src/lib/elfldltl/test/container-tests.cc b/src/lib/elfldltl/test/container-tests.cc
index bee368b..0ee4a6f 100644
--- a/src/lib/elfldltl/test/container-tests.cc
+++ b/src/lib/elfldltl/test/container-tests.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <lib/elfldltl/alloc-checker-container.h>
 #include <lib/elfldltl/container.h>
 #include <lib/elfldltl/diagnostics.h>
 #include <lib/elfldltl/preallocated-vector.h>
@@ -12,6 +13,7 @@
 #include <array>
 #include <string_view>
 
+#include <fbl/vector.h>
 #include <gtest/gtest.h>
 
 namespace {
@@ -411,4 +413,54 @@
   }
 }
 
+TEST(ElfldltlAllocCheckerContainerTests, Basic) {
+  std::vector<std::string> errors;
+  auto diag = elfldltl::CollectStringsDiagnostics(errors);
+
+  elfldltl::AllocCheckerContainer<fbl::Vector>::Container<int> list;
+
+  EXPECT_TRUE(list.push_back(diag, ""sv, 1));
+  EXPECT_TRUE(list.push_back(diag, ""sv, 3));
+
+  EXPECT_TRUE(list.insert(diag, ""sv, 1, 2));
+  EXPECT_TRUE(list.insert(diag, ""sv, 0, 0));
+
+  auto expected = {0, 1, 2, 3};
+  EXPECT_TRUE(std::equal(list.begin(), list.end(), expected.begin()));
+  EXPECT_EQ(diag.errors() + diag.warnings(), 0u);
+}
+
+class PartiallyFailingAllocatorTraits : public fbl::DefaultAllocatorTraits {
+ public:
+  static void* Allocate(size_t size) {
+    if (size <= failure_threshold_) {
+      return DefaultAllocatorTraits::Allocate(size);
+    }
+    return nullptr;
+  }
+
+  // Fail all allocations exceeding size "s".
+  static void SetFailureThreshold(size_t s) { failure_threshold_ = s; }
+
+ private:
+  static size_t failure_threshold_;
+};
+
+size_t PartiallyFailingAllocatorTraits::failure_threshold_;
+
+TEST(ElfldltlAllocCheckerContainerTests, FailedAllocation) {
+  std::vector<std::string> errors;
+  auto diag = elfldltl::CollectStringsDiagnostics(errors);
+
+  PartiallyFailingAllocatorTraits::SetFailureThreshold(1 * sizeof(int));
+  elfldltl::AllocCheckerContainer<fbl::Vector, PartiallyFailingAllocatorTraits>::Container<int>
+      list;
+  ASSERT_TRUE(list.reserve(diag, ""sv, 1));
+
+  EXPECT_TRUE(list.push_back(diag, ""sv, 1));
+
+  ExpectedSingleError error("cannot allocate ", 4, " bytes for ", "list");
+  list.push_back(error, "list"sv, 2);
+}
+
 }  // namespace
diff --git a/src/lib/elfldltl/test/diagnostics-tests.cc b/src/lib/elfldltl/test/diagnostics-tests.cc
index 81dd821..6dfd8f5c 100644
--- a/src/lib/elfldltl/test/diagnostics-tests.cc
+++ b/src/lib/elfldltl/test/diagnostics-tests.cc
@@ -230,4 +230,11 @@
   expected.FormatError("def ", 456);
 }
 
+TEST(ElfldltlDiagnosticsTests, OutOfMemory) {
+  {
+    ExpectedSingleError expected("cannot allocate ", 723, " bytes for ", "test");
+    expected.OutOfMemory("test", 723);
+  }
+}
+
 }  // namespace
diff --git a/src/lib/fidl/cpp/fidl_cpp_base_v2.api b/src/lib/fidl/cpp/fidl_cpp_base_v2.api
index 30b09a8..6a454c3e 100644
--- a/src/lib/fidl/cpp/fidl_cpp_base_v2.api
+++ b/src/lib/fidl/cpp/fidl_cpp_base_v2.api
@@ -1,10 +1,10 @@
 {
   "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/box.h": "6ad5fc22c8eb48d73cefcf81c2532acc",
-  "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/internal/framework_err.h": "812e82ef2b13a9f4c435f2b167e78aa3",
-  "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/internal/natural_types.h": "65c0c0acb97eea57d74c83dbd0fd7484",
-  "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/natural_coding_traits.h": "1d64c7a571692ee25f34547309dca48d",
+  "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/internal/framework_err.h": "79a471ea1bf92c7d8cdb8e180e0e2449",
+  "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/internal/natural_types.h": "f3df215fceca262945f42aaa556a1a78",
+  "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/natural_coding_traits.h": "9a533b94897107ed39d850e6a0ee426b",
   "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/natural_decoder.h": "9cc6513a73a84cf54fc653e601a63969",
   "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/natural_encoder.h": "e7bffd334fba11ca15d32af20844192e",
-  "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/natural_types.h": "de09a259d20fb6bc3f0127e176ac18ee",
+  "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/natural_types.h": "42474fe6e9170f70d22e2d7ed76cc736",
   "pkg/fidl_cpp_base_v2/include/lib/fidl/cpp/wire_natural_conversions.h": "4b15c8acfae77c92168e979ff7aa7e25"
 }
\ No newline at end of file
diff --git a/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/framework_err.h b/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/framework_err.h
index c603afa..52d143c 100644
--- a/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/framework_err.h
+++ b/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/framework_err.h
@@ -16,8 +16,8 @@
 template <>
 struct NaturalCodingTraits<::fidl::internal::FrameworkErr,
                            ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(int32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(int32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::fidl::internal::FrameworkErr* value,
                      size_t offset, size_t recursion_depth) {
diff --git a/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/natural_types.h b/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/natural_types.h
index a8dba6f..9ae010d 100644
--- a/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/natural_types.h
+++ b/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/natural_types.h
@@ -257,7 +257,7 @@
 
 template <typename T, size_t Size>
 struct NaturalStructCodingTraits {
-  static constexpr size_t inline_size_v2 = Size;
+  static constexpr size_t kInlineSize = Size;
   // True iff all fields are memcpy compatible.
   static constexpr bool are_members_memcpy_compatible =
       TupleVisitor::All(T::kMembers, [](auto member_info) {
@@ -266,11 +266,11 @@
         return NaturalIsMemcpyCompatible<Field, Constraint>();
       });
   // True iff fields are memcpy compatible and there is no padding.
-  static constexpr bool is_memcpy_compatible =
+  static constexpr bool kIsMemcpyCompatible =
       are_members_memcpy_compatible && std::tuple_size_v<decltype(T::kPadding)> == 0;
 
   static void Encode(NaturalEncoder* encoder, T* value, size_t offset, size_t recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(encoder->GetPtr<T>(offset), value, sizeof(T));
     } else {
       MemberVisitor<T>::Visit(value, [&](auto* member, auto& member_info) -> void {
@@ -282,7 +282,7 @@
   }
 
   static void Decode(NaturalDecoder* decoder, T* value, size_t offset, size_t recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(value, decoder->GetPtr<T>(offset), sizeof(T));
     } else {
       MemberVisitor<T>::Visit(value, [&](auto* member, auto& member_info) {
@@ -317,8 +317,8 @@
 
 template <typename T>
 struct NaturalEmptyStructCodingTraits {
-  static constexpr size_t inline_size_v2 = 1;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 1;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, T* value, size_t offset, size_t recursion_depth) {}
 
@@ -342,8 +342,8 @@
 
 template <typename T>
 struct NaturalTableCodingTraits {
-  static constexpr size_t inline_size_v2 = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   struct TableMemberVisitor : public MemberVisitor<T> {
     using Base = MemberVisitor<T>;
@@ -507,8 +507,8 @@
 
 template <typename T>
 struct NaturalUnionCodingTraits {
-  static constexpr size_t inline_size_v2 = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, T* value, size_t offset, size_t recursion_depth) {
     const size_t index = value->storage_->index();
diff --git a/src/lib/fidl/cpp/include/lib/fidl/cpp/natural_coding_traits.h b/src/lib/fidl/cpp/include/lib/fidl/cpp/natural_coding_traits.h
index 297c40c..2a3fed1 100644
--- a/src/lib/fidl/cpp/include/lib/fidl/cpp/natural_coding_traits.h
+++ b/src/lib/fidl/cpp/include/lib/fidl/cpp/natural_coding_traits.h
@@ -125,25 +125,25 @@
 template <typename T, typename Constraint>
 size_t NaturalEncodingInlineSize(NaturalEncoder* encoder) {
   ZX_DEBUG_ASSERT(encoder->wire_format() == ::fidl::internal::WireFormatVersion::kV2);
-  return NaturalCodingTraits<T, Constraint>::inline_size_v2;
+  return NaturalCodingTraits<T, Constraint>::kInlineSize;
 }
 
 template <typename T, typename Constraint>
 size_t NaturalDecodingInlineSize(NaturalDecoder* decoder) {
   ZX_DEBUG_ASSERT(decoder->wire_format() == ::fidl::internal::WireFormatVersion::kV2);
-  return NaturalCodingTraits<T, Constraint>::inline_size_v2;
+  return NaturalCodingTraits<T, Constraint>::kInlineSize;
 }
 
 template <typename T, typename Constraint>
 constexpr bool NaturalIsMemcpyCompatible() {
-  return NaturalCodingTraits<T, Constraint>::is_memcpy_compatible;
+  return NaturalCodingTraits<T, Constraint>::kIsMemcpyCompatible;
 }
 
 template <typename T>
 struct NaturalCodingTraits<T, NaturalCodingConstraintEmpty,
                            typename std::enable_if<IsPrimitive<T>::value>::type> {
-  static constexpr size_t inline_size_v2 = sizeof(T);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(T);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(NaturalEncoder* encoder, const T* value, size_t offset,
                      size_t recursion_depth) {
@@ -156,8 +156,8 @@
 
 template <>
 struct NaturalCodingTraits<bool, NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(bool);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(bool);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, const bool* value, size_t offset,
                      size_t recursion_depth) {
@@ -193,7 +193,7 @@
                              typename std::vector<T>::iterator in_begin,
                              typename std::vector<T>::iterator in_end, size_t out_offset,
                              size_t recursion_depth) {
-  static_assert(NaturalCodingTraits<T, Constraint>::inline_size_v2 == sizeof(T),
+  static_assert(NaturalCodingTraits<T, Constraint>::kInlineSize == sizeof(T),
                 "stride doesn't match object size");
   std::copy(in_begin, in_end, encoder->template GetPtr<T>(out_offset));
 }
@@ -214,7 +214,7 @@
 void NaturalDecodeVectorBody(NaturalUseStdCopy<true>, NaturalDecoder* decoder,
                              size_t in_begin_offset, size_t in_end_offset, std::vector<T>* out,
                              size_t count, size_t recursion_depth) {
-  static_assert(NaturalCodingTraits<T, Constraint>::inline_size_v2 == sizeof(T),
+  static_assert(NaturalCodingTraits<T, Constraint>::kInlineSize == sizeof(T),
                 "stride doesn't match object size");
   *out = std::vector<T>(decoder->template GetPtr<T>(in_begin_offset),
                         decoder->template GetPtr<T>(in_end_offset));
@@ -245,8 +245,8 @@
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<::std::vector<T>, Constraint> {
   using InnerConstraint = typename Constraint::Inner;
-  static constexpr size_t inline_size_v2 = sizeof(fidl_vector_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fidl_vector_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, ::std::vector<T>* value, size_t offset,
                      size_t recursion_depth) {
@@ -307,14 +307,14 @@
 
 template <typename T, size_t N, typename Constraint>
 struct NaturalCodingTraits<::std::array<T, N>, Constraint> {
-  static constexpr size_t inline_size_v2 = NaturalCodingTraits<T, Constraint>::inline_size_v2 * N;
-  static constexpr bool is_memcpy_compatible =
-      NaturalCodingTraits<T, Constraint>::is_memcpy_compatible;
+  static constexpr size_t kInlineSize = NaturalCodingTraits<T, Constraint>::kInlineSize * N;
+  static constexpr bool kIsMemcpyCompatible =
+      NaturalCodingTraits<T, Constraint>::kIsMemcpyCompatible;
 
   static void Encode(NaturalEncoder* encoder, std::array<T, N>* value, size_t offset,
                      size_t recursion_depth) {
     size_t stride = NaturalEncodingInlineSize<T, Constraint>(encoder);
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(encoder->template GetPtr<void>(offset), value->data(), N * stride);
     } else {
       for (size_t i = 0; i < N; ++i) {
@@ -326,7 +326,7 @@
   static void Decode(NaturalDecoder* decoder, std::array<T, N>* value, size_t offset,
                      size_t recursion_depth) {
     size_t stride = NaturalDecodingInlineSize<T, Constraint>(decoder);
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(value->data(), decoder->template GetPtr<void>(offset), N * stride);
     } else {
       for (size_t i = 0; i < N; ++i) {
@@ -341,8 +341,8 @@
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<
     T, Constraint, typename std::enable_if<std::is_base_of<zx::object_base, T>::value>::type> {
-  static constexpr size_t inline_size_v2 = sizeof(zx_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(zx_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, zx::object_base* value, size_t offset,
                      size_t recursion_depth) {
@@ -369,8 +369,8 @@
 
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<cpp17::optional<std::vector<T>>, Constraint> {
-  static constexpr size_t inline_size_v2 = sizeof(fidl_vector_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fidl_vector_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, cpp17::optional<std::vector<T>>* value, size_t offset,
                      size_t recursion_depth) {
@@ -413,8 +413,8 @@
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<fidl::Box<T>, Constraint,
                            typename std::enable_if<!IsUnion<T>::value>::type> {
-  static constexpr size_t inline_size_v2 = sizeof(uintptr_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uintptr_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, fidl::Box<T>* value, size_t offset,
                      size_t recursion_depth) {
@@ -458,8 +458,8 @@
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<fidl::Box<T>, Constraint,
                            typename std::enable_if<IsUnion<T>::value>::type> {
-  static constexpr size_t inline_size_v2 = sizeof(fidl_union_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fidl_union_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, fidl::Box<T>* value, size_t offset,
                      size_t recursion_depth) {
@@ -490,8 +490,8 @@
 
 template <typename Constraint>
 struct NaturalCodingTraits<::std::string, Constraint> final {
-  static constexpr size_t inline_size_v2 = sizeof(fidl_string_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fidl_string_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, std::string* value, size_t offset,
                      size_t recursion_depth) {
@@ -557,8 +557,8 @@
 
 template <typename Constraint>
 struct NaturalCodingTraits<cpp17::optional<std::string>, Constraint> {
-  static constexpr size_t inline_size_v2 = sizeof(fidl_string_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(fidl_string_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, cpp17::optional<std::string>* value, size_t offset,
                      size_t recursion_depth) {
@@ -601,9 +601,8 @@
 #ifdef __Fuchsia__
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<ClientEnd<T>, Constraint> {
-  static constexpr size_t inline_size_v1_no_ee = sizeof(zx_handle_t);
-  static constexpr size_t inline_size_v2 = sizeof(zx_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(zx_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, ClientEnd<T>* value, size_t offset,
                      size_t recursion_depth) {
@@ -630,9 +629,8 @@
 
 template <typename T, typename Constraint>
 struct NaturalCodingTraits<ServerEnd<T>, Constraint> {
-  static constexpr size_t inline_size_v1_no_ee = sizeof(zx_handle_t);
-  static constexpr size_t inline_size_v2 = sizeof(zx_handle_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(zx_handle_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(NaturalEncoder* encoder, ServerEnd<T>* value, size_t offset,
                      size_t recursion_depth) {
diff --git a/src/lib/fidl/cpp/include/lib/fidl/cpp/natural_types.h b/src/lib/fidl/cpp/include/lib/fidl/cpp/natural_types.h
index f9d12c7..de509f2 100644
--- a/src/lib/fidl/cpp/include/lib/fidl/cpp/natural_types.h
+++ b/src/lib/fidl/cpp/include/lib/fidl/cpp/natural_types.h
@@ -108,8 +108,7 @@
 // declaration only for natural types.
 template <typename FidlType>
 using EnableIfNaturalType = std::enable_if_t<static_cast<bool>(
-    internal::NaturalCodingTraits<FidlType,
-                                  internal::NaturalCodingConstraintEmpty>::inline_size_v2)>*;
+    internal::NaturalCodingTraits<FidlType, internal::NaturalCodingConstraintEmpty>::kInlineSize)>*;
 
 class NaturalEncodeResult final : public EncodeResult {
  public:
@@ -211,8 +210,7 @@
   FidlType value{internal::DefaultConstructPossiblyInvalidObjectTag{}};
 
   const size_t inline_size =
-      internal::NaturalCodingTraits<FidlType,
-                                    internal::NaturalCodingConstraintEmpty>::inline_size_v2;
+      internal::NaturalCodingTraits<FidlType, internal::NaturalCodingConstraintEmpty>::kInlineSize;
   const internal::NaturalTopLevelDecodeFn decode_fn =
       internal::MakeNaturalTopLevelDecodeFn<FidlType>();
   const Status status = internal::NaturalDecode(metadata, inline_size, decode_fn, message,
diff --git a/src/lib/fidl/llcpp/tests/conformance/conformance_utils.h b/src/lib/fidl/llcpp/tests/conformance/conformance_utils.h
index 61ffb8b..5eeb6048 100644
--- a/src/lib/fidl/llcpp/tests/conformance/conformance_utils.h
+++ b/src/lib/fidl/llcpp/tests/conformance/conformance_utils.h
@@ -58,15 +58,13 @@
                   << " expected=" << expected[i];
       } else {
         std::cout << std::dec << "element[" << i << "]: " << std::hex << "actual=0x" << +actual[i]
-                  << " "
-                  << "expected=0x" << +expected[i] << "\n";
+                  << " " << "expected=0x" << +expected[i] << "\n";
       }
     }
   }
   if (actual_size != expected_size) {
     pass = false;
-    std::cout << std::dec << "element[...]: "
-              << "actual.size=" << +actual_size << " "
+    std::cout << std::dec << "element[...]: " << "actual.size=" << +actual_size << " "
               << "expected.size=" << +expected_size << "\n";
   }
   return pass;
@@ -222,11 +220,6 @@
   return true;
 }
 
-constexpr inline uint64_t FidlAlign(uint32_t offset) {
-  constexpr uint64_t alignment_mask = FIDL_ALIGNMENT - 1;
-  return (offset + alignment_mask) & ~alignment_mask;
-}
-
 }  // namespace llcpp_conformance_utils
 
 #endif  // SRC_LIB_FIDL_LLCPP_TESTS_CONFORMANCE_CONFORMANCE_UTILS_H_
diff --git a/src/lib/fidl/llcpp/tests/transport/coding_test.cc b/src/lib/fidl/llcpp/tests/transport/coding_test.cc
index 0639f7b1..2d0a7f5 100644
--- a/src/lib/fidl/llcpp/tests/transport/coding_test.cc
+++ b/src/lib/fidl/llcpp/tests/transport/coding_test.cc
@@ -80,7 +80,7 @@
 template <bool IsRecursive>
 struct fidl::internal::WireCodingTraits<Input, fidl::internal::WireCodingConstraintEmpty,
                                         IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(fidl::internal::WireEncoder* encoder, Input* value, WirePosition position,
                      RecursionDepth<IsRecursive> recursion_depth) {
diff --git a/src/lib/fidl/llcpp/tests/transport/socket_integration_test.cc b/src/lib/fidl/llcpp/tests/transport/socket_integration_test.cc
index e605ed16..4607a8b 100644
--- a/src/lib/fidl/llcpp/tests/transport/socket_integration_test.cc
+++ b/src/lib/fidl/llcpp/tests/transport/socket_integration_test.cc
@@ -53,7 +53,7 @@
 template <bool IsRecursive>
 struct fidl::internal::WireCodingTraits<TwoWayRequest, fidl::internal::WireCodingConstraintEmpty,
                                         IsRecursive> {
-  static constexpr size_t inline_size = 24;
+  static constexpr size_t kInlineSize = 24;
 
   static void Encode(fidl::internal::WireEncoder* encoder, TwoWayRequest* value,
                      WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -83,7 +83,7 @@
 template <bool IsRecursive>
 struct fidl::internal::WireCodingTraits<TwoWayResponseBody,
                                         fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(fidl::internal::WireEncoder* encoder, TwoWayResponseBody* value,
                      fidl::internal::WirePosition position,
@@ -116,7 +116,7 @@
 template <bool IsRecursive>
 struct fidl::internal::WireCodingTraits<TwoWayResponse, fidl::internal::WireCodingConstraintEmpty,
                                         IsRecursive> {
-  static constexpr size_t inline_size = 24;
+  static constexpr size_t kInlineSize = 24;
 
   static void Encode(fidl::internal::WireEncoder* encoder, TwoWayResponse* value,
                      fidl::internal::WirePosition position,
diff --git a/src/lib/fidl/llcpp/tests/wire_types/README.md b/src/lib/fidl/llcpp/tests/wire_types/README.md
index d9d0195..460b6a5 100644
--- a/src/lib/fidl/llcpp/tests/wire_types/README.md
+++ b/src/lib/fidl/llcpp/tests/wire_types/README.md
@@ -1,8 +1,8 @@
 # Wire types tests
 
-These cover the construction and manipulation of LLCPP domain objects
-(wire types). Tests generally should not require running client/server bindings,
-such that they are more likely to work on both Fuchsia and host.
+These cover the construction and manipulation of C++ wire domain objects. Tests
+generally should not require running client/server bindings, such that they are
+more likely to work on both Fuchsia and host.
 
-See //src/lib/fidl/llcpp/tests/conformance for testing the
-encoding and decoding of these domain objects.
+See //src/lib/fidl/llcpp/tests/conformance for testing the encoding and decoding
+of these domain objects.
diff --git a/src/lib/fuchsia-async-macro/src/lib.rs b/src/lib/fuchsia-async-macro/src/lib.rs
index 1cec5ac..8597459 100644
--- a/src/lib/fuchsia-async-macro/src/lib.rs
+++ b/src/lib/fuchsia-async-macro/src/lib.rs
@@ -195,8 +195,7 @@
     } else {
         quote! {
             let mut #executor = ::fuchsia_async::TestExecutor::new();
-            let mut fut = func();
-            ::fuchsia_async::pin_mut!(fut);
+            let mut fut = ::std::pin::pin!(func());
             match #executor.run_until_stalled(&mut fut) {
                 ::core::task::Poll::Ready(result) => result,
                 _ => panic!("Stalled without completing. Consider using \"run_singlethreaded\", \
diff --git a/src/lib/fuchsia-async/BUILD.gn b/src/lib/fuchsia-async/BUILD.gn
index 927b67b..046993d 100644
--- a/src/lib/fuchsia-async/BUILD.gn
+++ b/src/lib/fuchsia-async/BUILD.gn
@@ -28,7 +28,7 @@
   deps = [
     "//src/lib/fuchsia-async-macro",
     "//third_party/rust_crates:futures",
-    "//third_party/rust_crates:pin-utils",
+    "//third_party/rust_crates:pin-project-lite",
   ]
   sources = [
     "src/atomic_future.rs",
diff --git a/src/lib/fuchsia-async/src/atomic_future.rs b/src/lib/fuchsia-async/src/atomic_future.rs
index bece4b7..4dd58f0 100644
--- a/src/lib/fuchsia-async/src/atomic_future.rs
+++ b/src/lib/fuchsia-async/src/atomic_future.rs
@@ -2,32 +2,103 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use futures::future::FutureObj;
-use futures::FutureExt;
-use std::cell::UnsafeCell;
-use std::mem::ManuallyDrop;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use std::task::Context;
+use {
+    futures::ready,
+    std::{
+        cell::UnsafeCell,
+        future::Future,
+        marker::PhantomData,
+        mem::ManuallyDrop,
+        pin::Pin,
+        sync::atomic::{
+            AtomicUsize,
+            Ordering::{Acquire, Relaxed, Release},
+        },
+        task::{Context, Poll},
+    },
+};
 
 /// A lock-free thread-safe future.
-pub struct AtomicFuture {
+// The debugger knows the layout so that async backtraces work, so if this changes the debugger
+// might need to be changed too.
+// LINT.IfChange
+pub struct AtomicFuture<'a> {
     // A bitfield (holds the bits INACTIVE, READY or DONE).
     state: AtomicUsize,
 
     // `future` is safe to access after successfully clearing the INACTIVE bit and the `DONE` bit
-    // isn't set.  The debugger knows the layout so that async backtraces work, so if this changes
-    // the debugger might need to be changed too.
+    // isn't set.
+    future: UnsafeCell<Box<dyn FutureOrResultAccess<'a>>>,
+}
+// LINT.ThenChange(//src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc)
+
+trait FutureOrResultAccess<'a>: 'a {
+    /// Drops the future.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure the future hasn't been dropped.
+    // zxdb uses this method to figure out the concrete type of the future and it currently assumes
+    // it is the first method in the trait.
     // LINT.IfChange
-    future: UnsafeCell<ManuallyDrop<FutureObj<'static, ()>>>,
+    unsafe fn drop_future(&mut self);
     // LINT.ThenChange(//src/developer/debug/zxdb/console/commands/verb_async_backtrace.cc)
+
+    /// Polls the future.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure the future hasn't been dropped.
+    unsafe fn poll(&mut self, cx: &mut Context<'_>) -> Poll<()>;
+
+    /// Gets the result.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure the future is finished and the result hasn't been taken or dropped.
+    unsafe fn get_result(&self) -> *const ();
+
+    /// Drops the result.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure the future is finished and the result hasn't already been taken or
+    /// dropped.
+    unsafe fn drop_result(&mut self);
+}
+
+union FutureOrResult<'a, F: 'a, R: 'a> {
+    future: ManuallyDrop<F>,
+    result: ManuallyDrop<R>,
+    lifetime: PhantomData<&'a ()>,
+}
+
+impl<'a, F: Future<Output = R> + 'a, R: 'a> FutureOrResultAccess<'a> for FutureOrResult<'a, F, R> {
+    unsafe fn poll(&mut self, cx: &mut Context<'_>) -> Poll<()> {
+        let result = ready!(Pin::new_unchecked(&mut *self.future).poll(cx));
+        // This might panic which will leave ourselves in a bad state.  We deal with this by
+        // aborting (see below).
+        ManuallyDrop::drop(&mut self.future);
+        self.result = ManuallyDrop::new(result);
+        Poll::Ready(())
+    }
+
+    unsafe fn drop_future(&mut self) {
+        ManuallyDrop::drop(&mut self.future);
+    }
+
+    unsafe fn get_result(&self) -> *const () {
+        &*self.result as *const R as *const ()
+    }
+
+    unsafe fn drop_result(&mut self) {
+        ManuallyDrop::drop(&mut self.result);
+    }
 }
 
 /// `AtomicFuture` is safe to access from multiple threads at once.
-unsafe impl Sync for AtomicFuture {}
-#[allow(dead_code)]
-trait AssertSend: Send {}
-impl AssertSend for AtomicFuture {}
+unsafe impl Sync for AtomicFuture<'_> {}
+unsafe impl Send for AtomicFuture<'_> {}
 
 /// State Bits
 
@@ -37,13 +108,22 @@
 // Set to indicate the future needs to be polled again.
 const READY: usize = 1 << 1;
 
-// Terminal state: the future is dropped upon entry to this state.  When in this state, the READY
-// bit can be set, but it has no meaning.
+// Terminal state: the future is dropped upon entry to this state.  When in this state, other bits
+// can be set, including READY (which has no meaning).
 const DONE: usize = 1 << 2;
 
+// The task has been detached.
+const DETACHED: usize = 1 << 3;
+
+// The task has been cancelled.
+const CANCELLED: usize = 1 << 4;
+
+// The result has been taken.
+const RESULT_TAKEN: usize = 1 << 5;
+
 /// The result of a call to `try_poll`.
 /// This indicates the result of attempting to `poll` the future.
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+#[derive(Debug)]
 pub enum AttemptPollResult {
     /// The future was being polled by another thread, but it was notified
     /// to poll at least once more before yielding.
@@ -58,14 +138,33 @@
     /// The future was polled, did not complete, but it is woken whilst it is polled so it
     /// should be polled again.
     Yield,
+    /// The future was cancelled.
+    Cancelled,
 }
 
-impl AtomicFuture {
+impl<'a> AtomicFuture<'a> {
     /// Create a new `AtomicFuture`.
-    pub fn new(future: FutureObj<'static, ()>) -> Self {
+    pub fn new<F: Future<Output = R> + Send + 'a, R: Send + 'a>(future: F, detached: bool) -> Self {
+        unsafe { Self::new_local(future, detached) }
+    }
+
+    /// Create a new `AtomicFuture` from a !Send future.
+    ///
+    /// # Safety
+    ///
+    /// The caller must uphold the Send requirements.
+    pub unsafe fn new_local<F: Future<Output = R> + 'a, R: 'a>(future: F, detached: bool) -> Self {
         AtomicFuture {
-            state: AtomicUsize::new(INACTIVE),
-            future: UnsafeCell::new(ManuallyDrop::new(future)),
+            state: AtomicUsize::new(
+                INACTIVE + {
+                    if detached {
+                        DETACHED
+                    } else {
+                        0
+                    }
+                },
+            ),
+            future: UnsafeCell::new(Box::new(FutureOrResult { future: ManuallyDrop::new(future) })),
         }
     }
 
@@ -84,7 +183,15 @@
                 return AttemptPollResult::SomeoneElseFinished;
             }
             if old & INACTIVE != 0 {
-                // We are now the (only) active worker. proceed to poll!
+                // We are now the (only) active worker, proceed to poll...
+                if old & CANCELLED != 0 {
+                    // The future was cancelled.
+                    // SAFETY: We have exclusive access.
+                    unsafe {
+                        self.drop_future_unchecked();
+                    }
+                    return AttemptPollResult::Cancelled;
+                }
                 break;
             }
             // Future was already active; this shouldn't really happen because we shouldn't be
@@ -101,20 +208,27 @@
             // the future won't be in a run queue.
         }
 
-        // This `UnsafeCell` access is valid because `self.future.get()` is only called here,
-        // inside the critical section where we performed the transition from INACTIVE to
-        // ACTIVE.
-        let future: &mut FutureObj<'static, ()> = unsafe { &mut *self.future.get() };
+        // We cannot recover from panics.
+        struct Bomb;
+        impl Drop for Bomb {
+            fn drop(&mut self) {
+                std::process::abort();
+            }
+        }
 
-        if future.poll_unpin(cx).is_ready() {
+        let bomb = Bomb;
+
+        // This `UnsafeCell` access is valid because `self.future.get()` is only called here, inside
+        // the critical section where we performed the transition from INACTIVE to ACTIVE.
+        let result = unsafe { (*self.future.get()).poll(cx) };
+
+        std::mem::forget(bomb);
+
+        if let Poll::Ready(()) = result {
+            // The future will have been dropped, so we just need to set the state.
+            self.state.fetch_or(DONE, Relaxed);
             // No one else will read `future` unless they see `INACTIVE`, which will never
             // happen again.
-
-            // SAFETY: We have exclusive access.
-            unsafe {
-                self.drop_future_unchecked();
-            }
-
             AttemptPollResult::IFinished
         } else if self.state.fetch_or(INACTIVE, Release) & READY == 0 {
             AttemptPollResult::Pending
@@ -126,8 +240,9 @@
 
     /// Marks the future as ready and returns true if it needs to be added to a run queue, i.e.
     /// it isn't already ready, active or done.
+    #[must_use]
     pub fn mark_ready(&self) -> bool {
-        self.state.fetch_or(READY, Relaxed) == INACTIVE
+        self.state.fetch_or(READY, Relaxed) & (INACTIVE | READY | DONE) == INACTIVE
     }
 
     /// Drops the future without checking its current state.
@@ -139,8 +254,8 @@
     /// the future.
     pub unsafe fn drop_future_unchecked(&self) {
         // Set the state first in case we panic when we drop.
-        self.state.store(DONE, Relaxed);
-        ManuallyDrop::drop(&mut *self.future.get());
+        assert!(self.state.fetch_or(DONE | RESULT_TAKEN, Relaxed) & DONE == 0);
+        (*self.future.get()).drop_future();
     }
 
     /// Drops the future if it is not currently being polled. Returns success if the future was
@@ -159,14 +274,51 @@
             Err(())
         }
     }
+
+    /// Cancels the task.  Returns true if the task needs to be added to a run queue.
+    #[must_use]
+    pub fn cancel(&self) -> bool {
+        self.state.fetch_or(CANCELLED | READY, Relaxed) & (INACTIVE | READY | DONE) == INACTIVE
+    }
+
+    /// Marks the task as detached.
+    pub fn detach(&self) {
+        self.state.fetch_or(DETACHED, Relaxed);
+    }
+
+    /// Returns true if the task is detached or cancelled.
+    pub fn is_detached_or_cancelled(&self) -> bool {
+        self.state.load(Relaxed) & (DETACHED | CANCELLED) != 0
+    }
+
+    /// Takes the result.
+    ///
+    /// # Safety
+    ///
+    /// The caller must guarantee that `R` is the correct type.
+    pub unsafe fn take_result<R>(&self) -> Option<R> {
+        if self.state.load(Relaxed) & (DONE | RESULT_TAKEN) == DONE
+            && self.state.fetch_or(RESULT_TAKEN, Relaxed) & RESULT_TAKEN == 0
+        {
+            Some(((*self.future.get()).get_result() as *const R).read())
+        } else {
+            None
+        }
+    }
 }
 
-impl Drop for AtomicFuture {
+impl Drop for AtomicFuture<'_> {
     fn drop(&mut self) {
-        if *self.state.get_mut() & DONE == 0 {
-            // SAFETY: The state isn't DONE so we must drop.
+        let state = *self.state.get_mut();
+        if state & DONE == 0 {
+            // SAFETY: The state isn't DONE so we must drop the future.
             unsafe {
-                ManuallyDrop::drop(self.future.get_mut());
+                (*self.future.get()).drop_future();
+            }
+        } else if state & RESULT_TAKEN == 0 {
+            // SAFETY: The result hasn't been taken so we must drop the result.
+            unsafe {
+                (*self.future.get()).drop_result();
             }
         }
     }
diff --git a/src/lib/fuchsia-async/src/handle/emulated/shutdown_test.rs b/src/lib/fuchsia-async/src/handle/emulated/shutdown_test.rs
index 4f939a5..0d782bf 100644
--- a/src/lib/fuchsia-async/src/handle/emulated/shutdown_test.rs
+++ b/src/lib/fuchsia-async/src/handle/emulated/shutdown_test.rs
@@ -2,10 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use fuchsia_async::emulated_handle::{shut_down_handles, Channel, MessageBuf};
-use fuchsia_zircon_status::Status;
-use std::future::Future;
-use std::task::{Context, Poll};
+use {
+    fuchsia_async::emulated_handle::{shut_down_handles, Channel, MessageBuf},
+    fuchsia_zircon_status::Status,
+    std::{
+        future::Future,
+        pin::pin,
+        task::{Context, Poll},
+    },
+};
 
 fn main() {
     let mut noop_ctx = Context::from_waker(futures::task::noop_waker_ref());
@@ -14,8 +19,7 @@
     a.write(&[1, 2, 3], &mut []).unwrap();
     std::mem::drop(a);
 
-    let fut = shut_down_handles();
-    futures::pin_mut!(fut);
+    let mut fut = pin!(shut_down_handles());
 
     assert_eq!(fut.as_mut().poll(&mut noop_ctx), Poll::Pending);
 
diff --git a/src/lib/fuchsia-async/src/handle/zircon/channel.rs b/src/lib/fuchsia-async/src/handle/zircon/channel.rs
index b1d303b..0b6cc88 100644
--- a/src/lib/fuchsia-async/src/handle/zircon/channel.rs
+++ b/src/lib/fuchsia-async/src/handle/zircon/channel.rs
@@ -201,7 +201,6 @@
     use crate::TestExecutor;
     use fuchsia_zircon::{self as zx};
     use futures::task::{waker, ArcWake};
-    use pin_utils::pin_mut;
     use std::{future::poll_fn, mem, pin::pin, sync::Arc};
 
     #[test]
@@ -212,12 +211,11 @@
         let (tx, rx) = zx::Channel::create();
         let f_rx = Channel::from_channel(rx);
 
-        let receiver = async move {
+        let mut receiver = pin!(async move {
             let mut buffer = MessageBuf::new();
             f_rx.recv_msg(&mut buffer).await.expect("failed to receive message");
             assert_eq!(bytes, buffer.bytes());
-        };
-        pin_mut!(receiver);
+        });
 
         assert!(exec.run_until_stalled(&mut receiver).is_pending());
 
@@ -235,12 +233,11 @@
         let (tx, rx) = zx::Channel::create();
         let f_rx = Channel::from_channel(rx);
 
-        let receiver = async move {
+        let mut receiver = pin!(async move {
             let mut buffer = MessageBufEtc::new();
             f_rx.recv_etc_msg(&mut buffer).await.expect("failed to receive message");
             assert_eq!(bytes, buffer.bytes());
-        };
-        pin_mut!(receiver);
+        });
 
         assert!(exec.run_until_stalled(&mut receiver).is_pending());
 
@@ -260,11 +257,10 @@
         mem::drop(f_rx0);
         let f_rx1 = Channel::from_channel(rx1);
         // f_rx0 and f_rx1 use the same key.
-        let receiver = async move {
+        let mut receiver = pin!(async move {
             let mut buffer = MessageBuf::new();
             f_rx1.recv_msg(&mut buffer).await.expect("failed to receive message");
-        };
-        pin_mut!(receiver);
+        });
 
         assert!(exec.run_until_stalled(&mut receiver).is_pending());
     }
@@ -279,11 +275,10 @@
         mem::drop(f_rx0);
         let f_rx1 = Channel::from_channel(rx1);
         // f_rx0 and f_rx1 use the same key.
-        let receiver = async move {
+        let mut receiver = pin!(async move {
             let mut buffer = MessageBufEtc::new();
             f_rx1.recv_etc_msg(&mut buffer).await.expect("failed to receive message");
-        };
-        pin_mut!(receiver);
+        });
 
         assert!(exec.run_until_stalled(&mut receiver).is_pending());
     }
diff --git a/src/lib/fuchsia-async/src/handle/zircon/rwhandle.rs b/src/lib/fuchsia-async/src/handle/zircon/rwhandle.rs
index dbbf997..971ba7b 100644
--- a/src/lib/fuchsia-async/src/handle/zircon/rwhandle.rs
+++ b/src/lib/fuchsia-async/src/handle/zircon/rwhandle.rs
@@ -8,13 +8,9 @@
         OnSignalsRef,
     },
     fuchsia_zircon::{self as zx, AsHandleRef},
-    futures::task::AtomicWaker,
     std::{
-        sync::{
-            atomic::{AtomicU32, Ordering},
-            Arc,
-        },
-        task::{ready, Context, Poll},
+        sync::{Arc, Mutex},
+        task::{ready, Context, Poll, Waker},
     },
 };
 
@@ -112,10 +108,12 @@
     fn need_writable(&self, cx: &mut Context<'_>) -> Poll<Result<(), zx::Status>>;
 }
 
-struct RWPacketReceiver {
-    signals: AtomicU32,
-    read_task: AtomicWaker,
-    write_task: AtomicWaker,
+struct RWPacketReceiver(Mutex<Inner>);
+
+struct Inner {
+    signals: zx::Signals,
+    read_task: Option<Waker>,
+    write_task: Option<Waker>,
 }
 
 impl PacketReceiver for RWPacketReceiver {
@@ -126,21 +124,34 @@
             return;
         };
 
-        let old =
-            zx::Signals::from_bits_truncate(self.signals.fetch_or(new.bits(), Ordering::SeqCst));
+        // We wake the tasks when the lock isn't held in case the wakers need the same lock.
+        let mut read_task = None;
+        let mut write_task = None;
+        {
+            let mut inner = self.0.lock().unwrap();
+            let old = inner.signals;
+            inner.signals |= new;
 
-        let became_readable = new.contains(OBJECT_READABLE) && !old.contains(OBJECT_READABLE);
-        let became_writable = new.contains(OBJECT_WRITABLE) && !old.contains(OBJECT_WRITABLE);
-        let became_closed = new.contains(OBJECT_PEER_CLOSED) && !old.contains(OBJECT_PEER_CLOSED);
+            let became_readable = new.contains(OBJECT_READABLE) && !old.contains(OBJECT_READABLE);
+            let became_writable = new.contains(OBJECT_WRITABLE) && !old.contains(OBJECT_WRITABLE);
+            let became_closed =
+                new.contains(OBJECT_PEER_CLOSED) && !old.contains(OBJECT_PEER_CLOSED);
 
+            if became_readable || became_closed {
+                read_task = inner.read_task.take();
+            }
+            if became_writable || became_closed {
+                write_task = inner.write_task.take();
+            }
+        }
         // *NOTE*: This is the only safe place to wake wakers.  In any other location, there is a
         // risk that locks are held which might be required when the waker is woken.  It is safe to
         // wake here because this is called from the executor when no locks are held.
-        if became_readable || became_closed {
-            self.read_task.wake();
+        if let Some(read_task) = read_task {
+            read_task.wake();
         }
-        if became_writable || became_closed {
-            self.write_task.wake();
+        if let Some(write_task) = write_task {
+            write_task.wake();
         }
     }
 }
@@ -165,17 +176,17 @@
         let ehandle = EHandle::local();
 
         let initial_signals = OBJECT_READABLE | OBJECT_WRITABLE;
-        let receiver = ehandle.register_receiver(Arc::new(RWPacketReceiver {
+        let receiver = ehandle.register_receiver(Arc::new(RWPacketReceiver(Mutex::new(Inner {
             // Optimistically assume that the handle is readable and writable.
             // Reads and writes will be attempted before queueing a packet.
             // This makes handles slightly faster to read/write the first time
             // they're accessed after being created, provided they start off as
             // readable or writable. In return, there will be an extra wasted
             // syscall per read/write if the handle is not readable or writable.
-            signals: AtomicU32::new(initial_signals.bits()),
-            read_task: AtomicWaker::new(),
-            write_task: AtomicWaker::new(),
-        }));
+            signals: initial_signals,
+            read_task: None,
+            write_task: None,
+        }))));
 
         RWHandle { handle, receiver }
     }
@@ -197,8 +208,7 @@
 
     /// Returns true if the object received the `OBJECT_PEER_CLOSED` signal.
     pub fn is_closed(&self) -> bool {
-        let signals =
-            zx::Signals::from_bits_truncate(self.receiver().signals.load(Ordering::Relaxed));
+        let signals = self.receiver().0.lock().unwrap().signals;
         if signals.contains(OBJECT_PEER_CLOSED) {
             return true;
         }
@@ -236,18 +246,34 @@
     fn need_signal(
         &self,
         cx: &mut Context<'_>,
-        task: &AtomicWaker,
+        for_read: bool,
         signal: zx::Signals,
     ) -> Poll<Result<(), zx::Status>> {
-        crate::runtime::need_signal_or_peer_closed(
-            cx,
-            task,
-            &self.receiver.signals,
-            signal,
-            self.handle.as_handle_ref(),
-            self.receiver.port(),
-            self.receiver.key(),
-        )
+        let mut inner = self.receiver.0.lock().unwrap();
+        let old = inner.signals;
+        if old.contains(zx::Signals::OBJECT_PEER_CLOSED) {
+            // We don't want to return an error here because even though the peer has closed, the
+            // object could still have queued messages that can be read.
+            Poll::Ready(Ok(()))
+        } else {
+            let waker = cx.waker().clone();
+            if for_read {
+                inner.read_task = Some(waker);
+            } else {
+                inner.write_task = Some(waker);
+            }
+            if old.contains(signal) {
+                inner.signals &= !signal;
+                std::mem::drop(inner);
+                self.handle.wait_async_handle(
+                    self.receiver.port(),
+                    self.receiver.key(),
+                    signal | zx::Signals::OBJECT_PEER_CLOSED,
+                    zx::WaitAsyncOpts::empty(),
+                )?;
+            }
+            Poll::Pending
+        }
     }
 }
 
@@ -257,21 +283,20 @@
 {
     fn poll_readable(&self, cx: &mut Context<'_>) -> Poll<Result<ReadableState, zx::Status>> {
         loop {
-            let signals =
-                zx::Signals::from_bits_truncate(self.receiver().signals.load(Ordering::SeqCst));
+            let signals = self.receiver().0.lock().unwrap().signals;
             match (signals.contains(OBJECT_READABLE), signals.contains(OBJECT_PEER_CLOSED)) {
                 (true, false) => return Poll::Ready(Ok(ReadableState::Readable)),
                 (false, true) => return Poll::Ready(Ok(ReadableState::Closed)),
                 (true, true) => return Poll::Ready(Ok(ReadableState::ReadableAndClosed)),
                 (false, false) => {
-                    ready!(self.need_signal(cx, &self.receiver.read_task, OBJECT_READABLE)?)
+                    ready!(self.need_signal(cx, true, OBJECT_READABLE)?)
                 }
             }
         }
     }
 
     fn need_readable(&self, cx: &mut Context<'_>) -> Poll<Result<(), zx::Status>> {
-        self.need_signal(cx, &self.receiver.read_task, OBJECT_READABLE)
+        self.need_signal(cx, true, OBJECT_READABLE)
     }
 }
 
@@ -281,20 +306,19 @@
 {
     fn poll_writable(&self, cx: &mut Context<'_>) -> Poll<Result<WritableState, zx::Status>> {
         loop {
-            let signals =
-                zx::Signals::from_bits_truncate(self.receiver().signals.load(Ordering::SeqCst));
+            let signals = self.receiver().0.lock().unwrap().signals;
             match (signals.contains(OBJECT_WRITABLE), signals.contains(OBJECT_PEER_CLOSED)) {
                 (_, true) => return Poll::Ready(Ok(WritableState::Closed)),
                 (true, _) => return Poll::Ready(Ok(WritableState::Writable)),
                 (false, false) => {
-                    ready!(self.need_signal(cx, &self.receiver.write_task, OBJECT_WRITABLE)?)
+                    ready!(self.need_signal(cx, false, OBJECT_WRITABLE)?)
                 }
             }
         }
     }
 
     fn need_writable(&self, cx: &mut Context<'_>) -> Poll<Result<(), zx::Status>> {
-        self.need_signal(cx, &self.receiver.write_task, OBJECT_WRITABLE)
+        self.need_signal(cx, false, OBJECT_WRITABLE)
     }
 }
 
diff --git a/src/lib/fuchsia-async/src/lib.rs b/src/lib/fuchsia-async/src/lib.rs
index 4b8b49f..2f5a44b 100644
--- a/src/lib/fuchsia-async/src/lib.rs
+++ b/src/lib/fuchsia-async/src/lib.rs
@@ -64,9 +64,6 @@
 /// A future which can be used by multiple threads at once.
 pub mod atomic_future;
 
-// Re-export pin_mut as its used by the async proc macros
-pub use pin_utils::pin_mut;
-
 pub use fuchsia_async_macro::{run, run_singlethreaded, run_until_stalled};
 
 /// Testing support for repeated runs
diff --git a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/common.rs b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/common.rs
index 021918b..9f65a7f 100644
--- a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/common.rs
+++ b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/common.rs
@@ -12,7 +12,6 @@
 use crossbeam::queue::SegQueue;
 use fuchsia_sync::Mutex;
 use fuchsia_zircon::{self as zx};
-use futures::future::{FutureObj, LocalFutureObj};
 use rustc_hash::FxHashMap as HashMap;
 use std::{
     any::Any,
@@ -23,7 +22,7 @@
     panic::Location,
     sync::atomic::{AtomicBool, AtomicI64, AtomicU16, AtomicU64, AtomicUsize, Ordering},
     sync::{Arc, Weak},
-    task::{Context, RawWaker, RawWakerVTable, Waker},
+    task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
     u64, usize,
 };
 
@@ -82,7 +81,7 @@
     is_local: bool,
     receivers: Mutex<PacketReceiverMap<Arc<dyn PacketReceiver>>>,
     task_count: AtomicUsize,
-    active_tasks: Mutex<HashMap<usize, Arc<Task>>>,
+    task_state: Mutex<TaskState>,
     pub(super) ready_tasks: SegQueue<Arc<Task>>,
     time: ExecutorTime,
     pub(super) collector: Collector,
@@ -97,6 +96,11 @@
     pub(super) owner_data: Mutex<Option<Box<dyn Any + Send>>>,
 }
 
+struct TaskState {
+    all_tasks: HashMap<usize, Arc<Task>>,
+    join_wakers: HashMap<usize, Waker>,
+}
+
 impl Inner {
     #[cfg_attr(trace_level_logging, track_caller)]
     pub fn new(time: ExecutorTime, is_local: bool, num_threads: u8) -> Self {
@@ -112,7 +116,10 @@
             is_local,
             receivers: Mutex::new(PacketReceiverMap::new()),
             task_count: AtomicUsize::new(MAIN_TASK_ID + 1),
-            active_tasks: Mutex::new(HashMap::default()),
+            task_state: Mutex::new(TaskState {
+                all_tasks: HashMap::default(),
+                join_wakers: HashMap::default(),
+            }),
             ready_tasks: SegQueue::new(),
             time,
             collector,
@@ -138,18 +145,15 @@
                 let Some(task) = self.ready_tasks.pop() else {
                     return PollReadyTasksResult::NoneReady;
                 };
-                let complete = task.try_poll();
+                let complete = self.try_poll(&task);
                 local_collector.task_polled(
                     task.id,
                     task.source(),
                     complete,
                     self.ready_tasks.len(),
                 );
-                if complete {
-                    self.active_tasks.lock().remove(&task.id);
-                    if task.id == MAIN_TASK_ID {
-                        return PollReadyTasksResult::MainTaskCompleted;
-                    }
+                if complete && task.id == MAIN_TASK_ID {
+                    return PollReadyTasksResult::MainTaskCompleted;
                 }
                 self.polled.fetch_add(1, Ordering::Relaxed);
             }
@@ -174,42 +178,44 @@
     }
 
     #[cfg_attr(trace_level_logging, track_caller)]
-    pub fn spawn(self: &Arc<Self>, future: FutureObj<'static, ()>) {
-        // Prevent a deadlock in `.active_tasks` when a task is spawned from a custom
+    pub fn spawn(self: &Arc<Self>, future: AtomicFuture<'static>) -> usize {
+        // Prevent a deadlock in `.all_tasks` when a task is spawned from a custom
         // Drop impl while the executor is being torn down.
         if self.done.load(Ordering::SeqCst) {
-            return;
+            return usize::MAX;
         }
         let next_id = self.task_count.fetch_add(1, Ordering::Relaxed);
         let task = Task::new(next_id, future, self.clone());
         self.collector.task_created(next_id, task.source());
-        self.active_tasks.lock().insert(next_id, task.clone());
+        self.task_state.lock().all_tasks.insert(next_id, task.clone());
         task.wake();
+        next_id
     }
 
     #[cfg_attr(trace_level_logging, track_caller)]
-    pub fn spawn_local(self: &Arc<Self>, future: LocalFutureObj<'static, ()>) {
+    pub fn spawn_local<F: Future<Output = R> + 'static, R: 'static>(
+        self: &Arc<Self>,
+        future: F,
+        detached: bool,
+    ) -> usize {
         if !self.is_local {
             panic!(
                 "Error: called `spawn_local` on multithreaded executor. \
-                Use `spawn` or a `LocalExecutor` instead."
+                 Use `spawn` or a `LocalExecutor` instead."
             );
         }
-        Inner::spawn(
-            self,
-            // SAFETY: We've confirmed that the boxed futures here will never be used
-            // across multiple threads, so we can safely convert from a non-`Send`able
-            // future to a `Send`able one.
-            unsafe { future.into_future_obj() },
-        );
+
+        // SAFETY: We've confirmed that the futures here will never be used across multiple threads,
+        // so the Send requirements that `new_local` requires should be met.
+        self.spawn(unsafe { AtomicFuture::new_local(future, detached) })
     }
 
     /// Spawns the main future.
-    pub fn spawn_main(self: &Arc<Self>, future: FutureObj<'static, ()>) {
+    pub fn spawn_main(self: &Arc<Self>, future: AtomicFuture<'static>) {
         let task = Task::new(MAIN_TASK_ID, future, self.clone());
         self.collector.task_created(MAIN_TASK_ID, task.source());
         assert!(
-            self.active_tasks.lock().insert(MAIN_TASK_ID, task.clone()).is_none(),
+            self.task_state.lock().all_tasks.insert(MAIN_TASK_ID, task.clone()).is_none(),
             "Existing main task"
         );
         task.wake();
@@ -381,7 +387,7 @@
     /// https://github.com/tokio-rs/tokio/blob/b42f21ec3e212ace25331d0c13889a45769e6006/tokio/src/io/driver/mod.rs#L297
     pub fn on_parent_drop(&self) {
         // Drop all tasks
-        let active_tasks = std::mem::take(&mut *self.active_tasks.lock());
+        let all_tasks = std::mem::take(&mut self.task_state.lock().all_tasks);
 
         // Any use of fasync::unblock can involve a waker. Wakers hold weak references to tasks, but
         // as part of waking, there's an upgrade to a strong reference, so for a small amount of
@@ -389,7 +395,7 @@
         // future for the task which in turn could hold references to receivers, which, if we did
         // nothing about it, would trip the assertion below. For that reason, we forcibly drop the
         // task futures here.
-        for (_, task) in active_tasks {
+        for (_, task) in all_tasks {
             task.future.try_drop().expect("Failed to drop task");
         }
 
@@ -547,7 +553,7 @@
     ///
     /// The caller must guarantee that the executor isn't running.
     pub(super) unsafe fn drop_main_task(&self) {
-        if let Some(task) = self.active_tasks.lock().remove(&MAIN_TASK_ID) {
+        if let Some(task) = self.task_state.lock().all_tasks.remove(&MAIN_TASK_ID) {
             // Even though we've removed the task from active tasks, it could still be in
             // pending_tasks, so we have to drop the future here. At time of writing, this is only
             // used by the local executor and there could only be something in ready_tasks if
@@ -555,6 +561,57 @@
             task.future.drop_future_unchecked();
         }
     }
+
+    /// Polls for a join result for the given task ID.
+    ///
+    /// # Safety
+    ///
+    /// The caller must guarantee that `R` is the correct type.
+    pub unsafe fn poll_join_result<R>(&self, task_id: usize, cx: &mut Context<'_>) -> Poll<R> {
+        let mut tasks = self.task_state.lock();
+        let Some(task) = tasks.all_tasks.get(&task_id) else { return Poll::Pending };
+        if let Some(result) = task.future.take_result() {
+            tasks.join_wakers.remove(&task_id);
+            tasks.all_tasks.remove(&task_id);
+            Poll::Ready(result)
+        } else {
+            tasks.join_wakers.insert(task_id, cx.waker().clone());
+            Poll::Pending
+        }
+    }
+
+    fn try_poll(&self, task: &Arc<Task>) -> bool {
+        // SAFETY: We meet the contract for RawWaker/RawWakerVtable.
+        let task_waker = unsafe {
+            Waker::from_raw(RawWaker::new(Arc::as_ptr(task) as *const (), &BORROWED_VTABLE))
+        };
+        match task.future.try_poll(&mut Context::from_waker(&task_waker)) {
+            AttemptPollResult::Yield => {
+                self.ready_tasks.push(task.clone());
+                false
+            }
+            AttemptPollResult::IFinished => {
+                let mut waker = None;
+                {
+                    let mut tasks = self.task_state.lock();
+                    if !task.future.is_detached_or_cancelled() {
+                        waker = tasks.join_wakers.remove(&task.id);
+                    } else if task.id != MAIN_TASK_ID {
+                        tasks.all_tasks.remove(&task.id);
+                    }
+                }
+                if let Some(waker) = waker {
+                    waker.wake();
+                }
+                true
+            }
+            AttemptPollResult::Cancelled => {
+                self.task_state.lock().all_tasks.remove(&task.id);
+                true
+            }
+            _ => false,
+        }
+    }
 }
 
 /// A handle to an executor.
@@ -620,13 +677,31 @@
         });
     }
 
+    /// See `Inner::spawn`.
+    #[cfg_attr(trace_level_logging, track_caller)]
+    pub(crate) fn spawn<R: Send + 'static>(
+        &self,
+        future: impl Future<Output = R> + Send + 'static,
+    ) -> usize {
+        self.inner.spawn(AtomicFuture::new(future, false))
+    }
+
     /// Spawn a new task to be run on this executor.
     ///
     /// Tasks spawned using this method must be thread-safe (implement the `Send` trait), as they
     /// may be run on either a singlethreaded or multithreaded executor.
     #[cfg_attr(trace_level_logging, track_caller)]
     pub fn spawn_detached(&self, future: impl Future<Output = ()> + Send + 'static) {
-        self.inner.spawn(FutureObj::new(Box::new(future)))
+        self.inner.spawn(AtomicFuture::new(future, true));
+    }
+
+    /// See `Inner::spawn_local`.
+    #[cfg_attr(trace_level_logging, track_caller)]
+    pub(crate) fn spawn_local<R: 'static>(
+        &self,
+        future: impl Future<Output = R> + 'static,
+    ) -> usize {
+        self.inner.spawn_local(future, false)
     }
 
     /// Spawn a new task to be run on this executor.
@@ -636,13 +711,47 @@
     /// this executor is a LocalExecutor.
     #[cfg_attr(trace_level_logging, track_caller)]
     pub fn spawn_local_detached(&self, future: impl Future<Output = ()> + 'static) {
-        self.inner.spawn_local(LocalFutureObj::new(Box::new(future)))
+        self.inner.spawn_local(future, true);
+    }
+
+    /// Marks the task as detached.
+    pub(crate) fn detach(&self, task_id: usize) {
+        let mut tasks = self.inner.task_state.lock();
+        if let Some(task) = tasks.all_tasks.get(&task_id) {
+            task.future.detach();
+        }
+        tasks.join_wakers.remove(&task_id);
+    }
+
+    /// Cancels the task.
+    ///
+    /// # Safety
+    ///
+    /// The caller must guarantee that `R` is the correct type.
+    pub(crate) unsafe fn cancel<R>(&self, task_id: usize) -> Option<R> {
+        let mut tasks = self.inner.task_state.lock();
+        tasks.join_wakers.remove(&task_id);
+        tasks.all_tasks.get(&task_id).and_then(|task| {
+            if task.future.cancel() {
+                self.inner.ready_tasks.push(task.clone());
+            }
+            task.future.take_result()
+        })
+    }
+
+    /// See `Inner::poll_join_result`.
+    pub(crate) unsafe fn poll_join_result<R>(
+        &self,
+        task_id: usize,
+        cx: &mut Context<'_>,
+    ) -> Poll<R> {
+        self.inner.poll_join_result(task_id, cx)
     }
 }
 
 pub(super) struct Task {
     id: usize,
-    future: AtomicFuture,
+    future: AtomicFuture<'static>,
     executor: Arc<Inner>,
     #[cfg(trace_level_logging)]
     source: &'static Location<'static>,
@@ -650,10 +759,10 @@
 
 impl Task {
     #[cfg_attr(trace_level_logging, track_caller)]
-    fn new(id: usize, future: FutureObj<'static, ()>, executor: Arc<Inner>) -> Arc<Self> {
+    fn new(id: usize, future: AtomicFuture<'static>, executor: Arc<Inner>) -> Arc<Self> {
         let this = Arc::new(Self {
             id,
-            future: AtomicFuture::new(future),
+            future,
             executor,
             #[cfg(trace_level_logging)]
             source: Location::caller(),
@@ -672,18 +781,6 @@
         }
     }
 
-    fn try_poll(self: &Arc<Self>) -> bool {
-        // SAFETY: We meet the contract for RawWaker/RawWakerVtable.
-        let task_waker = unsafe {
-            Waker::from_raw(RawWaker::new(Arc::as_ptr(self) as *const (), &BORROWED_VTABLE))
-        };
-        let result = self.future.try_poll(&mut Context::from_waker(&task_waker));
-        if result == AttemptPollResult::Yield {
-            self.executor.ready_tasks.push(self.clone());
-        }
-        result == AttemptPollResult::IFinished
-    }
-
     fn source(&self) -> Option<&'static Location<'static>> {
         #[cfg(trace_level_logging)]
         {
@@ -743,3 +840,108 @@
         Weak::from_raw(weak_raw as *const Task);
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use {
+        crate::{LocalExecutor, Task},
+        std::{
+            future::poll_fn,
+            sync::{
+                atomic::{AtomicU32, Ordering},
+                Arc,
+            },
+            task::Poll,
+        },
+    };
+
+    async fn yield_to_executor() {
+        let mut done = false;
+        poll_fn(|cx| {
+            if done {
+                Poll::Ready(())
+            } else {
+                done = true;
+                cx.waker().wake_by_ref();
+                Poll::Pending
+            }
+        })
+        .await;
+    }
+
+    #[test]
+    fn test_detach() {
+        let mut e = LocalExecutor::new();
+        e.run_singlethreaded(async {
+            let counter = Arc::new(AtomicU32::new(0));
+
+            {
+                let counter = counter.clone();
+                Task::spawn(async move {
+                    for _ in 0..5 {
+                        yield_to_executor().await;
+                        counter.fetch_add(1, Ordering::Relaxed);
+                    }
+                })
+                .detach();
+            }
+
+            while counter.load(Ordering::Relaxed) != 5 {
+                yield_to_executor().await;
+            }
+        });
+
+        assert!(e.ehandle.inner.task_state.lock().join_wakers.is_empty());
+    }
+
+    #[test]
+    fn test_cancel() {
+        let mut e = LocalExecutor::new();
+        e.run_singlethreaded(async {
+            let ref_count = Arc::new(());
+            // First, just drop the task.
+            {
+                let ref_count = ref_count.clone();
+                let _ = Task::spawn(async move {
+                    let _ref_count = ref_count;
+                    let _: () = std::future::pending().await;
+                });
+            }
+
+            while Arc::strong_count(&ref_count) != 1 {
+                yield_to_executor().await;
+            }
+
+            // Now try explicitly cancelling.
+            let task = {
+                let ref_count = ref_count.clone();
+                Task::spawn(async move {
+                    let _ref_count = ref_count;
+                    let _: () = std::future::pending().await;
+                })
+            };
+
+            assert_eq!(task.cancel(), None);
+            while Arc::strong_count(&ref_count) != 1 {
+                yield_to_executor().await;
+            }
+
+            // Now cancel a task that has already finished.
+            let task = {
+                let ref_count = ref_count.clone();
+                Task::spawn(async move {
+                    let _ref_count = ref_count;
+                })
+            };
+
+            // Wait for it to finish.
+            while Arc::strong_count(&ref_count) != 1 {
+                yield_to_executor().await;
+            }
+
+            assert_eq!(task.cancel(), Some(()));
+        });
+
+        assert!(e.ehandle.inner.task_state.lock().join_wakers.is_empty());
+    }
+}
diff --git a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/instrumentation.rs b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/instrumentation.rs
index 5daa861..b1789b7 100644
--- a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/instrumentation.rs
+++ b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/instrumentation.rs
@@ -198,13 +198,16 @@
 
 #[cfg(test)]
 mod tests {
-    use fuchsia_zircon::{self as zx, DurationNum};
-    use futures::future;
-    use pin_utils::pin_mut;
-
-    use super::*;
-    use crate::runtime::fuchsia::executor::Time;
-    use crate::{handle::channel::Channel, LocalExecutor, SendExecutor, TestExecutor, Timer};
+    use {
+        super::*,
+        crate::{
+            handle::channel::Channel, runtime::fuchsia::executor::Time, LocalExecutor,
+            SendExecutor, TestExecutor, Timer,
+        },
+        fuchsia_zircon::{self as zx, DurationNum},
+        futures::future,
+        std::pin::pin,
+    };
 
     const MICROSECOND: std::time::Duration = std::time::Duration::from_micros(1);
     use std::thread::sleep;
@@ -428,8 +431,7 @@
     #[test]
     fn instrumentation_until_stalled_smoke_test() {
         let mut executor = TestExecutor::new_with_fake_time();
-        let fut = simple_task_for_snapshot();
-        pin_mut!(fut);
+        let mut fut = pin!(simple_task_for_snapshot());
         assert!(executor.run_until_stalled(&mut fut).is_ready());
         let snapshot = executor.snapshot();
         snapshot_sanity_check(&snapshot);
diff --git a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/local.rs b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/local.rs
index abf5ef8..8680d7a8 100644
--- a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/local.rs
+++ b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/local.rs
@@ -4,18 +4,18 @@
 
 use super::super::timer::TimerHeap;
 use super::{
-    common::{with_local_timer_heap, EHandle, ExecutorTime, Inner},
+    common::{with_local_timer_heap, EHandle, ExecutorTime, Inner, MAIN_TASK_ID},
     time::Time,
 };
+use crate::atomic_future::AtomicFuture;
 use futures::{
     future::{self, Either},
-    task::{AtomicWaker, FutureObj, LocalFutureObj},
-    FutureExt,
+    task::AtomicWaker,
 };
-use pin_utils::pin_mut;
 use std::{
     fmt,
     future::{poll_fn, Future},
+    pin::pin,
     sync::{
         atomic::{AtomicBool, AtomicI64, Ordering},
         Arc,
@@ -34,12 +34,12 @@
 /// other words, zircon objects backed by a `LocalExecutor` must be dropped before it.
 pub struct LocalExecutor {
     /// The inner executor state.
-    inner: Arc<Inner>,
+    pub(crate) ehandle: EHandle,
 }
 
 impl fmt::Debug for LocalExecutor {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("LocalExecutor").field("port", &self.inner.port).finish()
+        f.debug_struct("LocalExecutor").field("port", &self.ehandle.inner.port).finish()
     }
 }
 
@@ -52,7 +52,7 @@
             /* num_threads */ 1,
         ));
         inner.clone().set_local(TimerHeap::default());
-        Self { inner }
+        Self { ehandle: EHandle { inner } }
     }
 
     /// Run a single future to completion on a single thread, also polling other active tasks.
@@ -61,36 +61,31 @@
         F: Future,
     {
         assert!(
-            self.inner.is_real_time(),
+            self.ehandle.inner.is_real_time(),
             "Error: called `run_singlethreaded` on an executor using fake time"
         );
 
-        let mut result = None;
-        let main_future = main_future.map(|r| result = Some(r));
-        pin_mut!(main_future);
-
-        self.run::</* UNTIL_STALLED: */ false>(LocalFutureObj::new(main_future));
-
-        // The main future must have completed.
-        result.unwrap()
+        let Poll::Ready(result) = self.run::</* UNTIL_STALLED: */ false, F::Output>(
+            // SAFETY: This is a singlethreaded executor, so the future will never be sent across
+            // threads.
+            unsafe { AtomicFuture::new_local(main_future, true) }
+        ) else {
+            unreachable!()
+        };
+        result
     }
 
-    fn run<const UNTIL_STALLED: bool>(&mut self, main_future: LocalFutureObj<'_, ()>) {
+    fn run<const UNTIL_STALLED: bool, R>(&mut self, main_future: AtomicFuture<'_>) -> Poll<R> {
         /// # Safety
         ///
         /// See the comment below.
-        unsafe fn remove_lifetime(obj: FutureObj<'_, ()>) -> FutureObj<'static, ()> {
+        unsafe fn remove_lifetime(obj: AtomicFuture<'_>) -> AtomicFuture<'static> {
             std::mem::transmute(obj)
         }
 
-        // SAFETY: This is a single-threaded executor, so the future here will never be used
-        // across multiple threads, so we can safely convert from a non-`Send`able future to a
-        // `Send`able one.
-        let obj = unsafe { main_future.into_future_obj() };
-
         // SAFETY: Erasing the lifetime is safe because we make sure to drop the main task within
         // the required lifetime.
-        self.inner.spawn_main(unsafe { remove_lifetime(obj) });
+        self.ehandle.inner.spawn_main(unsafe { remove_lifetime(main_future) });
 
         struct DropMainTask<'a>(&'a Inner);
         impl Drop for DropMainTask<'_> {
@@ -100,21 +95,30 @@
                 unsafe { self.0.drop_main_task() };
             }
         }
-        let _drop_main_task = DropMainTask(&self.inner);
+        let _drop_main_task = DropMainTask(&self.ehandle.inner);
 
-        self.inner.worker_lifecycle::<UNTIL_STALLED>();
+        self.ehandle.inner.worker_lifecycle::<UNTIL_STALLED>();
+
+        // SAFETY: We spawned the task earlier, so `R` (the return type) will be the correct type
+        // here.
+        unsafe {
+            self.ehandle.inner.poll_join_result(
+                MAIN_TASK_ID,
+                &mut Context::from_waker(&futures::task::noop_waker()),
+            )
+        }
     }
 
     #[cfg(test)]
     pub(crate) fn snapshot(&self) -> super::instrumentation::Snapshot {
-        self.inner.collector.snapshot()
+        self.ehandle.inner.collector.snapshot()
     }
 }
 
 impl Drop for LocalExecutor {
     fn drop(&mut self) {
-        self.inner.mark_done();
-        self.inner.on_parent_drop();
+        self.ehandle.inner.mark_done();
+        self.ehandle.inner.on_parent_drop();
     }
 }
 
@@ -139,12 +143,12 @@
             /* num_threads */ 1,
         ));
         inner.clone().set_local(TimerHeap::default());
-        Self { local: LocalExecutor { inner } }
+        Self { local: LocalExecutor { ehandle: EHandle { inner } } }
     }
 
     /// Return the current time according to the executor.
     pub fn now(&self) -> Time {
-        self.local.inner.now()
+        self.local.ehandle.inner.now()
     }
 
     /// Set the fake time to a given value.
@@ -153,7 +157,7 @@
     ///
     /// If the executor was not created with fake time
     pub fn set_fake_time(&self, t: Time) {
-        self.local.inner.set_fake_time(t)
+        self.local.ehandle.inner.set_fake_time(t)
     }
 
     /// Run a single future to completion on a single thread, also polling other active tasks.
@@ -173,14 +177,12 @@
     /// the knowledge of the executor.
     ///
     /// Unpin: this function requires all futures to be `Unpin`able, so any `!Unpin`
-    /// futures must first be pinned using the `pin_mut!` macro from the `pin-utils` crate.
+    /// futures must first be pinned using the `pin!` macro.
     pub fn run_until_stalled<F>(&mut self, main_future: &mut F) -> Poll<F::Output>
     where
         F: Future + Unpin,
     {
-        let mut result = None;
-        let main_future = main_future.map(|r| result = Some(r));
-        pin_mut!(main_future);
+        let mut main_future = pin!(main_future);
 
         // Set up an instance of UntilStalledData that works with `poll_until_stalled`.
         struct Cleanup(Arc<Inner>);
@@ -189,11 +191,19 @@
                 *self.0.owner_data.lock() = None;
             }
         }
-        let _cleanup = Cleanup(self.local.inner.clone());
-        *self.local.inner.owner_data.lock() = Some(Box::new(UntilStalledData { watcher: None }));
+        let _cleanup = Cleanup(self.local.ehandle.inner.clone());
+        *self.local.ehandle.inner.owner_data.lock() =
+            Some(Box::new(UntilStalledData { watcher: None }));
 
         loop {
-            self.local.run::</* UNTIL_STALLED: */ true>(LocalFutureObj::new(main_future.as_mut()));
+            let result = self.local.run::</* UNTIL_STALLED: */ true, F::Output>(
+                // SAFETY: We don't move the main future across threads.
+                unsafe { AtomicFuture::new_local(main_future.as_mut(), true) }
+            );
+            if result.is_ready() {
+                return result;
+            }
+
             // If a waker was set by `poll_until_stalled`, disarm, wake, and loop.
             if let Some(watcher) = with_data(|data| data.watcher.take()) {
                 watcher.waker.wake();
@@ -205,11 +215,7 @@
             }
         }
 
-        if let Some(result) = result {
-            Poll::Ready(result)
-        } else {
-            Poll::Pending
-        }
+        Poll::Pending
     }
 
     /// Wake all tasks waiting for expired timers, and return `true` if any task was woken.
@@ -260,7 +266,7 @@
 
     #[cfg(test)]
     pub(crate) fn snapshot(&self) -> super::instrumentation::Snapshot {
-        self.local.inner.collector.snapshot()
+        self.local.ehandle.inner.collector.snapshot()
     }
 
     /// Advances fake time to the specified time.  This will only work if the executor is being run
@@ -380,7 +386,6 @@
     use assert_matches::assert_matches;
     use fuchsia_zircon::{self as zx, AsHandleRef, DurationNum};
     use futures::StreamExt;
-    use pin_utils::pin_mut;
     use std::{
         cell::{Cell, RefCell},
         task::Waker,
@@ -415,7 +420,7 @@
         let mut executor = TestExecutor::new_with_fake_time();
         // Spawn the future rather than waking it the main task because run_until_stalled will wake
         // the main future on every call, and we want to wake it ourselves using the waker.
-        executor.local.inner.spawn_local(LocalFutureObj::new(fut));
+        executor.local.ehandle.spawn_local_detached(fut);
         assert_eq!(fut_step.get(), 0);
         assert_eq!(executor.run_until_stalled(&mut future::pending::<()>()), Poll::Pending);
         assert_eq!(fut_step.get(), 1);
@@ -430,8 +435,7 @@
     fn stepwise_timer() {
         let mut executor = TestExecutor::new_with_fake_time();
         executor.set_fake_time(Time::from_nanos(0));
-        let fut = Timer::new(Time::after(1000.nanos()));
-        pin_mut!(fut);
+        let mut fut = pin!(Timer::new(Time::after(1000.nanos())));
 
         let _ = executor.run_until_stalled(&mut fut);
         assert_eq!(Time::now(), Time::from_nanos(0));
@@ -446,8 +450,7 @@
     fn stepwise_event() {
         let mut executor = TestExecutor::new_with_fake_time();
         let event = zx::Event::create();
-        let fut = OnSignals::new(&event, zx::Signals::USER_0);
-        pin_mut!(fut);
+        let mut fut = pin!(OnSignals::new(&event, zx::Signals::USER_0));
 
         let _ = executor.run_until_stalled(&mut fut);
 
@@ -466,10 +469,9 @@
             Timer::new(Time::after(5.seconds())).await;
             spawned_fut_completed_writer.store(true, Ordering::SeqCst);
         });
-        let main_fut = async {
+        let mut main_fut = pin!(async {
             Timer::new(Time::after(10.seconds())).await;
-        };
-        pin_mut!(main_fut);
+        });
         spawn(spawned_fut);
         assert_eq!(executor.run_until_stalled(&mut main_fut), Poll::Pending);
         executor.set_fake_time(Time::after(15.seconds()));
@@ -498,14 +500,13 @@
         let mut dropped = Arc::new(AtomicBool::new(false));
         let drop_spawner = DropSpawner { dropped: dropped.clone() };
         let mut executor = TestExecutor::new();
-        let main_fut = async move {
+        let mut main_fut = pin!(async move {
             spawn(async move {
                 // Take ownership of the drop spawner
                 let _drop_spawner = drop_spawner;
                 future::pending::<()>().await;
             });
-        };
-        pin_mut!(main_fut);
+        });
         assert!(executor.run_until_stalled(&mut main_fut).is_ready());
         assert_eq!(
             dropped.load(Ordering::SeqCst),
@@ -579,7 +580,7 @@
         let run = |n| {
             let mut executor = LocalExecutor::new();
             executor.run_singlethreaded(multi_wake(n));
-            let snapshot = executor.inner.collector.snapshot();
+            let snapshot = executor.ehandle.inner.collector.snapshot();
             snapshot.wakeups_notification
         };
         assert_eq!(run(5), run(10)); // Same number of notifications independent of wakeup calls
@@ -598,7 +599,7 @@
         let mut executor = TestExecutor::new_with_fake_time();
         executor.set_fake_time(Time::from_nanos(0));
 
-        let fut = async {
+        let mut fut = pin!(async {
             let timer_fired = Arc::new(AtomicBool::new(false));
             futures::join!(
                 async {
@@ -630,8 +631,7 @@
                     TestExecutor::advance_to(Time::after(2.seconds())).await;
                 }
             )
-        };
-        pin_mut!(fut);
+        });
         assert!(executor.run_until_stalled(&mut fut).is_ready());
     }
 }
diff --git a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/mod.rs b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/mod.rs
index 7fef16b..d204952 100644
--- a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/mod.rs
+++ b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/mod.rs
@@ -11,6 +11,6 @@
 
 pub use common::EHandle;
 pub use local::{LocalExecutor, TestExecutor};
-pub use packets::{need_signal_or_peer_closed, PacketReceiver, ReceiverRegistration};
+pub use packets::{PacketReceiver, ReceiverRegistration};
 pub use send::SendExecutor;
 pub use time::{Duration, Time};
diff --git a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/packets.rs b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/packets.rs
index 6cdf129..1231850 100644
--- a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/packets.rs
+++ b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/packets.rs
@@ -2,50 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use fuchsia_zircon::{self as zx, AsHandleRef};
-use futures::task::AtomicWaker;
+use fuchsia_zircon as zx;
 use rustc_hash::FxHashMap as HashMap;
-use std::{
-    ops::Deref,
-    sync::{
-        atomic::{AtomicU32, Ordering},
-        Arc,
-    },
-    task::{Context, Poll},
-    u64, usize,
-};
+use std::{ops::Deref, sync::Arc, u64, usize};
 
 use super::common::EHandle;
 
-/// Clears `signal` on `atomic_signals`, then schedules a packet to wake `task` when the object
-/// referred to by `handle` asserts `signal` or `OBJECT_PEER_CLOSED`.  If `atomic_signals` contains
-/// `OBJECT_PEER_CLOSED` already, wakes `task` immediately. To avoid unnecessary packets, does
-/// nothing if `signal` was already cleared.  If a packet is scheduled, the `OBJECT_PEER_CLOSED`
-/// signal is _always_ included as a signal of interest.
-pub fn need_signal_or_peer_closed(
-    cx: &mut Context<'_>,
-    task: &AtomicWaker,
-    atomic_signals: &AtomicU32,
-    signal: zx::Signals,
-    handle: zx::HandleRef<'_>,
-    port: &zx::Port,
-    key: u64,
-) -> Poll<Result<(), zx::Status>> {
-    task.register(cx.waker());
-    let old =
-        zx::Signals::from_bits_truncate(atomic_signals.fetch_and(!signal.bits(), Ordering::SeqCst));
-    if old.contains(zx::Signals::OBJECT_PEER_CLOSED) {
-        // We don't want to return an error here because even though the peer has closed, the
-        // object could still have queued messages that can be read.
-        Poll::Ready(Ok(()))
-    } else {
-        if old.contains(signal) {
-            schedule_packet(handle, port, key, signal | zx::Signals::OBJECT_PEER_CLOSED)?;
-        }
-        Poll::Pending
-    }
-}
-
 /// A trait for handling the arrival of a packet on a `zx::Port`.
 ///
 /// This trait should be implemented by users who wish to write their own
@@ -99,15 +61,6 @@
     }
 }
 
-pub fn schedule_packet(
-    handle: zx::HandleRef<'_>,
-    port: &zx::Port,
-    key: u64,
-    signals: zx::Signals,
-) -> Result<(), zx::Status> {
-    handle.wait_async_handle(port, key, signals, zx::WaitAsyncOpts::empty())
-}
-
 /// A registration of a `PacketReceiver`.
 /// When dropped, it will automatically deregister the `PacketReceiver`.
 // NOTE: purposefully does not implement `Clone`.
diff --git a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/send.rs b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/send.rs
index d1e5fd7..773b315 100644
--- a/src/lib/fuchsia-async/src/runtime/fuchsia/executor/send.rs
+++ b/src/lib/fuchsia-async/src/runtime/fuchsia/executor/send.rs
@@ -4,11 +4,9 @@
 
 use super::super::timer::TimerHeap;
 use super::common::{with_local_timer_heap, ExecutorTime, Inner};
+use crate::atomic_future::AtomicFuture;
 use fuchsia_sync::{Condvar, Mutex};
-use futures::{
-    future::{self, FutureObj},
-    FutureExt,
-};
+use futures::FutureExt;
 use std::{
     fmt,
     future::Future,
@@ -74,13 +72,15 @@
         // Spawn a future which will set the result upon completion.
         Inner::spawn_main(
             &self.inner,
-            FutureObj::new(Box::new(future.then(move |fut_result| {
-                let (lock, cvar) = &*pair2;
-                let mut result = lock.lock();
-                *result = Some(fut_result);
-                cvar.notify_one();
-                future::ready(())
-            }))),
+            AtomicFuture::new(
+                future.map(move |fut_result| {
+                    let (lock, cvar) = &*pair2;
+                    let mut result = lock.lock();
+                    *result = Some(fut_result);
+                    cvar.notify_one();
+                }),
+                true,
+            ),
         );
 
         // Start worker threads, handing off timers from the current thread.
diff --git a/src/lib/fuchsia-async/src/runtime/fuchsia/task.rs b/src/lib/fuchsia-async/src/runtime/fuchsia/task.rs
index a572719..cde9016 100644
--- a/src/lib/fuchsia-async/src/runtime/fuchsia/task.rs
+++ b/src/lib/fuchsia-async/src/runtime/fuchsia/task.rs
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 use crate::EHandle;
-use futures::future::RemoteHandle;
 use futures::prelude::*;
+use std::marker::PhantomData;
 use std::pin::Pin;
 use std::task::{Context, Poll};
 
@@ -21,9 +21,13 @@
 #[must_use]
 #[derive(Debug)]
 pub struct Task<T> {
-    remote_handle: RemoteHandle<T>,
+    executor: EHandle,
+    task_id: usize,
+    phantom: PhantomData<T>,
 }
 
+impl<T> Unpin for Task<T> {}
+
 impl Task<()> {
     /// Detach this task so that it can run independently in the background.
     ///
@@ -49,12 +53,13 @@
     /// * [`futures::stream::TryStreamExt::try_for_each_concurrent`]
     ///
     /// can meet your needs.
-    pub fn detach(self) {
-        self.remote_handle.forget();
+    pub fn detach(mut self) {
+        self.executor.detach(self.task_id);
+        self.task_id = 0;
     }
 }
 
-impl<T: Send> Task<T> {
+impl<T: Send + 'static> Task<T> {
     /// Spawn a new task on the current executor.
     ///
     /// The task may be executed on any thread(s) owned by the current executor.
@@ -70,20 +75,13 @@
     /// within a call to `run` or `run_singlethreaded`).
     #[cfg_attr(trace_level_logging, track_caller)]
     pub fn spawn(future: impl Future<Output = T> + Send + 'static) -> Task<T> {
-        // Fuse is a combinator that will drop the underlying future as soon as it has been
-        // completed to ensure resources are reclaimed as soon as possible. That gives callers that
-        // await on the Task the guarantee that the future has been dropped.
-        //
-        // Note that it is safe to pass in a future that has already been fused. Double fusing
-        // a future does not change the expected behavior.
-        let future = future.fuse();
-        let (future, remote_handle) = future.remote_handle();
-        EHandle::local().spawn_detached(future);
-        Task { remote_handle }
+        let executor = EHandle::local();
+        let task_id = executor.spawn(future);
+        Task { executor, task_id, phantom: PhantomData }
     }
 }
 
-impl<T> Task<T> {
+impl<T: 'static> Task<T> {
     /// Spawn a new task on the thread local executor.
     ///
     /// The passed future will live until either (a) the future completes,
@@ -99,16 +97,9 @@
     /// within a call to `run` or `run_singlethreaded`).
     #[cfg_attr(trace_level_logging, track_caller)]
     pub fn local(future: impl Future<Output = T> + 'static) -> Task<T> {
-        // Fuse is a combinator that will drop the underlying future as soon as it has been
-        // completed to ensure resources are reclaimed as soon as possible. That gives callers that
-        // await on the Task the guarantee that the future has been dropped.
-        //
-        // Note that it is safe to pass in a future that has already been fused. Double fusing
-        // a future does not change the expected behavior.
-        let future = future.fuse();
-        let (future, remote_handle) = future.remote_handle();
-        EHandle::local().spawn_local_detached(future);
-        Task { remote_handle }
+        let executor = EHandle::local();
+        let task_id = executor.spawn_local(future);
+        Task { executor, task_id, phantom: PhantomData }
     }
 }
 
@@ -121,15 +112,32 @@
     /// short period before getting dropped. If so, do not assume any resources held
     /// by the task's future are released. If `Some(..)` is returned, such resources
     /// are guaranteed to be released.
-    pub async fn cancel(self) -> Option<T> {
-        self.remote_handle.now_or_never()
+    pub fn cancel(mut self) -> Option<T> {
+        // SAFETY: We spawned the task so the return type should be correct.
+        let result = unsafe { self.executor.cancel(self.task_id) };
+        self.task_id = 0;
+        result
+    }
+}
+
+impl<T> Drop for Task<T> {
+    fn drop(&mut self) {
+        if self.task_id != 0 {
+            // SAFETY: We spawned the task so the return type should be correct.
+            unsafe { self.executor.cancel::<T>(self.task_id) };
+        }
     }
 }
 
 impl<T: 'static> Future for Task<T> {
     type Output = T;
     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-        self.remote_handle.poll_unpin(cx)
+        // SAFETY: We spawned the task so the return type should be correct.
+        let result = unsafe { self.executor.poll_join_result(self.task_id, cx) };
+        if result.is_ready() {
+            self.task_id = 0;
+        }
+        result
     }
 }
 
diff --git a/src/lib/fuchsia-async/src/runtime/mod.rs b/src/lib/fuchsia-async/src/runtime/mod.rs
index 8a2a0ac..2eed768 100644
--- a/src/lib/fuchsia-async/src/runtime/mod.rs
+++ b/src/lib/fuchsia-async/src/runtime/mod.rs
@@ -36,11 +36,8 @@
     timer::Interval,
 };
 
-#[cfg(target_os = "fuchsia")]
-pub(crate) use self::fuchsia::executor::need_signal_or_peer_closed;
-
 use futures::prelude::*;
-use pin_utils::{unsafe_pinned, unsafe_unpinned};
+use pin_project_lite::pin_project;
 use std::pin::Pin;
 use std::task::{Context, Poll};
 
@@ -111,40 +108,31 @@
 
 impl<F: Future + Sized> TimeoutExt for F {}
 
-/// A wrapper for a future which will complete with a provided closure when a timeout occurs.
-#[derive(Debug)]
-#[must_use = "futures do nothing unless polled"]
-pub struct OnTimeout<F, OT> {
-    timer: Timer,
-    future: F,
-    on_timeout: Option<OT>,
+pin_project! {
+    /// A wrapper for a future which will complete with a provided closure when a timeout occurs.
+    #[derive(Debug)]
+    #[must_use = "futures do nothing unless polled"]
+    pub struct OnTimeout<F, OT> {
+        timer: Timer,
+        #[pin]
+        future: F,
+        on_timeout: Option<OT>,
+    }
 }
 
-impl<F, OT> OnTimeout<F, OT> {
-    // Safety: this is safe because `OnTimeout` is only `Unpin` if
-    // the future is `Unpin`, and aside from `future`, all other fields are
-    // treated as movable.
-    unsafe_unpinned!(timer: Timer);
-    unsafe_pinned!(future: F);
-    unsafe_unpinned!(on_timeout: Option<OT>);
-}
-
-impl<F: Unpin, OT> Unpin for OnTimeout<F, OT> {}
-
 impl<F: Future, OT> Future for OnTimeout<F, OT>
 where
     OT: FnOnce() -> F::Output,
 {
     type Output = F::Output;
 
-    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-        if let Poll::Ready(item) = self.as_mut().future().poll(cx) {
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        let this = self.project();
+        if let Poll::Ready(item) = this.future.poll(cx) {
             return Poll::Ready(item);
         }
-        if let Poll::Ready(()) = self.as_mut().timer().poll_unpin(cx) {
-            let ot = OnTimeout::on_timeout(self.as_mut())
-                .take()
-                .expect("polled withtimeout after completion");
+        if let Poll::Ready(()) = this.timer.poll_unpin(cx) {
+            let ot = this.on_timeout.take().expect("polled withtimeout after completion");
             let item = (ot)();
             return Poll::Ready(item);
         }
@@ -152,48 +140,37 @@
     }
 }
 
-/// A wrapper for a future who's steady progress is monitored and will complete with the provided
-/// closure if no progress is made before the timeout.
-#[derive(Debug)]
-#[must_use = "futures do nothing unless polled"]
-pub struct OnStalled<F, OS> {
-    timer: Timer,
-    future: F,
-    timeout: std::time::Duration,
-    on_stalled: Option<OS>,
+pin_project! {
+    /// A wrapper for a future who's steady progress is monitored and will complete with the
+    /// provided closure if no progress is made before the timeout.
+    #[derive(Debug)]
+    #[must_use = "futures do nothing unless polled"]
+    pub struct OnStalled<F, OS> {
+        timer: Timer,
+        #[pin]
+        future: F,
+        timeout: std::time::Duration,
+        on_stalled: Option<OS>,
+    }
 }
 
-impl<F, OS> OnStalled<F, OS> {
-    // Safety: this is safe because `OnTimeout` is only `Unpin` if
-    // the future is `Unpin`, and aside from `future`, all other fields are
-    // treated as movable.
-    unsafe_unpinned!(timer: Timer);
-    unsafe_pinned!(future: F);
-    unsafe_unpinned!(timeout: std::time::Duration);
-    unsafe_unpinned!(on_stalled: Option<OS>);
-}
-
-impl<F: Unpin, OT> Unpin for OnStalled<F, OT> {}
-
 impl<F: Future, OS> Future for OnStalled<F, OS>
 where
     OS: FnOnce() -> F::Output,
 {
     type Output = F::Output;
 
-    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
-        if let Poll::Ready(item) = self.as_mut().future().poll(cx) {
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        let this = self.project();
+        if let Poll::Ready(item) = this.future.poll(cx) {
             return Poll::Ready(item);
         }
-        match self.as_mut().timer().poll_unpin(cx) {
+        match this.timer.poll_unpin(cx) {
             Poll::Ready(()) => {
-                let os =
-                    OnStalled::on_stalled(self.as_mut()).take().expect("polled after completion");
-                Poll::Ready((os)())
+                Poll::Ready((this.on_stalled.take().expect("polled after completion"))())
             }
             Poll::Pending => {
-                let new_timer = Timer::new(*self.as_mut().timeout());
-                *self.as_mut().timer() = new_timer;
+                *this.timer = Timer::new(*this.timeout);
                 Poll::Pending
             }
         }
@@ -281,12 +258,11 @@
         run(async move {
             let (_tx_start, rx_start) = oneshot::channel::<()>();
             let (tx_done, rx_done) = oneshot::channel();
-            let t = Task::spawn(async move {
+            // Start and immediately cancel the task (by dropping it).
+            let _ = Task::spawn(async move {
                 rx_start.await.unwrap();
                 tx_done.send(()).unwrap();
             });
-            // cancel the task without sending the start signal
-            t.cancel().await;
             // we should see an error on receive
             rx_done.await.expect_err("done should not be sent");
         })
diff --git a/src/lib/fuchsia-async/src/test_support.rs b/src/lib/fuchsia-async/src/test_support.rs
index 5bceecb..8981311 100644
--- a/src/lib/fuchsia-async/src/test_support.rs
+++ b/src/lib/fuchsia-async/src/test_support.rs
@@ -6,9 +6,9 @@
 use futures::{lock::Mutex, prelude::*};
 use std::pin::Pin;
 use std::sync::Arc;
-#[cfg(target_os = "fuchsia")]
-use std::task::Poll;
 use std::time::Duration;
+#[cfg(target_os = "fuchsia")]
+use std::{pin::pin, task::Poll};
 
 // Apply the timeout from config to test
 // Ideally this would be a function like Config::with_timeout, but we need to handle Send and !Send
@@ -132,8 +132,7 @@
     ) -> Poll<Self> {
         // TODO(ctiller): figure out why this is necessary and unify the loops
         if cfg.repeat_count == 1 {
-            let test = test(1);
-            crate::pin_mut!(test);
+            let mut test = pin!(test(1));
             executor.run_until_stalled(&mut test)
         } else {
             executor.run_until_stalled(
diff --git a/src/lib/fuchsia-async/tests/hung_task/BUILD.gn b/src/lib/fuchsia-async/tests/hung_task/BUILD.gn
index d667b34..98b836d4 100644
--- a/src/lib/fuchsia-async/tests/hung_task/BUILD.gn
+++ b/src/lib/fuchsia-async/tests/hung_task/BUILD.gn
@@ -41,7 +41,6 @@
     "//src/lib/fuchsia-runtime",
     "//src/lib/zircon/rust:fuchsia-zircon",
     "//third_party/rust_crates:futures",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:test-case",
     "//third_party/rust_crates:tracing",
   ]
diff --git a/src/lib/fuchsia-async/tests/hung_task/src/test.rs b/src/lib/fuchsia-async/tests/hung_task/src/test.rs
index 87b25ee..3a8ed6f 100644
--- a/src/lib/fuchsia-async/tests/hung_task/src/test.rs
+++ b/src/lib/fuchsia-async/tests/hung_task/src/test.rs
@@ -8,7 +8,7 @@
 use fuchsia_async::{Task, Timer};
 use fuchsia_zircon::AsHandleRef as _;
 use futures::prelude::*;
-use std::time::Duration;
+use std::{pin::pin, time::Duration};
 use test_case::test_case;
 use tracing::trace;
 
@@ -81,8 +81,7 @@
         // the logging pipeline. using a delay here means that legitimate failures will appear as
         // flakes, but given the lack of a "flush everything and wait" api from archivist i think
         // it's the best we can do for now
-        let pending_until_channel_send = events.next();
-        pin_utils::pin_mut!(pending_until_channel_send);
+        let mut pending_until_channel_send = pin!(events.next());
         Timer::new(Duration::from_secs(1)).await;
         assert!(futures::poll!(&mut pending_until_channel_send).is_pending());
 
diff --git a/src/lib/fuchsia-component-test/realm_builder_server/BUILD.gn b/src/lib/fuchsia-component-test/realm_builder_server/BUILD.gn
index ecacfa7..2b3028d 100644
--- a/src/lib/fuchsia-component-test/realm_builder_server/BUILD.gn
+++ b/src/lib/fuchsia-component-test/realm_builder_server/BUILD.gn
@@ -29,6 +29,7 @@
     "//sdk/fidl/fuchsia.logger:fuchsia.logger_rust",
     "//sdk/fidl/fuchsia.mem:fuchsia.mem_rust",
     "//src/lib/fidl/rust/fidl",
+    "//src/lib/flyweights",
     "//src/lib/fuchsia",
     "//src/lib/fuchsia-async",
     "//src/lib/fuchsia-component",
@@ -51,6 +52,7 @@
     "//third_party/rust_crates:url",
   ]
   test_deps = [
+    "//src/sys/lib/cm_rust/testing",
     "//third_party/rust_crates:assert_matches",
     "//third_party/rust_crates:difference",
     "//third_party/rust_crates:maplit",
diff --git a/src/lib/fuchsia-component-test/realm_builder_server/src/main.rs b/src/lib/fuchsia-component-test/realm_builder_server/src/main.rs
index af5a6b8..d227632 100644
--- a/src/lib/fuchsia-component-test/realm_builder_server/src/main.rs
+++ b/src/lib/fuchsia-component-test/realm_builder_server/src/main.rs
@@ -5,7 +5,7 @@
 use {
     anyhow::Context,
     cm_rust::{FidlIntoNative, NativeIntoFidl, OfferDeclCommon},
-    cm_types::RelativePath,
+    cm_types::{LongName, RelativePath},
     fidl::endpoints::{DiscoverableProtocolMarker, ProtocolMarker, Proxy, ServerEnd},
     fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_decl as fcdecl,
     fidl_fuchsia_component_runner as fcrunner, fidl_fuchsia_component_test as ftest,
@@ -13,6 +13,7 @@
     fidl_fuchsia_inspect::InspectSinkMarker,
     fidl_fuchsia_io as fio,
     fidl_fuchsia_logger::LogSinkMarker,
+    flyweights::FlyStr,
     fuchsia_async as fasync,
     fuchsia_component::server as fserver,
     fuchsia_zircon_status as zx_status,
@@ -599,10 +600,11 @@
         url: String,
         options: ftest::ChildOptions,
     ) -> Result<(), RealmBuilderError> {
+        let name = name.parse().map_err(|_| RealmBuilderError::ChildNameInvalid)?;
         if is_fragment_only_url(&url) {
             let child_realm_node =
                 RealmNode2::load_from_pkg(url, Clone::clone(&self.pkg_dir)).await?;
-            self.realm_node.add_child(name.clone(), options, child_realm_node).await
+            self.realm_node.add_child(name, options, child_realm_node).await
         } else {
             self.realm_node.add_child_decl(name, url, options).await
         }
@@ -614,9 +616,10 @@
         component_decl: fcdecl::Component,
         options: ftest::ChildOptions,
     ) -> Result<(), RealmBuilderError> {
+        let name: LongName = name.parse().map_err(|_| RealmBuilderError::ChildNameInvalid)?;
         if let Err(e) = cm_fidl_validator::validate(&component_decl) {
             return Err(RealmBuilderError::InvalidComponentDeclWithName(
-                name,
+                name.to_string(),
                 to_tabulated_string(e),
             ));
         }
@@ -629,11 +632,12 @@
         name: String,
         options: ftest::ChildOptions,
     ) -> Result<(), RealmBuilderError> {
+        let name: LongName = name.parse().map_err(|_| RealmBuilderError::ChildNameInvalid)?;
         let local_component_id =
             self.runner.register_local_component(self.runner_proxy_placeholder.clone()).await;
         self.realm_contents.lock().await.add_local_component_id(local_component_id.clone());
         let mut child_path = self.realm_path.clone();
-        child_path.push(name.clone());
+        child_path.push(name.to_string());
         let child_realm_node = RealmNode2::new_from_decl(
             new_decl_with_program_entries(vec![
                 (runner::LOCAL_COMPONENT_ID_KEY.to_string(), local_component_id.into()),
@@ -674,9 +678,10 @@
         let self_execution_scope = self.execution_scope.clone();
 
         async move {
+            let name: LongName = name.parse().map_err(|_| RealmBuilderError::ChildNameInvalid)?;
             let child_realm_stream = child_realm_server_end
                 .into_stream()
-                .map_err(|e| RealmBuilderError::InvalidChildRealmHandle(name.clone(), e))?;
+                .map_err(|e| RealmBuilderError::InvalidChildRealmHandle(name.to_string(), e))?;
             self_realm_node.add_child(name, options, child_realm_node).await?;
 
             self_execution_scope.spawn(async move {
@@ -780,10 +785,11 @@
             .await;
         self.realm_contents.lock().await.add_local_component_id(local_component_id.clone());
         let string_id: String = local_component_id.clone().into();
-        let child_name = format!("read-only-directory-{}", string_id);
+        let child_name: LongName =
+            format!("read-only-directory-{}", string_id).parse().expect("should be valid name");
 
         let mut child_path = self.realm_path.clone();
-        child_path.push(child_name.clone());
+        child_path.push(child_name.to_string());
 
         let child_realm_node = RealmNode2::new_from_decl(
             new_decl_with_program_entries(vec![(
@@ -853,20 +859,20 @@
     ///
     /// Suitable `ChildDecl`s for the contents of `mutable_children` are generated and added to
     /// `decl.children` when `commit()` is called.
-    mutable_children: HashMap<String, (ftest::ChildOptions, RealmNode2)>,
+    mutable_children: HashMap<LongName, (ftest::ChildOptions, RealmNode2)>,
 }
 
 impl RealmNodeState {
     // Returns true if a child with the given name exists either as a mutable child or as a
     // ChildDecl in this node's ComponentDecl.
-    fn contains_child(&self, child_name: &String) -> bool {
-        self.decl.children.iter().any(|c| &c.name == child_name)
-            || self.mutable_children.contains_key(child_name)
+    fn contains_child(&self, child_name: &LongName) -> bool {
+        self.decl.children.iter().any(|c| c.name.as_str() == child_name.as_str())
+            || self.mutable_children.contains_key(&FlyStr::new(child_name.as_str()))
     }
 
     fn add_child_decl(
         &mut self,
-        child_name: String,
+        child_name: LongName,
         child_url: String,
         child_options: ftest::ChildOptions,
     ) {
@@ -917,7 +923,7 @@
                 self.decl.offers.push(cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                     source: cm_rust::OfferSource::Parent,
                     target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                        name: child.name.clone().into(),
+                        name: child.name.clone(),
                         collection: None,
                     }),
                     source_name: protocol.clone(),
@@ -932,7 +938,7 @@
 
     // Returns children whose manifest must be updated during invocations to
     // AddRoute.
-    fn get_updateable_children(&mut self) -> HashMap<String, &mut RealmNode2> {
+    fn get_updateable_children(&mut self) -> HashMap<LongName, &mut RealmNode2> {
         self.mutable_children
             .iter_mut()
             .map(|(key, (_options, child))| (key.clone(), child))
@@ -951,7 +957,7 @@
     ) -> Result<(), RealmBuilderError> {
         let child_decls =
             self.mutable_children.iter().map(|(name, _options_and_node)| fcdecl::Child {
-                name: Some(name.clone()),
+                name: Some(name.to_string()),
                 url: Some("invalid://url".to_string()),
                 startup: Some(fcdecl::StartupMode::Lazy),
                 ..Default::default()
@@ -1031,27 +1037,27 @@
 
     async fn add_child(
         &self,
-        child_name: String,
+        child_name: LongName,
         child_options: ftest::ChildOptions,
         node: RealmNode2,
     ) -> Result<(), RealmBuilderError> {
         let mut state_guard = self.state.lock().await;
         if state_guard.contains_child(&child_name) {
-            return Err(RealmBuilderError::ChildAlreadyExists(child_name));
+            return Err(RealmBuilderError::ChildAlreadyExists(child_name.to_string()));
         }
-        state_guard.mutable_children.insert(child_name, (child_options, node));
+        state_guard.mutable_children.insert(child_name.clone().into(), (child_options, node));
         Ok(())
     }
 
     async fn add_child_decl(
         &self,
-        child_name: String,
+        child_name: LongName,
         child_url: String,
         child_options: ftest::ChildOptions,
     ) -> Result<(), RealmBuilderError> {
         let mut state_guard = self.state.lock().await;
         if state_guard.contains_child(&child_name) {
-            return Err(RealmBuilderError::ChildAlreadyExists(child_name));
+            return Err(RealmBuilderError::ChildAlreadyExists(child_name.to_string()));
         }
         state_guard.add_child_decl(child_name, child_url, child_options);
         Ok(())
@@ -1135,17 +1141,17 @@
         .boxed()
     }
 
-    async fn get_sub_realm(&self, child_name: &String) -> Result<RealmNode2, RealmBuilderError> {
+    async fn get_sub_realm(&self, child_name: &str) -> Result<RealmNode2, RealmBuilderError> {
         let state_guard = self.state.lock().await;
-        if state_guard.decl.children.iter().any(|c| &c.name == child_name) {
-            return Err(RealmBuilderError::ChildDeclNotVisible(child_name.clone()));
+        if state_guard.decl.children.iter().any(|c| c.name.as_str() == child_name) {
+            return Err(RealmBuilderError::ChildDeclNotVisible(child_name.into()));
         }
         state_guard
             .mutable_children
-            .get(child_name)
+            .get(&FlyStr::new(child_name))
             .cloned()
             .map(|(_, r)| r)
-            .ok_or_else(|| RealmBuilderError::NoSuchChild(child_name.clone()))
+            .ok_or_else(|| RealmBuilderError::NoSuchChild(child_name.into()))
     }
 
     async fn add_capability(
@@ -1265,7 +1271,7 @@
             mutable_children.sort_unstable_by_key(|t| t.0.clone());
             for (child_name, (child_options, node)) in mutable_children {
                 let mut new_path = walked_path.clone();
-                new_path.push(child_name.clone());
+                new_path.push(child_name.to_string());
 
                 let child_url = node
                     .build(
@@ -1316,7 +1322,7 @@
     capability: ftest::Capability,
 ) -> Result<(), RealmBuilderError> {
     if let fcdecl::Ref::Child(child) = ref_ {
-        if let Some(child) = realm.get_updateable_children().get(&child.name) {
+        if let Some(child) = realm.get_updateable_children().get(&FlyStr::new(&child.name)) {
             let mut decl = child.get_decl().await;
             push_if_not_present(&mut decl.uses, create_use_decl(capability)?);
             let () = child.replace_decl(decl).await?;
@@ -1332,7 +1338,7 @@
     capability: ftest::Capability,
 ) -> Result<(), RealmBuilderError> {
     if let fcdecl::Ref::Child(child) = ref_ {
-        if let Some(child) = realm.get_updateable_children().get(&child.name) {
+        if let Some(child) = realm.get_updateable_children().get(&FlyStr::new(child.name)) {
             let mut decl = child.get_decl().await;
             push_if_not_present(
                 &mut decl.capabilities,
@@ -1805,16 +1811,13 @@
 
 fn contains_child(realm: &RealmNodeState, ref_: &fcdecl::Ref) -> bool {
     match ref_ {
-        fcdecl::Ref::Child(child) => {
-            let children = realm
-                .decl
-                .children
-                .iter()
-                .map(|c| c.name.clone())
-                .chain(realm.mutable_children.iter().map(|(name, _)| name.clone()))
-                .collect::<Vec<_>>();
-            children.contains(&child.name)
-        }
+        fcdecl::Ref::Child(child) => realm
+            .decl
+            .children
+            .iter()
+            .map(|c| &c.name)
+            .chain(realm.mutable_children.keys())
+            .any(|name| child.name.as_str() == name.as_str()),
         _ => true,
     }
 }
@@ -1938,6 +1941,9 @@
     #[error("Failed to route capability. {0:?}")]
     CapabilityInvalid(anyhow::Error),
 
+    #[error("Invalid child declaration. Field `name` is not a valid name.")]
+    ChildNameInvalid,
+
     /// The handle the client provided is not usable
     #[error("Handle for child realm \"{0}\" is not usable. {1:?}")]
     InvalidChildRealmHandle(String, fidl::Error),
@@ -1978,6 +1984,7 @@
             RealmBuilderError::InvalidComponentDecl(_) => Self::InvalidComponentDecl,
             RealmBuilderError::InvalidComponentDeclWithName(_, _) => Self::InvalidComponentDecl,
             RealmBuilderError::NoSuchChild(_) => Self::NoSuchChild,
+            RealmBuilderError::ChildNameInvalid => Self::InvalidChildDecl,
             RealmBuilderError::ChildDeclNotVisible(_) => Self::ChildDeclNotVisible,
             RealmBuilderError::NoSuchSource(_) => Self::NoSuchSource,
             RealmBuilderError::NoSuchTarget(_) => Self::NoSuchTarget,
@@ -2028,6 +2035,7 @@
     use {
         super::*,
         assert_matches::assert_matches,
+        cm_rust_testing::*,
         difference::Changeset,
         fidl::endpoints::{
             create_endpoints, create_proxy, create_proxy_and_stream, create_request_stream,
@@ -2060,7 +2068,7 @@
     #[derive(Debug, Clone, PartialEq)]
     struct ComponentTree {
         decl: cm_rust::ComponentDecl,
-        children: Vec<(String, ftest::ChildOptions, ComponentTree)>,
+        children: Vec<(LongName, ftest::ChildOptions, ComponentTree)>,
     }
 
     impl ComponentTree {
@@ -2122,7 +2130,7 @@
                 cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                     source: cm_rust::OfferSource::Parent,
                     target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                        name: child_name.into(),
+                        name: child_name.parse().unwrap(),
                         collection: None,
                     }),
                     source_name: protocol.clone(),
@@ -2406,7 +2414,7 @@
 
                     // This doesn't exist
                     target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                        name: "a".into(),
+                        name: "a".parse().unwrap(),
                         collection: None,
                     }),
                     availability: cm_rust::Availability::Required,
@@ -2427,7 +2435,7 @@
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Parent,
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "a".into(),
+                            name: "a".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: LogSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -2439,7 +2447,7 @@
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Parent,
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "a".into(),
+                            name: "a".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: InspectSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -2451,7 +2459,7 @@
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Parent,
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "b".into(),
+                            name: "b".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: LogSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -2463,7 +2471,7 @@
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Parent,
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "b".into(),
+                            name: "b".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: InspectSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -2474,7 +2482,7 @@
                     }),
                 ],
                 children: vec![cm_rust::ChildDecl {
-                    name: "a".to_string(),
+                    name: "a".parse().unwrap(),
                     url: "test://a".to_string(),
                     startup: fcdecl::StartupMode::Lazy,
                     on_terminate: None,
@@ -2484,7 +2492,7 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "b".to_string(),
+                "b".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree {
                     decl: cm_rust::ComponentDecl {
@@ -2492,7 +2500,7 @@
                             cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                                 source: cm_rust::OfferSource::Parent,
                                 target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                                    name: "b_child_static".into(),
+                                    name: "b_child_static".parse().unwrap(),
                                     collection: None,
                                 }),
                                 source_name: LogSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -2504,7 +2512,7 @@
                             cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                                 source: cm_rust::OfferSource::Parent,
                                 target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                                    name: "b_child_static".into(),
+                                    name: "b_child_static".parse().unwrap(),
                                     collection: None,
                                 }),
                                 source_name: InspectSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -2516,7 +2524,7 @@
                             cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                                 source: cm_rust::OfferSource::Parent,
                                 target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                                    name: "b_child_dynamic".into(),
+                                    name: "b_child_dynamic".parse().unwrap(),
                                     collection: None,
                                 }),
                                 source_name: LogSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -2528,7 +2536,7 @@
                             cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                                 source: cm_rust::OfferSource::Parent,
                                 target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                                    name: "b_child_dynamic".into(),
+                                    name: "b_child_dynamic".parse().unwrap(),
                                     collection: None,
                                 }),
                                 source_name: InspectSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -2539,7 +2547,7 @@
                             }),
                         ],
                         children: vec![cm_rust::ChildDecl {
-                            name: "b_child_static".to_string(),
+                            name: "b_child_static".parse().unwrap(),
                             url: "test://b_child_static".to_string(),
                             startup: fcdecl::StartupMode::Lazy,
                             on_terminate: None,
@@ -2549,7 +2557,7 @@
                         ..cm_rust::ComponentDecl::default()
                     },
                     children: vec![(
-                        "b_child_dynamic".to_string(),
+                        "b_child_dynamic".parse().unwrap(),
                         ftest::ChildOptions::default(),
                         ComponentTree {
                             decl: cm_rust::ComponentDecl { ..cm_rust::ComponentDecl::default() },
@@ -2568,7 +2576,7 @@
             decl: cm_rust::ComponentDecl {
                 offers: vec![],
                 children: vec![cm_rust::ChildDecl {
-                    name: "a".to_string(),
+                    name: "a".parse().unwrap(),
                     url: "test://a".to_string(),
                     startup: fcdecl::StartupMode::Lazy,
                     on_terminate: None,
@@ -2578,13 +2586,13 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "b".to_string(),
+                "b".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree {
                     decl: cm_rust::ComponentDecl {
                         offers: vec![],
                         children: vec![cm_rust::ChildDecl {
-                            name: "b_child_static".to_string(),
+                            name: "b_child_static".parse().unwrap(),
                             url: "test://b_child_static".to_string(),
                             startup: fcdecl::StartupMode::Lazy,
                             on_terminate: None,
@@ -2594,7 +2602,7 @@
                         ..cm_rust::ComponentDecl::default()
                     },
                     children: vec![(
-                        "b_child_dynamic".to_string(),
+                        "b_child_dynamic".parse().unwrap(),
                         ftest::ChildOptions::default(),
                         ComponentTree {
                             decl: cm_rust::ComponentDecl { ..cm_rust::ComponentDecl::default() },
@@ -2615,7 +2623,7 @@
         let mut tree = ComponentTree {
             decl: cm_rust::ComponentDecl {
                 children: vec![cm_rust::ChildDecl {
-                    name: "a".to_string(),
+                    name: "a".parse().unwrap(),
                     url: "test://a".to_string(),
                     startup: fcdecl::StartupMode::Lazy,
                     on_terminate: None,
@@ -2636,7 +2644,7 @@
         let mut tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree { decl: cm_rust::ComponentDecl::default(), children: vec![] },
             )],
@@ -2651,7 +2659,7 @@
         let mut tree = ComponentTree {
             decl: cm_rust::ComponentDecl {
                 children: vec![cm_rust::ChildDecl {
-                    name: "a".to_string(),
+                    name: "a".parse().unwrap(),
                     url: "test://a".to_string(),
                     startup: fcdecl::StartupMode::Lazy,
                     on_terminate: None,
@@ -2661,7 +2669,7 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "b".to_string(),
+                "b".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree { decl: cm_rust::ComponentDecl::default(), children: vec![] },
             )],
@@ -2676,12 +2684,12 @@
         let mut tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree {
                     decl: cm_rust::ComponentDecl::default(),
                     children: vec![(
-                        "b".to_string(),
+                        "b".parse().unwrap(),
                         ftest::ChildOptions::default(),
                         ComponentTree { decl: cm_rust::ComponentDecl::default(), children: vec![] },
                     )],
@@ -2698,7 +2706,7 @@
         let mut tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions {
                     startup: Some(fcdecl::StartupMode::Eager),
                     ..Default::default()
@@ -2730,7 +2738,7 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions {
                     environment: Some("new-env".to_string()),
                     ..Default::default()
@@ -2748,7 +2756,7 @@
         let mut tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions {
                     on_terminate: Some(fcdecl::OnTerminate::Reboot),
                     ..Default::default()
@@ -2859,7 +2867,7 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl {
                 children: vec![cm_rust::ChildDecl {
-                    name: "a".to_string(),
+                    name: "a".parse().unwrap(),
                     url: "test:///a".to_string(),
                     startup: fcdecl::StartupMode::Lazy,
                     on_terminate: None,
@@ -2990,7 +2998,7 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree { decl: a_decl, children: vec![] },
             )],
@@ -3030,7 +3038,7 @@
 
         // The "a" child is rewritten by realm builder
         realm_with_child_decl.children =
-            realm_with_child_decl.children.into_iter().filter(|c| &c.name != "a").collect();
+            realm_with_child_decl.children.into_iter().filter(|c| c.name.as_str() != "a").collect();
 
         let a_decl_file =
             fuchsia_fs::file::open_in_namespace("/pkg/meta/a.cm", fio::OpenFlags::RIGHT_READABLE)
@@ -3046,7 +3054,7 @@
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Parent,
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "realm_with_child".into(),
+                            name: "realm_with_child".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: LogSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -3058,7 +3066,7 @@
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Parent,
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "realm_with_child".into(),
+                            name: "realm_with_child".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: InspectSinkMarker::PROTOCOL_NAME.parse().unwrap(),
@@ -3071,7 +3079,7 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "realm_with_child".to_string(),
+                "realm_with_child".parse().unwrap(),
                 ftest::ChildOptions {
                     startup: Some(fcdecl::StartupMode::Eager),
                     ..Default::default()
@@ -3079,7 +3087,7 @@
                 ComponentTree {
                     decl: realm_with_child_decl,
                     children: vec![(
-                        "a".to_string(),
+                        "a".parse().unwrap(),
                         ftest::ChildOptions::default(),
                         ComponentTree { decl: a_decl, children: vec![] },
                     )],
@@ -3124,7 +3132,7 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree { decl: a_decl, children: vec![] },
             )],
@@ -3215,7 +3223,10 @@
                     ..Default::default()
                 })],
                 fcdecl::Ref::Parent(fcdecl::ParentRef {}),
-                vec![fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None })],
+                vec![fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await;
         let resulting_a_decl = realm_and_builder_task
@@ -3259,7 +3270,7 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree { decl: a_decl, children: vec![] },
             )],
@@ -3356,7 +3367,10 @@
                     }),
                 ],
                 fcdecl::Ref::Parent(fcdecl::ParentRef {}),
-                vec![fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None })],
+                vec![fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await;
 
@@ -3367,8 +3381,14 @@
                     name: Some("fuchsia.examples.Echo".to_owned()),
                     ..Default::default()
                 })],
-                fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".to_owned(), collection: None }),
-                vec![fcdecl::Ref::Child(fcdecl::ChildRef { name: "b".into(), collection: None })],
+                fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                }),
+                vec![fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "b".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await;
 
@@ -3380,7 +3400,10 @@
                     type_: Some(fcdecl::DependencyType::Weak),
                     ..Default::default()
                 })],
-                fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None }),
+                fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                }),
                 vec![fcdecl::Ref::Parent(fcdecl::ParentRef {})],
             )
             .await;
@@ -3390,7 +3413,7 @@
             decl: cm_rust::ComponentDecl {
                 children: vec![
                     cm_rust::ChildDecl {
-                        name: "a".to_string(),
+                        name: "a".parse().unwrap(),
                         url: "test:///a".to_string(),
                         startup: fcdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -3398,7 +3421,7 @@
                         config_overrides: None,
                     },
                     cm_rust::ChildDecl {
-                        name: "b".to_string(),
+                        name: "b".parse().unwrap(),
                         url: "test:///b".to_string(),
                         startup: fcdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -3411,7 +3434,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "fuchsia.examples.Hippo".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "fuchsia.examples.Elephant".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         availability: cm_rust::Availability::Required,
@@ -3420,7 +3443,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "config-data".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "config-data".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         rights: Some(fio::RW_STAR_DIR),
@@ -3430,7 +3453,7 @@
                     cm_rust::OfferDecl::Storage(cm_rust::OfferStorageDecl {
                         source: cm_rust::OfferSource::Parent,
                         source_name: "temp".parse().unwrap(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "data".parse().unwrap(),
                         availability: cm_rust::Availability::Required,
                     }),
@@ -3438,7 +3461,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "fuchsia.examples.Whale".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "fuchsia.examples.Orca".parse().unwrap(),
                         source_instance_filter: None,
                         renamed_instances: None,
@@ -3448,15 +3471,15 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "started".parse().unwrap(),
                         scope: None,
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "started_event".parse().unwrap(),
                         availability: cm_rust::Availability::Required,
                     }),
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
-                        source: cm_rust::OfferSource::static_child("a".to_string()),
+                        source: offer_source_static_child("a"),
                         source_name: "fuchsia.examples.Echo".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("b".to_string()),
+                        target: offer_target_static_child("b"),
                         target_name: "fuchsia.examples.Echo".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         availability: cm_rust::Availability::Required,
@@ -3526,8 +3549,14 @@
                 ],
                 fcdecl::Ref::Parent(fcdecl::ParentRef {}),
                 vec![
-                    fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None }),
-                    fcdecl::Ref::Child(fcdecl::ChildRef { name: "b".into(), collection: None }),
+                    fcdecl::Ref::Child(fcdecl::ChildRef {
+                        name: "a".parse().unwrap(),
+                        collection: None,
+                    }),
+                    fcdecl::Ref::Child(fcdecl::ChildRef {
+                        name: "b".parse().unwrap(),
+                        collection: None,
+                    }),
                 ],
             )
             .await;
@@ -3588,7 +3617,7 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl {
                 children: vec![cm_rust::ChildDecl {
-                    name: "a".to_string(),
+                    name: "a".parse().unwrap(),
                     url: "test:///a".to_string(),
                     startup: fcdecl::StartupMode::Lazy,
                     on_terminate: None,
@@ -3600,7 +3629,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "fuchsia.examples.Hippo".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "fuchsia.examples.Elephant".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         availability: cm_rust::Availability::Optional,
@@ -3609,7 +3638,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "fuchsia.examples.Hippo".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("b".to_string()),
+                        target: offer_target_static_child("b"),
                         target_name: "fuchsia.examples.Elephant".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         availability: cm_rust::Availability::Optional,
@@ -3618,7 +3647,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "config-data".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "config-data".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         rights: Some(fio::RW_STAR_DIR),
@@ -3629,7 +3658,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "config-data".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("b".to_string()),
+                        target: offer_target_static_child("b"),
                         target_name: "config-data".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         rights: Some(fio::RW_STAR_DIR),
@@ -3639,14 +3668,14 @@
                     cm_rust::OfferDecl::Storage(cm_rust::OfferStorageDecl {
                         source: cm_rust::OfferSource::Parent,
                         source_name: "temp".parse().unwrap(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "data".parse().unwrap(),
                         availability: cm_rust::Availability::Optional,
                     }),
                     cm_rust::OfferDecl::Storage(cm_rust::OfferStorageDecl {
                         source: cm_rust::OfferSource::Parent,
                         source_name: "temp".parse().unwrap(),
-                        target: cm_rust::OfferTarget::static_child("b".to_string()),
+                        target: offer_target_static_child("b"),
                         target_name: "data".parse().unwrap(),
                         availability: cm_rust::Availability::Optional,
                     }),
@@ -3654,7 +3683,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "fuchsia.examples.Whale".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "fuchsia.examples.Orca".parse().unwrap(),
                         source_instance_filter: None,
                         renamed_instances: None,
@@ -3664,7 +3693,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "fuchsia.examples.Whale".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("b".to_string()),
+                        target: offer_target_static_child("b"),
                         target_name: "fuchsia.examples.Orca".parse().unwrap(),
                         source_instance_filter: None,
                         renamed_instances: None,
@@ -3674,7 +3703,7 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "b".to_string(),
+                "b".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree { decl: b_decl, children: vec![] },
             )],
@@ -3724,7 +3753,10 @@
                     }),
                 ],
                 fcdecl::Ref::Parent(fcdecl::ParentRef {}),
-                vec![fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None })],
+                vec![fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await;
 
@@ -3732,7 +3764,7 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl {
                 children: vec![cm_rust::ChildDecl {
-                    name: "a".to_string(),
+                    name: "a".parse().unwrap(),
                     url: "test:///a".to_string(),
                     startup: fcdecl::StartupMode::Lazy,
                     on_terminate: None,
@@ -3744,7 +3776,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "fuchsia.examples.Hippo".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "fuchsia.examples.Elephant".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         availability: cm_rust::Availability::SameAsTarget,
@@ -3753,7 +3785,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "config-data".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "config-data".parse().unwrap(),
                         dependency_type: cm_rust::DependencyType::Strong,
                         rights: Some(fio::RW_STAR_DIR),
@@ -3763,7 +3795,7 @@
                     cm_rust::OfferDecl::Storage(cm_rust::OfferStorageDecl {
                         source: cm_rust::OfferSource::Parent,
                         source_name: "temp".parse().unwrap(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "data".parse().unwrap(),
                         availability: cm_rust::Availability::SameAsTarget,
                     }),
@@ -3771,7 +3803,7 @@
                         source: cm_rust::OfferSource::Parent,
                         source_name: "fuchsia.examples.Whale".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: cm_rust::OfferTarget::static_child("a".to_string()),
+                        target: offer_target_static_child("a"),
                         target_name: "fuchsia.examples.Orca".parse().unwrap(),
                         source_instance_filter: None,
                         renamed_instances: None,
@@ -3806,7 +3838,10 @@
                     ..Default::default()
                 })],
                 &fcdecl::Ref::Parent(fcdecl::ParentRef {}),
-                &[fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None })],
+                &[fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await
             .expect("failed to call add_route")
@@ -3837,8 +3872,14 @@
                     name: Some("fuchsia.examples.Hippo".to_owned()),
                     ..Default::default()
                 })],
-                fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None }),
-                vec![fcdecl::Ref::Child(fcdecl::ChildRef { name: "b".into(), collection: None })],
+                fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                }),
+                vec![fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "b".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await;
         realm_and_builder_task
@@ -3847,8 +3888,14 @@
                     name: Some("fuchsia.examples.Hippo".to_owned()),
                     ..Default::default()
                 })],
-                fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None }),
-                vec![fcdecl::Ref::Child(fcdecl::ChildRef { name: "c".into(), collection: None })],
+                fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                }),
+                vec![fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "c".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await;
 
@@ -3857,7 +3904,7 @@
             decl: cm_rust::ComponentDecl {
                 children: vec![
                     cm_rust::ChildDecl {
-                        name: "b".to_string(),
+                        name: "b".parse().unwrap(),
                         url: "test:///b".to_string(),
                         startup: fcdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -3865,7 +3912,7 @@
                         config_overrides: None,
                     },
                     cm_rust::ChildDecl {
-                        name: "c".to_string(),
+                        name: "c".parse().unwrap(),
                         url: "test:///c".to_string(),
                         startup: fcdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -3876,13 +3923,13 @@
                 offers: vec![
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Child(cm_rust::ChildRef {
-                            name: "a".into(),
+                            name: "a".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: "fuchsia.examples.Hippo".parse().unwrap(),
                         source_dictionary: Default::default(),
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "b".into(),
+                            name: "b".parse().unwrap(),
                             collection: None,
                         }),
                         target_name: "fuchsia.examples.Hippo".parse().unwrap(),
@@ -3891,13 +3938,13 @@
                     }),
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Child(cm_rust::ChildRef {
-                            name: "a".into(),
+                            name: "a".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: "fuchsia.examples.Hippo".parse().unwrap(),
                         source_dictionary: Default::default(),
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "c".into(),
+                            name: "c".parse().unwrap(),
                             collection: None,
                         }),
                         target_name: "fuchsia.examples.Hippo".parse().unwrap(),
@@ -3908,7 +3955,7 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "a".to_owned(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree {
                     decl: cm_rust::ComponentDecl {
@@ -4060,8 +4107,14 @@
                     name: Some("fuchsia.examples.Echo".to_owned()),
                     ..Default::default()
                 })],
-                fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None }),
-                vec![fcdecl::Ref::Child(fcdecl::ChildRef { name: "b".into(), collection: None })],
+                fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                }),
+                vec![fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "b".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await;
         realm_and_builder_task
@@ -4070,8 +4123,14 @@
                     name: Some("fuchsia.examples.RandonNumberGenerator".to_owned()),
                     ..Default::default()
                 })],
-                fcdecl::Ref::Child(fcdecl::ChildRef { name: "c".to_owned(), collection: None }),
-                vec![fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None })],
+                fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "c".parse().unwrap(),
+                    collection: None,
+                }),
+                vec![fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                })],
             )
             .await;
 
@@ -4080,7 +4139,7 @@
             decl: cm_rust::ComponentDecl {
                 children: vec![
                     cm_rust::ChildDecl {
-                        name: "b".to_owned(),
+                        name: "b".parse().unwrap(),
                         url: "test:///b".to_owned(),
                         startup: fcdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -4088,7 +4147,7 @@
                         config_overrides: None,
                     },
                     cm_rust::ChildDecl {
-                        name: "c".to_owned(),
+                        name: "c".parse().unwrap(),
                         url: "test:///c".to_owned(),
                         startup: fcdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -4099,13 +4158,13 @@
                 offers: vec![
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Child(cm_rust::ChildRef {
-                            name: "a".into(),
+                            name: "a".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: "fuchsia.examples.Echo".parse().unwrap(),
                         source_dictionary: Default::default(),
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "b".into(),
+                            name: "b".parse().unwrap(),
                             collection: None,
                         }),
                         target_name: "fuchsia.examples.Echo".parse().unwrap(),
@@ -4114,13 +4173,13 @@
                     }),
                     cm_rust::OfferDecl::Protocol(cm_rust::OfferProtocolDecl {
                         source: cm_rust::OfferSource::Child(cm_rust::ChildRef {
-                            name: "c".into(),
+                            name: "c".parse().unwrap(),
                             collection: None,
                         }),
                         source_name: "fuchsia.examples.RandonNumberGenerator".parse().unwrap(),
                         source_dictionary: Default::default(),
                         target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                            name: "a".into(),
+                            name: "a".parse().unwrap(),
                             collection: None,
                         }),
                         target_name: "fuchsia.examples.RandonNumberGenerator".parse().unwrap(),
@@ -4131,7 +4190,7 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "a".to_owned(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree {
                     decl: cm_rust::ComponentDecl {
@@ -4210,12 +4269,12 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree {
                     decl: cm_rust::ComponentDecl {
                         children: vec![cm_rust::ChildDecl {
-                            name: "b".to_string(),
+                            name: "b".parse().unwrap(),
                             url: "test:///b".to_string(),
                             startup: fcdecl::StartupMode::Lazy,
                             on_terminate: None,
@@ -4335,7 +4394,7 @@
         let tree_from_resolver = realm_and_builder_task.call_build_and_get_tree().await;
         let mut expected_tree = ComponentTree {
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree { decl: a_decl, children: vec![] },
             )],
@@ -4347,35 +4406,35 @@
 
     #[test_case(vec![
         create_valid_capability()],
-        fcdecl::Ref::Child(fcdecl::ChildRef { name: "unknown".into(),
+        fcdecl::Ref::Child(fcdecl::ChildRef { name: "unknown".parse().unwrap(),
             collection: None
         }),
         vec![],
         ftest::RealmBuilderError::NoSuchSource ; "no_such_source")]
     #[test_case(vec![
         create_valid_capability()],
-        fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(),
+        fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".parse().unwrap(),
             collection: None
         }),
         vec![
-            fcdecl::Ref::Child(fcdecl::ChildRef { name: "unknown".into(),
+            fcdecl::Ref::Child(fcdecl::ChildRef { name: "unknown".parse().unwrap(),
                 collection: None
             }),
         ],
         ftest::RealmBuilderError::NoSuchTarget ; "no_such_target")]
     #[test_case(vec![
         create_valid_capability()],
-        fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(),
+        fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".parse().unwrap(),
             collection: None
         }),
         vec![
-            fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(),
+            fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".parse().unwrap(),
                 collection: None
             }),
         ],
         ftest::RealmBuilderError::SourceAndTargetMatch ; "source_and_target_match")]
     #[test_case(vec![],
-        fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(),
+        fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".parse().unwrap(),
             collection: None
         }),
         vec![fcdecl::Ref::Parent(fcdecl::ParentRef {})],
@@ -4450,12 +4509,12 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl::default(),
             children: vec![(
-                "a".to_string(),
+                "a".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree {
                     decl: cm_rust::ComponentDecl::default(),
                     children: vec![(
-                        "b".to_string(),
+                        "b".parse().unwrap(),
                         ftest::ChildOptions::default(),
                         ComponentTree { decl: b_decl, children: vec![] },
                     )],
@@ -4632,7 +4691,10 @@
             .realm_proxy
             .read_only_directory(
                 "data",
-                &[fcdecl::Ref::Child(fcdecl::ChildRef { name: "a".into(), collection: None })],
+                &[fcdecl::Ref::Child(fcdecl::ChildRef {
+                    name: "a".parse().unwrap(),
+                    collection: None,
+                })],
                 ftest::DirectoryContents {
                     entries: vec![ftest::DirectoryEntry {
                         file_path: "hippos".to_string(),
@@ -4681,7 +4743,7 @@
         let mut expected_tree = ComponentTree {
             decl: cm_rust::ComponentDecl {
                 children: vec![cm_rust::ChildDecl {
-                    name: "a".to_string(),
+                    name: "a".parse().unwrap(),
                     url: "test://a".to_string(),
                     startup: fcdecl::StartupMode::Lazy,
                     environment: None,
@@ -4690,13 +4752,13 @@
                 }],
                 offers: vec![cm_rust::OfferDecl::Directory(cm_rust::OfferDirectoryDecl {
                     source: cm_rust::OfferSource::Child(cm_rust::ChildRef {
-                        name: "read-only-directory-0".into(),
+                        name: "read-only-directory-0".parse().unwrap(),
                         collection: None,
                     }),
                     source_name: "data".parse().unwrap(),
                     source_dictionary: Default::default(),
                     target: cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                        name: "a".into(),
+                        name: "a".parse().unwrap(),
                         collection: None,
                     }),
                     target_name: "data".parse().unwrap(),
@@ -4708,7 +4770,7 @@
                 ..cm_rust::ComponentDecl::default()
             },
             children: vec![(
-                "read-only-directory-0".to_string(),
+                "read-only-directory-0".parse().unwrap(),
                 ftest::ChildOptions::default(),
                 ComponentTree { decl: read_only_dir_decl, children: vec![] },
             )],
diff --git a/src/lib/fuchsia-component-test/tests/src/lib.rs b/src/lib/fuchsia-component-test/tests/src/lib.rs
index 5d78dd0..5a56f8b 100644
--- a/src/lib/fuchsia-component-test/tests/src/lib.rs
+++ b/src/lib/fuchsia-component-test/tests/src/lib.rs
@@ -340,7 +340,7 @@
     let mut root_decl = builder.get_realm_decl().await?;
     assert_eq!(root_decl, cm_rust::ComponentDecl::default());
     root_decl.children.push(cm_rust::ChildDecl {
-        name: "example-child".to_string(),
+        name: "example-child".parse().unwrap(),
         url: "example://url".to_string(),
         startup: fcdecl::StartupMode::Eager,
         on_terminate: None,
@@ -359,7 +359,7 @@
         builder.add_local_child("child", |_| pending().boxed(), ChildOptions::new()).await?;
     let mut child_decl = builder.get_component_decl(&child).await?;
     child_decl.children.push(cm_rust::ChildDecl {
-        name: "example-grand-child".to_string(),
+        name: "example-grand-child".parse().unwrap(),
         url: "example://url".to_string(),
         startup: fcdecl::StartupMode::Eager,
         on_terminate: None,
diff --git a/src/lib/fuchsia/macro/src/lib.rs b/src/lib/fuchsia/macro/src/lib.rs
index 97698b5..b87ef24 100644
--- a/src/lib/fuchsia/macro/src/lib.rs
+++ b/src/lib/fuchsia/macro/src/lib.rs
@@ -17,6 +17,7 @@
 ///  - `logging_tags` - optional list of string to be used as tags for logs. Default: None.
 ///  - `logging_minimum_severity` - optional minimum severity to be set for logs. Default: None,
 ///                                 the logging library will choose it (typically `info`).
+///  - `logging_panic_prefix` - optional string indicating the panic message prefix to log
 ///
 /// The main function can return either () or a Result<(), E> where E is an error type.
 #[proc_macro_attribute]
@@ -37,6 +38,7 @@
 ///  - `logging_tags` - optional list of string to be used as tags for logs. Default: None.
 ///  - `logging_minimum_severity` - optional minimum severity to be set for logs. Default: None,
 ///                                 the logging library will choose it (typically `info`).
+///  - `logging_panic_prefix` - optional string indicating the panic message prefix to log
 ///  - `allow_stalls`  - boolean toggle for whether the async test is allowed to stall during
 ///                      execution (if true), or whether the function must complete without pausing
 ///                      (if false).
diff --git a/src/lib/fuchsia/macro/src/transformer.rs b/src/lib/fuchsia/macro/src/transformer.rs
index 0daf5ac..51a5633 100644
--- a/src/lib/fuchsia/macro/src/transformer.rs
+++ b/src/lib/fuchsia/macro/src/transformer.rs
@@ -84,6 +84,7 @@
     logging: bool,
     logging_blocking: bool,
     logging_tags: LoggingTags,
+    panic_prefix: LitStr,
     interest: Interest,
     add_test_attr: bool,
 }
@@ -95,6 +96,7 @@
     logging_blocking: bool,
     logging_tags: LoggingTags,
     interest: Interest,
+    panic_prefix: Option<LitStr>,
     add_test_attr: bool,
 }
 
@@ -240,6 +242,7 @@
             logging: true,
             logging_blocking: false,
             logging_tags: LoggingTags::default(),
+            panic_prefix: None,
             interest: Interest::default(),
             add_test_attr: true,
         };
@@ -257,6 +260,7 @@
                 "logging_blocking" => args.logging_blocking = get_bool_arg(&input, true)?,
                 "logging_tags" => args.logging_tags = get_logging_tags(&input)?,
                 "logging_minimum_severity" => args.interest = get_interest_arg(&input)?,
+                "logging_panic_prefix" => args.panic_prefix = Some(get_arg(&input)?),
                 "add_test_attr" => args.add_test_attr = get_bool_arg(&input, true)?,
                 x => return err(format!("unknown argument: {}", x)),
             }
@@ -316,6 +320,8 @@
             (_, Some(true) | None, false, _) => return err("must be async to use >1 thread"),
         };
 
+        let panic_prefix =
+            args.panic_prefix.unwrap_or_else(|| LitStr::new("PANIC", sig.ident.span()));
         Ok(Transformer {
             executor,
             attrs,
@@ -325,6 +331,7 @@
             logging: args.logging,
             logging_blocking: args.logging_blocking,
             logging_tags: args.logging_tags,
+            panic_prefix,
             interest: args.interest,
             add_test_attr: args.add_test_attr,
         })
@@ -344,6 +351,7 @@
         let inputs = self.sig.inputs;
         let logging_blocking = self.logging_blocking;
         let mut logging_tags = self.logging_tags;
+        let panic_prefix = self.panic_prefix;
         let interest = self.interest;
 
         let mut func_attrs = Vec::new();
@@ -353,42 +361,32 @@
             quote! { func }
         } else if self.executor.is_test() {
             logging_tags.tags.insert(0, format!("{ident}"));
+            let logging_options = quote! {
+                ::fuchsia::LoggingOptions {
+                    blocking: #logging_blocking,
+                    interest: #interest,
+                    tags: &[#logging_tags],
+                    panic_prefix: #panic_prefix,
+                }
+            };
             if self.executor.is_some() {
-                quote! {
-                    ::fuchsia::init_logging_for_test_with_executor(func, ::fuchsia::LoggingOptions {
-                        blocking: #logging_blocking,
-                        interest: #interest,
-                        tags: &[#logging_tags],
-                    })
-                }
+                quote!(::fuchsia::init_logging_for_test_with_executor(func, #logging_options))
             } else {
-                quote! {
-                    ::fuchsia::init_logging_for_test_with_threads(func, ::fuchsia::LoggingOptions {
-                        blocking: #logging_blocking,
-                        interest: #interest,
-                        tags: &[#logging_tags],
-                    })
-                }
+                quote!(::fuchsia::init_logging_for_test_with_threads(func, #logging_options))
             }
         } else {
+            let logging_options = quote! {
+                ::fuchsia::LoggingOptions {
+                    blocking: #logging_blocking,
+                    interest: #interest,
+                    tags: &[#logging_tags],
+                    panic_prefix: #panic_prefix,
+                }
+            };
             if self.executor.is_some() {
-                quote! {
-                    ::fuchsia::init_logging_for_component_with_executor(
-                        func, ::fuchsia::LoggingOptions {
-                            blocking: #logging_blocking,
-                            interest: #interest,
-                            tags: &[#logging_tags],
-                        })
-                }
+                quote!(::fuchsia::init_logging_for_component_with_executor(func, #logging_options))
             } else {
-                quote! {
-                    ::fuchsia::init_logging_for_component_with_threads(
-                        func, ::fuchsia::LoggingOptions {
-                            blocking: #logging_blocking,
-                            interest: #interest,
-                            tags: &[#logging_tags],
-                        })
-                }
+                quote!(::fuchsia::init_logging_for_component_with_threads(func, #logging_options))
             }
         };
 
diff --git a/src/lib/fuchsia/src/lib.rs b/src/lib/fuchsia/src/lib.rs
index d34a982..7453116 100644
--- a/src/lib/fuchsia/src/lib.rs
+++ b/src/lib/fuchsia/src/lib.rs
@@ -40,6 +40,9 @@
     ///
     /// NOTE: this is ignored on `host`.
     pub blocking: bool,
+
+    /// String to include in logged panic messages.
+    pub panic_prefix: &'static str,
 }
 
 #[cfg(not(target_os = "fuchsia"))]
@@ -49,6 +52,7 @@
         if let Some(severity) = logging.interest.min_severity {
             options = options.minimum_severity(severity);
         }
+        options = options.panic_prefix(logging.panic_prefix);
         options
     }
 }
@@ -61,6 +65,7 @@
         if let Some(severity) = logging.interest.min_severity {
             options = options.minimum_severity(severity);
         }
+        options = options.panic_prefix(logging.panic_prefix);
         options
     }
 }
diff --git a/src/lib/loader_service/loader_service.cc b/src/lib/loader_service/loader_service.cc
index a173191..16166ba 100644
--- a/src/lib/loader_service/loader_service.cc
+++ b/src/lib/loader_service/loader_service.cc
@@ -27,11 +27,7 @@
 }
 
 zx::result<fidl::ClientEnd<fuchsia_ldsvc::Loader>> LoaderServiceBase::Connect() {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_ldsvc::Loader>();
-  if (endpoints.is_error()) {
-    return endpoints.take_error();
-  }
-  auto [client, server] = *std::move(endpoints);
+  auto [client, server] = fidl::Endpoints<fuchsia_ldsvc::Loader>::Create();
   Bind(std::move(server));
   return zx::ok(std::move(client));
 }
diff --git a/src/lib/loader_service/loader_service_test.cc b/src/lib/loader_service/loader_service_test.cc
index 0b85dd5..f490d3e 100644
--- a/src/lib/loader_service/loader_service_test.cc
+++ b/src/lib/loader_service/loader_service_test.cc
@@ -45,9 +45,7 @@
 
   // Should be able to still make new connections.
   {
-    auto endpoints = fidl::CreateEndpoints<fldsvc::Loader>();
-    ASSERT_TRUE(endpoints.is_ok());
-    auto [client_end, server_end] = *std::move(endpoints);
+    auto [client_end, server_end] = fidl::Endpoints<fldsvc::Loader>::Create();
     loader->Bind(std::move(server_end));
     fidl::WireSyncClient<fldsvc::Loader> client(std::move(client_end));
     EXPECT_NO_FATAL_FAILURE(LoadObject(client, "libfoo.so", zx::ok("science")));
@@ -86,9 +84,7 @@
   loader.reset();
 
   // Should still be able to Clone any open connection.
-  zx::result endpoints = fidl::CreateEndpoints<fldsvc::Loader>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fldsvc::Loader>::Create();
   auto result = client2->Clone(std::move(server));
   ASSERT_TRUE(result.ok());
   ASSERT_OK(result->rv);
@@ -204,9 +200,7 @@
   EXPECT_NO_FATAL_FAILURE(LoadObject(client, "libasan_only.so", zx::ok("lives")));
   EXPECT_NO_FATAL_FAILURE(LoadObject(client, "libno_san.so", zx::ok("matter")));
 
-  zx::result endpoints = fidl::CreateEndpoints<fldsvc::Loader>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client2, server] = endpoints.value();
+  auto [client2, server] = fidl::Endpoints<fldsvc::Loader>::Create();
   auto result = client->Clone(std::move(server));
   ASSERT_TRUE(result.ok());
   ASSERT_OK(result->rv);
diff --git a/src/lib/loader_service/loader_service_test_fixture.cc b/src/lib/loader_service/loader_service_test_fixture.cc
index 2c93494..27380e7 100644
--- a/src/lib/loader_service/loader_service_test_fixture.cc
+++ b/src/lib/loader_service/loader_service_test_fixture.cc
@@ -60,9 +60,7 @@
     ASSERT_NO_FATAL_FAILURE(AddDirectoryEntry(root_dir_, entry));
   }
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(endpoints.status_value());
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
   ASSERT_OK(vfs_->ServeDirectory(fbl::RefPtr(root_dir_), std::move(server)));
 
   // Must start fs_loop before fdio_fd_create, since that will attempt to Describe the directory.
diff --git a/src/lib/memory_barriers/BUILD.gn b/src/lib/memory_barriers/BUILD.gn
index 63168d7..c748d61 100644
--- a/src/lib/memory_barriers/BUILD.gn
+++ b/src/lib/memory_barriers/BUILD.gn
@@ -2,6 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("memory_barriers") {
+import("//build/cpp/sdk_source_set.gni")
+
+sdk_source_set("memory_barriers") {
+  category = "internal"
+  sdk_name = "memory_barriers"
+  include_base = "//"
   sources = [ "memory_barriers.h" ]
 }
diff --git a/src/lib/syslog/rust/BUILD.gn b/src/lib/syslog/rust/BUILD.gn
index d0bafd8..15bff29 100644
--- a/src/lib/syslog/rust/BUILD.gn
+++ b/src/lib/syslog/rust/BUILD.gn
@@ -25,7 +25,7 @@
   visibility = [
     "//examples/diagnostics/logs/rust:*",
     "//src/diagnostics/archivist:*",
-    "//src/diagnostics/archivist/tests/integration:*",
+    "//src/diagnostics/archivist/tests/integration/test_cases:*",
     "//src/diagnostics/log_listener:*",
     "//src/lib/syslog/rust:*",
     "//src/recovery/system:*",
diff --git a/src/lib/test-suite/test_suite.cc b/src/lib/test-suite/test_suite.cc
index 08fa076..7eff4db 100644
--- a/src/lib/test-suite/test_suite.cc
+++ b/src/lib/test-suite/test_suite.cc
@@ -121,7 +121,7 @@
 bool TestSuite::ShouldSkipTest(const fuchsia::test::RunOptions& run_options,
                                const std::string& test_name) const {
   // Disabled tests are excluded && this test is disabled.
-  return !run_options.include_disabled_tests() &&
+  return run_options.has_include_disabled_tests() && !run_options.include_disabled_tests() &&
          (disabled_tests_.find(test_name) != disabled_tests_.end());
 }
 
diff --git a/src/lib/ubsan-custom/BUILD.gn b/src/lib/ubsan-custom/BUILD.gn
new file mode 100644
index 0000000..33dce4e
--- /dev/null
+++ b/src/lib/ubsan-custom/BUILD.gn
@@ -0,0 +1,76 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This enables both the ubsan checking that happens in normal application code,
+# and also some non-default checks that are a good idea for the kind of
+# low-level and highly sensitive code likely to need a custom runtime.
+_ubsan_sanitizers = [
+  "undefined",
+
+  # Checks whether an implicit truncation caused data loss. It's not
+  # undefined behavior but most of the time it is unintentional.
+  "implicit-integer-truncation",
+
+  # The kernel has some _Nonnull annotations, this would check
+  # them at runtime.
+  "nullability",
+]
+
+config("ubsan") {
+  cflags = []
+  foreach(sanitizer, _ubsan_sanitizers) {
+    cflags += [ "-fsanitize=$sanitizer" ]
+  }
+
+  # The ubsan variant adds rtti, but that is not used by the kernel variant.
+  configs = [ "//build/config:no_rtti" ]
+}
+
+# This disables all those, and can be appended to a configs list that has the
+# "ubsan" config earlier in its list, or to one that doesn't.
+config("no-ubsan") {
+  cflags = []
+  foreach(sanitizer, _ubsan_sanitizers) {
+    cflags += [ "-fno-sanitize=$sanitizer" ]
+  }
+}
+
+# This should only be in the deps of a source_set() for the single source file
+# that does `#include <lib/ubsan-custom/handlers.h>`.
+source_set("handlers") {
+  public = [ "handlers.h" ]
+  public_deps = [ ":types" ]
+
+  # The handlers themselves shouldn't be compiled with instrumentation, so
+  # apply a config to the dependent source_set() to disable it.  Disabling it
+  # on the command-line not only saves adding NO_UBSAN annotations to each
+  # function, but covers inline functions from shared header files that
+  # shouldn't all be annotated for their other callers.  The former could be
+  # addressed via `#pragma clang attribute`, but the latter cannot be.
+  public_configs = [ ":no-ubsan" ]
+
+  # This is meant to be read by authors depending on this target, but not
+  # `#include`d in their code; they use only `<lib/ubsan-custom/handlers.h>`.
+  # Since it contains `inline` declarations for functions not defined, it's
+  # meant to generate warnings if it's included in any translation unit other
+  # than the single one that should define those functions.
+  sources = [ "report.h" ]
+}
+
+# This can be used freely, for example if a custom ubsan::Report implementation
+# wants to pass ubsan::SourceLocation to other code outside the single-file
+# source_set() that includes <lib/ubsan-commit/handlers.h>.
+source_set("types") {
+  public = [ "types.h" ]
+  public_configs = [ ":includes" ]
+}
+
+config("includes") {
+  visibility = [ ":*" ]
+  include_dirs = [ "//src" ]
+}
+
+group("tests") {
+  testonly = true
+}
diff --git a/src/lib/ubsan-custom/OWNERS b/src/lib/ubsan-custom/OWNERS
new file mode 100644
index 0000000..96c33a4
--- /dev/null
+++ b/src/lib/ubsan-custom/OWNERS
@@ -0,0 +1,4 @@
+leonardchan@google.com
+mcgrathr@google.com
+mvanotti@google.com
+phosek@google.com
diff --git a/src/lib/ubsan-custom/README.md b/src/lib/ubsan-custom/README.md
new file mode 100644
index 0000000..114b924
--- /dev/null
+++ b/src/lib/ubsan-custom/README.md
@@ -0,0 +1,19 @@
+# Minimal UndefinedBehaviorSanitizer for custom embedded uses
+
+This is a small header-only library that makes it simple to define the runtime
+required by (UndefinedBehaviorSanitizer)[ubsan].  The runtime implementations
+in LLVM's compiler-rt, even the "minimal" one, cannot fit into custom build
+situations such as kernel or embedded code, for a variety of reasons.
+
+**TODO(https://fxbug.dev/334165273):**
+This may be upstreamed into LLVM in the future, removing the need
+for this separate header library.
+
+[ubsan]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
+
+## Embedder API
+
+The `<lib/ubsan-custom/ubsan-report.h>` header file describes the few functions
+that the embedder must define.  These have to take care of printing messages
+via a `printf`-style API; and whatever it should look to prepare for a problem
+report or panic before printing details and to panic afterwards.
diff --git a/src/lib/ubsan-custom/handlers.h b/src/lib/ubsan-custom/handlers.h
new file mode 100644
index 0000000..f7db01d
--- /dev/null
+++ b/src/lib/ubsan-custom/handlers.h
@@ -0,0 +1,189 @@
+// Copyright 2024 The Fuchsia Authors
+//
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT
+
+#ifndef SRC_LIB_UBSAN_CUSTOM_HANDLERS_H_
+#define SRC_LIB_UBSAN_CUSTOM_HANDLERS_H_
+
+#include <stdint.h>
+
+#include "report.h"
+#include "types.h"
+
+// This implements a minimal ubsan runtime.  This header should be included by
+// one and only one translation unit (source file).  The including code must
+// also define the interfaces described in "ubsan-report.h".  That file should
+// not be included directly but only included via this file and only in the one
+// translation unit that defines those interfaces.
+//
+// The rest of this file is implementation detail.
+
+namespace [[gnu::visibility("hidden")]] ubsan {
+
+// LLVM provides no documentation on the ABI between the compiler and
+// the runtime.  The set of function signatures here was culled from
+// the LLVM sources for the compiler instrumentation and the runtime.
+//
+// See
+// https://github.com/llvm/llvm-project/tree/eb8ebabfb0efcae69e682b592f12366c3b82e78d/compiler-rt/lib/ubsan
+
+inline void PrintTypeDescriptor(const TypeDescriptor& type, const char* prefix = nullptr) {
+  // TODO(https://fxbug.dev/42056251): Improve logging by interpreting TypeDescriptor values.
+  Printf("%s%sType Kind (0x%04hx)\tInfo (0x%04hx)\tName %s\n", prefix ? prefix : "",
+         prefix ? ":" : "", type.TypeKind, type.TypeInfo, type.TypeName);
+}
+
+// All the runtime handlers have unmangled C-style external linkage names.
+extern "C" {
+
+// Declare each function `inline` so that it has "vague linkage", i.e. COMDAT
+// semantics; that's really just to be entirely proper for a header file in
+// case this were included in more than one TU though it ought not be.  Then
+// use `[[gnu::noinline]]` to make sure that LTO doesn't try to inline these to
+// their call sites, primarily so that the `__builtin_return_address(0)` in the
+// default argument to each Report constructor will be a useful call site
+// address for each instance.  Since they have vague linkage, the compiler's
+// front end usually won't emit them at all in a TU where it doesn't see any
+// references.  So also use `[[gnu::used]]` to tell the compiler that each
+// function is used by some kind of linkage it can't understand.  When the
+// later instrumentation passes add in the calls to the runtime handlers, their
+// linkage will resolve happily.  If an individual function is never actually
+// called by any generated code, then --gc-sections will drop its COMDAT group.
+//
+// Vague linkage (via ELF COMDAT) also means that these definitions will
+// implicitly have weak linkage, so if there is an alternative ubsan runtime
+// implementation linked in (e.g. from the compiler's prebuilt libraries meant
+// for the default build environment), its functions will take precedence.
+#define UBSAN_HANDLER [[gnu::used, gnu::noinline]] inline void
+
+UBSAN_HANDLER __ubsan_handle_nonnull_arg(NonNullArgData* Data) {
+  Report failure("NULL ARG passed to NonNullarg parameter.", Data->Loc);
+}
+
+UBSAN_HANDLER __ubsan_handle_type_mismatch_v1(TypeMismatchData* Data, ValueHandle Pointer) {
+  Report failure("Type Mismatch", Data->Loc);
+
+  const uintptr_t Alignment = (uintptr_t)1 << Data->LogAlignment;
+  const uintptr_t AlignmentMask = Alignment - 1;
+
+  Printf("Pointer: 0x%016lx\n", Pointer);
+  Printf("Alignment: 0x%lx bytes\n", Alignment);
+
+  if (Pointer & AlignmentMask) {
+    Printf("%s misaligned address 0x%016lx\n", TypeCheckKindMsg(Data->TypeCheckKind), Pointer);
+  } else {
+    Printf("TypeCheck Kind: %s (0x%hhx)\n", TypeCheckKindMsg(Data->TypeCheckKind),
+           Data->TypeCheckKind);
+  }
+
+  PrintTypeDescriptor(Data->Type);
+}
+
+UBSAN_HANDLER __ubsan_handle_function_type_mismatch(FunctionTypeMismatchData* Data,
+                                                    ValueHandle Val) {
+  Report failure("Function Type Mismatch", Data->Loc);
+
+  PrintTypeDescriptor(Data->Type);
+}
+
+#define UBSAN_OVERFLOW_HANDLER(handler_name, op)                                     \
+  UBSAN_HANDLER handler_name(OverflowData* Data, ValueHandle LHS, ValueHandle RHS) { \
+    Report failure("Integer " op " overflow\n", Data->Loc);                          \
+    Printf("LHS: 0x%016lx\n", LHS);                                                  \
+    Printf("RHS: 0x%016lx\n", RHS);                                                  \
+    PrintTypeDescriptor(Data->Type);                                                 \
+  }
+
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "ADD")
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "MUL")
+UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "SUB")
+
+#undef UBSAN_OVERFLOW_HANDLER
+
+UBSAN_HANDLER __ubsan_handle_divrem_overflow(OverflowData* Data, ValueHandle LHS, ValueHandle RHS,
+                                             ReportOptions Opts) {
+  Report failure("Integer DIVREM overflow", Data->Loc);
+  Printf("LHS: 0x%016lx\n", LHS);
+  Printf("RHS: 0x%016lx\n", RHS);
+  PrintTypeDescriptor(Data->Type);
+}
+
+UBSAN_HANDLER __ubsan_handle_negate_overflow(OverflowData* Data, ValueHandle OldVal) {
+  Report failure("Integer NEGATE overflow", Data->Loc);
+  Printf("old value: 0x%016lx\n", OldVal);
+  PrintTypeDescriptor(Data->Type);
+}
+
+UBSAN_HANDLER __ubsan_handle_load_invalid_value(InvalidValueData* Data, ValueHandle Val) {
+  Report failure("Load invalid value into enum/bool", Data->Loc);
+  Printf("Val: 0x%016lx\n", Val);
+  PrintTypeDescriptor(Data->Type);
+}
+
+UBSAN_HANDLER __ubsan_handle_implicit_conversion(ImplicitConversionData* Data, ValueHandle Src,
+                                                 ValueHandle Dst) {
+  Report failure("Implicit Conversion", Data->Loc);
+  Printf("Src: 0x%016lx\n", Src);
+  Printf("Dst: 0x%016lx\n", Dst);
+  PrintTypeDescriptor(Data->FromType, "From");
+  PrintTypeDescriptor(Data->ToType, "To");
+}
+
+UBSAN_HANDLER __ubsan_handle_out_of_bounds(OutOfBoundsData* Data, ValueHandle Index) {
+  Report failure("Out of bounds access", Data->Loc);
+  Printf("Index: 0x%016lx\n", Index);
+  PrintTypeDescriptor(Data->ArrayType, "Array");
+  PrintTypeDescriptor(Data->IndexType, "Index");
+}
+
+UBSAN_HANDLER __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData* Data, ValueHandle LHS,
+                                                 ValueHandle RHS) {
+  Report failure("SHIFT overflow", Data->Loc);
+  Printf("LHS: 0x%016lx\n", LHS);
+  Printf("RHS: 0x%016lx\n", RHS);
+  PrintTypeDescriptor(Data->LHSType, "LHS");
+  PrintTypeDescriptor(Data->RHSType, "RHS");
+}
+
+UBSAN_HANDLER __ubsan_handle_pointer_overflow(PointerOverflowData* Data, ValueHandle Base,
+                                              ValueHandle Result) {
+  Report failure("POINTER overflow", Data->Loc);
+  Printf("Base: 0x%016lx\n", Base);
+  Printf("Result: 0x%016lx\n", Result);
+}
+
+UBSAN_HANDLER __ubsan_handle_builtin_unreachable(UnreachableData* Data) {
+  Report failure("Executed unreachable code", Data->Loc);
+}
+
+UBSAN_HANDLER __ubsan_handle_alignment_assumption(AlignmentAssumptionData* Data,
+                                                  ValueHandle Pointer, ValueHandle Alignment,
+                                                  ValueHandle Offset) {
+  Report failure("Alignment Assumption violation", Data->Loc);
+  PrintTypeDescriptor(Data->Type);
+  Printf("Pointer: 0x%016lx\n", Pointer);
+  Printf("Alignment: 0x%016lx\n", Alignment);
+  Printf("Offset: 0x%016lx\n", Offset);
+}
+
+// TODO(https://fxbug.dev/42056251): Add missing handlers:
+// * invalid_builtin
+// * nonnull_return_v1
+// * nullability_return_v1
+// * nullability_arg
+// * cfi_check_fail
+// * cfi_bad_type
+
+// NOTE: The following functions should never be generated in the kernel ubsan:
+//  * missing_return
+//  * vla_bound_not_positive
+//  * float_cast_overflow
+
+#undef UBSAN_HANDLER
+
+}  // extern "C"
+}  // namespace ubsan
+
+#endif  // SRC_LIB_UBSAN_CUSTOM_HANDLERS_H_
diff --git a/src/lib/ubsan-custom/report.h b/src/lib/ubsan-custom/report.h
new file mode 100644
index 0000000..62a8447
--- /dev/null
+++ b/src/lib/ubsan-custom/report.h
@@ -0,0 +1,78 @@
+// Copyright 2024 The Fuchsia Authors
+//
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT
+
+#ifndef SRC_LIB_UBSAN_CUSTOM_REPORT_H_
+#define SRC_LIB_UBSAN_CUSTOM_REPORT_H_
+
+#include <stdarg.h>
+
+#include "types.h"
+
+// This file declares the interfaces that must be supplied by the embedder.
+// The ubsan-handlers.h implementations use these things to report specific
+// kinds of check failures.
+//
+// This header should only actually be included indirectly via ubsan-handlers.h
+// but is separate to isolate the embedder API contract for readability.
+//
+// There are three functions (Report constructor, Report destructor, VPrintf)
+// declared here as `inline` but not defined in this file.  This means the
+// compiler will warn if the embedder does not define all of these functions
+// all in the same translation unit where ubsan-handlers.h is included:
+//
+// ```
+// ubsan::Report::Report(...) { ... }
+// ubsan::Report::~Report() { ... }
+// void ubsan::VPrintf(const char* fmt, ...) { ... }
+// ```
+
+namespace [[gnu::visibility("hidden")]] ubsan {
+
+// Each ubsan handler starts by creating a ubsan::Report object to indicate
+// that a report is commencing.  The constructor arguments give the name of the
+// failing check, source location details, and the PC and FP of the check's
+// call site.  The constructor implementation is expected to log an opening
+// message with that information presented however it chooses, but presumed to
+// be in whole lines.  It then uses ubsan::Printf to print additional
+// information about the specific check, usually making one call per line with
+// "\n" ending the format string.  Finally the Report object is destroyed when
+// there are no more details to describe.  The destructor implementation may or
+// may not return.  Usually check failures cause an immediate panic, but the
+// implementation can choose to just return and let execution continue, where
+// it might hit more check failures and report more details before crashing.
+struct Report {
+  Report() = delete;
+  Report(const Report&) = delete;
+
+  // The check string is a sentence or thereabouts usually with no punctuation.
+  // The default arguments are evaluated in the context of the ubsan handler
+  // function itself (which cannot be inlined), so they should always indicate
+  // the actual call site for the specific ubsan check failure and might be
+  // used for deduplication or log-throttling, etc.
+  inline explicit Report(const char* check, const SourceLocation& loc,
+                         void* caller = __builtin_return_address(0),
+                         void* frame = __builtin_frame_address(0));
+
+  //
+  inline ~Report();
+};
+
+// This must be defined to function that is called like vprintf.
+// It will be used by handlers
+inline void VPrintf(const char* fmt, va_list args);
+
+// This is is used by the handlers directly, and just calls VPrintf.
+// The Report method implementations can use this too if it's convenient.
+[[gnu::format(printf, 1, 2)]] inline void Printf(const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  VPrintf(fmt, args);
+  va_end(args);
+}
+
+}  // namespace ubsan
+
+#endif  // SRC_LIB_UBSAN_CUSTOM_REPORT_H_
diff --git a/src/lib/ubsan-custom/types.h b/src/lib/ubsan-custom/types.h
new file mode 100644
index 0000000..ba91144
--- /dev/null
+++ b/src/lib/ubsan-custom/types.h
@@ -0,0 +1,186 @@
+// Copyright 2023 The Fuchsia Authors
+//
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT
+
+#ifndef SRC_LIB_UBSAN_CUSTOM_TYPES_H_
+#define SRC_LIB_UBSAN_CUSTOM_TYPES_H_
+
+#include <stdint.h>
+
+// These are the types used in the LLVM UndefinedBehaviorSanitizer runtime
+// calls emitted by the compiler.  LLVM provides no documentation on the ABI
+// between the compiler and the runtime.  The types here signatures here were
+// culled from the LLVM sources for the compiler instrumentation and runtime.
+//
+// See
+// https://github.com/llvm/llvm-project/tree/eb8ebabfb0efcae69e682b592f12366c3b82e78d/compiler-rt/lib/ubsan
+
+namespace ubsan {
+
+/// Situations in which we might emit a check for the suitability of a
+/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in
+/// clang.
+enum TypeCheckKind : uint8_t {
+  /// Checking the operand of a load. Must be suitably sized and aligned.
+  TCK_Load,
+  /// Checking the destination of a store. Must be suitably sized and aligned.
+  TCK_Store,
+  /// Checking the bound value in a reference binding. Must be suitably sized
+  /// and aligned, but is not required to refer to an object (until the
+  /// reference is used), per core issue 453.
+  TCK_ReferenceBinding,
+  /// Checking the object expression in a non-static data member access. Must
+  /// be an object within its lifetime.
+  TCK_MemberAccess,
+  /// Checking the 'this' pointer for a call to a non-static member function.
+  /// Must be an object within its lifetime.
+  TCK_MemberCall,
+  /// Checking the 'this' pointer for a constructor call.
+  TCK_ConstructorCall,
+  /// Checking the operand of a static_cast to a derived pointer type. Must be
+  /// null or an object within its lifetime.
+  TCK_DowncastPointer,
+  /// Checking the operand of a static_cast to a derived reference type. Must
+  /// be an object within its lifetime.
+  TCK_DowncastReference,
+  /// Checking the operand of a cast to a base object. Must be suitably sized
+  /// and aligned.
+  TCK_Upcast,
+  /// Checking the operand of a cast to a virtual base object. Must be an
+  /// object within its lifetime.
+  TCK_UpcastToVirtualBase,
+  /// Checking the value assigned to a _Nonnull pointer. Must not be null.
+  TCK_NonnullAssign,
+  /// Checking the operand of a dynamic_cast or a typeid expression.  Must be
+  /// null or an object within its lifetime.
+  TCK_DynamicOperation
+};
+
+constexpr const char* TypeCheckKindMsg(TypeCheckKind kind) {
+  switch (kind) {
+    case TCK_Load:
+      return "load of";
+    case TCK_Store:
+      return "store to";
+    case TCK_ReferenceBinding:
+      return "reference binding to";
+    case TCK_MemberAccess:
+      return "member access within";
+    case TCK_MemberCall:
+      return "member call on";
+    case TCK_ConstructorCall:
+      return "constructor call on";
+    case TCK_DowncastPointer:
+    case TCK_DowncastReference:
+      return "downcast of";
+    case TCK_Upcast:
+      return "upcast of";
+    case TCK_UpcastToVirtualBase:
+      return "cast to virtual base of";
+    case TCK_NonnullAssign:
+      return "_Nonnull binding to";
+    case TCK_DynamicOperation:
+      return "dynamic operation on";
+    default:
+      return "UBSAN BUG! Invalid TypeCheckKind";
+  }
+}
+
+struct SourceLocation {
+  const char* filename;
+  uint32_t line;
+  uint32_t column;
+};
+
+struct TypeDescriptor {
+  uint16_t TypeKind;
+  uint16_t TypeInfo;
+  char TypeName[];
+};
+
+struct NonNullArgData {
+  SourceLocation Loc;
+  SourceLocation AttrLoc;
+  int32_t ArgIndex;
+};
+
+struct TypeMismatchData {
+  SourceLocation Loc;
+  const TypeDescriptor& Type;
+  uint8_t LogAlignment;
+  TypeCheckKind TypeCheckKind;
+};
+
+struct FunctionTypeMismatchData {
+  SourceLocation Loc;
+  const TypeDescriptor& Type;
+};
+
+struct UnreachableData {
+  SourceLocation Loc;
+};
+
+struct AlignmentAssumptionData {
+  SourceLocation Loc;
+  SourceLocation AssumptionLoc;
+  const TypeDescriptor& Type;
+};
+
+using ValueHandle = uintptr_t;
+
+struct OverflowData {
+  SourceLocation Loc;
+  const TypeDescriptor& Type;
+};
+
+struct ReportOptions {
+  // If FromUnrecoverableHandler is specified, UBSan runtime handler is not
+  // expected to return.
+  bool FromUnrecoverableHandler;
+  /// pc/bp are used to unwind the stack trace.
+  uintptr_t pc;
+  uintptr_t bp;
+};
+
+struct InvalidValueData {
+  SourceLocation Loc;
+  const TypeDescriptor& Type;
+};
+
+// Known implicit conversion check kinds.
+enum ImplicitConversionCheckKind : uint8_t {
+  ICCK_IntegerTruncation = 0,  // Legacy, was only used by clang 7.
+  ICCK_UnsignedIntegerTruncation = 1,
+  ICCK_SignedIntegerTruncation = 2,
+  ICCK_IntegerSignChange = 3,
+  ICCK_SignedIntegerTruncationOrSignChange = 4,
+};
+
+struct ImplicitConversionData {
+  SourceLocation Loc;
+  const TypeDescriptor& FromType;
+  const TypeDescriptor& ToType;
+  ImplicitConversionCheckKind Kind;
+};
+
+struct OutOfBoundsData {
+  SourceLocation Loc;
+  const TypeDescriptor& ArrayType;
+  const TypeDescriptor& IndexType;
+};
+
+struct ShiftOutOfBoundsData {
+  SourceLocation Loc;
+  const TypeDescriptor& LHSType;
+  const TypeDescriptor& RHSType;
+};
+
+struct PointerOverflowData {
+  SourceLocation Loc;
+};
+
+}  // namespace ubsan
+
+#endif  // SRC_LIB_UBSAN_CUSTOM_TYPES_H_
diff --git a/src/lib/ui/carnelian/BUILD.gn b/src/lib/ui/carnelian/BUILD.gn
index 15a60a5..ed34fd74 100644
--- a/src/lib/ui/carnelian/BUILD.gn
+++ b/src/lib/ui/carnelian/BUILD.gn
@@ -136,10 +136,12 @@
 
 config("carnelian-performance") {
   # Enable all optimizations that benefit speed, even if they increase size
-  configs = [
-    "//build/config:optimize_speed",
-    "//build/config/lto:thinlto",
-  ]
+  configs = [ "//build/config:optimize_speed" ]
+
+  # Add thinlto config if lto variants are not used.
+  if (!is_lto_variant) {
+    configs += [ "//build/config/lto:thinlto" ]
+  }
 
   if (target_cpu == "x64") {
     # TODO(https://fxbug.dev/42168719): not all x64 targets are haswell.
diff --git a/src/lib/ui/carnelian/src/app/strategies/framebuffer.rs b/src/lib/ui/carnelian/src/app/strategies/framebuffer.rs
index b1b5efc..cf65341 100644
--- a/src/lib/ui/carnelian/src/app/strategies/framebuffer.rs
+++ b/src/lib/ui/carnelian/src/app/strategies/framebuffer.rs
@@ -115,13 +115,7 @@
     }
 
     fn cancel_autorepeat_timer(&mut self) {
-        let task = self.keyboard_autorepeat_task.take();
-        if let Some(task) = task {
-            fasync::Task::local(async move {
-                task.cancel().await;
-            })
-            .detach();
-        }
+        self.keyboard_autorepeat_task = None;
     }
 }
 
diff --git a/src/lib/zircon/rust/src/stream.rs b/src/lib/zircon/rust/src/stream.rs
index a17009d..bbd46f8 100644
--- a/src/lib/zircon/rust/src/stream.rs
+++ b/src/lib/zircon/rust/src/stream.rs
@@ -279,6 +279,49 @@
     ]
 );
 
+impl std::io::Read for Stream {
+    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+        let mut iovec = [sys::zx_iovec_t { buffer: buf.as_mut_ptr(), capacity: buf.len() }];
+        // SAFETY: The buffer in `iovec` comes from a mutable slice so we know it's safe to pass it
+        // to `readv`.
+        Ok(unsafe { self.readv(StreamReadOptions::empty(), &mut iovec) }?)
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
+        // SAFETY: `zx_iovec_t` and `IoSliceMut` have the same layout.
+        let mut iovecs = unsafe {
+            std::slice::from_raw_parts_mut(bufs.as_mut_ptr() as *mut sys::zx_iovec_t, bufs.len())
+        };
+        // SAFETY: `IoSliceMut` can only be constructed from a mutable slice so we know it's safe to
+        // pass to `readv`.
+        Ok(unsafe { self.readv(StreamReadOptions::empty(), &mut iovecs) }?)
+    }
+}
+
+impl std::io::Seek for Stream {
+    fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
+        Ok(Self::seek(&self, pos)? as u64)
+    }
+}
+
+impl std::io::Write for Stream {
+    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+        Ok(Self::write(&self, StreamWriteOptions::empty(), buf)?)
+    }
+
+    fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
+        // SAFETY: `zx_iovec_t` and `IoSliceMut` have the same layout.
+        let iovecs = unsafe {
+            std::slice::from_raw_parts(bufs.as_ptr() as *const sys::zx_iovec_t, bufs.len())
+        };
+        Ok(self.writev(StreamWriteOptions::empty(), &iovecs)?)
+    }
+
+    fn flush(&mut self) -> std::io::Result<()> {
+        Ok(())
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -461,4 +504,57 @@
         let data = stream.read_at_to_vec(StreamReadOptions::empty(), 0, DATA.len()).unwrap();
         assert_eq!(data, DATA);
     }
+
+    #[test]
+    fn std_io_read_write_seek() {
+        const DATA: &'static str = "stream-contents";
+        let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0).unwrap();
+        let mut stream =
+            Stream::create(StreamOptions::MODE_READ | StreamOptions::MODE_WRITE, &vmo, 0).unwrap();
+
+        std::io::Write::write_all(&mut stream, DATA.as_bytes()).unwrap();
+        assert_eq!(std::io::Seek::stream_position(&mut stream).unwrap(), DATA.len() as u64);
+        std::io::Seek::rewind(&mut stream).unwrap();
+        assert_eq!(std::io::read_to_string(&mut stream).unwrap(), DATA);
+        assert_eq!(std::io::Seek::stream_position(&mut stream).unwrap(), DATA.len() as u64);
+    }
+
+    #[test]
+    fn std_io_read_vectored() {
+        const DATA: &'static [u8] = b"stream-contents";
+        let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0).unwrap();
+        let mut stream =
+            Stream::create(StreamOptions::MODE_READ | StreamOptions::MODE_WRITE, &vmo, 0).unwrap();
+        assert_eq!(stream.write(StreamWriteOptions::empty(), DATA).unwrap(), DATA.len());
+        std::io::Seek::rewind(&mut stream).unwrap();
+
+        let mut buf1 = [0; 6];
+        let mut buf2 = [0; 1];
+        let mut buf3 = [0; 8];
+        let mut bufs = [
+            std::io::IoSliceMut::new(&mut buf1),
+            std::io::IoSliceMut::new(&mut buf2),
+            std::io::IoSliceMut::new(&mut buf3),
+        ];
+        assert_eq!(std::io::Read::read_vectored(&mut stream, &mut bufs).unwrap(), DATA.len());
+        assert_eq!(buf1, DATA[0..6]);
+        assert_eq!(buf2, DATA[6..7]);
+        assert_eq!(buf3, DATA[7..]);
+    }
+
+    #[test]
+    fn std_io_write_vectored() {
+        let vmo = zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, 0).unwrap();
+        let mut stream =
+            Stream::create(StreamOptions::MODE_READ | StreamOptions::MODE_WRITE, &vmo, 0).unwrap();
+
+        let bufs = [
+            std::io::IoSlice::new(b"stream"),
+            std::io::IoSlice::new(b"-"),
+            std::io::IoSlice::new(b"contents"),
+        ];
+        assert_eq!(std::io::Write::write_vectored(&mut stream, &bufs).unwrap(), 15);
+        std::io::Seek::rewind(&mut stream).unwrap();
+        assert_eq!(stream.read_to_vec(StreamReadOptions::empty(), 15).unwrap(), b"stream-contents");
+    }
 }
diff --git a/src/lib/zxdump/test-tool-process.cc b/src/lib/zxdump/test-tool-process.cc
index 200336f8..c9b0796 100644
--- a/src/lib/zxdump/test-tool-process.cc
+++ b/src/lib/zxdump/test-tool-process.cc
@@ -139,7 +139,7 @@
     AddSvcEntry<fuchsia_kernel::RootJob, &SandboxLoop::root_job_server_>(*job);
     AddSvcEntry<fuchsia_boot::RootResource, &SandboxLoop::root_resource_server_>(*resource);
 
-    auto [svc_client, svc_server] = *fidl::CreateEndpoints<fuchsia_io::Directory>();
+    auto [svc_client, svc_server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
     status = vfs_->ServeDirectory(svc_dir_, std::move(svc_server));
     ASSERT_EQ(status, ZX_OK) << zx_status_get_string(status);
     out_svc = std::move(svc_client);
diff --git a/src/media/audio/drivers/aml-dsp/aml-g12-tdm-dsp/audio-stream.h b/src/media/audio/drivers/aml-dsp/aml-g12-tdm-dsp/audio-stream.h
index c293d66..a5711c5 100644
--- a/src/media/audio/drivers/aml-dsp/aml-g12-tdm-dsp/audio-stream.h
+++ b/src/media/audio/drivers/aml-dsp/aml-g12-tdm-dsp/audio-stream.h
@@ -23,7 +23,6 @@
 #include <audio-proto/audio-proto.h>
 #include <ddktl/device-internal.h>
 #include <ddktl/device.h>
-#include <ddktl/metadata/audio.h>
 #include <fbl/mutex.h>
 #include <soc/aml-common/aml-tdm-audio.h>
 
@@ -91,13 +90,11 @@
   int64_t codecs_turn_off_delay_nsec_ = 0;
   bool hardware_configured_ = false;
 
-  async::TaskClosureMethod<AmlG12TdmDspStream,
-                           &AmlG12TdmDspStream::ProcessRingNotification> notify_timer_
-      __TA_GUARDED(domain_token()){this};
+  async::TaskClosureMethod<AmlG12TdmDspStream, &AmlG12TdmDspStream::ProcessRingNotification>
+      notify_timer_ __TA_GUARDED(domain_token()){this};
   // Inform DSP FW of ring buffer location information regularly
-  async::TaskClosureMethod<AmlG12TdmDspStream,
-                           &AmlG12TdmDspStream::RingNotificationReport> position_timer_
-      __TA_GUARDED(domain_token()){this};
+  async::TaskClosureMethod<AmlG12TdmDspStream, &AmlG12TdmDspStream::RingNotificationReport>
+      position_timer_ __TA_GUARDED(domain_token()){this};
 
   ddk::PDevFidl pdev_;
 
diff --git a/src/media/audio/drivers/aml-g12-tdm/README.md b/src/media/audio/drivers/aml-g12-tdm/README.md
index 6cadbbb..212c5cd 100644
--- a/src/media/audio/drivers/aml-g12-tdm/README.md
+++ b/src/media/audio/drivers/aml-g12-tdm/README.md
@@ -12,8 +12,5 @@
 See [Audio Codec Interface](https://fuchsia.dev/fuchsia-src/development/audio/drivers/codec.md) for a
 description of codec terms used in this driver.
 
-See [audio.h](https://cs.opensource.google/fuchsia/fuchsia/+/main:src/lib/ddktl/include/ddktl/metadata/audio.h)
-for descriptions of audio metadata used in DFv1 drivers.
-
 See [aml-audio.h](https://cs.opensource.google/fuchsia/fuchsia/+/main:src/devices/lib/amlogic/include/soc/aml-common/aml-audio.h)
 for descriptions of AMLogic specific metadata used in DFv1 drivers.
diff --git a/src/media/audio/drivers/aml-g12-tdm/aml-tdm-config-device.h b/src/media/audio/drivers/aml-g12-tdm/aml-tdm-config-device.h
index d8a5471..f85f285 100644
--- a/src/media/audio/drivers/aml-g12-tdm/aml-tdm-config-device.h
+++ b/src/media/audio/drivers/aml-g12-tdm/aml-tdm-config-device.h
@@ -26,6 +26,7 @@
     return {8'000, 16'000, 32'000, 48'000, 96'000};
   }
   static uint32_t GetDefaultFrameRate() { return 48'000; }
+  static std::vector<uint8_t> GetSupportedRingBufferBytesPerSlot() { return {2}; }
   static std::vector<uint8_t> GetSupportedBitsPerSlot() { return {16, 32}; }
   static std::vector<uint8_t> GetSupportedBitsPerSample() { return {16, 32}; }
   static std::vector<fuchsia_hardware_audio::DaiFrameFormat> GetFidlSupportedFrameFormats() {
diff --git a/src/media/audio/drivers/aml-g12-tdm/audio-stream.h b/src/media/audio/drivers/aml-g12-tdm/audio-stream.h
index b2e904e..ffd51cf 100644
--- a/src/media/audio/drivers/aml-g12-tdm/audio-stream.h
+++ b/src/media/audio/drivers/aml-g12-tdm/audio-stream.h
@@ -22,7 +22,6 @@
 #include <audio-proto/audio-proto.h>
 #include <ddktl/device-internal.h>
 #include <ddktl/device.h>
-#include <ddktl/metadata/audio.h>
 #include <fbl/mutex.h>
 #include <soc/aml-common/aml-tdm-audio.h>
 
diff --git a/src/media/audio/drivers/aml-g12-tdm/composite-server.cc b/src/media/audio/drivers/aml-g12-tdm/composite-server.cc
index d8975d9..d9e82fd 100644
--- a/src/media/audio/drivers/aml-g12-tdm/composite-server.cc
+++ b/src/media/audio/drivers/aml-g12-tdm/composite-server.cc
@@ -136,16 +136,14 @@
   // Sample format is PCM signed.
   pcm_formats.sample_formats(std::vector{fuchsia_hardware_audio::SampleFormat::kPcmSigned});
 
-  // Bits per slot supported on DAI are supported in Ring Buffer as bytes per sample.
-  auto v = supported_dai_formats_[dai_index].bits_per_slot();
-  std::transform(v.begin(), v.end(), v.begin(), [](const uint8_t bits_per_slot) -> uint8_t {
-    ZX_ASSERT(bits_per_slot % 8 == 0);
-    return bits_per_slot / 8;
-  });
-  pcm_formats.bytes_per_sample(v);
+  // Bits per slot supported on Ring Buffer.
+  pcm_formats.bytes_per_sample(AmlTdmConfigDevice::GetSupportedRingBufferBytesPerSlot());
 
-  // Bits per sample supported on DAI are supported in Ring Buffer.
-  pcm_formats.valid_bits_per_sample(supported_dai_formats_[dai_index].bits_per_sample());
+  // Valid bits per sample supported on Ring Buffer.
+  auto v = AmlTdmConfigDevice::GetSupportedRingBufferBytesPerSlot();
+  std::transform(v.begin(), v.end(), v.begin(),
+                 [](const uint8_t bytes_per_slot) -> uint8_t { return bytes_per_slot * 8; });
+  pcm_formats.valid_bits_per_sample(v);
 
   supported_ring_buffer_formats_[index] = std::move(pcm_formats);
 
@@ -254,6 +252,15 @@
     request.protocol().Close(ZX_ERR_ALREADY_BOUND);
     return;
   }
+
+  // Reset all completion state related to signalprocessing.
+  topology_completer_.completer.reset();
+  topology_completer_.first_response_sent = false;
+  for (auto& element_entry : element_completers_) {
+    element_entry.second.completer.reset();
+    element_entry.second.first_response_sent = false;
+  }
+
   signal_.emplace(dispatcher(), std::move(request.protocol()), this,
                   std::mem_fn(&AudioCompositeServer::OnSignalProcessingClosed));
 }
diff --git a/src/media/audio/drivers/aml-g12-tdm/composite-server.h b/src/media/audio/drivers/aml-g12-tdm/composite-server.h
index ec7a6a9..ba3815e 100644
--- a/src/media/audio/drivers/aml-g12-tdm/composite-server.h
+++ b/src/media/audio/drivers/aml-g12-tdm/composite-server.h
@@ -13,8 +13,6 @@
 
 #include <unordered_map>
 
-#include <ddktl/metadata/audio.h>
-
 #include "src/media/audio/drivers/aml-g12-tdm/aml-tdm-config-device.h"
 
 namespace audio::aml_g12 {
diff --git a/src/media/audio/drivers/aml-g12-tdm/dai.h b/src/media/audio/drivers/aml-g12-tdm/dai.h
index 60d34ff..2ba8727 100644
--- a/src/media/audio/drivers/aml-g12-tdm/dai.h
+++ b/src/media/audio/drivers/aml-g12-tdm/dai.h
@@ -24,7 +24,6 @@
 #include <ddktl/device-internal.h>
 #include <ddktl/device.h>
 #include <ddktl/fidl.h>
-#include <ddktl/metadata/audio.h>
 #include <soc/aml-common/aml-tdm-audio.h>
 
 #include "aml-tdm-config-device.h"
diff --git a/src/media/audio/drivers/aml-g12-tdm/test/BUILD.gn b/src/media/audio/drivers/aml-g12-tdm/test/BUILD.gn
index aae6637..aca6231 100644
--- a/src/media/audio/drivers/aml-g12-tdm/test/BUILD.gn
+++ b/src/media/audio/drivers/aml-g12-tdm/test/BUILD.gn
@@ -31,7 +31,7 @@
     "//src/devices/lib/mmio",
     "//src/devices/testing/fake-mmio-reg",
     "//src/devices/testing/mock-ddk",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//src/lib/ddk",
     "//src/lib/ddktl",
     "//src/media/audio/drivers/lib/audio-driver-proto",
diff --git a/src/media/audio/drivers/aml-g12-tdm/test/composite-test.cc b/src/media/audio/drivers/aml-g12-tdm/test/composite-test.cc
index 475ef28..b51770b 100644
--- a/src/media/audio/drivers/aml-g12-tdm/test/composite-test.cc
+++ b/src/media/audio/drivers/aml-g12-tdm/test/composite-test.cc
@@ -833,6 +833,15 @@
     ASSERT_TRUE(ring_buffer_formats_result.is_ok());
     // There is at least one entry reported.
     ASSERT_GE(1, ring_buffer_formats_result->ring_buffer_formats().size());
+    // Only 2 bytes per sample supported.
+    auto& first_format = ring_buffer_formats_result->ring_buffer_formats()[0];
+    ASSERT_TRUE(first_format.pcm_supported_formats());
+    auto& first_pcm_format = *first_format.pcm_supported_formats();
+    ASSERT_TRUE(first_pcm_format.bytes_per_sample());
+    ASSERT_EQ(1, first_pcm_format.bytes_per_sample()->size());
+    ASSERT_EQ(2, (*first_pcm_format.bytes_per_sample())[0]);
+    ASSERT_EQ(1, first_pcm_format.valid_bits_per_sample()->size());
+    ASSERT_EQ(16, (*first_pcm_format.valid_bits_per_sample())[0]);
   }
 }
 
diff --git a/src/media/audio/drivers/aml-g12-tdm/test/stream-test.cc b/src/media/audio/drivers/aml-g12-tdm/test/stream-test.cc
index b3d0247..84f5769 100644
--- a/src/media/audio/drivers/aml-g12-tdm/test/stream-test.cc
+++ b/src/media/audio/drivers/aml-g12-tdm/test/stream-test.cc
@@ -18,7 +18,7 @@
 #include <vector>
 
 #include <fake-mmio-reg/fake-mmio-reg.h>
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 #include <soc/aml-s905d2/s905d2-hw.h>
 #include <zxtest/zxtest.h>
 
diff --git a/src/media/audio/drivers/usb-audio/BUILD.gn b/src/media/audio/drivers/usb-audio/BUILD.gn
index ffcd06c..9886e18 100644
--- a/src/media/audio/drivers/usb-audio/BUILD.gn
+++ b/src/media/audio/drivers/usb-audio/BUILD.gn
@@ -49,6 +49,7 @@
     "//sdk/fidl/fuchsia.hardware.audio:fuchsia.hardware.audio_cpp",
     "//sdk/fidl/fuchsia.hardware.midi:fuchsia.hardware.midi_cpp",
     "//sdk/fidl/fuchsia.hardware.usb:fuchsia.hardware.usb_cpp",
+    "//src/devices/lib/dev-operation",
     "//src/devices/lib/driver",
     "//src/devices/lib/driver:driver_runtime",
     "//src/devices/usb/lib/usb",
diff --git a/src/media/audio/lib/rust/BUILD.gn b/src/media/audio/lib/rust/BUILD.gn
index 86a6e6e..8e08f44 100644
--- a/src/media/audio/lib/rust/BUILD.gn
+++ b/src/media/audio/lib/rust/BUILD.gn
@@ -26,6 +26,7 @@
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia-async",
     "//src/lib/fuchsia-fs",
+    "//src/lib/zircon/rust:fuchsia-zircon-types",
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:camino",
     "//third_party/rust_crates:futures",
@@ -44,6 +45,7 @@
   }
 
   sources = [
+    "src/dai.rs",
     "src/device.rs",
     "src/format.rs",
     "src/format_set.rs",
diff --git a/src/media/audio/lib/rust/src/dai.rs b/src/media/audio/lib/rust/src/dai.rs
new file mode 100644
index 0000000..95c96f0
--- /dev/null
+++ b/src/media/audio/lib/rust/src/dai.rs
@@ -0,0 +1,307 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use fidl_fuchsia_hardware_audio as fhaudio;
+use std::fmt::Display;
+
+#[derive(Debug, Default, Clone, PartialEq)]
+pub struct DaiFormatSet {
+    pub number_of_channels: Vec<u32>,
+    pub sample_formats: Vec<DaiSampleFormat>,
+    pub frame_formats: Vec<DaiFrameFormat>,
+    pub frame_rates: Vec<u32>,
+    pub bits_per_slot: Vec<u8>,
+    pub bits_per_sample: Vec<u8>,
+}
+
+impl From<fhaudio::DaiSupportedFormats> for DaiFormatSet {
+    fn from(value: fhaudio::DaiSupportedFormats) -> Self {
+        Self {
+            number_of_channels: value.number_of_channels,
+            sample_formats: value.sample_formats.into_iter().map(From::from).collect(),
+            frame_formats: value.frame_formats.into_iter().map(From::from).collect(),
+            frame_rates: value.frame_rates,
+            bits_per_slot: value.bits_per_slot,
+            bits_per_sample: value.bits_per_sample,
+        }
+    }
+}
+
+impl From<DaiFormatSet> for fhaudio::DaiSupportedFormats {
+    fn from(value: DaiFormatSet) -> Self {
+        Self {
+            number_of_channels: value.number_of_channels,
+            sample_formats: value.sample_formats.into_iter().map(From::from).collect(),
+            frame_formats: value.frame_formats.into_iter().map(From::from).collect(),
+            frame_rates: value.frame_rates,
+            bits_per_slot: value.bits_per_slot,
+            bits_per_sample: value.bits_per_sample,
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DaiSampleFormat {
+    Pdm,
+    PcmSigned,
+    PcmUnsigned,
+    PcmFloat,
+}
+
+impl Display for DaiSampleFormat {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let s = match self {
+            DaiSampleFormat::Pdm => "pdm",
+            DaiSampleFormat::PcmSigned => "pcm_signed",
+            DaiSampleFormat::PcmUnsigned => "pcm_unsigned",
+            DaiSampleFormat::PcmFloat => "pcm_float",
+        };
+        f.write_str(s)
+    }
+}
+
+impl From<fhaudio::DaiSampleFormat> for DaiSampleFormat {
+    fn from(value: fhaudio::DaiSampleFormat) -> Self {
+        match value {
+            fhaudio::DaiSampleFormat::Pdm => Self::Pdm,
+            fhaudio::DaiSampleFormat::PcmSigned => Self::PcmSigned,
+            fhaudio::DaiSampleFormat::PcmUnsigned => Self::PcmUnsigned,
+            fhaudio::DaiSampleFormat::PcmFloat => Self::PcmFloat,
+        }
+    }
+}
+
+impl From<DaiSampleFormat> for fhaudio::DaiSampleFormat {
+    fn from(value: DaiSampleFormat) -> Self {
+        match value {
+            DaiSampleFormat::Pdm => Self::Pdm,
+            DaiSampleFormat::PcmSigned => Self::PcmSigned,
+            DaiSampleFormat::PcmUnsigned => Self::PcmUnsigned,
+            DaiSampleFormat::PcmFloat => Self::PcmFloat,
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DaiFrameFormat {
+    Standard(DaiFrameFormatStandard),
+    Custom(DaiFrameFormatCustom),
+}
+
+impl Display for DaiFrameFormat {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            DaiFrameFormat::Standard(standard) => standard.fmt(f),
+            DaiFrameFormat::Custom(custom) => {
+                f.write_str("custom:")?;
+                custom.fmt(f)
+            }
+        }
+    }
+}
+
+impl From<fhaudio::DaiFrameFormat> for DaiFrameFormat {
+    fn from(value: fhaudio::DaiFrameFormat) -> Self {
+        match value {
+            fhaudio::DaiFrameFormat::FrameFormatStandard(standard) => {
+                Self::Standard(standard.into())
+            }
+            fhaudio::DaiFrameFormat::FrameFormatCustom(custom) => Self::Custom(custom.into()),
+        }
+    }
+}
+
+impl From<DaiFrameFormat> for fhaudio::DaiFrameFormat {
+    fn from(value: DaiFrameFormat) -> Self {
+        match value {
+            DaiFrameFormat::Standard(standard) => Self::FrameFormatStandard(standard.into()),
+            DaiFrameFormat::Custom(custom) => Self::FrameFormatCustom(custom.into()),
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DaiFrameFormatStandard {
+    None,
+    I2S,
+    StereoLeft,
+    StereoRight,
+    Tdm1,
+    Tdm2,
+    Tdm3,
+}
+
+impl Display for DaiFrameFormatStandard {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let s = match self {
+            DaiFrameFormatStandard::None => "none",
+            DaiFrameFormatStandard::I2S => "i2s",
+            DaiFrameFormatStandard::StereoLeft => "stereo_left",
+            DaiFrameFormatStandard::StereoRight => "stereo_right",
+            DaiFrameFormatStandard::Tdm1 => "tdm1",
+            DaiFrameFormatStandard::Tdm2 => "tdm2",
+            DaiFrameFormatStandard::Tdm3 => "tdm3",
+        };
+        f.write_str(s)
+    }
+}
+
+impl From<fhaudio::DaiFrameFormatStandard> for DaiFrameFormatStandard {
+    fn from(value: fhaudio::DaiFrameFormatStandard) -> Self {
+        match value {
+            fhaudio::DaiFrameFormatStandard::None => Self::None,
+            fhaudio::DaiFrameFormatStandard::I2S => Self::I2S,
+            fhaudio::DaiFrameFormatStandard::StereoLeft => Self::StereoLeft,
+            fhaudio::DaiFrameFormatStandard::StereoRight => Self::StereoRight,
+            fhaudio::DaiFrameFormatStandard::Tdm1 => Self::Tdm1,
+            fhaudio::DaiFrameFormatStandard::Tdm2 => Self::Tdm2,
+            fhaudio::DaiFrameFormatStandard::Tdm3 => Self::Tdm3,
+        }
+    }
+}
+
+impl From<DaiFrameFormatStandard> for fhaudio::DaiFrameFormatStandard {
+    fn from(value: DaiFrameFormatStandard) -> Self {
+        match value {
+            DaiFrameFormatStandard::None => Self::None,
+            DaiFrameFormatStandard::I2S => Self::I2S,
+            DaiFrameFormatStandard::StereoLeft => Self::StereoLeft,
+            DaiFrameFormatStandard::StereoRight => Self::StereoRight,
+            DaiFrameFormatStandard::Tdm1 => Self::Tdm1,
+            DaiFrameFormatStandard::Tdm2 => Self::Tdm2,
+            DaiFrameFormatStandard::Tdm3 => Self::Tdm3,
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct DaiFrameFormatCustom {
+    pub justification: DaiFrameFormatJustification,
+    pub clocking: DaiFrameFormatClocking,
+    pub frame_sync_sclks_offset: i8,
+    pub frame_sync_size: u8,
+}
+
+impl Display for DaiFrameFormatCustom {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{},{},{},{}",
+            self.justification, self.clocking, self.frame_sync_sclks_offset, self.frame_sync_size
+        )
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DaiFrameFormatJustification {
+    Left,
+    Right,
+}
+
+impl Display for DaiFrameFormatJustification {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let s = match self {
+            DaiFrameFormatJustification::Left => "left_justified",
+            DaiFrameFormatJustification::Right => "right_justified",
+        };
+        f.write_str(s)
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum DaiFrameFormatClocking {
+    RaisingSclk,
+    FallingSclk,
+}
+
+impl Display for DaiFrameFormatClocking {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let s = match self {
+            DaiFrameFormatClocking::RaisingSclk => "raising_sclk",
+            DaiFrameFormatClocking::FallingSclk => "falling_sclk",
+        };
+        f.write_str(s)
+    }
+}
+
+impl From<DaiFrameFormatCustom> for fhaudio::DaiFrameFormatCustom {
+    fn from(value: DaiFrameFormatCustom) -> Self {
+        Self {
+            left_justified: match value.justification {
+                DaiFrameFormatJustification::Left => true,
+                DaiFrameFormatJustification::Right => false,
+            },
+            sclk_on_raising: match value.clocking {
+                DaiFrameFormatClocking::RaisingSclk => true,
+                DaiFrameFormatClocking::FallingSclk => false,
+            },
+            frame_sync_sclks_offset: value.frame_sync_sclks_offset,
+            frame_sync_size: value.frame_sync_size,
+        }
+    }
+}
+
+impl From<fhaudio::DaiFrameFormatCustom> for DaiFrameFormatCustom {
+    fn from(value: fhaudio::DaiFrameFormatCustom) -> Self {
+        Self {
+            justification: if value.left_justified {
+                DaiFrameFormatJustification::Left
+            } else {
+                DaiFrameFormatJustification::Right
+            },
+            clocking: if value.sclk_on_raising {
+                DaiFrameFormatClocking::RaisingSclk
+            } else {
+                DaiFrameFormatClocking::FallingSclk
+            },
+            frame_sync_sclks_offset: value.frame_sync_sclks_offset,
+            frame_sync_size: value.frame_sync_size,
+        }
+    }
+}
+
+#[cfg(test)]
+pub mod test {
+    use super::*;
+    use test_case::test_case;
+
+    #[test_case(DaiFrameFormat::Standard(DaiFrameFormatStandard::None), "none"; "standard: none")]
+    #[test_case(DaiFrameFormat::Standard(DaiFrameFormatStandard::I2S), "i2s"; "standard: i2s")]
+    #[test_case(
+        DaiFrameFormat::Standard(DaiFrameFormatStandard::StereoLeft),
+        "stereo_left";
+        "standard: stereo_left"
+    )]
+    #[test_case(
+        DaiFrameFormat::Standard(DaiFrameFormatStandard::StereoRight),
+        "stereo_right";
+        "standard: stereo_right"
+    )]
+    #[test_case(DaiFrameFormat::Standard(DaiFrameFormatStandard::Tdm1), "tdm1"; "standard: tdm1")]
+    #[test_case(DaiFrameFormat::Standard(DaiFrameFormatStandard::Tdm2), "tdm2"; "standard: tdm2")]
+    #[test_case(DaiFrameFormat::Standard(DaiFrameFormatStandard::Tdm3), "tdm3"; "standard: tdm3")]
+    #[test_case(
+        DaiFrameFormat::Custom(DaiFrameFormatCustom {
+            justification: DaiFrameFormatJustification::Left,
+            clocking: DaiFrameFormatClocking::RaisingSclk,
+            frame_sync_sclks_offset: 0,
+            frame_sync_size: 1,
+        }),
+        "custom:left_justified,raising_sclk,0,1";
+        "custom 1"
+    )]
+    #[test_case(
+        DaiFrameFormat::Custom(DaiFrameFormatCustom {
+            justification: DaiFrameFormatJustification::Right,
+            clocking: DaiFrameFormatClocking::FallingSclk,
+            frame_sync_sclks_offset: -1,
+            frame_sync_size: 0,
+        }),
+        "custom:right_justified,falling_sclk,-1,0";
+        "custom 2"
+    )]
+    fn test_dai_frame_format_display(dai_frame_format: DaiFrameFormat, expected: &str) {
+        assert_eq!(dai_frame_format.to_string(), expected);
+    }
+}
diff --git a/src/media/audio/lib/rust/src/device.rs b/src/media/audio/lib/rust/src/device.rs
index d0165e8..8c31ca9 100644
--- a/src/media/audio/lib/rust/src/device.rs
+++ b/src/media/audio/lib/rust/src/device.rs
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+use crate::{dai::DaiFormatSet, format_set::PcmFormatSet};
 use camino::Utf8PathBuf;
 use fidl_fuchsia_audio_controller as fac;
 use fidl_fuchsia_audio_device as fadevice;
 use fidl_fuchsia_hardware_audio as fhaudio;
 use fidl_fuchsia_io as fio;
+use fuchsia_zircon_types as zx_types;
+use std::collections::BTreeMap;
 use std::fmt::Display;
 use std::str::FromStr;
 use thiserror::Error;
@@ -165,7 +168,7 @@
 }
 
 /// Identifies a single audio device.
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub enum Selector {
     Devfs(DevfsSelector),
     Registry(RegistrySelector),
@@ -199,15 +202,23 @@
 }
 
 /// Identifies a device backed by a hardware driver protocol in devfs.
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct DevfsSelector(pub fac::Devfs);
 
 impl DevfsSelector {
     /// Returns the full devfs path for this device.
     pub fn path(&self) -> Utf8PathBuf {
-        Utf8PathBuf::from("/dev/class")
-            .join(Type(self.0.device_type).devfs_class())
-            .join(self.0.id.clone())
+        Utf8PathBuf::from("/dev/class").join(self.relative_path())
+    }
+
+    /// Returns the path for this device relative to the /dev/class directory root.
+    pub fn relative_path(&self) -> Utf8PathBuf {
+        Utf8PathBuf::from(self.device_type().devfs_class()).join(self.0.id.clone())
+    }
+
+    /// Returns the type of this device.
+    pub fn device_type(&self) -> Type {
+        Type(self.0.device_type)
     }
 }
 
@@ -241,7 +252,7 @@
 }
 
 /// Identifies a device available through the `fuchsia.audio.device/Registry` protocol.
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct RegistrySelector(pub fadevice::TokenId);
 
 impl RegistrySelector {
@@ -295,6 +306,90 @@
     pub fn device_type(&self) -> Type {
         Type(self.0.device_type.expect("missing device_type"))
     }
+
+    pub fn unique_instance_id(&self) -> Option<UniqueInstanceId> {
+        self.0.unique_instance_id.map(UniqueInstanceId)
+    }
+
+    pub fn plug_detect_capabilities(&self) -> Option<PlugDetectCapabilities> {
+        self.0.plug_detect_caps.map(PlugDetectCapabilities::from)
+    }
+
+    pub fn gain_capabilities(&self) -> Option<GainCapabilities> {
+        self.0.gain_caps.clone().and_then(|gain_caps| GainCapabilities::try_from(gain_caps).ok())
+    }
+
+    pub fn clock_domain(&self) -> Option<ClockDomain> {
+        self.0.clock_domain.map(ClockDomain)
+    }
+
+    pub fn supported_ring_buffer_formats(
+        &self,
+    ) -> Result<BTreeMap<fadevice::ElementId, Vec<PcmFormatSet>>, String> {
+        self.0
+            .ring_buffer_format_sets
+            .as_ref()
+            .map_or_else(
+                || Ok(BTreeMap::new()),
+                |element_rb_format_sets| {
+                    element_rb_format_sets
+                        .iter()
+                        .cloned()
+                        .map(|element_rb_format_set| {
+                            let element_id = element_rb_format_set
+                                .element_id
+                                .ok_or_else(|| "missing element_id".to_string())?;
+                            let fidl_format_sets = element_rb_format_set
+                                .format_sets
+                                .ok_or_else(|| "missing format_sets".to_string())?;
+
+                            let format_sets: Vec<PcmFormatSet> = fidl_format_sets
+                                .into_iter()
+                                .map(TryInto::try_into)
+                                .collect::<Result<Vec<_>, _>>()
+                                .map_err(|err| format!("invalid format set: {}", err))?;
+
+                            Ok((element_id, format_sets))
+                        })
+                        .collect::<Result<BTreeMap<_, _>, String>>()
+                },
+            )
+            .map_err(|err| format!("invalid ring buffer format sets: {}", err))
+    }
+
+    pub fn supported_dai_formats(
+        &self,
+    ) -> Result<BTreeMap<fadevice::ElementId, Vec<DaiFormatSet>>, String> {
+        self.0
+            .dai_format_sets
+            .as_ref()
+            .map_or_else(
+                || Ok(BTreeMap::new()),
+                |element_dai_format_sets| {
+                    element_dai_format_sets
+                        .iter()
+                        .cloned()
+                        .map(|element_dai_format_set| {
+                            let element_id = element_dai_format_set
+                                .element_id
+                                .ok_or_else(|| "missing element_id".to_string())?;
+                            let fidl_format_sets = element_dai_format_set
+                                .format_sets
+                                .ok_or_else(|| "missing format_sets".to_string())?;
+
+                            let dai_format_sets: Vec<DaiFormatSet> = fidl_format_sets
+                                .into_iter()
+                                .map(TryInto::try_into)
+                                .collect::<Result<Vec<_>, _>>()
+                                .map_err(|err| format!("invalid DAI format set: {}", err))?;
+
+                            Ok((element_id, dai_format_sets))
+                        })
+                        .collect::<Result<BTreeMap<_, _>, String>>()
+                },
+            )
+            .map_err(|err| format!("invalid ring buffer format sets: {}", err))
+    }
 }
 
 impl From<fadevice::Info> for Info {
@@ -373,7 +468,38 @@
     }
 }
 
-#[derive(Debug, Clone, PartialEq)]
+/// Describes the plug state of a device or endpoint, and when it changed.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct PlugEvent {
+    pub state: PlugState,
+
+    /// The Zircon monotonic time when the plug state changed.
+    pub time: zx_types::zx_time_t,
+}
+
+impl From<(fadevice::PlugState, i64 /* time */)> for PlugEvent {
+    fn from(value: (fadevice::PlugState, i64)) -> Self {
+        let (state, time) = value;
+        Self { state: state.into(), time }
+    }
+}
+
+impl TryFrom<fhaudio::PlugState> for PlugEvent {
+    type Error = String;
+
+    fn try_from(value: fhaudio::PlugState) -> Result<Self, Self::Error> {
+        let plugged = value.plugged.ok_or_else(|| "missing 'plugged'".to_string())?;
+        let time = value.plug_state_time.ok_or_else(|| "missing 'plug_state_time'".to_string())?;
+        let state = PlugState(if plugged {
+            fadevice::PlugState::Plugged
+        } else {
+            fadevice::PlugState::Unplugged
+        });
+        Ok(Self { state, time })
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub struct PlugState(pub fadevice::PlugState);
 
 impl Display for PlugState {
@@ -399,17 +525,6 @@
     }
 }
 
-impl TryFrom<fhaudio::PlugState> for PlugState {
-    type Error = String;
-
-    fn try_from(value: fhaudio::PlugState) -> Result<Self, Self::Error> {
-        let plugged = value.plugged.ok_or_else(|| "missing 'plugged'".to_string())?;
-        let plug_state =
-            if plugged { fadevice::PlugState::Plugged } else { fadevice::PlugState::Unplugged };
-        Ok(Self(plug_state))
-    }
-}
-
 // TODO(https://fxbug.dev/102027): Remove legacy gain aspects once driver API does.
 // Going forward, gain will be handled by `SignalProcessing`.
 #[derive(Debug, Clone, Copy, PartialEq)]
diff --git a/src/media/audio/lib/rust/src/lib.rs b/src/media/audio/lib/rust/src/lib.rs
index bf89442..08a5882 100644
--- a/src/media/audio/lib/rust/src/lib.rs
+++ b/src/media/audio/lib/rust/src/lib.rs
@@ -8,6 +8,7 @@
 use futures::TryStreamExt;
 use std::sync::atomic::{AtomicBool, Ordering};
 
+pub mod dai;
 pub mod device;
 pub mod format;
 pub mod format_set;
diff --git a/src/media/audio/lib/rust/src/registry.rs b/src/media/audio/lib/rust/src/registry.rs
index 7f29e8af..9e8cdd1 100644
--- a/src/media/audio/lib/rust/src/registry.rs
+++ b/src/media/audio/lib/rust/src/registry.rs
@@ -34,6 +34,12 @@
         self.devices_initialized.wait().await;
         self.devices.lock().await.get(&token_id).cloned()
     }
+
+    /// Returns information about all devices in the registry.
+    pub async fn get_all(&self) -> BTreeMap<fadevice::TokenId, DeviceInfo> {
+        self.devices_initialized.wait().await;
+        self.devices.lock().await.clone()
+    }
 }
 
 /// Watches devices added to and removed from the registry and updates
diff --git a/src/media/audio/lib/simple-audio-stream/tests/BUILD.gn b/src/media/audio/lib/simple-audio-stream/tests/BUILD.gn
index d68ea23..5adcb21 100644
--- a/src/media/audio/lib/simple-audio-stream/tests/BUILD.gn
+++ b/src/media/audio/lib/simple-audio-stream/tests/BUILD.gn
@@ -13,7 +13,6 @@
     "//sdk/fidl/fuchsia.device:fuchsia.device_cpp",
     "//sdk/fidl/fuchsia.hardware.audio:fuchsia.hardware.audio_cpp",
     "//sdk/lib/inspect/testing/cpp:zxtest",
-    "//src/devices/lib/dev-operation",
     "//src/devices/testing/mock-ddk",
     "//src/lib/ddk",
     "//src/lib/ddktl",
diff --git a/src/media/audio/services/device_registry/adr_server_unittest_base.h b/src/media/audio/services/device_registry/adr_server_unittest_base.h
index c35b67b..9c9bec5 100644
--- a/src/media/audio/services/device_registry/adr_server_unittest_base.h
+++ b/src/media/audio/services/device_registry/adr_server_unittest_base.h
@@ -7,7 +7,6 @@
 
 #include <fidl/fuchsia.audio.device/cpp/common_types.h>
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 
 #include <memory>
 #include <optional>
@@ -25,7 +24,6 @@
 #include "src/media/audio/services/device_registry/observer_server.h"
 #include "src/media/audio/services/device_registry/provider_server.h"
 #include "src/media/audio/services/device_registry/registry_server.h"
-#include "src/media/audio/services/device_registry/ring_buffer_server.h"
 #include "src/media/audio/services/device_registry/testing/fake_codec.h"
 #include "src/media/audio/services/device_registry/testing/fake_composite.h"
 #include "src/media/audio/services/device_registry/testing/fake_stream_config.h"
@@ -33,7 +31,7 @@
 
 namespace media_audio {
 
-inline void LogFidlClientError(fidl::UnbindInfo error, std::string tag = "") {
+inline void LogFidlClientError(fidl::UnbindInfo error, const std::string& tag = "") {
   if (error.status() != ZX_OK && error.status() != ZX_ERR_PEER_CLOSED) {
     FX_LOGS(WARNING) << tag << ":" << error;
   } else {
@@ -79,6 +77,16 @@
         Device::Create(adr_service_, dispatcher(), name, device_type, std::move(driver_client)));
   }
 
+  static const std::unordered_map<TopologyId,
+                                  std::vector<fuchsia_hardware_audio_signalprocessing::EdgePair>>&
+  topology_map(const std::shared_ptr<Device>& device) {
+    return device->sig_proc_topology_map_;
+  }
+  static const std::unordered_map<ElementId, ElementRecord>& element_map(
+      const std::shared_ptr<Device>& device) {
+    return device->sig_proc_element_map_;
+  }
+
   class FidlHandler {
    public:
     explicit FidlHandler(AudioDeviceRegistryServerTestBase* parent) : parent_(parent) {}
@@ -94,6 +102,7 @@
   std::unique_ptr<TestServerAndNaturalAsyncClient<ProviderServer>> CreateTestProviderServer() {
     auto [client_end, server_end] = CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Provider>();
     auto server = adr_service_->CreateProviderServer(std::move(server_end));
+    provider_fidl_error_status().reset();
     auto client = fidl::Client<fuchsia_audio_device::Provider>(std::move(client_end), dispatcher(),
                                                                provider_fidl_handler_.get());
     return std::make_unique<TestServerAndNaturalAsyncClient<ProviderServer>>(
@@ -108,14 +117,13 @@
       parent()->provider_fidl_error_status_ = error.status();
     }
   };
-  std::unique_ptr<ProviderFidlHandler> provider_fidl_handler_ =
-      std::make_unique<ProviderFidlHandler>(static_cast<AudioDeviceRegistryServerTestBase*>(this));
-  std::optional<zx_status_t> provider_fidl_error_status_;
+  std::optional<zx_status_t>& provider_fidl_error_status() { return provider_fidl_error_status_; }
 
   // Registry support
   std::unique_ptr<TestServerAndNaturalAsyncClient<RegistryServer>> CreateTestRegistryServer() {
     auto [client_end, server_end] = CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Registry>();
     auto server = adr_service_->CreateRegistryServer(std::move(server_end));
+    registry_fidl_error_status().reset();
     auto client = fidl::Client<fuchsia_audio_device::Registry>(std::move(client_end), dispatcher(),
                                                                registry_fidl_handler_.get());
     return std::make_unique<TestServerAndNaturalAsyncClient<RegistryServer>>(
@@ -130,9 +138,7 @@
       parent()->registry_fidl_error_status_ = error.status();
     }
   };
-  std::unique_ptr<RegistryFidlHandler> registry_fidl_handler_ =
-      std::make_unique<RegistryFidlHandler>(static_cast<AudioDeviceRegistryServerTestBase*>(this));
-  std::optional<zx_status_t> registry_fidl_error_status_;
+  std::optional<zx_status_t>& registry_fidl_error_status() { return registry_fidl_error_status_; }
 
   // ControlCreator support
   class ControlCreatorFidlHandler
@@ -146,29 +152,29 @@
       parent()->control_creator_fidl_error_status_ = error.status();
     }
   };
-  std::unique_ptr<ControlCreatorFidlHandler> control_creator_fidl_handler_ =
-      std::make_unique<ControlCreatorFidlHandler>(
-          static_cast<AudioDeviceRegistryServerTestBase*>(this));
-  std::optional<zx_status_t> control_creator_fidl_error_status_;
-
   std::unique_ptr<TestServerAndNaturalAsyncClient<ControlCreatorServer>>
   CreateTestControlCreatorServer() {
     auto [client_end, server_end] =
         CreateNaturalAsyncClientOrDie<fuchsia_audio_device::ControlCreator>();
     auto server = adr_service_->CreateControlCreatorServer(std::move(server_end));
+    control_creator_fidl_error_status().reset();
     auto client = fidl::Client<fuchsia_audio_device::ControlCreator>(
         std::move(client_end), dispatcher(), control_creator_fidl_handler_.get());
     return std::make_unique<TestServerAndNaturalAsyncClient<ControlCreatorServer>>(
         test_loop(), std::move(server), std::move(client));
   }
+  std::optional<zx_status_t>& control_creator_fidl_error_status() {
+    return control_creator_fidl_error_status_;
+  }
 
   // Observer support
   std::unique_ptr<TestServerAndNaturalAsyncClient<ObserverServer>> CreateTestObserverServer(
-      std::shared_ptr<Device> observed_device) {
+      const std::shared_ptr<Device>& observed_device) {
     auto [client_end, server_end] = CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
     auto server = adr_service_->CreateObserverServer(std::move(server_end), observed_device);
+    observer_fidl_error_status().reset();
     auto client = fidl::Client<fuchsia_audio_device::Observer>(std::move(client_end), dispatcher(),
-                                                               observer_fidl_handler_.get());
+                                                               observer_fidl_handler().get());
     return std::make_unique<TestServerAndNaturalAsyncClient<ObserverServer>>(
         test_loop(), std::move(server), std::move(client));
   }
@@ -182,18 +188,20 @@
       parent()->observer_fidl_error_status_ = error.status();
     }
   };
-  std::unique_ptr<ObserverFidlHandler> observer_fidl_handler_ =
-      std::make_unique<ObserverFidlHandler>(static_cast<AudioDeviceRegistryServerTestBase*>(this));
-  std::optional<zx_status_t> observer_fidl_error_status_;
+  const std::unique_ptr<ObserverFidlHandler>& observer_fidl_handler() {
+    return observer_fidl_handler_;
+  }
+  std::optional<zx_status_t>& observer_fidl_error_status() { return observer_fidl_error_status_; }
 
   // Control support
   std::unique_ptr<TestServerAndNaturalAsyncClient<ControlServer>> CreateTestControlServer(
-      std::shared_ptr<Device> device_to_control) {
+      const std::shared_ptr<Device>& device_to_control) {
     auto [client_end, server_end] = CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Control>();
     auto server = adr_service_->CreateControlServer(std::move(server_end), device_to_control);
     FX_CHECK(server) << "ControlServer is NULL";
+    control_fidl_error_status().reset();
     auto client = fidl::Client<fuchsia_audio_device::Control>(std::move(client_end), dispatcher(),
-                                                              control_fidl_handler_.get());
+                                                              control_fidl_handler().get());
     return std::make_unique<TestServerAndNaturalAsyncClient<ControlServer>>(
         test_loop(), std::move(server), std::move(client));
   }
@@ -206,9 +214,10 @@
       parent()->control_fidl_error_status_ = error.status();
     }
   };
-  std::unique_ptr<ControlFidlHandler> control_fidl_handler_ =
-      std::make_unique<ControlFidlHandler>(static_cast<AudioDeviceRegistryServerTestBase*>(this));
-  std::optional<zx_status_t> control_fidl_error_status_;
+  const std::unique_ptr<ControlFidlHandler>& control_fidl_handler() {
+    return control_fidl_handler_;
+  }
+  std::optional<zx_status_t>& control_fidl_error_status() { return control_fidl_error_status_; }
 
   // RingBuffer support
   class RingBufferFidlHandler : public fidl::AsyncEventHandler<fuchsia_audio_device::RingBuffer>,
@@ -221,27 +230,54 @@
       parent()->ring_buffer_fidl_error_status_ = error.status();
     }
   };
+  const std::unique_ptr<RingBufferFidlHandler>& ring_buffer_fidl_handler() {
+    return ring_buffer_fidl_handler_;
+  }
+
+  // General members
+  std::shared_ptr<media_audio::AudioDeviceRegistry> adr_service() { return adr_service_; }
+
+ private:
+  std::unique_ptr<ProviderFidlHandler> provider_fidl_handler_ =
+      std::make_unique<ProviderFidlHandler>(static_cast<AudioDeviceRegistryServerTestBase*>(this));
+  std::optional<zx_status_t> provider_fidl_error_status_;
+
+  std::unique_ptr<RegistryFidlHandler> registry_fidl_handler_ =
+      std::make_unique<RegistryFidlHandler>(static_cast<AudioDeviceRegistryServerTestBase*>(this));
+  std::optional<zx_status_t> registry_fidl_error_status_;
+
+  std::unique_ptr<ControlCreatorFidlHandler> control_creator_fidl_handler_ =
+      std::make_unique<ControlCreatorFidlHandler>(
+          static_cast<AudioDeviceRegistryServerTestBase*>(this));
+  std::optional<zx_status_t> control_creator_fidl_error_status_;
+
+  std::unique_ptr<ObserverFidlHandler> observer_fidl_handler_ =
+      std::make_unique<ObserverFidlHandler>(static_cast<AudioDeviceRegistryServerTestBase*>(this));
+  std::optional<zx_status_t> observer_fidl_error_status_;
+
+  std::unique_ptr<ControlFidlHandler> control_fidl_handler_ =
+      std::make_unique<ControlFidlHandler>(static_cast<AudioDeviceRegistryServerTestBase*>(this));
+  std::optional<zx_status_t> control_fidl_error_status_;
+
   std::unique_ptr<RingBufferFidlHandler> ring_buffer_fidl_handler_ =
       std::make_unique<RingBufferFidlHandler>(
           static_cast<AudioDeviceRegistryServerTestBase*>(this));
   std::optional<zx_status_t> ring_buffer_fidl_error_status_;
 
-  // General members
   std::shared_ptr<FidlThread> server_thread_ =
       FidlThread::CreateFromCurrentThread("test_server_thread", dispatcher());
 
   std::shared_ptr<media_audio::AudioDeviceRegistry> adr_service_ =
       std::make_shared<media_audio::AudioDeviceRegistry>(server_thread_);
 
- private:
   // Create a FakeStreamConfig that can mock a real device that has been detected, using default
   // settings. From here, the fake StreamConfig can be customized before it is enabled.
   std::shared_ptr<FakeStreamConfig> CreateFakeStreamConfig(bool is_input = false) {
     EXPECT_EQ(dispatcher(), test_loop().dispatcher());
     auto stream_config_endpoints = fidl::Endpoints<fuchsia_hardware_audio::StreamConfig>::Create();
     auto fake_stream = std::make_shared<FakeStreamConfig>(
-        stream_config_endpoints.server.TakeChannel(),
-        stream_config_endpoints.client.TakeChannel(), dispatcher());
+        stream_config_endpoints.server.TakeChannel(), stream_config_endpoints.client.TakeChannel(),
+        dispatcher());
     fake_stream->set_is_input(is_input);
     return fake_stream;
   }
diff --git a/src/media/audio/services/device_registry/audio_device_registry.cc b/src/media/audio/services/device_registry/audio_device_registry.cc
index 52c63ae..d659362 100644
--- a/src/media/audio/services/device_registry/audio_device_registry.cc
+++ b/src/media/audio/services/device_registry/audio_device_registry.cc
@@ -7,9 +7,7 @@
 #include <fidl/fuchsia.audio.device/cpp/markers.h>
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
 #include <lib/component/outgoing/cpp/outgoing_directory.h>
-#include <lib/fidl/cpp/wire/internal/transport.h>
 #include <lib/syslog/cpp/macros.h>
-#include <zircon/errors.h>
 
 #include <memory>
 #include <utility>
diff --git a/src/media/audio/services/device_registry/audio_device_registry.h b/src/media/audio/services/device_registry/audio_device_registry.h
index 74aff7d..bd0f918 100644
--- a/src/media/audio/services/device_registry/audio_device_registry.h
+++ b/src/media/audio/services/device_registry/audio_device_registry.h
@@ -5,9 +5,7 @@
 #ifndef SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_AUDIO_DEVICE_REGISTRY_H_
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_AUDIO_DEVICE_REGISTRY_H_
 
-#include <fidl/fuchsia.audio.device/cpp/common_types.h>
 #include <fidl/fuchsia.audio.device/cpp/markers.h>
-#include <fidl/fuchsia.hardware.audio/cpp/markers.h>
 #include <lib/component/outgoing/cpp/outgoing_directory.h>
 #include <lib/fidl/cpp/wire/internal/transport_channel.h>
 
diff --git a/src/media/audio/services/device_registry/audio_device_registry_unittest.cc b/src/media/audio/services/device_registry/audio_device_registry_unittest.cc
index 5e1a26f..b0c0094 100644
--- a/src/media/audio/services/device_registry/audio_device_registry_unittest.cc
+++ b/src/media/audio/services/device_registry/audio_device_registry_unittest.cc
@@ -9,9 +9,6 @@
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/device_registry/adr_server_unittest_base.h"
-#include "src/media/audio/services/device_registry/testing/fake_codec.h"
-#include "src/media/audio/services/device_registry/testing/fake_composite.h"
-#include "src/media/audio/services/device_registry/testing/fake_stream_config.h"
 
 namespace media_audio {
 namespace {
@@ -37,8 +34,8 @@
       fuchsia_audio_device::DriverClient::WithStreamConfig(std::move(stream_config_client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 3u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 3u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 }
 
 TEST_F(AudioDeviceRegistryServerTest, DeviceRemoval) {
@@ -60,16 +57,16 @@
       fuchsia_audio_device::DriverClient::WithStreamConfig(std::move(stream_config_client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 3u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 3u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 
   fake_codec->DropCodec();
   fake_composite->DropComposite();
   fake_stream->DropStreamConfig();
   RunLoopUntilIdle();
 
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 }
 
 /////////////////////
@@ -82,10 +79,10 @@
                         fuchsia_audio_device::DriverClient::WithCodec(std::move(client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  auto token_id = adr_service_->devices().begin()->get()->token_id();
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  auto token_id = adr_service()->devices().begin()->get()->token_id();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Active);
 }
 
@@ -98,10 +95,10 @@
                         fuchsia_audio_device::DriverClient::WithComposite(std::move(client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  auto token_id = adr_service_->devices().begin()->get()->token_id();
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  auto token_id = adr_service()->devices().begin()->get()->token_id();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Active);
 }
 
@@ -115,10 +112,10 @@
                         fuchsia_audio_device::DriverClient::WithStreamConfig(std::move(client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  auto token_id = adr_service_->devices().begin()->get()->token_id();
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  auto token_id = adr_service()->devices().begin()->get()->token_id();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Active);
 }
 
diff --git a/src/media/audio/services/device_registry/audio_device_registry_warning_unittest.cc b/src/media/audio/services/device_registry/audio_device_registry_warning_unittest.cc
index 88852a9..ece0ad6 100644
--- a/src/media/audio/services/device_registry/audio_device_registry_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/audio_device_registry_warning_unittest.cc
@@ -3,15 +3,11 @@
 // found in the LICENSE file.
 
 #include <fidl/fuchsia.audio.device/cpp/common_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/device_registry/adr_server_unittest_base.h"
 #include "src/media/audio/services/device_registry/audio_device_registry.h"
-#include "src/media/audio/services/device_registry/testing/fake_codec.h"
-#include "src/media/audio/services/device_registry/testing/fake_composite.h"
-#include "src/media/audio/services/device_registry/testing/fake_stream_config.h"
 
 namespace media_audio {
 namespace {
@@ -20,7 +16,7 @@
 
 // Device-less tests
 TEST_F(AudioDeviceRegistryServerWarningTest, FindDeviceByTokenIdUnknown) {
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(-1).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(-1).first,
             AudioDeviceRegistry::DevicePresence::Unknown);
 }
 
@@ -48,8 +44,8 @@
       fuchsia_audio_device::DriverClient::WithStreamConfig(std::move(stream_config_client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 3u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 3u);
 }
 
 /////////////////////
@@ -62,11 +58,11 @@
                         fuchsia_audio_device::DriverClient::WithCodec(std::move(client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 1u);
-  auto token_id = adr_service_->unhealthy_devices().begin()->get()->token_id();
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 1u);
+  auto token_id = adr_service()->unhealthy_devices().begin()->get()->token_id();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Error);
 }
 
@@ -77,13 +73,13 @@
                         fuchsia_audio_device::DriverClient::WithCodec(std::move(client)));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  auto token_id = adr_service_->devices().begin()->get()->token_id();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  auto token_id = adr_service()->devices().begin()->get()->token_id();
 
   fake_driver->DropCodec();
   RunLoopUntilIdle();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Unknown);
 }
 
@@ -97,11 +93,11 @@
                         fuchsia_audio_device::DriverClient::WithComposite(std::move(client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 1u);
-  auto token_id = adr_service_->unhealthy_devices().begin()->get()->token_id();
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 1u);
+  auto token_id = adr_service()->unhealthy_devices().begin()->get()->token_id();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Error);
 }
 
@@ -112,13 +108,13 @@
                         fuchsia_audio_device::DriverClient::WithComposite(std::move(client)));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  auto token_id = adr_service_->devices().begin()->get()->token_id();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  auto token_id = adr_service()->devices().begin()->get()->token_id();
 
   fake_driver->DropComposite();
   RunLoopUntilIdle();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Unknown);
 }
 
@@ -132,11 +128,11 @@
                         fuchsia_audio_device::DriverClient::WithStreamConfig(std::move(client)));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 1u);
-  auto token_id = adr_service_->unhealthy_devices().begin()->get()->token_id();
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 1u);
+  auto token_id = adr_service()->unhealthy_devices().begin()->get()->token_id();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Error);
 }
 
@@ -147,13 +143,13 @@
                         fuchsia_audio_device::DriverClient::WithStreamConfig(std::move(client)));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  auto token_id = adr_service_->devices().begin()->get()->token_id();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  auto token_id = adr_service()->devices().begin()->get()->token_id();
 
   fake_driver->DropStreamConfig();
   RunLoopUntilIdle();
 
-  EXPECT_EQ(adr_service_->FindDeviceByTokenId(token_id).first,
+  EXPECT_EQ(adr_service()->FindDeviceByTokenId(token_id).first,
             AudioDeviceRegistry::DevicePresence::Unknown);
 }
 
diff --git a/src/media/audio/services/device_registry/basic_types.h b/src/media/audio/services/device_registry/basic_types.h
index b3aeb56..a4004c4 100644
--- a/src/media/audio/services/device_registry/basic_types.h
+++ b/src/media/audio/services/device_registry/basic_types.h
@@ -6,9 +6,6 @@
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_BASIC_TYPES_H_
 
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/markers.h>
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_messaging.h>
-#include <lib/fidl/cpp/unified_messaging.h>
 
 #include <array>
 
@@ -22,8 +19,8 @@
 using UniqueId = std::array<uint8_t, fuchsia_audio_device::kUniqueInstanceIdSize>;
 
 // In addition to just mapping the ElementId to its unique Element, we also store the ElementState,
-// as well as conveniently store what is needed to manage the hanging-gets to the driver. This
-// enables us to interact properly with ObserverNotify instances.
+// as well as conveniently store what is needed to manage pending state-change notifications to
+// clients. This enables us to interact properly with ObserverNotify instances.
 struct ElementRecord {
   fuchsia_hardware_audio_signalprocessing::Element element;
   std::optional<fuchsia_hardware_audio_signalprocessing::ElementState> state;
diff --git a/src/media/audio/services/device_registry/common_unittest.cc b/src/media/audio/services/device_registry/common_unittest.cc
index 1648fb7..4d45171 100644
--- a/src/media/audio/services/device_registry/common_unittest.cc
+++ b/src/media/audio/services/device_registry/common_unittest.cc
@@ -5,12 +5,9 @@
 #include "src/media/audio/services/device_registry/common_unittest.h"
 
 #include <fidl/fuchsia.audio.device/cpp/fidl.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
-#include <lib/syslog/cpp/macros.h>
 
 #include <gtest/gtest.h>
 
-#include "src/media/audio/services/device_registry/logging.h"
 #include "src/media/audio/services/device_registry/validate.h"
 
 namespace media_audio {
diff --git a/src/media/audio/services/device_registry/common_unittest.h b/src/media/audio/services/device_registry/common_unittest.h
index c455e62..a873fb9 100644
--- a/src/media/audio/services/device_registry/common_unittest.h
+++ b/src/media/audio/services/device_registry/common_unittest.h
@@ -6,7 +6,6 @@
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_COMMON_UNITTEST_H_
 
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 
 #include "src/media/audio/services/device_registry/basic_types.h"
 
diff --git a/src/media/audio/services/device_registry/control_creator_server.cc b/src/media/audio/services/device_registry/control_creator_server.cc
index 64962a5..73a3eb3 100644
--- a/src/media/audio/services/device_registry/control_creator_server.cc
+++ b/src/media/audio/services/device_registry/control_creator_server.cc
@@ -4,11 +4,9 @@
 
 #include "src/media/audio/services/device_registry/control_creator_server.h"
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
 #include <lib/fit/internal/result.h>
 #include <lib/syslog/cpp/macros.h>
 
-#include <optional>
 #include <utility>
 
 #include "src/media/audio/services/device_registry/audio_device_registry.h"
diff --git a/src/media/audio/services/device_registry/control_creator_server_unittest.cc b/src/media/audio/services/device_registry/control_creator_server_unittest.cc
index 521cd75..d767993 100644
--- a/src/media/audio/services/device_registry/control_creator_server_unittest.cc
+++ b/src/media/audio/services/device_registry/control_creator_server_unittest.cc
@@ -8,7 +8,6 @@
 
 #include <gtest/gtest.h>
 
-#include "src/media/audio/services/common/testing/test_server_and_async_client.h"
 #include "src/media/audio/services/device_registry/adr_server_unittest_base.h"
 
 namespace media_audio {
@@ -16,6 +15,7 @@
 
 class ControlCreatorServerTest : public AudioDeviceRegistryServerTestBase {};
 class ControlCreatorServerCodecTest : public ControlCreatorServerTest {};
+class ControlCreatorServerCompositeTest : public ControlCreatorServerTest {};
 class ControlCreatorServerStreamConfigTest : public ControlCreatorServerTest {};
 
 /////////////////////
@@ -45,13 +45,13 @@
   auto control_creator = CreateTestControlCreatorServer();
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   auto fake_driver = CreateFakeCodecOutput();
-  adr_service_->AddDevice(Device::Create(
-      adr_service_, dispatcher(), "Test codec name", fuchsia_audio_device::DeviceType::kCodec,
+  adr_service()->AddDevice(Device::Create(
+      adr_service(), dispatcher(), "Test codec name", fuchsia_audio_device::DeviceType::kCodec,
       fuchsia_audio_device::DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto control_endpoints = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client = fidl::Client<fuchsia_audio_device::Control>(
       std::move(control_endpoints.client), dispatcher());
@@ -59,7 +59,7 @@
 
   control_creator->client()
       ->Create({{
-          .token_id = (*adr_service_->devices().begin())->token_id(),
+          .token_id = (*adr_service()->devices().begin())->token_id(),
           .control_server = std::move(control_endpoints.server),
       }})
       .Then([&received_callback](
@@ -71,6 +71,45 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value());
+}
+
+/////////////////////
+// Composite tests
+//
+// Validate the ControlCreator/CreateControl method for Composite devices.
+TEST_F(ControlCreatorServerCompositeTest, CreateControl) {
+  auto control_creator = CreateTestControlCreatorServer();
+  ASSERT_EQ(ControlCreatorServer::count(), 1u);
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(
+      Device::Create(adr_service(), dispatcher(), "Test composite name",
+                     fuchsia_audio_device::DeviceType::kComposite,
+                     fuchsia_audio_device::DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  auto control_endpoints = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
+  auto control_client = fidl::Client<fuchsia_audio_device::Control>(
+      std::move(control_endpoints.client), dispatcher());
+  auto received_callback = false;
+
+  control_creator->client()
+      ->Create({{
+          .token_id = (*adr_service()->devices().begin())->token_id(),
+          .control_server = std::move(control_endpoints.server),
+      }})
+      .Then([&received_callback](
+                fidl::Result<fuchsia_audio_device::ControlCreator::Create>& result) mutable {
+        received_callback = true;
+        EXPECT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value());
 }
 
 /////////////////////
@@ -81,13 +120,13 @@
   auto control_creator = CreateTestControlCreatorServer();
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(
-      adr_service_, dispatcher(), "Test output name", fuchsia_audio_device::DeviceType::kOutput,
+  adr_service()->AddDevice(Device::Create(
+      adr_service(), dispatcher(), "Test output name", fuchsia_audio_device::DeviceType::kOutput,
       fuchsia_audio_device::DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto control_endpoints = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client = fidl::Client<fuchsia_audio_device::Control>(
       std::move(control_endpoints.client), dispatcher());
@@ -95,7 +134,7 @@
 
   control_creator->client()
       ->Create({{
-          .token_id = (*adr_service_->devices().begin())->token_id(),
+          .token_id = (*adr_service()->devices().begin())->token_id(),
           .control_server = std::move(control_endpoints.server),
       }})
       .Then([&received_callback](
@@ -107,6 +146,7 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value());
 }
 
 }  // namespace
diff --git a/src/media/audio/services/device_registry/control_creator_server_warning_unittest.cc b/src/media/audio/services/device_registry/control_creator_server_warning_unittest.cc
index 7e16f8e..b0e1dd5 100644
--- a/src/media/audio/services/device_registry/control_creator_server_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/control_creator_server_warning_unittest.cc
@@ -7,7 +7,6 @@
 
 #include <gtest/gtest.h>
 
-#include "src/media/audio/services/common/testing/test_server_and_async_client.h"
 #include "src/media/audio/services/device_registry/adr_server_unittest_base.h"
 #include "src/media/audio/services/device_registry/control_creator_server.h"
 
@@ -20,6 +19,7 @@
 
 class ControlCreatorServerWarningTest : public AudioDeviceRegistryServerTestBase {};
 class ControlCreatorServerCodecWarningTest : public ControlCreatorServerWarningTest {};
+class ControlCreatorServerCompositeWarningTest : public ControlCreatorServerWarningTest {};
 class ControlCreatorServerStreamConfigWarningTest : public ControlCreatorServerWarningTest {};
 
 /////////////////////
@@ -30,15 +30,14 @@
   auto control_creator = CreateTestControlCreatorServer();
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
 
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   auto received_callback = false;
   control_creator->client()
       ->Create({{
           // Missing token_id
-          .control_server = std::move(control_endpoints->server),
+          .control_server = std::move(server),
       }})
       .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
         ASSERT_TRUE(result.is_error());
@@ -51,6 +50,7 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value());
 }
 
 /////////////////////
@@ -63,12 +63,12 @@
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto fake_driver = CreateFakeCodecOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto received_callback = false;
   std::optional<TokenId> added_device_id;
 
@@ -86,16 +86,15 @@
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
   ASSERT_TRUE(added_device_id);
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
       ->Create({{
           .token_id = *added_device_id - 1,  // Bad token_id
-          .control_server = std::move(control_endpoints->server),
+          .control_server = std::move(server),
       }})
       .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
         received_callback = true;
@@ -108,6 +107,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
 }
 
 TEST_F(ControlCreatorServerCodecWarningTest, MissingServerEnd) {
@@ -116,13 +118,13 @@
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto fake_driver = CreateFakeCodecInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto received_callback = false;
   std::optional<TokenId> added_device_id;
 
@@ -139,10 +141,9 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(added_device_id);
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
@@ -161,19 +162,22 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
 }
 
 TEST_F(ControlCreatorServerCodecWarningTest, BadServerEnd) {
   auto control_creator = CreateTestControlCreatorServer();
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   auto fake_driver = CreateFakeCodecOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   std::optional<TokenId> added_device_id;
   auto received_callback = false;
 
@@ -194,13 +198,13 @@
 
     RunLoopUntilIdle();
     ASSERT_TRUE(received_callback);
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
   }
 
   ASSERT_TRUE(added_device_id);
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
@@ -219,19 +223,21 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 0u);
+  ASSERT_TRUE(control_creator_fidl_error_status().has_value());
+  EXPECT_EQ(*control_creator_fidl_error_status(), ZX_ERR_INVALID_ARGS);
 }
 
 TEST_F(ControlCreatorServerCodecWarningTest, IdAlreadyControlled) {
   auto control_creator = CreateTestControlCreatorServer();
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   auto fake_driver = CreateFakeCodecInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   std::optional<TokenId> added_device_id;
   auto received_callback = false;
 
@@ -252,20 +258,20 @@
 
     RunLoopUntilIdle();
     ASSERT_TRUE(received_callback);
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
   }
 
   ASSERT_TRUE(added_device_id);
   ASSERT_EQ(ControlServer::count(), 0u);
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_1 = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
       ->Create({{
           .token_id = *added_device_id,
-          .control_server = std::move(control_endpoints->server),
+          .control_server = std::move(server),
       }})
       .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
         received_callback = true;
@@ -276,16 +282,17 @@
   ASSERT_TRUE(received_callback);
   ASSERT_EQ(ControlServer::count(), 1u);
   EXPECT_TRUE(control_client_1.is_valid());
-  auto control_endpoints2 = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client2, server2] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_2 = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints2->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client2), dispatcher(), control_fidl_handler().get());
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
   received_callback = false;
 
   control_creator->client()
       ->Create({{
           .token_id = *added_device_id,
-          .control_server = std::move(control_endpoints2->server),
+          .control_server = std::move(server2),
       }})
       .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
         received_callback = true;
@@ -299,6 +306,268 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
+}
+
+// TODO(https://fxbug.dev/42068381): If Health can change post-initialization, test: device becomes
+//   unhealthy before ControlCreator/Create. Expect Obs/Ctl/RingBuf to drop + Reg/WatcDevRemoved.
+
+/////////////////////
+// Composite tests
+//
+// ControlCreator/Create with an unknown ID should fail.
+TEST_F(ControlCreatorServerCompositeWarningTest, BadId) {
+  auto control_creator = CreateTestControlCreatorServer();
+  ASSERT_EQ(ControlCreatorServer::count(), 1u);
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  std::optional<TokenId> added_device_id;
+  auto received_callback = false;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback,
+       &added_device_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        ASSERT_TRUE(result->devices());
+        ASSERT_EQ(result->devices()->size(), 1u);
+        ASSERT_TRUE(result->devices()->at(0).token_id());
+        added_device_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(added_device_id);
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
+  auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
+      std::move(client), dispatcher(), control_fidl_handler().get());
+  received_callback = false;
+
+  control_creator->client()
+      ->Create({{
+          .token_id = *added_device_id - 1,  // Bad token_id
+          .control_server = std::move(server),
+      }})
+      .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().domain_error(),
+                  fuchsia_audio_device::ControlCreatorError::kDeviceNotFound)
+            << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
+}
+
+TEST_F(ControlCreatorServerCompositeWarningTest, MissingServerEnd) {
+  auto control_creator = CreateTestControlCreatorServer();
+  ASSERT_EQ(ControlCreatorServer::count(), 1u);
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  std::optional<TokenId> added_device_id;
+  auto received_callback = false;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback,
+       &added_device_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        ASSERT_TRUE(result->devices());
+        ASSERT_EQ(result->devices()->size(), 1u);
+        ASSERT_TRUE(result->devices()->at(0).token_id());
+        added_device_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(added_device_id);
+
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
+  auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
+      std::move(client), dispatcher(), control_fidl_handler().get());
+  received_callback = false;
+
+  control_creator->client()
+      ->Create({{
+          .token_id = *added_device_id,
+          // Missing server_end
+      }})
+      .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().domain_error(),
+                  fuchsia_audio_device::ControlCreatorError::kInvalidControl)
+            << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
+}
+
+TEST_F(ControlCreatorServerCompositeWarningTest, BadServerEnd) {
+  auto control_creator = CreateTestControlCreatorServer();
+  ASSERT_EQ(ControlCreatorServer::count(), 1u);
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  std::optional<TokenId> added_device_id;
+  auto received_callback = false;
+
+  {
+    auto registry = CreateTestRegistryServer();
+    ASSERT_EQ(RegistryServer::count(), 1u);
+
+    registry->client()->WatchDevicesAdded().Then(
+        [&received_callback,
+         &added_device_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          ASSERT_TRUE(result->devices());
+          ASSERT_EQ(result->devices()->size(), 1u);
+          ASSERT_TRUE(result->devices()->at(0).token_id());
+          added_device_id = *result->devices()->at(0).token_id();
+        });
+
+    RunLoopUntilIdle();
+    ASSERT_TRUE(received_callback);
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  }
+
+  ASSERT_TRUE(added_device_id);
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
+  auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
+      std::move(client), dispatcher(), control_fidl_handler().get());
+  received_callback = false;
+
+  control_creator->client()
+      ->Create({{
+          .token_id = *added_device_id,
+          .control_server = fidl::ServerEnd<fuchsia_audio_device::Control>(),  // Bad server_end
+      }})
+      .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_INVALID_ARGS)
+            << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_EQ(ControlServer::count(), 0u);
+  ASSERT_TRUE(control_creator_fidl_error_status().has_value());
+  EXPECT_EQ(*control_creator_fidl_error_status(), ZX_ERR_INVALID_ARGS);
+}
+
+TEST_F(ControlCreatorServerCompositeWarningTest, IdAlreadyControlled) {
+  auto control_creator = CreateTestControlCreatorServer();
+  ASSERT_EQ(ControlCreatorServer::count(), 1u);
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  std::optional<TokenId> added_device_id;
+  auto received_callback = false;
+
+  {
+    auto registry = CreateTestRegistryServer();
+    ASSERT_EQ(RegistryServer::count(), 1u);
+
+    registry->client()->WatchDevicesAdded().Then(
+        [&received_callback,
+         &added_device_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          ASSERT_TRUE(result->devices());
+          ASSERT_EQ(result->devices()->size(), 1u);
+          ASSERT_TRUE(result->devices()->at(0).token_id());
+          added_device_id = *result->devices()->at(0).token_id();
+        });
+
+    RunLoopUntilIdle();
+    ASSERT_TRUE(received_callback);
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  }
+
+  ASSERT_TRUE(added_device_id);
+  ASSERT_EQ(ControlServer::count(), 0u);
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
+  auto control_client_1 = fidl::Client<fuchsia_audio_device::Control>(
+      std::move(client), dispatcher(), control_fidl_handler().get());
+  received_callback = false;
+
+  control_creator->client()
+      ->Create({{
+          .token_id = *added_device_id,
+          .control_server = std::move(server),
+      }})
+      .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  EXPECT_TRUE(control_client_1.is_valid());
+  auto [client2, server2] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
+  auto control_client_2 = fidl::Client<fuchsia_audio_device::Control>(
+      std::move(client2), dispatcher(), control_fidl_handler().get());
+  received_callback = false;
+
+  control_creator->client()
+      ->Create({{
+          .token_id = *added_device_id,
+          .control_server = std::move(server2),
+      }})
+      .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().domain_error(),
+                  fuchsia_audio_device::ControlCreatorError::kAlreadyAllocated)
+            << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
 }
 
 // TODO(https://fxbug.dev/42068381): If Health can change post-initialization, test: device becomes
@@ -314,13 +583,13 @@
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   std::optional<TokenId> added_device_id;
   auto received_callback = false;
 
@@ -337,16 +606,15 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(added_device_id);
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
       ->Create({{
           .token_id = *added_device_id - 1,  // Bad token_id
-          .control_server = std::move(control_endpoints->server),
+          .control_server = std::move(server),
       }})
       .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
         received_callback = true;
@@ -359,6 +627,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
 }
 
 TEST_F(ControlCreatorServerStreamConfigWarningTest, MissingServerEnd) {
@@ -367,13 +638,13 @@
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto fake_driver = CreateFakeStreamConfigInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test input name",
-                                         fuchsia_audio_device::DeviceType::kInput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test input name",
+                                          fuchsia_audio_device::DeviceType::kInput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   std::optional<TokenId> added_device_id;
   auto received_callback = false;
 
@@ -392,10 +663,9 @@
   ASSERT_TRUE(received_callback);
   ASSERT_TRUE(added_device_id);
 
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
@@ -414,19 +684,22 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
 }
 
 TEST_F(ControlCreatorServerStreamConfigWarningTest, BadServerEnd) {
   auto control_creator = CreateTestControlCreatorServer();
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   std::optional<TokenId> added_device_id;
   auto received_callback = false;
 
@@ -447,13 +720,13 @@
 
     RunLoopUntilIdle();
     ASSERT_TRUE(received_callback);
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
   }
 
   ASSERT_TRUE(added_device_id);
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_unused = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
@@ -472,19 +745,21 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 0u);
+  ASSERT_TRUE(control_creator_fidl_error_status().has_value());
+  EXPECT_EQ(*control_creator_fidl_error_status(), ZX_ERR_INVALID_ARGS);
 }
 
 TEST_F(ControlCreatorServerStreamConfigWarningTest, IdAlreadyControlled) {
   auto control_creator = CreateTestControlCreatorServer();
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   auto fake_driver = CreateFakeStreamConfigInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test input name",
-                                         fuchsia_audio_device::DeviceType::kInput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test input name",
+                                          fuchsia_audio_device::DeviceType::kInput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   std::optional<TokenId> added_device_id;
   auto received_callback = false;
 
@@ -505,20 +780,20 @@
 
     RunLoopUntilIdle();
     ASSERT_TRUE(received_callback);
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
   }
 
   ASSERT_TRUE(added_device_id);
   ASSERT_EQ(ControlServer::count(), 0u);
-  auto control_endpoints = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_1 = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
       ->Create({{
           .token_id = *added_device_id,
-          .control_server = std::move(control_endpoints->server),
+          .control_server = std::move(server),
       }})
       .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
         received_callback = true;
@@ -529,16 +804,15 @@
   ASSERT_TRUE(received_callback);
   ASSERT_EQ(ControlServer::count(), 1u);
   EXPECT_TRUE(control_client_1.is_valid());
-  auto control_endpoints2 = fidl::CreateEndpoints<fuchsia_audio_device::Control>();
-  ASSERT_TRUE(control_endpoints2.is_ok());
+  auto [client2, server2] = fidl::Endpoints<fuchsia_audio_device::Control>::Create();
   auto control_client_2 = fidl::Client<fuchsia_audio_device::Control>(
-      std::move(control_endpoints2->client), dispatcher(), control_fidl_handler_.get());
+      std::move(client2), dispatcher(), control_fidl_handler().get());
   received_callback = false;
 
   control_creator->client()
       ->Create({{
           .token_id = *added_device_id,
-          .control_server = std::move(control_endpoints2->server),
+          .control_server = std::move(server2),
       }})
       .Then([&received_callback](fidl::Result<ControlCreator::Create>& result) mutable {
         received_callback = true;
@@ -552,6 +826,8 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
 }
 
 // TODO(https://fxbug.dev/42068381): If Health can change post-initialization, test: device becomes
diff --git a/src/media/audio/services/device_registry/control_server.cc b/src/media/audio/services/device_registry/control_server.cc
index 2d51e6c..59e5547 100644
--- a/src/media/audio/services/device_registry/control_server.cc
+++ b/src/media/audio/services/device_registry/control_server.cc
@@ -19,6 +19,7 @@
 #include <optional>
 #include <utility>
 
+#include "lib/zx/result.h"
 #include "src/media/audio/services/device_registry/device.h"
 #include "src/media/audio/services/device_registry/logging.h"
 #include "src/media/audio/services/device_registry/ring_buffer_server.h"
@@ -208,8 +209,8 @@
     element_id = *request.element_id();
     auto& rb_ids = device_->ring_buffer_endpoint_ids();
     if (rb_ids.find(element_id) == rb_ids.end()) {
-      ADR_WARN_METHOD()
-          << "required field 'element_id' does not refer to an ENDPOINT of type RING_BUFFER";
+      ADR_WARN_METHOD() << "required field 'element_id' (" << element_id
+                        << ") does not refer to an ENDPOINT of type RING_BUFFER";
       completer.Reply(
           fit::error(fuchsia_audio_device::ControlCreateRingBufferError::kInvalidElementId));
       return;
@@ -217,14 +218,15 @@
   }
 
   if (create_ring_buffer_completers_.find(element_id) != create_ring_buffer_completers_.end()) {
-    ADR_WARN_METHOD() << "previous `CreateRingBuffer` request has not yet completed";
+    ADR_WARN_METHOD() << "(element_id " << element_id
+                      << ") previous `CreateRingBuffer` request has not completed";
     completer.Reply(
         fit::error(fuchsia_audio_device::ControlCreateRingBufferError::kAlreadyPending));
     return;
   }
 
   if (!request.options()) {
-    ADR_WARN_METHOD() << "required field 'options' is missing";
+    ADR_WARN_METHOD() << "(element_id " << element_id << ") required field 'options' is missing";
     completer.Reply(
         fit::error(fuchsia_audio_device::ControlCreateRingBufferError::kInvalidOptions));
     return;
@@ -232,33 +234,38 @@
   if (!request.options()->format() || !request.options()->format()->sample_type() ||
       !request.options()->format()->channel_count() ||
       !request.options()->format()->frames_per_second()) {
-    ADR_WARN_METHOD() << "required 'options.format' (or one of its required members) is missing";
+    ADR_WARN_METHOD() << "(element_id " << element_id
+                      << ") required 'options.format' (or one of its required members) is missing";
     completer.Reply(fit::error(fuchsia_audio_device::ControlCreateRingBufferError::kInvalidFormat));
     return;
   }
   if (!request.options()->ring_buffer_min_bytes()) {
-    ADR_WARN_METHOD() << "required field 'options.ring_buffer_min_bytes' is missing";
+    ADR_WARN_METHOD() << "(element_id " << element_id
+                      << ") required field 'options.ring_buffer_min_bytes' is missing";
     completer.Reply(
         fit::error(fuchsia_audio_device::ControlCreateRingBufferError::kInvalidMinBytes));
     return;
   }
   if (!request.ring_buffer_server()) {
-    ADR_WARN_METHOD() << "required field 'ring_buffer_server' is missing";
+    ADR_WARN_METHOD() << "(element_id " << element_id
+                      << ") required field 'ring_buffer_server' is missing";
     completer.Reply(
         fit::error(fuchsia_audio_device::ControlCreateRingBufferError::kInvalidRingBuffer));
     return;
   }
   if (TryGetRingBufferServer(element_id)) {
-    ADR_WARN_METHOD() << "device RingBuffer already exists";
+    ADR_WARN_METHOD() << "(element_id " << element_id << ") device RingBuffer already exists";
     completer.Reply(
         fit::error(fuchsia_audio_device::wire::ControlCreateRingBufferError::kAlreadyAllocated));
+    return;
   }
 
   auto driver_format =
       device_->SupportedDriverFormatForClientFormat(element_id, *request.options()->format());
   // Fail if device cannot satisfy the requested format.
   if (!driver_format) {
-    ADR_WARN_METHOD() << "device does not support the specified options";
+    ADR_WARN_METHOD() << "(element_id " << element_id
+                      << ") device does not support the specified options";
     completer.Reply(
         fit::error(fuchsia_audio_device::ControlCreateRingBufferError::kFormatMismatch));
     return;
@@ -274,7 +281,8 @@
         if (create_ring_buffer_completers_.find(element_id) ==
             create_ring_buffer_completers_.end()) {
           ADR_WARN_OBJECT()
-              << "create_ring_buffer_completer_ gone by the time the CreateRingBuffer callback ran";
+              << "(element_id " << element_id
+              << ") create_ring_buffer_completer_ gone by the time the CreateRingBuffer callback ran";
           device_->DropRingBuffer(element_id);  //  Let this unwind the RingBufferServer.
           return;
         }
@@ -557,6 +565,7 @@
     auto stop_completer = std::move(*codec_stop_completer_);
     codec_stop_completer_.reset();
     stop_completer.Reply(fit::error(fuchsia_audio_device::ControlCodecStopError::kDeviceError));
+    return;
   }
 
   // We need `stop_time` to complete this, so we wait for the Device to notify us. Besides,
@@ -614,31 +623,274 @@
   completer.Reply(fit::success(fuchsia_audio_device::ControlResetResponse{}));
 }
 
-// fuchsia.hardware.audio.signalprocessing support
+// fuchsia.hardware.audio.signalprocessing.SignalProcessing support
 //
 void ControlServer::GetTopologies(GetTopologiesCompleter::Sync& completer) {
-  ADR_WARN_METHOD() << kClassName << "(" << this << ")::" << __func__
-                    << ": signalprocessing not supported";
-  completer.Reply(fit::error(ZX_ERR_NOT_SUPPORTED));
+  ADR_LOG_METHOD(kLogControlServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Reply(zx::error(ZX_ERR_INTERNAL));
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "This device_type does not support " << __func__;
+    completer.Reply(zx::error(ZX_ERR_WRONG_TYPE));
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogSignalProcessingFidlCalls)
+        << "This driver does not support signalprocessing";
+    completer.Reply(zx::error(ZX_ERR_NOT_SUPPORTED));
+    return;
+  }
+
+  FX_CHECK(device_->info().has_value() &&
+           device_->info()->signal_processing_topologies().has_value() &&
+           !device_->info()->signal_processing_topologies()->empty());
+  completer.Reply(zx::ok(*device_->info()->signal_processing_topologies()));
 }
 
-void ControlServer::GetElements(GetElementsCompleter::Sync& completer) {
-  ADR_WARN_METHOD() << kClassName << "(" << this << ")::" << __func__
-                    << ": signalprocessing not supported";
-  completer.Reply(fit::error(ZX_ERR_NOT_SUPPORTED));
+void ControlServer::WatchTopology(WatchTopologyCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogControlServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Close(ZX_ERR_INTERNAL);
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "This device_type does not support " << __func__;
+    completer.Close(ZX_ERR_WRONG_TYPE);
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogSignalProcessingFidlCalls)
+        << "This driver does not support signalprocessing";
+    completer.Close(ZX_ERR_NOT_SUPPORTED);
+    return;
+  }
+
+  if (watch_topology_completer_) {
+    ADR_WARN_METHOD() << "previous `WatchTopology` request has not yet completed";
+    completer.Close(ZX_ERR_BAD_STATE);
+    return;
+  }
+
+  FX_CHECK(!watch_topology_completer_.has_value());
+  watch_topology_completer_ = completer.ToAsync();
+  FX_CHECK(watch_topology_completer_.has_value());
+  MaybeCompleteWatchTopology();
 }
 
-// For now, don't do anything with this.
+void ControlServer::SetTopology(SetTopologyRequest& request,
+                                SetTopologyCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogControlServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Reply(zx::error(ZX_ERR_INTERNAL));
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "unsupported method for this device_type";
+    completer.Reply(zx::error(ZX_ERR_WRONG_TYPE));
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogSignalProcessingFidlCalls)
+        << "This driver does not support signalprocessing";
+    completer.Reply(zx::error(ZX_ERR_NOT_SUPPORTED));
+    return;
+  }
+
+  if (device_->topology_ids().find(request.topology_id()) == device_->topology_ids().end()) {
+    ADR_WARN_METHOD() << "Unknown topology_id " << request.topology_id();
+    completer.Reply(zx::error(ZX_ERR_INVALID_ARGS));
+    return;
+  }
+
+  if (auto status = device_->SetTopology(request.topology_id()); status == ZX_OK) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogSignalProcessingFidlCalls)
+        << "SetTopology succeeded";
+    completer.Reply(zx::ok());
+  } else {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogSignalProcessingFidlCalls)
+        << "SetTopology failed: " << status;
+    completer.Reply(zx::error(status));
+  }
+}
+
 void ControlServer::TopologyChanged(TopologyId topology_id) {
   ADR_LOG_METHOD(kLogControlServerMethods || kLogNotifyMethods)
       << "(topology_id " << topology_id << ")";
+
+  topology_id_to_notify_ = topology_id;
+  MaybeCompleteWatchTopology();
 }
 
-// For now, don't do anything with this.
+void ControlServer::MaybeCompleteWatchTopology() {
+  if (watch_topology_completer_ && topology_id_to_notify_) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogNotifyMethods)
+        << "completing(" << *topology_id_to_notify_ << ")";
+    auto completer = std::move(*watch_topology_completer_);
+    watch_topology_completer_.reset();
+
+    auto new_topology_id = *topology_id_to_notify_;
+    topology_id_to_notify_.reset();
+
+    completer.Reply({new_topology_id});
+  } else {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogNotifyMethods) << "NOT completing";
+  }
+}
+
+void ControlServer::GetElements(GetElementsCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogObserverServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Reply(zx::error(ZX_ERR_INTERNAL));
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "This device_type does not support " << __func__;
+    completer.Reply(zx::error(ZX_ERR_WRONG_TYPE));
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogSignalProcessingFidlCalls)
+        << "This driver does not support signalprocessing";
+    completer.Reply(zx::error(ZX_ERR_NOT_SUPPORTED));
+    return;
+  }
+
+  FX_CHECK(device_->info().has_value() &&
+           device_->info()->signal_processing_elements().has_value() &&
+           !device_->info()->signal_processing_elements()->empty());
+  completer.Reply(zx::ok(*device_->info()->signal_processing_elements()));
+}
+
+void ControlServer::WatchElementState(WatchElementStateRequest& request,
+                                      WatchElementStateCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogControlServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Close(ZX_ERR_INTERNAL);
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "This device_type does not support " << __func__;
+    completer.Close(ZX_ERR_WRONG_TYPE);
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogSignalProcessingFidlCalls)
+        << "This driver does not support signalprocessing";
+    completer.Close(ZX_ERR_NOT_SUPPORTED);
+    return;
+  }
+
+  if (device_->element_ids().find(request.processing_element_id()) ==
+      device_->element_ids().end()) {
+    ADR_WARN_METHOD() << "Unknown element_id " << request.processing_element_id();
+    completer.Close(ZX_ERR_INVALID_ARGS);
+    return;
+  }
+
+  ElementId element_id = request.processing_element_id();
+  if (watch_element_state_completers_.find(element_id) != watch_element_state_completers_.end()) {
+    ADR_WARN_METHOD() << "previous `WatchElementState(" << element_id
+                      << ")` request has not yet completed";
+    completer.Close(ZX_ERR_BAD_STATE);
+    return;
+  }
+
+  watch_element_state_completers_.insert({element_id, completer.ToAsync()});
+  MaybeCompleteWatchElementState(element_id);
+}
+
+void ControlServer::SetElementState(SetElementStateRequest& request,
+                                    SetElementStateCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogControlServerMethods)
+      << "(element_id " << request.processing_element_id() << ")";
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Reply(zx::error(ZX_ERR_INTERNAL));
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "unsupported method for this device_type";
+    completer.Reply(zx::error(ZX_ERR_WRONG_TYPE));
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogSignalProcessingFidlCalls)
+        << "This driver does not support signalprocessing";
+    completer.Reply(zx::error(ZX_ERR_NOT_SUPPORTED));
+    return;
+  }
+
+  if (device_->element_ids().find(request.processing_element_id()) ==
+      device_->element_ids().end()) {
+    ADR_WARN_METHOD() << "Unknown element_id " << request.processing_element_id();
+    completer.Reply(zx::error(ZX_ERR_INVALID_ARGS));
+    return;
+  }
+
+  if (auto status = device_->SetElementState(request.processing_element_id(), request.state());
+      status == ZX_OK) {
+    completer.Reply(zx::ok());
+  } else {
+    completer.Reply(zx::error(status));
+  }
+}
+
 void ControlServer::ElementStateChanged(
     ElementId element_id, fuchsia_hardware_audio_signalprocessing::ElementState element_state) {
   ADR_LOG_METHOD(kLogControlServerMethods || kLogNotifyMethods)
       << "(element_id " << element_id << ")";
+
+  element_states_to_notify_.insert_or_assign(element_id, element_state);
+  MaybeCompleteWatchElementState(element_id);
+}
+
+// If we have an outstanding hanging-get and a state-change, respond with the state change.
+void ControlServer::MaybeCompleteWatchElementState(ElementId element_id) {
+  if (watch_element_state_completers_.find(element_id) != watch_element_state_completers_.end() &&
+      element_states_to_notify_.find(element_id) != element_states_to_notify_.end()) {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogNotifyMethods) << element_id << ": completing";
+    auto completer = std::move(watch_element_state_completers_.find(element_id)->second);
+    watch_element_state_completers_.erase(element_id);
+
+    auto new_element_state = element_states_to_notify_.find(element_id)->second;
+    element_states_to_notify_.erase(element_id);
+
+    completer.Reply({new_element_state});
+  } else {
+    ADR_LOG_METHOD(kLogControlServerMethods || kLogNotifyMethods)
+        << element_id << ": NOT completing";
+  }
 }
 
 }  // namespace media_audio
diff --git a/src/media/audio/services/device_registry/control_server.h b/src/media/audio/services/device_registry/control_server.h
index 533b945..e0ac684 100644
--- a/src/media/audio/services/device_registry/control_server.h
+++ b/src/media/audio/services/device_registry/control_server.h
@@ -78,24 +78,19 @@
   void CodecStart(CodecStartCompleter::Sync& completer) final;
   void CodecStop(CodecStopCompleter::Sync& completer) final;
 
-  // fuchsia.hardware.audio.signalprocessing support
+  // fuchsia.hardware.audio.signalprocessing.SignalProcessing support
   //
   void GetTopologies(GetTopologiesCompleter::Sync& completer) final;
   void GetElements(GetElementsCompleter::Sync& completer) final;
-  void WatchTopology(WatchTopologyCompleter::Sync& completer) final {
-    completer.Close(ZX_ERR_NOT_SUPPORTED);
-  }
+  void WatchTopology(WatchTopologyCompleter::Sync& completer) final;
   void WatchElementState(WatchElementStateRequest& request,
-                         WatchElementStateCompleter::Sync& completer) final {
-    completer.Close(ZX_ERR_NOT_SUPPORTED);
-  }
-  void SetTopology(SetTopologyRequest& request, SetTopologyCompleter::Sync& completer) final {
-    completer.Reply(fit::error(ZX_ERR_NOT_SUPPORTED));
-  }
+                         WatchElementStateCompleter::Sync& completer) final;
+  void SetTopology(SetTopologyRequest& request, SetTopologyCompleter::Sync& completer) final;
   void SetElementState(SetElementStateRequest& request,
-                       SetElementStateCompleter::Sync& completer) final {
-    completer.Reply(fit::error(ZX_ERR_NOT_SUPPORTED));
-  }
+                       SetElementStateCompleter::Sync& completer) final;
+
+  void MaybeCompleteWatchTopology();
+  void MaybeCompleteWatchElementState(ElementId element_id);
 
   // Static object count, for debugging purposes.
   static inline uint64_t count() { return count_; }
@@ -124,6 +119,14 @@
   std::unordered_map<ElementId, SetDaiFormatCompleter::Async> set_dai_format_completers_;
   std::unordered_map<ElementId, CreateRingBufferCompleter::Async> create_ring_buffer_completers_;
 
+  std::optional<TopologyId> topology_id_to_notify_;
+  std::optional<WatchTopologyCompleter::Async> watch_topology_completer_;
+  std::optional<SetTopologyCompleter::Async> set_topology_completer_;
+
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states_to_notify_;
+  std::unordered_map<ElementId, WatchElementStateCompleter::Async> watch_element_state_completers_;
+
   // Locks a weak_ptr ring_buffer_server_ to shared_ptr and returns it, or returns nullptr.
   std::shared_ptr<RingBufferServer> TryGetRingBufferServer(ElementId element_id);
   std::unordered_map<ElementId, std::weak_ptr<RingBufferServer>> ring_buffer_servers_;
diff --git a/src/media/audio/services/device_registry/control_server_unittest.cc b/src/media/audio/services/device_registry/control_server_unittest.cc
index a439c77..b595a9c 100644
--- a/src/media/audio/services/device_registry/control_server_unittest.cc
+++ b/src/media/audio/services/device_registry/control_server_unittest.cc
@@ -10,10 +10,12 @@
 #include <lib/syslog/cpp/macros.h>
 #include <lib/zx/time.h>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/device_registry/adr_server_unittest_base.h"
 #include "src/media/audio/services/device_registry/common_unittest.h"
+#include "src/media/audio/services/device_registry/ring_buffer_server.h"
 #include "src/media/audio/services/device_registry/testing/fake_codec.h"
 #include "src/media/audio/services/device_registry/testing/fake_composite.h"
 #include "src/media/audio/services/device_registry/testing/fake_stream_config.h"
@@ -49,8 +51,9 @@
     auto [control_client_end, control_server_end] =
         CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Control>();
     auto control_client = fidl::Client<fuchsia_audio_device::Control>(
-        std::move(control_client_end), dispatcher(), control_fidl_handler_.get());
+        std::move(control_client_end), dispatcher(), control_fidl_handler().get());
     bool received_callback = false;
+
     control_creator_client
         ->Create({{
             .token_id = token_id,
@@ -61,6 +64,7 @@
           ASSERT_TRUE(result.is_ok()) << result.error_value();
           received_callback = true;
         });
+
     RunLoopUntilIdle();
     EXPECT_TRUE(received_callback);
     EXPECT_TRUE(control_client.is_valid());
@@ -81,9 +85,9 @@
   std::shared_ptr<FakeCodec> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeCodecOutput();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                           fuchsia_audio_device::DeviceType::kCodec,
-                                           DriverClient::WithCodec(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                            fuchsia_audio_device::DeviceType::kCodec,
+                                            DriverClient::WithCodec(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -94,9 +98,9 @@
   std::shared_ptr<FakeComposite> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeComposite();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test composite name",
-                                           fuchsia_audio_device::DeviceType::kComposite,
-                                           DriverClient::WithComposite(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                            fuchsia_audio_device::DeviceType::kComposite,
+                                            DriverClient::WithComposite(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -107,9 +111,9 @@
   std::shared_ptr<FakeStreamConfig> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeStreamConfigOutput();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                           fuchsia_audio_device::DeviceType::kOutput,
-                                           DriverClient::WithStreamConfig(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                            fuchsia_audio_device::DeviceType::kOutput,
+                                            DriverClient::WithStreamConfig(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -121,18 +125,21 @@
 // When client drops their Control, the server should cleanly unwind without hang or WARNING.
 TEST_F(ControlServerCodecTest, CleanClientDrop) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
+
   RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
 
   (void)control->client().UnbindMaybeGetEndpoint();
+
   // If Control client doesn't drop cleanly, ControlServer will emit a WARNING, causing a failure.
 }
 
 // When server closes a client connection, the shutdown should be orderly without hang or WARNING.
 TEST_F(ControlServerCodecTest, CleanServerShutdown) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
+
   RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
 
@@ -148,17 +155,18 @@
 TEST_F(ControlServerCodecTest, BasicClose) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(control_client.is_valid());
+
   (void)control_client.UnbindMaybeGetEndpoint();
 }
 
@@ -169,27 +177,30 @@
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
   control_creator->server().Shutdown(ZX_ERR_PEER_CLOSED);
+
   RunLoopUntilIdle();
   EXPECT_TRUE(control_creator->server().WaitForShutdown(zx::sec(1)));
-
-  EXPECT_TRUE(control_client.is_valid());
   EXPECT_EQ(ControlServer::count(), 1u);
-  (void)control_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+  ASSERT_TRUE(control_creator_fidl_error_status().has_value());
+  EXPECT_EQ(*control_creator_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Verify that the ControlServer shuts down cleanly if the driver drops its Codec.
 TEST_F(ControlServerCodecTest, CodecDropCausesCleanControlServerShutdown) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -200,24 +211,28 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(control->server().WaitForShutdown(zx::sec(5)));
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Validate basic SetDaiFormat functionality, including valid CodecFormatInfo returned.
 TEST_F(ControlServerCodecTest, SetDaiFormat) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
-  auto received_callback = false;
-
   // Determine a safe DaiFormat to set
   auto dai_format =
       SafeDaiFormatFromElementDaiFormatSets(dai_element_id(), device->dai_format_sets());
+  auto received_callback = false;
+
   control->client()
       ->SetDaiFormat({{.dai_format = dai_format}})
       .Then([&received_callback](fidl::Result<Control::SetDaiFormat>& result) {
@@ -230,22 +245,26 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Validate basic CodecStart functionality including a current start_time.
 TEST_F(ControlServerCodecTest, CodecStart) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
-  auto received_callback = false;
   auto dai_format =
       SafeDaiFormatFromElementDaiFormatSets(dai_element_id(), device->dai_format_sets());
+  auto received_callback = false;
+
   control->client()
       ->SetDaiFormat({{.dai_format = dai_format}})
       .Then([&received_callback](fidl::Result<Control::SetDaiFormat>& result) {
@@ -255,9 +274,9 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
-  received_callback = false;
   auto start_time = zx::time::infinite_past();
   auto time_before_start = zx::clock::get_monotonic();
+  received_callback = false;
 
   control->client()->CodecStart().Then(
       [&received_callback, &start_time](fidl::Result<Control::CodecStart>& result) {
@@ -271,14 +290,17 @@
   EXPECT_TRUE(received_callback);
   EXPECT_GT(start_time.get(), time_before_start.get());
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Validate basic CodecStop functionality including a current stop_time.
 TEST_F(ControlServerCodecTest, CodecStop) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -287,6 +309,7 @@
   auto dai_format =
       SafeDaiFormatFromElementDaiFormatSets(dai_element_id(), device->dai_format_sets());
   auto received_callback = false;
+
   control->client()
       ->SetDaiFormat({{.dai_format = dai_format}})
       .Then([&received_callback](fidl::Result<Control::SetDaiFormat>& result) {
@@ -297,6 +320,7 @@
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
   received_callback = false;
+
   control->client()->CodecStart().Then(
       [&received_callback](fidl::Result<Control::CodecStart>& result) {
         received_callback = true;
@@ -321,14 +345,17 @@
   EXPECT_TRUE(received_callback);
   EXPECT_GT(stop_time.get(), time_before_stop.get());
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Reset - validate that the DaiFormat and the Start state are reset.
 TEST_F(ControlServerCodecTest, Reset) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -337,6 +364,7 @@
   auto dai_format =
       SafeDaiFormatFromElementDaiFormatSets(dai_element_id(), device->dai_format_sets());
   auto received_callback = false;
+
   control->client()
       ->SetDaiFormat({{.dai_format = dai_format}})
       .Then([&received_callback](fidl::Result<Control::SetDaiFormat>& result) {
@@ -348,6 +376,7 @@
   ASSERT_TRUE(received_callback);
   received_callback = false;
   zx::time first_start_time;
+
   control->client()->CodecStart().Then(
       [&received_callback, &first_start_time](fidl::Result<Control::CodecStart>& result) {
         received_callback = true;
@@ -369,6 +398,7 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   received_callback = false;
+
   control->client()
       ->SetDaiFormat({{.dai_format = dai_format}})
       .Then([&received_callback](fidl::Result<Control::SetDaiFormat>& result) {
@@ -381,6 +411,7 @@
   EXPECT_TRUE(received_callback);
   received_callback = false;
   zx::time second_start_time;
+
   control->client()->CodecStart().Then(
       [&received_callback, &second_start_time](fidl::Result<Control::CodecStart>& result) {
         received_callback = true;
@@ -393,11 +424,77 @@
   EXPECT_TRUE(received_callback);
   EXPECT_GT(second_start_time.get(), first_start_time.get());
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
-// Add test cases for SetTopology and SetElementState (once implemented)
 //
-// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain).
+// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain),
+// including in the FakeCodec test fixture. Then add positive test cases for
+// GetTopologies/GetElements and WatchTopology/WatchElementState, as are in Composite as well as
+// for SetTopology/SetElementState (once implemented).
+
+// Verify GetTopologies if the driver does not support signalprocessing.
+TEST_F(ControlServerCodecTest, GetTopologiesUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()->GetTopologies().Then([&received_callback](
+                                              fidl::Result<Control::GetTopologies>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify GetElements if the driver does not support signalprocessing.
+TEST_F(ControlServerCodecTest, GetElementsUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()->GetElements().Then([&received_callback](
+                                            fidl::Result<Control::GetElements>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
 
 /////////////////////
 // Composite tests
@@ -405,18 +502,21 @@
 // When client drops their Control, the server should cleanly unwind without hang or WARNING.
 TEST_F(ControlServerCompositeTest, CleanClientDrop) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
+
   RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
 
   (void)control->client().UnbindMaybeGetEndpoint();
+
   // If Control client doesn't drop cleanly, ControlServer will emit a WARNING, causing a failure.
 }
 
 // When server closes a client connection, the shutdown should be orderly without hang or WARNING.
 TEST_F(ControlServerCompositeTest, CleanServerShutdown) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
+
   RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
 
@@ -432,17 +532,18 @@
 TEST_F(ControlServerCompositeTest, BasicClose) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(control_client.is_valid());
+
   (void)control_client.UnbindMaybeGetEndpoint();
 }
 
@@ -450,22 +551,25 @@
 TEST_F(ControlServerCompositeTest, ControlCreatorServerShutdownDoesNotAffectControl) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
   control_creator->server().Shutdown(ZX_ERR_PEER_CLOSED);
+
   RunLoopUntilIdle();
   EXPECT_TRUE(control_creator->server().WaitForShutdown(zx::sec(1)));
-
-  EXPECT_TRUE(control_client.is_valid());
   EXPECT_EQ(ControlServer::count(), 1u);
-  (void)control_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+  ASSERT_TRUE(control_creator_fidl_error_status().has_value());
+  EXPECT_EQ(*control_creator_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Verify that the ControlServer shuts down cleanly if the driver drops its Composite.
@@ -473,7 +577,7 @@
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
   WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -484,6 +588,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(control->server().WaitForShutdown(zx::sec(5)));
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Validate (in depth) the ring_buffer and properties returned from CreateRingBuffer -
@@ -493,8 +600,8 @@
   auto registry = CreateTestRegistryServer();
 
   WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
-  auto device = *adr_service_->devices().begin();
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
+  auto device = *adr_service()->devices().begin();
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -508,7 +615,7 @@
     bool received_callback = false;
 
     auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
     auto requested_format = SafeRingBufferFormatFromElementRingBufferFormatSets(
         ring_buffer_element_id, device->ring_buffer_format_sets());
     uint32_t requested_ring_buffer_bytes = 2000;
@@ -592,8 +699,9 @@
 
   // Allow the ControlServer to destruct, if it (erroneously) wants to.
   RunLoopUntilIdle();
-  EXPECT_TRUE(control->client().is_valid());
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that the Control lives, even if the client drops its child RingBuffer.
@@ -602,8 +710,8 @@
   auto registry = CreateTestRegistryServer();
 
   WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
-  auto device = *adr_service_->devices().begin();
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
+  auto device = *adr_service()->devices().begin();
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -617,7 +725,7 @@
     bool received_callback = false;
 
     auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
 
     control->client()
         ->CreateRingBuffer({{
@@ -647,8 +755,9 @@
 
   // Allow the ControlServer to destruct, if it (erroneously) wants to.
   RunLoopUntilIdle();
-  EXPECT_TRUE(control->client().is_valid());
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that the Control lives, even if the driver drops its RingBuffer connection.
@@ -657,8 +766,8 @@
   auto registry = CreateTestRegistryServer();
 
   WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto device = *adr_service()->devices().begin();
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -701,8 +810,9 @@
 
   // Allow the ControlServer to destruct, if it (erroneously) wants to.
   RunLoopUntilIdle();
-  EXPECT_TRUE(control->client().is_valid());
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Validate basic SetDaiFormat functionality.
@@ -710,7 +820,7 @@
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -739,6 +849,8 @@
     EXPECT_TRUE(received_callback);
     EXPECT_EQ(ControlServer::count(), 1u);
   }
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Reset - validate that the DaiFormat and the Start state are reset.
@@ -746,7 +858,7 @@
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -800,15 +912,522 @@
 
     // Verify that the ControlNotify received the DaiFormat notification.
   }
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
+// Retrieves the static list of Topologies and their properties.
+// Compare results from Control/GetTopologies to the topologies returned in the Device info.
+TEST_F(ControlServerCompositeTest, GetTopologies) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto initial_topologies = device->info()->signal_processing_topologies();
+  ASSERT_TRUE(initial_topologies.has_value() && !initial_topologies->empty());
+
+  auto control = CreateTestControlServer(device);
+  auto received_callback = false;
+  std::vector<::fuchsia_hardware_audio_signalprocessing::Topology> received_topologies;
+
+  control->client()->GetTopologies().Then(
+      [&received_callback, &received_topologies](fidl::Result<Control::GetTopologies>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        received_topologies = result->topologies();
+        EXPECT_FALSE(received_topologies.empty());
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_EQ(initial_topologies->size(), received_topologies.size());
+  EXPECT_THAT(received_topologies, testing::ElementsAreArray(*initial_topologies));
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Retrieves the static list of Elements and their properties.
+// Compare results from Control/GetElements to the elements returned in the Device info.
+TEST_F(ControlServerCompositeTest, GetElements) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto initial_elements = device->info()->signal_processing_elements();
+  ASSERT_TRUE(initial_elements.has_value() && !initial_elements->empty());
+
+  auto control = CreateTestControlServer(device);
+  auto received_callback = false;
+  std::vector<::fuchsia_hardware_audio_signalprocessing::Element> received_elements;
+
+  control->client()->GetElements().Then(
+      [&received_callback, &received_elements](fidl::Result<Control::GetElements>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        received_elements = result->processing_elements();
+        EXPECT_FALSE(received_elements.empty());
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_EQ(initial_elements->size(), received_elements.size());
+  EXPECT_THAT(received_elements, testing::ElementsAreArray(*initial_elements));
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify that WatchTopology correctly returns the initial topology state.
+TEST_F(ControlServerCompositeTest, WatchTopologyInitial) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto control = CreateTestControlServer(device);
+  auto received_callback = false;
+  std::optional<TopologyId> topology_id;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_TRUE(topology_id.has_value());
+  EXPECT_FALSE(topology_map(device).find(*topology_id) == topology_map(device).end());
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify that WatchTopology pends when called a second time (if no change).
+TEST_F(ControlServerCompositeTest, WatchTopologyNoChange) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto control = CreateTestControlServer(device);
+  auto received_callback = false;
+  std::optional<TopologyId> topology_id;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(topology_id.has_value());
+  received_callback = false;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify that WatchTopology works with dynamic changes, after initial query.
+TEST_F(ControlServerCompositeTest, WatchTopologyUpdate) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto control = CreateTestControlServer(device);
+  auto received_callback = false;
+  std::optional<TopologyId> topology_id;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(topology_id.has_value());
+  ASSERT_FALSE(topology_map(device).find(*topology_id) == topology_map(device).end());
+  std::optional<TopologyId> topology_id_to_inject;
+  for (const auto& [id, _] : topology_map(device)) {
+    if (id != *topology_id) {
+      topology_id_to_inject = id;
+      break;
+    }
+  }
+  if (!topology_id_to_inject.has_value()) {
+    GTEST_SKIP() << "Fake driver does not expose multiple topologies";
+  }
+  received_callback = false;
+  topology_id.reset();
+
+  control->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+
+  fake_driver->InjectTopologyChange(topology_id_to_inject);
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(topology_id.has_value());
+  EXPECT_FALSE(topology_map(device).find(*topology_id) == topology_map(device).end());
+  EXPECT_EQ(*topology_id, *topology_id_to_inject);
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify that WatchElementState correctly returns the initial states of all elements.
+TEST_F(ControlServerCompositeTest, WatchElementStateInitial) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto control = CreateTestControlServer(device);
+  auto& elements_from_device = element_map(device);
+  auto received_callback = false;
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states;
+
+  // Gather the complete set of initial element states.
+  for (auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    control->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id,
+               &element_states](fidl::Result<Control::WatchElementState>& result) {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          element_states.insert_or_assign(element_id, result->state());
+        });
+
+    RunLoopUntilIdle();
+    EXPECT_TRUE(received_callback);
+  }
+
+  // Compare them to the collection held by the Device object.
+  EXPECT_EQ(element_states.size(), elements_from_device.size());
+  for (const auto& [element_id, element_record] : elements_from_device) {
+    ASSERT_FALSE(element_states.find(element_id) == element_states.end())
+        << "WatchElementState response not received for element_id " << element_id;
+    const auto& state_from_device = element_record.state;
+    ASSERT_TRUE(state_from_device.has_value())
+        << "Device element_map did not contain ElementState for element_id ";
+    EXPECT_EQ(element_states.find(element_id)->second, state_from_device);
+  }
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify that WatchElementState pends indefinitely, if there has been no change.
+TEST_F(ControlServerCompositeTest, WatchElementStateNoChange) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto control = CreateTestControlServer(device);
+  auto& elements_from_device = element_map(device);
+  auto received_callback = false;
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states;
+
+  // Gather the complete set of initial element states.
+  for (auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    control->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id,
+               &element_states](fidl::Result<Control::WatchElementState>& result) {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          element_states.insert_or_assign(element_id, result->state());
+        });
+
+    // We wait for each WatchElementState in turn.
+    RunLoopUntilIdle();
+    EXPECT_TRUE(received_callback);
+    received_callback = false;
+  }
+
+  for (auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    control->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id](fidl::Result<Control::WatchElementState>& result) {
+          received_callback = true;
+          FAIL() << "Unexpected WatchElementState completion for element_id " << element_id;
+        });
+  }
+
+  // We request all the states from the Elements again, then wait once.
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify that WatchElementState works with dynamic changes, after initial query.
+TEST_F(ControlServerCompositeTest, WatchElementStateUpdate) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto control = CreateTestControlServer(device);
+  auto& elements_from_device = element_map(device);
+  auto received_callback = false;
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states;
+
+  // Gather the complete set of initial element states.
+  for (auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    control->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id,
+               &element_states](fidl::Result<Control::WatchElementState>& result) {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          element_states.insert_or_assign(element_id, result->state());
+        });
+
+    RunLoopUntilIdle();
+    EXPECT_TRUE(received_callback);
+  }
+
+  // Determine which states we can change.
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states_to_inject;
+  auto plug_change_time_to_inject = zx::clock::get_monotonic();
+  for (const auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    const auto& element = element_map_entry.second.element;
+    const auto& state = element_map_entry.second.state;
+    if (element.type() != fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint ||
+        !element.type_specific().has_value() || !element.type_specific()->endpoint().has_value() ||
+        element.type_specific()->endpoint()->plug_detect_capabilities() !=
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kCanAsyncNotify) {
+      continue;
+    }
+    if (!state.has_value() || !state->type_specific().has_value() ||
+        !state->type_specific()->endpoint().has_value() ||
+        !state->type_specific()->endpoint()->plug_state().has_value() ||
+        !state->type_specific()->endpoint()->plug_state()->plugged().has_value() ||
+        !state->type_specific()->endpoint()->plug_state()->plug_state_time().has_value()) {
+      continue;
+    }
+    auto was_plugged = state->type_specific()->endpoint()->plug_state()->plugged();
+    auto new_state = fuchsia_hardware_audio_signalprocessing::ElementState{{
+        .type_specific =
+            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::WithEndpoint(
+                fuchsia_hardware_audio_signalprocessing::EndpointElementState{{
+                    fuchsia_hardware_audio_signalprocessing::PlugState{{
+                        !was_plugged,
+                        plug_change_time_to_inject.get(),
+                    }},
+                }}),
+        .enabled = true,
+        .latency =
+            fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyTime(ZX_USEC(element_id)),
+        .vendor_specific_data = {{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
+                                  'D', 'E', 'F', 'Z'}},  // 'Z' is located at byte [16].
+    }};
+    ASSERT_EQ(new_state.vendor_specific_data()->size(), 17u) << "Test configuration error";
+    element_states_to_inject.insert_or_assign(element_id, new_state);
+  }
+
+  if (element_states_to_inject.empty()) {
+    GTEST_SKIP()
+        << "No element states can be changed, so dynamic element_state change cannot be tested";
+  }
+
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states_received;
+
+  // Inject the changes.
+  for (const auto& element_state_entry : element_states_to_inject) {
+    auto& element_id = element_state_entry.first;
+    auto& element_state = element_state_entry.second;
+    fake_driver->InjectElementStateChange(element_id, element_state);
+    received_callback = false;
+
+    control->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id,
+               &element_states_received](fidl::Result<Control::WatchElementState>& result) {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          element_states_received.insert_or_assign(element_id, result->state());
+        });
+
+    RunLoopUntilIdle();
+    EXPECT_TRUE(received_callback);
+  }
+
+  EXPECT_EQ(element_states_to_inject.size(), element_states_received.size());
+  for (const auto& [element_id, state_received] : element_states_received) {
+    // Compare to actual static values we know.
+    ASSERT_TRUE(state_received.type_specific().has_value());
+    ASSERT_TRUE(state_received.type_specific()->endpoint().has_value());
+    ASSERT_TRUE(state_received.type_specific()->endpoint()->plug_state().has_value());
+    ASSERT_TRUE(state_received.type_specific()->endpoint()->plug_state()->plugged().has_value());
+    ASSERT_TRUE(
+        state_received.type_specific()->endpoint()->plug_state()->plug_state_time().has_value());
+    EXPECT_EQ(*state_received.type_specific()->endpoint()->plug_state()->plug_state_time(),
+              plug_change_time_to_inject.get());
+
+    ASSERT_TRUE(state_received.enabled().has_value());
+    EXPECT_EQ(state_received.enabled(), true);
+
+    ASSERT_TRUE(state_received.latency().has_value());
+    ASSERT_EQ(state_received.latency()->Which(),
+              fuchsia_hardware_audio_signalprocessing::Latency::Tag::kLatencyTime);
+    EXPECT_EQ(state_received.latency()->latency_time().value(), ZX_USEC(element_id));
+
+    ASSERT_TRUE(state_received.vendor_specific_data().has_value());
+    ASSERT_EQ(state_received.vendor_specific_data()->size(), 17u);
+    EXPECT_EQ(state_received.vendor_specific_data()->at(16), 'Z');
+
+    // Compare to what we injected.
+    ASSERT_FALSE(element_states_to_inject.find(element_id) == element_states_to_inject.end())
+        << "Unexpected WatchElementState response received for element_id " << element_id;
+    const auto& state_injected = element_states_to_inject.find(element_id)->second;
+    EXPECT_EQ(state_received, state_injected);
+
+    // Compare the updates received by the client to the collection held by the Device object.
+    ASSERT_FALSE(elements_from_device.find(element_id) == elements_from_device.end());
+    const auto& state_from_device = elements_from_device.find(element_id)->second.state;
+    EXPECT_EQ(state_received, state_from_device);
+  }
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify SetTopology (OK to use WatchTopology in doing this)
+TEST_F(ControlServerCompositeTest, SetTopology) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  if (device->topology_ids().size() == 1) {
+    GTEST_SKIP() << "Fake driver does not expose multiple topologies";
+  }
+
+  auto control = CreateTestControlServer(device);
+  auto received_callback = false;
+  std::optional<TopologyId> current_topology_id;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback, &current_topology_id](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        current_topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(current_topology_id.has_value());
+  ASSERT_TRUE(device->topology_ids().find(*current_topology_id) != device->topology_ids().end());
+  TopologyId topology_id_to_set = 0;
+  for (auto id : device->topology_ids()) {
+    if (id != *current_topology_id) {
+      topology_id_to_set = id;
+      break;
+    }
+  }
+  received_callback = false;
+  std::optional<TopologyId> new_topology_id;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback, &new_topology_id](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        new_topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+  auto received_callback2 = false;
+
+  control->client()
+      ->SetTopology(topology_id_to_set)
+      .Then([&received_callback2](fidl::Result<Control::SetTopology>& result) {
+        received_callback2 = true;
+        EXPECT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback2);
+  EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(new_topology_id.has_value());
+  EXPECT_EQ(*new_topology_id, topology_id_to_set);
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify SetElementState (OK to use WatchElementState in doing this)
+
 /////////////////////
 // StreamConfig tests
 //
 // When client drops their Control, the server should cleanly unwind without hang or WARNING.
 TEST_F(ControlServerStreamConfigTest, CleanClientDrop) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
+
   RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
 
@@ -820,7 +1439,8 @@
 // When server closes a client connection, the shutdown should be orderly without hang or WARNING.
 TEST_F(ControlServerStreamConfigTest, CleanServerShutdown) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
+
   RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
 
@@ -836,17 +1456,18 @@
 TEST_F(ControlServerStreamConfigTest, BasicClose) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(control_client.is_valid());
+
   (void)control_client.UnbindMaybeGetEndpoint();
 }
 
@@ -854,22 +1475,25 @@
 TEST_F(ControlServerStreamConfigTest, ControlCreatorServerShutdownDoesNotAffectControl) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlCreatorServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
   control_creator->server().Shutdown(ZX_ERR_PEER_CLOSED);
+
   RunLoopUntilIdle();
   EXPECT_TRUE(control_creator->server().WaitForShutdown(zx::sec(1)));
-
-  EXPECT_TRUE(control_client.is_valid());
   EXPECT_EQ(ControlServer::count(), 1u);
-  (void)control_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+  ASSERT_TRUE(control_creator_fidl_error_status().has_value());
+  EXPECT_EQ(*control_creator_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Verify that the ControlServer shuts down cleanly if the driver drops its StreamConfig.
@@ -880,10 +1504,9 @@
 
   WaitForAddedDeviceTokenId(registry->client());
 
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
-
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
@@ -907,18 +1530,23 @@
         ASSERT_TRUE(result.is_ok()) << result.error_value();
         received_callback = true;
       });
+
   RunLoopUntilIdle();
   EXPECT_EQ(RingBufferServer::count(), 1u);
   EXPECT_TRUE(received_callback);
 
   // Drop the driver StreamConfig connection.
   fake_driver->DropStreamConfig();
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   while (RingBufferServer::count() > 0u) {
     RunLoopUntilIdle();
   }
+
   EXPECT_TRUE(control->server().WaitForShutdown(zx::sec(5)));
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Verify that the Control lives, even if the client drops its child RingBuffer.
@@ -929,10 +1557,9 @@
 
   WaitForAddedDeviceTokenId(registry->client());
 
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
-
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
@@ -942,7 +1569,7 @@
     bool received_callback = false;
 
     auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
 
     control->client()
         ->CreateRingBuffer({{
@@ -960,6 +1587,7 @@
           ASSERT_TRUE(result.is_ok()) << result.error_value();
           received_callback = true;
         });
+
     RunLoopUntilIdle();
     EXPECT_TRUE(received_callback);
 
@@ -974,8 +1602,9 @@
 
   // Allow the ControlServer to destruct, if it (erroneously) wants to.
   RunLoopUntilIdle();
-  EXPECT_TRUE(control->client().is_valid());
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that the Control lives, even if the driver drops its RingBuffer connection.
@@ -986,10 +1615,9 @@
 
   WaitForAddedDeviceTokenId(registry->client());
 
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
-
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
 
@@ -1014,6 +1642,7 @@
         ASSERT_TRUE(result.is_ok()) << result.error_value();
         received_callback = true;
       });
+
   RunLoopUntilIdle();
   EXPECT_EQ(RingBufferServer::count(), 1u);
   EXPECT_TRUE(received_callback);
@@ -1028,8 +1657,9 @@
 
   // Allow the ControlServer to destruct, if it (erroneously) wants to.
   RunLoopUntilIdle();
-  EXPECT_TRUE(control->client().is_valid());
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that the ControlServer shuts down cleanly if the driver drops its StreamConfig.
@@ -1037,9 +1667,9 @@
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   fake_driver->AllocateRingBuffer(8192);
   auto registry = CreateTestRegistryServer();
-  (void)WaitForAddedDeviceTokenId(registry->client());
 
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  (void)WaitForAddedDeviceTokenId(registry->client());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -1055,10 +1685,78 @@
         EXPECT_TRUE(result.is_ok()) << result.error_value();
         received_callback = true;
       });
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// TODO(https://fxbug.dev/323270827): implement signalprocessing, including in the FakeStreamConfig
+// test fixture. Then add positive test cases for
+// GetTopologies/GetElements/WatchTopology/WatchElementState, as are in Composite.
+
+// Verify GetTopologies if the driver does not support signalprocessing.
+TEST_F(ControlServerStreamConfigTest, GetTopologiesUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()->GetTopologies().Then([&received_callback](
+                                              fidl::Result<Control::GetTopologies>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify GetElements if the driver does not support signalprocessing.
+TEST_F(ControlServerStreamConfigTest, GetElementsUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()->GetElements().Then([&received_callback](
+                                            fidl::Result<Control::GetElements>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 }  // namespace
diff --git a/src/media/audio/services/device_registry/control_server_warning_unittest.cc b/src/media/audio/services/device_registry/control_server_warning_unittest.cc
index f6b45ad..9c0f48b 100644
--- a/src/media/audio/services/device_registry/control_server_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/control_server_warning_unittest.cc
@@ -57,7 +57,7 @@
     auto [control_client_end, control_server_end] =
         CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Control>();
     auto control_client = fidl::Client<fuchsia_audio_device::Control>(
-        std::move(control_client_end), dispatcher(), control_fidl_handler_.get());
+        std::move(control_client_end), dispatcher(), control_fidl_handler().get());
     bool received_callback = false;
     control_creator_client
         ->Create({{
@@ -89,9 +89,9 @@
   std::shared_ptr<FakeCodec> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeCodecInput();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                           fuchsia_audio_device::DeviceType::kCodec,
-                                           DriverClient::WithCodec(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                            fuchsia_audio_device::DeviceType::kCodec,
+                                            DriverClient::WithCodec(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -102,9 +102,9 @@
   std::shared_ptr<FakeComposite> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeComposite();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test composite name",
-                                           fuchsia_audio_device::DeviceType::kComposite,
-                                           DriverClient::WithComposite(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                            fuchsia_audio_device::DeviceType::kComposite,
+                                            DriverClient::WithComposite(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -121,14 +121,14 @@
 
     RunLoopUntilIdle();
     ASSERT_EQ(ControlServer::count(), 1u);
-    auto device = *adr_service_->devices().begin();
+    auto device = *adr_service()->devices().begin();
 
     for (auto ring_buffer_element_id : device->ring_buffer_endpoint_ids()) {
       fake_driver->ReserveRingBufferSize(ring_buffer_element_id, 8192);
       auto [ring_buffer_client_end, ring_buffer_server_end] =
           CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
       auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-          std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+          std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
       bool received_callback = false;
 
       control_client
@@ -149,6 +149,8 @@
       EXPECT_TRUE(received_callback);
       EXPECT_EQ(ControlServer::count(), 1u);
     }
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+    EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   }
 };
 
@@ -157,9 +159,9 @@
   std::shared_ptr<FakeStreamConfig> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeStreamConfigOutput();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                           fuchsia_audio_device::DeviceType::kOutput,
-                                           DriverClient::WithStreamConfig(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                            fuchsia_audio_device::DeviceType::kOutput,
+                                            DriverClient::WithStreamConfig(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -172,26 +174,26 @@
   void TestSetGainBadState(const std::optional<fuchsia_audio_device::GainState>& bad_state,
                            fuchsia_audio_device::ControlSetGainError expected_error) {
     auto fake_driver = CreateFakeStreamConfigOutput();
-
     fake_driver->set_can_mute(false);
     fake_driver->set_can_agc(false);
     fake_driver->AllocateRingBuffer(8192);
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                           fuchsia_audio_device::DeviceType::kOutput,
-                                           DriverClient::WithStreamConfig(fake_driver->Enable())));
-    RunLoopUntilIdle();
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                            fuchsia_audio_device::DeviceType::kOutput,
+                                            DriverClient::WithStreamConfig(fake_driver->Enable())));
 
+    RunLoopUntilIdle();
     auto registry = CreateTestRegistryServer();
+
     auto added_id = WaitForAddedDeviceTokenId(registry->client());
     auto control_creator = CreateTestControlCreatorServer();
     auto control_client = ConnectToControl(control_creator->client(), *added_id);
-    RunLoopUntilIdle();
 
+    RunLoopUntilIdle();
     ASSERT_EQ(ControlServer::count(), 1u);
     auto [ring_buffer_client_end, ring_buffer_server_end] =
         CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
     auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
     bool received_callback = false;
 
     control_client
@@ -208,6 +210,9 @@
     RunLoopUntilIdle();
     EXPECT_TRUE(received_callback);
     EXPECT_EQ(ControlServer::count(), 1u);
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+    EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+        << *control_creator_fidl_error_status();
   }
 
   void TestCreateRingBufferBadOptions(
@@ -215,17 +220,18 @@
       fuchsia_audio_device::ControlCreateRingBufferError expected_error) {
     auto fake_driver = CreateAndEnableDriverWithDefaults();
     fake_driver->AllocateRingBuffer(8192);
+
     auto registry = CreateTestRegistryServer();
     auto added_id = WaitForAddedDeviceTokenId(registry->client());
     auto control_creator = CreateTestControlCreatorServer();
     auto control_client = ConnectToControl(control_creator->client(), *added_id);
-    RunLoopUntilIdle();
 
+    RunLoopUntilIdle();
     ASSERT_EQ(ControlServer::count(), 1u);
     auto [ring_buffer_client_end, ring_buffer_server_end] =
         CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
     auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
     bool received_callback = false;
 
     control_client
@@ -244,6 +250,9 @@
     RunLoopUntilIdle();
     EXPECT_TRUE(received_callback);
     EXPECT_EQ(ControlServer::count(), 1u);
+    EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+    EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+        << *control_creator_fidl_error_status();
   }
 };
 
@@ -256,7 +265,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -289,14 +298,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback && received_callback2);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // SetDaiFormat invalid
 TEST_F(ControlServerCodecWarningTest, SetDaiFormatInvalidFormat) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -321,14 +333,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // SetDaiFormat unsupported
 TEST_F(ControlServerCodecWarningTest, SetDaiFormatUnsupportedFormat) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -352,14 +367,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Start when already pending
 TEST_F(ControlServerCodecWarningTest, CodecStartWhenAlreadyPending) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -398,14 +416,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback && received_callback2);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Start before SetDaiFormat
 TEST_F(ControlServerCodecWarningTest, CodecStartBeforeSetDaiFormat) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -426,14 +447,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Start when Started
 TEST_F(ControlServerCodecWarningTest, CodecStartWhenStarted) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -475,14 +499,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Stop when already pending
 TEST_F(ControlServerCodecWarningTest, CodecStopWhenAlreadyPending) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -491,6 +518,7 @@
   auto dai_format =
       SafeDaiFormatFromElementDaiFormatSets(dai_element_id(), device->dai_format_sets());
   auto received_callback = false;
+
   control->client()
       ->SetDaiFormat({{.dai_format = dai_format}})
       .Then([&received_callback](fidl::Result<Control::SetDaiFormat>& result) {
@@ -501,6 +529,7 @@
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
   received_callback = false;
+
   control->client()->CodecStart().Then(
       [&received_callback](fidl::Result<Control::CodecStart>& result) {
         received_callback = true;
@@ -530,14 +559,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback && received_callback2);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Stop before SetDaiFormat
 TEST_F(ControlServerCodecWarningTest, CodecStopBeforeSetDaiFormat) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -558,14 +590,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Stop when Stopped
 TEST_F(ControlServerCodecWarningTest, CodecStopWhenStopped) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -574,6 +609,7 @@
   auto dai_format =
       SafeDaiFormatFromElementDaiFormatSets(dai_element_id(), device->dai_format_sets());
   auto received_callback = false;
+
   control->client()
       ->SetDaiFormat({{.dai_format = dai_format}})
       .Then([&received_callback](fidl::Result<Control::SetDaiFormat>& result) {
@@ -598,14 +634,17 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // SetGain WRONG_DEVICE_TYPE
 TEST_F(ControlServerCodecWarningTest, SetGainWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -633,25 +672,26 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerCodecWarningTest, CreateRingBufferWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
   ASSERT_EQ(ControlServer::count(), 1u);
-  auto received_callback = false;
-
   auto [ring_buffer_client_end, ring_buffer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
-
   auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-      std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+      std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
+  auto received_callback = false;
 
   control->client()
       ->CreateRingBuffer({{
@@ -677,11 +717,173 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
-// Add negative test cases for SetTopology and SetElementState (once implemented)
-//
-// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain).
+// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain),
+// including in the FakeCodec test fixture. Then add negative test cases for
+// GetTopologies/GetElements/WatchTopology/WatchElementState, as are in Composite, as well as
+// negative cases for SetTopology/SetElementState.
+
+// Verify WatchTopology if the driver has an error.
+
+// Verify WatchTopology if the driver does not support signalprocessing.
+TEST_F(ControlServerCodecWarningTest, WatchTopologyUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  received_callback = false;
+
+  // After this failing call, the binding should not be usable.
+  control->client()->Reset().Then([&received_callback](fidl::Result<Control::Reset>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_framework_error());
+    EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_NOT_SUPPORTED);
+}
+
+// Verify WatchElementState if the driver has an error.
+
+// Verify WatchElementState if the driver does not support signalprocessing.
+TEST_F(ControlServerCodecWarningTest, WatchElementStateUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()
+      ->WatchElementState(fuchsia_audio_device::kDefaultDaiInterconnectElementId)
+      .Then([&received_callback](fidl::Result<Control::WatchElementState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  received_callback = false;
+
+  // After this failing call, the binding should not be usable.
+  control->client()->Reset().Then([&received_callback](fidl::Result<Control::Reset>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_framework_error());
+    EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_NOT_SUPPORTED);
+}
+
+// Verify SetTopology if the driver has an error.
+
+// Verify SetTopology if the driver does not support signalprocessing.
+TEST_F(ControlServerCodecWarningTest, SetTopologyUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()->SetTopology(0).Then([&received_callback](
+                                             fidl::Result<Control::SetTopology>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify SetElementState if the driver has an error.
+
+// Verify SetElementState if the driver does not support signalprocessing.
+TEST_F(ControlServerCodecWarningTest, SetElementStateUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()
+      ->SetElementState({fuchsia_audio_device::kDefaultDaiInterconnectElementId, {}})
+      .Then([&received_callback](fidl::Result<Control::SetElementState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_domain_error())
+            << result.error_value().framework_error();
+        EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
 
 /////////////////////
 // Composite tests
@@ -692,7 +894,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -734,6 +936,9 @@
     EXPECT_TRUE(received_callback && received_callback2);
     EXPECT_EQ(ControlServer::count(), 1u);
   }
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // SetDaiFormat invalid
@@ -742,7 +947,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -773,6 +978,9 @@
     EXPECT_TRUE(received_callback);
     EXPECT_EQ(ControlServer::count(), 1u);
   }
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // SetDaiFormat unsupported
@@ -781,7 +989,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -811,6 +1019,9 @@
     EXPECT_TRUE(received_callback);
     EXPECT_EQ(ControlServer::count(), 1u);
   }
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // SetDaiFormat on RingBuffer element
@@ -819,7 +1030,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -848,6 +1059,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // SetDaiFormat on unknown element_id
@@ -856,7 +1069,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -885,6 +1098,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerCompositeWarningTest, SetGainWrongDeviceType) {
@@ -892,7 +1107,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -920,6 +1135,8 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerCompositeWarningTest, CodecStartWrongDeviceType) {
@@ -927,7 +1144,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -947,6 +1164,8 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerCompositeWarningTest, CodecStopWrongDeviceType) {
@@ -954,7 +1173,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -974,6 +1193,8 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerCompositeWarningTest, CreateRingBufferWrongElementType) {
@@ -981,7 +1202,7 @@
   auto registry = CreateTestRegistryServer();
 
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   auto control = CreateTestControlServer(device);
 
   RunLoopUntilIdle();
@@ -994,7 +1215,7 @@
         CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
 
     auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+        std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
 
     control->client()
         ->CreateRingBuffer({{
@@ -1022,6 +1243,9 @@
     EXPECT_TRUE(received_callback);
     EXPECT_EQ(ControlServer::count(), 1u);
   }
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerCompositeWarningTest, CreateRingBufferMissingOptions) {
@@ -1144,8 +1368,7 @@
       fuchsia_audio_device::ControlCreateRingBufferError::kInvalidMinBytes);
 }
 
-// TODO: enable
-TEST_F(ControlServerCompositeWarningTest, DISABLED_CreateRingBufferWhilePending) {
+TEST_F(ControlServerCompositeWarningTest, CreateRingBufferWhilePending) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
 
@@ -1154,22 +1377,22 @@
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
 
   RunLoopUntilIdle();
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   ASSERT_EQ(ControlServer::count(), 1u);
 
   for (auto ring_buffer_element_id : device->ring_buffer_endpoint_ids()) {
+    fake_driver->ReserveRingBufferSize(ring_buffer_element_id, 8192);
     auto [ring_buffer_client_end1, ring_buffer_server_end1] =
         CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
     auto [ring_buffer_client_end2, ring_buffer_server_end2] =
         CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
-
-    fake_driver->ReserveRingBufferSize(ring_buffer_element_id, 8192);
-    bool received_callback_1 = false, received_callback_2 = false;
     auto options = fuchsia_audio_device::RingBufferOptions{{
         .format = SafeRingBufferFormatFromElementRingBufferFormatSets(
             ring_buffer_element_id, device->ring_buffer_format_sets()),
-        .ring_buffer_min_bytes = 8192,
+        .ring_buffer_min_bytes = 4096,
     }};
+    bool received_callback_1 = false, received_callback_2 = false;
+
     control_client
         ->CreateRingBuffer({{
             ring_buffer_element_id,
@@ -1177,8 +1400,10 @@
             std::move(ring_buffer_server_end1),
         }})
         .Then([&received_callback_1](fidl::Result<Control::CreateRingBuffer>& result) {
-          ASSERT_TRUE(result.is_ok()) << result.error_value();
           received_callback_1 = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          EXPECT_TRUE(result->properties().has_value());
+          EXPECT_TRUE(result->ring_buffer().has_value());
         });
     control_client
         ->CreateRingBuffer({{
@@ -1187,12 +1412,12 @@
             std::move(ring_buffer_server_end2),
         }})
         .Then([&received_callback_2](fidl::Result<Control::CreateRingBuffer>& result) {
+          received_callback_2 = true;
           ASSERT_TRUE(result.is_error());
           ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
           EXPECT_EQ(result.error_value().domain_error(),
                     fuchsia_audio_device::ControlCreateRingBufferError::kAlreadyPending)
               << result.error_value();
-          received_callback_2 = true;
         });
 
     RunLoopUntilIdle();
@@ -1200,6 +1425,11 @@
     EXPECT_EQ(ControlServer::count(), 1u);
     EXPECT_TRUE(control_client.is_valid());
   }
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerCompositeWarningTest, CreateRingBufferUnknownElementId) {
@@ -1211,7 +1441,7 @@
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
 
   RunLoopUntilIdle();
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   ASSERT_EQ(ControlServer::count(), 1u);
   auto ring_buffer_element_id_unused = *device->ring_buffer_endpoint_ids().begin();
   // fake_driver->ReserveRingBufferSize(ring_buffer_element_id_unused, 8192);
@@ -1243,7 +1473,8 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
-  EXPECT_TRUE(control_client.is_valid());
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerCompositeWarningTest, CreateRingBufferMissingRingBufferServerEnd) {
@@ -1256,7 +1487,7 @@
 
   RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
-  auto device = *adr_service_->devices().begin();
+  auto device = *adr_service()->devices().begin();
   bool received_callback = false;
 
   for (auto ring_buffer_element_id : device->ring_buffer_endpoint_ids()) {
@@ -1287,27 +1518,34 @@
     EXPECT_TRUE(received_callback);
     EXPECT_EQ(ControlServer::count(), 1u);
   }
+
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
 }
 
-// TODO: enable
-TEST_F(ControlServerCompositeWarningTest, DISABLED_CreateRingBufferBadRingBufferServerEnd) {
+// If the ServerEnd<RingBuffer> passed to CreateRingBuffer is invalid, the Control will disconnect.
+// We recreate it for each RING_BUFFER element so we can probe each one.
+TEST_F(ControlServerCompositeWarningTest, CreateRingBufferBadRingBufferServerEnd) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
 
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
-  auto control_client = ConnectToControl(control_creator->client(), *added_id);
-
-  RunLoopUntilIdle();
-  ASSERT_EQ(ControlServer::count(), 1u);
-  auto device = *adr_service_->devices().begin();
-  bool received_callback = false;
+  auto device = *adr_service()->devices().begin();
 
   for (auto ring_buffer_element_id : device->ring_buffer_endpoint_ids()) {
+    auto control_client = ConnectToControl(control_creator->client(), *added_id);
+
+    RunLoopUntilIdle();
+    ASSERT_EQ(ControlServer::count(), 1u);
+    bool received_callback = false;
+
     fake_driver->ReserveRingBufferSize(ring_buffer_element_id, 8192);
     control_client
         ->CreateRingBuffer({{
-            .options = fuchsia_audio_device::RingBufferOptions{{
+            ring_buffer_element_id,
+            fuchsia_audio_device::RingBufferOptions{{
                 .format = fuchsia_audio::Format{{
                     .sample_type = fuchsia_audio::SampleType::kInt16,
                     .channel_count = 2,
@@ -1315,7 +1553,7 @@
                 }},
                 .ring_buffer_min_bytes = 8192,
             }},
-            .ring_buffer_server = {},  // bad value
+            fidl::ServerEnd<fuchsia_audio_device::RingBuffer>(),  // bad value
         }})
         .Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
           ASSERT_TRUE(result.is_error());
@@ -1328,7 +1566,12 @@
     RunLoopUntilIdle();
     EXPECT_TRUE(received_callback);
     EXPECT_EQ(ControlServer::count(), 0u);
+    ASSERT_TRUE(control_fidl_error_status().has_value());
+    EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_INVALID_ARGS);
   }
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
 }
 
 // TODO(https://fxbug.dev/42069012): Create a unittest to test the upper limit of VMO size (4Gb).
@@ -1337,6 +1580,235 @@
 //     Note the disabled attempt (for StreamConfig below) to create this.
 // TEST_F(ControlServerCompositeWarningTest, DISABLED_CreateRingBufferHugeRingBufferMinBytes) {}
 
+// Verify WatchTopology if the driver has an error.
+
+TEST_F(ControlServerCompositeWarningTest, WatchTopologyWhilePending) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback1 = false, received_callback2 = false;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback1](fidl::Result<Control::WatchTopology>& result) {
+        received_callback1 = true;
+        EXPECT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback1);
+  received_callback1 = false;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback1](fidl::Result<Control::WatchTopology>& result) {
+        // This should pend until the subsequent WatchTopology fails, causing a disconnect.
+        // The epitaph of that disconnect is ZX_ERR_BAD_STATE.
+        received_callback1 = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_BAD_STATE);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback1);
+
+  control->client()->WatchTopology().Then(
+      [&received_callback2](fidl::Result<Control::WatchTopology>& result) {
+        received_callback2 = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_BAD_STATE);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback2);
+  // After a failing WatchTopology call, the binding should not be usable, so the previous
+  // WatchElementState will complete with a failure.
+  EXPECT_TRUE(received_callback1);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_BAD_STATE);
+}
+
+// Verify WatchElementState if the driver has an error.
+
+TEST_F(ControlServerCompositeWarningTest, WatchElementStateUnknownElementId) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto& elements_from_device = element_map(device);
+  ElementId unknown_element_id = 0;
+  while (true) {
+    if (elements_from_device.find(unknown_element_id) == elements_from_device.end()) {
+      break;
+    }
+    ++unknown_element_id;
+  }
+  auto received_callback = false;
+
+  control->client()
+      ->WatchElementState(unknown_element_id)
+      .Then([&received_callback](fidl::Result<Control::WatchElementState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_INVALID_ARGS);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+
+  // After a failing WatchElementState call, the binding should not be usable.
+  control->client()->Reset().Then([&received_callback](fidl::Result<Control::Reset>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_framework_error());
+    EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_INVALID_ARGS);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_INVALID_ARGS);
+}
+
+TEST_F(ControlServerCompositeWarningTest, WatchElementStateWhilePending) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto& elements_from_device = element_map(device);
+
+  auto element_id = elements_from_device.begin()->first;
+  auto received_callback1 = false, received_callback2 = false;
+
+  control->client()
+      ->WatchElementState(element_id)
+      .Then([&received_callback1](fidl::Result<Control::WatchElementState>& result) {
+        received_callback1 = true;
+        EXPECT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback1);
+  received_callback1 = false;
+
+  control->client()
+      ->WatchElementState(element_id)
+      .Then([&received_callback1](fidl::Result<Control::WatchElementState>& result) {
+        received_callback1 = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_BAD_STATE) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback1);
+
+  control->client()
+      ->WatchElementState(element_id)
+      .Then([&received_callback2](fidl::Result<Control::WatchElementState>& result) {
+        received_callback2 = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_BAD_STATE) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback2);
+  // After a failing WatchElementState call, the binding should not be usable, so the previous
+  // WatchElementState will complete with a failure.
+  EXPECT_TRUE(received_callback1);
+  received_callback1 = false;
+
+  control->client()->Reset().Then([&received_callback1](fidl::Result<Control::Reset>& result) {
+    received_callback1 = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_framework_error()) << result.error_value();
+    EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_BAD_STATE)
+        << result.error_value().framework_error();
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback1);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_BAD_STATE);
+}
+
+// Verify SetTopology if the driver has an error.
+
+TEST_F(ControlServerCompositeWarningTest, SetTopologyUnknownId) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  const auto& topologies = topology_map(device);
+  TopologyId unknown_topology_id = 0;
+  bool found_an_unknown_topology_id = false;
+  do {
+    if (topologies.find(unknown_topology_id) == topologies.end()) {
+      found_an_unknown_topology_id = true;
+    } else {
+      ++unknown_topology_id;
+    }
+  } while (!found_an_unknown_topology_id);
+  auto received_callback = false;
+
+  control->client()
+      ->SetTopology(unknown_topology_id)
+      .Then([&received_callback](fidl::Result<Control::SetTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_domain_error())
+            << result.error_value().framework_error();
+        EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_INVALID_ARGS);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify SetTopology if the driver does not support signalprocessing.
+
+// Verify SetElementState if the driver has an error.
+
+// Verify SetElementState if the ElementId is unknown.
+
+// Verify SetElementState if the ElementState is invalid.
+//   (missing fields, wrong element type, internally inconsistent values, read-only)
+
 /////////////////////
 // StreamConfig tests
 //
@@ -1513,18 +1985,17 @@
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   fake_driver->AllocateRingBuffer(8192);
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
   auto [ring_buffer_client_end1, ring_buffer_server_end1] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
   auto [ring_buffer_client_end2, ring_buffer_server_end2] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
-
-  bool received_callback_1 = false, received_callback_2 = false;
   auto options = fuchsia_audio_device::RingBufferOptions{{
       .format = fuchsia_audio::Format{{
           .sample_type = fuchsia_audio::SampleType::kInt16,
@@ -1533,14 +2004,18 @@
       }},
       .ring_buffer_min_bytes = 8192,
   }};
+  bool received_callback_1 = false, received_callback_2 = false;
+
   control_client
       ->CreateRingBuffer({{
           .options = options,
           .ring_buffer_server = std::move(ring_buffer_server_end1),
       }})
       .Then([&received_callback_1](fidl::Result<Control::CreateRingBuffer>& result) {
-        ASSERT_TRUE(result.is_ok()) << result.error_value();
         received_callback_1 = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        EXPECT_TRUE(result->properties().has_value());
+        EXPECT_TRUE(result->ring_buffer().has_value());
       });
   control_client
       ->CreateRingBuffer({{
@@ -1548,18 +2023,21 @@
           .ring_buffer_server = std::move(ring_buffer_server_end2),
       }})
       .Then([&received_callback_2](fidl::Result<Control::CreateRingBuffer>& result) {
+        received_callback_2 = true;
         ASSERT_TRUE(result.is_error());
         ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
         EXPECT_EQ(result.error_value().domain_error(),
                   fuchsia_audio_device::ControlCreateRingBufferError::kAlreadyPending)
             << result.error_value();
-        received_callback_2 = true;
       });
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback_1 && received_callback_2);
   EXPECT_EQ(ControlServer::count(), 1u);
-  EXPECT_TRUE(control_client.is_valid());
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value())
+      << *control_creator_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // TODO(https://fxbug.dev/42069012): Enable this unittest to test the upper limit of VMO size
@@ -1578,23 +2056,24 @@
   fake_driver->set_valid_bits_per_sample(0, {8});
   fake_driver->set_frame_rates(0, {48000});
 
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
   fake_driver->AllocateRingBuffer(8192);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
   auto [ring_buffer_client_end, ring_buffer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::RingBuffer>();
   auto ring_buffer_client = fidl::Client<fuchsia_audio_device::RingBuffer>(
-      std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler_.get());
+      std::move(ring_buffer_client_end), dispatcher(), ring_buffer_fidl_handler().get());
   bool received_callback = false;
 
   control_client
@@ -1659,12 +2138,15 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerStreamConfigWarningTest, CreateRingBufferMissingRingBufferServerEnd) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   fake_driver->AllocateRingBuffer(8192);
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
@@ -1696,17 +2178,20 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerStreamConfigWarningTest, CreateRingBufferBadRingBufferServerEnd) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   fake_driver->AllocateRingBuffer(8192);
   auto registry = CreateTestRegistryServer();
+
   auto added_id = WaitForAddedDeviceTokenId(registry->client());
   auto control_creator = CreateTestControlCreatorServer();
   auto control_client = ConnectToControl(control_creator->client(), *added_id);
-  RunLoopUntilIdle();
 
+  RunLoopUntilIdle();
   ASSERT_EQ(ControlServer::count(), 1u);
   bool received_callback = false;
 
@@ -1733,10 +2218,13 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_INVALID_ARGS);
 }
 
 // TODO(https://fxbug.dev/42068381): If Health can change post-initialization, test: device becomes
-//   unhealthy before SetGain. Expect Observer/Control/RingBuffer to drop, Reg/WatchRemoved.
+//   unhealthy before SetGain. Expect Control/Control/RingBuffer to drop, Reg/WatchRemoved.
 
 // TODO(https://fxbug.dev/42068381): If Health can change post-initialization, test: device becomes
 //   unhealthy before CreateRingBuffer. Expect Obs/Ctl to drop, Reg/WatchRemoved.
@@ -1744,8 +2232,9 @@
 TEST_F(ControlServerStreamConfigWarningTest, SetDaiFormatWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -1778,13 +2267,16 @@
 
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerStreamConfigWarningTest, CodecStartWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -1804,13 +2296,16 @@
 
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerStreamConfigWarningTest, CodecStopWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -1830,13 +2325,16 @@
 
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(ControlServerStreamConfigWarningTest, ResetWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
   auto registry = CreateTestRegistryServer();
+
   (void)WaitForAddedDeviceTokenId(registry->client());
-  auto control = CreateTestControlServer(*adr_service_->devices().begin());
+  auto control = CreateTestControlServer(*adr_service()->devices().begin());
 
   RunLoopUntilIdle();
   ASSERT_EQ(RegistryServer::count(), 1u);
@@ -1855,6 +2353,170 @@
 
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// TODO(https://fxbug.dev/323270827): implement signalprocessing, including in the FakeStreamConfig
+// test fixture. Then add those types of negative test cases for
+// GetTopologies/GetElements/WatchTopology/WatchElementState, as are in Composite, as well as for
+// SetTopology/SetElementState.
+//
+// Verify WatchTopology if the driver does not support signalprocessing.
+TEST_F(ControlServerStreamConfigWarningTest, WatchTopologyUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()->WatchTopology().Then(
+      [&received_callback](fidl::Result<Control::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  received_callback = false;
+
+  // After a failing WatchTopology call, the binding should not be usable.
+  control->client()
+      ->SetGain({{fuchsia_audio_device::GainState{{.gain_db = 0}}}})
+      .Then([&received_callback](fidl::Result<Control::SetGain>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_NOT_SUPPORTED)
+            << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_NOT_SUPPORTED);
+}
+
+// Verify WatchElementState if the driver does not support signalprocessing.
+TEST_F(ControlServerStreamConfigWarningTest, WatchElementStateUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()
+      ->WatchElementState(fuchsia_audio_device::kDefaultDaiInterconnectElementId)
+      .Then([&received_callback](fidl::Result<Control::WatchElementState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  received_callback = false;
+
+  // After a failing WatchElementState call, the binding should not be usable.
+  control->client()
+      ->SetGain({{fuchsia_audio_device::GainState{{.gain_db = 0}}}})
+      .Then([&received_callback](fidl::Result<Control::SetGain>& result) {
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_NOT_SUPPORTED)
+            << result.error_value();
+        received_callback = true;
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(*control_fidl_error_status(), ZX_ERR_NOT_SUPPORTED);
+}
+
+// Verify SetTopology if the driver does not support signalprocessing.
+TEST_F(ControlServerStreamConfigWarningTest, SetTopologyUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()->SetTopology(0).Then([&received_callback](
+                                             fidl::Result<Control::SetTopology>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
+}
+
+// Verify SetElementState if the driver does not support signalprocessing.
+TEST_F(ControlServerStreamConfigWarningTest, SetElementStateUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto control = CreateTestControlServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ControlServer::count(), 1u);
+  auto received_callback = false;
+
+  control->client()
+      ->SetElementState({fuchsia_audio_device::kDefaultDaiInterconnectElementId, {}})
+      .Then([&received_callback](fidl::Result<Control::SetElementState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_domain_error())
+            << result.error_value().framework_error();
+        EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 }  // namespace
diff --git a/src/media/audio/services/device_registry/device.cc b/src/media/audio/services/device_registry/device.cc
index 611aa52..b106b60 100644
--- a/src/media/audio/services/device_registry/device.cc
+++ b/src/media/audio/services/device_registry/device.cc
@@ -16,11 +16,13 @@
 #include <lib/zx/clock.h>
 #include <lib/zx/result.h>
 #include <zircon/errors.h>
+#include <zircon/types.h>
 
 #include <algorithm>
 #include <cstdint>
 #include <memory>
 #include <optional>
+#include <string>
 #include <string_view>
 
 #include "src/media/audio/lib/clock/real_clock.h"
@@ -207,6 +209,7 @@
     --initialized_count_;
 
     DropControl();  // Probably unneeded (the Device is going away) but makes unwind "complete".
+    ADR_LOG_OBJECT(kLogNotifyMethods) << "ForEachObserver => DeviceIsRemoved()" << token_id_ << ")";
     ForEachObserver([](auto obs) { obs->DeviceIsRemoved(); });  // Our control is also an observer.
   }
 
@@ -215,6 +218,7 @@
   codec_client_.reset();
   stream_config_client_.reset();
 
+  LogDeviceRemoval(info());
   LogObjectCounts();
 
   // Regardless of whether device was pending / operational / unhealthy, notify the state watcher.
@@ -224,7 +228,6 @@
 }
 
 void Device::ForEachObserver(fit::function<void(std::shared_ptr<ObserverNotify>)> action) {
-  ADR_LOG_METHOD(kLogNotifyMethods);
   for (auto weak_obs = observers_.begin(); weak_obs < observers_.end(); ++weak_obs) {
     if (auto observer = weak_obs->lock(); observer) {
       action(observer);
@@ -246,10 +249,12 @@
     --initialized_count_;
 
     DropControl();
+    ADR_LOG_OBJECT(kLogNotifyMethods) << "ForEachObserver => DeviceHasError";
     ForEachObserver([](auto obs) { obs->DeviceHasError(); });
   }
   ++unhealthy_count_;
   SetError(error);
+  LogDeviceError(info());
   LogObjectCounts();
 
   if (std::shared_ptr<DevicePresenceWatcher> pw = presence_watcher_.lock(); pw) {
@@ -328,6 +333,7 @@
   if (IsFullyInitialized()) {
     ++initialized_count_;
     SetDeviceInfo();
+    LogDeviceAddition(*info());
     SetState(State::DeviceInitialized);
     LogObjectCounts();
 
@@ -388,14 +394,14 @@
   ADR_LOG_METHOD(kLogDeviceMethods || kLogNotifyMethods);
   FX_CHECK(state_ != State::DeviceInitializing);
 
-  // TODO drop ring buffers?
-
   auto control_notify = GetControlNotify();
   if (!control_notify) {
     ADR_LOG_METHOD(kLogNotifyMethods) << "already not controlled";
     return false;
   }
 
+  // Need to drop ring buffers here?
+
   control_notify_.reset();
   // We don't remove our ControlNotify from the observer list: we wait for it to self-invalidate.
 
@@ -867,15 +873,8 @@
     return;
   }
 
-  auto endpoints =
-      fidl::CreateEndpoints<fuchsia_hardware_audio_signalprocessing::SignalProcessing>();
-  if (!endpoints.is_ok()) {
-    ADR_WARN_METHOD() << "unable to create SignalProcessing endpoints: "
-                      << endpoints.status_string();
-    OnError(endpoints.status_value());
-    return;
-  }
-  auto [sig_proc_client_end, sig_proc_server_end] = std::move(endpoints.value());
+  auto [sig_proc_client_end, sig_proc_server_end] =
+      fidl::Endpoints<fuchsia_hardware_audio_signalprocessing::SignalProcessing>::Create();
 
   // TODO(https://fxbug.dev/113429): handle command timeouts
 
@@ -984,6 +983,9 @@
               OnError(ZX_ERR_INVALID_ARGS);
               return;
             }
+            for (const auto& [element_id, _] : sig_proc_element_map_) {
+              element_ids_.insert(element_id);
+            }
             RetrieveSignalProcessingTopologies();
 
             if (is_composite()) {
@@ -1029,6 +1031,9 @@
           OnError(ZX_ERR_INVALID_ARGS);
           return;
         }
+        for (const auto& [topology_id, _] : sig_proc_topology_map_) {
+          topology_ids_.insert(topology_id);
+        }
 
         SetSignalProcessingSupported(true);
 
@@ -1051,24 +1056,31 @@
       .Then([this](fidl::Result<
                    fuchsia_hardware_audio_signalprocessing::SignalProcessing::WatchTopology>&
                        result) {
-        std::string context("signalprocessing::WatchTopology response");
+        TopologyId topology_id = result->topology_id();
+        std::string context("signalprocessing::WatchTopology response: topology_id ");
+        context.append(std::to_string(topology_id));
         if (LogResultFrameworkError(result, context.c_str())) {
           return;
         }
+        ADR_LOG_OBJECT(kLogSignalProcessingFidlResponses) << context;
 
-        TopologyId new_topology_id = result->topology_id();
-        auto match = sig_proc_topology_map_.find(new_topology_id);
-        if (match == sig_proc_topology_map_.end()) {
-          ADR_WARN_OBJECT() << context << ": topology_id " << new_topology_id << " not found";
+        // Either (a) sig_proc_topology_map_ is incorrect, or (b) the driver is poorly-behaved.
+        if (sig_proc_topology_map_.find(topology_id) == sig_proc_topology_map_.end()) {
+          FX_LOGS(ERROR) << context << ": not found";
           OnError(ZX_ERR_INVALID_ARGS);
           return;
         }
 
         // Save the topology and notify Observers, but only if this is a change in topology.
-        if (!current_topology_id_.has_value() || *current_topology_id_ != new_topology_id) {
-          current_topology_id_ = new_topology_id;
-          ForEachObserver([new_topology_id](auto obs) { obs->TopologyChanged(new_topology_id); });
+        if (!current_topology_id_.has_value() || *current_topology_id_ != topology_id) {
+          current_topology_id_ = topology_id;
+          ADR_LOG_OBJECT(kLogNotifyMethods)
+              << "ForEachObserver => TopologyChanged: " << topology_id;
+          ForEachObserver([topology_id](auto obs) { obs->TopologyChanged(topology_id); });
         }
+
+        // Register for any future change in topology, whether this was a change or not.
+        RetrieveCurrentTopology();
       });
 }
 
@@ -1080,69 +1092,159 @@
   }
   FX_DCHECK(sig_proc_client_->is_valid());
 
-  for (auto& element_pair : sig_proc_element_map_) {
-    const auto& element = element_pair.second.element;
-    (*sig_proc_client_)
-        ->WatchElementState({{.processing_element_id = element_pair.first}})
-        .Then([this, element](
-                  fidl::Result<
-                      fuchsia_hardware_audio_signalprocessing::SignalProcessing::WatchElementState>&
-                      result) {
-          std::string context("signalprocessing::WatchElementState response");
-          if (LogResultFrameworkError(result, context.c_str())) {
-            return;
-          }
-
-          auto element_state = result->state();
-          if (!ValidateElementState(element_state, element)) {
-            OnError(ZX_ERR_INVALID_ARGS);
-            return;
-          }
-          ADR_LOG_OBJECT(kLogSignalProcessingFidlResponses) << context;
-
-          // Save the state and notify Observers, but only if this is a change in element state.
-          auto element_record = sig_proc_element_map_.find(*element.id());
-          if (!element_record->second.state.has_value() ||
-              *element_record->second.state != element_state) {
-            element_record->second.state = element_state;
-            // Notify any Observers of this change in element state.
-            ForEachObserver([element_id = *element.id(), element_state](auto obs) {
-              obs->ElementStateChanged(element_id, element_state);
-            });
-          }
-        });
+  for (auto& [element_id, _] : sig_proc_element_map_) {
+    RetrieveElementState(element_id);
   }
 }
 
-bool Device::SetTopology(uint64_t topology_id) {
-  ADR_LOG_METHOD(kLogSignalProcessingFidlCalls);
-  if (state_ == State::Error || !supports_signalprocessing()) {
-    return false;
-  }
-  if (!supports_signalprocessing()) {
-    return false;
-  }
-  FX_DCHECK(sig_proc_client_->is_valid());
+void Device::RetrieveElementState(ElementId element_id) {
+  auto element_match = sig_proc_element_map_.find(element_id);
+  FX_CHECK(element_match != sig_proc_element_map_.end());
+  auto& element = element_match->second.element;
 
-  if (sig_proc_topology_map_.find(topology_id) == sig_proc_topology_map_.end()) {
-    ADR_WARN_METHOD() << "invalid topology_id";
-    return false;
+  (*sig_proc_client_)
+      ->WatchElementState({element_id})
+      .Then([this, element_id,
+             element](fidl::Result<
+                      fuchsia_hardware_audio_signalprocessing::SignalProcessing::WatchElementState>&
+                          result) {
+        std::string context("signalprocessing::WatchElementState response: element_id ");
+        context.append(std::to_string(element_id));
+        if (LogResultFrameworkError(result, context.c_str())) {
+          return;
+        }
+        ADR_LOG_OBJECT(kLogSignalProcessingFidlResponses) << context;
+
+        // Either (a) sig_proc_topology_map_.at(element_id).element is incorrect, or (b) the driver
+        // is behaving incorrectly.
+        auto element_state = result->state();
+        if (!ValidateElementState(element_state, element)) {
+          FX_LOGS(ERROR) << context << ": not found";
+          OnError(ZX_ERR_INVALID_ARGS);
+          return;
+        }
+
+        // Save the state and notify Observers, but only if this is a change in element state.
+        auto element_record = sig_proc_element_map_.find(*element.id());
+        if (element_record->second.state.has_value() &&
+            *element_record->second.state == element_state) {
+          ADR_LOG_OBJECT(kLogNotifyMethods)
+              << "Not sending ElementStateChanged: state is unchanged.";
+        } else {
+          element_record->second.state = element_state;
+          // Notify any Observers of this change in element state.
+          ADR_LOG_OBJECT(kLogNotifyMethods)
+              << "ForEachObserver => ElementStateChanged(" << element_id << ")";
+          ForEachObserver([element_id, element_state](auto obs) {
+            obs->ElementStateChanged(element_id, element_state);
+          });
+        }
+
+        // Register for any future change in element state, whether this was a change or not.
+        RetrieveElementState(element_id);
+      });
+}
+
+// If the method does not return ZX_OK, then the driver was not called.
+zx_status_t Device::SetTopology(uint64_t topology_id) {
+  ADR_LOG_METHOD(kLogSignalProcessingFidlCalls);
+  if (state_ == State::Error) {
+    ADR_WARN_METHOD() << "device already has an error";
+    return ZX_ERR_IO;
   }
 
+  if (!supports_signalprocessing()) {
+    ADR_WARN_METHOD() << "device does not support signalprocessing";
+    return ZX_ERR_NOT_SUPPORTED;
+  }
+
+  if (!GetControlNotify()) {
+    ADR_WARN_METHOD() << "Device must be controlled before this method can be called";
+    return ZX_ERR_ACCESS_DENIED;
+  }
+
+  FX_DCHECK(sig_proc_client_->is_valid());
+  if (sig_proc_topology_map_.find(topology_id) == sig_proc_topology_map_.end()) {
+    ADR_WARN_METHOD() << "invalid topology_id " << topology_id;
+    return ZX_ERR_INVALID_ARGS;
+  }
+
+  // We don't check/prevent "no-change" here, since current_topology_id_ may not reflect in-flight
+  // updates. We update current_topology_id_ and call ObserverNotify::TopologyChanged (or
+  // not, if no change) at only one place: the WatchTopology response handler.
+
   (*sig_proc_client_)
       ->SetTopology(topology_id)
       .Then(
-          [this](
+          [this, topology_id](
               fidl::Result<fuchsia_hardware_audio_signalprocessing::SignalProcessing::SetTopology>&
                   result) {
-            if (LogResultError(result, "SigProc::SetTopology response")) {
+            std::string context("SigProc::SetTopology response: topology_id ");
+            context.append(std::to_string(topology_id));
+            if (LogResultError(result, context.c_str())) {
               return;
             }
-            ADR_LOG_OBJECT(kLogSignalProcessingFidlResponses) << "SigProc::SetTopology response";
-            // We can expect our WatchTopology call to complete now.
+
+            ADR_LOG_OBJECT(kLogSignalProcessingFidlResponses) << context;
+            // Our hanging WatchTopology call will complete now, updating topology_id_ and calling
+            // ObserverNotify::TopologyChanged (or not, if no change).
           });
 
-  return true;
+  return ZX_OK;
+}
+
+// If the method does not return ZX_OK, then the driver was not called.
+zx_status_t Device::SetElementState(
+    ElementId element_id,
+    const fuchsia_hardware_audio_signalprocessing::ElementState& element_state) {
+  ADR_LOG_METHOD(kLogSignalProcessingFidlCalls);
+
+  if (state_ == State::Error) {
+    ADR_WARN_METHOD() << "device already has an error";
+    return ZX_ERR_IO;
+  }
+  if (!supports_signalprocessing()) {
+    ADR_WARN_METHOD() << "device does not support signalprocessing";
+    return ZX_ERR_NOT_SUPPORTED;
+  }
+  if (!GetControlNotify()) {
+    ADR_WARN_METHOD() << "Device must be controlled before this method can be called";
+    return ZX_ERR_ACCESS_DENIED;
+  }
+
+  FX_DCHECK(sig_proc_client_->is_valid());
+  if (sig_proc_element_map_.find(element_id) == sig_proc_element_map_.end()) {
+    ADR_WARN_METHOD() << "invalid element_id " << element_id;
+    return ZX_ERR_INVALID_ARGS;
+  }
+
+  if (!ValidateElementState(element_state, sig_proc_element_map_.at(element_id).element)) {
+    ADR_WARN_METHOD() << "invalid ElementState for element_id " << element_id;
+    return ZX_ERR_INVALID_ARGS;
+  }
+
+  // We don't check/prevent "no-change" here, since sig_proc_element_map_ may not reflect in-flight
+  // updates. We update sig_proc_element_map_ and call ObserverNotify::ElementStateChanged (or
+  // not, if no change) at only one place: the WatchElementState response handler.
+
+  (*sig_proc_client_)
+      ->SetElementState({element_id, element_state})
+      .Then([this, element_id](
+                fidl::Result<
+                    fuchsia_hardware_audio_signalprocessing::SignalProcessing::SetElementState>&
+                    result) {
+        std::string context("SigProc::SetElementState response: element_id ");
+        context.append(std::to_string(element_id));
+        if (LogResultError(result, context.c_str())) {
+          return;
+        }
+
+        ADR_LOG_OBJECT(kLogSignalProcessingFidlResponses) << context;
+        // Our hanging WatchElementState call will complete now, updating our cached state and
+        // calling ObserverNotify::ElementStateChanged (or not, if no change).
+      });
+
+  return ZX_OK;
 }
 
 void Device::RetrieveCodecDaiFormatSets() {
@@ -1322,6 +1424,7 @@
           OnInitializationResponse();
         } else {
           ADR_LOG_OBJECT(kLogStreamConfigFidlResponses) << "WatchGainState received update";
+          ADR_LOG_OBJECT(kLogNotifyMethods) << "ForEachObserver => GainStateChanged";
           ForEachObserver([gain_state = *gain_state_](auto obs) {
             obs->GainStateChanged({{
                 .gain_db = *gain_state.gain_db(),
@@ -1371,6 +1474,7 @@
           OnInitializationResponse();
         } else {
           ADR_LOG_OBJECT(kLogStreamConfigFidlResponses) << "WatchPlugState received update";
+          ADR_LOG_OBJECT(kLogNotifyMethods) << "ForEachObserver => PlugStateChanged";
           ForEachObserver([plug_state = *plug_state_](auto obs) {
             obs->PlugStateChanged(plug_state.plugged().value_or(true)
                                       ? fuchsia_audio_device::PlugState::kPlugged
@@ -1419,6 +1523,7 @@
           OnInitializationResponse();
         } else {
           ADR_LOG_OBJECT(kLogCodecFidlResponses) << "Codec::WatchPlugState received update";
+          ADR_LOG_OBJECT(kLogNotifyMethods) << "ForEachObserver => PlugStateChanged";
           ForEachObserver([plug_state = *plug_state_](auto obs) {
             obs->PlugStateChanged(plug_state.plugged().value_or(true)
                                       ? fuchsia_audio_device::PlugState::kPlugged
@@ -2281,24 +2386,17 @@
     return fuchsia_audio_device::ControlCreateRingBufferError::kFormatMismatch;
   }
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_audio::RingBuffer>();
-  if (!endpoints.is_ok()) {
-    FX_PLOGS(ERROR, endpoints.status_value())
-        << "CreateEndpoints<fuchsia_hardware_audio::RingBuffer> failed";
-    OnError(endpoints.status_value());
-    return fuchsia_audio_device::ControlCreateRingBufferError::kDeviceError;
-  }
+  auto [client, server] = fidl::Endpoints<fuchsia_hardware_audio::RingBuffer>::Create();
 
   if (is_stream_config()) {
-    auto result =
-        (*stream_config_client_)->CreateRingBuffer({driver_format, std::move(endpoints->server)});
+    auto result = (*stream_config_client_)->CreateRingBuffer({driver_format, std::move(server)});
     if (!result.is_ok()) {
       FX_PLOGS(ERROR, result.error_value().status()) << "StreamConfig/CreateRingBuffer failed";
       return fuchsia_audio_device::ControlCreateRingBufferError::kFormatMismatch;
     }
   } else {
     (*composite_client_)
-        ->CreateRingBuffer({element_id, driver_format, std::move(endpoints->server)})
+        ->CreateRingBuffer({element_id, driver_format, std::move(server)})
         .Then([this](fidl::Result<fuchsia_hardware_audio::Composite::CreateRingBuffer>& result) {
           std::string context{"Composite/CreateRingBuffer response"};
           if (LogResultError(result, context.c_str())) {
@@ -2339,14 +2437,13 @@
           .sample_type = *sample_type,
           .channel_count = driver_format.pcm_format()->number_of_channels(),
           .frames_per_second = driver_format.pcm_format()->frame_rate(),
-          // TODO(https://fxbug.dev/42168795): handle .channel_layout, when communicated from
-          // driver.
+          // TODO(https://fxbug.dev/42168795): handle channel_layout when communicated from driver.
       }},
       .driver_format = driver_format,
       .active_channels_bitmask = active_channels_bitmask,
   };
   ring_buffer_record.ring_buffer_client = fidl::Client<fuchsia_hardware_audio::RingBuffer>(
-      std::move(endpoints->client), dispatcher_, ring_buffer_record.ring_buffer_handler.get()),
+      std::move(client), dispatcher_, ring_buffer_record.ring_buffer_handler.get()),
 
   ring_buffer_map_.insert_or_assign(element_id, std::move(ring_buffer_record));
 
diff --git a/src/media/audio/services/device_registry/device.h b/src/media/audio/services/device_registry/device.h
index 49b1195..29c4691 100644
--- a/src/media/audio/services/device_registry/device.h
+++ b/src/media/audio/services/device_registry/device.h
@@ -7,7 +7,7 @@
 
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
 #include <fidl/fuchsia.audio/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/fidl.h>
+#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <lib/fidl/cpp/client.h>
 #include <lib/fit/function.h>
@@ -114,7 +114,11 @@
 
   bool CompositeReset();
 
-  bool SetTopology(TopologyId topology_id);
+  // These return error codes that can be directly returned to the FIDL client.
+  zx_status_t SetTopology(TopologyId topology_id);
+  zx_status_t SetElementState(
+      ElementId element_id,
+      const fuchsia_hardware_audio_signalprocessing::ElementState& element_state);
 
   struct RingBufferInfo {
     fuchsia_audio::RingBuffer ring_buffer;
@@ -204,6 +208,8 @@
   const std::unordered_set<ElementId>& ring_buffer_endpoint_ids() const {
     return ring_buffer_endpoint_ids_;
   }
+  const std::unordered_set<TopologyId>& topology_ids() const { return topology_ids_; }
+  const std::unordered_set<ElementId>& element_ids() const { return element_ids_; }
 
   bool has_plug_state() const { return plug_state_.has_value(); }
   bool has_gain_state() const { return gain_state_.has_value(); }
@@ -259,6 +265,7 @@
   void RetrieveSignalProcessingElements();
   void RetrieveCurrentTopology();
   void RetrieveCurrentElementStates();
+  void RetrieveElementState(ElementId element_id);
 
   bool IsFullyInitialized();
   void OnInitializationResponse();
@@ -399,8 +406,11 @@
   std::unordered_set<ElementId> temp_dai_endpoint_ids_;
   std::unordered_set<ElementId> ring_buffer_endpoint_ids_;
   std::unordered_set<ElementId> temp_ring_buffer_endpoint_ids_;
+  std::unordered_set<ElementId> element_ids_;
+
   std::unordered_map<TopologyId, std::vector<fuchsia_hardware_audio_signalprocessing::EdgePair>>
       sig_proc_topology_map_;
+  std::unordered_set<TopologyId> topology_ids_;
   std::optional<TopologyId> current_topology_id_;
 
   bool dai_format_sets_retrieved_ = false;
diff --git a/src/media/audio/services/device_registry/device_detector.cc b/src/media/audio/services/device_registry/device_detector.cc
index 751f66e..06e9587 100644
--- a/src/media/audio/services/device_registry/device_detector.cc
+++ b/src/media/audio/services/device_registry/device_detector.cc
@@ -4,19 +4,13 @@
 
 #include "src/media/audio/services/device_registry/device_detector.h"
 
-#include <fcntl.h>
 #include <fidl/fuchsia.audio.device/cpp/common_types.h>
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <lib/component/incoming/cpp/protocol.h>
 #include <lib/fidl/cpp/wire/internal/transport_channel.h>
 #include <lib/syslog/cpp/macros.h>
-#include <lib/zx/channel.h>
 
 #include <memory>
-#include <vector>
-
-#include <fbl/unique_fd.h>
 
 #include "src/lib/fsl/io/device_watcher.h"
 #include "src/media/audio/services/device_registry/logging.h"
@@ -111,53 +105,22 @@
       return;
     }
     fidl::Client connector(std::move(client_end.value()), dispatcher_);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_audio::Codec>();
-    if (!endpoints.is_ok()) {
-      FX_LOGS(ERROR) << "DriverClientFromDevFs: CreateEndpoints failed";
-      return;
-    }
-    auto status = connector->Connect(std::move(endpoints->server));
+    auto [client, server] = fidl::Endpoints<fuchsia_hardware_audio::Codec>::Create();
+    auto status = connector->Connect(std::move(server));
     if (!status.is_ok()) {
       FX_PLOGS(ERROR, status.error_value().status())
           << "Connector/Connect failed for " << device_type;
       return;
     }
-    driver_client = DriverClient::WithCodec(std::move(endpoints->client));
+    driver_client = DriverClient::WithCodec(std::move(client));
   } else if (device_type == fuchsia_audio_device::DeviceType::kComposite) {
-    // Composite devices such as aml-g12-tdm are DFv2: we can connect directly to them.
-    // TODO(https://fxbug.dev/304551042): Convert VirtualAudioComposite to DFv2; remove 'else'.
-    if constexpr (kDetectDFv2CompositeDevices) {
-      zx::result client_end = component::ConnectAt<fuchsia_hardware_audio::Composite>(dir, name);
-      if (client_end.is_error()) {
-        FX_PLOGS(ERROR, client_end.error_value())
-            << "DeviceDetector failed to connect to DFv2 Composite node at '" << name << "'";
-        return;
-      }
-      driver_client = DriverClient::WithComposite(std::move(client_end.value()));
+    zx::result client_end = component::ConnectAt<fuchsia_hardware_audio::Composite>(dir, name);
+    if (client_end.is_error()) {
+      FX_PLOGS(ERROR, client_end.error_value())
+          << "DeviceDetector failed to connect to DFv2 Composite node at '" << name << "'";
+      return;
     }
-    // The VirtualAudioComposite implementation is DFv1: connect via CompositeConnector.
-    else {
-      zx::result client_end =
-          component::ConnectAt<fuchsia_hardware_audio::CompositeConnector>(dir, name);
-      if (client_end.is_error()) {
-        FX_PLOGS(ERROR, client_end.error_value())
-            << "DeviceDetector failed to connect to device node at '" << name << "'";
-        return;
-      }
-      fidl::Client connector(std::move(client_end.value()), dispatcher_);
-      auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_audio::Composite>();
-      if (!endpoints.is_ok()) {
-        FX_LOGS(ERROR) << "DriverClientFromDevFs: CreateEndpoints failed";
-        return;
-      }
-      auto status = connector->Connect(std::move(endpoints->server));
-      if (!status.is_ok()) {
-        FX_PLOGS(ERROR, status.error_value().status())
-            << "Connector/Connect failed for " << device_type;
-        return;
-      }
-      driver_client = DriverClient::WithComposite(std::move(endpoints->client));
-    }
+    driver_client = DriverClient::WithComposite(std::move(client_end.value()));
   } else if (device_type == fuchsia_audio_device::DeviceType::kInput ||
              device_type == fuchsia_audio_device::DeviceType::kOutput) {
     zx::result client_end =
@@ -168,18 +131,14 @@
       return;
     }
     fidl::Client connector(std::move(client_end.value()), dispatcher_);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_audio::StreamConfig>();
-    if (!endpoints.is_ok()) {
-      FX_LOGS(ERROR) << "DriverClientFromDevFs: CreateEndpoints failed";
-      return;
-    }
-    auto status = connector->Connect(std::move(endpoints->server));
+    auto [client, server] = fidl::Endpoints<fuchsia_hardware_audio::StreamConfig>::Create();
+    auto status = connector->Connect(std::move(server));
     if (!status.is_ok()) {
       FX_PLOGS(ERROR, status.error_value().status())
           << "Connector/Connect failed for " << device_type;
       return;
     }
-    driver_client = DriverClient::WithStreamConfig(std::move(endpoints->client));
+    driver_client = DriverClient::WithStreamConfig(std::move(client));
   } else {
     FX_LOGS(WARNING) << device_type << " device detection not yet supported";
     return;
diff --git a/src/media/audio/services/device_registry/device_detector.h b/src/media/audio/services/device_registry/device_detector.h
index a43ecde..1866715 100644
--- a/src/media/audio/services/device_registry/device_detector.h
+++ b/src/media/audio/services/device_registry/device_detector.h
@@ -7,8 +7,6 @@
 
 #include <fidl/fuchsia.audio.device/cpp/common_types.h>
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
-#include <lib/fit/function.h>
 #include <lib/zx/result.h>
 
 #include <functional>
@@ -20,11 +18,6 @@
 
 namespace media_audio {
 
-// If true, we detect Composite devices directly (without CompositeConnector).
-// If false, we detect Composite devices via the "trampoline" CompositeConnector.
-// TODO(https://fxbug.dev/304551042): Convert VirtualAudioComposite to DFv2 and remove this flag.
-constexpr bool kDetectDFv2CompositeDevices = true;
-
 using DeviceDetectionHandler = std::function<void(
     std::string_view, fuchsia_audio_device::DeviceType, fuchsia_audio_device::DriverClient)>;
 
diff --git a/src/media/audio/services/device_registry/device_detector_unittest.cc b/src/media/audio/services/device_registry/device_detector_unittest.cc
index bc689e2..f5ad491 100644
--- a/src/media/audio/services/device_registry/device_detector_unittest.cc
+++ b/src/media/audio/services/device_registry/device_detector_unittest.cc
@@ -5,18 +5,12 @@
 #include "src/media/audio/services/device_registry/device_detector.h"
 
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <fidl/fuchsia.hardware.audio/cpp/test_base.h>
-#include <lib/async-loop/cpp/loop.h>
-#include <lib/async-loop/default.h>
 #include <lib/async/cpp/task.h>
 #include <lib/fdio/namespace.h>
-#include <lib/fidl/cpp/binding.h>
-#include <lib/fidl/cpp/channel.h>
 #include <lib/fidl/cpp/wire/channel.h>
 #include <lib/fidl/cpp/wire/internal/transport.h>
 #include <lib/fidl/cpp/wire/internal/transport_channel.h>
-#include <lib/syslog/cpp/macros.h>
 #include <lib/zx/clock.h>
 
 #include <memory>
@@ -85,18 +79,10 @@
   void GetProperties(GetPropertiesCompleter::Sync& completer) override { completer.Reply({}); }
 
   fbl::RefPtr<fs::Service> AsService() {
-    // TODO(https://fxbug.dev/304551042): Convert VirtualAudioComposite to DFv2; remove 'else'.
-    if constexpr (kDetectDFv2CompositeDevices) {
-      return fbl::MakeRefCounted<fs::Service>([this](fidl::ServerEnd<Composite> c) {
-        binding_ = fidl::BindServer(dispatcher(), std::move(c), this);
-        return ZX_OK;
-      });
-    } else {
-      return fbl::MakeRefCounted<fs::Service>([this](fidl::ServerEnd<CompositeConnector> c) {
-        connector_binding_ = fidl::BindServer(dispatcher(), std::move(c), this);
-        return ZX_OK;
-      });
-    }
+    return fbl::MakeRefCounted<fs::Service>([this](fidl::ServerEnd<Composite> c) {
+      binding_ = fidl::BindServer(dispatcher(), std::move(c), this);
+      return ZX_OK;
+    });
   }
 
   bool is_bound() const { return binding_.has_value(); }
diff --git a/src/media/audio/services/device_registry/device_unittest.cc b/src/media/audio/services/device_registry/device_unittest.cc
index 0eb8e33..c20c6f4 100644
--- a/src/media/audio/services/device_registry/device_unittest.cc
+++ b/src/media/audio/services/device_registry/device_unittest.cc
@@ -6,9 +6,9 @@
 
 #include <fidl/fuchsia.audio.device/cpp/common_types.h>
 #include <fidl/fuchsia.audio/cpp/common_types.h>
-#include <fidl/fuchsia.audio/cpp/natural_types.h>
+#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/common_types.h>
+#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
-#include <lib/fidl/cpp/enum.h>
 #include <lib/zx/clock.h>
 #include <zircon/errors.h>
 
@@ -20,7 +20,6 @@
 
 #include "src/media/audio/services/device_registry/common_unittest.h"
 #include "src/media/audio/services/device_registry/device_unittest.h"
-#include "src/media/audio/services/device_registry/logging.h"
 #include "src/media/audio/services/device_registry/testing/fake_codec.h"
 #include "src/media/audio/services/device_registry/testing/fake_composite.h"
 #include "src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.h"
@@ -29,8 +28,6 @@
 
 namespace media_audio {
 
-using ::testing::Optional;
-
 /////////////////////
 // Codec tests
 //
@@ -131,11 +128,10 @@
   ASSERT_TRUE(IsInitialized(device));
 
   // Set up a second, entirely distinct fake device.
-  auto codec_endpoints = fidl::CreateEndpoints<fuchsia_hardware_audio::Codec>();
-  ASSERT_TRUE(codec_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_hardware_audio::Codec>::Create();
 
-  auto fake_driver2 = std::make_shared<FakeCodec>(
-      codec_endpoints->server.TakeChannel(), codec_endpoints->client.TakeChannel(), dispatcher());
+  auto fake_driver2 =
+      std::make_shared<FakeCodec>(server.TakeChannel(), client.TakeChannel(), dispatcher());
   fake_driver2->set_is_input(true);
 
   auto device2 = InitializeDeviceForFakeCodec(fake_driver2);
@@ -779,12 +775,10 @@
   ASSERT_TRUE(IsInitialized(device));
 
   // Set up a second, entirely distinct fake device.
-  auto composite_endpoints = fidl::CreateEndpoints<fuchsia_hardware_audio::Composite>();
-  ASSERT_TRUE(composite_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_hardware_audio::Composite>::Create();
 
   auto fake_driver2 =
-      std::make_shared<FakeComposite>(composite_endpoints->server.TakeChannel(),
-                                      composite_endpoints->client.TakeChannel(), dispatcher());
+      std::make_shared<FakeComposite>(server.TakeChannel(), client.TakeChannel(), dispatcher());
 
   auto device2 = InitializeDeviceForFakeComposite(fake_driver2);
   EXPECT_TRUE(IsInitialized(device2));
@@ -1538,6 +1532,442 @@
 //// Until then, it is not a high priority.
 // TEST_F(CompositeTest, PositionNotifications) { FAIL() << "NOT YET IMPLEMENTED"; }
 
+// Signalprocessing test cases
+//
+// Ensure that we captured the full contents of FakeComposite signalprocessing functionality,
+// specifically the signalprocessing elements.
+TEST_F(CompositeTest, GetElements) {
+  auto fake_driver = MakeFakeComposite();
+  auto device = InitializeDeviceForFakeComposite(fake_driver);
+  ASSERT_TRUE(IsInitialized(device));
+
+  ASSERT_TRUE(device->info().has_value());
+  ASSERT_TRUE(device->info()->signal_processing_elements().has_value());
+  auto& elements = device->info()->signal_processing_elements();
+  ASSERT_TRUE(elements.has_value());
+  ASSERT_EQ(elements->size(), FakeComposite::kElements.size());
+
+  // Get all the `has_value` checks done in automated fashion upfront.
+  for (const auto& element : *elements) {
+    ASSERT_TRUE(element.id().has_value());
+    ASSERT_TRUE(elements->at(0).type().has_value());
+    ASSERT_TRUE(element.description().has_value());
+    ASSERT_TRUE(element.can_disable().has_value());
+    if (element.type() == fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint) {
+      ASSERT_TRUE(element.type_specific().has_value());
+      ASSERT_TRUE(element.type_specific()->endpoint().has_value());
+      ASSERT_TRUE(element.type_specific()->endpoint()->type().has_value());
+      ASSERT_TRUE(element.type_specific()->endpoint()->plug_detect_capabilities().has_value());
+    }
+  }
+
+  EXPECT_EQ(elements->at(0).id(), FakeComposite::kSourceDaiElementId);
+  EXPECT_EQ(elements->at(1).id(), FakeComposite::kDestDaiElementId);
+  EXPECT_EQ(elements->at(0).type(),
+            fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint);
+  EXPECT_EQ(elements->at(1).type(),
+            fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint);
+  EXPECT_FALSE(elements->at(0).can_disable().value());
+  EXPECT_FALSE(elements->at(1).can_disable().value());
+  EXPECT_EQ(*elements->at(0).description(), *FakeComposite::kSourceDaiElement.description());
+  EXPECT_EQ(*elements->at(1).description(), *FakeComposite::kDestDaiElement.description());
+  EXPECT_EQ(*elements->at(0).type_specific()->endpoint()->type(),
+            fuchsia_hardware_audio_signalprocessing::EndpointType::kDaiInterconnect);
+  EXPECT_EQ(*elements->at(1).type_specific()->endpoint()->type(),
+            fuchsia_hardware_audio_signalprocessing::EndpointType::kDaiInterconnect);
+  EXPECT_EQ(elements->at(0).type_specific()->endpoint()->plug_detect_capabilities(),
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kCanAsyncNotify);
+  EXPECT_EQ(elements->at(1).type_specific()->endpoint()->plug_detect_capabilities(),
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kCanAsyncNotify);
+
+  EXPECT_EQ(elements->at(2).id(), FakeComposite::kSourceRbElementId);
+  EXPECT_EQ(elements->at(3).id(), FakeComposite::kDestRbElementId);
+  EXPECT_EQ(elements->at(2).type(),
+            fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint);
+  EXPECT_EQ(elements->at(3).type(),
+            fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint);
+  EXPECT_FALSE(elements->at(2).can_disable().value());
+  EXPECT_FALSE(elements->at(3).can_disable().value());
+  EXPECT_EQ(*elements->at(2).description(), *FakeComposite::kSourceRbElement.description());
+  EXPECT_EQ(*elements->at(3).description(), *FakeComposite::kDestRbElement.description());
+  EXPECT_EQ(*elements->at(2).type_specific()->endpoint()->type(),
+            fuchsia_hardware_audio_signalprocessing::EndpointType::kRingBuffer);
+  EXPECT_EQ(*elements->at(3).type_specific()->endpoint()->type(),
+            fuchsia_hardware_audio_signalprocessing::EndpointType::kRingBuffer);
+  EXPECT_EQ(elements->at(2).type_specific()->endpoint()->plug_detect_capabilities(),
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kHardwired);
+  EXPECT_EQ(elements->at(3).type_specific()->endpoint()->plug_detect_capabilities(),
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kHardwired);
+
+  EXPECT_EQ(elements->at(4).id(), FakeComposite::kMuteElementId);
+  EXPECT_EQ(elements->at(4).type(), fuchsia_hardware_audio_signalprocessing::ElementType::kMute);
+  EXPECT_TRUE(elements->at(4).can_disable().value());
+  EXPECT_EQ(*elements->at(4).description(), *FakeComposite::kMuteElement.description());
+  EXPECT_FALSE(elements->at(4).type_specific().has_value());
+}
+
+// Ensure that we captured the full contents of FakeComposite signalprocessing functionality,
+// specifically the signalprocessing topologies.
+TEST_F(CompositeTest, GetTopologies) {
+  auto fake_driver = MakeFakeComposite();
+  auto device = InitializeDeviceForFakeComposite(fake_driver);
+  ASSERT_TRUE(IsInitialized(device));
+
+  ASSERT_TRUE(device->info().has_value());
+  ASSERT_TRUE(device->info()->signal_processing_elements().has_value());
+  auto& topologies = device->info()->signal_processing_topologies();
+  ASSERT_EQ(topologies->size(), FakeComposite::kTopologies.size());
+
+  ASSERT_TRUE(topologies->at(0).id().has_value());
+  EXPECT_EQ(*topologies->at(0).id(), FakeComposite::kInputOnlyTopologyId);
+  ASSERT_TRUE(topologies->at(0).processing_elements_edge_pairs().has_value());
+  EXPECT_EQ(topologies->at(0).processing_elements_edge_pairs()->size(), 1u);
+  EXPECT_EQ(topologies->at(0).processing_elements_edge_pairs()->at(0).processing_element_id_from(),
+            FakeComposite::kSourceDaiElementId);
+  EXPECT_EQ(topologies->at(0).processing_elements_edge_pairs()->at(0).processing_element_id_to(),
+            FakeComposite::kDestRbElementId);
+
+  ASSERT_TRUE(topologies->at(1).id().has_value());
+  EXPECT_EQ(*topologies->at(1).id(), FakeComposite::kFullDuplexTopologyId);
+  ASSERT_TRUE(topologies->at(1).processing_elements_edge_pairs().has_value());
+  EXPECT_EQ(topologies->at(1).processing_elements_edge_pairs()->size(), 2u);
+  EXPECT_EQ(topologies->at(1).processing_elements_edge_pairs()->at(0).processing_element_id_from(),
+            FakeComposite::kSourceDaiElementId);
+  EXPECT_EQ(topologies->at(1).processing_elements_edge_pairs()->at(0).processing_element_id_to(),
+            FakeComposite::kDestRbElementId);
+  EXPECT_EQ(topologies->at(1).processing_elements_edge_pairs()->at(1).processing_element_id_from(),
+            FakeComposite::kSourceRbElementId);
+  EXPECT_EQ(topologies->at(1).processing_elements_edge_pairs()->at(1).processing_element_id_to(),
+            FakeComposite::kDestDaiElementId);
+
+  ASSERT_TRUE(topologies->at(2).id().has_value());
+  EXPECT_EQ(*topologies->at(2).id(), FakeComposite::kOutputOnlyTopologyId);
+  ASSERT_TRUE(topologies->at(2).processing_elements_edge_pairs().has_value());
+  EXPECT_EQ(topologies->at(2).processing_elements_edge_pairs()->size(), 1u);
+  EXPECT_EQ(topologies->at(2).processing_elements_edge_pairs()->at(0).processing_element_id_from(),
+            FakeComposite::kSourceRbElementId);
+  EXPECT_EQ(topologies->at(2).processing_elements_edge_pairs()->at(0).processing_element_id_to(),
+            FakeComposite::kDestDaiElementId);
+}
+
+// Ensure that we captured the full contents of FakeComposite signalprocessing functionality,
+// specifically the initial signalprocessing state.
+TEST_F(CompositeTest, WatchElementStateInitial) {
+  auto fake_driver = MakeFakeComposite();
+  auto device = InitializeDeviceForFakeComposite(fake_driver);
+  ASSERT_TRUE(IsInitialized(device));
+  ASSERT_TRUE(AddObserver(device));
+
+  const auto& states = notify()->element_states();
+  ASSERT_EQ(states.size(), FakeComposite::kElements.size());
+
+  auto state = states.find(FakeComposite::kSourceDaiElementId)->second;
+  ASSERT_TRUE(state.enabled().has_value());
+  ASSERT_TRUE(state.latency().has_value());
+  ASSERT_TRUE(state.type_specific().has_value());
+  ASSERT_TRUE(state.vendor_specific_data().has_value());
+
+  EXPECT_TRUE(*state.enabled());
+  ASSERT_EQ(state.latency()->Which(),
+            fuchsia_hardware_audio_signalprocessing::Latency::Tag::kLatencyTime);
+  ASSERT_TRUE(state.latency()->latency_time().has_value());
+  EXPECT_EQ(state.latency()->latency_time().value(),
+            FakeComposite::kSourceDaiElementLatency.latency_time().value());
+  ASSERT_EQ(state.type_specific()->Which(),
+            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::Tag::kEndpoint);
+  const auto& endpt_state1 = state.type_specific()->endpoint();
+  ASSERT_TRUE(endpt_state1.has_value());
+  ASSERT_TRUE(endpt_state1->plug_state().has_value());
+  ASSERT_TRUE(endpt_state1->plug_state()->plugged().has_value());
+  EXPECT_TRUE(*endpt_state1->plug_state()->plugged());
+  EXPECT_EQ(*endpt_state1->plug_state()->plug_state_time(), ZX_TIME_INFINITE_PAST);
+  ASSERT_EQ(state.vendor_specific_data()->size(), 8u);
+  EXPECT_EQ(state.vendor_specific_data()->at(0), 1u);
+  EXPECT_EQ(state.vendor_specific_data()->at(7), 8u);
+
+  state = states.find(FakeComposite::kDestDaiElementId)->second;
+  ASSERT_TRUE(state.enabled().has_value());
+  ASSERT_TRUE(state.latency().has_value());
+  ASSERT_TRUE(state.type_specific().has_value());
+  ASSERT_TRUE(state.vendor_specific_data().has_value());
+
+  EXPECT_TRUE(*state.enabled());
+  ASSERT_EQ(state.latency()->Which(),
+            fuchsia_hardware_audio_signalprocessing::Latency::Tag::kLatencyTime);
+  ASSERT_TRUE(state.latency()->latency_time().has_value());
+  EXPECT_EQ(state.latency()->latency_time().value(),
+            FakeComposite::kDestDaiElementLatency.latency_time().value());
+  ASSERT_EQ(state.type_specific()->Which(),
+            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::Tag::kEndpoint);
+  const auto& endpt_state2 = state.type_specific()->endpoint();
+  ASSERT_TRUE(endpt_state2.has_value());
+  ASSERT_TRUE(endpt_state2->plug_state().has_value());
+  ASSERT_TRUE(endpt_state2->plug_state()->plugged().has_value());
+  EXPECT_TRUE(*endpt_state2->plug_state()->plugged());
+  EXPECT_EQ(*endpt_state2->plug_state()->plug_state_time(), ZX_TIME_INFINITE_PAST);
+  ASSERT_EQ(state.vendor_specific_data()->size(), 9u);
+  EXPECT_EQ(state.vendor_specific_data()->at(0), 8u);
+  EXPECT_EQ(state.vendor_specific_data()->at(8), 0u);
+
+  state = states.find(FakeComposite::kSourceRbElementId)->second;
+  ASSERT_TRUE(state.enabled().has_value());
+  ASSERT_TRUE(state.latency().has_value());
+  ASSERT_TRUE(state.type_specific().has_value());
+  EXPECT_FALSE(state.vendor_specific_data().has_value());
+
+  EXPECT_TRUE(*state.enabled());
+  ASSERT_EQ(state.latency()->Which(),
+            fuchsia_hardware_audio_signalprocessing::Latency::Tag::kLatencyFrames);
+  ASSERT_TRUE(states.find(FakeComposite::kSourceRbElementId)
+                  ->second.latency()
+                  ->latency_frames()
+                  .has_value());
+  EXPECT_EQ(state.latency()->latency_frames().value(),
+            FakeComposite::kSourceRbElementLatency.latency_frames().value());
+  ASSERT_EQ(state.type_specific()->Which(),
+            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::Tag::kEndpoint);
+  const auto& endpt_state3 = state.type_specific()->endpoint();
+  ASSERT_TRUE(endpt_state3.has_value());
+  ASSERT_TRUE(endpt_state3->plug_state().has_value());
+  ASSERT_TRUE(endpt_state3->plug_state()->plugged().has_value());
+  EXPECT_TRUE(*endpt_state3->plug_state()->plugged());
+  EXPECT_EQ(*endpt_state3->plug_state()->plug_state_time(), ZX_TIME_INFINITE_PAST);
+
+  state = states.find(FakeComposite::kDestRbElementId)->second;
+  ASSERT_TRUE(state.enabled().has_value());
+  ASSERT_TRUE(state.latency().has_value());
+  ASSERT_TRUE(state.type_specific().has_value());
+  EXPECT_FALSE(state.vendor_specific_data().has_value());
+
+  EXPECT_TRUE(*state.enabled());
+  ASSERT_EQ(state.latency()->Which(),
+            fuchsia_hardware_audio_signalprocessing::Latency::Tag::kLatencyFrames);
+  ASSERT_TRUE(state.latency()->latency_frames().has_value());
+  EXPECT_EQ(state.latency()->latency_frames().value(),
+            FakeComposite::kDestRbElementLatency.latency_frames().value());
+  ASSERT_EQ(state.type_specific()->Which(),
+            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::Tag::kEndpoint);
+  const auto& endpt_state4 = state.type_specific()->endpoint();
+  ASSERT_TRUE(endpt_state4.has_value());
+  ASSERT_TRUE(endpt_state4->plug_state().has_value());
+  ASSERT_TRUE(endpt_state4->plug_state()->plugged().has_value());
+  EXPECT_TRUE(*endpt_state4->plug_state()->plugged());
+  EXPECT_EQ(*endpt_state4->plug_state()->plug_state_time(), ZX_TIME_INFINITE_PAST);
+
+  state = states.find(FakeComposite::kMuteElementId)->second;
+  ASSERT_TRUE(state.enabled().has_value());
+  EXPECT_FALSE(state.latency().has_value());
+  EXPECT_FALSE(state.type_specific().has_value());
+  EXPECT_FALSE(state.vendor_specific_data().has_value());
+
+  EXPECT_FALSE(*state.enabled());
+}
+
+TEST_F(CompositeTest, WatchElementStateUpdate) {
+  auto fake_driver = MakeFakeComposite();
+  auto device = InitializeDeviceForFakeComposite(fake_driver);
+  ASSERT_TRUE(IsInitialized(device));
+  ASSERT_TRUE(AddObserver(device));
+
+  auto& elements = *device->info()->signal_processing_elements();
+  const auto& states = notify()->element_states();
+  ASSERT_EQ(states.size(), FakeComposite::kElements.size());
+
+  // Determine which states we can inject change into.
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states_to_inject;
+  auto plug_change_time_to_inject = zx::clock::get_monotonic();
+  for (const auto& element : elements) {
+    auto element_id = *element.id();
+    auto match_state = states.find(element_id);
+    ASSERT_NE(match_state, states.end());
+    auto state = match_state->second;
+
+    // Handle the Mute node
+    if (element.type() == fuchsia_hardware_audio_signalprocessing::ElementType::kMute &&
+        element.can_disable().value_or(false)) {
+      // By configuration, our Mute starts disabled (we enable it as our ElementState change).
+      ASSERT_TRUE(state.enabled().has_value());
+      EXPECT_FALSE(*state.enabled());
+      element_states_to_inject.insert_or_assign(
+          element_id, fuchsia_hardware_audio_signalprocessing::ElementState{{.enabled = true}});
+      continue;
+    }
+
+    // Then weed out any non-pluggable elements.
+    if (element.type() != fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint ||
+        !element.type_specific().has_value() || !element.type_specific()->endpoint().has_value() ||
+        element.type_specific()->endpoint()->plug_detect_capabilities() !=
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kCanAsyncNotify) {
+      continue;
+    }
+    if (!state.type_specific().has_value() || !state.type_specific()->endpoint().has_value() ||
+        !state.type_specific()->endpoint()->plug_state().has_value() ||
+        !state.type_specific()->endpoint()->plug_state()->plugged().has_value() ||
+        !state.type_specific()->endpoint()->plug_state()->plug_state_time().has_value()) {
+      continue;
+    }
+    auto was_plugged = state.type_specific()->endpoint()->plug_state()->plugged();
+    auto new_state = fuchsia_hardware_audio_signalprocessing::ElementState{{
+        .type_specific =
+            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::WithEndpoint(
+                fuchsia_hardware_audio_signalprocessing::EndpointElementState{{
+                    fuchsia_hardware_audio_signalprocessing::PlugState{{
+                        !was_plugged,
+                        plug_change_time_to_inject.get(),
+                    }},
+                }}),
+        .enabled = true,
+        .latency =
+            fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyTime(ZX_USEC(element_id)),
+        .vendor_specific_data = {{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
+                                  'D', 'E', 'F', 'Z'}},  // 'Z' is located at byte [16].
+    }};
+    ASSERT_EQ(new_state.vendor_specific_data()->size(), 17u) << "Test configuration error";
+    element_states_to_inject.insert_or_assign(element_id, new_state);
+  }
+
+  if (element_states_to_inject.empty()) {
+    GTEST_SKIP()
+        << "No element states can be changed, so dynamic element_state change cannot be tested";
+  }
+
+  notify()->clear_element_states();
+
+  // Inject the changes.
+  for (const auto& [element_id, element_state] : element_states_to_inject) {
+    fake_driver->InjectElementStateChange(element_id, element_state);
+  }
+
+  RunLoopUntilIdle();
+  EXPECT_EQ(element_states_to_inject.size(), notify()->element_states().size());
+  for (const auto& [element_id, state_received] : notify()->element_states()) {
+    // Compare to actual static values we know.
+    if (element_id == FakeComposite::kMuteElementId) {
+      EXPECT_FALSE(state_received.type_specific().has_value());
+      ASSERT_TRUE(state_received.enabled().has_value());
+      EXPECT_FALSE(state_received.latency().has_value());
+      EXPECT_FALSE(state_received.vendor_specific_data().has_value());
+
+      EXPECT_EQ(state_received.enabled(), true);
+    } else {
+      ASSERT_TRUE(state_received.type_specific().has_value());
+      ASSERT_TRUE(state_received.type_specific()->endpoint().has_value());
+      ASSERT_TRUE(state_received.type_specific()->endpoint()->plug_state().has_value());
+      ASSERT_TRUE(state_received.type_specific()->endpoint()->plug_state()->plugged().has_value());
+      ASSERT_TRUE(
+          state_received.type_specific()->endpoint()->plug_state()->plug_state_time().has_value());
+      EXPECT_EQ(*state_received.type_specific()->endpoint()->plug_state()->plug_state_time(),
+                plug_change_time_to_inject.get());
+
+      ASSERT_TRUE(state_received.enabled().has_value());
+      EXPECT_EQ(state_received.enabled(), true);
+
+      ASSERT_TRUE(state_received.latency().has_value());
+      ASSERT_EQ(state_received.latency()->Which(),
+                fuchsia_hardware_audio_signalprocessing::Latency::Tag::kLatencyTime);
+      EXPECT_EQ(state_received.latency()->latency_time().value(), ZX_USEC(element_id));
+
+      ASSERT_TRUE(state_received.vendor_specific_data().has_value());
+      ASSERT_EQ(state_received.vendor_specific_data()->size(), 17u);
+      EXPECT_EQ(state_received.vendor_specific_data()->at(16), 'Z');
+    }
+
+    // Compare to what we injected.
+    ASSERT_FALSE(element_states_to_inject.find(element_id) == element_states_to_inject.end())
+        << "WatchElementState response received for unknown element_id " << element_id;
+    const auto& state_injected = element_states_to_inject.find(element_id)->second;
+    EXPECT_EQ(state_received, state_injected);
+  }
+}
+
+TEST_F(CompositeTest, WatchTopologyInitial) {
+  auto fake_driver = MakeFakeComposite();
+  fake_driver->InjectTopologyChange(FakeComposite::kFullDuplexTopologyId);
+  auto device = InitializeDeviceForFakeComposite(fake_driver);
+  ASSERT_TRUE(IsInitialized(device));
+  ASSERT_TRUE(AddObserver(device));
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(notify()->topology_id().has_value());
+  EXPECT_EQ(*notify()->topology_id(), FakeComposite::kFullDuplexTopologyId);
+}
+
+TEST_F(CompositeTest, WatchTopologyUpdate) {
+  auto fake_driver = MakeFakeComposite();
+  fake_driver->InjectTopologyChange(FakeComposite::kFullDuplexTopologyId);
+  auto device = InitializeDeviceForFakeComposite(fake_driver);
+  ASSERT_TRUE(IsInitialized(device));
+  ASSERT_TRUE(AddObserver(device));
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(notify()->topology_id().has_value());
+  EXPECT_EQ(*notify()->topology_id(), FakeComposite::kFullDuplexTopologyId);
+  notify()->clear_topology_id();
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(notify()->topology_id().has_value());
+
+  fake_driver->InjectTopologyChange(FakeComposite::kInputOnlyTopologyId);
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(notify()->topology_id().has_value());
+  EXPECT_EQ(*notify()->topology_id(), FakeComposite::kInputOnlyTopologyId);
+}
+
+TEST_F(CompositeTest, SetTopology) {
+  auto fake_driver = MakeFakeComposite();
+  auto device = InitializeDeviceForFakeComposite(fake_driver);
+  ASSERT_TRUE(IsInitialized(device));
+  ASSERT_TRUE(SetControl(device));
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(notify()->topology_id().has_value());
+  TopologyId current_topology_id = *notify()->topology_id();
+
+  TopologyId topology_id_to_set = 0;
+  if (device->topology_ids().size() < 2) {
+    GTEST_SKIP() << "Not enough topologies to run this test case";
+  }
+  for (auto t : device->topology_ids()) {
+    if (t != current_topology_id) {
+      topology_id_to_set = t;
+      break;
+    }
+  }
+
+  EXPECT_EQ(device->SetTopology(topology_id_to_set), ZX_OK);
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(notify()->topology_id().has_value());
+  EXPECT_EQ(*notify()->topology_id(), topology_id_to_set);
+}
+
+TEST_F(CompositeTest, SetElementState) {
+  auto fake_driver = MakeFakeComposite();
+  auto device = InitializeDeviceForFakeComposite(fake_driver);
+  ASSERT_TRUE(IsInitialized(device));
+  ASSERT_TRUE(SetControl(device));
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(notify()->element_states().find(FakeComposite::kMuteElementId) !=
+              notify()->element_states().end());
+  notify()->clear_element_states();
+  fuchsia_hardware_audio_signalprocessing::ElementState state{{.enabled = true}};
+
+  EXPECT_EQ(device->SetElementState(FakeComposite::kMuteElementId, state), ZX_OK);
+
+  RunLoopUntilIdle();
+  ASSERT_FALSE(notify()->element_states().find(FakeComposite::kMuteElementId) ==
+               notify()->element_states().end());
+  auto new_state = notify()->element_states().find(FakeComposite::kMuteElementId)->second;
+  ASSERT_TRUE(new_state.enabled().has_value());
+  EXPECT_EQ(*new_state.enabled(), true);
+  EXPECT_FALSE(new_state.latency().has_value());
+  EXPECT_FALSE(new_state.type_specific().has_value());
+  EXPECT_FALSE(new_state.vendor_specific_data().has_value());
+}
+
 /////////////////////
 // StreamConfig tests
 //
@@ -1593,12 +2023,10 @@
   ASSERT_TRUE(IsInitialized(device));
 
   // Set up a second, entirely distinct fake device.
-  auto stream_config_endpoints = fidl::CreateEndpoints<fuchsia_hardware_audio::StreamConfig>();
-  ASSERT_TRUE(stream_config_endpoints.is_ok());
+  auto [client, server] = fidl::Endpoints<fuchsia_hardware_audio::StreamConfig>::Create();
 
-  auto fake_driver2 = std::make_shared<FakeStreamConfig>(
-      stream_config_endpoints->server.TakeChannel(), stream_config_endpoints->client.TakeChannel(),
-      dispatcher());
+  auto fake_driver2 =
+      std::make_shared<FakeStreamConfig>(server.TakeChannel(), client.TakeChannel(), dispatcher());
   fake_driver2->set_is_input(true);
 
   auto device2 = InitializeDeviceForFakeStreamConfig(fake_driver2);
diff --git a/src/media/audio/services/device_registry/device_unittest.h b/src/media/audio/services/device_registry/device_unittest.h
index b1fa6ff..401fb76 100644
--- a/src/media/audio/services/device_registry/device_unittest.h
+++ b/src/media/audio/services/device_registry/device_unittest.h
@@ -7,12 +7,6 @@
 
 #include <fidl/fuchsia.audio.device/cpp/common_types.h>
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
-#include <lib/fidl/cpp/client.h>
-#include <lib/fidl/cpp/enum.h>
-#include <lib/fidl/cpp/unified_messaging_declarations.h>
-#include <lib/fidl/cpp/wire/status.h>
-#include <zircon/compiler.h>
 #include <zircon/errors.h>
 #include <zircon/types.h>
 
@@ -288,11 +282,14 @@
     std::optional<zx::time>& codec_stop_time() { return codec_stop_time_; }
     bool codec_stop_failed() const { return codec_stop_failed_; }
 
-    std::optional<TopologyId> topology_id() const { return topology_id_; }
     const std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>&
     element_states() const {
       return element_states_;
     }
+    void clear_element_states() { element_states_.clear(); }
+
+    std::optional<TopologyId> topology_id() const { return topology_id_; }
+    void clear_topology_id() { topology_id_.reset(); }
 
    private:
     [[maybe_unused]] DeviceTestBase& parent_;
@@ -418,6 +415,11 @@
     return device->element_driver_ring_buffer_format_sets_;
   }
 
+  static const std::unordered_map<ElementId, ElementRecord>& signal_processing_elements(
+      const std::shared_ptr<Device>& device) {
+    return device->sig_proc_element_map_;
+  }
+
   std::shared_ptr<FakeComposite> MakeFakeComposite() {
     auto composite_endpoints = fidl::CreateEndpoints<fuchsia_hardware_audio::Composite>();
     EXPECT_TRUE(composite_endpoints.is_ok());
@@ -649,8 +651,8 @@
   std::shared_ptr<FakeStreamConfig> MakeFakeStreamConfig(bool is_input = false) {
     auto stream_config_endpoints = fidl::Endpoints<fuchsia_hardware_audio::StreamConfig>::Create();
     auto fake_stream = std::make_shared<FakeStreamConfig>(
-        stream_config_endpoints.server.TakeChannel(),
-        stream_config_endpoints.client.TakeChannel(), dispatcher());
+        stream_config_endpoints.server.TakeChannel(), stream_config_endpoints.client.TakeChannel(),
+        dispatcher());
     fake_stream->set_is_input(is_input);
     return fake_stream;
   }
diff --git a/src/media/audio/services/device_registry/device_warning_unittest.cc b/src/media/audio/services/device_registry/device_warning_unittest.cc
index 0a3e1f8..e01c43a 100644
--- a/src/media/audio/services/device_registry/device_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/device_warning_unittest.cc
@@ -6,17 +6,12 @@
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/common_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/natural_types.h>
-#include <lib/fidl/cpp/enum.h>
-#include <zircon/errors.h>
-#include <zircon/types.h>
 
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/device_registry/common_unittest.h"
 #include "src/media/audio/services/device_registry/device.h"
 #include "src/media/audio/services/device_registry/device_unittest.h"
-#include "src/media/audio/services/device_registry/testing/fake_codec.h"
-#include "src/media/audio/services/device_registry/testing/fake_stream_config.h"
 #include "src/media/audio/services/device_registry/validate.h"
 
 namespace media_audio {
@@ -236,7 +231,11 @@
 
   RunLoopUntilIdle();
   EXPECT_FALSE(notify()->dai_format());
-  // TODO: Expect a NotSet notification here.
+  auto error_notify =
+      notify()->dai_format_errors().find(fuchsia_audio_device::kDefaultDaiInterconnectElementId);
+  ASSERT_TRUE(error_notify != notify()->dai_format_errors().end());
+  EXPECT_EQ(error_notify->second,
+            fuchsia_audio_device::ControlSetDaiFormatError::kInvalidDaiFormat);
 
   EXPECT_EQ(device_presence_watcher()->ready_devices().size(), 1u);
   EXPECT_EQ(device_presence_watcher()->error_devices().size(), 0u);
@@ -267,7 +266,10 @@
 
   RunLoopUntilIdle();
   EXPECT_FALSE(notify()->dai_format());
-  // TODO: Expect a NotSet notification here.
+  auto error_notify =
+      notify()->dai_format_errors().find(fuchsia_audio_device::kDefaultDaiInterconnectElementId);
+  ASSERT_TRUE(error_notify != notify()->dai_format_errors().end());
+  EXPECT_EQ(error_notify->second, fuchsia_audio_device::ControlSetDaiFormatError::kFormatMismatch);
 
   EXPECT_EQ(device_presence_watcher()->ready_devices().size(), 1u);
   EXPECT_EQ(device_presence_watcher()->error_devices().size(), 0u);
@@ -347,6 +349,26 @@
   EXPECT_EQ(device_presence_watcher()->error_devices().size(), 0u);
 }
 
+// GetTopologies on error device
+// GetTopologies (unsupported by driver)
+
+// GetElements on error device
+// GetElements (unsupported by driver)
+
+// WatchTopology on error device
+// WatchTopology (unsupported by driver)
+
+// WatchElementState on error device
+// WatchElementState (unsupported by driver)
+
+// SetTopology on error device
+// SetTopology (unsupported by driver)
+// SetTopology without a Control
+
+// SetElementState on error device
+// SetElementState (unsupported by driver)
+// SetElementState without a Control
+
 ////////////////////
 // Composite tests
 //
@@ -679,19 +701,64 @@
 
 // CreateRingBufferSizeTooLarge test?
 
-// TODO: negative RingBufferProperties cases?
+// Negative RingBufferProperties cases?
+// Device with error
 
-// TODO: negative GetVmo cases?
+// Negative GetVmo cases?
+// Device with error
 
-// TODO: negative SetActiveChannels cases.
+// Negative SetActiveChannels cases.
+// Device with error
 
-// TODO: negative RingBuffer Start cases.
+// Negative RingBuffer Start cases.
+// Device with error
 
-// TODO: negative RingBuffer Stop  cases.
+// Negative RingBuffer Stop  cases.
+// Device with error
 
-// TODO: negative WatchDelayInfo cases.
+// Negative WatchDelayInfo cases.
+// Device with error
 
-// TODO: negative WatchClockRecoveryPositionInfo cases?
+// Negative WatchClockRecoveryPositionInfo cases?
+// Device with error
+
+////////////////////////////////////////////////////////
+// Signalprocessing test cases
+//
+// Negative cases for GetTopologies?
+// GetTopologies on error device
+
+// Negative cases for GetElements?
+// GetElements on error device
+
+// Negative cases for WatchTopology?
+// WatchTopology on error device
+// WatchTopology while pending
+
+// Negative cases for WatchElementState
+// WatchElementState on error device
+// WatchElementState with unknown element_id
+// WatchElementState while pending
+
+// Negative cases for SetTopology
+// SetTopology on error device
+// SetTopology without Control.
+// SetTopology with unknown topology_id
+// Try pipelining a bunch of these calls without waiting and see if errors occur
+
+// Negative cases for SetElementState
+// SetElementState on error device
+// SetElementState without Control
+// SetElementState with unknown element_id
+// SetElementState with invalid state
+// SetElementState when the state can't be changed
+// Try pipelining a bunch of these calls without waiting and see if errors occur
+
+// Move these ideas to device_unittest.cc:
+// SetTopology(no-change) should not generate a notification.
+// SetElementState(no-change) should not generate a notification.
+// Eventually, develop a mechanism in FakeComposite to disable signalprocessing, and test the six
+// methods in that mode as well
 
 ////////////////////
 // StreamConfig tests
@@ -930,4 +997,22 @@
 // GetDaiFormats for FakeDriver that fails the GetDaiFormats call
 // GetDaiFormats for FakeDriver that returns bad dai_format_sets
 
+// GetTopologies on error device
+// GetTopologies (unsupported by driver)
+
+// GetElements on error device
+// GetElements (unsupported by driver)
+
+// WatchTopology on error device
+// WatchTopology (unsupported by driver)
+
+// WatchElementState on error device
+// WatchElementState (unsupported by driver)
+
+// SetTopology on error device
+// SetTopology (unsupported by driver)
+
+// SetElementState on error device
+// SetElementState (unsupported by driver)
+
 }  // namespace media_audio
diff --git a/src/media/audio/services/device_registry/logging.cc b/src/media/audio/services/device_registry/logging.cc
index 82cb7f9..2504a97 100644
--- a/src/media/audio/services/device_registry/logging.cc
+++ b/src/media/audio/services/device_registry/logging.cc
@@ -4,7 +4,7 @@
 
 #include "src/media/audio/services/device_registry/logging.h"
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
+#include <fidl/fuchsia.audio.device/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/fidl.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <lib/syslog/cpp/macros.h>
@@ -513,7 +513,7 @@
 
 void LogElementStateInternal(
     const std::optional<fuchsia_hardware_audio_signalprocessing::ElementState>& element_state,
-    std::string indent) {
+    const std::string& indent) {
   if (!element_state.has_value()) {
     FX_LOGS(INFO) << indent << "                      <none>  (during device initialization)";
     return;
@@ -740,17 +740,63 @@
   }
 }
 
-void LogDeviceInfo(const fuchsia_audio_device::Info& device_info) {
-  if constexpr (kLogSummaryFinalDeviceInfo) {
-    FX_LOGS(INFO) << "Detected " << device_info.device_type() << " device "
+// Signal the successful detection, querying, initialization and addition of a device.
+void LogDeviceAddition(const fuchsia_audio_device::Info& device_info) {
+  if constexpr (kLogDeviceAddErrorRemove) {
+    FX_DCHECK(device_info.device_type().has_value());
+    FX_LOGS(INFO) << device_info.device_type() << " device "
                   << (device_info.device_name()
                           ? std::string("'") + *device_info.device_name() + "'"
-                          : "[nameless]")
-                  << ", assigned token_id "
+                          : "<none>")
+                  << " with token_id "
                   << (device_info.token_id() ? std::to_string(*device_info.token_id())
-                                             : "<none> (non-compliant)");
+                                             : "<none> (non-compliant)")
+                  << " has been added";
   }
-  if constexpr (!kLogDetailedFinalDeviceInfo) {
+}
+
+// Mirror (bookend) the analogous `LogDeviceAddition` for device removal. Removals may be "normal"
+// (USB unplug) or caused by fatal error. The latter can happen before `device_info` is created.
+void LogDeviceRemoval(const std::optional<fuchsia_audio_device::Info>& device_info) {
+  if constexpr (kLogDeviceAddErrorRemove) {
+    if (device_info.has_value()) {
+      FX_DCHECK(device_info->device_type().has_value());
+      FX_LOGS(INFO) << device_info->device_type() << " device "
+                    << (device_info->device_name()
+                            ? std::string("'") + *device_info->device_name() + "'"
+                            : "<none>")
+                    << " with token_id "
+                    << (device_info->token_id() ? std::to_string(*device_info->token_id())
+                                                : "<none> (non-compliant)")
+                    << " has been removed";
+    } else {
+      FX_LOGS(WARNING) << "UNKNOWN (uninitialized) device has encountered a fatal error";
+    }
+  }
+}
+
+// Mirror (bookend) the analogous `LogDeviceAddition`, for a device error.
+// This can also occur before a device has been successfully added: device_info may not be set.
+void LogDeviceError(const std::optional<fuchsia_audio_device::Info>& device_info) {
+  if constexpr (kLogDeviceAddErrorRemove) {
+    if (device_info.has_value()) {
+      FX_DCHECK(device_info->device_type().has_value());
+      FX_LOGS(WARNING) << device_info->device_type() << " device "
+                       << (device_info->device_name().has_value()
+                               ? std::string("'") + *device_info->device_name() + "'"
+                               : "<none>")
+                       << " with token_id "
+                       << (device_info->token_id() ? std::to_string(*device_info->token_id())
+                                                   : "<none> (non-compliant)")
+                       << " has encountered a fatal error";
+    } else {
+      FX_LOGS(WARNING) << "UNKNOWN (uninitialized) device has encountered a fatal error";
+    }
+  }
+}
+
+void LogDeviceInfo(const fuchsia_audio_device::Info& device_info) {
+  if constexpr (!kLogDeviceInfo) {
     return;
   }
 
@@ -958,9 +1004,9 @@
                           : "");
   }
 
-  FX_LOGS(INFO) << "   plug_detect_caps             " << device_info.plug_detect_caps();
+  FX_LOGS(INFO) << "  plug_detect_caps             " << device_info.plug_detect_caps();
 
-  std::string clock_domain_str{"   clock_domain                 "};
+  std::string clock_domain_str{"  clock_domain                 "};
   if (device_info.clock_domain()) {
     clock_domain_str += std::to_string(*device_info.clock_domain());
     if (*device_info.clock_domain() == fuchsia_hardware_audio::kClockDomainMonotonic) {
@@ -979,7 +1025,7 @@
   FX_LOGS(INFO) << clock_domain_str;
 
   if (device_info.signal_processing_elements()) {
-    FX_LOGS(INFO) << "   signal_processing_elements ["
+    FX_LOGS(INFO) << "  signal_processing_elements ["
                   << device_info.signal_processing_elements()->size() << "]"
                   << (device_info.signal_processing_elements()->empty() ? " (non-compliant)" : "");
     for (auto idx = 0u; idx < device_info.signal_processing_elements()->size(); ++idx) {
@@ -987,14 +1033,14 @@
                          "    ");
     }
   } else {
-    FX_LOGS(INFO) << "   signal_processing_elements   <none>"
+    FX_LOGS(INFO) << "  signal_processing_elements   <none>"
                   << (device_info.device_type() == fuchsia_audio_device::DeviceType::kComposite
                           ? " (non-compliant)"
                           : "");
   }
 
   if (device_info.signal_processing_topologies()) {
-    FX_LOGS(INFO) << "   signal_processing_topologies ["
+    FX_LOGS(INFO) << "  signal_processing_topologies ["
                   << device_info.signal_processing_topologies()->size() << "]"
                   << (device_info.signal_processing_topologies()->empty() ? " (non-compliant)"
                                                                           : "");
diff --git a/src/media/audio/services/device_registry/logging.h b/src/media/audio/services/device_registry/logging.h
index 170fc50..9146bac 100644
--- a/src/media/audio/services/device_registry/logging.h
+++ b/src/media/audio/services/device_registry/logging.h
@@ -6,7 +6,6 @@
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_LOGGING_H_
 
 #include <fidl/fuchsia.audio.device/cpp/common_types.h>
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/fidl.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <lib/syslog/cpp/macros.h>
@@ -41,8 +40,8 @@
 inline constexpr bool kLogDeviceDetection = false;
 inline constexpr bool kLogDeviceInitializationProgress = false;
 inline constexpr bool kLogAudioDeviceRegistryMethods = false;
-inline constexpr bool kLogSummaryFinalDeviceInfo = true;
-inline constexpr bool kLogDetailedFinalDeviceInfo = false;
+inline constexpr bool kLogDeviceAddErrorRemove = true;
+inline constexpr bool kLogDeviceInfo = true;
 
 inline constexpr bool kLogDeviceMethods = false;
 inline constexpr bool kLogObjectLifetimes = false;
@@ -103,6 +102,9 @@
 
 void LogCompositeProperties(const fuchsia_hardware_audio::CompositeProperties& composite_props);
 
+void LogDeviceAddition(const fuchsia_audio_device::Info& device_info);
+void LogDeviceRemoval(const std::optional<fuchsia_audio_device::Info>& device_info);
+void LogDeviceError(const std::optional<fuchsia_audio_device::Info>& device_info);
 void LogDeviceInfo(const fuchsia_audio_device::Info& device_info);
 
 void LogElementMap(const std::unordered_map<ElementId, ElementRecord>& element_map);
diff --git a/src/media/audio/services/device_registry/observer_server.cc b/src/media/audio/services/device_registry/observer_server.cc
index 5f4d7fa..e00e540 100644
--- a/src/media/audio/services/device_registry/observer_server.cc
+++ b/src/media/audio/services/device_registry/observer_server.cc
@@ -23,10 +23,10 @@
     std::shared_ptr<const Device> device) {
   ADR_LOG_STATIC(kLogObserverServerMethods);
 
-  return BaseFidlServer::Create(std::move(thread), std::move(server_end), device);
+  return BaseFidlServer::Create(std::move(thread), std::move(server_end), std::move(device));
 }
 
-ObserverServer::ObserverServer(std::shared_ptr<const Device> device) : device_(device) {
+ObserverServer::ObserverServer(std::shared_ptr<const Device> device) : device_(std::move(device)) {
   ADR_LOG_METHOD(kLogObjectLifetimes);
 
   // TODO(https://fxbug.dev/42068381): Consider Health-check if this can change post-initialization.
@@ -44,7 +44,7 @@
 void ObserverServer::DeviceHasError() {
   ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods);
 
-  has_error_ = true;
+  device_has_error_ = true;
   DeviceIsRemoved();
 }
 
@@ -60,7 +60,7 @@
 void ObserverServer::WatchGainState(WatchGainStateCompleter::Sync& completer) {
   ADR_LOG_METHOD(kLogObserverServerMethods);
 
-  if (has_error_) {
+  if (device_has_error_) {
     ADR_WARN_METHOD() << "Device encountered an error and will be removed";
     completer.Reply(fit::error<fuchsia_audio_device::ObserverWatchGainStateError>(
         fuchsia_audio_device::ObserverWatchGainStateError::kDeviceError));
@@ -82,15 +82,8 @@
     return;
   }
 
-  if (new_gain_state_to_notify_) {
-    fuchsia_audio_device::ObserverWatchGainStateResponse response{{
-        .state = std::move(*new_gain_state_to_notify_),
-    }};
-    new_gain_state_to_notify_.reset();
-    completer.Reply(fit::success(std::move(response)));
-  } else {
-    watch_gain_state_completer_ = completer.ToAsync();
-  }
+  watch_gain_state_completer_ = completer.ToAsync();
+  MaybeCompleteWatchGainState();
 }
 
 void ObserverServer::GainStateChanged(const fuchsia_audio_device::GainState& new_gain_state) {
@@ -98,23 +91,27 @@
 
   FX_DCHECK(device_->is_stream_config());
 
-  if (watch_gain_state_completer_) {
-    new_gain_state_to_notify_.reset();
+  new_gain_state_to_notify_ = new_gain_state;
+  MaybeCompleteWatchGainState();
+}
 
+void ObserverServer::MaybeCompleteWatchGainState() {
+  if (watch_gain_state_completer_ && new_gain_state_to_notify_) {
     auto completer = std::move(*watch_gain_state_completer_);
     watch_gain_state_completer_.reset();
-    completer.Reply(fit::success(fuchsia_audio_device::ObserverWatchGainStateResponse{{
-        .state = new_gain_state,
-    }}));
-  } else {
-    new_gain_state_to_notify_ = new_gain_state;
+
+    fuchsia_audio_device::ObserverWatchGainStateResponse response{
+        {.state = std::move(*new_gain_state_to_notify_)}};
+    new_gain_state_to_notify_.reset();
+
+    completer.Reply(fit::success(response));
   }
 }
 
 void ObserverServer::WatchPlugState(WatchPlugStateCompleter::Sync& completer) {
   ADR_LOG_METHOD(kLogObserverServerMethods);
 
-  if (has_error_) {
+  if (device_has_error_) {
     ADR_WARN_METHOD() << "Device encountered an error and will be removed";
     completer.Reply(fit::error<fuchsia_audio_device::ObserverWatchPlugStateError>(
         fuchsia_audio_device::ObserverWatchPlugStateError::kDeviceError));
@@ -136,14 +133,8 @@
     return;
   }
 
-  if (new_plug_state_to_notify_) {
-    fuchsia_audio_device::ObserverWatchPlugStateResponse response =
-        std::move(*new_plug_state_to_notify_);
-    new_plug_state_to_notify_.reset();
-    completer.Reply(fit::success(response));
-  } else {
-    watch_plug_state_completer_ = completer.ToAsync();
-  }
+  watch_plug_state_completer_ = completer.ToAsync();
+  MaybeCompleteWatchPlugState();
 }
 
 void ObserverServer::PlugStateChanged(const fuchsia_audio_device::PlugState& new_plug_state,
@@ -155,21 +146,25 @@
       .state = new_plug_state,
       .plug_time = plug_change_time.get(),
   }};
+  MaybeCompleteWatchPlugState();
+}
 
-  if (watch_plug_state_completer_) {
+void ObserverServer::MaybeCompleteWatchPlugState() {
+  if (watch_plug_state_completer_ && new_plug_state_to_notify_) {
     auto completer = std::move(*watch_plug_state_completer_);
     watch_plug_state_completer_.reset();
 
-    auto response = std::move(*new_plug_state_to_notify_);
+    auto new_plug_state = std::move(*new_plug_state_to_notify_);
     new_plug_state_to_notify_.reset();
-    completer.Reply(fit::success(response));
+
+    completer.Reply(fit::success(new_plug_state));
   }
 }
 
 void ObserverServer::GetReferenceClock(GetReferenceClockCompleter::Sync& completer) {
   ADR_LOG_METHOD(kLogObserverServerMethods);
 
-  if (has_error_) {
+  if (device_has_error_) {
     ADR_WARN_METHOD() << "Device encountered an error and will be removed";
     completer.Reply(fit::error<fuchsia_audio_device::ObserverGetReferenceClockError>(
         fuchsia_audio_device::ObserverGetReferenceClockError::kDeviceError));
@@ -197,17 +192,187 @@
   completer.Reply(fit::success(std::move(response)));
 }
 
-// For now, don't do anything with this.
+void ObserverServer::GetElements(GetElementsCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogObserverServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Reply(fit::error(ZX_ERR_INTERNAL));
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "This device_type does not support " << __func__;
+    completer.Reply(fit::error(ZX_ERR_WRONG_TYPE));
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_LOG_METHOD(kLogObserverServerMethods) << "This driver does not support signalprocessing";
+    completer.Reply(fit::error(ZX_ERR_NOT_SUPPORTED));
+    return;
+  }
+
+  FX_CHECK(device_->info().has_value() &&
+           device_->info()->signal_processing_elements().has_value() &&
+           !device_->info()->signal_processing_elements()->empty());
+  completer.Reply(fit::success(*device_->info()->signal_processing_elements()));
+}
+
+void ObserverServer::GetTopologies(GetTopologiesCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogObserverServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Reply(fit::error(ZX_ERR_INTERNAL));
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "This device_type does not support " << __func__;
+    completer.Reply(fit::error(ZX_ERR_WRONG_TYPE));
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_LOG_METHOD(kLogObserverServerMethods) << "This driver does not support signalprocessing";
+    completer.Reply(fit::error(ZX_ERR_NOT_SUPPORTED));
+    return;
+  }
+
+  FX_CHECK(device_->info().has_value() &&
+           device_->info()->signal_processing_topologies().has_value() &&
+           !device_->info()->signal_processing_topologies()->empty());
+  completer.Reply(fit::success(*device_->info()->signal_processing_topologies()));
+}
+
+void ObserverServer::WatchTopology(WatchTopologyCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogObserverServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Close(ZX_ERR_INTERNAL);
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "This device_type does not support " << __func__;
+    completer.Close(ZX_ERR_WRONG_TYPE);
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_WARN_METHOD() << "This driver does not support signalprocessing";
+    completer.Close(ZX_ERR_NOT_SUPPORTED);
+    return;
+  }
+
+  if (watch_topology_completer_) {
+    ADR_WARN_METHOD() << "previous `WatchTopology` request has not yet completed";
+    completer.Close(ZX_ERR_BAD_STATE);
+    return;
+  }
+
+  watch_topology_completer_ = completer.ToAsync();
+  MaybeCompleteWatchTopology();
+}
+
 void ObserverServer::TopologyChanged(TopologyId topology_id) {
   ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods)
       << "(topology_id " << topology_id << ")";
+
+  topology_id_to_notify_ = topology_id;
+  MaybeCompleteWatchTopology();
 }
 
-// For now, don't do anything with this.
+void ObserverServer::MaybeCompleteWatchTopology() {
+  // ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods);
+
+  if (watch_topology_completer_.has_value() && topology_id_to_notify_.has_value()) {
+    ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods) << " will Reply";
+
+    auto completer = std::move(*watch_topology_completer_);
+    watch_topology_completer_.reset();
+
+    auto new_topology_id = *topology_id_to_notify_;
+    topology_id_to_notify_.reset();
+
+    completer.Reply(new_topology_id);
+  } else {
+    ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods) << " did not occur";
+  }
+}
+
+void ObserverServer::WatchElementState(WatchElementStateRequest& request,
+                                       WatchElementStateCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogObserverServerMethods);
+
+  if (device_has_error_) {
+    ADR_WARN_METHOD() << "Device has error";
+    completer.Close(ZX_ERR_INTERNAL);
+    return;
+  }
+
+  FX_CHECK(device_);
+  if (!device_->is_codec() && !device_->is_composite() && !device_->is_stream_config()) {
+    ADR_WARN_METHOD() << "This device_type does not support " << __func__;
+    completer.Close(ZX_ERR_WRONG_TYPE);
+    return;
+  }
+
+  if (!device_->supports_signalprocessing()) {
+    ADR_WARN_METHOD() << "This driver does not support signalprocessing";
+    completer.Close(ZX_ERR_NOT_SUPPORTED);
+    return;
+  }
+
+  ElementId element_id = request.processing_element_id();
+  if (device_->element_ids().find(element_id) == device_->element_ids().end()) {
+    ADR_WARN_METHOD() << "unknown element_id " << element_id;
+    completer.Close(ZX_ERR_INVALID_ARGS);
+    return;
+  }
+
+  if (watch_element_state_completers_.find(element_id) != watch_element_state_completers_.end()) {
+    ADR_WARN_METHOD() << "previous `WatchElementState(" << element_id
+                      << ")` request has not yet completed";
+    completer.Close(ZX_ERR_BAD_STATE);
+    return;
+  }
+
+  watch_element_state_completers_.insert({element_id, completer.ToAsync()});
+  MaybeCompleteWatchElementState(element_id);
+}
+
 void ObserverServer::ElementStateChanged(
     ElementId element_id, fuchsia_hardware_audio_signalprocessing::ElementState element_state) {
   ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods)
       << "(element_id " << element_id << ")";
+
+  element_states_to_notify_.insert_or_assign(element_id, element_state);
+  MaybeCompleteWatchElementState(element_id);
+}
+
+// If we have an outstanding hanging-get and a state-change, respond with the state change.
+void ObserverServer::MaybeCompleteWatchElementState(ElementId element_id) {
+  // ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods) << element_id;
+
+  if (watch_element_state_completers_.find(element_id) != watch_element_state_completers_.end() &&
+      element_states_to_notify_.find(element_id) != element_states_to_notify_.end()) {
+    ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods) << element_id << " will Reply";
+    auto completer = std::move(watch_element_state_completers_.find(element_id)->second);
+    watch_element_state_completers_.erase(element_id);
+
+    auto new_element_state = element_states_to_notify_.find(element_id)->second;
+    element_states_to_notify_.erase(element_id);
+
+    completer.Reply(new_element_state);
+  } else {
+    ADR_LOG_METHOD(kLogObserverServerMethods || kLogNotifyMethods) << " did not occur";
+  }
 }
 
 }  // namespace media_audio
diff --git a/src/media/audio/services/device_registry/observer_server.h b/src/media/audio/services/device_registry/observer_server.h
index 7bb6d75..7f15a07 100644
--- a/src/media/audio/services/device_registry/observer_server.h
+++ b/src/media/audio/services/device_registry/observer_server.h
@@ -43,12 +43,17 @@
   void WatchPlugState(WatchPlugStateCompleter::Sync& completer) final;
   void GetReferenceClock(GetReferenceClockCompleter::Sync& completer) final;
 
-  // Stub signal_processing implementation
-  void GetElements(GetElementsCompleter::Sync& completer) final {}
+  // fuchsia.hardware.audio.signal_processing.Reader implementation
+  void GetElements(GetElementsCompleter::Sync& completer) final;
+  void GetTopologies(GetTopologiesCompleter::Sync& completer) final;
   void WatchElementState(WatchElementStateRequest& request,
-                         WatchElementStateCompleter::Sync& completer) final {}
-  void GetTopologies(GetTopologiesCompleter::Sync& completer) final {}
-  void WatchTopology(WatchTopologyCompleter::Sync& completer) final {}
+                         WatchElementStateCompleter::Sync& completer) final;
+  void WatchTopology(WatchTopologyCompleter::Sync& completer) final;
+
+  void MaybeCompleteWatchGainState();
+  void MaybeCompleteWatchPlugState();
+  void MaybeCompleteWatchTopology();
+  void MaybeCompleteWatchElementState(ElementId element_id);
 
   // Static object count, for debugging purposes.
   static inline uint64_t count() { return count_; }
@@ -68,8 +73,14 @@
   std::optional<fuchsia_audio_device::ObserverWatchPlugStateResponse> new_plug_state_to_notify_;
   std::optional<WatchPlugStateCompleter::Async> watch_plug_state_completer_;
 
-  bool has_error_ = false;
+  std::optional<TopologyId> topology_id_to_notify_;
+  std::optional<WatchTopologyCompleter::Async> watch_topology_completer_;
 
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states_to_notify_;
+  std::unordered_map<ElementId, WatchElementStateCompleter::Async> watch_element_state_completers_;
+
+  bool device_has_error_ = false;
   std::shared_ptr<const Device> device_;
 };
 
diff --git a/src/media/audio/services/device_registry/observer_server_unittest.cc b/src/media/audio/services/device_registry/observer_server_unittest.cc
index a0bd8aab..89b16d7 100644
--- a/src/media/audio/services/device_registry/observer_server_unittest.cc
+++ b/src/media/audio/services/device_registry/observer_server_unittest.cc
@@ -5,15 +5,20 @@
 #include "src/media/audio/services/device_registry/observer_server.h"
 
 #include <fidl/fuchsia.audio.device/cpp/fidl.h>
+#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/common_types.h>
+#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
+#include <lib/zx/clock.h>
 #include <zircon/errors.h>
 
 #include <memory>
 #include <optional>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/device_registry/adr_server_unittest_base.h"
+#include "src/media/audio/services/device_registry/basic_types.h"
 #include "src/media/audio/services/device_registry/common_unittest.h"
 #include "src/media/audio/services/device_registry/testing/fake_codec.h"
 #include "src/media/audio/services/device_registry/testing/fake_composite.h"
@@ -101,8 +106,8 @@
     auto fake_driver = std::make_shared<FakeCodec>(
         codec_endpoints.server.TakeChannel(), codec_endpoints.client.TakeChannel(), dispatcher());
 
-    adr_service_->AddDevice(Device::Create(
-        adr_service_, dispatcher(), "Test codec name", fuchsia_audio_device::DeviceType::kCodec,
+    adr_service()->AddDevice(Device::Create(
+        adr_service(), dispatcher(), "Test codec name", fuchsia_audio_device::DeviceType::kCodec,
         fuchsia_audio_device::DriverClient::WithCodec(fake_driver->Enable())));
 
     RunLoopUntilIdle();
@@ -115,8 +120,8 @@
   std::shared_ptr<FakeComposite> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeComposite();
 
-    adr_service_->AddDevice(Device::Create(
-        adr_service_, dispatcher(), "Test composite name",
+    adr_service()->AddDevice(Device::Create(
+        adr_service(), dispatcher(), "Test composite name",
         fuchsia_audio_device::DeviceType::kComposite,
         DriverClient::WithComposite(
             fidl::ClientEnd<fuchsia_hardware_audio::Composite>(fake_driver->Enable()))));
@@ -136,9 +141,9 @@
   std::shared_ptr<FakeStreamConfig> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeStreamConfigOutput();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                           fuchsia_audio_device::DeviceType::kOutput,
-                                           DriverClient::WithStreamConfig(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                            fuchsia_audio_device::DeviceType::kOutput,
+                                            DriverClient::WithStreamConfig(fake_driver->Enable())));
 
     RunLoopUntilIdle();
     return fake_driver;
@@ -151,13 +156,13 @@
 // Verify that an Observer client can drop cleanly (without generating a WARNING or ERROR).
 TEST_F(ObserverServerCodecTest, CleanClientDrop) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto observer = CreateTestObserverServer(*adr_service_->devices().begin());
+  auto observer = CreateTestObserverServer(*adr_service()->devices().begin());
   ASSERT_EQ(ObserverServer::count(), 1u);
 
   (void)observer->client().UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 
   // No WARNING logging should occur during test case shutdown.
 }
@@ -165,14 +170,14 @@
 // Verify that an Observer server can shutdown cleanly (without generating a WARNING or ERROR).
 TEST_F(ObserverServerCodecTest, CleanServerShutdown) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto observer = CreateTestObserverServer(*adr_service_->devices().begin());
+  auto observer = CreateTestObserverServer(*adr_service()->devices().begin());
   ASSERT_EQ(ObserverServer::count(), 1u);
 
   observer->server().Shutdown(ZX_ERR_PEER_CLOSED);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(observer_fidl_error_status_.has_value());
-  EXPECT_EQ(*observer_fidl_error_status_, ZX_ERR_PEER_CLOSED);
+  ASSERT_TRUE(observer_fidl_error_status().has_value());
+  EXPECT_EQ(*observer_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 
   // No WARNING logging should occur during test case shutdown.
 }
@@ -181,8 +186,8 @@
 // directly create an Observer server and client synthetically via CreateTestObserverServer.
 TEST_F(ObserverServerCodecTest, Creation) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
@@ -191,7 +196,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   bool received_callback = false;
 
   registry->client()
@@ -207,22 +212,22 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_TRUE(observer_client.is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that when an observed device is removed, the Observer is dropped.
 TEST_F(ObserverServerCodecTest, ObservedDeviceRemoved) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
 
   fake_driver->DropCodec();
 
@@ -232,8 +237,8 @@
   EXPECT_EQ(*added_device_id, *removed_device_id);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(observer_fidl_error_status_.has_value());
-  EXPECT_EQ(*observer_fidl_error_status_, ZX_ERR_PEER_CLOSED);
+  ASSERT_TRUE(observer_fidl_error_status().has_value());
+  EXPECT_EQ(*observer_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Verify that the Observer receives the initial plug state of the observed device.
@@ -244,21 +249,21 @@
   fake_driver->InjectUnpluggedAt(initial_plug_time);
 
   RunLoopUntilIdle();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
   bool received_callback = false;
   zx::time reported_plug_time = zx::time::infinite_past();
 
@@ -277,22 +282,22 @@
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(initial_plug_time.get(), reported_plug_time.get());
   EXPECT_EQ(ObserverServer::count(), 1u);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that the Observer receives changes in the plug state of the observed device.
 TEST_F(ObserverServerCodecTest, PlugChange) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
   auto time_after_device_added = zx::clock::get_monotonic();
   zx::time received_plug_time;
   bool received_callback = false;
@@ -330,7 +335,7 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(received_plug_time.get(), time_of_plug_change.get());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that an Observer does not drop, if the observed device's Control client is dropped.
@@ -340,13 +345,13 @@
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
 
   {
     auto received_callback = false;
-    auto control = CreateTestControlServer(added_device);
+    auto control = CreateTestControlServer(device);
     control->client()->Reset().Then([&received_callback](fidl::Result<Control::Reset>& result) {
       received_callback = true;
       EXPECT_TRUE(result.is_ok()) << result.error_value();
@@ -359,12 +364,70 @@
   RunLoopUntilIdle();
   EXPECT_EQ(ObserverServer::count(), 1u);
   EXPECT_TRUE(observer->client().is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
-// Add test cases for WatchTopology and WatchElementState (once implemented)
-//
-// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain).
+// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain),
+// including in the FakeCodec test fixture. Then add positive test cases for
+// GetTopologies/GetElements/WatchTopology/WatchElementState, as are in Composite.
+
+// Verify GetTopologies if the driver does not support signalprocessing.
+TEST_F(ObserverServerCodecTest, GetTopologiesUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback = false;
+
+  observer->client()->GetTopologies().Then([&received_callback](
+                                               fidl::Result<Observer::GetTopologies>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+}
+
+// Verify GetElements if the driver does not support signalprocessing.
+TEST_F(ObserverServerCodecTest, GetElementsUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback = false;
+
+  observer->client()->GetElements().Then([&received_callback](
+                                             fidl::Result<Observer::GetElements>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+}
 
 /////////////////////
 // Composite tests
@@ -372,13 +435,13 @@
 // Verify that an Observer client can drop cleanly (without generating a WARNING or ERROR).
 TEST_F(ObserverServerCompositeTest, CleanClientDrop) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto observer = CreateTestObserverServer(*adr_service_->devices().begin());
+  auto observer = CreateTestObserverServer(*adr_service()->devices().begin());
   ASSERT_EQ(ObserverServer::count(), 1u);
 
   (void)observer->client().UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 
   // No WARNING logging should occur during test case shutdown.
 }
@@ -386,14 +449,14 @@
 // Verify that an Observer server can shutdown cleanly (without generating a WARNING or ERROR).
 TEST_F(ObserverServerCompositeTest, CleanServerShutdown) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto observer = CreateTestObserverServer(*adr_service_->devices().begin());
+  auto observer = CreateTestObserverServer(*adr_service()->devices().begin());
   ASSERT_EQ(ObserverServer::count(), 1u);
 
   observer->server().Shutdown(ZX_ERR_PEER_CLOSED);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(observer_fidl_error_status_.has_value());
-  EXPECT_EQ(*observer_fidl_error_status_, ZX_ERR_PEER_CLOSED);
+  ASSERT_TRUE(observer_fidl_error_status().has_value());
+  EXPECT_EQ(*observer_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 
   // No WARNING logging should occur during test case shutdown.
 }
@@ -402,8 +465,8 @@
 // directly create an Observer server and client synthetically via CreateTestObserverServer.
 TEST_F(ObserverServerCompositeTest, Creation) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
@@ -412,7 +475,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   bool received_callback = false;
 
   registry->client()
@@ -428,22 +491,22 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_TRUE(observer_client.is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that when an observed device is removed, the Observer is dropped.
 TEST_F(ObserverServerCompositeTest, ObservedDeviceRemoved) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
 
   fake_driver->DropComposite();
 
@@ -452,23 +515,23 @@
   EXPECT_EQ(*added_device_id, *removed_device_id);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(observer_fidl_error_status_.has_value());
-  EXPECT_EQ(*observer_fidl_error_status_, ZX_ERR_PEER_CLOSED);
+  ASSERT_TRUE(observer_fidl_error_status().has_value());
+  EXPECT_EQ(*observer_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Verify that the Observer receives the observed device's reference clock, and that it is valid.
 TEST_F(ObserverServerCompositeTest, GetReferenceClock) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
   bool received_callback = false;
 
   observer->client()->GetReferenceClock().Then(
@@ -482,7 +545,7 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that an Observer does not drop, if an observed device's driver RingBuffer is dropped.
@@ -492,14 +555,14 @@
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto control = CreateTestControlServer(added_device);
-  auto observer = CreateTestObserverServer(added_device);
+  auto control = CreateTestControlServer(device);
+  auto observer = CreateTestObserverServer(device);
 
-  auto ring_buffer_element_id = *added_device->ring_buffer_endpoint_ids().begin();
+  auto ring_buffer_element_id = *device->ring_buffer_endpoint_ids().begin();
   auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
-      ring_buffer_element_id, added_device->ring_buffer_format_sets());
+      ring_buffer_element_id, device->ring_buffer_format_sets());
   fake_driver->ReserveRingBufferSize(ring_buffer_element_id, 8192);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
   bool received_callback = false;
@@ -523,7 +586,7 @@
   RunLoopUntilIdle();
   EXPECT_EQ(ObserverServer::count(), 1u);
   EXPECT_TRUE(observer->client().is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that an Observer does not drop, if an observed device's RingBuffer client is dropped.
@@ -533,14 +596,14 @@
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto control = CreateTestControlServer(added_device);
-  auto observer = CreateTestObserverServer(added_device);
+  auto control = CreateTestControlServer(device);
+  auto observer = CreateTestObserverServer(device);
 
-  auto ring_buffer_element_id = *added_device->ring_buffer_endpoint_ids().begin();
+  auto ring_buffer_element_id = *device->ring_buffer_endpoint_ids().begin();
   auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
-      ring_buffer_element_id, added_device->ring_buffer_format_sets());
+      ring_buffer_element_id, device->ring_buffer_format_sets());
   fake_driver->ReserveRingBufferSize(ring_buffer_element_id, 8192);
   {
     auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -564,7 +627,7 @@
   RunLoopUntilIdle();
   EXPECT_EQ(ObserverServer::count(), 1u);
   EXPECT_TRUE(observer->client().is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that an Observer does not drop, if the observed device's Control client is dropped.
@@ -574,12 +637,12 @@
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
 
   {
-    auto control = CreateTestControlServer(added_device);
+    auto control = CreateTestControlServer(device);
     bool received_callback = false;
 
     control->client()->Reset().Then([&received_callback](fidl::Result<Control::Reset>& result) {
@@ -594,7 +657,421 @@
   RunLoopUntilIdle();
   EXPECT_EQ(ObserverServer::count(), 1u);
   EXPECT_TRUE(observer->client().is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
+}
+
+// Retrieves the static list of Topologies and their properties.
+// Compare results from Observer/GetTopologies to the topologies returned in the Device info.
+TEST_F(ObserverServerCompositeTest, GetTopologies) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto initial_topologies = device->info()->signal_processing_topologies();
+  ASSERT_TRUE(initial_topologies.has_value() && !initial_topologies->empty());
+
+  auto observer = CreateTestObserverServer(device);
+  auto received_callback = false;
+  std::vector<::fuchsia_hardware_audio_signalprocessing::Topology> received_topologies;
+
+  observer->client()->GetTopologies().Then(
+      [&received_callback, &received_topologies](fidl::Result<Observer::GetTopologies>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        received_topologies = result->topologies();
+        EXPECT_FALSE(received_topologies.empty());
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_EQ(initial_topologies->size(), received_topologies.size());
+  EXPECT_THAT(received_topologies, testing::ElementsAreArray(*initial_topologies));
+}
+
+// Retrieves the static list of Elements and their properties.
+// Compare results from Observer/GetElements to the elements returned in the Device info.
+TEST_F(ObserverServerCompositeTest, GetElements) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto initial_elements = device->info()->signal_processing_elements();
+  ASSERT_TRUE(initial_elements.has_value() && !initial_elements->empty());
+
+  auto observer = CreateTestObserverServer(device);
+  auto received_callback = false;
+  std::vector<::fuchsia_hardware_audio_signalprocessing::Element> received_elements;
+
+  observer->client()->GetElements().Then(
+      [&received_callback, &received_elements](fidl::Result<Observer::GetElements>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        received_elements = result->processing_elements();
+        EXPECT_FALSE(received_elements.empty());
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_EQ(initial_elements->size(), received_elements.size());
+  EXPECT_THAT(received_elements, testing::ElementsAreArray(*initial_elements));
+}
+
+// Verify that WatchTopology correctly returns the initial topology state.
+TEST_F(ObserverServerCompositeTest, WatchTopologyInitial) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto observer = CreateTestObserverServer(device);
+  auto received_callback = false;
+  std::optional<TopologyId> topology_id;
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_TRUE(topology_id.has_value());
+  EXPECT_FALSE(topology_map(device).find(*topology_id) == topology_map(device).end());
+}
+
+// Verify that WatchTopology pends when called a second time (if no change).
+TEST_F(ObserverServerCompositeTest, WatchTopologyNoChange) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto observer = CreateTestObserverServer(device);
+  auto received_callback = false;
+  std::optional<TopologyId> topology_id;
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(topology_id.has_value());
+  received_callback = false;
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+}
+
+// Verify that WatchTopology works with dynamic changes, after initial query.
+TEST_F(ObserverServerCompositeTest, WatchTopologyUpdate) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto observer = CreateTestObserverServer(device);
+  auto received_callback = false;
+  std::optional<TopologyId> topology_id;
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(topology_id.has_value());
+  ASSERT_FALSE(topology_map(device).find(*topology_id) == topology_map(device).end());
+  std::optional<TopologyId> topology_id_to_inject;
+  for (const auto& [id, _] : topology_map(device)) {
+    if (id != *topology_id) {
+      topology_id_to_inject = id;
+      break;
+    }
+  }
+  if (!topology_id_to_inject.has_value()) {
+    GTEST_SKIP() << "Fake driver does not expose multiple topologies";
+  }
+  received_callback = false;
+  topology_id.reset();
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback, &topology_id](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        topology_id = result->topology_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+
+  fake_driver->InjectTopologyChange(topology_id_to_inject);
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(topology_id.has_value());
+  EXPECT_FALSE(topology_map(device).find(*topology_id) == topology_map(device).end());
+  EXPECT_EQ(*topology_id, *topology_id_to_inject);
+}
+
+// Verify that WatchElementState correctly returns the initial states of all elements.
+TEST_F(ObserverServerCompositeTest, WatchElementStateInitial) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto observer = CreateTestObserverServer(device);
+  auto& elements_from_device = element_map(device);
+  auto received_callback = false;
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states;
+
+  // Gather the complete set of initial element states.
+  for (auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    observer->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id,
+               &element_states](fidl::Result<Observer::WatchElementState>& result) {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          element_states.insert_or_assign(element_id, result->state());
+        });
+
+    RunLoopUntilIdle();
+    EXPECT_TRUE(received_callback);
+  }
+
+  // Compare them to the collection held by the Device object.
+  EXPECT_EQ(element_states.size(), elements_from_device.size());
+  for (const auto& [element_id, element_record] : elements_from_device) {
+    ASSERT_FALSE(element_states.find(element_id) == element_states.end())
+        << "WatchElementState response not received for element_id " << element_id;
+    const auto& state_from_device = element_record.state;
+    ASSERT_TRUE(state_from_device.has_value())
+        << "Device element_map did not contain ElementState for element_id ";
+    EXPECT_EQ(element_states.find(element_id)->second, state_from_device);
+  }
+}
+
+// Verify that WatchElementState pends indefinitely, if there has been no change.
+TEST_F(ObserverServerCompositeTest, WatchElementStateNoChange) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto observer = CreateTestObserverServer(device);
+  auto& elements_from_device = element_map(device);
+  auto received_callback = false;
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states;
+
+  // Gather the complete set of initial element states.
+  for (auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    observer->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id,
+               &element_states](fidl::Result<Observer::WatchElementState>& result) {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          element_states.insert_or_assign(element_id, result->state());
+        });
+
+    // We wait for each WatchElementState in turn.
+    RunLoopUntilIdle();
+    EXPECT_TRUE(received_callback);
+    received_callback = false;
+  }
+
+  for (auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    observer->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id](fidl::Result<Observer::WatchElementState>& result) {
+          received_callback = true;
+          FAIL() << "Unexpected WatchElementState completion for element_id " << element_id;
+        });
+  }
+
+  // We request all the states from the Elements again, then wait once.
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+}
+
+// Verify that WatchElementState works with dynamic changes, after initial query.
+TEST_F(ObserverServerCompositeTest, WatchElementStateUpdate) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+
+  auto observer = CreateTestObserverServer(device);
+  auto& elements_from_device = element_map(device);
+  auto received_callback = false;
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states;
+
+  // Gather the complete set of initial element states.
+  for (auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    observer->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id,
+               &element_states](fidl::Result<Observer::WatchElementState>& result) {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          element_states.insert_or_assign(element_id, result->state());
+        });
+
+    RunLoopUntilIdle();
+    EXPECT_TRUE(received_callback);
+  }
+
+  // Determine which states we can change.
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states_to_inject;
+  auto plug_change_time_to_inject = zx::clock::get_monotonic();
+  for (const auto& element_map_entry : elements_from_device) {
+    auto element_id = element_map_entry.first;
+    const auto& element = element_map_entry.second.element;
+    const auto& state = element_map_entry.second.state;
+    if (element.type() != fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint ||
+        !element.type_specific().has_value() || !element.type_specific()->endpoint().has_value() ||
+        element.type_specific()->endpoint()->plug_detect_capabilities() !=
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kCanAsyncNotify) {
+      continue;
+    }
+    if (!state.has_value() || !state->type_specific().has_value() ||
+        !state->type_specific()->endpoint().has_value() ||
+        !state->type_specific()->endpoint()->plug_state().has_value() ||
+        !state->type_specific()->endpoint()->plug_state()->plugged().has_value() ||
+        !state->type_specific()->endpoint()->plug_state()->plug_state_time().has_value()) {
+      continue;
+    }
+    auto was_plugged = state->type_specific()->endpoint()->plug_state()->plugged();
+    auto new_state = fuchsia_hardware_audio_signalprocessing::ElementState{{
+        .type_specific =
+            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::WithEndpoint(
+                fuchsia_hardware_audio_signalprocessing::EndpointElementState{{
+                    fuchsia_hardware_audio_signalprocessing::PlugState{{
+                        !was_plugged,
+                        plug_change_time_to_inject.get(),
+                    }},
+                }}),
+        .enabled = true,
+        .latency =
+            fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyTime(ZX_USEC(element_id)),
+        .vendor_specific_data = {{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
+                                  'D', 'E', 'F', 'Z'}},  // 'Z' is located at byte [16].
+    }};
+    ASSERT_EQ(new_state.vendor_specific_data()->size(), 17u) << "Test configuration error";
+    element_states_to_inject.insert_or_assign(element_id, new_state);
+  }
+
+  if (element_states_to_inject.empty()) {
+    GTEST_SKIP()
+        << "No element states can be changed, so dynamic element_state change cannot be tested";
+  }
+
+  std::unordered_map<ElementId, fuchsia_hardware_audio_signalprocessing::ElementState>
+      element_states_received;
+
+  // Inject the changes.
+  for (const auto& element_state_entry : element_states_to_inject) {
+    auto& element_id = element_state_entry.first;
+    auto& element_state = element_state_entry.second;
+    fake_driver->InjectElementStateChange(element_id, element_state);
+    received_callback = false;
+
+    observer->client()
+        ->WatchElementState(element_id)
+        .Then([&received_callback, element_id,
+               &element_states_received](fidl::Result<Observer::WatchElementState>& result) {
+          received_callback = true;
+          ASSERT_TRUE(result.is_ok()) << result.error_value();
+          element_states_received.insert_or_assign(element_id, result->state());
+        });
+
+    RunLoopUntilIdle();
+    EXPECT_TRUE(received_callback);
+  }
+
+  EXPECT_EQ(element_states_to_inject.size(), element_states_received.size());
+  for (const auto& [element_id, state_received] : element_states_received) {
+    // Compare to actual static values we know.
+    ASSERT_TRUE(state_received.type_specific().has_value());
+    ASSERT_TRUE(state_received.type_specific()->endpoint().has_value());
+    ASSERT_TRUE(state_received.type_specific()->endpoint()->plug_state().has_value());
+    ASSERT_TRUE(state_received.type_specific()->endpoint()->plug_state()->plugged().has_value());
+    ASSERT_TRUE(
+        state_received.type_specific()->endpoint()->plug_state()->plug_state_time().has_value());
+    EXPECT_EQ(*state_received.type_specific()->endpoint()->plug_state()->plug_state_time(),
+              plug_change_time_to_inject.get());
+
+    ASSERT_TRUE(state_received.enabled().has_value());
+    EXPECT_EQ(state_received.enabled(), true);
+
+    ASSERT_TRUE(state_received.latency().has_value());
+    ASSERT_EQ(state_received.latency()->Which(),
+              fuchsia_hardware_audio_signalprocessing::Latency::Tag::kLatencyTime);
+    EXPECT_EQ(state_received.latency()->latency_time().value(), ZX_USEC(element_id));
+
+    ASSERT_TRUE(state_received.vendor_specific_data().has_value());
+    ASSERT_EQ(state_received.vendor_specific_data()->size(), 17u);
+    EXPECT_EQ(state_received.vendor_specific_data()->at(16), 'Z');
+
+    // Compare to what we injected.
+    ASSERT_FALSE(element_states_to_inject.find(element_id) == element_states_to_inject.end())
+        << "Unexpected WatchElementState response received for element_id " << element_id;
+    const auto& state_injected = element_states_to_inject.find(element_id)->second;
+    EXPECT_EQ(state_received, state_injected);
+
+    // Compare the updates received by the client to the collection held by the Device object.
+    ASSERT_FALSE(elements_from_device.find(element_id) == elements_from_device.end());
+    const auto& state_from_device = elements_from_device.find(element_id)->second.state;
+    EXPECT_EQ(state_received, state_from_device);
+  }
 }
 
 /////////////////////
@@ -603,13 +1080,13 @@
 // Verify that an Observer client can drop cleanly (without generating a WARNING or ERROR).
 TEST_F(ObserverServerStreamConfigTest, CleanClientDrop) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto observer = CreateTestObserverServer(*adr_service_->devices().begin());
+  auto observer = CreateTestObserverServer(*adr_service()->devices().begin());
   ASSERT_EQ(ObserverServer::count(), 1u);
 
   (void)observer->client().UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 
   // No WARNING logging should occur during test case shutdown.
 }
@@ -617,14 +1094,14 @@
 // Verify that an Observer server can shutdown cleanly (without generating a WARNING or ERROR).
 TEST_F(ObserverServerStreamConfigTest, CleanServerShutdown) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  auto observer = CreateTestObserverServer(*adr_service_->devices().begin());
+  auto observer = CreateTestObserverServer(*adr_service()->devices().begin());
   ASSERT_EQ(ObserverServer::count(), 1u);
 
   observer->server().Shutdown(ZX_ERR_PEER_CLOSED);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(observer_fidl_error_status_.has_value());
-  EXPECT_EQ(*observer_fidl_error_status_, ZX_ERR_PEER_CLOSED);
+  ASSERT_TRUE(observer_fidl_error_status().has_value());
+  EXPECT_EQ(*observer_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 
   // No WARNING logging should occur during test case shutdown.
 }
@@ -633,8 +1110,8 @@
 // directly create an Observer server and client synthetically via CreateTestObserverServer.
 TEST_F(ObserverServerStreamConfigTest, Creation) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
@@ -643,7 +1120,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   bool received_callback = false;
 
   registry->client()
@@ -659,22 +1136,22 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_TRUE(observer_client.is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that when an observed device is removed, the Observer is dropped.
 TEST_F(ObserverServerStreamConfigTest, ObservedDeviceRemoved) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
 
   fake_driver->DropStreamConfig();
 
@@ -683,8 +1160,8 @@
   EXPECT_EQ(*added_device_id, *removed_device_id);
 
   RunLoopUntilIdle();
-  EXPECT_TRUE(observer_fidl_error_status_.has_value());
-  EXPECT_EQ(*observer_fidl_error_status_, ZX_ERR_PEER_CLOSED);
+  ASSERT_TRUE(observer_fidl_error_status().has_value());
+  EXPECT_EQ(*observer_fidl_error_status(), ZX_ERR_PEER_CLOSED);
 }
 
 // Verify that the Observer receives the initial gain state of the observed device.
@@ -698,21 +1175,21 @@
   }});
 
   RunLoopUntilIdle();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
   bool received_callback = false;
 
   observer->client()->WatchGainState().Then(
@@ -728,22 +1205,22 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that the Observer receives changes in the gain state of the observed device.
 TEST_F(ObserverServerStreamConfigTest, GainChange) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
   bool received_callback = false;
 
   observer->client()->WatchGainState().Then(
@@ -783,7 +1260,7 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that the Observer receives the initial plug state of the observed device.
@@ -793,21 +1270,21 @@
   fake_driver->InjectUnpluggedAt(initial_plug_time);
 
   RunLoopUntilIdle();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
   bool received_callback = false;
 
   observer->client()->WatchPlugState().Then(
@@ -822,23 +1299,23 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that the Observer receives changes in the plug state of the observed device.
 TEST_F(ObserverServerStreamConfigTest, PlugChange) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
   auto time_of_plug_change = zx::clock::get_monotonic();
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
   bool received_callback = false;
 
   observer->client()->WatchPlugState().Then(
@@ -871,22 +1348,22 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that the Observer receives the observed device's reference clock, and that it is valid.
 TEST_F(ObserverServerStreamConfigTest, GetReferenceClock) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
   bool received_callback = false;
 
   observer->client()->GetReferenceClock().Then(
@@ -900,7 +1377,7 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that an Observer does not drop, if the observed device's driver RingBuffer is dropped.
@@ -911,10 +1388,10 @@
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto control = CreateTestControlServer(added_device);
-  auto observer = CreateTestObserverServer(added_device);
+  auto control = CreateTestControlServer(device);
+  auto observer = CreateTestObserverServer(device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
   bool received_callback = false;
 
@@ -936,7 +1413,7 @@
   RunLoopUntilIdle();
   EXPECT_EQ(ObserverServer::count(), 1u);
   EXPECT_TRUE(observer->client().is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that an Observer does not drop, if the observed device's RingBuffer client is dropped.
@@ -947,10 +1424,10 @@
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto control = CreateTestControlServer(added_device);
-  auto observer = CreateTestObserverServer(added_device);
+  auto control = CreateTestControlServer(device);
+  auto observer = CreateTestObserverServer(device);
 
   {
     auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -974,7 +1451,7 @@
   RunLoopUntilIdle();
   EXPECT_EQ(ObserverServer::count(), 1u);
   EXPECT_TRUE(observer->client().is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that an Observer does not drop, if the observed device's Control client is dropped.
@@ -985,12 +1462,12 @@
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-  auto observer = CreateTestObserverServer(added_device);
+  auto observer = CreateTestObserverServer(device);
 
   {
-    auto control = CreateTestControlServer(added_device);
+    auto control = CreateTestControlServer(device);
     auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
     bool received_callback = false;
 
@@ -1014,11 +1491,69 @@
   RunLoopUntilIdle();
   EXPECT_EQ(ObserverServer::count(), 1u);
   EXPECT_TRUE(observer->client().is_valid());
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
-// Add StreamConfig test cases for WatchTopology and WatchElementState (once implemented)
-//
-// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain).
+// TODO(https://fxbug.dev/323270827): implement signalprocessing, including in the FakeStreamConfig
+// test fixture. Then add positive test cases for
+// GetTopologies/GetElements/WatchTopology/WatchElementState, as are in Composite.
+
+// Verify GetTopologies if the driver does not support signalprocessing.
+TEST_F(ObserverServerStreamConfigTest, GetTopologiesUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback = false;
+
+  observer->client()->GetTopologies().Then([&received_callback](
+                                               fidl::Result<Observer::GetTopologies>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+}
+
+// Verify GetElements if the driver does not support signalprocessing.
+TEST_F(ObserverServerStreamConfigTest, GetElementsUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback = false;
+
+  observer->client()->GetElements().Then([&received_callback](
+                                             fidl::Result<Observer::GetElements>& result) {
+    received_callback = true;
+    ASSERT_TRUE(result.is_error());
+    ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value().framework_error();
+    EXPECT_EQ(result.error_value().domain_error(), ZX_ERR_NOT_SUPPORTED);
+  });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+}
 
 }  // namespace media_audio
diff --git a/src/media/audio/services/device_registry/observer_server_warning_unittest.cc b/src/media/audio/services/device_registry/observer_server_warning_unittest.cc
index 2f52946..0a2bf02 100644
--- a/src/media/audio/services/device_registry/observer_server_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/observer_server_warning_unittest.cc
@@ -4,7 +4,6 @@
 
 #include <fidl/fuchsia.audio.device/cpp/common_types.h>
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <zircon/errors.h>
 
 #include <memory>
@@ -21,9 +20,10 @@
 namespace media_audio {
 
 using DriverClient = fuchsia_audio_device::DriverClient;
+using Observer = fuchsia_audio_device::Observer;
 
 class ObserverServerWarningTest : public AudioDeviceRegistryServerTestBase,
-                                  public fidl::AsyncEventHandler<fuchsia_audio_device::Observer> {
+                                  public fidl::AsyncEventHandler<Observer> {
  protected:
   std::optional<TokenId> WaitForAddedDeviceTokenId(
       fidl::Client<fuchsia_audio_device::Registry>& registry_client) {
@@ -47,9 +47,9 @@
   std::shared_ptr<FakeCodec> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeCodecNoDirection();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                           fuchsia_audio_device::DeviceType::kCodec,
-                                           DriverClient::WithCodec(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                            fuchsia_audio_device::DeviceType::kCodec,
+                                            DriverClient::WithCodec(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -60,9 +60,9 @@
   std::shared_ptr<FakeComposite> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeComposite();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test composite name",
-                                           fuchsia_audio_device::DeviceType::kComposite,
-                                           DriverClient::WithComposite(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                            fuchsia_audio_device::DeviceType::kComposite,
+                                            DriverClient::WithComposite(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -73,9 +73,9 @@
   std::shared_ptr<FakeStreamConfig> CreateAndEnableDriverWithDefaults() {
     auto fake_driver = CreateFakeStreamConfigOutput();
 
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                           fuchsia_audio_device::DeviceType::kOutput,
-                                           DriverClient::WithStreamConfig(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                            fuchsia_audio_device::DeviceType::kOutput,
+                                            DriverClient::WithStreamConfig(fake_driver->Enable())));
     RunLoopUntilIdle();
     return fake_driver;
   }
@@ -87,22 +87,21 @@
 // Codec: WatchGainState is unsupported
 TEST_F(ObserverServerCodecWarningTest, WatchGainStateWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto observer = CreateTestObserverServer(added_device);
   ASSERT_EQ(ObserverServer::count(), 1u);
   bool received_callback = false;
 
   observer->client()->WatchGainState().Then(
-      [&received_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchGainState>& result) mutable {
+      [&received_callback](fidl::Result<Observer::WatchGainState>& result) mutable {
         received_callback = true;
         ASSERT_TRUE(result.is_error());
         ASSERT_TRUE(result.error_value().is_domain_error())
@@ -115,39 +114,37 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ObserverServer::count(), 1u);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // While `WatchPlugState` is pending, calling this again is an error (but non-fatal).
 TEST_F(ObserverServerCodecWarningTest, WatchPlugStateWhilePending) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   // We'll always receive an immediate response from the first `WatchPlugState` call.
   auto observer = CreateTestObserverServer(added_device);
   bool received_initial_callback = false;
   observer->client()->WatchPlugState().Then(
-      [&received_initial_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchPlugState>& result) mutable {
+      [&received_initial_callback](fidl::Result<Observer::WatchPlugState>& result) mutable {
         received_initial_callback = true;
         EXPECT_TRUE(result.is_ok()) << result.error_value();
       });
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_initial_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
   bool received_second_callback = false;
   // The second `WatchPlugState` call should pend indefinitely (even after the third one fails).
   observer->client()->WatchPlugState().Then(
-      [&received_second_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchPlugState>& result) mutable {
+      [&received_second_callback](fidl::Result<Observer::WatchPlugState>& result) mutable {
         received_second_callback = true;
         FAIL() << "Unexpected completion for pending WatchPlugState call";
       });
@@ -158,8 +155,7 @@
   // This third `WatchPlugState` call should fail immediately (domain error ALREADY_PENDING)
   // since the second call has not yet completed.
   observer->client()->WatchPlugState().Then(
-      [&received_third_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchPlugState>& result) mutable {
+      [&received_third_callback](fidl::Result<Observer::WatchPlugState>& result) mutable {
         received_third_callback = true;
         ASSERT_TRUE(result.is_error());
         ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
@@ -173,28 +169,27 @@
   EXPECT_FALSE(received_second_callback);
   EXPECT_TRUE(received_third_callback);
   EXPECT_EQ(ObserverServer::count(), 1u);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Codec: GetReferenceClock is unsupported
 TEST_F(ObserverServerCodecWarningTest, GetReferenceClockWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto observer = CreateTestObserverServer(added_device);
   ASSERT_EQ(ObserverServer::count(), 1u);
   bool received_callback = false;
 
   observer->client()->GetReferenceClock().Then(
-      [&received_callback](
-          fidl::Result<fuchsia_audio_device::Observer::GetReferenceClock>& result) mutable {
+      [&received_callback](fidl::Result<Observer::GetReferenceClock>& result) mutable {
         received_callback = true;
         ASSERT_TRUE(result.is_error());
         ASSERT_TRUE(result.error_value().is_domain_error())
@@ -207,11 +202,97 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ObserverServer::count(), 1u);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
-// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain).
-// Add Codec negative test cases for WatchTopology and WatchElementState (once implemented)
+// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain),
+// including in the FakeCodec test fixture. Then add negative test cases for
+// GetTopologies/GetElements/WatchTopology/WatchElementState, as are in Composite.
+
+// Verify WatchTopology if the driver does not support signalprocessing.
+TEST_F(ObserverServerCodecWarningTest, WatchTopologyUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback = false;
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  received_callback = false;
+
+  // After this failing call, the binding should not be usable.
+  observer->client()->WatchPlugState().Then(
+      [&received_callback](fidl::Result<Observer::WatchPlugState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error());
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_TRUE(observer->client().is_valid());
+}
+
+// Verify WatchElementState if the driver does not support signalprocessing.
+TEST_F(ObserverServerCodecWarningTest, WatchElementStateUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback = false;
+
+  observer->client()
+      ->WatchElementState(fuchsia_audio_device::kDefaultDaiInterconnectElementId)
+      .Then([&received_callback](fidl::Result<Observer::WatchElementState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  received_callback = false;
+
+  // After this failing call, the binding should not be usable.
+  observer->client()->WatchPlugState().Then(
+      [&received_callback](fidl::Result<Observer::WatchPlugState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error());
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_TRUE(observer->client().is_valid());
+}
 
 /////////////////////
 // Composite tests
@@ -219,22 +300,21 @@
 // Verify that the Observer cannot handle a WatchGainState request from this type of device.
 TEST_F(ObserverServerCompositeWarningTest, WatchGainStateWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto observer = CreateTestObserverServer(added_device);
   ASSERT_EQ(ObserverServer::count(), 1u);
   bool received_callback = false;
 
   observer->client()->WatchGainState().Then(
-      [&received_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchGainState>& result) mutable {
+      [&received_callback](fidl::Result<Observer::WatchGainState>& result) mutable {
         received_callback = true;
         ASSERT_TRUE(result.is_error());
         ASSERT_TRUE(result.error_value().is_domain_error())
@@ -247,28 +327,27 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ObserverServer::count(), 1u);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // Verify that the Observer cannot handle a WatchPlugState request from this type of device.
 TEST_F(ObserverServerCompositeWarningTest, WatchPlugStateWrongDeviceType) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto observer = CreateTestObserverServer(added_device);
   ASSERT_EQ(ObserverServer::count(), 1u);
   bool received_callback = false;
 
   observer->client()->WatchPlugState().Then(
-      [&received_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchPlugState>& result) mutable {
+      [&received_callback](fidl::Result<Observer::WatchPlugState>& result) mutable {
         received_callback = true;
         ASSERT_TRUE(result.is_error());
         ASSERT_TRUE(result.error_value().is_domain_error())
@@ -281,7 +360,176 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ObserverServer::count(), 1u);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
+}
+
+// WatchTopology cases (without using SetTopology): Watch-while-pending
+TEST_F(ObserverServerCompositeWarningTest, WatchTopologyWhilePending) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback1 = false, received_callback2 = false;
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback1](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback1 = true;
+        EXPECT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback1);
+  received_callback1 = false;
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback1](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback1 = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_BAD_STATE);
+        // EXPECT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback1);
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback2](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback2 = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_BAD_STATE);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback2);
+  // After a failing WatchTopology call, the binding should not be usable, so the previous
+  // WatchElementState will complete with a failure.
+  EXPECT_TRUE(received_callback1);
+}
+
+// WatchElementState cases (without SetElementState): unknown ElementId, Watch-while-pending
+TEST_F(ObserverServerCompositeWarningTest, WatchElementStateUnknownElementId) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto& elements_from_device = element_map(device);
+  ElementId unknown_element_id = 0;
+  while (true) {
+    if (elements_from_device.find(unknown_element_id) == elements_from_device.end()) {
+      break;
+    }
+    ++unknown_element_id;
+  }
+  auto received_callback = false;
+
+  observer->client()
+      ->WatchElementState(unknown_element_id)
+      .Then([&received_callback](fidl::Result<Observer::WatchElementState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_INVALID_ARGS);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+
+  // After a failing WatchElementState call, the binding should not be usable.
+  observer->client()->GetReferenceClock().Then(
+      [&received_callback](fidl::Result<Observer::GetReferenceClock>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error());
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_INVALID_ARGS);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_TRUE(observer->client().is_valid());
+}
+
+TEST_F(ObserverServerCompositeWarningTest, WatchElementStateWhilePending) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto& elements_from_device = element_map(device);
+
+  auto element_id = elements_from_device.begin()->first;
+  auto received_callback1 = false, received_callback2 = false;
+
+  observer->client()
+      ->WatchElementState(element_id)
+      .Then([&received_callback1](fidl::Result<Observer::WatchElementState>& result) {
+        received_callback1 = true;
+        EXPECT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback1);
+  received_callback1 = false;
+
+  observer->client()
+      ->WatchElementState(element_id)
+      .Then([&received_callback1](fidl::Result<Observer::WatchElementState>& result) {
+        received_callback1 = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_BAD_STATE) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback1);
+
+  observer->client()
+      ->WatchElementState(element_id)
+      .Then([&received_callback2](fidl::Result<Observer::WatchElementState>& result) {
+        received_callback2 = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_BAD_STATE) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback2);
+  // After a failing WatchElementState call, the binding should not be usable, so the previous
+  // WatchElementState will complete with a failure.
+  EXPECT_TRUE(received_callback1);
+  received_callback1 = false;
+
+  observer->client()->GetReferenceClock().Then(
+      [&received_callback1](fidl::Result<Observer::GetReferenceClock>& result) {
+        received_callback1 = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_BAD_STATE)
+            << result.error_value().framework_error();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback1);
+  EXPECT_TRUE(observer->client().is_valid());
 }
 
 /////////////////////
@@ -290,34 +538,32 @@
 // A subsequent call to WatchGainState before the previous one completes should fail.
 TEST_F(ObserverServerStreamConfigWarningTest, WatchGainStateWhilePending) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   // We'll always receive an immediate response from the first `WatchGainState` call.
   auto observer = CreateTestObserverServer(added_device);
   bool received_initial_callback = false;
   observer->client()->WatchGainState().Then(
-      [&received_initial_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchGainState>& result) mutable {
+      [&received_initial_callback](fidl::Result<Observer::WatchGainState>& result) mutable {
         received_initial_callback = true;
         EXPECT_TRUE(result.is_ok()) << result.error_value();
       });
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_initial_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
-  // EXPECT_EQ(observer_fidl_error_status_.value_or(ZX_OK), ZX_OK);
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
+  // EXPECT_EQ(observer_fidl_error_status().value_or(ZX_OK), ZX_OK);
   bool received_second_callback = false;
   // The second `WatchGainState` call should pend indefinitely (even after the third one fails).
   observer->client()->WatchGainState().Then(
-      [&received_second_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchGainState>& result) mutable {
+      [&received_second_callback](fidl::Result<Observer::WatchGainState>& result) mutable {
         received_second_callback = true;
         FAIL() << "Unexpected completion for pending WatchGainState call";
       });
@@ -328,8 +574,7 @@
   EXPECT_FALSE(received_second_callback);
   bool received_third_callback = false;
   observer->client()->WatchGainState().Then(
-      [&received_third_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchGainState>& result) mutable {
+      [&received_third_callback](fidl::Result<Observer::WatchGainState>& result) mutable {
         received_third_callback = true;
         ASSERT_TRUE(result.is_error()) << "Unexpected success to third WatchGainState";
         ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
@@ -343,39 +588,37 @@
   EXPECT_FALSE(received_second_callback);
   EXPECT_TRUE(received_third_callback);
   EXPECT_EQ(ObserverServer::count(), 1u);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 TEST_F(ObserverServerStreamConfigWarningTest, WatchPlugStateWhilePending) {
   auto fake_driver = CreateAndEnableDriverWithDefaults();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
 
   auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(added_device_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*added_device_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*added_device_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   // We'll always receive an immediate response from the first `WatchPlugState` call.
   auto observer = CreateTestObserverServer(added_device);
   bool received_initial_callback = false;
   observer->client()->WatchPlugState().Then(
-      [&received_initial_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchPlugState>& result) mutable {
+      [&received_initial_callback](fidl::Result<Observer::WatchPlugState>& result) mutable {
         received_initial_callback = true;
         EXPECT_TRUE(result.is_ok()) << result.error_value();
       });
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_initial_callback);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
-  // EXPECT_EQ(observer_fidl_error_status_.value_or(ZX_OK), ZX_OK);
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
+  // EXPECT_EQ(observer_fidl_error_status().value_or(ZX_OK), ZX_OK);
   bool received_second_callback = false;
   // The second `WatchPlugState` call should pend indefinitely (even after the third one fails).
   observer->client()->WatchPlugState().Then(
-      [&received_second_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchPlugState>& result) mutable {
+      [&received_second_callback](fidl::Result<Observer::WatchPlugState>& result) mutable {
         received_second_callback = true;
         FAIL() << "Unexpected completion for pending WatchPlugState call";
       });
@@ -386,8 +629,7 @@
   // This third `WatchPlugState` call should fail immediately (domain error ALREADY_PENDING)
   // since the second call has not yet completed.
   observer->client()->WatchPlugState().Then(
-      [&received_third_callback](
-          fidl::Result<fuchsia_audio_device::Observer::WatchPlugState>& result) mutable {
+      [&received_third_callback](fidl::Result<Observer::WatchPlugState>& result) mutable {
         received_third_callback = true;
         ASSERT_TRUE(result.is_error());
         ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
@@ -401,7 +643,7 @@
   EXPECT_FALSE(received_second_callback);
   EXPECT_TRUE(received_third_callback);
   EXPECT_EQ(ObserverServer::count(), 1u);
-  EXPECT_FALSE(observer_fidl_error_status_.has_value());
+  EXPECT_FALSE(observer_fidl_error_status().has_value()) << *observer_fidl_error_status();
 }
 
 // TODO(https://fxbug.dev/42068381): If Health can change post-initialization, test: device becomes
@@ -413,4 +655,93 @@
 // TODO(https://fxbug.dev/42068381): If Health can change post-initialization, test: device becomes
 //   unhealthy before GetReferenceClock. Expect Obs/Ctl/RingBuf to drop + Reg/WatchRemove notif.
 
+// TODO(https://fxbug.dev/323270827): implement signalprocessing, including in the FakeStreamConfig
+// test fixture. Then add negative test cases for
+// GetTopologies/GetElements/WatchTopology/WatchElementState, as are in Composite.
+
+// Verify WatchTopology if the driver does not support signalprocessing.
+TEST_F(ObserverServerStreamConfigWarningTest, WatchTopologyUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback = false;
+
+  observer->client()->WatchTopology().Then(
+      [&received_callback](fidl::Result<Observer::WatchTopology>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  received_callback = false;
+
+  // After a failing WatchTopology call, the binding should not be usable.
+  observer->client()->GetReferenceClock().Then(
+      [&received_callback](fidl::Result<Observer::GetReferenceClock>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error());
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_TRUE(observer->client().is_valid());
+}
+
+// Verify WatchElementState if the driver does not support signalprocessing.
+TEST_F(ObserverServerStreamConfigWarningTest, WatchElementStateUnsupported) {
+  auto fake_driver = CreateAndEnableDriverWithDefaults();
+  auto registry = CreateTestRegistryServer();
+
+  auto added_device_id = WaitForAddedDeviceTokenId(registry->client());
+  ASSERT_TRUE(added_device_id);
+  auto [status, device] = adr_service()->FindDeviceByTokenId(*added_device_id);
+  ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
+  ASSERT_FALSE(device->info()->signal_processing_topologies().has_value());
+  auto observer = CreateTestObserverServer(device);
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(ObserverServer::count(), 1u);
+  auto received_callback = false;
+
+  observer->client()
+      ->WatchElementState(fuchsia_audio_device::kDefaultDaiInterconnectElementId)
+      .Then([&received_callback](fidl::Result<Observer::WatchElementState>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        EXPECT_EQ(result.error_value().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  received_callback = false;
+
+  // After a failing WatchElementState call, the binding should not be usable.
+  observer->client()->GetReferenceClock().Then(
+      [&received_callback](fidl::Result<Observer::GetReferenceClock>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error());
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_NOT_SUPPORTED);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_TRUE(observer->client().is_valid());
+}
+
 }  // namespace media_audio
diff --git a/src/media/audio/services/device_registry/provider_server.cc b/src/media/audio/services/device_registry/provider_server.cc
index 1c8f547..845ac7c 100644
--- a/src/media/audio/services/device_registry/provider_server.cc
+++ b/src/media/audio/services/device_registry/provider_server.cc
@@ -4,11 +4,10 @@
 
 #include "src/media/audio/services/device_registry/provider_server.h"
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
+#include <fidl/fuchsia.audio.device/cpp/natural_types.h>
 #include <lib/fit/internal/result.h>
-#include <lib/syslog/cpp/macros.h>
 
-#include <optional>
+#include <utility>
 
 #include "src/media/audio/services/device_registry/audio_device_registry.h"
 #include "src/media/audio/services/device_registry/device.h"
@@ -26,10 +25,11 @@
     std::shared_ptr<AudioDeviceRegistry> parent) {
   ADR_LOG_STATIC(kLogProviderServerMethods);
 
-  return BaseFidlServer::Create(std::move(thread), std::move(server_end), parent);
+  return BaseFidlServer::Create(std::move(thread), std::move(server_end), std::move(parent));
 }
 
-ProviderServer::ProviderServer(std::shared_ptr<AudioDeviceRegistry> parent) : parent_(parent) {
+ProviderServer::ProviderServer(std::shared_ptr<AudioDeviceRegistry> parent)
+    : parent_(std::move(parent)) {
   ADR_LOG_METHOD(kLogObjectLifetimes);
   ++count_;
   LogObjectCounts();
diff --git a/src/media/audio/services/device_registry/provider_server.h b/src/media/audio/services/device_registry/provider_server.h
index 15be961..5028ced 100644
--- a/src/media/audio/services/device_registry/provider_server.h
+++ b/src/media/audio/services/device_registry/provider_server.h
@@ -5,7 +5,8 @@
 #ifndef SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_PROVIDER_SERVER_H_
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_PROVIDER_SERVER_H_
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
+#include <fidl/fuchsia.audio.device/cpp/markers.h>
+#include <fidl/fuchsia.audio.device/cpp/type_conversions.h>
 
 #include <cstdint>
 #include <memory>
diff --git a/src/media/audio/services/device_registry/provider_server_unittest.cc b/src/media/audio/services/device_registry/provider_server_unittest.cc
index 65529f3..2c92404 100644
--- a/src/media/audio/services/device_registry/provider_server_unittest.cc
+++ b/src/media/audio/services/device_registry/provider_server_unittest.cc
@@ -31,6 +31,7 @@
   ASSERT_EQ(ProviderServer::count(), 1u);
 
   (void)provider->client().UnbindMaybeGetEndpoint();
+
   // No WARNING logging should occur.
 }
 
@@ -40,6 +41,7 @@
   ASSERT_EQ(ProviderServer::count(), 1u);
 
   provider->server().Shutdown(ZX_ERR_PEER_CLOSED);
+
   // No WARNING logging should occur.
 }
 
@@ -66,15 +68,15 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 
   (void)provider->client().UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
   EXPECT_TRUE(provider->server().WaitForShutdown(zx::sec(1)));
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 }
 
 // An added Codec can be dropped without affecting the used Provider.
@@ -97,15 +99,16 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 
   fake_driver->DropCodec();
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
   EXPECT_EQ(ProviderServer::count(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // For Codecs added by Provider, ensure that Add-then-Watch works as expected.
@@ -130,8 +133,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   received_callback = false;
 
   registry_wrapper->client()->WatchDevicesAdded().Then(
@@ -144,6 +147,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // For Codecs added by Provider, ensure that Watch-then-Add works as expected.
@@ -179,8 +184,10 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback1);
   EXPECT_TRUE(received_callback2);
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 /////////////////////
@@ -206,15 +213,15 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 
   provider->client() = fidl::Client<Provider>();
 
   RunLoopUntilIdle();
   EXPECT_TRUE(provider->server().WaitForShutdown(zx::sec(1)));
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 }
 
 // An added Composite can be dropped without affecting the used Provider.
@@ -237,15 +244,16 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 
   fake_driver->DropComposite();
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
   EXPECT_EQ(ProviderServer::count(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 // For Composites added by Provider, ensure that Add-then-Watch works as expected.
@@ -270,8 +278,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   received_callback = false;
 
   registry_wrapper->client()->WatchDevicesAdded().Then(
@@ -284,6 +292,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // For Composites added by Provider, ensure that Watch-then-Add works as expected.
@@ -319,8 +329,10 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback1);
   EXPECT_TRUE(received_callback2);
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 /////////////////////
@@ -347,15 +359,15 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 
   (void)provider->client().UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
   EXPECT_TRUE(provider->server().WaitForShutdown(zx::sec(1)));
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 }
 
 // An added StreamConfig can be dropped without affecting the used Provider.
@@ -379,15 +391,16 @@
 
   RunLoopUntilIdle();
   ASSERT_TRUE(received_callback);
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 
   fake_driver->DropStreamConfig();
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
   EXPECT_EQ(ProviderServer::count(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 // For StreamConfigs added by Provider, ensure that Add-then-Watch works as expected.
@@ -413,8 +426,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   received_callback = false;
 
   registry_wrapper->client()->WatchDevicesAdded().Then(
@@ -427,6 +440,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // For StreamConfigs added by Provider, ensure that Watch-then-Add works as expected.
@@ -463,8 +478,10 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback1);
   EXPECT_TRUE(received_callback2);
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 }  // namespace
diff --git a/src/media/audio/services/device_registry/provider_server_warning_unittest.cc b/src/media/audio/services/device_registry/provider_server_warning_unittest.cc
index 28ba7c8..02e41f7 100644
--- a/src/media/audio/services/device_registry/provider_server_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/provider_server_warning_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "src/media/audio/services/device_registry/adr_server_unittest_base.h"
 #include "src/media/audio/services/device_registry/provider_server.h"
+#include "zircon/errors.h"
 
 namespace media_audio {
 namespace {
@@ -48,8 +49,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerCodecWarningTest, EmptyDeviceName) {
@@ -75,8 +77,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerCodecWarningTest, MissingDeviceType) {
@@ -102,8 +105,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerCodecWarningTest, MissingDriverClient) {
@@ -128,8 +132,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerCodecWarningTest, InvalidDriverClient) {
@@ -154,8 +159,10 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  ASSERT_TRUE(provider_fidl_error_status().has_value());
+  EXPECT_EQ(*provider_fidl_error_status(), ZX_ERR_INVALID_ARGS);
 }
 
 TEST_F(ProviderServerCodecWarningTest, WrongDriverClient) {
@@ -183,8 +190,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 /////////////////////
@@ -215,8 +223,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerCompositeWarningTest, EmptyDeviceName) {
@@ -242,8 +251,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerCompositeWarningTest, MissingDeviceType) {
@@ -269,8 +279,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerCompositeWarningTest, MissingDriverClient) {
@@ -295,8 +306,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerCompositeWarningTest, InvalidDriverClient) {
@@ -321,8 +333,10 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  ASSERT_TRUE(provider_fidl_error_status().has_value());
+  EXPECT_EQ(*provider_fidl_error_status(), ZX_ERR_INVALID_ARGS);
 }
 
 TEST_F(ProviderServerCompositeWarningTest, WrongDriverClient) {
@@ -350,8 +364,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 /////////////////////
@@ -384,8 +399,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 /////////////////////
@@ -415,8 +431,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
 }
 
 TEST_F(ProviderServerStreamConfigWarningTest, EmptyDeviceName) {
@@ -443,8 +459,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerStreamConfigWarningTest, MissingDeviceType) {
@@ -471,8 +488,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerStreamConfigWarningTest, MissingDriverClient) {
@@ -497,8 +515,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 TEST_F(ProviderServerStreamConfigWarningTest, InvalidDriverClient) {
@@ -523,8 +542,10 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  ASSERT_TRUE(provider_fidl_error_status().has_value());
+  EXPECT_EQ(*provider_fidl_error_status(), ZX_ERR_INVALID_ARGS);
 }
 
 TEST_F(ProviderServerStreamConfigWarningTest, WrongDriverClient) {
@@ -551,8 +572,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
-  EXPECT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  EXPECT_FALSE(provider_fidl_error_status().has_value()) << *provider_fidl_error_status();
 }
 
 }  // namespace
diff --git a/src/media/audio/services/device_registry/registry_server_unittest.cc b/src/media/audio/services/device_registry/registry_server_unittest.cc
index bca19c8..011f1d6 100644
--- a/src/media/audio/services/device_registry/registry_server_unittest.cc
+++ b/src/media/audio/services/device_registry/registry_server_unittest.cc
@@ -6,7 +6,6 @@
 
 #include <fidl/fuchsia.audio.device/cpp/fidl.h>
 #include <lib/fidl/cpp/client.h>
-#include <lib/sync/cpp/completion.h>
 
 #include <optional>
 
@@ -23,6 +22,7 @@
 
 class RegistryServerTest : public AudioDeviceRegistryServerTestBase {};
 class RegistryServerCodecTest : public RegistryServerTest {};
+class RegistryServerCompositeTest : public RegistryServerTest {};
 class RegistryServerStreamConfigTest : public RegistryServerTest {};
 
 /////////////////////
@@ -51,13 +51,13 @@
 // Client calls WatchDevicesAdded and is notified.
 TEST_F(RegistryServerCodecTest, DeviceAddThenRegistryCreate) {
   auto fake_driver = CreateFakeCodecOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -73,14 +73,15 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Client calls WatchDevicesAdded, then add device and client is notified.
 TEST_F(RegistryServerCodecTest, WatchAddsThenDeviceAdd) {
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto received_callback = false;
 
   registry->client()->WatchDevicesAdded().Then(
@@ -94,30 +95,31 @@
 
   RunLoopUntilIdle();
   EXPECT_FALSE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
 
   auto fake_driver = CreateFakeCodecInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Add device, see it added, then client calls WatchDevicesAdded and is notified.
 TEST_F(RegistryServerCodecTest, DeviceAddThenWatchAdds) {
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
   auto fake_driver = CreateFakeCodecOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
   auto received_callback = false;
 
   registry->client()->WatchDevicesAdded().Then(
@@ -131,17 +133,18 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Client calls WatchDeviceRemoved, then remove device, then client is notified.
 TEST_F(RegistryServerCodecTest, WatchRemovesThenDeviceRemove) {
   auto fake_driver = CreateFakeCodecInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -182,18 +185,19 @@
   EXPECT_TRUE(received_callback);
   ASSERT_TRUE(removed_device_id.has_value());
   EXPECT_EQ(*added_device_id, *removed_device_id);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Remove device, see ADR remove it, then client calls WatchDeviceRemoved and is notified.
 TEST_F(RegistryServerCodecTest, DeviceRemoveThenWatchRemoves) {
   auto fake_driver = CreateFakeCodecOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -216,7 +220,7 @@
   fake_driver->DropCodec();
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
   received_callback = false;
   std::optional<TokenId> removed_device_id;
 
@@ -233,7 +237,8 @@
   EXPECT_TRUE(received_callback);
   ASSERT_TRUE(removed_device_id.has_value());
   EXPECT_EQ(*added_device_id, *removed_device_id);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Create a Registry connection then add and remove device (see ADR count go up and down).
@@ -242,16 +247,16 @@
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto fake_driver = CreateFakeCodecInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   fake_driver->DropCodec();
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
   bool received_add_response = false, received_remove_response = false;
 
   registry->client()->WatchDevicesAdded().Then(
@@ -268,6 +273,7 @@
   RunLoopUntilIdle();
   EXPECT_FALSE(received_add_response);
   EXPECT_FALSE(received_remove_response);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Remove device, add device, WatchDevicesAdded/WatchDeviceRemoved (id's differ: should notify).
@@ -275,12 +281,12 @@
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto fake_driver = CreateFakeCodecNoDirection();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   bool received_callback = false;
   std::optional<TokenId> first_added_id;
 
@@ -301,14 +307,14 @@
   fake_driver->DropCodec();
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
   fake_driver = CreateFakeCodecNoDirection();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   received_callback = false;
   std::optional<TokenId> removed_device_id;
 
@@ -343,21 +349,18 @@
   EXPECT_TRUE(received_callback);
   ASSERT_TRUE(second_added_id);
   EXPECT_NE(*first_added_id, *second_added_id);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
-// Add cases for info.signalprocessing_topologies and signalprocessing_elements (once implemented).
-//
-// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain).
-
 // Client can open an Observer connection on an added Codec device.
 TEST_F(RegistryServerCodecTest, CreateObserver) {
   auto fake_driver = CreateFakeCodecOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = true;
@@ -379,7 +382,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   received_callback = false;
 
   registry->client()
@@ -394,6 +397,364 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+/////////////////////
+// Composite tests
+// Device already exists before the Registry connection is created.
+TEST_F(RegistryServerCompositeTest, DeviceAddThenRegistryCreate) {
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto received_callback = false;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        ASSERT_TRUE(result->devices());
+        ASSERT_EQ(result->devices()->size(), 1u);
+        EXPECT_EQ(result->devices()->at(0).device_type(),
+                  fuchsia_audio_device::DeviceType::kComposite);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+// Client calls WatchDevicesAdded, then add device and client is notified.
+TEST_F(RegistryServerCompositeTest, WatchAddsThenDeviceAdd) {
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
+  auto received_callback = false;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        ASSERT_TRUE(result->devices());
+        ASSERT_EQ(result->devices()->size(), 1u);
+        EXPECT_EQ(result->devices()->at(0).device_type(),
+                  fuchsia_audio_device::DeviceType::kComposite);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+// Add device, see it added, then client calls WatchDevicesAdded and is notified.
+TEST_F(RegistryServerCompositeTest, DeviceAddThenWatchAdds) {
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  auto received_callback = false;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        ASSERT_TRUE(result->devices());
+        ASSERT_EQ(result->devices()->size(), 1u);
+        EXPECT_EQ(result->devices()->at(0).device_type(),
+                  fuchsia_audio_device::DeviceType::kComposite);
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+// Client calls WatchDeviceRemoved, then remove device, then client is notified.
+TEST_F(RegistryServerCompositeTest, WatchRemovesThenDeviceRemove) {
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto received_callback = false;
+  std::optional<TokenId> added_device_id;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback,
+       &added_device_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok() && result->devices() && result->devices()->size() == 1);
+        ASSERT_TRUE(result->devices()->at(0).device_type() ==
+                        fuchsia_audio_device::DeviceType::kComposite &&
+                    result->devices()->at(0).token_id().has_value());
+        added_device_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(added_device_id);
+  received_callback = false;
+  std::optional<TokenId> removed_device_id;
+
+  registry->client()->WatchDeviceRemoved().Then(
+      [&received_callback,
+       &removed_device_id](fidl::Result<Registry::WatchDeviceRemoved>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        ASSERT_TRUE(result->token_id());
+        removed_device_id = *result->token_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_callback);
+  EXPECT_FALSE(removed_device_id.has_value());
+  fake_driver->DropComposite();
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(removed_device_id.has_value());
+  EXPECT_EQ(*added_device_id, *removed_device_id);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+// Remove device, see ADR remove it, then client calls WatchDeviceRemoved and is notified.
+TEST_F(RegistryServerCompositeTest, DeviceRemoveThenWatchRemoves) {
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto received_callback = false;
+  std::optional<TokenId> added_device_id;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback,
+       &added_device_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok() && result->devices() && result->devices()->size() == 1);
+        ASSERT_TRUE(result->devices()->at(0).device_type() ==
+                        fuchsia_audio_device::DeviceType::kComposite &&
+                    result->devices()->at(0).token_id().has_value());
+        added_device_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(added_device_id);
+  fake_driver->DropComposite();
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
+  received_callback = false;
+  std::optional<TokenId> removed_device_id;
+
+  registry->client()->WatchDeviceRemoved().Then(
+      [&received_callback,
+       &removed_device_id](fidl::Result<Registry::WatchDeviceRemoved>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        ASSERT_TRUE(result->token_id());
+        removed_device_id = *result->token_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(removed_device_id.has_value());
+  EXPECT_EQ(*added_device_id, *removed_device_id);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+// Create a Registry connection then add and remove device (see ADR count go up and down).
+// Then when client calls WatchDevicesAdded and WatchDeviceRemoved, no notifications should occur.
+TEST_F(RegistryServerCompositeTest, DeviceAddRemoveThenWatches) {
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  fake_driver->DropComposite();
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
+  bool received_add_response = false, received_remove_response = false;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_add_response](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_add_response = true;
+        FAIL() << "Unexpected WatchDevicesAdded response";
+      });
+  registry->client()->WatchDeviceRemoved().Then(
+      [&received_remove_response](fidl::Result<Registry::WatchDeviceRemoved>& result) mutable {
+        received_remove_response = true;
+        FAIL() << "Unexpected WatchDeviceRemoved response";
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_FALSE(received_add_response);
+  EXPECT_FALSE(received_remove_response);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+// Remove device, add device, WatchDevicesAdded/WatchDeviceRemoved (id's differ: should notify).
+TEST_F(RegistryServerCompositeTest, DeviceRemoveAddThenWatches) {
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  bool received_callback = false;
+  std::optional<TokenId> first_added_id;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback,
+       &first_added_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok() && result->devices() && result->devices()->size() == 1);
+        ASSERT_TRUE(result->devices()->at(0).device_type() ==
+                        fuchsia_audio_device::DeviceType::kComposite &&
+                    result->devices()->at(0).token_id().has_value());
+        first_added_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(first_added_id);
+  fake_driver->DropComposite();
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
+  fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  received_callback = false;
+  std::optional<TokenId> removed_device_id;
+
+  registry->client()->WatchDeviceRemoved().Then(
+      [&received_callback,
+       &removed_device_id](fidl::Result<Registry::WatchDeviceRemoved>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok()) << result.error_value();
+        ASSERT_TRUE(result->token_id());
+        removed_device_id = *result->token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(removed_device_id);
+  EXPECT_EQ(*first_added_id, *removed_device_id);
+  received_callback = false;
+  std::optional<TokenId> second_added_id;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback,
+       &second_added_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok() && result->devices() && result->devices()->size() == 1);
+        ASSERT_TRUE(result->devices()->at(0).device_type() ==
+                        fuchsia_audio_device::DeviceType::kComposite &&
+                    result->devices()->at(0).token_id().has_value());
+        second_added_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(second_added_id);
+  EXPECT_NE(*first_added_id, *second_added_id);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+// Client can open an Observer connection on an added Composite device.
+TEST_F(RegistryServerCompositeTest, CreateObserver) {
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto received_callback = true;
+  std::optional<TokenId> added_id;
+
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback, &added_id](fidl::Result<Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok() && result->devices() && result->devices()->size() == 1);
+        ASSERT_TRUE(result->devices()->at(0).device_type() ==
+                        fuchsia_audio_device::DeviceType::kComposite &&
+                    result->devices()->at(0).token_id().has_value());
+        added_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(added_id);
+  auto [observer_client_end, observer_server_end] =
+      CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
+  auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
+  received_callback = false;
+
+  registry->client()
+      ->CreateObserver({{
+          .token_id = *added_id,
+          .observer_server = std::move(observer_server_end),
+      }})
+      .Then([&received_callback](fidl::Result<Registry::CreateObserver>& result) {
+        received_callback = true;
+        EXPECT_TRUE(result.is_ok()) << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 /////////////////////
@@ -401,13 +762,13 @@
 // Device already exists before the Registry connection is created.
 TEST_F(RegistryServerStreamConfigTest, DeviceAddThenRegistryCreate) {
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -424,14 +785,15 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Client calls WatchDevicesAdded, then add device and client is notified.
 TEST_F(RegistryServerStreamConfigTest, WatchAddsThenDeviceAdd) {
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
-  ASSERT_EQ(adr_service_->unhealthy_devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->unhealthy_devices().size(), 0u);
   auto received_callback = false;
 
   registry->client()->WatchDevicesAdded().Then(
@@ -445,30 +807,31 @@
 
   RunLoopUntilIdle();
   EXPECT_FALSE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
 
   auto fake_driver = CreateFakeStreamConfigInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test input name",
-                                         fuchsia_audio_device::DeviceType::kInput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test input name",
+                                          fuchsia_audio_device::DeviceType::kInput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Add device, see it added, then client calls WatchDevicesAdded and is notified.
 TEST_F(RegistryServerStreamConfigTest, DeviceAddThenWatchAdds) {
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  EXPECT_EQ(adr_service_->devices().size(), 1u);
+  EXPECT_EQ(adr_service()->devices().size(), 1u);
   auto received_callback = false;
 
   registry->client()->WatchDevicesAdded().Then(
@@ -483,17 +846,18 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Client calls WatchDeviceRemoved, then remove device, then client is notified.
 TEST_F(RegistryServerStreamConfigTest, WatchRemovesThenDeviceRemove) {
   auto fake_driver = CreateFakeStreamConfigInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test input name",
-                                         fuchsia_audio_device::DeviceType::kInput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test input name",
+                                          fuchsia_audio_device::DeviceType::kInput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -534,18 +898,19 @@
   EXPECT_TRUE(received_callback);
   ASSERT_TRUE(removed_device_id.has_value());
   EXPECT_EQ(*added_device_id, *removed_device_id);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Remove device, see ADR remove it, then client calls WatchDeviceRemoved and is notified.
 TEST_F(RegistryServerStreamConfigTest, DeviceRemoveThenWatchRemoves) {
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -568,7 +933,7 @@
   fake_driver->DropStreamConfig();
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
   received_callback = false;
   std::optional<TokenId> removed_device_id;
 
@@ -585,7 +950,8 @@
   EXPECT_TRUE(received_callback);
   ASSERT_TRUE(removed_device_id.has_value());
   EXPECT_EQ(*added_device_id, *removed_device_id);
-  EXPECT_EQ(adr_service_->devices().size(), 0u);
+  EXPECT_EQ(adr_service()->devices().size(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Create a Registry connection then add and remove device (see ADR count go up and down).
@@ -594,16 +960,16 @@
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto fake_driver = CreateFakeStreamConfigInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test input name",
-                                         fuchsia_audio_device::DeviceType::kInput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test input name",
+                                          fuchsia_audio_device::DeviceType::kInput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   fake_driver->DropStreamConfig();
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
   bool received_add_response = false, received_remove_response = false;
 
   registry->client()->WatchDevicesAdded().Then(
@@ -620,6 +986,7 @@
   RunLoopUntilIdle();
   EXPECT_FALSE(received_add_response);
   EXPECT_FALSE(received_remove_response);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Remove device, add device, WatchDevicesAdded/WatchDeviceRemoved (id's differ: should notify).
@@ -627,12 +994,12 @@
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   bool received_callback = false;
   std::optional<TokenId> first_added_id;
 
@@ -653,14 +1020,14 @@
   fake_driver->DropStreamConfig();
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 0u);
+  ASSERT_EQ(adr_service()->devices().size(), 0u);
   fake_driver = CreateFakeStreamConfigInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test input name",
-                                         fuchsia_audio_device::DeviceType::kInput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test input name",
+                                          fuchsia_audio_device::DeviceType::kInput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   received_callback = false;
   std::optional<TokenId> removed_device_id;
 
@@ -695,21 +1062,18 @@
   EXPECT_TRUE(received_callback);
   ASSERT_TRUE(second_added_id);
   EXPECT_NE(*first_added_id, *second_added_id);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
-// Add cases for info.signalprocessing_topologies and signalprocessing_elements (once implemented).
-//
-// TODO(https://fxbug.dev/323270827): implement signalprocessing for Codec (topology, gain).
-
-// Client can open an Observer connection on an added Codec device.
+// Client can open an Observer connection on an added StreamConfig device.
 TEST_F(RegistryServerStreamConfigTest, CreateObserver) {
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = true;
@@ -731,7 +1095,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   received_callback = false;
 
   registry->client()
@@ -746,6 +1110,7 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 }  // namespace
diff --git a/src/media/audio/services/device_registry/registry_server_warning_unittest.cc b/src/media/audio/services/device_registry/registry_server_warning_unittest.cc
index 5386fbd..4d17269 100644
--- a/src/media/audio/services/device_registry/registry_server_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/registry_server_warning_unittest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <fidl/fuchsia.audio.device/cpp/natural_types.h>
-#include <lib/sync/cpp/completion.h>
 #include <zircon/errors.h>
 
 #include <gtest/gtest.h>
@@ -19,6 +18,7 @@
 
 class RegistryServerWarningTest : public AudioDeviceRegistryServerTestBase {};
 class RegistryServerCodecWarningTest : public RegistryServerWarningTest {};
+class RegistryServerCompositeWarningTest : public RegistryServerWarningTest {};
 class RegistryServerStreamConfigWarningTest : public RegistryServerWarningTest {};
 
 /////////////////////
@@ -58,6 +58,7 @@
   EXPECT_FALSE(received_callback_1);
   EXPECT_TRUE(received_callback_2);
   EXPECT_EQ(RegistryServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // A subsequent call to WatchDeviceRemoved before the previous one completes should fail.
@@ -94,6 +95,7 @@
   EXPECT_FALSE(received_callback_1);
   EXPECT_TRUE(received_callback_2);
   EXPECT_EQ(RegistryServer::count(), 1u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // If the required 'id' field is not set, CreateObserver should fail with kInvalidTokenId.
@@ -103,7 +105,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   bool received_callback = false;
 
   registry->client()
@@ -122,6 +124,7 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // If 'id' doesn't identify an initialized device, CreateObserver should fail with kDeviceNotFound.
@@ -131,7 +134,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   bool received_callback = false;
 
   registry->client()
@@ -151,6 +154,7 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 /////////////////////
@@ -159,12 +163,12 @@
 // If required 'observer_server' is not set, CreateObserver should fail with kInvalidObserver.
 TEST_F(RegistryServerCodecWarningTest, CreateObserverMissingObserver) {
   auto fake_driver = CreateFakeCodecOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -184,7 +188,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   received_callback = false;
 
   registry->client()
@@ -203,17 +207,18 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // If 'observer_server' is not set to a valid handle, we should fail with ZX_ERR_INVALID_ARGS.
 TEST_F(RegistryServerCodecWarningTest, CreateObserverBadObserver) {
   auto fake_driver = CreateFakeCodecInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test codec name",
-                                         fuchsia_audio_device::DeviceType::kCodec,
-                                         DriverClient::WithCodec(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test codec name",
+                                          fuchsia_audio_device::DeviceType::kCodec,
+                                          DriverClient::WithCodec(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -233,7 +238,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   received_callback = false;
 
   registry->client()
@@ -252,23 +257,132 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(registry_fidl_error_status().has_value());
+  EXPECT_EQ(*registry_fidl_error_status(), ZX_ERR_INVALID_ARGS);
 }
 
 // TODO(https://fxbug.dev/42068381): If Health can change post-initialization, add a test case for:
 //   CreateObserver with token of Codec that was ready & Added, but then became unhealthy.
 
 /////////////////////
+// Composite tests
+//
+// If required 'observer_server' is not set, CreateObserver should fail with kInvalidObserver.
+TEST_F(RegistryServerCompositeWarningTest, CreateObserverMissingObserver) {
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto received_callback = false;
+  std::optional<TokenId> added_id;
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback,
+       &added_id](fidl::Result<fuchsia_audio_device::Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok() && result->devices() && result->devices()->size() == 1u);
+        ASSERT_TRUE(result->devices()->at(0).token_id());
+        added_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(added_id);
+  auto [observer_client_end, observer_server_end] =
+      CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
+  auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
+  received_callback = false;
+
+  registry->client()
+      ->CreateObserver({{
+          .token_id = *added_id,
+      }})
+      .Then([&received_callback](
+                fidl::Result<fuchsia_audio_device::Registry::CreateObserver>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_domain_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().domain_error(),
+                  fuchsia_audio_device::RegistryCreateObserverError::kInvalidObserver)
+            << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+}
+
+// If 'observer_server' is not set to a valid handle, we should fail with ZX_ERR_INVALID_ARGS.
+TEST_F(RegistryServerCompositeWarningTest, CreateObserverBadObserver) {
+  auto fake_driver = CreateFakeComposite();
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test composite name",
+                                          fuchsia_audio_device::DeviceType::kComposite,
+                                          DriverClient::WithComposite(fake_driver->Enable())));
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
+  auto registry = CreateTestRegistryServer();
+  ASSERT_EQ(RegistryServer::count(), 1u);
+  auto received_callback = false;
+  std::optional<TokenId> added_id;
+  registry->client()->WatchDevicesAdded().Then(
+      [&received_callback,
+       &added_id](fidl::Result<fuchsia_audio_device::Registry::WatchDevicesAdded>& result) mutable {
+        received_callback = true;
+        ASSERT_TRUE(result.is_ok() && result->devices() && result->devices()->size() == 1u);
+        ASSERT_TRUE(result->devices()->at(0).token_id());
+        added_id = *result->devices()->at(0).token_id();
+      });
+
+  RunLoopUntilIdle();
+  ASSERT_TRUE(received_callback);
+  ASSERT_TRUE(added_id);
+  auto [observer_client_end, observer_server_end] =
+      CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
+  auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
+  received_callback = false;
+
+  registry->client()
+      ->CreateObserver({{
+          .token_id = *added_id,
+          .observer_server = fidl::ServerEnd<fuchsia_audio_device::Observer>(),
+      }})
+      .Then([&received_callback](
+                fidl::Result<fuchsia_audio_device::Registry::CreateObserver>& result) {
+        received_callback = true;
+        ASSERT_TRUE(result.is_error());
+        ASSERT_TRUE(result.error_value().is_framework_error()) << result.error_value();
+        EXPECT_EQ(result.error_value().framework_error().status(), ZX_ERR_INVALID_ARGS)
+            << result.error_value();
+      });
+
+  RunLoopUntilIdle();
+  EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(registry_fidl_error_status().has_value());
+  EXPECT_EQ(*registry_fidl_error_status(), ZX_ERR_INVALID_ARGS);
+}
+
+// TODO(https://fxbug.dev/42068381): If Health can change post-initialization, add a test case for:
+//   CreateObserver with token of Composite that was ready & Added, but then became unhealthy.
+
+/////////////////////
 // StreamConfig tests
 //
 // If the required 'observer_server' field is not set, we should fail.
 TEST_F(RegistryServerStreamConfigWarningTest, CreateObserverMissingObserver) {
   auto fake_driver = CreateFakeStreamConfigOutput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test output name",
-                                         fuchsia_audio_device::DeviceType::kOutput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test output name",
+                                          fuchsia_audio_device::DeviceType::kOutput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -288,7 +402,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   received_callback = false;
 
   registry->client()
@@ -307,17 +421,18 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // If 'observer_server' is not set to a valid handle, we should fail.
 TEST_F(RegistryServerStreamConfigWarningTest, CreateObserverBadObserver) {
   auto fake_driver = CreateFakeStreamConfigInput();
-  adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test input name",
-                                         fuchsia_audio_device::DeviceType::kInput,
-                                         DriverClient::WithStreamConfig(fake_driver->Enable())));
+  adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test input name",
+                                          fuchsia_audio_device::DeviceType::kInput,
+                                          DriverClient::WithStreamConfig(fake_driver->Enable())));
 
   RunLoopUntilIdle();
-  ASSERT_EQ(adr_service_->devices().size(), 1u);
+  ASSERT_EQ(adr_service()->devices().size(), 1u);
   auto registry = CreateTestRegistryServer();
   ASSERT_EQ(RegistryServer::count(), 1u);
   auto received_callback = false;
@@ -337,7 +452,7 @@
   auto [observer_client_end, observer_server_end] =
       CreateNaturalAsyncClientOrDie<fuchsia_audio_device::Observer>();
   auto observer_client = fidl::Client<fuchsia_audio_device::Observer>(
-      std::move(observer_client_end), dispatcher(), observer_fidl_handler_.get());
+      std::move(observer_client_end), dispatcher(), observer_fidl_handler().get());
   received_callback = false;
 
   registry->client()
@@ -356,6 +471,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  ASSERT_TRUE(registry_fidl_error_status().has_value());
+  EXPECT_EQ(*registry_fidl_error_status(), ZX_ERR_INVALID_ARGS);
 }
 
 // TODO(https://fxbug.dev/42068381): If Health can change post-initialization, add a test case for:
diff --git a/src/media/audio/services/device_registry/ring_buffer_server.cc b/src/media/audio/services/device_registry/ring_buffer_server.cc
index 5bf0652..737e033 100644
--- a/src/media/audio/services/device_registry/ring_buffer_server.cc
+++ b/src/media/audio/services/device_registry/ring_buffer_server.cc
@@ -4,15 +4,13 @@
 
 #include "src/media/audio/services/device_registry/ring_buffer_server.h"
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
+#include <fidl/fuchsia.audio.device/cpp/markers.h>
 #include <lib/fit/internal/result.h>
 #include <zircon/errors.h>
 
-#include <optional>
 #include <utility>
 
 #include "src/media/audio/services/common/base_fidl_server.h"
-#include "src/media/audio/services/device_registry/audio_device_registry.h"
 #include "src/media/audio/services/device_registry/control_server.h"
 #include "src/media/audio/services/device_registry/device.h"
 #include "src/media/audio/services/device_registry/logging.h"
diff --git a/src/media/audio/services/device_registry/ring_buffer_server.h b/src/media/audio/services/device_registry/ring_buffer_server.h
index e59c0f2..1409376 100644
--- a/src/media/audio/services/device_registry/ring_buffer_server.h
+++ b/src/media/audio/services/device_registry/ring_buffer_server.h
@@ -5,7 +5,8 @@
 #ifndef SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_RING_BUFFER_SERVER_H_
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_RING_BUFFER_SERVER_H_
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
+#include <fidl/fuchsia.audio.device/cpp/markers.h>
+#include <fidl/fuchsia.audio.device/cpp/type_conversions.h>
 
 #include <memory>
 
diff --git a/src/media/audio/services/device_registry/ring_buffer_server_unittest.cc b/src/media/audio/services/device_registry/ring_buffer_server_unittest.cc
index 29d5118..7575bd1 100644
--- a/src/media/audio/services/device_registry/ring_buffer_server_unittest.cc
+++ b/src/media/audio/services/device_registry/ring_buffer_server_unittest.cc
@@ -13,7 +13,6 @@
 #include <lib/zx/clock.h>
 #include <zircon/errors.h>
 
-#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/common/testing/test_server_and_async_client.h"
@@ -26,7 +25,6 @@
 namespace media_audio {
 namespace {
 
-using ::testing::Optional;
 using Control = fuchsia_audio_device::Control;
 using RingBuffer = fuchsia_audio_device::RingBuffer;
 using DriverClient = fuchsia_audio_device::DriverClient;
@@ -90,7 +88,7 @@
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   FX_CHECK(token_id);
   auto control_creator = CreateTestControlCreatorServer();
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_TRUE(presence == AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -105,6 +103,9 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_creator_fidl_error_status().has_value());
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   return std::make_pair(std::move(control), std::move(ring_buffer_client));
 }
 
@@ -112,10 +113,10 @@
  protected:
   std::shared_ptr<Device> EnableDriverAndAddDevice(
       const std::shared_ptr<FakeComposite>& fake_driver) {
-    auto device = Device::Create(adr_service_, dispatcher(), "Test composite name",
+    auto device = Device::Create(adr_service(), dispatcher(), "Test composite name",
                                  fuchsia_audio_device::DeviceType::kComposite,
                                  DriverClient::WithComposite(fake_driver->Enable()));
-    adr_service_->AddDevice(device);
+    adr_service()->AddDevice(device);
 
     RunLoopUntilIdle();
     return device;
@@ -137,6 +138,7 @@
   (void)ring_buffer_client.UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   // If RingBuffer client doesn't drop cleanly, RingBufferServer emits a WARNING, which will fail.
 }
 
@@ -155,6 +157,7 @@
   fake_driver->DropRingBuffer(element_id);
 
   RunLoopUntilIdle();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   // If RingBufferServer doesn't shutdown cleanly, it emits a WARNING, which will cause a failure.
 }
 
@@ -173,6 +176,8 @@
   fake_driver->DropComposite();
 
   RunLoopUntilIdle();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(control_fidl_error_status(), ZX_ERR_PEER_CLOSED);
   // If RingBufferServer doesn't shutdown cleanly, it emits a WARNING, which will cause a failure.
 }
 
@@ -188,7 +193,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto requested_ring_buffer_bytes = 2000u;
@@ -235,7 +240,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that RingBuffer/SetActiveChannels succeeds and returns an expected set_time.
@@ -251,7 +257,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -291,7 +297,8 @@
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(fake_driver->active_channels_bitmask(element_id), 0x0u);
   EXPECT_GT(fake_driver->active_channels_set_time(element_id), before_set_active_channels);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(RingBufferServerCompositeTest, DriverDoesNotSupportSetActiveChannels) {
@@ -308,7 +315,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -344,7 +351,8 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(fake_driver->active_channels_bitmask(element_id), (1u << channel_count) - 1u);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that RingBuffer/Start and /Stop function as expected, including start_time.
@@ -360,7 +368,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -427,7 +435,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that RingBuffer/WatchDelayInfo notifies of the delay received during initialization.
@@ -446,7 +455,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -485,7 +494,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that RingBuffer/WatchDelayInfo notifies of delay changes after initialization.
@@ -500,7 +510,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -555,7 +565,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that the RingBufferServer is destructed if the client drops the Control.
@@ -570,7 +581,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -591,12 +602,14 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 
   (void)control->client().UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
   EXPECT_TRUE(control->server().WaitForShutdown());
   EXPECT_EQ(RingBufferServer::count(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Verify that the RingBufferServer is destructed if the ControlServer shuts down.
@@ -611,7 +624,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -631,6 +644,7 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   EXPECT_EQ(ControlServer::count(), 1u);
   EXPECT_EQ(RingBufferServer::count(), 1u);
 
@@ -639,6 +653,7 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(control->server().WaitForShutdown());
   EXPECT_EQ(RingBufferServer::count(), 0u);
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 // Verify that RingBuffer works as expected, after RingBuffer being created/destroyed/recreated.
@@ -654,7 +669,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   {
     auto control = CreateTestControlServer(device_to_control);
@@ -692,6 +707,7 @@
 
     RunLoopUntilIdle();
     ASSERT_TRUE(received_callback);
+    EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 
     // Now that we are started, we want to suddenly drop the RingBuffer connection.
     (void)ring_buffer_client.UnbindMaybeGetEndpoint();
@@ -737,17 +753,19 @@
 
     RunLoopUntilIdle();
     EXPECT_TRUE(received_callback);
+    EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   }
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 class RingBufferServerStreamConfigTest : public RingBufferServerTest {
  protected:
   std::shared_ptr<Device> EnableDriverAndAddDevice(
       const std::shared_ptr<FakeStreamConfig>& fake_driver) {
-    auto device = Device::Create(adr_service_, dispatcher(), "Test output name",
+    auto device = Device::Create(adr_service(), dispatcher(), "Test output name",
                                  fuchsia_audio_device::DeviceType::kOutput,
                                  DriverClient::WithStreamConfig(fake_driver->Enable()));
-    adr_service_->AddDevice(device);
+    adr_service()->AddDevice(device);
 
     RunLoopUntilIdle();
     return device;
@@ -764,6 +782,7 @@
   (void)ring_buffer_client.UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   // If RingBuffer client doesn't drop cleanly, RingBufferServer emits a WARNING, which will fail.
 }
 
@@ -776,6 +795,7 @@
   fake_driver->DropRingBuffer();
 
   RunLoopUntilIdle();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   // If RingBufferServer doesn't shutdown cleanly, it emits a WARNING, which will cause a failure.
 }
 
@@ -789,6 +809,8 @@
   fake_driver->DropStreamConfig();
 
   RunLoopUntilIdle();
+  ASSERT_TRUE(control_fidl_error_status().has_value());
+  EXPECT_EQ(control_fidl_error_status(), ZX_ERR_PEER_CLOSED);
   // If RingBufferServer doesn't shutdown cleanly, it emits a WARNING, which will cause a failure.
 }
 
@@ -801,7 +823,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -842,7 +864,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that RingBuffer/SetActiveChannels succeeds and returns an expected set_time.
@@ -854,7 +877,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -892,7 +915,8 @@
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(fake_driver->active_channels_bitmask(), 0x0u);
   EXPECT_GT(fake_driver->active_channels_set_time(), before_set_active_channels);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 TEST_F(RingBufferServerStreamConfigTest, DriverDoesNotSupportSetActiveChannels) {
@@ -905,7 +929,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -939,7 +963,8 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(fake_driver->active_channels_bitmask(), 0x3u);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that RingBuffer/Start and /Stop function as expected, including start_time.
@@ -952,7 +977,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -1017,7 +1042,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that RingBuffer/WatchDelayInfo notifies of the delay received during initialization.
@@ -1032,7 +1058,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -1069,7 +1095,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that RingBuffer/WatchDelayInfo notifies of delay changes after initialization.
@@ -1081,7 +1108,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -1133,7 +1160,8 @@
 
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
-  (void)ring_buffer_client.UnbindMaybeGetEndpoint();
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 }
 
 // Verify that the RingBufferServer is destructed if the client drops the Control.
@@ -1145,7 +1173,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -1164,11 +1192,13 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 
   (void)control->client().UnbindMaybeGetEndpoint();
 
   RunLoopUntilIdle();
   EXPECT_TRUE(control->server().WaitForShutdown());
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
   EXPECT_EQ(RingBufferServer::count(), 0u);
 }
 
@@ -1181,7 +1211,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -1200,12 +1230,14 @@
   RunLoopUntilIdle();
   EXPECT_TRUE(received_callback);
   EXPECT_EQ(ControlServer::count(), 1u);
+  EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   EXPECT_EQ(RingBufferServer::count(), 1u);
 
   control->server().Shutdown(ZX_ERR_PEER_CLOSED);
 
   RunLoopUntilIdle();
   EXPECT_TRUE(control->server().WaitForShutdown());
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
   EXPECT_EQ(RingBufferServer::count(), 0u);
 }
 
@@ -1219,7 +1251,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   {
     auto control = CreateTestControlServer(device_to_control);
@@ -1255,6 +1287,7 @@
 
     RunLoopUntilIdle();
     ASSERT_TRUE(received_callback);
+    EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
 
     // Now that we are started, we want to suddenly drop the RingBuffer connection.
     (void)ring_buffer_client.UnbindMaybeGetEndpoint();
@@ -1298,7 +1331,9 @@
 
     RunLoopUntilIdle();
     EXPECT_TRUE(received_callback);
+    EXPECT_FALSE(control_fidl_error_status().has_value()) << *control_fidl_error_status();
   }
+  EXPECT_FALSE(registry_fidl_error_status().has_value()) << *registry_fidl_error_status();
 }
 
 }  // namespace
diff --git a/src/media/audio/services/device_registry/ring_buffer_server_warning_unittest.cc b/src/media/audio/services/device_registry/ring_buffer_server_warning_unittest.cc
index db02af0..c0be7f4 100644
--- a/src/media/audio/services/device_registry/ring_buffer_server_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/ring_buffer_server_warning_unittest.cc
@@ -6,10 +6,8 @@
 #include <fidl/fuchsia.audio.device/cpp/markers.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <lib/fidl/cpp/wire/internal/transport_channel.h>
-#include <lib/syslog/cpp/macros.h>
 #include <lib/zx/clock.h>
 
-#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/common/testing/test_server_and_async_client.h"
@@ -23,7 +21,6 @@
 namespace media_audio {
 namespace {
 
-using ::testing::Optional;
 using Control = fuchsia_audio_device::Control;
 using RingBuffer = fuchsia_audio_device::RingBuffer;
 using DriverClient = fuchsia_audio_device::DriverClient;
@@ -75,51 +72,15 @@
  protected:
   std::shared_ptr<Device> EnableDriverAndAddDevice(
       const std::shared_ptr<FakeComposite>& fake_driver) {
-    auto device = Device::Create(adr_service_, dispatcher(), "Test composite name",
+    auto device = Device::Create(adr_service(), dispatcher(), "Test composite name",
                                  fuchsia_audio_device::DeviceType::kComposite,
                                  DriverClient::WithComposite(fake_driver->Enable()));
-    adr_service_->AddDevice(device);
+    adr_service()->AddDevice(device);
 
     RunLoopUntilIdle();
     return device;
   }
 
-  void PrepareRingBufferClientForNegativeTesting(const std::shared_ptr<FakeComposite>& fake_driver,
-                                                 ElementId element_id) {
-    fake_driver->ReserveRingBufferSize(element_id, 8192);
-    auto device = EnableDriverAndAddDevice(fake_driver);
-    auto format = SafeRingBufferFormatFromElementRingBufferFormatSets(
-        element_id, device->ring_buffer_format_sets());
-
-    auto registry = CreateTestRegistryServer();
-    auto token_id = WaitForAddedDeviceTokenId(registry->client());
-    ASSERT_TRUE(token_id);
-
-    auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
-    ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
-    auto control_ = CreateTestControlServer(added_device);
-
-    auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
-    bool received_callback = false;
-    control_->client()
-        ->CreateRingBuffer({{
-            element_id,
-            fuchsia_audio_device::RingBufferOptions{
-                {.format = format, .ring_buffer_min_bytes = 2000}},
-            std::move(ring_buffer_server_end),
-        }})
-        .Then([&received_callback](fidl::Result<Control::CreateRingBuffer>& result) {
-          EXPECT_TRUE(result.is_ok()) << result.error_value();
-          received_callback = true;
-        });
-
-    RunLoopUntilIdle();
-    ASSERT_TRUE(received_callback);
-    ring_buffer_client_ = std::move(ring_buffer_client);
-    EXPECT_TRUE(ring_buffer_client_.is_valid());
-    device_ = std::move(added_device);
-  }
-
   fidl::Client<fuchsia_audio_device::RingBuffer>& ring_buffer_client() {
     return ring_buffer_client_;
   }
@@ -142,7 +103,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -197,7 +158,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -252,7 +213,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -310,7 +271,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -370,7 +331,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -435,7 +396,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -485,7 +446,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -559,7 +520,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -637,7 +598,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control_ = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -704,9 +665,9 @@
 class RingBufferServerStreamConfigWarningTest : public RingBufferServerWarningTest {
  protected:
   void EnableDriverAndAddDevice(const std::shared_ptr<FakeStreamConfig>& fake_driver) {
-    adr_service_->AddDevice(Device::Create(adr_service_, dispatcher(), "Test input name",
-                                           fuchsia_audio_device::DeviceType::kInput,
-                                           DriverClient::WithStreamConfig(fake_driver->Enable())));
+    adr_service()->AddDevice(Device::Create(adr_service(), dispatcher(), "Test input name",
+                                            fuchsia_audio_device::DeviceType::kInput,
+                                            DriverClient::WithStreamConfig(fake_driver->Enable())));
 
     RunLoopUntilIdle();
   }
@@ -720,7 +681,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -768,7 +729,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -817,7 +778,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [status, added_device] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [status, added_device] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(status, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(added_device);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -871,7 +832,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -926,7 +887,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -987,7 +948,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -1031,7 +992,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -1094,7 +1055,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   EXPECT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
@@ -1160,7 +1121,7 @@
 
   auto token_id = WaitForAddedDeviceTokenId(registry->client());
   ASSERT_TRUE(token_id);
-  auto [presence, device_to_control] = adr_service_->FindDeviceByTokenId(*token_id);
+  auto [presence, device_to_control] = adr_service()->FindDeviceByTokenId(*token_id);
   ASSERT_EQ(presence, AudioDeviceRegistry::DevicePresence::Active);
   auto control = CreateTestControlServer(device_to_control);
   auto [ring_buffer_client, ring_buffer_server_end] = CreateRingBufferClient();
diff --git a/src/media/audio/services/device_registry/signal_processing_utils_unittest.cc b/src/media/audio/services/device_registry/signal_processing_utils_unittest.cc
index 4139176..a298f78 100644
--- a/src/media/audio/services/device_registry/signal_processing_utils_unittest.cc
+++ b/src/media/audio/services/device_registry/signal_processing_utils_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "src/media/audio/services/device_registry/signal_processing_utils.h"
 
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
+#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/common_types.h>
 
 #include <gtest/gtest.h>
 
diff --git a/src/media/audio/services/device_registry/signal_processing_utils_unittest.h b/src/media/audio/services/device_registry/signal_processing_utils_unittest.h
index 08503b4..f657b68 100644
--- a/src/media/audio/services/device_registry/signal_processing_utils_unittest.h
+++ b/src/media/audio/services/device_registry/signal_processing_utils_unittest.h
@@ -7,8 +7,6 @@
 
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/common_types.h>
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/common_types.h>
-#include <fidl/fuchsia.hardware.audio/cpp/natural_types.h>
 
 #include <vector>
 
diff --git a/src/media/audio/services/device_registry/signal_processing_utils_warning_unittest.cc b/src/media/audio/services/device_registry/signal_processing_utils_warning_unittest.cc
index daafc25..edcc991 100644
--- a/src/media/audio/services/device_registry/signal_processing_utils_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/signal_processing_utils_warning_unittest.cc
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
-#include <zircon/errors.h>
-
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/device_registry/signal_processing_utils.h"
diff --git a/src/media/audio/services/device_registry/testing/fake_codec.cc b/src/media/audio/services/device_registry/testing/fake_codec.cc
index d4f9662..c749ed8c 100644
--- a/src/media/audio/services/device_registry/testing/fake_codec.cc
+++ b/src/media/audio/services/device_registry/testing/fake_codec.cc
@@ -4,7 +4,6 @@
 
 #include "src/media/audio/services/device_registry/testing/fake_codec.h"
 
-#include <fidl/fuchsia.audio.device/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/markers.h>
 #include <fidl/fuchsia.hardware.audio/cpp/natural_types.h>
 #include <lib/fit/result.h>
@@ -84,6 +83,7 @@
 }
 
 void FakeCodec::GetHealthState(GetHealthStateCompleter::Sync& completer) {
+  ADR_LOG_METHOD(kLogFakeCodec);
   if (responsive_) {
     if (healthy_.has_value()) {
       completer.Reply(fuchsia_hardware_audio::HealthState{{healthy_.value()}});
@@ -93,7 +93,6 @@
   } else {
     health_completer_.emplace(completer.ToAsync());  // Just pend it; never respond.
   }
-  ADR_LOG_METHOD(kLogFakeCodec) << "exit";
 }
 
 void FakeCodec::SignalProcessingConnect(SignalProcessingConnectRequest& request,
@@ -135,7 +134,6 @@
   }
 
   completer.Reply(codec_properties);
-  ADR_LOG_METHOD(kLogFakeCodec) << "exit";
 }
 
 void FakeCodec::GetDaiFormats(GetDaiFormatsCompleter::Sync& completer) {
@@ -151,7 +149,6 @@
           .bits_per_sample = bits_per_sample_,
       }},
   }));
-  ADR_LOG_METHOD(kLogFakeCodec) << "exit";
 }
 
 bool FakeCodec::CheckDaiFormatSupported(const fuchsia_hardware_audio::DaiFormat& candidate) {
@@ -191,7 +188,6 @@
   }
 
   completer.Reply(fit::ok(info));
-  ADR_LOG_METHOD(kLogFakeCodec) << "exit";
 }
 
 void FakeCodec::Start(StartCompleter::Sync& completer) {
@@ -204,7 +200,6 @@
   }
 
   completer.Reply(mono_start_time_.get());
-  ADR_LOG_METHOD(kLogFakeCodec) << "exit";
 }
 
 void FakeCodec::Stop(StopCompleter::Sync& completer) {
@@ -216,7 +211,6 @@
   }
 
   completer.Reply(mono_stop_time_.get());
-  ADR_LOG_METHOD(kLogFakeCodec) << "exit";
 }
 
 void FakeCodec::Reset(ResetCompleter::Sync& completer) {
@@ -237,7 +231,6 @@
   // Reset all signalprocessing Elements and the signalprocessing Topology.
 
   completer.Reply();
-  ADR_LOG_METHOD(kLogFakeCodec) << "exit";
 }
 
 void FakeCodec::WatchPlugState(WatchPlugStateCompleter::Sync& completer) {
@@ -256,8 +249,6 @@
   } else {
     watch_plug_state_completer_ = completer.ToAsync();
   }
-
-  ADR_LOG_METHOD(kLogFakeCodec) << "exit";
 }
 
 void FakeCodec::InjectPluggedAt(zx::time plug_time) {
diff --git a/src/media/audio/services/device_registry/testing/fake_codec.h b/src/media/audio/services/device_registry/testing/fake_codec.h
index 23b0908c4..86f129a 100644
--- a/src/media/audio/services/device_registry/testing/fake_codec.h
+++ b/src/media/audio/services/device_registry/testing/fake_codec.h
@@ -10,14 +10,9 @@
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/test_base.h>
 #include <fidl/fuchsia.hardware.audio/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/test_base.h>
-#include <lib/async/cpp/time.h>
-#include <lib/fidl/cpp/binding_set.h>
-#include <lib/fpromise/result.h>
-#include <lib/fzl/vmo-mapper.h>
 #include <lib/syslog/cpp/macros.h>
 #include <lib/zx/channel.h>
 #include <lib/zx/time.h>
-#include <lib/zx/vmo.h>
 #include <zircon/errors.h>
 
 #include <cstring>
diff --git a/src/media/audio/services/device_registry/testing/fake_composite.cc b/src/media/audio/services/device_registry/testing/fake_composite.cc
index 3948a3b..bff8c25 100644
--- a/src/media/audio/services/device_registry/testing/fake_composite.cc
+++ b/src/media/audio/services/device_registry/testing/fake_composite.cc
@@ -13,7 +13,6 @@
 #include <zircon/errors.h>
 
 #include <string>
-#include <unordered_map>
 
 #include <gtest/gtest.h>
 
@@ -195,16 +194,20 @@
                                                         .state = kDestRbElementInitState}});
   elements_.insert({kSourceRbElementId, FakeElementRecord{.element = kSourceRbElement,
                                                           .state = kSourceRbElementInitState}});
+  elements_.insert(
+      {kMuteElementId, FakeElementRecord{.element = kMuteElement, .state = kMuteElementInitState}});
 
   ASSERT_TRUE(elements_.at(kSourceDaiElementId).state_has_changed);
   ASSERT_TRUE(elements_.at(kDestDaiElementId).state_has_changed);
   ASSERT_TRUE(elements_.at(kDestRbElementId).state_has_changed);
   ASSERT_TRUE(elements_.at(kSourceRbElementId).state_has_changed);
+  ASSERT_TRUE(elements_.at(kMuteElementId).state_has_changed);
 
   ASSERT_FALSE(elements_.at(kSourceDaiElementId).watch_completer.has_value());
   ASSERT_FALSE(elements_.at(kDestDaiElementId).watch_completer.has_value());
   ASSERT_FALSE(elements_.at(kDestRbElementId).watch_completer.has_value());
   ASSERT_FALSE(elements_.at(kSourceRbElementId).watch_completer.has_value());
+  ASSERT_FALSE(elements_.at(kMuteElementId).watch_completer.has_value());
 }
 
 void FakeComposite::GetHealthState(GetHealthStateCompleter::Sync& completer) {
@@ -380,25 +383,15 @@
 
   auto match_turn_on_delay = turn_on_delay_overrides_.find(element_id);
   if (match_turn_on_delay != turn_on_delay_overrides_.end()) {
-    FX_LOGS(INFO) << "Setting turn_on_delay to "
-                  << (match_turn_on_delay->second.has_value()
-                          ? (std::to_string(match_turn_on_delay->second->get()) + " ns")
-                          : "nullopt");
     match_turn_on_delay->second ? ring_buffer_impl->set_turn_on_delay(*match_turn_on_delay->second)
                                 : ring_buffer_impl->clear_turn_on_delay();
   }
   auto match_internal_delay = internal_delay_overrides_.find(element_id);
   if (match_internal_delay != internal_delay_overrides_.end()) {
-    FX_LOGS(INFO) << "Setting internal_delay to "
-                  << std::to_string(match_internal_delay->second.get()) + " ns";
     ring_buffer_impl->set_internal_delay(match_internal_delay->second);
   }
   auto match_external_delay = external_delay_overrides_.find(element_id);
   if (match_external_delay != external_delay_overrides_.end()) {
-    FX_LOGS(INFO) << "Setting external_delay to "
-                  << (match_external_delay->second.has_value()
-                          ? (std::to_string(match_external_delay->second->get()) + " ns")
-                          : "nullopt");
     match_external_delay->second
         ? ring_buffer_impl->set_external_delay(*match_external_delay->second)
         : ring_buffer_impl->clear_external_delay();
@@ -422,6 +415,7 @@
   if (element_id < kMinDaiElementId || element_id > kMaxDaiElementId) {
     ADR_WARN_METHOD() << "Element " << element_id << " is out of range";
     completer.Reply(fit::error(fuchsia_hardware_audio::DriverError::kInvalidArgs));
+    return;
   }
 
   auto dai_format_sets = kDefaultDaiFormatsMap.find(element_id);
@@ -576,7 +570,7 @@
 
   element.watch_completer = completer.ToAsync();
 
-  CheckForElementStateCompletion(element);
+  MaybeCompleteWatchElementState(element);
 }
 
 void FakeComposite::SetElementState(SetElementStateRequest& request,
@@ -599,7 +593,7 @@
     element_record.state = request.state();
     element_record.state_has_changed = true;
 
-    CheckForElementStateCompletion(element_record);
+    MaybeCompleteWatchElementState(element_record);
   }
 
   completer.Reply(fit::ok());
@@ -607,6 +601,7 @@
 
 void FakeComposite::InjectElementStateChange(
     ElementId element_id, fuchsia_hardware_audio_signalprocessing::ElementState new_state) {
+  ADR_LOG_METHOD(kLogFakeComposite) << "(" << element_id << ")";
   auto match = elements_.find(element_id);
   ASSERT_NE(match, elements_.end());
   auto& element = match->second;
@@ -614,18 +609,23 @@
   element.state = std::move(new_state);
   element.state_has_changed = true;
 
-  CheckForElementStateCompletion(element);
+  MaybeCompleteWatchElementState(element);
 }
 
 // static
-void FakeComposite::CheckForElementStateCompletion(FakeElementRecord& element_record) {
+void FakeComposite::MaybeCompleteWatchElementState(FakeElementRecord& element_record) {
   if (element_record.state_has_changed && element_record.watch_completer.has_value()) {
     auto completer = std::move(*element_record.watch_completer);
     element_record.watch_completer.reset();
 
     element_record.state_has_changed = false;
 
+    ADR_LOG_STATIC(kLogFakeComposite)
+        << "About to complete WatchElementState for element_id " << *element_record.element.id();
     completer.Reply(element_record.state);
+  } else {
+    ADR_LOG_STATIC(kLogFakeComposite)
+        << "Not completing WatchElementState for element_id " << *element_record.element.id();
   }
 }
 
@@ -640,7 +640,7 @@
 
   watch_topology_completer_ = completer.ToAsync();
 
-  CheckForTopologyCompletion();
+  MaybeCompleteWatchTopology();
 }
 
 void FakeComposite::SetTopology(SetTopologyRequest& request,
@@ -667,7 +667,7 @@
     topology_id_ = request.topology_id();
     topology_has_changed_ = true;
 
-    CheckForTopologyCompletion();
+    MaybeCompleteWatchTopology();
   }
   completer.Reply(fit::ok());
 }
@@ -679,20 +679,24 @@
   if (topology_has_changed_) {
     topology_id_ = *topology_id;
 
-    CheckForTopologyCompletion();
+    MaybeCompleteWatchTopology();
   } else {
     topology_id_.reset();  // A new `SetTopology` call must be made
   }
 }
 
-void FakeComposite::CheckForTopologyCompletion() {
+void FakeComposite::MaybeCompleteWatchTopology() {
   if (topology_id_.has_value() && topology_has_changed_ && watch_topology_completer_.has_value()) {
     auto completer = std::move(*watch_topology_completer_);
     watch_topology_completer_.reset();
 
     topology_has_changed_ = false;
 
+    ADR_LOG_STATIC(kLogFakeComposite)
+        << "About to complete WatchTopology with topology_id " << *topology_id_;
     completer.Reply(*topology_id_);
+  } else {
+    ADR_LOG_STATIC(kLogFakeComposite) << "Not completing WatchTopology";
   }
 }
 
diff --git a/src/media/audio/services/device_registry/testing/fake_composite.h b/src/media/audio/services/device_registry/testing/fake_composite.h
index 7864e6d..67e6f0b 100644
--- a/src/media/audio/services/device_registry/testing/fake_composite.h
+++ b/src/media/audio/services/device_registry/testing/fake_composite.h
@@ -9,14 +9,9 @@
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/test_base.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <fidl/fuchsia.hardware.audio/cpp/test_base.h>
-#include <lib/fidl/cpp/unified_messaging_declarations.h>
 #include <lib/fidl/cpp/wire/internal/transport_channel.h>
-#include <lib/fit/result.h>
-#include <lib/fzl/vmo-mapper.h>
 #include <lib/zx/channel.h>
-#include <lib/zx/clock.h>
 #include <zircon/errors.h>
-#include <zircon/time.h>
 
 #include <cstddef>
 #include <cstdint>
@@ -161,13 +156,16 @@
   static constexpr ElementId kMinRingBufferElementId = kDestRbElementId;
   static constexpr ElementId kMaxRingBufferElementId = kSourceRbElementId;
 
+  static constexpr ElementId kMuteElementId = 4;
+
   static constexpr ElementId kMinElementId = kSourceDaiElementId;
-  static constexpr ElementId kMaxElementId = kSourceRbElementId;
+  static constexpr ElementId kMaxElementId = kMuteElementId;
 
   static const fuchsia_hardware_audio_signalprocessing::Element kSourceDaiElement;
   static const fuchsia_hardware_audio_signalprocessing::Element kDestRbElement;
   static const fuchsia_hardware_audio_signalprocessing::Element kSourceRbElement;
   static const fuchsia_hardware_audio_signalprocessing::Element kDestDaiElement;
+  static const fuchsia_hardware_audio_signalprocessing::Element kMuteElement;
   static const fuchsia_hardware_audio_signalprocessing::Latency kSourceDaiElementLatency;
   static const fuchsia_hardware_audio_signalprocessing::Latency kDestRbElementLatency;
   static const fuchsia_hardware_audio_signalprocessing::Latency kSourceRbElementLatency;
@@ -176,20 +174,25 @@
   static const fuchsia_hardware_audio_signalprocessing::ElementState kDestRbElementInitState;
   static const fuchsia_hardware_audio_signalprocessing::ElementState kSourceRbElementInitState;
   static const fuchsia_hardware_audio_signalprocessing::ElementState kDestDaiElementInitState;
+  static const fuchsia_hardware_audio_signalprocessing::ElementState kMuteElementInitState;
   static const std::vector<fuchsia_hardware_audio_signalprocessing::Element> kElements;
 
   // For min/max checks based on ranges, keep this range contiguous.
   static constexpr TopologyId kInputOnlyTopologyId = 10;
   static constexpr TopologyId kFullDuplexTopologyId = 11;
   static constexpr TopologyId kOutputOnlyTopologyId = 12;
+  static constexpr TopologyId kOutputWithMuteTopologyId = 13;
   static constexpr TopologyId kMinTopologyId = kInputOnlyTopologyId;
-  static constexpr TopologyId kMaxTopologyId = kOutputOnlyTopologyId;
+  static constexpr TopologyId kMaxTopologyId = kOutputWithMuteTopologyId;
 
   static const fuchsia_hardware_audio_signalprocessing::EdgePair kTopologyInputEdgePair;
   static const fuchsia_hardware_audio_signalprocessing::EdgePair kTopologyOutputEdgePair;
+  static const fuchsia_hardware_audio_signalprocessing::EdgePair kTopologyRbToMuteEdgePair;
+  static const fuchsia_hardware_audio_signalprocessing::EdgePair kTopologyMuteToDaiEdgePair;
   static const fuchsia_hardware_audio_signalprocessing::Topology kInputOnlyTopology;
   static const fuchsia_hardware_audio_signalprocessing::Topology kFullDuplexTopology;
   static const fuchsia_hardware_audio_signalprocessing::Topology kOutputOnlyTopology;
+  static const fuchsia_hardware_audio_signalprocessing::Topology kOutputWithMuteTopology;
   static const std::vector<fuchsia_hardware_audio_signalprocessing::Topology> kTopologies;
 
   FakeComposite(zx::channel server_end, zx::channel client_end, async_dispatcher_t* dispatcher);
@@ -321,8 +324,8 @@
   static bool DaiFormatIsSupported(ElementId element_id,
                                    const fuchsia_hardware_audio::DaiFormat& format);
 
-  static void CheckForElementStateCompletion(FakeElementRecord& element_record);
-  void CheckForTopologyCompletion();
+  static void MaybeCompleteWatchElementState(FakeElementRecord& element_record);
+  void MaybeCompleteWatchTopology();
 
   async_dispatcher_t* dispatcher_;
   fidl::ServerEnd<fuchsia_hardware_audio::Composite> server_end_;
diff --git a/src/media/audio/services/device_registry/testing/fake_composite_consts.cc b/src/media/audio/services/device_registry/testing/fake_composite_consts.cc
index 9c84f7c..acf774f 100644
--- a/src/media/audio/services/device_registry/testing/fake_composite_consts.cc
+++ b/src/media/audio/services/device_registry/testing/fake_composite_consts.cc
@@ -202,16 +202,16 @@
     .can_disable = false,
     .description = "Endpoint::DaiInterconnect source element description",
 }};
-const fuchsia_hardware_audio_signalprocessing::Element FakeComposite::kDestRbElement{{
-    .id = kDestRbElementId,
+const fuchsia_hardware_audio_signalprocessing::Element FakeComposite::kDestDaiElement{{
+    .id = kDestDaiElementId,
     .type = fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint,
     .type_specific = fuchsia_hardware_audio_signalprocessing::TypeSpecificElement::WithEndpoint({{
-        .type = fuchsia_hardware_audio_signalprocessing::EndpointType::kRingBuffer,
+        .type = fuchsia_hardware_audio_signalprocessing::EndpointType::kDaiInterconnect,
         .plug_detect_capabilities =
-            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kHardwired,
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kCanAsyncNotify,
     }}),
     .can_disable = false,
-    .description = "Endpoint::RingBuffer destination element description",
+    .description = "Endpoint::DaiInterconnect destination element description",
 }};
 const fuchsia_hardware_audio_signalprocessing::Element FakeComposite::kSourceRbElement{{
     .id = kSourceRbElementId,
@@ -224,27 +224,33 @@
     .can_disable = false,
     .description = "Endpoint::RingBuffer source element description",
 }};
-const fuchsia_hardware_audio_signalprocessing::Element FakeComposite::kDestDaiElement{{
-    .id = kDestDaiElementId,
+const fuchsia_hardware_audio_signalprocessing::Element FakeComposite::kDestRbElement{{
+    .id = kDestRbElementId,
     .type = fuchsia_hardware_audio_signalprocessing::ElementType::kEndpoint,
     .type_specific = fuchsia_hardware_audio_signalprocessing::TypeSpecificElement::WithEndpoint({{
-        .type = fuchsia_hardware_audio_signalprocessing::EndpointType::kDaiInterconnect,
+        .type = fuchsia_hardware_audio_signalprocessing::EndpointType::kRingBuffer,
         .plug_detect_capabilities =
-            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kCanAsyncNotify,
+            fuchsia_hardware_audio_signalprocessing::PlugDetectCapabilities::kHardwired,
     }}),
     .can_disable = false,
-    .description = "Endpoint::DaiInterconnect destination element description",
+    .description = "Endpoint::RingBuffer destination element description",
+}};
+const fuchsia_hardware_audio_signalprocessing::Element FakeComposite::kMuteElement{{
+    .id = kMuteElementId,
+    .type = fuchsia_hardware_audio_signalprocessing::ElementType::kMute,
+    .can_disable = true,
+    .description = "Mute element description",
 }};
 
 // ElementStates - note that the two Dai endpoints have vendor_specific_data that can be queried.
 const fuchsia_hardware_audio_signalprocessing::Latency FakeComposite::kSourceDaiElementLatency =
     fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyTime(0);
-const fuchsia_hardware_audio_signalprocessing::Latency FakeComposite::kDestRbElementLatency =
-    fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyFrames(0);
-const fuchsia_hardware_audio_signalprocessing::Latency FakeComposite::kSourceRbElementLatency =
-    fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyFrames(1);
 const fuchsia_hardware_audio_signalprocessing::Latency FakeComposite::kDestDaiElementLatency =
     fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyTime(10417);
+const fuchsia_hardware_audio_signalprocessing::Latency FakeComposite::kSourceRbElementLatency =
+    fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyFrames(1);
+const fuchsia_hardware_audio_signalprocessing::Latency FakeComposite::kDestRbElementLatency =
+    fuchsia_hardware_audio_signalprocessing::Latency::WithLatencyFrames(0);
 const fuchsia_hardware_audio_signalprocessing::ElementState
     FakeComposite::kSourceDaiElementInitState{{
         .type_specific =
@@ -258,29 +264,6 @@
         .latency = kSourceDaiElementLatency,
         .vendor_specific_data = std::vector<uint8_t>{1, 2, 3, 4, 5, 6, 7, 8},
     }};
-const fuchsia_hardware_audio_signalprocessing::ElementState FakeComposite::kDestRbElementInitState{{
-    .type_specific =
-        fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::WithEndpoint({{
-            .plug_state = fuchsia_hardware_audio_signalprocessing::PlugState{{
-                .plugged = true,
-                .plug_state_time = ZX_TIME_INFINITE_PAST,
-            }},
-        }}),
-    .enabled = true,
-    .latency = kDestRbElementLatency,
-}};
-const fuchsia_hardware_audio_signalprocessing::ElementState
-    FakeComposite::kSourceRbElementInitState{{
-        .type_specific =
-            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::WithEndpoint({{
-                .plug_state = fuchsia_hardware_audio_signalprocessing::PlugState{{
-                    .plugged = true,
-                    .plug_state_time = ZX_TIME_INFINITE_PAST,
-                }},
-            }}),
-        .enabled = true,
-        .latency = kSourceRbElementLatency,
-    }};
 const fuchsia_hardware_audio_signalprocessing::ElementState FakeComposite::kDestDaiElementInitState{
     {
         .type_specific =
@@ -294,6 +277,32 @@
         .latency = kDestDaiElementLatency,
         .vendor_specific_data = std::vector<uint8_t>{8, 7, 6, 5, 4, 3, 2, 1, 0},
     }};
+const fuchsia_hardware_audio_signalprocessing::ElementState
+    FakeComposite::kSourceRbElementInitState{{
+        .type_specific =
+            fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::WithEndpoint({{
+                .plug_state = fuchsia_hardware_audio_signalprocessing::PlugState{{
+                    .plugged = true,
+                    .plug_state_time = ZX_TIME_INFINITE_PAST,
+                }},
+            }}),
+        .enabled = true,
+        .latency = kSourceRbElementLatency,
+    }};
+const fuchsia_hardware_audio_signalprocessing::ElementState FakeComposite::kDestRbElementInitState{{
+    .type_specific =
+        fuchsia_hardware_audio_signalprocessing::TypeSpecificElementState::WithEndpoint({{
+            .plug_state = fuchsia_hardware_audio_signalprocessing::PlugState{{
+                .plugged = true,
+                .plug_state_time = ZX_TIME_INFINITE_PAST,
+            }},
+        }}),
+    .enabled = true,
+    .latency = kDestRbElementLatency,
+}};
+const fuchsia_hardware_audio_signalprocessing::ElementState FakeComposite::kMuteElementInitState{{
+    .enabled = false,
+}};
 
 // Element set
 const std::vector<fuchsia_hardware_audio_signalprocessing::Element> FakeComposite::kElements{{
@@ -301,6 +310,7 @@
     kDestDaiElement,
     kSourceRbElement,
     kDestRbElement,
+    kMuteElement,
 }};
 
 // Topologies and element paths
@@ -314,6 +324,14 @@
     .processing_element_id_from = kSourceRbElementId,
     .processing_element_id_to = kDestDaiElementId,
 }};
+const fuchsia_hardware_audio_signalprocessing::EdgePair FakeComposite::kTopologyRbToMuteEdgePair{{
+    .processing_element_id_from = kSourceRbElementId,
+    .processing_element_id_to = kMuteElementId,
+}};
+const fuchsia_hardware_audio_signalprocessing::EdgePair FakeComposite::kTopologyMuteToDaiEdgePair{{
+    .processing_element_id_from = kMuteElementId,
+    .processing_element_id_to = kDestDaiElementId,
+}};
 
 // Individual topologies
 const fuchsia_hardware_audio_signalprocessing::Topology FakeComposite::kInputOnlyTopology{{
@@ -335,12 +353,20 @@
         kTopologyOutputEdgePair,
     }},
 }};
+const fuchsia_hardware_audio_signalprocessing::Topology FakeComposite::kOutputWithMuteTopology{{
+    .id = kOutputWithMuteTopologyId,
+    .processing_elements_edge_pairs = {{
+        kTopologyRbToMuteEdgePair,
+        kTopologyMuteToDaiEdgePair,
+    }},
+}};
 
 // Topology set
 const std::vector<fuchsia_hardware_audio_signalprocessing::Topology> FakeComposite::kTopologies{{
     kInputOnlyTopology,
     kFullDuplexTopology,
     kOutputOnlyTopology,
+    kOutputWithMuteTopology,
 }};
 
 }  // namespace media_audio
diff --git a/src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.cc b/src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.cc
index 43ece28..ae8b326 100644
--- a/src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.cc
+++ b/src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.cc
@@ -4,21 +4,14 @@
 
 #include "src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.h"
 
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/fidl.h>
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/test_base.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <fidl/fuchsia.hardware.audio/cpp/test_base.h>
-#include <lib/fidl/cpp/unified_messaging_declarations.h>
-#include <lib/fidl/cpp/wire/internal/transport_channel.h>
 #include <lib/fit/result.h>
 #include <lib/fzl/vmo-mapper.h>
-#include <lib/zx/channel.h>
 #include <lib/zx/clock.h>
 #include <zircon/errors.h>
-#include <zircon/time.h>
 
 #include <cstddef>
-#include <cstring>
 #include <optional>
 
 #include "src/media/audio/services/device_registry/basic_types.h"
diff --git a/src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.h b/src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.h
index da504f6..ce19e14 100644
--- a/src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.h
+++ b/src/media/audio/services/device_registry/testing/fake_composite_ring_buffer.h
@@ -5,28 +5,16 @@
 #ifndef SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_TESTING_FAKE_COMPOSITE_RING_BUFFER_H_
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_TESTING_FAKE_COMPOSITE_RING_BUFFER_H_
 
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/fidl.h>
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/test_base.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
 #include <fidl/fuchsia.hardware.audio/cpp/test_base.h>
-#include <lib/fidl/cpp/unified_messaging_declarations.h>
 #include <lib/fidl/cpp/wire/internal/transport_channel.h>
-#include <lib/fit/result.h>
-#include <lib/fzl/vmo-mapper.h>
-#include <lib/zx/channel.h>
-#include <lib/zx/clock.h>
-#include <zircon/errors.h>
-#include <zircon/time.h>
 
 #include <cstddef>
 #include <cstdint>
-#include <cstring>
-#include <memory>
 #include <optional>
 #include <string_view>
 
 #include "src/media/audio/services/device_registry/basic_types.h"
-#include "src/media/audio/services/device_registry/logging.h"
 
 namespace media_audio {
 
diff --git a/src/media/audio/services/device_registry/testing/fake_device_presence_watcher.h b/src/media/audio/services/device_registry/testing/fake_device_presence_watcher.h
index 9fb1125..7ebc543 100644
--- a/src/media/audio/services/device_registry/testing/fake_device_presence_watcher.h
+++ b/src/media/audio/services/device_registry/testing/fake_device_presence_watcher.h
@@ -5,9 +5,6 @@
 #ifndef SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_TESTING_FAKE_DEVICE_PRESENCE_WATCHER_H_
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_TESTING_FAKE_DEVICE_PRESENCE_WATCHER_H_
 
-#include <lib/fidl/cpp/wire/internal/transport.h>
-#include <lib/syslog/cpp/macros.h>
-
 #include <unordered_set>
 
 #include <gtest/gtest.h>
diff --git a/src/media/audio/services/device_registry/testing/fake_stream_config.cc b/src/media/audio/services/device_registry/testing/fake_stream_config.cc
index 0f3f502..22896c1 100644
--- a/src/media/audio/services/device_registry/testing/fake_stream_config.cc
+++ b/src/media/audio/services/device_registry/testing/fake_stream_config.cc
@@ -6,16 +6,12 @@
 
 #include <fuchsia/hardware/audio/cpp/fidl.h>
 #include <fuchsia/hardware/audio/signalprocessing/cpp/fidl.h>
-#include <lib/fidl/cpp/binding.h>
-#include <lib/fidl/cpp/unified_messaging_declarations.h>
 #include <lib/fidl/cpp/wire/channel.h>
 #include <lib/fpromise/result.h>
 #include <lib/syslog/cpp/macros.h>
 #include <lib/zx/clock.h>
-#include <lib/zx/result.h>
 #include <zircon/errors.h>
 
-#include <audio-proto-utils/format-utils.h>
 #include <gtest/gtest.h>
 
 #include "src/media/audio/services/device_registry/logging.h"
diff --git a/src/media/audio/services/device_registry/testing/fake_stream_config.h b/src/media/audio/services/device_registry/testing/fake_stream_config.h
index ad458af..0d81e879 100644
--- a/src/media/audio/services/device_registry/testing/fake_stream_config.h
+++ b/src/media/audio/services/device_registry/testing/fake_stream_config.h
@@ -7,12 +7,9 @@
 
 #include <fuchsia/hardware/audio/cpp/fidl.h>
 #include <fuchsia/hardware/audio/signalprocessing/cpp/fidl.h>
-#include <lib/async/cpp/time.h>
-#include <lib/fidl/cpp/binding_set.h>
+#include <lib/fidl/cpp/binding.h>
 #include <lib/fidl/cpp/wire/channel.h>
-#include <lib/fpromise/result.h>
 #include <lib/fzl/vmo-mapper.h>
-#include <lib/syslog/cpp/macros.h>
 #include <lib/zx/channel.h>
 #include <lib/zx/time.h>
 #include <lib/zx/vmo.h>
diff --git a/src/media/audio/services/device_registry/testing/stub_adr_server.cc b/src/media/audio/services/device_registry/testing/stub_adr_server.cc
index dbe381b..46e5481 100644
--- a/src/media/audio/services/device_registry/testing/stub_adr_server.cc
+++ b/src/media/audio/services/device_registry/testing/stub_adr_server.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
+// #include <fidl/fuchsia.audio.device/cpp/fidl.h>
+#include <fidl/fuchsia.audio.device/cpp/markers.h>
 #include <lib/async-loop/cpp/loop.h>
 #include <lib/async-loop/default.h>
 #include <lib/component/outgoing/cpp/outgoing_directory.h>
diff --git a/src/media/audio/services/device_registry/testing/stub_control_creator_server.h b/src/media/audio/services/device_registry/testing/stub_control_creator_server.h
index f89fd4c..0dfb007 100644
--- a/src/media/audio/services/device_registry/testing/stub_control_creator_server.h
+++ b/src/media/audio/services/device_registry/testing/stub_control_creator_server.h
@@ -6,8 +6,6 @@
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_TESTING_STUB_CONTROL_CREATOR_SERVER_H_
 
 #include <fidl/fuchsia.audio.device/cpp/fidl.h>
-#include <lib/fidl/cpp/wire/internal/transport_channel.h>
-#include <lib/fit/internal/result.h>
 #include <lib/syslog/cpp/macros.h>
 
 #include <memory>
diff --git a/src/media/audio/services/device_registry/testing/stub_provider_server.h b/src/media/audio/services/device_registry/testing/stub_provider_server.h
index ea5dab6..3977978 100644
--- a/src/media/audio/services/device_registry/testing/stub_provider_server.h
+++ b/src/media/audio/services/device_registry/testing/stub_provider_server.h
@@ -11,7 +11,6 @@
 #include <lib/syslog/cpp/macros.h>
 
 #include <memory>
-#include <optional>
 #include <string_view>
 
 #include "src/media/audio/services/common/base_fidl_server.h"
@@ -34,8 +33,10 @@
   // fuchsia.audio.device.Provider implementation
   void AddDevice(AddDeviceRequest& request, AddDeviceCompleter::Sync& completer) override {
     FX_LOGS(INFO) << kClassName << "::" << __FUNCTION__ << ": request to add "
-                  << request.device_type() << " '" << request.device_name().value_or("[missing]")
-                  << "'";
+                  << request.device_type() << " "
+                  << (request.device_name().has_value()
+                          ? std::string("'") + *request.device_name() + "'"
+                          : "");
 
     completer.Reply(fit::success(fuchsia_audio_device::ProviderAddDeviceResponse{}));
   }
diff --git a/src/media/audio/services/device_registry/testing/stub_registry_server.h b/src/media/audio/services/device_registry/testing/stub_registry_server.h
index 8ec2a73..bc1b38ac 100644
--- a/src/media/audio/services/device_registry/testing/stub_registry_server.h
+++ b/src/media/audio/services/device_registry/testing/stub_registry_server.h
@@ -10,9 +10,7 @@
 #include <lib/syslog/cpp/macros.h>
 
 #include <memory>
-#include <optional>
 #include <string_view>
-#include <utility>
 
 #include "src/media/audio/services/common/base_fidl_server.h"
 #include "src/media/audio/services/common/fidl_thread.h"
diff --git a/src/media/audio/services/device_registry/validate.cc b/src/media/audio/services/device_registry/validate.cc
index 84ef87f..d63877c 100644
--- a/src/media/audio/services/device_registry/validate.cc
+++ b/src/media/audio/services/device_registry/validate.cc
@@ -4,7 +4,6 @@
 
 #include "src/media/audio/services/device_registry/validate.h"
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/common_types.h>
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
@@ -21,10 +20,6 @@
 
 namespace media_audio {
 
-// Frame rates must be listed in ascending order, but some drivers don't do this.
-// TODO(https://fxbug.dev/42068180): once this is fixed, clean out this workaround.
-inline constexpr bool kStrictFrameRateOrdering = true;
-
 namespace {
 
 /////////////////////////////////////////////////////
@@ -1095,12 +1090,12 @@
   }
 
   for (const auto& element : elements) {
-    if (auto status = ValidateElement(element); status != true) {
+    if (auto status = ValidateElement(element); !status) {
       return status;
     }
   }
 
-  return (MapElements(elements).empty() ? false : true);
+  return (!MapElements(elements).empty());
 }
 
 bool ValidateTopology(const fuchsia_hardware_audio_signalprocessing::Topology& topology,
diff --git a/src/media/audio/services/device_registry/validate.h b/src/media/audio/services/device_registry/validate.h
index ea0c246..d877134 100644
--- a/src/media/audio/services/device_registry/validate.h
+++ b/src/media/audio/services/device_registry/validate.h
@@ -5,10 +5,10 @@
 #ifndef SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_VALIDATE_H_
 #define SRC_MEDIA_AUDIO_SERVICES_DEVICE_REGISTRY_VALIDATE_H_
 
-#include <fidl/fuchsia.audio.device/cpp/fidl.h>
+#include <fidl/fuchsia.audio.device/cpp/common_types.h>
+#include <fidl/fuchsia.audio.device/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/fidl.h>
-#include <zircon/types.h>
 
 #include <unordered_map>
 
diff --git a/src/media/audio/services/device_registry/validate_unittest.cc b/src/media/audio/services/device_registry/validate_unittest.cc
index 0beb375..e80c831 100644
--- a/src/media/audio/services/device_registry/validate_unittest.cc
+++ b/src/media/audio/services/device_registry/validate_unittest.cc
@@ -5,10 +5,8 @@
 #include "src/media/audio/services/device_registry/validate.h"
 
 #include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/common_types.h>
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/common_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/natural_types.h>
-#include <lib/syslog/cpp/macros.h>
 #include <lib/zx/clock.h>
 #include <lib/zx/vmo.h>
 #include <zircon/errors.h>
diff --git a/src/media/audio/services/device_registry/validate_warning_unittest.cc b/src/media/audio/services/device_registry/validate_warning_unittest.cc
index f073316..5b89418 100644
--- a/src/media/audio/services/device_registry/validate_warning_unittest.cc
+++ b/src/media/audio/services/device_registry/validate_warning_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <fidl/fuchsia.hardware.audio.signalprocessing/cpp/natural_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/common_types.h>
 #include <fidl/fuchsia.hardware.audio/cpp/natural_types.h>
 #include <lib/zx/clock.h>
diff --git a/src/media/audio/services/ffxdaemon/BUILD.gn b/src/media/audio/services/ffxdaemon/BUILD.gn
index 5a0af46..e3ce012 100644
--- a/src/media/audio/services/ffxdaemon/BUILD.gn
+++ b/src/media/audio/services/ffxdaemon/BUILD.gn
@@ -20,6 +20,7 @@
   with_unit_tests = true
 
   deps = [
+    "//sdk/fidl/fuchsia.audio:fuchsia.audio_rust",
     "//sdk/fidl/fuchsia.audio.controller:fuchsia.audio.controller_rust",
     "//sdk/fidl/fuchsia.audio.device:fuchsia.audio.device_rust",
     "//sdk/fidl/fuchsia.hardware.audio:fuchsia.hardware.audio_rust",
diff --git a/src/media/audio/services/ffxdaemon/meta/audio_ffx_daemon.cml b/src/media/audio/services/ffxdaemon/meta/audio_ffx_daemon.cml
index 568432c..5229a25 100644
--- a/src/media/audio/services/ffxdaemon/meta/audio_ffx_daemon.cml
+++ b/src/media/audio/services/ffxdaemon/meta/audio_ffx_daemon.cml
@@ -12,22 +12,21 @@
     },
     capabilities: [
         {
-            protocol: [ "fuchsia.audio.controller.DeviceControl" ],
-        },
-        {
-            protocol: [ "fuchsia.audio.controller.Player" ],
-        },
-        {
-            protocol: [ "fuchsia.audio.controller.Recorder" ],
+            protocol: [
+                "fuchsia.audio.controller.DeviceControl",
+                "fuchsia.audio.controller.Player",
+                "fuchsia.audio.controller.Recorder",
+            ],
         },
     ],
     use: [
         {
-            protocol: "fuchsia.media.Audio",
-            availability: "optional",
-        },
-        {
-            protocol: "fuchsia.ultrasound.Factory",
+            protocol: [
+                "fuchsia.audio.device.ControlCreator",
+                "fuchsia.audio.device.Registry",
+                "fuchsia.media.Audio",
+                "fuchsia.ultrasound.Factory",
+            ],
             availability: "optional",
         },
         {
@@ -48,15 +47,11 @@
     ],
     expose: [
         {
-            protocol: [ "fuchsia.audio.controller.DeviceControl" ],
-            from: "self",
-        },
-        {
-            protocol: [ "fuchsia.audio.controller.Player" ],
-            from: "self",
-        },
-        {
-            protocol: [ "fuchsia.audio.controller.Recorder" ],
+            protocol: [
+                "fuchsia.audio.controller.DeviceControl",
+                "fuchsia.audio.controller.Player",
+                "fuchsia.audio.controller.Recorder",
+            ],
             from: "self",
         },
     ],
diff --git a/src/media/audio/services/ffxdaemon/meta/audio_ffx_daemon.core_shard.cml b/src/media/audio/services/ffxdaemon/meta/audio_ffx_daemon.core_shard.cml
index eb6b00b..cdf4406 100644
--- a/src/media/audio/services/ffxdaemon/meta/audio_ffx_daemon.core_shard.cml
+++ b/src/media/audio/services/ffxdaemon/meta/audio_ffx_daemon.core_shard.cml
@@ -16,16 +16,22 @@
             to: "#audio_ffx_daemon",
         },
         {
-            protocol: [ "fuchsia.media.Audio" ],
+            protocol: [
+                "fuchsia.media.Audio",
+                "fuchsia.ultrasound.Factory",
+            ],
             from: "#audio_core",
-            to: [ "#audio_ffx_daemon" ],
+            to: "#audio_ffx_daemon",
             availability: "optional",
             source_availability: "unknown",
         },
         {
-            protocol: [ "fuchsia.ultrasound.Factory" ],
-            from: "#audio_core",
-            to: [ "#audio_ffx_daemon" ],
+            protocol: [
+                "fuchsia.audio.device.ControlCreator",
+                "fuchsia.audio.device.Registry",
+            ],
+            from: "#audio_device_registry",
+            to: "#audio_ffx_daemon",
             availability: "optional",
             source_availability: "unknown",
         },
diff --git a/src/media/audio/services/ffxdaemon/src/device.rs b/src/media/audio/services/ffxdaemon/src/device.rs
index f3545bd..c5679e6 100644
--- a/src/media/audio/services/ffxdaemon/src/device.rs
+++ b/src/media/audio/services/ffxdaemon/src/device.rs
@@ -4,7 +4,7 @@
 
 use crate::{
     error::ControllerError,
-    ring_buffer::{HardwareRingBuffer, RingBuffer},
+    ring_buffer::{AudioDeviceRingBuffer, HardwareRingBuffer, RingBuffer},
     wav_socket::WavSocket,
 };
 use anyhow::{anyhow, Context, Error};
@@ -15,14 +15,19 @@
 use fidl_fuchsia_hardware_audio as fhaudio;
 use fuchsia_audio::{
     device::{DevfsSelector, RegistrySelector, Selector},
-    format_set::PcmFormatSet,
     stop_listener, Format,
 };
-use fuchsia_component::client::connect_to_protocol_at_path;
+use fuchsia_component::client::{connect_to_protocol, connect_to_protocol_at_path};
 use fuchsia_zircon::{self as zx};
 use futures::{AsyncWriteExt, StreamExt};
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::time::Duration;
+use std::{
+    collections::{btree_map, BTreeMap},
+    sync::{
+        atomic::{AtomicBool, Ordering},
+        Arc, Mutex, Weak,
+    },
+    time::Duration,
+};
 
 // TODO(https://fxbug.dev/332322792): Replace with an integer conversion.
 const SECONDS_PER_NANOSECOND: f64 = 1.0 / 10_u64.pow(9) as f64;
@@ -30,75 +35,25 @@
 // TODO(https://fxbug.dev/317991807): Remove #[async_trait] when supported by compiler.
 #[async_trait]
 pub trait DeviceControl {
-    async fn get_properties(&mut self) -> Result<Properties, Error>;
-    async fn get_supported_formats(&mut self) -> Result<SupportedFormats, Error>;
-    async fn watch_gain_state(&mut self) -> Result<fhaudio::GainState, Error>;
-    async fn watch_plug_state(&mut self) -> Result<fhaudio::PlugState, Error>;
-    async fn create_ring_buffer(&mut self, format: Format) -> Result<Box<dyn RingBuffer>, Error>;
+    async fn create_ring_buffer(
+        &mut self,
+        element_id: fadevice::ElementId,
+        format: Format,
+    ) -> Result<Box<dyn RingBuffer>, Error>;
     fn set_gain(&mut self, gain_state: fhaudio::GainState) -> Result<(), Error>;
 }
 
-pub enum Properties {
-    StreamConfig(fhaudio::StreamProperties),
-    Composite(fhaudio::CompositeProperties),
-}
-
-pub struct SupportedFormats {
-    ring_buffer: Vec<PcmFormatSet>,
-    dai: Vec<fhaudio::DaiSupportedFormats>,
-}
-
 pub struct StreamConfigDevice {
     proxy: fhaudio::StreamConfigProxy,
 }
 
 #[async_trait]
 impl DeviceControl for StreamConfigDevice {
-    async fn get_properties(&mut self) -> Result<Properties, Error> {
-        let response = self
-            .proxy
-            .get_properties()
-            .await
-            .map_err(|e| anyhow!("Failed to get StreamConfig properties: {e}"))?;
-
-        Ok(Properties::StreamConfig(response))
-    }
-
-    async fn get_supported_formats(&mut self) -> Result<SupportedFormats, Error> {
-        let supported_formats = self
-            .proxy
-            .get_supported_formats()
-            .await
-            .map_err(|e| anyhow!("Could not query streamconfig supported formats: {e}"))?
-            .into_iter()
-            .map(PcmFormatSet::try_from)
-            .collect::<Result<Vec<_>, _>>()
-            .map_err(|err| anyhow!("Invalid supported format: {}", err))?;
-
-        Ok(SupportedFormats { ring_buffer: supported_formats, dai: vec![] })
-    }
-
-    async fn watch_gain_state(&mut self) -> Result<fhaudio::GainState, Error> {
-        let response = self
-            .proxy
-            .watch_gain_state()
-            .await
-            .map_err(|e| anyhow!("Could not query streamconfig gain state: {e}"))?;
-
-        Ok(response)
-    }
-
-    async fn watch_plug_state(&mut self) -> Result<fhaudio::PlugState, Error> {
-        let response = self
-            .proxy
-            .watch_plug_state()
-            .await
-            .map_err(|e| anyhow!("Could not query streamconfig plug state: {e}"))?;
-
-        Ok(response)
-    }
-
-    async fn create_ring_buffer(&mut self, format: Format) -> Result<Box<dyn RingBuffer>, Error> {
+    async fn create_ring_buffer(
+        &mut self,
+        _element_id: fadevice::ElementId,
+        format: Format,
+    ) -> Result<Box<dyn RingBuffer>, Error> {
         let (ring_buffer_proxy, ring_buffer_server) =
             create_proxy::<fhaudio::RingBufferMarker>().unwrap();
         self.proxy.create_ring_buffer(&fhaudio::Format::from(format), ring_buffer_server)?;
@@ -113,34 +68,16 @@
 }
 
 pub struct CompositeDevice {
-    pub proxy: fhaudio::CompositeProxy,
+    pub _proxy: fhaudio::CompositeProxy,
 }
 
 #[async_trait]
 impl DeviceControl for CompositeDevice {
-    async fn get_properties(&mut self) -> Result<Properties, Error> {
-        let response = self
-            .proxy
-            .get_properties()
-            .await
-            .map_err(|e| anyhow!("Failed to get Composite properties: {e}"))?;
-
-        Ok(Properties::Composite(response))
-    }
-
-    async fn get_supported_formats(&mut self) -> Result<SupportedFormats, Error> {
-        Err(anyhow!("Supported formats for Composite devices not yet supported yet in ffx audio."))
-    }
-
-    async fn watch_gain_state(&mut self) -> Result<fhaudio::GainState, Error> {
-        Err(anyhow!("watch gain state for Composite devices not supported yet in ffx audio."))
-    }
-
-    async fn watch_plug_state(&mut self) -> Result<fhaudio::PlugState, Error> {
-        Err(anyhow!("watch plug state for Composite devices not supported yet in ffx audio."))
-    }
-
-    async fn create_ring_buffer(&mut self, _format: Format) -> Result<Box<dyn RingBuffer>, Error> {
+    async fn create_ring_buffer(
+        &mut self,
+        _element_id: fadevice::ElementId,
+        _format: Format,
+    ) -> Result<Box<dyn RingBuffer>, Error> {
         Err(anyhow!("Creating ring buffers for Composite devices not supported yet in ffx audio."))
     }
 
@@ -151,25 +88,63 @@
     }
 }
 
-fn validate_format(
-    requested_format: Format,
-    supported_formats: SupportedFormats,
-) -> Result<(), ControllerError> {
-    if !supported_formats
-        .ring_buffer
-        .iter()
-        .any(|pcm_format_set| pcm_format_set.supports(&requested_format))
-    {
-        return Err(ControllerError::new(
-            fac::Error::InvalidArguments,
-            format!("Requested format not supported."),
-        ));
+pub struct RegistryDevice {
+    proxy: fadevice::ControlProxy,
+}
+
+impl RegistryDevice {
+    fn new(proxy: fadevice::ControlProxy) -> Self {
+        Self { proxy }
     }
-    Ok(())
+}
+
+#[async_trait]
+impl DeviceControl for RegistryDevice {
+    async fn create_ring_buffer(
+        &mut self,
+        element_id: fadevice::ElementId,
+        format: Format,
+    ) -> Result<Box<dyn RingBuffer>, Error> {
+        let (ring_buffer_proxy, ring_buffer_server) =
+            create_proxy::<fadevice::RingBufferMarker>().unwrap();
+
+        // Request at least 100ms worth of frames.
+        let min_frames = format.frames_per_second / 10;
+        let min_bytes = min_frames * format.bytes_per_frame();
+
+        let options = fadevice::RingBufferOptions {
+            format: Some(format.into()),
+            ring_buffer_min_bytes: Some(min_bytes),
+            ..Default::default()
+        };
+
+        let response = self
+            .proxy
+            .create_ring_buffer(fadevice::ControlCreateRingBufferRequest {
+                element_id: Some(element_id),
+                options: Some(options),
+                ring_buffer_server: Some(ring_buffer_server),
+                ..Default::default()
+            })
+            .await
+            .context("Failed to call CreateRingBuffer")?
+            .map_err(|err| anyhow!("Failed to create ring buffer: {err:?}"))?;
+        let properties = response.properties.ok_or_else(|| anyhow!("missing 'properties'"))?;
+        let ring_buffer = response.ring_buffer.ok_or_else(|| anyhow!("missing 'ring_buffer'"))?;
+
+        let ring_buffer =
+            AudioDeviceRingBuffer::new(ring_buffer_proxy, ring_buffer, properties, format).await?;
+
+        Ok(Box::new(ring_buffer))
+    }
+
+    fn set_gain(&mut self, _gain_state: fhaudio::GainState) -> Result<(), Error> {
+        Err(anyhow!("set gain is not supported for Registry devices"))
+    }
 }
 
 /// Connects to the device protocol for a device in devfs.
-pub fn connect_to_devfs(devfs: DevfsSelector) -> Result<Box<dyn DeviceControl>, Error> {
+fn connect_to_devfs_device(devfs: DevfsSelector) -> Result<Box<dyn DeviceControl>, Error> {
     let protocol_path = devfs.path().join("device_protocol");
 
     match devfs.0.device_type {
@@ -191,90 +166,117 @@
                 connect_to_protocol_at_path::<fhaudio::CompositeMarker>(protocol_path.as_str())
                     .context("Failed to connect to Composite")?;
 
-            Ok(Box::new(CompositeDevice { proxy }))
+            Ok(Box::new(CompositeDevice { _proxy: proxy }))
         }
         _ => Err(anyhow!("Unsupported DeviceType for connect_to_device_controller()")),
     }
 }
 
-fn connect_to_registry(_selector: RegistrySelector) -> Result<Box<dyn DeviceControl>, Error> {
-    Err(anyhow!("TODO(https://fxbug.dev/329150383) ffx audio supports fuchsia.audio (ADR) devices"))
+async fn connect_to_registry_device(
+    selector: RegistrySelector,
+) -> Result<Box<dyn DeviceControl>, Error> {
+    let control_creator = connect_to_protocol::<fadevice::ControlCreatorMarker>()
+        .context("Failed to connect to ControlCreator")?;
+
+    let (proxy, server_end) = create_proxy::<fadevice::ControlMarker>().unwrap();
+
+    control_creator
+        .create(fadevice::ControlCreatorCreateRequest {
+            token_id: Some(selector.token_id()),
+            control_server: Some(server_end),
+            ..Default::default()
+        })
+        .await
+        .context("failed to call ControlCreator.Create")?
+        .map_err(|err| anyhow!("failed to create Control: {:?}", err))?;
+
+    Ok(Box::new(RegistryDevice::new(proxy)))
+}
+
+async fn connect_device_control(
+    selector: Selector,
+) -> Result<Box<dyn DeviceControl>, ControllerError> {
+    match selector {
+        Selector::Devfs(selector) => connect_to_devfs_device(selector),
+        Selector::Registry(selector) => connect_to_registry_device(selector).await,
+    }
+    .map_err(|err| {
+        ControllerError::new(
+            fac::Error::DeviceNotReachable,
+            format!("Failed to connect to device with error: {err}"),
+        )
+    })
+}
+
+pub struct DeviceControlConnector {
+    device_controls: BTreeMap<Selector, Weak<Mutex<Box<dyn DeviceControl>>>>,
+}
+
+impl DeviceControlConnector {
+    pub fn new() -> Self {
+        Self { device_controls: BTreeMap::new() }
+    }
+
+    /// Returns a [DeviceControl] connection to the device identified by `selector`.
+    ///
+    /// If the connection already exists from a previous call to `connect`, returns
+    /// the existing shared [DeviceControl]. Otherwise, creates a new connection,
+    /// stores it for subsequent calls, and return it.
+    pub async fn connect(
+        &mut self,
+        selector: Selector,
+    ) -> Result<Arc<Mutex<Box<dyn DeviceControl>>>, ControllerError> {
+        match self.device_controls.entry(selector) {
+            btree_map::Entry::Vacant(entry) => {
+                let selector = entry.key().clone();
+                let device_control = Arc::new(Mutex::new(connect_device_control(selector).await?));
+                let _ = entry.insert(Arc::downgrade(&device_control));
+                Ok(device_control)
+            }
+            btree_map::Entry::Occupied(mut entry) => {
+                match entry.get().upgrade() {
+                    Some(device_control) => Ok(device_control),
+                    None => {
+                        let selector = entry.key().clone();
+                        let device_control =
+                            Arc::new(Mutex::new(connect_device_control(selector).await?));
+                        // Replace with a live connection.
+                        let _ = entry.insert(Arc::downgrade(&device_control));
+                        Ok(device_control)
+                    }
+                }
+            }
+        }
+    }
 }
 
 pub struct Device {
-    pub device_controller: Box<dyn DeviceControl>,
+    pub device_controller: Arc<Mutex<Box<dyn DeviceControl>>>,
 }
 
 impl Device {
-    pub fn new_from_selector(selector: Selector) -> Result<Self, Error> {
-        let device_controller = match selector {
-            Selector::Devfs(selector) => connect_to_devfs(selector)?,
-            Selector::Registry(selector) => connect_to_registry(selector)?,
-        };
-        Ok(Self { device_controller })
-    }
-
-    pub async fn get_info(&mut self) -> Result<fac::DeviceInfo, Error> {
-        let properties = self.device_controller.get_properties().await?;
-
-        match properties {
-            Properties::StreamConfig(stream_properties) => {
-                let supported_formats =
-                    self.device_controller.get_supported_formats().await.ok().map(
-                        |supported_formats| {
-                            supported_formats.ring_buffer.into_iter().map(Into::into).collect()
-                        },
-                    );
-
-                let gain_state = self.device_controller.watch_gain_state().await.ok();
-                let plug_state = self.device_controller.watch_plug_state().await.ok();
-                Ok(fac::DeviceInfo::StreamConfig(fac::StreamConfigDeviceInfo {
-                    stream_properties: Some(stream_properties),
-                    supported_formats,
-                    gain_state,
-                    plug_state,
-                    ..Default::default()
-                }))
-            }
-            Properties::Composite(composite_properties) => {
-                let (supported_ring_buffer_formats, supported_dai_formats) =
-                    self.device_controller.get_supported_formats().await.ok().map_or(
-                        (None, None),
-                        |supported_formats| {
-                            let ring_buffer =
-                                supported_formats.ring_buffer.into_iter().map(Into::into).collect();
-                            let dai = supported_formats.dai;
-                            (Some(ring_buffer), Some(dai))
-                        },
-                    );
-
-                Ok(fac::DeviceInfo::Composite(fac::CompositeDeviceInfo {
-                    composite_properties: Some(composite_properties),
-                    supported_dai_formats,
-                    supported_ring_buffer_formats,
-                    ..Default::default()
-                }))
-            }
-        }
+    pub fn new(device_controller: Arc<Mutex<Box<dyn DeviceControl>>>) -> Self {
+        Self { device_controller }
     }
 
     pub fn set_gain(&mut self, gain_state: fhaudio::GainState) -> Result<(), Error> {
         self.device_controller
+            .lock()
+            .unwrap()
             .set_gain(gain_state)
             .map_err(|e| anyhow!("Error setting device gain state: {e}"))
     }
 
     pub async fn play(
         &mut self,
+        element_id: fadevice::ElementId,
         mut socket: WavSocket,
     ) -> Result<fac::PlayerPlayResponse, ControllerError> {
         let spec = socket.read_header().await?;
         let format = Format::from(spec);
 
-        let supported_formats = self.device_controller.get_supported_formats().await?;
-        validate_format(format, supported_formats)?;
-
-        let ring_buffer = self.device_controller.create_ring_buffer(format).await?;
+        let ring_buffer =
+            self.device_controller.lock().unwrap().create_ring_buffer(element_id, format).await?;
 
         let mut silenced_frames = 0u64;
         let mut late_wakeups = 0;
@@ -427,15 +429,14 @@
 
     pub async fn record(
         &mut self,
+        element_id: fadevice::ElementId,
         format: Format,
         mut socket: WavSocket,
         duration: Option<Duration>,
         cancel_server: Option<ServerEnd<fac::RecordCancelerMarker>>,
     ) -> Result<fac::RecorderRecordResponse, ControllerError> {
-        let supported_formats = self.device_controller.get_supported_formats().await?;
-        validate_format(format, supported_formats)?;
-
-        let ring_buffer = self.device_controller.create_ring_buffer(format).await?;
+        let ring_buffer =
+            self.device_controller.lock().unwrap().create_ring_buffer(element_id, format).await?;
 
         // Hardware might not use all bytes in vmo. Only want to read frames hardware will write to.
         let bytes_in_rb = ring_buffer.vmo_buffer().data_size_bytes();
diff --git a/src/media/audio/services/ffxdaemon/src/main.rs b/src/media/audio/services/ffxdaemon/src/main.rs
index ace5253..ec75a95 100644
--- a/src/media/audio/services/ffxdaemon/src/main.rs
+++ b/src/media/audio/services/ffxdaemon/src/main.rs
@@ -11,7 +11,7 @@
 mod wav_socket;
 
 use capturer::Capturer;
-use device::Device;
+use device::{Device, DeviceControlConnector};
 use renderer::Renderer;
 use wav_socket::WavSocket;
 
@@ -22,9 +22,11 @@
 use fuchsia_audio::{device::Selector, Format};
 use fuchsia_component::server::ServiceFs;
 use fuchsia_inspect::{component, health::Reporter};
-use fuchsia_zircon as zx;
 use futures::{StreamExt, TryStreamExt};
-use std::time::Duration;
+use std::{
+    sync::{Arc, Mutex},
+    time::Duration,
+};
 use tracing::error;
 
 /// Wraps all hosted protocols into a single type that can be matched against and dispatched.
@@ -35,6 +37,7 @@
 }
 
 pub async fn handle_play_request(
+    device_control_connector: Arc<Mutex<DeviceControlConnector>>,
     request: fac::PlayerPlayRequest,
 ) -> Result<fac::PlayerPlayResponse, ControllerError> {
     let destination = request.destination.ok_or_else(|| {
@@ -62,7 +65,10 @@
 
             renderer.play(wav_socket).await
         }
-        fac::PlayDestination::DeviceRingBuffer(fidl_selector) => {
+        fac::PlayDestination::DeviceRingBuffer(fac::DeviceRingBuffer {
+            selector: fidl_selector,
+            ring_buffer_element_id,
+        }) => {
             let selector = Selector::try_from(fidl_selector).map_err(|msg| {
                 ControllerError::new(
                     fac::Error::InvalidArguments,
@@ -70,13 +76,10 @@
                 )
             })?;
 
-            let mut device = Device::new_from_selector(selector).map_err(|err| {
-                ControllerError::new(
-                    fac::Error::DeviceNotReachable,
-                    format!("Failed to connect to device with error: {err}"),
-                )
-            })?;
-            device.play(wav_socket).await
+            let device_control = device_control_connector.lock().unwrap().connect(selector).await?;
+            let mut device = Device::new(device_control);
+
+            device.play(ring_buffer_element_id, wav_socket).await
         }
         fac::PlayDestinationUnknown!() => Err(ControllerError::new(
             fac::Error::InvalidArguments,
@@ -85,12 +88,15 @@
     }
 }
 
-async fn serve_player(mut stream: fac::PlayerRequestStream) -> Result<(), Error> {
+async fn serve_player(
+    device_control_connector: Arc<Mutex<DeviceControlConnector>>,
+    mut stream: fac::PlayerRequestStream,
+) -> Result<(), Error> {
     while let Ok(Some(request)) = stream.try_next().await {
         let request_name = request.method_name();
         match request {
             fac::PlayerRequest::Play { payload, responder } => {
-                let result = handle_play_request(payload).await;
+                let result = handle_play_request(device_control_connector.clone(), payload).await;
 
                 if let Err(ref err) = result {
                     error!(%err, "Failed to play");
@@ -104,6 +110,7 @@
 }
 
 pub async fn handle_record_request(
+    device_control_connector: Arc<Mutex<DeviceControlConnector>>,
     request: fac::RecorderRecordRequest,
 ) -> Result<fac::RecorderRecordResponse, ControllerError> {
     let source = request.source.ok_or_else(|| {
@@ -134,7 +141,10 @@
 
             capturer.record(wav_socket, duration, request.canceler, request.buffer_size).await
         }
-        fac::RecordSource::DeviceRingBuffer(fidl_selector) => {
+        fac::RecordSource::DeviceRingBuffer(fac::DeviceRingBuffer {
+            selector: fidl_selector,
+            ring_buffer_element_id,
+        }) => {
             let selector = Selector::try_from(fidl_selector).map_err(|msg| {
                 ControllerError::new(
                     fac::Error::InvalidArguments,
@@ -142,14 +152,12 @@
                 )
             })?;
 
-            let mut device = Device::new_from_selector(selector).map_err(|err| {
-                ControllerError::new(
-                    fac::Error::DeviceNotReachable,
-                    format!("Failed to connect to device with error: {err}"),
-                )
-            })?;
+            let device_control = device_control_connector.lock().unwrap().connect(selector).await?;
+            let mut device = Device::new(device_control);
 
-            device.record(format, wav_socket, duration, request.canceler).await
+            device
+                .record(ring_buffer_element_id, format, wav_socket, duration, request.canceler)
+                .await
         }
         fac::RecordSourceUnknown!() => {
             Err(ControllerError::new(fac::Error::InvalidArguments, format!("Unknown RecordSource")))
@@ -157,12 +165,15 @@
     }
 }
 
-async fn serve_recorder(mut stream: fac::RecorderRequestStream) -> Result<(), Error> {
+async fn serve_recorder(
+    device_control_connector: Arc<Mutex<DeviceControlConnector>>,
+    mut stream: fac::RecorderRequestStream,
+) -> Result<(), Error> {
     while let Ok(Some(request)) = stream.try_next().await {
         let request_name = request.method_name();
         match request {
             fac::RecorderRequest::Record { payload, responder } => {
-                let result = handle_record_request(payload).await;
+                let result = handle_record_request(device_control_connector.clone(), payload).await;
 
                 if let Err(ref err) = result {
                     error!(%err, "Failed to record");
@@ -176,38 +187,13 @@
 }
 
 // TODO(b/298683668) this will be removed, replaced by client direct calls.
-async fn serve_device_control(mut stream: fac::DeviceControlRequestStream) -> Result<(), Error> {
+async fn serve_device_control(
+    device_control_connector: Arc<Mutex<DeviceControlConnector>>,
+    mut stream: fac::DeviceControlRequestStream,
+) -> Result<(), Error> {
     while let Ok(Some(request)) = stream.try_next().await {
         let request_name = request.method_name();
         let request_result = match request {
-            fac::DeviceControlRequest::GetDeviceInfo { payload, responder } => {
-                let selector: Selector = payload
-                    .device
-                    .ok_or(anyhow!("No device specified"))?
-                    .try_into()
-                    .map_err(|msg| anyhow!("invalid selector: {msg}"))?;
-
-                let mut device = device::Device::new_from_selector(selector)?;
-
-                let info = device.get_info().await;
-                match info {
-                    Ok(info) => {
-                        let response = fac::DeviceControlGetDeviceInfoResponse {
-                            device_info: Some(info),
-                            ..Default::default()
-                        };
-                        responder
-                            .send(Ok(response))
-                            .map_err(|e| anyhow!("Error sending response: {e}"))
-                    }
-                    Err(e) => {
-                        println!("Could not connect to device. {e}");
-                        responder
-                            .send(Err(zx::Status::INTERNAL.into_raw()))
-                            .map_err(|e| anyhow!("Error sending response: {e}"))
-                    }
-                }
-            }
             fac::DeviceControlRequest::DeviceSetGainState { payload, responder } => {
                 let selector = payload
                     .device
@@ -216,7 +202,9 @@
                     .map_err(|msg| anyhow!("invalid selector: {msg}"))?;
                 let gain_state = payload.gain_state.ok_or(anyhow!("No gain state specified"))?;
 
-                let mut device = device::Device::new_from_selector(selector)?;
+                let device_control =
+                    device_control_connector.lock().unwrap().connect(selector).await?;
+                let mut device = Device::new(device_control);
 
                 device.set_gain(gain_state)?;
                 responder.send(Ok(())).map_err(|e| anyhow!("Error sending response: {e}"))
@@ -253,22 +241,29 @@
 
     component::health().set_ok();
 
+    let device_control_connector = Arc::new(Mutex::new(DeviceControlConnector::new()));
+
     service_fs
-        .for_each_concurrent(None, |request: IncomingRequest| async {
-            match request {
-                IncomingRequest::DeviceControl(stream) => {
-                    if let Err(err) = serve_device_control(stream).await {
-                        error!(%err, "Failed to serve DeviceControl protocol");
+        .for_each_concurrent(None, |request: IncomingRequest| {
+            let device_control_connector = device_control_connector.clone();
+            async {
+                match request {
+                    IncomingRequest::DeviceControl(stream) => {
+                        if let Err(err) =
+                            serve_device_control(device_control_connector, stream).await
+                        {
+                            error!(%err, "Failed to serve DeviceControl protocol");
+                        }
                     }
-                }
-                IncomingRequest::Player(stream) => {
-                    if let Err(err) = serve_player(stream).await {
-                        error!(%err, "Failed to serve Player protocol");
+                    IncomingRequest::Player(stream) => {
+                        if let Err(err) = serve_player(device_control_connector, stream).await {
+                            error!(%err, "Failed to serve Player protocol");
+                        }
                     }
-                }
-                IncomingRequest::Recorder(stream) => {
-                    if let Err(err) = serve_recorder(stream).await {
-                        error!(%err, "Failed to serve Recorder protocol");
+                    IncomingRequest::Recorder(stream) => {
+                        if let Err(err) = serve_recorder(device_control_connector, stream).await {
+                            error!(%err, "Failed to serve Recorder protocol");
+                        }
                     }
                 }
             }
diff --git a/src/media/audio/services/ffxdaemon/src/ring_buffer.rs b/src/media/audio/services/ffxdaemon/src/ring_buffer.rs
index 8b9ff90..649b743 100644
--- a/src/media/audio/services/ffxdaemon/src/ring_buffer.rs
+++ b/src/media/audio/services/ffxdaemon/src/ring_buffer.rs
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use anyhow::{anyhow, Context};
+use anyhow::{anyhow, bail, Context};
 use async_trait::async_trait;
+use fidl_fuchsia_audio as faudio;
+use fidl_fuchsia_audio_device as fadevice;
 use fidl_fuchsia_hardware_audio as fhaudio;
 use fuchsia_audio::Format;
 use fuchsia_runtime::vmar_root_self;
@@ -34,8 +36,8 @@
 /// A [RingBuffer] backed by the `fuchsia.hardware.audio.RingBuffer` protocol.
 pub struct HardwareRingBuffer {
     proxy: fhaudio::RingBufferProxy,
-    pub vmo_buffer: VmoBuffer,
-    pub driver_transfer_bytes: u64,
+    vmo_buffer: VmoBuffer,
+    driver_transfer_bytes: u64,
 }
 
 impl HardwareRingBuffer {
@@ -90,6 +92,80 @@
     }
 }
 
+/// A [RingBuffer] backed by the `fuchsia.audio.device.RingBuffer` protocol.
+pub struct AudioDeviceRingBuffer {
+    proxy: fadevice::RingBufferProxy,
+    vmo_buffer: VmoBuffer,
+    producer_bytes: u64,
+    consumer_bytes: u64,
+}
+
+impl AudioDeviceRingBuffer {
+    pub async fn new(
+        proxy: fadevice::RingBufferProxy,
+        ring_buffer: faudio::RingBuffer,
+        _properties: fadevice::RingBufferProperties,
+        format: Format,
+    ) -> Result<Self, anyhow::Error> {
+        let producer_bytes =
+            ring_buffer.producer_bytes.ok_or_else(|| anyhow!("missing 'producer_bytes'"))?;
+        let consumer_bytes =
+            ring_buffer.consumer_bytes.ok_or_else(|| anyhow!("missing 'consumer_bytes'"))?;
+        let buffer = ring_buffer.buffer.ok_or_else(|| anyhow!("missing 'buffer'"))?;
+
+        let rb_format: Format = ring_buffer
+            .format
+            .clone()
+            .ok_or_else(|| anyhow!("missing 'format'"))?
+            .try_into()
+            .map_err(|err| anyhow!("invalid ring buffer format: {}", err))?;
+        if rb_format != format {
+            bail!("requested format {} does not match ring buffer format {}", format, rb_format);
+        }
+
+        let num_frames = buffer.size / (format.bytes_per_frame() as u64);
+        let vmo_buffer = VmoBuffer::new(buffer.vmo, num_frames, format)?;
+
+        Ok(Self { proxy, vmo_buffer, producer_bytes, consumer_bytes })
+    }
+}
+
+#[async_trait]
+impl RingBuffer for AudioDeviceRingBuffer {
+    async fn start(&self) -> Result<zx::Time, anyhow::Error> {
+        let response = self
+            .proxy
+            .start(&Default::default())
+            .await
+            .context("failed to call Start")?
+            .map_err(|err| anyhow!("failed to start ring buffer: {:?}", err))?;
+        let start_time = response.start_time.ok_or_else(|| anyhow!("missing 'start_time'"))?;
+        Ok(zx::Time::from_nanos(start_time))
+    }
+
+    async fn stop(&self) -> Result<(), anyhow::Error> {
+        let _ = self
+            .proxy
+            .stop(&Default::default())
+            .await
+            .context("failed to call Stop")?
+            .map_err(|err| anyhow!("failed to stop ring buffer: {:?}", err))?;
+        Ok(())
+    }
+
+    fn vmo_buffer(&self) -> &VmoBuffer {
+        &self.vmo_buffer
+    }
+
+    fn producer_bytes(&self) -> u64 {
+        self.producer_bytes
+    }
+
+    fn consumer_bytes(&self) -> u64 {
+        self.consumer_bytes
+    }
+}
+
 #[derive(Error, Debug)]
 pub enum VmoBufferError {
     #[error("VMO is too small ({vmo_size_bytes} bytes) to hold ring buffer data ({data_size_bytes} bytes)")]
diff --git a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.cc b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.cc
index 07acf07..b434778 100644
--- a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.cc
+++ b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.cc
@@ -141,13 +141,13 @@
     // which holds the current picture size since the height is based on the current picture size
     // and the width is based on the overall surface stride.
     //
-    // TODO(https://fxbug.dev/42073228): We should consider making the created surface only as big as needed
-    // to hold the image generated by |coded_picture_size_| instead of the the current size of the
-    // surface. This would require that we inform the client that update |bytes_per_row| to reflect
-    // the current size of the smaller surface. The below method works fine, we do end up create an
-    // image backed by a surface that can be larger than |coded_picture_size_| which will increase
-    // the amount of time to deswizzle and copy to our VMO since we will end up copying junk data in
-    // the DPB that was not a part of the current decode operation.
+    // TODO(https://fxbug.dev/42073228): We should consider making the created surface only as big
+    // as needed to hold the image generated by |coded_picture_size_| instead of the the current
+    // size of the surface. This would require that we inform the client that update |bytes_per_row|
+    // to reflect the current size of the smaller surface. The below method works fine, we do end up
+    // create an image backed by a surface that can be larger than |coded_picture_size_| which will
+    // increase the amount of time to deswizzle and copy to our VMO since we will end up copying
+    // junk data in the DPB that was not a part of the current decode operation.
     auto aligned_stride_checked = safemath::MakeCheckedNum(surface_size.width()).Cast<uint32_t>();
     auto aligned_y_height = safemath::checked_cast<uint32_t>(coded_picture_size_.height());
     auto aligned_uv_height = safemath::checked_cast<uint32_t>(coded_picture_size_.height()) / 2u;
@@ -376,11 +376,11 @@
 
     // Create the new number for requested DBP surfaces at the picture size.
     //
-    // TODO(https://fxbug.dev/42073230): Consider only replacing amount of unused surfaces in |dpb_surfaces_|
-    // and then allocate the replacement surfaces once the old one is destroyed. This way reduce the
-    // overall memory usage but more information gathering would need to be done to show that we
-    // would not need to increase the number of DPB surfaces needed todo the decode operation, or we
-    // can do sysmem incremental allocation and use it here.
+    // TODO(https://fxbug.dev/42073230): Consider only replacing amount of unused surfaces in
+    // |dpb_surfaces_| and then allocate the replacement surfaces once the old one is destroyed.
+    // This way reduce the overall memory usage but more information gathering would need to be done
+    // to show that we would not need to increase the number of DPB surfaces needed todo the decode
+    // operation, or we can do sysmem incremental allocation and use it here.
     VASurfaceAttrib attrib = {.type = VASurfaceAttribPixelFormat,
                               .flags = VA_SURFACE_ATTRIB_SETTABLE,
                               .value = {.type = VAGenericValueTypeInteger,
@@ -746,14 +746,14 @@
   // Structure that maps allocated buffers shared with the client. Once the buffer is no longer in
   // use by the client and the decoder it should be removed from this map and marked as free in the
   // output_buffer_pool_.
-  std::unordered_map<VASurfaceID, const CodecBuffer*> surface_to_buffer_ FXL_GUARDED_BY(
-      surface_lock_);
+  std::unordered_map<VASurfaceID, const CodecBuffer*> surface_to_buffer_
+      FXL_GUARDED_BY(surface_lock_);
 
   // Once a surface is allocated it is stored in this map which maps the codec buffer that backs
   // the surface. If a resize event happens this structure will have to be invalidated and the
   // surfaces will have to be regenerated to match the new surface_size_
-  std::unordered_map<const CodecBuffer*, ScopedSurfaceID> allocated_free_surfaces_ FXL_GUARDED_BY(
-      surface_lock_);
+  std::unordered_map<const CodecBuffer*, ScopedSurfaceID> allocated_free_surfaces_
+      FXL_GUARDED_BY(surface_lock_);
 
   // Maps the codec buffer to the VA surface being shared to the client. In addition to the
   // mapping this data structure holds a reference to the surface being used by the client,
@@ -970,7 +970,8 @@
       FX_SLOG(INFO, "Are new buffers required for bitstream change?",
               FX_KV("output_re_config_required", output_re_config_required ? "yes" : "no"));
 
-      // TODO(https://fxbug.dev/42060469): This is a temporary workaround until the new media APIs are adopted
+      // TODO(https://fxbug.dev/42060469): This is a temporary workaround until the new media APIs
+      // are adopted
       if (surface_buffer_manager_ &&
           (surface_buffer_manager_->NeedsKeyframeForBufferAllocation() &&
            !media_decoder_->IsCurrentFrameKeyframe() && output_re_config_required)) {
@@ -988,8 +989,8 @@
       }
 
       if (output_re_config_required) {
-        // TODO(https://fxbug.dev/42073231): Calling onCoreCodecMidStreamOutputConstraintsChange() with false
-        // is now deprecated. Remove the |output_re_config_buffer| parameter.
+        // TODO(https://fxbug.dev/42073231): Calling onCoreCodecMidStreamOutputConstraintsChange()
+        // with false is now deprecated. Remove the |output_re_config_buffer| parameter.
         events_->onCoreCodecMidStreamOutputConstraintsChange(true);
       } else {
         // If an output reconfiguration was not needed, we still need to inform the client that the
@@ -1198,11 +1199,11 @@
     return fit::ok(true);
   }
 
-  ZX_ASSERT(buffer_settings_[kOutputPort]->has_image_format_constraints);
+  ZX_ASSERT(buffer_settings_[kOutputPort]->image_format_constraints().has_value());
   auto surface_size = surface_buffer_manager_->GetRequiredSurfaceSize(pic_size);
 
-  // TODO(https://fxbug.dev/42073232): This isn't the correct calculation as it does not factor in alignment
-  // for tiled surfaces
+  // TODO(https://fxbug.dev/42073232): This isn't the correct calculation as it does not factor in
+  // alignment for tiled surfaces
   auto total_plane_size_checked =
       ((safemath::MakeCheckedNum(surface_size.GetArea()) * 3) / 2).Cast<uint32_t>();
 
@@ -1215,27 +1216,28 @@
   uint32_t total_plane_size = total_plane_size_checked.ValueOrDie();
 
   // Ensure the size of the buffers can hold the new plane size
-  if (total_plane_size > buffer_settings_[kOutputPort]->buffer_settings.size_bytes) {
+  if (total_plane_size > *buffer_settings_[kOutputPort]->buffer_settings()->size_bytes()) {
     FX_SLOG(DEBUG, "total_plane_size > buffer_size_bytes",
             FX_KV("total_plane_size", total_plane_size),
-            FX_KV("buffer_size_bytes", buffer_settings_[kOutputPort]->buffer_settings.size_bytes));
+            FX_KV("buffer_size_bytes",
+                  *buffer_settings_[kOutputPort]->buffer_settings()->size_bytes()));
     return fit::ok(true);
   }
 
-  const auto& image_constraints = buffer_settings_[kOutputPort]->image_format_constraints;
+  const auto& image_constraints = *buffer_settings_[kOutputPort]->image_format_constraints();
 
-  if (display_width % image_constraints.display_width_divisor != 0u) {
+  if (display_width % image_constraints.display_rect_alignment()->width() != 0u) {
     FX_SLOG(DEBUG, "display_width not divisible by display_width_divisor",
             FX_KV("display_width", display_width),
-            FX_KV("display_width_divisor", image_constraints.display_width_divisor));
+            FX_KV("display_width_divisor", image_constraints.display_rect_alignment()->width()));
     // These will fail, but let them fail when trying to re-negotiate sysmem buffers.
     return fit::ok(true);
   }
 
-  if (display_height % image_constraints.display_height_divisor != 0u) {
+  if (display_height % image_constraints.display_rect_alignment()->height() != 0u) {
     FX_SLOG(DEBUG, "display_height not divisible by display_height_divisor",
             FX_KV("display_height", display_height),
-            FX_KV("display_height_divisor", image_constraints.display_height_divisor));
+            FX_KV("display_height_divisor", image_constraints.display_rect_alignment()->height()));
     // These will fail, but let them fail when trying to re-negotiate sysmem buffers.
     return fit::ok(true);
   }
@@ -1247,74 +1249,73 @@
     return fit::error("Surface size exceeds uint32_t");
   }
   uint32_t coded_area = coded_area_checked.ValueOrDie();
-  if (coded_area > image_constraints.max_coded_width_times_coded_height) {
-    FX_SLOG(DEBUG, "coded_area > max_coded_width_times_coded_height",
-            FX_KV("coded_area", coded_area),
-            FX_KV("max_coded_width_times_coded_height",
-                  image_constraints.max_coded_width_times_coded_height));
+  if (coded_area > *image_constraints.max_width_times_height()) {
+    FX_SLOG(
+        DEBUG, "coded_area > max_coded_width_times_coded_height", FX_KV("coded_area", coded_area),
+        FX_KV("max_coded_width_times_coded_height", *image_constraints.max_width_times_height()));
     // These will very likely fail, but let them fail when trying to re-negotiate sysmem buffers.
     return fit::ok(true);
   }
 
-  if (coded_width % image_constraints.coded_width_divisor != 0u) {
+  if (coded_width % image_constraints.size_alignment()->width() != 0u) {
     FX_SLOG(DEBUG, "coded_width not divisible by coded_width_divisor",
             FX_KV("coded_width", coded_width),
-            FX_KV("coded_width_divisor", image_constraints.coded_width_divisor));
+            FX_KV("coded_width_divisor", image_constraints.size_alignment()->width()));
     // These will fail, but let them fail when trying to re-negotiate sysmem buffers.
     return fit::ok(true);
   }
 
-  if (coded_height % image_constraints.coded_height_divisor != 0u) {
+  if (coded_height % image_constraints.size_alignment()->height() != 0u) {
     FX_SLOG(DEBUG, "coded_height not divisible by coded_height_divisor",
             FX_KV("coded_height", coded_height),
-            FX_KV("coded_height_divisor", image_constraints.coded_height_divisor));
+            FX_KV("coded_height_divisor", image_constraints.size_alignment()->height()));
     // These will fail, but let them fail when trying to re-negotiate sysmem buffers.
     return fit::ok(true);
   }
 
-  if (coded_width < image_constraints.min_coded_width) {
+  if (coded_width < image_constraints.min_size()->width()) {
     FX_SLOG(DEBUG, "coded_width < min_coded_width", FX_KV("coded_width", coded_width),
-            FX_KV("min_coded_width", image_constraints.min_coded_width));
+            FX_KV("min_coded_width", image_constraints.min_size()->width()));
     return fit::ok(true);
   }
 
-  if (coded_width > image_constraints.max_coded_width) {
+  if (coded_width > image_constraints.max_size()->width()) {
     FX_SLOG(DEBUG, "coded_width > max_coded_width", FX_KV("coded_width", coded_width),
-            FX_KV("max_coded_width", image_constraints.max_coded_width));
+            FX_KV("max_coded_width", image_constraints.max_size()->width()));
     return fit::ok(true);
   }
 
-  if (coded_height < image_constraints.min_coded_height) {
+  if (coded_height < image_constraints.min_size()->height()) {
     FX_SLOG(DEBUG, "coded_height < min_coded_height", FX_KV("coded_height", coded_height),
-            FX_KV("min_coded_height", image_constraints.min_coded_height));
+            FX_KV("min_coded_height", image_constraints.min_size()->height()));
     return fit::ok(true);
   }
 
-  if (coded_height > image_constraints.max_coded_height) {
+  if (coded_height > image_constraints.max_size()->height()) {
     FX_SLOG(DEBUG, "coded_height > max_coded_height", FX_KV("coded_height", coded_height),
-            FX_KV("max_coded_height", image_constraints.max_coded_height));
+            FX_KV("max_coded_height", image_constraints.max_size()->height()));
     return fit::ok(true);
   }
 
   uint32_t stride = safemath::checked_cast<uint32_t>(surface_size.width());
-  if (stride < image_constraints.min_bytes_per_row) {
+  if (stride < *image_constraints.min_bytes_per_row()) {
     FX_SLOG(DEBUG, "stride < min_bytes_per_row", FX_KV("stride", stride),
-            FX_KV("min_bytes_per_row", image_constraints.min_bytes_per_row));
+            FX_KV("min_bytes_per_row", *image_constraints.min_bytes_per_row()));
     return fit::ok(true);
   }
 
-  if (stride > image_constraints.max_bytes_per_row) {
+  if (stride > *image_constraints.max_bytes_per_row()) {
     FX_SLOG(DEBUG, "stride > max_bytes_per_row", FX_KV("stride", stride),
-            FX_KV("max_bytes_per_row", image_constraints.max_bytes_per_row));
+            FX_KV("max_bytes_per_row", *image_constraints.max_bytes_per_row()));
     return fit::ok(true);
   }
 
   // This check only makes sense if the output is linear since tiled formats don't really have a
   // concept of bytes per row divisor
   if (!IsOutputTiled()) {
-    if (stride % image_constraints.bytes_per_row_divisor != 0u) {
+    if (stride % *image_constraints.bytes_per_row_divisor() != 0u) {
       FX_SLOG(DEBUG, "stride not divisible by bytes_per_row_divisor", FX_KV("stride", stride),
-              FX_KV("bytes_per_row_divisor", image_constraints.bytes_per_row_divisor));
+              FX_KV("bytes_per_row_divisor", *image_constraints.bytes_per_row_divisor()));
       // These will fail, but let them fail when trying to re-negotiate sysmem buffers.
       return fit::ok(true);
     }
@@ -1405,7 +1406,8 @@
       if (media_codec_.value() == CodecType::kH264) {
         constexpr uint8_t kAccessUnitDelimiterNalUnitType = 9;
         constexpr uint8_t kPrimaryPicType = 1 << (7 - 3);
-        // Force frames to be processed. TODO(https://fxbug.dev/42073233): Key on known_end_access_unit.
+        // Force frames to be processed. TODO(https://fxbug.dev/42073233): Key on
+        // known_end_access_unit.
         std::vector<uint8_t> access_unit_delimiter{0, 0, 1, kAccessUnitDelimiterNalUnitType,
                                                    kPrimaryPicType};
 
diff --git a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.h b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.h
index db61b60..1d0e177 100644
--- a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.h
+++ b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_decoder.h
@@ -92,9 +92,9 @@
   // into account the pixel format.
   virtual gfx::Size GetRequiredSurfaceSize(const gfx::Size& picture_size) = 0;
 
-  // TODO(https://fxbug.dev/42060469): This is a temporary workaround until the new media APIs are adopted
-  // Returns true if the surface manager can not have outstanding reference frames when new buffers
-  // are required to hold the new coded picture size.
+  // TODO(https://fxbug.dev/42060469): This is a temporary workaround until the new media APIs are
+  // adopted Returns true if the surface manager can not have outstanding reference frames when new
+  // buffers are required to hold the new coded picture size.
   virtual bool NeedsKeyframeForBufferAllocation() const = 0;
 
   // Updates the picture size of the current stream. If the surfaces that are currently under
@@ -399,42 +399,40 @@
     return result;
   }
 
-  fuchsia::sysmem::BufferCollectionConstraints CoreCodecGetBufferCollectionConstraints(
+  fuchsia_sysmem2::BufferCollectionConstraints CoreCodecGetBufferCollectionConstraints2(
       CodecPort port, const fuchsia::media::StreamBufferConstraints& stream_buffer_constraints,
       const fuchsia::media::StreamBufferPartialSettings& partial_settings) override {
+    fuchsia_sysmem2::BufferCollectionConstraints constraints;
+    auto& bmc = constraints.buffer_memory_constraints().emplace();
+
     if (port == kInputPort) {
-      fuchsia::sysmem::BufferCollectionConstraints constraints;
-      constraints.min_buffer_count_for_camping = 1;
-      constraints.has_buffer_memory_constraints = true;
-      constraints.buffer_memory_constraints.cpu_domain_supported = true;
+      constraints.min_buffer_count_for_camping() = 1;
+      bmc.cpu_domain_supported() = true;
       // Must be big enough to hold an entire NAL unit, since the H264Decoder doesn't support
       // split NAL units.
-      constraints.buffer_memory_constraints.min_size_bytes = 8192 * 512;
-      return constraints;
-    } else if (port == kOutputPort) {
-      fuchsia::sysmem::BufferCollectionConstraints constraints;
-      constraints.min_buffer_count_for_camping =
+      bmc.min_size_bytes() = 8192 * 512;
+    } else {
+      ZX_DEBUG_ASSERT(port == kOutputPort);
+      constraints.min_buffer_count_for_camping() =
           static_cast<uint32_t>(media_decoder_->GetRequiredNumOfPictures());
-      constraints.has_buffer_memory_constraints = true;
       // TODO(https://fxbug.dev/42176003): Add RAM domain support.
-      constraints.buffer_memory_constraints.cpu_domain_supported = true;
+      bmc.cpu_domain_supported() = true;
 
       // Lamdba that will set the common constraint values regardless of what format modifier value
       using CommonConstraintsFunction =
-          fit::inline_function<void(fuchsia::sysmem::ImageFormatConstraints & constraints)>;
+          fit::inline_function<void(fuchsia_sysmem2::ImageFormatConstraints & constraints)>;
       auto set_common_constraints =
-          CommonConstraintsFunction([this](fuchsia::sysmem::ImageFormatConstraints& constraints) {
+          CommonConstraintsFunction([this](fuchsia_sysmem2::ImageFormatConstraints& constraints) {
             ZX_ASSERT(media_decoder_);
             ZX_ASSERT(media_codec_.has_value());
 
             bool is_h264 = (media_codec_.value() == CodecType::kH264);
 
             // Currently only support outputting to NV12
-            constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::NV12;
+            constraints.pixel_format() = fuchsia_images2::PixelFormat::kNv12;
 
             // Currently only support the REC709 color space.
-            constraints.color_spaces_count = 1;
-            constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::REC709;
+            constraints.color_spaces() = {fuchsia_images2::ColorSpace::kRec709};
 
             // The non-"required_" fields indicate the decoder's ability to potentially
             // output frames at various dimensions as coded in the stream.  Aside from
@@ -442,23 +440,19 @@
             // do with the current stream in particular. We advertise the known min codec width
             // depending on the codec. For the max, we advertise what the current hardware supports,
             // not the codec max.
-            constraints.min_coded_width = is_h264 ? kH264MinBlockSize : kVp9MinBlockSize;
-            constraints.max_coded_width = max_picture_width_;
-            constraints.min_coded_height = is_h264 ? kH264MinBlockSize : kVp9MinBlockSize;
-            constraints.max_coded_height = max_picture_height_;
-            constraints.max_coded_width_times_coded_height =
-                (max_picture_width_ * max_picture_height_);
+            constraints.min_size() = {is_h264 ? kH264MinBlockSize : kVp9MinBlockSize,
+                                      is_h264 ? kH264MinBlockSize : kVp9MinBlockSize};
+            constraints.max_size() = {max_picture_width_, max_picture_height_};
+            constraints.max_width_times_height() = max_picture_width_ * max_picture_height_;
 
-            constraints.layers = 1;
-            constraints.coded_width_divisor = is_h264 ? kH264MinBlockSize : kVp9MinBlockSize;
-            constraints.coded_height_divisor = is_h264 ? kH264MinBlockSize : kVp9MinBlockSize;
-            constraints.start_offset_divisor = 1;
+            constraints.size_alignment() = {is_h264 ? kH264MinBlockSize : kVp9MinBlockSize,
+                                            is_h264 ? kH264MinBlockSize : kVp9MinBlockSize};
+            constraints.start_offset_divisor() = 1;
 
             // Odd display dimensions are permitted, but these don't imply odd YV12
             // dimensions - those are constrained by coded_width_divisor and
             // coded_height_divisor which are both 16.
-            constraints.display_width_divisor = 1;
-            constraints.display_height_divisor = 1;
+            constraints.display_rect_alignment() = {1, 1};
 
             // The decoder is producing frames and the decoder has no choice but to
             // produce frames at their coded size.  The decoder wants to potentially be
@@ -486,70 +480,60 @@
                 static_cast<bool>(surface_buffer_manager_)
                     ? surface_buffer_manager_->GetRequiredSurfaceSize(pic_size)
                     : pic_size;
-            constraints.required_min_coded_width = required_size.width();
-            constraints.required_max_coded_width = required_size.width();
-            constraints.required_min_coded_height = required_size.height();
-            constraints.required_max_coded_height = required_size.height();
-            constraints.required_min_bytes_per_row = required_size.width();
-            constraints.required_max_bytes_per_row = required_size.width();
+            constraints.required_min_size() = {static_cast<uint32_t>(required_size.width()),
+                                               static_cast<uint32_t>(required_size.height())};
+            constraints.required_max_size() = {static_cast<uint32_t>(required_size.width()),
+                                               static_cast<uint32_t>(required_size.height())};
 
-            constraints.min_bytes_per_row = required_size.width();
+            constraints.min_bytes_per_row() = required_size.width();
           });
 
-      constraints.image_format_constraints_count = 0;
+      constraints.image_format_constraints().emplace();
 
       // Linear Format
-      if (!output_buffer_format_modifier_ ||
-          (output_buffer_format_modifier_.value() == fuchsia::sysmem::FORMAT_MODIFIER_LINEAR)) {
-        auto& linear_constraints =
-            constraints.image_format_constraints[constraints.image_format_constraints_count];
-        linear_constraints.pixel_format.has_format_modifier = false;
-        linear_constraints.bytes_per_row_divisor = kLinearSurfaceWidthAlignment;
-        linear_constraints.max_bytes_per_row =
+      if (!output_buffer_format_modifier_ || (output_buffer_format_modifier_.value() ==
+                                              fuchsia_images2::PixelFormatModifier::kLinear)) {
+        auto& linear_constraints = constraints.image_format_constraints()->emplace_back();
+        linear_constraints.bytes_per_row_divisor() = kLinearSurfaceWidthAlignment;
+        linear_constraints.max_bytes_per_row() =
             fbl::round_up(max_picture_width_, kLinearSurfaceWidthAlignment);
 
         set_common_constraints(linear_constraints);
-
-        constraints.image_format_constraints_count += 1;
       }
 
       // Y-Tiled format
       if (!output_buffer_format_modifier_ ||
           (output_buffer_format_modifier_.value() ==
-           fuchsia::sysmem::FORMAT_MODIFIER_INTEL_I915_Y_TILED)) {
-        auto& tiled_constraints =
-            constraints.image_format_constraints[constraints.image_format_constraints_count];
-        tiled_constraints.pixel_format.has_format_modifier = true;
-        tiled_constraints.pixel_format.format_modifier.value =
-            fuchsia::sysmem::FORMAT_MODIFIER_INTEL_I915_Y_TILED;
-        tiled_constraints.bytes_per_row_divisor = 0;
+           fuchsia_images2::PixelFormatModifier::kIntelI915YTiled)) {
+        auto& tiled_constraints = constraints.image_format_constraints()->emplace_back();
+        tiled_constraints.pixel_format_modifier() =
+            fuchsia_images2::PixelFormatModifier::kIntelI915YTiled;
+        tiled_constraints.bytes_per_row_divisor() = 0;
 
         set_common_constraints(tiled_constraints);
-
-        constraints.image_format_constraints_count += 1;
       }
 
-      return constraints;
+      ZX_ASSERT(!constraints.image_format_constraints()->empty());
     }
 
-    return fuchsia::sysmem::BufferCollectionConstraints{};
+    return constraints;
   }
 
   void CoreCodecSetBufferCollectionInfo(
       CodecPort port,
-      const fuchsia::sysmem::BufferCollectionInfo_2& buffer_collection_info) override {
-    buffer_settings_[port] = buffer_collection_info.settings;
-    buffer_counts_[port] = buffer_collection_info.buffer_count;
+      const fuchsia_sysmem2::BufferCollectionInfo& buffer_collection_info) override {
+    buffer_settings_[port] = buffer_collection_info.settings();
+    buffer_counts_[port] = buffer_collection_info.buffers()->size();
 
     if (port == CodecPort::kOutputPort) {
-      ZX_ASSERT(buffer_collection_info.settings.has_image_format_constraints);
+      ZX_ASSERT(buffer_collection_info.settings()->image_format_constraints().has_value());
 
-      // If the format doesn't have a format modifier, then it is linear
-      const auto& pixel_format =
-          buffer_collection_info.settings.image_format_constraints.pixel_format;
-      uint64_t format_modifier = pixel_format.has_format_modifier
-                                     ? pixel_format.format_modifier.value
-                                     : fuchsia::sysmem::FORMAT_MODIFIER_LINEAR;
+      ZX_ASSERT(buffer_collection_info.settings()
+                    ->image_format_constraints()
+                    ->pixel_format_modifier()
+                    .has_value());
+      auto format_modifier =
+          *buffer_collection_info.settings()->image_format_constraints()->pixel_format_modifier();
 
       // Should never happen but ensure we do not overwrite a format modifier that has been
       // initialized with another value
@@ -561,10 +545,10 @@
       if (!output_buffer_format_modifier_.has_value()) {
         std::string format_modifier_str;
         switch (format_modifier) {
-          case fuchsia::sysmem::FORMAT_MODIFIER_LINEAR:
+          case fuchsia_images2::PixelFormatModifier::kLinear:
             format_modifier_str = "linear";
             break;
-          case fuchsia::sysmem::FORMAT_MODIFIER_INTEL_I915_Y_TILED:
+          case fuchsia_images2::PixelFormatModifier::kIntelI915YTiled:
             format_modifier_str = "intel_i915_y_tiled";
             break;
           default:
@@ -572,7 +556,8 @@
             break;
         }
 
-        FX_SLOG(INFO, "Format modifier has been chosen", FX_KV("format_modifier", format_modifier),
+        FX_SLOG(INFO, "Format modifier has been chosen",
+                FX_KV("format_modifier", fidl::ToUnderlying(format_modifier)),
                 FX_KV("format_modifier_str", format_modifier_str.c_str()));
       }
 
@@ -672,13 +657,13 @@
 
   bool IsOutputTiled() const {
     ZX_ASSERT(buffer_settings_[kOutputPort]);
-    ZX_ASSERT(buffer_settings_[kOutputPort]->has_image_format_constraints);
+    ZX_ASSERT(buffer_settings_[kOutputPort]->image_format_constraints().has_value());
 
-    auto& format_constraints = buffer_settings_[kOutputPort]->image_format_constraints;
+    auto& format_constraints = *buffer_settings_[kOutputPort]->image_format_constraints();
 
-    return (format_constraints.pixel_format.has_format_modifier) &&
-           (format_constraints.pixel_format.format_modifier.value !=
-            fuchsia_sysmem::wire::kFormatModifierLinear);
+    return format_constraints.pixel_format_modifier().has_value() &&
+           (*format_constraints.pixel_format_modifier() !=
+            fuchsia_images2::PixelFormatModifier::kLinear);
   }
 
   // Use to construct the |media_decoder_|. Can only be called iff |media_decoder_| is not
@@ -789,7 +774,7 @@
 
   AvccProcessor avcc_processor_;
 
-  std::optional<fuchsia::sysmem::SingleBufferSettings> buffer_settings_[kPortCount];
+  std::optional<fuchsia_sysmem2::SingleBufferSettings> buffer_settings_[kPortCount];
   std::optional<uint32_t> buffer_counts_[kPortCount];
 
   // Initially this value is std::nullopt meaning that there has been no format modifier set by the
@@ -799,7 +784,7 @@
   // CoreCodecGetBufferCollectionConstraints() will only advertise the format modifier selected
   // by the client since the format modifier can not be changed during a mid stream output
   // buffer reconfiguration or at any other part in the codec's lifecycle.
-  std::optional<uint64_t> output_buffer_format_modifier_{};
+  std::optional<fuchsia_images2::PixelFormatModifier> output_buffer_format_modifier_{};
 
   // Since CoreCodecInit() is called after SetDriverDiagnostics() we need to save a pointer to the
   // codec diagnostics object so that we can create the codec diagnotcis when we construct the
diff --git a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_encoder.cc b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_encoder.cc
index 5f0e5da..36bc5ae 100644
--- a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_encoder.cc
+++ b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_encoder.cc
@@ -305,9 +305,9 @@
   video_frame->coded_size = coded_size_;
   video_frame->base = packet->buffer()->base();
   video_frame->size_bytes = packet->buffer()->size();
-  video_frame->stride =
-      fbl::round_up(static_cast<uint32_t>(display_size_.width()),
-                    buffer_settings_[kInputPort]->image_format_constraints.bytes_per_row_divisor);
+  video_frame->stride = fbl::round_up(
+      static_cast<uint32_t>(display_size_.width()),
+      *buffer_settings_[kInputPort]->image_format_constraints()->bytes_per_row_divisor());
 
   scoped_refptr<VASurface> va_surface = GetVASurface();
   VABufferID coded_buffer;
diff --git a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_encoder.h b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_encoder.h
index 76c07d4..d0fb17e 100644
--- a/src/media/codec/codecs/vaapi/codec_adapter_vaapi_encoder.h
+++ b/src/media/codec/codecs/vaapi/codec_adapter_vaapi_encoder.h
@@ -238,75 +238,72 @@
     return result;
   }
 
-  fuchsia::sysmem::BufferCollectionConstraints CoreCodecGetBufferCollectionConstraints(
+  fuchsia_sysmem2::BufferCollectionConstraints CoreCodecGetBufferCollectionConstraints2(
       CodecPort port, const fuchsia::media::StreamBufferConstraints& stream_buffer_constraints,
       const fuchsia::media::StreamBufferPartialSettings& partial_settings) override {
+    fuchsia_sysmem2::BufferCollectionConstraints constraints;
+    auto& bmc = constraints.buffer_memory_constraints().emplace();
+
     if (port == kOutputPort) {
-      fuchsia::sysmem::BufferCollectionConstraints constraints;
-      constraints.min_buffer_count_for_camping = 1;
-      constraints.has_buffer_memory_constraints = true;
+      constraints.min_buffer_count_for_camping() = 1;
+
       // The Intel GPU supports CPU domain buffer collections, so we don't really need to support
       // RAM domain.
-      constraints.buffer_memory_constraints.cpu_domain_supported = true;
+      bmc.cpu_domain_supported() = true;
       ZX_ASSERT(display_size_.width() > 0);
       ZX_ASSERT(display_size_.height() > 0);
+
       // The encoder doesn't support splitting output across buffers.
-      constraints.buffer_memory_constraints.min_size_bytes =
+      bmc.min_size_bytes() =
           static_cast<uint32_t>(media::GetEncodeBitstreamBufferSize(coded_size_));
-      return constraints;
-    } else if (port == kInputPort) {
-      fuchsia::sysmem::BufferCollectionConstraints constraints;
-      constraints.min_buffer_count_for_camping = 1;
-      constraints.has_buffer_memory_constraints = true;
-      constraints.buffer_memory_constraints.cpu_domain_supported = true;
-      constraints.image_format_constraints_count = 1;
-      fuchsia::sysmem::ImageFormatConstraints& image_constraints =
-          constraints.image_format_constraints[0];
-      image_constraints.pixel_format.type = fuchsia::sysmem::PixelFormatType::NV12;
+    } else {
+      ZX_DEBUG_ASSERT(port == kInputPort);
+      constraints.min_buffer_count_for_camping() = 1;
+      bmc.cpu_domain_supported() = true;
+      auto& image_constraints = constraints.image_format_constraints().emplace().emplace_back();
+      image_constraints.pixel_format() = fuchsia_images2::PixelFormat::kNv12;
+
       // TODO(https://fxbug.dev/42051379): Add support for more colorspaces.
-      image_constraints.color_spaces_count = 1;
-      image_constraints.color_space[0].type = fuchsia::sysmem::ColorSpaceType::REC709;
+      image_constraints.color_spaces() = {fuchsia_images2::ColorSpace::kRec709};
 
       // The non-"required_" fields indicate the encoder's ability to accept
       // input frames at various dimensions. The input frames need to be within
       // these bounds.
-      image_constraints.min_coded_width = 16;
-      image_constraints.max_coded_width = 3840;
-      image_constraints.min_coded_height = 16;
+      image_constraints.min_size() = {16, 16};
+
       // This intentionally isn't the height of a 4k frame.  See
       // max_coded_width_times_coded_height.  We intentionally constrain the max
       // dimension in width or height to the width of a 4k frame.  While the HW
       // might be able to go bigger than that as long as the other dimension is
       // smaller to compensate, we don't really need to enable any larger than
       // 4k's width in either dimension, so we don't.
-      image_constraints.max_coded_height = 3840;
-      image_constraints.min_bytes_per_row = 16;
+      image_constraints.max_size() = {3840, 3840};
+      image_constraints.min_bytes_per_row() = 16;
+
       // no hard-coded max stride, at least for now
-      image_constraints.max_bytes_per_row = 0xFFFFFFFF;
-      image_constraints.max_coded_width_times_coded_height = 3840 * 2160;
-      image_constraints.layers = 1;
-      image_constraints.coded_width_divisor = 2;
-      image_constraints.coded_height_divisor = 2;
-      image_constraints.bytes_per_row_divisor = 2;
-      image_constraints.start_offset_divisor = 1;
+      ZX_DEBUG_ASSERT(!image_constraints.max_bytes_per_row().has_value());
+      image_constraints.max_width_times_height() = 3840 * 2160;
+      image_constraints.size_alignment() = {2, 2};
+      image_constraints.bytes_per_row_divisor() = 2;
+      image_constraints.start_offset_divisor() = 1;
+
       // Odd display dimensions are permitted, but these don't imply odd YV12
       // dimensions - those are constrainted by coded_width_divisor and
       // coded_height_divisor which are both 2.
-      image_constraints.display_width_divisor = 1;
-      image_constraints.display_height_divisor = 1;
+      image_constraints.display_rect_alignment() = {1, 1};
 
       // The required sizes aren't initialized, since
       // CoreCodecGetBufferCollectionConstraints won't be re-triggered when the
       // input format is changed.
-      return constraints;
     }
-    return fuchsia::sysmem::BufferCollectionConstraints{};
+
+    return constraints;
   }
 
   void CoreCodecSetBufferCollectionInfo(
       CodecPort port,
-      const fuchsia::sysmem::BufferCollectionInfo_2& buffer_collection_info) override {
-    buffer_settings_[port] = buffer_collection_info.settings;
+      const fuchsia_sysmem2::BufferCollectionInfo& buffer_collection_info) override {
+    buffer_settings_[port] = *buffer_collection_info.settings();
   }
 
   VAContextID context_id() { return context_id_->id(); }
@@ -382,7 +379,7 @@
   uint64_t input_format_details_version_ordinal_;
   media::VideoEncodeAccelerator::Config accelerator_config_;
 
-  std::optional<fuchsia::sysmem::SingleBufferSettings> buffer_settings_[kPortCount];
+  std::optional<fuchsia_sysmem2::SingleBufferSettings> buffer_settings_[kPortCount];
 
   // DPB surfaces.
   std::mutex surfaces_lock_;
diff --git a/src/media/codec/codecs/vaapi/test/decoder_fuzzer.cc b/src/media/codec/codecs/vaapi/test/decoder_fuzzer.cc
index 2d910c5..13d7034 100644
--- a/src/media/codec/codecs/vaapi/test/decoder_fuzzer.cc
+++ b/src/media/codec/codecs/vaapi/test/decoder_fuzzer.cc
@@ -100,36 +100,36 @@
   format_details.set_mime_type(mime_type);
   decoder_->CoreCodecInit(format_details);
 
-  auto input_constraints = decoder_->CoreCodecGetBufferCollectionConstraints(
+  auto input_constraints = decoder_->CoreCodecGetBufferCollectionConstraints2(
       CodecPort::kInputPort, fuchsia::media::StreamBufferConstraints(),
       fuchsia::media::StreamBufferPartialSettings());
-  ZX_ASSERT(input_constraints.buffer_memory_constraints.cpu_domain_supported);
+  ZX_ASSERT(*input_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
-  auto output_constraints = decoder_->CoreCodecGetBufferCollectionConstraints(
+  auto output_constraints = decoder_->CoreCodecGetBufferCollectionConstraints2(
       CodecPort::kOutputPort, fuchsia::media::StreamBufferConstraints(),
       fuchsia::media::StreamBufferPartialSettings());
-  ZX_ASSERT(output_constraints.buffer_memory_constraints.cpu_domain_supported);
+  ZX_ASSERT(*output_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
   // Set the codec output format to either linear or tiled depending on the fuzzer
-  fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection;
-  buffer_collection.settings.has_image_format_constraints = true;
-  buffer_collection.buffer_count = output_constraints.min_buffer_count_for_camping;
+  fuchsia_sysmem2::BufferCollectionInfo buffer_collection;
+  buffer_collection.buffers().emplace(*output_constraints.min_buffer_count_for_camping());
 
+  auto &ifc = buffer_collection.settings().emplace().image_format_constraints().emplace();
   switch (output_image_format_) {
     case ImageFormat::kLinear: {
-      const auto &linear_constraints = output_constraints.image_format_constraints.at(0);
-      ZX_ASSERT(!linear_constraints.pixel_format.has_format_modifier ||
-                linear_constraints.pixel_format.format_modifier.value ==
-                    fuchsia::sysmem::FORMAT_MODIFIER_LINEAR);
-      buffer_collection.settings.image_format_constraints = linear_constraints;
+      const auto &linear_constraints = output_constraints.image_format_constraints()->at(0);
+      ZX_ASSERT(!linear_constraints.pixel_format_modifier().has_value() ||
+                linear_constraints.pixel_format_modifier().value() ==
+                    fuchsia_images2::PixelFormatModifier::kLinear);
+      ifc = linear_constraints;
       break;
     }
     case ImageFormat::kTiled: {
-      const auto &tiled_constraints = output_constraints.image_format_constraints.at(1);
-      ZX_ASSERT(tiled_constraints.pixel_format.has_format_modifier &&
-                tiled_constraints.pixel_format.format_modifier.value ==
-                    fuchsia::sysmem::FORMAT_MODIFIER_INTEL_I915_Y_TILED);
-      buffer_collection.settings.image_format_constraints = tiled_constraints;
+      const auto &tiled_constraints = output_constraints.image_format_constraints()->at(1);
+      ZX_ASSERT(tiled_constraints.pixel_format_modifier().has_value() &&
+                tiled_constraints.pixel_format_modifier().value() ==
+                    fuchsia_images2::PixelFormatModifier::kIntelI915YTiled);
+      ifc = tiled_constraints;
       break;
     }
     default:
@@ -213,25 +213,25 @@
   decoder_->CoreCodecEnsureBuffersNotConfigured(CodecPort::kOutputPort);
 
   // Test a representative value.
-  auto output_constraints = decoder_->CoreCodecGetBufferCollectionConstraints(
+  auto output_constraints = decoder_->CoreCodecGetBufferCollectionConstraints2(
       CodecPort::kOutputPort, fuchsia::media::StreamBufferConstraints(),
       fuchsia::media::StreamBufferPartialSettings());
-  ZX_ASSERT(output_constraints.buffer_memory_constraints.cpu_domain_supported);
+  ZX_ASSERT(*output_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
-  ZX_ASSERT(output_constraints.image_format_constraints_count == 1u);
-  const auto &image_constraints = output_constraints.image_format_constraints.at(0u);
+  ZX_ASSERT(output_constraints.image_format_constraints()->size() == 1u);
+  const auto &image_constraints = output_constraints.image_format_constraints()->at(0);
 
   switch (output_image_format_) {
     case ImageFormat::kLinear: {
-      ZX_ASSERT(!image_constraints.pixel_format.has_format_modifier ||
-                image_constraints.pixel_format.format_modifier.value ==
-                    fuchsia::sysmem::FORMAT_MODIFIER_LINEAR);
+      ZX_ASSERT(!image_constraints.pixel_format_modifier().has_value() ||
+                image_constraints.pixel_format_modifier().value() ==
+                    fuchsia_images2::PixelFormatModifier::kLinear);
       break;
     }
     case ImageFormat::kTiled: {
-      ZX_ASSERT(image_constraints.pixel_format.has_format_modifier &&
-                image_constraints.pixel_format.format_modifier.value ==
-                    fuchsia::sysmem::FORMAT_MODIFIER_INTEL_I915_Y_TILED);
+      ZX_ASSERT(image_constraints.pixel_format_modifier().has_value() &&
+                image_constraints.pixel_format_modifier().value() ==
+                    fuchsia_images2::PixelFormatModifier::kIntelI915YTiled);
       break;
     }
     default:
@@ -240,10 +240,9 @@
   }
 
   // Set the codec output format to either linear or tiled depending on the fuzzer
-  fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection;
-  buffer_collection.buffer_count = output_constraints.min_buffer_count_for_camping;
-  buffer_collection.settings.has_image_format_constraints = true;
-  buffer_collection.settings.image_format_constraints = image_constraints;
+  fuchsia_sysmem2::BufferCollectionInfo buffer_collection;
+  buffer_collection.buffers().emplace(*output_constraints.min_buffer_count_for_camping());
+  buffer_collection.settings().emplace().image_format_constraints() = image_constraints;
   decoder_->CoreCodecSetBufferCollectionInfo(CodecPort::kOutputPort, buffer_collection);
 
   // Should be enough to handle a large fraction of bear.h264 output without recycling.
@@ -256,13 +255,14 @@
   switch (output_image_format_) {
     case ImageFormat::kLinear: {
       // Output is linear
-      auto out_width = RoundUp(safemath::MakeCheckedNum(image_constraints.required_max_coded_width),
-                               safemath::MakeCheckedNum(image_constraints.coded_width_divisor));
+      auto out_width =
+          RoundUp(safemath::MakeCheckedNum(image_constraints.required_max_size()->width()),
+                  safemath::MakeCheckedNum(image_constraints.size_alignment()->width()));
       auto out_width_stride =
-          RoundUp(out_width, safemath::MakeCheckedNum(image_constraints.bytes_per_row_divisor));
+          RoundUp(out_width, safemath::MakeCheckedNum(*image_constraints.bytes_per_row_divisor()));
       auto out_height =
-          RoundUp(safemath::MakeCheckedNum(image_constraints.required_max_coded_height),
-                  safemath::MakeCheckedNum(image_constraints.coded_height_divisor));
+          RoundUp(safemath::MakeCheckedNum(image_constraints.required_max_size()->height()),
+                  safemath::MakeCheckedNum(image_constraints.size_alignment()->height()));
 
       auto main_plane_size = out_width_stride * out_height;
       auto uv_plane_size = main_plane_size / 2;
@@ -281,12 +281,12 @@
       static constexpr auto kBytesPerRowPerTile =
           safemath::MakeCheckedNum(CodecAdapterVaApiDecoder::kTileSurfaceWidthAlignment);
 
-      auto aligned_stride =
-          RoundUp(safemath::MakeCheckedNum(image_constraints.required_max_coded_width),
-                  kBytesPerRowPerTile);
-      auto aligned_y_height = safemath::MakeCheckedNum(image_constraints.required_max_coded_height);
+      auto aligned_stride = RoundUp(safemath::MakeCheckedNum(image_constraints.max_size()->width()),
+                                    kBytesPerRowPerTile);
+      auto aligned_y_height =
+          safemath::MakeCheckedNum(image_constraints.required_max_size()->height());
       auto aligned_uv_height =
-          safemath::MakeCheckedNum(image_constraints.required_max_coded_height) / 2u;
+          safemath::MakeCheckedNum(image_constraints.required_max_size()->height()) / 2u;
 
       aligned_y_height = RoundUp(aligned_y_height, kRowsPerTile);
       aligned_uv_height = RoundUp(aligned_uv_height, kRowsPerTile);
diff --git a/src/media/codec/codecs/vaapi/test/h264_encoder_test.cc b/src/media/codec/codecs/vaapi/test/h264_encoder_test.cc
index 1519380..39c617f 100644
--- a/src/media/codec/codecs/vaapi/test/h264_encoder_test.cc
+++ b/src/media/codec/codecs/vaapi/test/h264_encoder_test.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <fidl/fuchsia.sysmem2/cpp/fidl.h>
 #include <lib/fdio/directory.h>
 #include <stdio.h>
 
@@ -44,20 +45,23 @@
 
   void onCoreCodecMidStreamOutputConstraintsChange(bool output_re_config_required) override {
     // Test a representative value.
-    auto output_constraints = codec_adapter_->CoreCodecGetBufferCollectionConstraints(
+    auto output_constraints = codec_adapter_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kOutputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    EXPECT_TRUE(output_constraints.buffer_memory_constraints.cpu_domain_supported);
+    EXPECT_TRUE(*output_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
     std::unique_lock<std::mutex> lock(lock_);
     // Wait for buffer initialization to complete to ensure all buffers are staged to be loaded.
     cond_.wait(lock, [&]() { return buffer_initialization_completed_; });
 
     // Fake out the client setting buffer constraints on sysmem
-    fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection;
-    buffer_collection.settings.image_format_constraints =
-        output_constraints.image_format_constraints.at(0);
-    buffer_collection.buffer_count = output_constraints.min_buffer_count_for_camping;
+    fuchsia_sysmem2::BufferCollectionInfo buffer_collection;
+    buffer_collection.settings().emplace();
+    if (output_constraints.image_format_constraints().has_value()) {
+      buffer_collection.settings()->image_format_constraints() =
+          output_constraints.image_format_constraints()->at(0);
+    }
+    buffer_collection.buffers().emplace(*output_constraints.min_buffer_count_for_camping());
     codec_adapter_->CoreCodecSetBufferCollectionInfo(CodecPort::kOutputPort, buffer_collection);
     codec_adapter_->CoreCodecMidStreamOutputBufferReConfigFinish();
   }
@@ -168,10 +172,10 @@
     format_details.set_domain(std::move(domain_format));
     encoder_->CoreCodecInit(format_details);
 
-    auto input_constraints = encoder_->CoreCodecGetBufferCollectionConstraints(
+    auto input_constraints = encoder_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kInputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    EXPECT_TRUE(input_constraints.buffer_memory_constraints.cpu_domain_supported);
+    EXPECT_TRUE(*input_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
     encoder_->CoreCodecStartStream();
     encoder_->CoreCodecQueueInputFormatDetails(format_details);
@@ -233,15 +237,15 @@
   // Nothing writes to the output packet so its size doesn't matter.
   constexpr size_t kOutputPacketSize = 4096;
   {
-    auto input_constraints = encoder_->CoreCodecGetBufferCollectionConstraints(
+    auto input_constraints = encoder_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kInputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    EXPECT_TRUE(input_constraints.buffer_memory_constraints.cpu_domain_supported);
+    EXPECT_TRUE(*input_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
     // Fake out the client setting buffer constraints on sysmem
-    fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection;
-    buffer_collection.settings.image_format_constraints =
-        input_constraints.image_format_constraints.at(0);
+    fuchsia_sysmem2::BufferCollectionInfo buffer_collection;
+    buffer_collection.settings().emplace().image_format_constraints() =
+        input_constraints.image_format_constraints()->at(0);
     encoder_->CoreCodecSetBufferCollectionInfo(CodecPort::kInputPort, buffer_collection);
   }
 
@@ -306,15 +310,15 @@
   // Nothing writes to the output packet so its size doesn't matter.
   constexpr size_t kOutputPacketSize = 4096;
   {
-    auto input_constraints = encoder_->CoreCodecGetBufferCollectionConstraints(
+    auto input_constraints = encoder_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kInputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    EXPECT_TRUE(input_constraints.buffer_memory_constraints.cpu_domain_supported);
+    EXPECT_TRUE(*input_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
     // Fake out the client setting buffer constraints on sysmem
-    fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection;
-    buffer_collection.settings.image_format_constraints =
-        input_constraints.image_format_constraints.at(0);
+    fuchsia_sysmem2::BufferCollectionInfo buffer_collection;
+    buffer_collection.settings().emplace().image_format_constraints() =
+        input_constraints.image_format_constraints()->at(0);
     encoder_->CoreCodecSetBufferCollectionInfo(CodecPort::kInputPort, buffer_collection);
   }
 
diff --git a/src/media/codec/codecs/vaapi/test/h264_vaapi_test.cc b/src/media/codec/codecs/vaapi/test/h264_vaapi_test.cc
index 22af646..77ecd2d 100644
--- a/src/media/codec/codecs/vaapi/test/h264_vaapi_test.cc
+++ b/src/media/codec/codecs/vaapi/test/h264_vaapi_test.cc
@@ -55,12 +55,12 @@
     {
       std::lock_guard lock(lock_);
       // Test a representative value.
-      output_constraints_ = codec_adapter_->CoreCodecGetBufferCollectionConstraints(
+      output_constraints_ = codec_adapter_->CoreCodecGetBufferCollectionConstraints2(
           CodecPort::kOutputPort, fuchsia::media::StreamBufferConstraints(),
           fuchsia::media::StreamBufferPartialSettings());
-      EXPECT_TRUE(output_constraints_.buffer_memory_constraints.cpu_domain_supported);
+      EXPECT_TRUE(*output_constraints_.buffer_memory_constraints()->cpu_domain_supported());
       EXPECT_EQ(kBearVideoWidth,
-                output_constraints_.image_format_constraints[0].required_min_coded_width);
+                output_constraints_.image_format_constraints()->at(0).required_min_size()->width());
       output_constraints_set_ = true;
       cond_.notify_all();
     }
@@ -140,16 +140,20 @@
     cond_.wait(lock, [&]() { return buffer_initialization_completed_; });
 
     // Set the codec output format to the linear format
-    auto output_constraints = codec_adapter_->CoreCodecGetBufferCollectionConstraints(
+    auto output_constraints = codec_adapter_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kOutputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection;
-    buffer_collection.settings.image_format_constraints =
-        output_constraints.image_format_constraints.at(0);
-    buffer_collection.settings.has_image_format_constraints = true;
-    buffer_collection.buffer_count = output_constraints.min_buffer_count_for_camping;
-    EXPECT_FALSE(
-        buffer_collection.settings.image_format_constraints.pixel_format.has_format_modifier);
+    fuchsia_sysmem2::BufferCollectionInfo buffer_collection;
+    buffer_collection.settings().emplace().image_format_constraints() =
+        output_constraints.image_format_constraints()->at(0);
+    buffer_collection.buffers().emplace(*output_constraints.min_buffer_count_for_camping());
+    if (!buffer_collection.settings()
+             ->image_format_constraints()
+             ->pixel_format_modifier()
+             .has_value()) {
+      buffer_collection.settings()->image_format_constraints()->pixel_format_modifier() =
+          fuchsia_images2::PixelFormatModifier::kLinear;
+    }
     codec_adapter_->CoreCodecSetBufferCollectionInfo(CodecPort::kOutputPort, buffer_collection);
     codec_adapter_->CoreCodecMidStreamOutputBufferReConfigFinish();
   }
@@ -175,7 +179,7 @@
   std::vector<CodecPacket *> output_packets_done_;
   bool buffer_initialization_completed_ = false;
   bool reconfigure_in_constraints_change_ = true;
-  fuchsia::sysmem::BufferCollectionConstraints output_constraints_;
+  fuchsia_sysmem2::BufferCollectionConstraints output_constraints_;
   bool output_constraints_set_ = false;
 };
 
@@ -203,10 +207,10 @@
     format_details.set_mime_type("video/h264");
     decoder_->CoreCodecInit(format_details);
 
-    auto input_constraints = decoder_->CoreCodecGetBufferCollectionConstraints(
+    auto input_constraints = decoder_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kInputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    EXPECT_TRUE(input_constraints.buffer_memory_constraints.cpu_domain_supported);
+    EXPECT_TRUE(*input_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
     decoder_->CoreCodecStartStream();
     decoder_->CoreCodecQueueInputFormatDetails(format_details);
@@ -355,7 +359,7 @@
   // video/x-motion-jpeg decode, video/h264 decode, video/vp9 decode, video/h264 encode
 
   // TODO(https://fxbug.dev/42166089): Uncomment this after new prebuilts have rolled.
-  //EXPECT_EQ(4u, codec_descriptions.size());
+  // EXPECT_EQ(4u, codec_descriptions.size());
 }
 
 // Test that we can connect using the CodecFactory.
diff --git a/src/media/codec/codecs/vaapi/test/vp9_vaapi_test.cc b/src/media/codec/codecs/vaapi/test/vp9_vaapi_test.cc
index 701e20e..bd82699 100644
--- a/src/media/codec/codecs/vaapi/test/vp9_vaapi_test.cc
+++ b/src/media/codec/codecs/vaapi/test/vp9_vaapi_test.cc
@@ -158,11 +158,12 @@
 
   void onCoreCodecMidStreamOutputConstraintsChange(bool output_re_config_required) override {
     // Test a representative value.
-    auto output_constraints = codec_adapter_->CoreCodecGetBufferCollectionConstraints(
+    auto output_constraints = codec_adapter_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kOutputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    EXPECT_TRUE(output_constraints.buffer_memory_constraints.cpu_domain_supported);
-    EXPECT_EQ(kVideoWidth, output_constraints.image_format_constraints[0].required_min_coded_width);
+    EXPECT_TRUE(*output_constraints.buffer_memory_constraints()->cpu_domain_supported());
+    EXPECT_EQ(kVideoWidth,
+              output_constraints.image_format_constraints()->at(0).required_min_size()->width());
 
     std::unique_lock<std::mutex> lock(lock_);
     // Wait for buffer initialization to complete to ensure all buffers are staged to be loaded.
@@ -171,13 +172,17 @@
     // Set the codec output format to the linear format and other various fields that sysmem would
     // normally populate. This is not meant to be an implementation of sysmem, only what is needed
     // for the test to work.
-    fuchsia::sysmem::BufferCollectionInfo_2 buffer_collection;
-    buffer_collection.settings.image_format_constraints =
-        output_constraints.image_format_constraints.at(0);
-    buffer_collection.settings.has_image_format_constraints = true;
-    buffer_collection.buffer_count = output_constraints.min_buffer_count_for_camping;
-    EXPECT_FALSE(
-        buffer_collection.settings.image_format_constraints.pixel_format.has_format_modifier);
+    fuchsia_sysmem2::BufferCollectionInfo buffer_collection;
+    buffer_collection.settings().emplace().image_format_constraints() =
+        output_constraints.image_format_constraints()->at(0);
+    buffer_collection.buffers().emplace(*output_constraints.min_buffer_count_for_camping());
+    if (!buffer_collection.settings()
+             ->image_format_constraints()
+             ->pixel_format_modifier()
+             .has_value()) {
+      buffer_collection.settings()->image_format_constraints()->pixel_format_modifier() =
+          fuchsia_images2::PixelFormatModifier::kLinear;
+    }
     codec_adapter_->CoreCodecSetBufferCollectionInfo(CodecPort::kOutputPort, buffer_collection);
     codec_adapter_->CoreCodecMidStreamOutputBufferReConfigFinish();
   }
@@ -280,10 +285,10 @@
     format_details.set_mime_type("video/vp9");
     decoder_->CoreCodecInit(format_details);
 
-    auto input_constraints = decoder_->CoreCodecGetBufferCollectionConstraints(
+    auto input_constraints = decoder_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kInputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    EXPECT_TRUE(input_constraints.buffer_memory_constraints.cpu_domain_supported);
+    EXPECT_TRUE(*input_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
     {
       std::lock_guard<std::mutex> guard(lock_);
@@ -312,10 +317,10 @@
     format_details.set_mime_type("video/vp9");
     decoder_->CoreCodecInit(format_details);
 
-    auto input_constraints = decoder_->CoreCodecGetBufferCollectionConstraints(
+    auto input_constraints = decoder_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kInputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
-    EXPECT_TRUE(input_constraints.buffer_memory_constraints.cpu_domain_supported);
+    EXPECT_TRUE(*input_constraints.buffer_memory_constraints()->cpu_domain_supported());
 
     decoder_->CoreCodecStartStream();
     decoder_->CoreCodecQueueInputFormatDetails(format_details);
@@ -568,21 +573,21 @@
   decoder_->CoreCodecInit(format_details);
 
   {
-    auto pre_cfg_constraints = decoder_->CoreCodecGetBufferCollectionConstraints(
+    auto pre_cfg_constraints = decoder_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kOutputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
 
-    ASSERT_EQ(pre_cfg_constraints.image_format_constraints_count, 2u);
+    ASSERT_EQ(pre_cfg_constraints.image_format_constraints()->size(), 2u);
 
-    const auto& linear_pixel_format = pre_cfg_constraints.image_format_constraints[0u].pixel_format;
-    EXPECT_TRUE(!linear_pixel_format.has_format_modifier ||
-                linear_pixel_format.format_modifier.value ==
-                    fuchsia::sysmem::FORMAT_MODIFIER_LINEAR);
+    const auto& linear_format_modifier =
+        pre_cfg_constraints.image_format_constraints()->at(0).pixel_format_modifier();
+    EXPECT_TRUE(!linear_format_modifier.has_value() ||
+                linear_format_modifier.value() == fuchsia_images2::PixelFormatModifier::kLinear);
 
-    const auto& tiled_pixel_format = pre_cfg_constraints.image_format_constraints[1u].pixel_format;
-    EXPECT_TRUE(tiled_pixel_format.has_format_modifier);
-    EXPECT_TRUE(tiled_pixel_format.format_modifier.value ==
-                fuchsia::sysmem::FORMAT_MODIFIER_INTEL_I915_Y_TILED);
+    const auto& tiled_image_constraints = pre_cfg_constraints.image_format_constraints()->at(1);
+    EXPECT_TRUE(tiled_image_constraints.pixel_format_modifier().has_value());
+    EXPECT_TRUE(tiled_image_constraints.pixel_format_modifier().value() ==
+                fuchsia_images2::PixelFormatModifier::kIntelI915YTiled);
   }
 
   decoder_->CoreCodecStartStream();
@@ -604,15 +609,16 @@
   events_.WaitForInputPacketsDone();
 
   {
-    auto post_cfg_constraints = decoder_->CoreCodecGetBufferCollectionConstraints(
+    auto post_cfg_constraints = decoder_->CoreCodecGetBufferCollectionConstraints2(
         CodecPort::kOutputPort, fuchsia::media::StreamBufferConstraints(),
         fuchsia::media::StreamBufferPartialSettings());
 
-    ASSERT_EQ(post_cfg_constraints.image_format_constraints_count, 1u);
+    ASSERT_EQ(post_cfg_constraints.image_format_constraints()->size(), 1u);
 
-    const auto& pixel_format = post_cfg_constraints.image_format_constraints[0u].pixel_format;
-    EXPECT_TRUE(!pixel_format.has_format_modifier ||
-                pixel_format.format_modifier.value == fuchsia::sysmem::FORMAT_MODIFIER_LINEAR);
+    const auto& image_format_constraints = post_cfg_constraints.image_format_constraints()->at(0);
+    EXPECT_TRUE(!image_format_constraints.pixel_format_modifier().has_value() ||
+                image_format_constraints.pixel_format_modifier().value() ==
+                    fuchsia_images2::PixelFormatModifier::kLinear);
   }
 
   EXPECT_EQ(kExpectedOutputPackets, events_.output_packet_count());
diff --git a/src/media/drivers/amlogic_decoder/BUILD.gn b/src/media/drivers/amlogic_decoder/BUILD.gn
index 0fc1c96..f1b9487e 100644
--- a/src/media/drivers/amlogic_decoder/BUILD.gn
+++ b/src/media/drivers/amlogic_decoder/BUILD.gn
@@ -158,6 +158,7 @@
       "registers.h",
       "secmem_session.cc",
       "secmem_session.h",
+      "setbuf_workaround.cc",
       "thread_role.h",
       "vdec1.cc",
       "vdec1.h",
diff --git a/src/media/drivers/amlogic_decoder/h264_multi_decoder.h b/src/media/drivers/amlogic_decoder/h264_multi_decoder.h
index f209ac3..8f8bec8 100644
--- a/src/media/drivers/amlogic_decoder/h264_multi_decoder.h
+++ b/src/media/drivers/amlogic_decoder/h264_multi_decoder.h
@@ -10,7 +10,6 @@
 #include <cstdint>
 #include <list>
 #include <map>
-#include <ostream>
 #include <string_view>
 #include <vector>
 
diff --git a/src/media/drivers/amlogic_decoder/setbuf_workaround.cc b/src/media/drivers/amlogic_decoder/setbuf_workaround.cc
new file mode 100644
index 0000000..74298bb
--- /dev/null
+++ b/src/media/drivers/amlogic_decoder/setbuf_workaround.cc
@@ -0,0 +1,14 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <zircon/assert.h>
+
+// TODO(b/333745994): This workaround prevents the driver from importing setbuf, but TBD why the
+// driver is importing setbuf with the new clang.
+extern "C" void setbuf(FILE* __restrict, char* __restrict) {
+  // While setbuf symbol is imported, we don't expect it to actually get called. If it is called,
+  // panic.
+  ZX_PANIC("setbuf called");
+}
diff --git a/src/media/drivers/amlogic_decoder/video_decoder.h b/src/media/drivers/amlogic_decoder/video_decoder.h
index 04815c5..f8517e6 100644
--- a/src/media/drivers/amlogic_decoder/video_decoder.h
+++ b/src/media/drivers/amlogic_decoder/video_decoder.h
@@ -25,7 +25,6 @@
 #include <zircon/syscalls.h>
 
 #include <functional>
-#include <sstream>
 #include <string>
 #include <string_view>
 #include <type_traits>
diff --git a/src/media/drivers/amlogic_decoder/vp9_decoder.h b/src/media/drivers/amlogic_decoder/vp9_decoder.h
index 3fa71b9..d7f2a20 100644
--- a/src/media/drivers/amlogic_decoder/vp9_decoder.h
+++ b/src/media/drivers/amlogic_decoder/vp9_decoder.h
@@ -9,7 +9,6 @@
 #include <lib/async/cpp/task.h>
 
 #include <cstdint>
-#include <ostream>
 #include <string_view>
 #include <vector>
 
diff --git a/src/media/sounds/example/src/main.rs b/src/media/sounds/example/src/main.rs
index e903d74..218cc8d 100644
--- a/src/media/sounds/example/src/main.rs
+++ b/src/media/sounds/example/src/main.rs
@@ -109,35 +109,13 @@
 
 /// Creates a file channel from a resource file.
 async fn resource_file(name: &str) -> Result<fidl::endpoints::ClientEnd<fio::FileMarker>> {
-    let open = |directory| {
-        use fidl::endpoints::Proxy as _;
-
-        let proxy = fuchsia_fs::file::open_in_namespace(
-            &format!("{directory}/{name}"),
-            fio::OpenFlags::RIGHT_READABLE,
-        )?;
-
-        Ok::<_, anyhow::Error>(proxy.into_channel().unwrap())
-    };
-
-    // We try two paths here, because normal components see their package data resources in
-    // /pkg/data and shell tools see them in /pkgfs/packages/<pkg>>/0/data.
-    let pkg = open("/pkg/data")?;
-    let pkgfs = open("/pkgfs/packages/soundplayer_example/0/data")?;
-
-    let file = futures::select! {
-        signals = pkg.on_closed().fuse() => {
-            let _: zx::Signals = signals?;
-            pkgfs
-        }
-        signals = pkgfs.on_closed().fuse() => {
-            let _: zx::Signals = signals?;
-            pkg
-        }
-    }
-    .into_zx_channel();
-
-    Ok::<_, anyhow::Error>(file.into())
+    use fidl::endpoints::Proxy as _;
+    let path = format!("/pkg/data/{name}");
+    let file = fuchsia_fs::file::open_in_namespace(&path, fio::OpenFlags::RIGHT_READABLE)
+        .with_context(|| format!("opening resource file: {path}"))?
+        .into_client_end()
+        .unwrap();
+    Ok(file)
 }
 
 /// Creates a file channel from a file name.
diff --git a/src/performance/experimental/profiler/README.md b/src/performance/experimental/profiler/README.md
index d4f2702..d0f3974 100644
--- a/src/performance/experimental/profiler/README.md
+++ b/src/performance/experimental/profiler/README.md
@@ -52,13 +52,7 @@
 ffx profiler start --pid <target pid> --duration 5
 ```
 
-This will place a `profile.out` file in your current directory. You'll need to export it to pprof format.
-
-```
-fx samples_to_pprof profile.out
-```
-
-This will output the file `profile.out.pb` which can be handed to pprof.
+This will place a `profile.pb` file in your current directory which can be handed to pprof.
 
 ```
 $ pprof -top profile.out.pb
diff --git a/src/performance/experimental/profiler/samples_to_pprof/BUILD.gn b/src/performance/experimental/profiler/samples_to_pprof/BUILD.gn
index 28d5fdd..3f0e43f 100644
--- a/src/performance/experimental/profiler/samples_to_pprof/BUILD.gn
+++ b/src/performance/experimental/profiler/samples_to_pprof/BUILD.gn
@@ -3,16 +3,17 @@
 # found in the LICENSE file.
 
 import("//build/host.gni")
+import("//build/rust/rustc_library.gni")
 import("//build/test.gni")
 import("//third_party/protobuf/proto_library.gni")
 
 source_set("samples_to_pprof_src") {
   sources = [ "samples_to_pprof.cc" ]
-  deps = [
+  public_deps = [
     # TODO(https://fxbug.dev/42066681): Replace with pprof.
     # "//third_party/github.com/google/pprof:profile_proto",
     ":profile_proto",
-    "//src/lib/fxl",
+    "//sdk/lib/fit",
     "//third_party/protobuf:protobuf_full",
   ]
 }
@@ -24,9 +25,30 @@
     deps = [
       ":profile_proto",
       ":samples_to_pprof_src",
-      "//src/lib/fxl",
+      "//sdk/lib/fit",
     ]
   }
+
+  static_library("rust_samples_to_pprof") {
+    visibility = [ ":*" ]
+    deps = [
+      ":profile_proto",
+      ":samples_to_pprof_src",
+      "//sdk/lib/fit",
+      "//src/zircon/lib/zircon:headers",
+      "//third_party/protobuf:protobuf_full",
+    ]
+    sources = [ "samples_to_pprof_rust.cc" ]
+  }
+
+  rustc_library("samples_to_pprof_rust") {
+    name = "samples_to_pprof"
+    edition = "2021"
+    source_root = "rust/src/lib.rs"
+    deps = [ ":rust_samples_to_pprof" ]
+
+    sources = [ "rust/src/lib.rs" ]
+  }
 }
 
 test("samples_to_pprof_test") {
diff --git a/src/performance/experimental/profiler/samples_to_pprof/rust/src/lib.rs b/src/performance/experimental/profiler/samples_to_pprof/rust/src/lib.rs
new file mode 100644
index 0000000..51aed8f
--- /dev/null
+++ b/src/performance/experimental/profiler/samples_to_pprof/rust/src/lib.rs
@@ -0,0 +1,26 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::ffi::CString;
+
+// Given a symbolized file output by ffx profiler start, convert it to pprof protobuf output format
+pub fn convert(from: String, to: String) -> bool {
+    unsafe {
+        return sys::convert(
+            // Strings do not have interior nul bytes so this is safe.
+            CString::from_vec_unchecked(from.into()).as_c_str().as_ptr(),
+            CString::from_vec_unchecked(to.into()).as_c_str().as_ptr(),
+        ) == 0;
+    }
+}
+
+mod sys {
+    use std::ffi::c_char;
+    use std::ffi::c_int;
+    #[link(name = "rust_samples_to_pprof")]
+    extern "C" {
+        // See the C++ documentation for this function in samples_to_pprof_rust.cc
+        pub(super) fn convert(from: *const c_char, to: *const c_char) -> c_int;
+    }
+}
diff --git a/src/performance/experimental/profiler/samples_to_pprof/samples_to_pprof_rust.cc b/src/performance/experimental/profiler/samples_to_pprof/samples_to_pprof_rust.cc
new file mode 100644
index 0000000..683b2f4
--- /dev/null
+++ b/src/performance/experimental/profiler/samples_to_pprof/samples_to_pprof_rust.cc
@@ -0,0 +1,37 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <zircon/compiler.h>
+
+#include <fstream>
+#include <iostream>
+
+#include "samples_to_pprof.h"
+
+__BEGIN_CDECLS
+int convert(const char* in_file, const char* out_file) __attribute__((visibility("default")));
+__END_CDECLS
+
+// C compatible declaration to convert `in_file` to pprof protobuf format and write the output to
+// out_file.
+//
+// Returns 0 on success, or non zero on failure.
+int convert(const char* in_file, const char* out_file) {
+  if (!in_file || !out_file) {
+    return 1;
+  }
+  std::string out_path(out_file);
+
+  std::ifstream in;
+  in.open(in_file);
+  std::ofstream out(out_path.c_str(), std::ios::out);
+
+  auto pprof = samples_to_profile(std::move(in));
+  if (pprof.is_error()) {
+    std::cerr << "Writing samples failed: " << pprof.error_value() << '\n';
+    return 1;
+  }
+  pprof.value().SerializePartialToOstream(&out);
+  return 0;
+}
diff --git a/src/performance/lib/trace_processing/metrics/cpu_breakdown.py b/src/performance/lib/trace_processing/metrics/cpu_breakdown.py
index 1d31487..1c6be5c 100644
--- a/src/performance/lib/trace_processing/metrics/cpu_breakdown.py
+++ b/src/performance/lib/trace_processing/metrics/cpu_breakdown.py
@@ -12,23 +12,34 @@
 
 _LOGGER: logging.Logger = logging.getLogger("CpuBreakdownMetricsProcessor")
 
+# Default cut-off for the percentage CPU. Any process that has CPU below this
+# won't be listed in the results. User can pass in a cutoff.
+DEFAULT_PERCENT_CUTOFF = 0.0
+
 
 class CpuBreakdownMetricsProcessor:
     """
-    Breaks down CPU metrics into a free-form metrics format, and
-    writes the metrics to JSON.
+    Breaks down CPU metrics into a free-form metrics format.
     """
 
-    def __init__(self, model: trace_model.Model) -> None:
+    def __init__(
+        self,
+        model: trace_model.Model,
+        output_path: str = "",
+        percent_cutoff: float = DEFAULT_PERCENT_CUTOFF,
+    ) -> None:
         self._model: trace_model.Model = model
+        self._percent_cutoff = percent_cutoff
+        self._output_path: str = output_path
         # Maps TID to a Dict of CPUs to total duration (ms) on that CPU.
         # E.g. For a TID of 1001 with 3 CPUs, this would be:
         #   {1001: {0: 1123.123, 1: 123123.123, 3: 1231.23}}
         self._tid_to_durations: Dict[int, Dict[int, float]] = {}
-        # Currently we just print this but we will output a JSON soon.
-        self._breakdown: Dict[str, Dict[int, float]] = {}
-        # Name composed of Process name and Thread name.
-        self._tid_to_name: Dict[int, str] = {}
+        self._breakdown: List[Dict[str, object]] = []
+        self._tid_to_thread_name: Dict[int, str] = {}
+        self._tid_to_process_name: Dict[int, str] = {}
+        # Map of CPU to total duration used (ms).
+        self._cpu_to_total_duration: Dict[int, float] = {}
 
     def _calculate_duration_per_cpu(
         self,
@@ -41,6 +52,11 @@
         Uses a List of sorted ContextSwitch records to sum up the duration for each thread.
         It's possible that consecutive records do not have matching incoming_tid and outgoing_tid.
         """
+        smallest_timestamp = self._timestamp_ms(records[0].start)
+        largest_timestamp = self._timestamp_ms(records[-1].start)
+        total_duration = largest_timestamp - smallest_timestamp
+        self._cpu_to_total_duration[cpu] = total_duration
+
         for prev_record, curr_record in itertools.pairwise(records):
             # Check that the previous ContextSwitch's incoming_tid ("this thread is starting work
             # on this CPU") matches the current ContextSwitch's outgoing_tid ("this thread is being
@@ -59,7 +75,7 @@
                 stop_ts = self._timestamp_ms(curr_record.start)
                 duration = stop_ts - start_ts
                 assert duration >= 0
-                if curr_record.outgoing_tid in self._tid_to_name:
+                if curr_record.outgoing_tid in self._tid_to_thread_name:
                     # Add duration to the total duration for that tid and CPU.
                     self._tid_to_durations.setdefault(
                         curr_record.outgoing_tid, {}
@@ -75,17 +91,18 @@
         """
         return timestamp.to_epoch_delta().to_milliseconds_f()
 
-    def process_metrics(self) -> Dict[str, Dict[int, float]]:
+    def process_metrics(self) -> List[Dict[str, object]]:
         """
         Given TraceModel:
         - Iterates through all the SchedulingRecords and calculates the duration
         for each Process's Threads, and saves them by CPU.
-        - Writes durations into free-form-metric JSON file. (TODO: https://fxbug.dev/331457527)
+        - Writes durations into free-form-metric JSON file.
         """
         # Map tids to names.
         for p in self._model.processes:
             for t in p.threads:
-                self._tid_to_name[t.tid] = "%s: %s" % (p.name, t.name)
+                self._tid_to_process_name[t.tid] = p.name
+                self._tid_to_thread_name[t.tid] = t.name
 
         # Calculate durations for each CPU for each tid.
         for cpu, records in self._model.scheduling_records.items():
@@ -101,10 +118,30 @@
                 ),
             )
 
-        # Return CPU breakdown.
-        # TODO: https://fxbug.dev/331457527 format this better.
-        for tid in self._tid_to_durations:
-            self._breakdown[self._tid_to_name[tid]] = self._tid_to_durations[
-                tid
-            ]
+        # Calculate the percent of time the thread spent on this CPU,
+        # compared to the total CPU duration.
+        # If the percent spent is at or above our cutoff, add metric to
+        # breakdown.
+        for tid, breakdown in self._tid_to_durations.items():
+            if tid in self._tid_to_thread_name:
+                for cpu, duration in breakdown.items():
+                    percent = round(
+                        duration / self._cpu_to_total_duration[cpu] * 100, 3
+                    )
+                    if percent >= self._percent_cutoff:
+                        metric = {
+                            "process_name": self._tid_to_process_name[tid],
+                            "thread_name": self._tid_to_thread_name[tid],
+                            "cpu": cpu,
+                            "percent": percent,
+                            "duration": duration,
+                        }
+                        self._breakdown.append(metric)
+
+        # Sort metrics by CPU (desc) and percent (desc).
+        self._breakdown = sorted(
+            self._breakdown,
+            key=lambda m: (m["cpu"], m["percent"]),
+            reverse=True,
+        )
         return self._breakdown
diff --git a/src/performance/lib/trace_processing/run_cpu_breakdown.py b/src/performance/lib/trace_processing/run_cpu_breakdown.py
index c7fb29b..f56871a 100644
--- a/src/performance/lib/trace_processing/run_cpu_breakdown.py
+++ b/src/performance/lib/trace_processing/run_cpu_breakdown.py
@@ -8,24 +8,40 @@
 """
 
 import argparse
-import os.path
+import json
 from trace_processing import trace_importing, trace_metrics, trace_model
 from trace_processing.metrics import cpu_breakdown
 import sys
 
 
+# Default cut-off for the percentage CPU. Any process that has CPU below this
+# won't be listed in the results. User can pass in a cutoff.
+DEFAULT_PERCENT_CUTOFF = 0.0
+
+
 def main() -> None:
     """
-    Takes in a trace file in JSON format.
+    Takes in a trace file in JSON format and outputs
+    a free-form JSON with breakdown metrics to `output_path`.
     """
     parser = argparse.ArgumentParser()
-    parser.add_argument("path_to_json")
+    parser.add_argument("path_to_trace_json", type=str)
+    parser.add_argument("output_path", type=str)
+    parser.add_argument(
+        "--percent_cutoff", type=float, default=DEFAULT_PERCENT_CUTOFF
+    )
     args = parser.parse_args()
 
     model: trace_model.Model = trace_importing.create_model_from_file_path(
-        args.path_to_json
+        args.path_to_trace_json
     )
-    cpu_breakdown.CpuBreakdownMetricsProcessor(model).process_metrics()
+    breakdown = cpu_breakdown.CpuBreakdownMetricsProcessor(
+        model, args.percent_cutoff
+    ).process_metrics()
+
+    if args.output_path:
+        with open(args.output_path, "w") as json_file:
+            json.dump(breakdown, json_file)
 
 
 if __name__ == "__main__":
diff --git a/src/performance/lib/trace_processing/tests/cpu_breakdown_test.py b/src/performance/lib/trace_processing/tests/cpu_breakdown_test.py
index 52a0289..7ec6f8a 100644
--- a/src/performance/lib/trace_processing/tests/cpu_breakdown_test.py
+++ b/src/performance/lib/trace_processing/tests/cpu_breakdown_test.py
@@ -29,11 +29,11 @@
         ]
 
         # CPU 2.
+        # Total time: 0 to 8000000000 = 8000 ms.
         records_2: List[trace_model.SchedulingRecord] = [
-            # "thread-1" is active from 500-1000 ms, 500 total duration.
-            trace_model.Waking(trace_time.TimePoint(100000000), 2, 612, {}),
+            # "thread-1" is active from 0 - 1500 ms, 1500 total duration.
             trace_model.ContextSwitch(
-                trace_time.TimePoint(500000000),
+                trace_time.TimePoint(0),
                 1,
                 100,
                 612,
@@ -42,7 +42,7 @@
                 {},
             ),
             trace_model.ContextSwitch(
-                trace_time.TimePoint(1000000000),
+                trace_time.TimePoint(1500000000),
                 100,
                 1,
                 612,
@@ -50,7 +50,7 @@
                 trace_model.ThreadState.ZX_THREAD_STATE_BLOCKED,
                 {},
             ),
-            # "small-thread" is active from 1000 to 2000 ms, 1000 total duration.
+            # "small-thread" is active from 1500 to 2000 ms, 500 total duration.
             trace_model.ContextSwitch(
                 trace_time.TimePoint(2000000000),
                 1,
@@ -60,10 +60,10 @@
                 trace_model.ThreadState.ZX_THREAD_STATE_BLOCKED,
                 {},
             ),
-            # "thread-2" is active from 3000-9000 ms, 6000 total duration.
+            # "thread-2" is active from 3000-8000 ms, 5000 total duration.
             # Switch the order of adding to records - shouldn't change behavior.
             trace_model.ContextSwitch(
-                trace_time.TimePoint(9000000000),
+                trace_time.TimePoint(8000000000),
                 100,
                 2,
                 612,
@@ -84,8 +84,10 @@
         ]
 
         # CPU 3.
+        # Total time: 3000000000 to 6000000000 = 3000 ms.
         records_3: List[trace_model.SchedulingRecord] = [
-            # "thread-3" (incoming) is idle; don't log it.
+            # "thread-3" (incoming) is idle; don't log it in breakdown,
+            # but do log it in the total CPU duration for CPU 3.
             trace_model.ContextSwitch(
                 trace_time.TimePoint(3000000000),
                 3,
@@ -105,7 +107,8 @@
                 trace_model.ThreadState.ZX_THREAD_STATE_BLOCKED,
                 {},
             ),
-            # TID 70 (outgoing) is idle; don't log it.
+            # TID 70 (outgoing) is idle; don't log it in breakdown,
+            # but do log it in the total CPU duration for CPU 3.
             # "thread-2" (incoming) is not idle.
             trace_model.ContextSwitch(
                 trace_time.TimePoint(5000000000),
@@ -129,10 +132,11 @@
         ]
 
         # CPU 5.
+        # Total time: 500000000 to 6000000000 = 5500
         records_5: List[trace_model.SchedulingRecord] = []
         # Add 5 Waking and ContextSwitch events for "thread-1" where the incoming_tid
         # is 1 and the outgoing_tid (70) is not mapped to a Thread in our Process.
-        for i in range(1, 6):
+        for i in range(1, 7):
             records_5.append(
                 trace_model.Waking(
                     trace_time.TimePoint(i * 1000000000 - 500000000),
@@ -187,17 +191,49 @@
         processor = cpu_breakdown.CpuBreakdownMetricsProcessor(model)
         breakdown = processor.process_metrics()
 
-        self.assertEqual(len(breakdown), 3)
+        self.assertEqual(len(breakdown), 5)
 
         # Each process: thread has the correct numbers for each CPU.
+        # Sorted by descending cpu and descending percent.
+        # Note that neither thread-3 nor thread-4 are logged because
+        # they are idle or there is no duration.
         self.assertEqual(
-            breakdown["big_process: thread-1"], {2: 500.0, 5: 2500.0}
+            breakdown,
+            [
+                {
+                    "process_name": "big_process",
+                    "thread_name": "thread-1",
+                    "cpu": 5,
+                    "percent": 54.545,
+                    "duration": 3000.0,
+                },
+                {
+                    "process_name": "big_process",
+                    "thread_name": "thread-2",
+                    "cpu": 3,
+                    "percent": 33.333,
+                    "duration": 1000.0,
+                },
+                {
+                    "process_name": "big_process",
+                    "thread_name": "thread-2",
+                    "cpu": 2,
+                    "percent": 62.5,
+                    "duration": 5000.0,
+                },
+                {
+                    "process_name": "big_process",
+                    "thread_name": "thread-1",
+                    "cpu": 2,
+                    "percent": 18.75,
+                    "duration": 1500.0,
+                },
+                {
+                    "process_name": "small_process",
+                    "thread_name": "small-thread",
+                    "cpu": 2,
+                    "percent": 6.25,
+                    "duration": 500.0,
+                },
+            ],
         )
-        self.assertEqual(
-            breakdown["big_process: thread-2"], {2: 6000.0, 3: 1000.0}
-        )
-        self.assertEqual(breakdown["small_process: small-thread"], {2: 1000.0})
-        # If thread is idle, don't log it.
-        self.assertNotIn("big_process: thread-3", breakdown)
-        # If there is no duration for the thread, don't log it.
-        self.assertNotIn("big_process: thread-4", breakdown)
diff --git a/src/performance/memory/attribution/src/attribution_server.rs b/src/performance/memory/attribution/src/attribution_server.rs
index 6a282a1..45a3001b 100644
--- a/src/performance/memory/attribution/src/attribution_server.rs
+++ b/src/performance/memory/attribution/src/attribution_server.rs
@@ -39,23 +39,17 @@
 /// [Observer] object using [AttributionServer::new_observer].
 /// [Publisher]s, created using [AttributionServer::new_publisher], should be
 /// used to push attribution changes.
-pub struct AttributionServer {
-    inner: Arc<Mutex<AttributionServerInner>>,
+#[derive(Clone)]
+pub struct AttributionServerHandle {
+    inner: Arc<Mutex<AttributionServer>>,
 }
 
-impl AttributionServer {
-    /// Create a new memory attribution server.
-    ///
-    /// `state` is a function returning the complete attribution state (not partial updates).
-    pub fn new(state: Box<GetAttributionFn>) -> Self {
-        Self { inner: Arc::new(Mutex::new(AttributionServerInner::new(state))) }
-    }
-
+impl AttributionServerHandle {
     /// Create a new [Observer] that represents a single client.
     ///
     /// Each FIDL client connection should get its own [Observer] object.
     pub fn new_observer(&self, control_handle: fattribution::ProviderControlHandle) -> Observer {
-        AttributionServerInner::register(&self.inner, control_handle)
+        AttributionServer::register(&self.inner, control_handle)
     }
 
     /// Create a new [Publisher] that can push updates to observers.
@@ -68,7 +62,7 @@
 /// get calls. These will be notified when the state changes or immediately the first time
 /// an `Observer` registers an observation.
 pub struct Observer {
-    inner: Arc<Mutex<AttributionServerInner>>,
+    inner: Arc<Mutex<AttributionServer>>,
 }
 
 impl Observer {
@@ -92,7 +86,7 @@
 
 /// A [Publisher] should be used to send updates to [Observer]s.
 pub struct Publisher {
-    inner: Arc<Mutex<AttributionServerInner>>,
+    inner: Arc<Mutex<AttributionServer>>,
 }
 
 impl Publisher {
@@ -109,14 +103,19 @@
     }
 }
 
-struct AttributionServerInner {
+pub struct AttributionServer {
     state: Box<GetAttributionFn>,
     consumer: Option<AttributionConsumer>,
 }
 
-impl AttributionServerInner {
-    pub fn new(state: Box<GetAttributionFn>) -> Self {
-        Self { state, consumer: None }
+impl AttributionServer {
+    /// Create a new memory attribution server.
+    ///
+    /// `state` is a function returning the complete attribution state (not partial updates).
+    pub fn new(state: Box<GetAttributionFn>) -> AttributionServerHandle {
+        AttributionServerHandle {
+            inner: Arc::new(Mutex::new(AttributionServer { state, consumer: None })),
+        }
     }
 
     pub fn on_update(
@@ -266,7 +265,12 @@
     /// Create a new [AttributionConsumer] without an `observer` and an initial `dirty`
     /// value of `true`.
     pub fn new(observer_control_handle: fattribution::ProviderControlHandle) -> Self {
-        AttributionConsumer { first: true, pending: HashMap::new(), observer_control_handle: observer_control_handle, responder: None }
+        AttributionConsumer {
+            first: true,
+            pending: HashMap::new(),
+            observer_control_handle: observer_control_handle,
+            responder: None,
+        }
     }
 
     /// Register a new observation request. The observer will be notified immediately if
@@ -488,7 +492,6 @@
 
         assert_matches!(result2, Err(ClientChannelClosed { status: zx::Status::BAD_STATE, .. }));
         assert_matches!(result, Err(ClientChannelClosed { status: zx::Status::BAD_STATE, .. }));
-
     }
 
     /// Tests that the first get call returns the full state, not updates.
@@ -513,14 +516,14 @@
         .detach();
 
         server
-        .new_publisher()
-        .on_update(vec![fattribution::AttributionUpdate::Update(
-            fattribution::UpdatedPrincipal {
-                identifier: Some(fattribution::Identifier::Self_(fattribution::Self_)),
-                ..Default::default()
-            },
-        )])
-        .expect("Error sending the update");
+            .new_publisher()
+            .on_update(vec![fattribution::AttributionUpdate::Update(
+                fattribution::UpdatedPrincipal {
+                    identifier: Some(fattribution::Identifier::Self_(fattribution::Self_)),
+                    ..Default::default()
+                },
+            )])
+            .expect("Error sending the update");
 
         // As this is the first call, we should get the full state, not the update.
         let attributions =
diff --git a/src/performance/memory/attribution/src/lib.rs b/src/performance/memory/attribution/src/lib.rs
index b032c2b..d3dcc98 100644
--- a/src/performance/memory/attribution/src/lib.rs
+++ b/src/performance/memory/attribution/src/lib.rs
@@ -4,4 +4,7 @@
 
 mod attribution_server;
 
-pub use attribution_server::{AttributionServer, AttributionServerObservationError};
+pub use attribution_server::{
+    AttributionServer, AttributionServerHandle, AttributionServerObservationError, Observer,
+    Publisher,
+};
diff --git a/src/power/battery-manager/battery-cli/BUILD.gn b/src/power/battery-manager/battery-cli/BUILD.gn
index 81b0e5d..a8a3bec 100644
--- a/src/power/battery-manager/battery-cli/BUILD.gn
+++ b/src/power/battery-manager/battery-cli/BUILD.gn
@@ -17,7 +17,6 @@
     "//src/lib/fuchsia-component",
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:futures",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:rustyline",
   ]
 
diff --git a/src/power/battery-manager/battery-cli/src/main.rs b/src/power/battery-manager/battery-cli/src/main.rs
index 0655202..a850cd9 100644
--- a/src/power/battery-manager/battery-cli/src/main.rs
+++ b/src/power/battery-manager/battery-cli/src/main.rs
@@ -14,9 +14,8 @@
         channel::mpsc::{channel, SendError},
         Sink, SinkExt, Stream, StreamExt, TryFutureExt,
     },
-    pin_utils::pin_mut,
     rustyline::{error::ReadlineError, CompletionType, Config, EditMode, Editor},
-    std::{fmt, thread, time::Duration},
+    std::{fmt, pin::pin, thread, time::Duration},
 };
 
 static PROMPT: &str = "\x1b[34mbattman>\x1b[0m ";
@@ -344,11 +343,8 @@
 async fn main() -> Result<(), Error> {
     println!("Welcome to the Battery Simulator. Type help and <Enter> to see all the options!");
     let battery_simulator = connect_to_protocol::<spower::BatterySimulatorMarker>()?;
-    let repl = run_repl(battery_simulator)
-        .unwrap_or_else(|e| eprintln!("REPL failed unexpectedly {:?}", e));
-
-    // Pins repl value on the stack
-    pin_mut!(repl);
+    let repl = pin!(run_repl(battery_simulator)
+        .unwrap_or_else(|e| eprintln!("REPL failed unexpectedly {:?}", e)));
 
     repl.await;
 
diff --git a/src/power/battery-manager/src/battery_manager.rs b/src/power/battery-manager/src/battery_manager.rs
index d1364f8..7371aae 100644
--- a/src/power/battery-manager/src/battery_manager.rs
+++ b/src/power/battery-manager/src/battery_manager.rs
@@ -197,6 +197,14 @@
 
                 new_battery_info.present_voltage_mv = Some(bi.present_voltage);
 
+                let battery_spec = fpower::BatterySpec {
+                    max_charging_current_ua: bi.battery_spec.max_charging_current_ua,
+                    max_charnging_voltage_uv: bi.battery_spec.max_charnging_voltage_uv,
+                    design_capacity_uah: bi.battery_spec.design_capacity_uah,
+                    ..Default::default()
+                };
+                new_battery_info.battery_spec = Some(battery_spec);
+
                 match bi.unit {
                     hpower::BatteryUnit::Ma => {
                         new_battery_info.remaining_capacity_uah =
@@ -387,6 +395,12 @@
             present_rate: -500,
             remaining_capacity: 3000,
             present_voltage: 7000,
+            battery_spec: hpower::BatterySpec {
+                max_charging_current_ua: Some(500000),
+                max_charnging_voltage_uv: Some(5000000),
+                design_capacity_uah: Some(380000),
+                ..Default::default()
+            },
         };
         return battery_info;
     }
diff --git a/src/power/battery-manager/src/battery_simulator.rs b/src/power/battery-manager/src/battery_simulator.rs
index e360643..46381af 100644
--- a/src/power/battery-manager/src/battery_simulator.rs
+++ b/src/power/battery-manager/src/battery_simulator.rs
@@ -115,6 +115,15 @@
         Ok(())
     }
 
+    async fn set_battery_spec(&self, spec: fpower::BatterySpec) -> Result<(), Error> {
+        let mut battery_info = self.battery_info.lock().await;
+        battery_info.battery_spec = Some(spec);
+        battery_info.timestamp = get_current_time();
+        drop(battery_info);
+        self.notify_battery_info_changed().await?;
+        Ok(())
+    }
+
     // Updates the simulated_battery_info in BatteryManager
     async fn notify_battery_info_changed(&self) -> Result<(), Error> {
         let observer = self.observer.upgrade().ok_or(format_err!("Observer not found"))?;
@@ -182,6 +191,9 @@
                 spower::BatterySimulatorRequest::IsSimulating { responder: _, .. } => {
                     Err(format_err!("Unexpected Simulating requested called"))?
                 }
+                spower::BatterySimulatorRequest::SetBatterySpec { spec, .. } => {
+                    self.set_battery_spec(spec).await?;
+                }
             }
             Ok::<(), Error>(())
         }
diff --git a/src/power/battery-manager/tests/integration_test.cc b/src/power/battery-manager/tests/integration_test.cc
index 90695bc..7d36b56 100644
--- a/src/power/battery-manager/tests/integration_test.cc
+++ b/src/power/battery-manager/tests/integration_test.cc
@@ -55,10 +55,9 @@
 
   void CreateAndConnectToWatcher() {
     watcher_ = std::make_unique<FakeInfoWatcher>();
-    auto endpoints = fidl::CreateEndpoints<fuchsia_power_battery::BatteryInfoWatcher>();
-    EXPECT_EQ(endpoints.status_value(), ZX_OK);
-    fidl::BindServer(dispatcher(), std::move(endpoints->server), watcher_.get());
-    watcher_client_.Bind(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_power_battery::BatteryInfoWatcher>::Create();
+    fidl::BindServer(dispatcher(), std::move(endpoints.server), watcher_.get());
+    watcher_client_.Bind(std::move(endpoints.client));
   }
 
   bool WatcherCalled() { return watcher_->called(); }
diff --git a/src/power/broker/BUILD.gn b/src/power/broker/BUILD.gn
index a50fc94..b46619d 100644
--- a/src/power/broker/BUILD.gn
+++ b/src/power/broker/BUILD.gn
@@ -21,13 +21,6 @@
   ]
 }
 
-# Forwarding declaration for //vendor/* dependencies.
-# Remove after soft transition.
-group("fuchsia.power.broker_rust") {
-  public_deps = [ "//sdk/fidl/fuchsia.power.broker:fuchsia.power.broker_rust" ]
-  visibility = [ "//vendor/*" ]
-}
-
 rustc_binary("bin") {
   output_name = "power-broker"
   edition = "2021"
diff --git a/src/power/broker/src/broker.rs b/src/power/broker/src/broker.rs
index 95c0abf..670800c 100644
--- a/src/power/broker/src/broker.rs
+++ b/src/power/broker/src/broker.rs
@@ -563,7 +563,10 @@
             if let Some(default_level) = self.topology.minimum_level(element_id) {
                 default_level
             } else {
-                tracing::error!("calculate_required_level: no minimum_level for {:?}", element_id);
+                // TODO(https://fxbug.dev/333930405): This can be `tracing::error!` again if
+                // dropping a lease after its corresponding element is gone is handled properly.
+                // See `session-manager-integration-test.cm` that exercises that case.
+                tracing::warn!("calculate_required_level: no minimum_level for {:?}", element_id);
                 BinaryPowerLevel::Off.into_primitive()
             }
         }
diff --git a/src/power/fake-powersource/power_source_state.h b/src/power/fake-powersource/power_source_state.h
index 5fcd324..becf951e 100644
--- a/src/power/fake-powersource/power_source_state.h
+++ b/src/power/fake-powersource/power_source_state.h
@@ -48,6 +48,11 @@
       .present_rate = 2,
       .remaining_capacity = 2900,
       .present_voltage = 2910,
+      .battery_spec = fuchsia_hardware_powersource::BatterySpec{{
+          .max_charging_current_ua = 1000000,
+          .max_charnging_voltage_uv = 5000000,
+          .design_capacity_uah = 300000,
+      }},
   }};
   fuchsia_hardware_powersource::SourceInfo source_info_;
   std::unordered_set<Observer*> observers_;
diff --git a/src/power/power-manager/testing/fake_driver/cpu_ctrl_driver.cc b/src/power/power-manager/testing/fake_driver/cpu_ctrl_driver.cc
index 7f938d0..6cf1dbd 100644
--- a/src/power/power-manager/testing/fake_driver/cpu_ctrl_driver.cc
+++ b/src/power/power-manager/testing/fake_driver/cpu_ctrl_driver.cc
@@ -23,6 +23,16 @@
     return result.take_error();
   }
 
+  fuchsia_hardware_cpu_ctrl::Service::InstanceHandler handler({
+      .device = fit::bind_member<&CpuCtrlDriver::ServeCpuCtrl>(this),
+  });
+
+  result = outgoing()->AddService<fuchsia_hardware_cpu_ctrl::Service>(std::move(handler));
+  if (result.is_error()) {
+    FDF_SLOG(ERROR, "Failed to add service", KV("status", result.status_string()));
+    return result.take_error();
+  }
+
   return zx::ok();
 }
 
diff --git a/src/power/power-manager/testing/fake_driver/meta/fake-cpu-ctrl-driver.cml b/src/power/power-manager/testing/fake_driver/meta/fake-cpu-ctrl-driver.cml
index 669f3ba..71681a2 100644
--- a/src/power/power-manager/testing/fake_driver/meta/fake-cpu-ctrl-driver.cml
+++ b/src/power/power-manager/testing/fake_driver/meta/fake-cpu-ctrl-driver.cml
@@ -11,4 +11,13 @@
         binary: "driver/fake-cpu-ctrl.so",
         bind: "meta/bind/bind-to-temp.bindbc",
     },
+    capabilities: [
+        { service: "fuchsia.hardware.cpu.ctrl.Service" },
+    ],
+    expose: [
+        {
+            service: "fuchsia.hardware.cpu.ctrl.Service",
+            from: "self",
+        },
+    ],
 }
diff --git a/src/power/power-manager/testing/fake_root/root_driver.cc b/src/power/power-manager/testing/fake_root/root_driver.cc
index 79f872e..ca899f5 100644
--- a/src/power/power-manager/testing/fake_root/root_driver.cc
+++ b/src/power/power-manager/testing/fake_root/root_driver.cc
@@ -45,23 +45,20 @@
                     .Build();
 
     // Create endpoints of the `NodeController` for the node.
-    zx::result controller_endpoints =
-        fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-    ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create controller endpoints: %s",
-                  controller_endpoints.status_string());
+    auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
     zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
     ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create node endpoints: %s",
                   node_endpoints.status_string());
 
     fidl::WireResult result = fidl::WireCall(node())->AddChild(
-        args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+        args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
     if (!result.ok()) {
       FDF_SLOG(ERROR, "Failed to add child", KV("status", result.status_string()));
       return zx::error(result.status());
     }
 
-    controllers_.emplace_back(std::move(controller_endpoints->client));
+    controllers_.emplace_back(std::move(controller_endpoints.client));
     nodes_.emplace_back(std::move(node_endpoints->client));
 
     return zx::ok();
@@ -91,19 +88,16 @@
                     .Build();
 
     // Create endpoints of the `NodeController` for the node.
-    zx::result controller_endpoints =
-        fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-    ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create controller endpoints: %s",
-                  controller_endpoints.status_string());
+    auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
     fidl::WireResult result =
-        fidl::WireCall(nodes_.back())->AddChild(args, std::move(controller_endpoints->server), {});
+        fidl::WireCall(nodes_.back())->AddChild(args, std::move(controller_endpoints.server), {});
     if (!result.ok()) {
       FDF_SLOG(ERROR, "Failed to add child", KV("status", result.status_string()));
       return zx::error(result.status());
     }
 
-    controllers_.emplace_back(std::move(controller_endpoints->client));
+    controllers_.emplace_back(std::move(controller_endpoints.client));
 
     // TODO(b/313922891): This is a temporary solution for a test to add a driver without disrupting
     // other tests.
@@ -117,20 +111,18 @@
                          .Build();
 
     // Create endpoints of the `NodeController` for the node.
-    zx::result temp_controller_endpoints =
-        fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-    ZX_ASSERT_MSG(temp_controller_endpoints.is_ok(), "Failed to create controller endpoints: %s",
-                  temp_controller_endpoints.status_string());
+    auto temp_controller_endpoints =
+        fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
     fidl::WireResult temp_result =
         fidl::WireCall(nodes_.back())
-            ->AddChild(temp_args, std::move(temp_controller_endpoints->server), {});
+            ->AddChild(temp_args, std::move(temp_controller_endpoints.server), {});
     if (!temp_result.ok()) {
       FDF_SLOG(ERROR, "Failed to add child", KV("status", temp_result.status_string()));
       return zx::error(temp_result.status());
     }
 
-    controllers_.emplace_back(std::move(temp_controller_endpoints->client));
+    controllers_.emplace_back(std::move(temp_controller_endpoints.client));
 
     return zx::ok();
   }
diff --git a/src/power/system-activity-governor/integration/tests/src/main.rs b/src/power/system-activity-governor/integration/tests/src/main.rs
index f3017de..4c0c44b 100644
--- a/src/power/system-activity-governor/integration/tests/src/main.rs
+++ b/src/power/system-activity-governor/integration/tests/src/main.rs
@@ -236,52 +236,13 @@
     set_up_default_suspender(&suspend_device).await;
     let stats = realm.connect_to_protocol::<fsuspend::StatsMarker>().await?;
 
-    // First watch should return immediately with default values.
-    let current_stats = stats.watch().await?;
-    assert_eq!(Some(0), current_stats.success_count);
-    assert_eq!(Some(0), current_stats.fail_count);
-    assert_eq!(None, current_stats.last_failed_error);
-    assert_eq!(None, current_stats.last_time_in_suspend);
-
-    block_until_inspect_matches!(
-        activity_governor_moniker,
-        root: {
-            power_elements: {
-                execution_state: {
-                    power_level: 0u64,
-                },
-                application_activity: {
-                    power_level: 0u64,
-                },
-                full_wake_handling: {
-                    power_level: 0u64,
-                },
-                wake_handling: {
-                    power_level: 0u64,
-                },
-                execution_resume_latency: contains {
-                    power_level: 0u64,
-                },
-            },
-            suspend_stats: {
-                success_count: 0u64,
-                fail_count: 0u64,
-                last_failed_error: 0u64,
-                last_time_in_suspend: -1i64,
-                last_time_in_suspend_operations: -1i64,
-            },
-            "fuchsia.inspect.Health": contains {
-                status: "OK",
-            },
-        }
-    );
-
     let suspend_controller = create_suspend_topology(&realm).await?;
     let suspend_lease_control = lease(&suspend_controller, 1).await?;
 
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 2u64,
@@ -333,6 +294,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 0u64,
@@ -369,6 +331,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 2u64,
@@ -420,6 +383,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 0u64,
@@ -467,12 +431,35 @@
     assert_eq!(None, current_stats.last_failed_error);
     assert_eq!(None, current_stats.last_time_in_suspend);
 
+    {
+        // Trigger "boot complete" logic.
+        let suspend_controller = create_suspend_topology(&realm).await?;
+        lease(&suspend_controller, 1).await?;
+    }
+    assert_eq!(0, suspend_device.await_suspend().await.unwrap().unwrap().state_index.unwrap());
+    let suspend_device2 = suspend_device.clone();
+
     let wake_controller = create_wake_topology(&realm).await?;
+
+    fasync::Task::local(async move {
+        suspend_device2
+            .resume(&tsc::DeviceResumeRequest::Result(tsc::SuspendResult {
+                suspend_duration: Some(2i64),
+                suspend_overhead: Some(1i64),
+                ..Default::default()
+            }))
+            .await
+            .unwrap()
+            .unwrap();
+    })
+    .detach();
+
     let wake_handling_lease_control = lease(&wake_controller, 1).await?;
 
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 1u64,
@@ -491,11 +478,11 @@
                 },
             },
             suspend_stats: {
-                success_count: 0u64,
+                success_count: 1u64,
                 fail_count: 0u64,
                 last_failed_error: 0u64,
-                last_time_in_suspend: -1i64,
-                last_time_in_suspend_operations: -1i64,
+                last_time_in_suspend: 2u64,
+                last_time_in_suspend_operations: 1u64,
             },
             "fuchsia.inspect.Health": contains {
                 status: "OK",
@@ -518,6 +505,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 0u64,
@@ -536,6 +524,82 @@
                 },
             },
             suspend_stats: {
+                success_count: 2u64,
+                fail_count: 0u64,
+                last_failed_error: 0u64,
+                last_time_in_suspend: 2u64,
+                last_time_in_suspend_operations: 1u64,
+            },
+            "fuchsia.inspect.Health": contains {
+                status: "OK",
+            },
+        }
+    );
+
+    Ok(())
+}
+
+#[fuchsia::test]
+async fn test_activity_governor_raises_execution_state_power_level_on_full_wake_handling_claim(
+) -> Result<()> {
+    let (realm, activity_governor_moniker, suspend_device) = create_realm().await?;
+    set_up_default_suspender(&suspend_device).await;
+    let stats = realm.connect_to_protocol::<fsuspend::StatsMarker>().await?;
+
+    // First watch should return immediately with default values.
+    let current_stats = stats.watch().await?;
+    assert_eq!(Some(0), current_stats.success_count);
+    assert_eq!(Some(0), current_stats.fail_count);
+    assert_eq!(None, current_stats.last_failed_error);
+    assert_eq!(None, current_stats.last_time_in_suspend);
+
+    {
+        // Trigger "boot complete" logic.
+        let suspend_controller = create_suspend_topology(&realm).await?;
+        lease(&suspend_controller, 1).await?;
+    }
+    assert_eq!(0, suspend_device.await_suspend().await.unwrap().unwrap().state_index.unwrap());
+    let suspend_device2 = suspend_device.clone();
+
+    let wake_controller = create_full_wake_topology(&realm).await?;
+
+    fasync::Task::local(async move {
+        suspend_device2
+            .resume(&tsc::DeviceResumeRequest::Result(tsc::SuspendResult {
+                suspend_duration: Some(2i64),
+                suspend_overhead: Some(1i64),
+                ..Default::default()
+            }))
+            .await
+            .unwrap()
+            .unwrap();
+    })
+    .detach();
+
+    let wake_handling_lease_control = lease(&wake_controller, 1).await?;
+
+    block_until_inspect_matches!(
+        activity_governor_moniker,
+        root: {
+            booting: false,
+            power_elements: {
+                execution_state: {
+                    power_level: 1u64,
+                },
+                application_activity: {
+                    power_level: 0u64,
+                },
+                full_wake_handling: {
+                    power_level: 1u64,
+                },
+                wake_handling: {
+                    power_level: 0u64,
+                },
+                execution_resume_latency: contains {
+                    power_level: 0u64,
+                },
+            },
+            suspend_stats: {
                 success_count: 1u64,
                 fail_count: 0u64,
                 last_failed_error: 0u64,
@@ -548,6 +612,52 @@
         }
     );
 
+    drop(wake_handling_lease_control);
+    assert_eq!(0, suspend_device.await_suspend().await.unwrap().unwrap().state_index.unwrap());
+    suspend_device
+        .resume(&tsc::DeviceResumeRequest::Result(tsc::SuspendResult {
+            suspend_duration: Some(2i64),
+            suspend_overhead: Some(1i64),
+            ..Default::default()
+        }))
+        .await
+        .unwrap()
+        .unwrap();
+
+    block_until_inspect_matches!(
+        activity_governor_moniker,
+        root: {
+            booting: false,
+            power_elements: {
+                execution_state: {
+                    power_level: 0u64,
+                },
+                application_activity: {
+                    power_level: 0u64,
+                },
+                full_wake_handling: {
+                    power_level: 0u64,
+                },
+                wake_handling: {
+                    power_level: 0u64,
+                },
+                execution_resume_latency: contains {
+                    power_level: 0u64,
+                },
+            },
+            suspend_stats: {
+                success_count: 2u64,
+                fail_count: 0u64,
+                last_failed_error: 0u64,
+                last_time_in_suspend: 2u64,
+                last_time_in_suspend_operations: 1u64,
+            },
+            "fuchsia.inspect.Health": contains {
+                status: "OK",
+            },
+        }
+    );
+
     Ok(())
 }
 
@@ -568,15 +678,6 @@
         .unwrap()
         .unwrap();
 
-    let stats = realm.connect_to_protocol::<fsuspend::StatsMarker>().await?;
-
-    // First watch should return immediately with default values.
-    let current_stats = stats.watch().await?;
-    assert_eq!(Some(0), current_stats.success_count);
-    assert_eq!(Some(0), current_stats.fail_count);
-    assert_eq!(None, current_stats.last_failed_error);
-    assert_eq!(None, current_stats.last_time_in_suspend);
-
     let expected_latencies = vec![1000i64, 100i64, 10i64];
     let erl_controller = create_latency_topology(&realm, &expected_latencies).await?;
 
@@ -586,9 +687,10 @@
         block_until_inspect_matches!(
             activity_governor_moniker,
             root: {
+                booting: true,
                 power_elements: {
                     execution_state: {
-                        power_level: 0u64,
+                        power_level: 2u64,
                     },
                     application_activity: {
                         power_level: 0u64,
@@ -650,6 +752,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 2u64,
@@ -700,6 +803,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 0u64,
@@ -763,6 +867,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 2u64,
@@ -805,6 +910,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 0u64,
@@ -891,11 +997,11 @@
     })
     .detach();
 
-    let full_wake_controller = create_full_wake_topology(&realm).await?;
-
-    // Cycle execution_state power level to trigger a suspend/resume cycle.
-    let full_wake_lease_control = lease(&full_wake_controller, 1).await?;
-    drop(full_wake_lease_control);
+    {
+        let suspend_controller = create_suspend_topology(&realm).await?;
+        // Cycle execution_state power level to trigger a suspend/resume cycle.
+        lease(&suspend_controller, 1).await?;
+    }
 
     // OnSuspend and OnResume should have been called once.
     on_suspend_rx.next().await.unwrap();
@@ -924,6 +1030,7 @@
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 0u64,
@@ -961,18 +1068,11 @@
 async fn test_activity_governor_handles_listener_raising_power_levels() -> Result<()> {
     let (realm, activity_governor_moniker, suspend_device) = create_realm().await?;
     set_up_default_suspender(&suspend_device).await;
-
-    let stats = realm.connect_to_protocol::<fsuspend::StatsMarker>().await?;
     let activity_governor = realm.connect_to_protocol::<fsystem::ActivityGovernorMarker>().await?;
 
-    // First watch should return immediately with default values.
-    let current_stats = stats.watch().await?;
-    assert_eq!(Some(0), current_stats.success_count);
-    assert_eq!(Some(0), current_stats.fail_count);
-    assert_eq!(None, current_stats.last_failed_error);
-    assert_eq!(None, current_stats.last_time_in_suspend);
-
     let suspend_controller = create_suspend_topology(&realm).await?;
+    // Trigger "boot complete" logic.
+    let suspend_lease = lease(&suspend_controller, 1).await.unwrap();
 
     let (listener_client_end, mut listener_stream) =
         fidl::endpoints::create_request_stream().unwrap();
@@ -1009,11 +1109,7 @@
     })
     .detach();
 
-    let full_wake_controller = create_full_wake_topology(&realm).await?;
-
-    // Cycle execution_state power level to trigger a suspend/resume cycle.
-    let full_wake_lease_control = lease(&full_wake_controller, 1).await?;
-    drop(full_wake_lease_control);
+    drop(suspend_lease);
 
     // OnSuspend should have been called.
     on_suspend_rx.next().await.unwrap();
@@ -1029,16 +1125,11 @@
         .unwrap()
         .unwrap();
 
-    let current_stats = stats.watch().await?;
-    assert_eq!(Some(1), current_stats.success_count);
-    assert_eq!(Some(0), current_stats.fail_count);
-    assert_eq!(None, current_stats.last_failed_error);
-    assert_eq!(Some(2), current_stats.last_time_in_suspend);
-
     // At this point, the listener should have raised the execution_state power level to 2.
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 2u64,
@@ -1086,10 +1177,11 @@
         .unwrap()
         .unwrap();
 
-    // At this point, the listener should have raised the execution_state power level to 2.
+    // At this point, the listener should have raised the execution_state power level to 2 again.
     block_until_inspect_matches!(
         activity_governor_moniker,
         root: {
+            booting: false,
             power_elements: {
                 execution_state: {
                     power_level: 2u64,
@@ -1208,3 +1300,93 @@
 
     Ok(())
 }
+
+#[fuchsia::test]
+async fn test_activity_governor_handles_boot_signal() -> Result<()> {
+    let (realm, activity_governor_moniker, suspend_device) = create_realm().await?;
+    set_up_default_suspender(&suspend_device).await;
+    let stats = realm.connect_to_protocol::<fsuspend::StatsMarker>().await?;
+
+    // First watch should return immediately with default values.
+    let current_stats = stats.watch().await?;
+    assert_eq!(Some(0), current_stats.success_count);
+    assert_eq!(Some(0), current_stats.fail_count);
+    assert_eq!(None, current_stats.last_failed_error);
+    assert_eq!(None, current_stats.last_time_in_suspend);
+
+    // Initial state should show execution_state is active and booting is true.
+    block_until_inspect_matches!(
+        activity_governor_moniker,
+        root: {
+            booting: true,
+            power_elements: {
+                execution_state: {
+                    power_level: 2u64,
+                },
+                application_activity: {
+                    power_level: 0u64,
+                },
+                full_wake_handling: {
+                    power_level: 0u64,
+                },
+                wake_handling: {
+                    power_level: 0u64,
+                },
+                execution_resume_latency: contains {
+                    power_level: 0u64,
+                },
+            },
+            suspend_stats: {
+                success_count: 0u64,
+                fail_count: 0u64,
+                last_failed_error: 0u64,
+                last_time_in_suspend: -1i64,
+                last_time_in_suspend_operations: -1i64,
+            },
+            "fuchsia.inspect.Health": contains {
+                status: "OK",
+            },
+        }
+    );
+
+    // Trigger "boot complete" signal.
+    let suspend_controller = create_suspend_topology(&realm).await?;
+    lease(&suspend_controller, 1).await.unwrap();
+
+    // Now execution_state should have dropped and booting is false.
+    block_until_inspect_matches!(
+        activity_governor_moniker,
+        root: {
+            booting: false,
+            power_elements: {
+                execution_state: {
+                    power_level: 0u64,
+                },
+                application_activity: {
+                    power_level: 0u64,
+                },
+                full_wake_handling: {
+                    power_level: 0u64,
+                },
+                wake_handling: {
+                    power_level: 0u64,
+                },
+                execution_resume_latency: contains {
+                    power_level: 0u64,
+                },
+            },
+            suspend_stats: {
+                success_count: 0u64,
+                fail_count: 0u64,
+                last_failed_error: 0u64,
+                last_time_in_suspend: -1i64,
+                last_time_in_suspend_operations: -1i64,
+            },
+            "fuchsia.inspect.Health": contains {
+                status: "OK",
+            },
+        }
+    );
+
+    Ok(())
+}
diff --git a/src/power/system-activity-governor/src/system_activity_governor.rs b/src/power/system-activity-governor/src/system_activity_governor.rs
index 1e61c19..7c4559f 100644
--- a/src/power/system-activity-governor/src/system_activity_governor.rs
+++ b/src/power/system-activity-governor/src/system_activity_governor.rs
@@ -37,6 +37,21 @@
     Stats(fsuspend::StatsRequestStream),
 }
 
+#[derive(Copy, Clone)]
+enum BootControlLevel {
+    Inactive,
+    Active,
+}
+
+impl From<BootControlLevel> for fbroker::PowerLevel {
+    fn from(bc: BootControlLevel) -> Self {
+        match bc {
+            BootControlLevel::Inactive => 0,
+            BootControlLevel::Active => 1,
+        }
+    }
+}
+
 #[async_trait(?Send)]
 trait SuspendResumeListener {
     /// Gets the manager of suspend stats.
@@ -73,6 +88,7 @@
 }
 
 impl ExecutionStateManager {
+    /// Creates a new ExecutionStateManager.
     fn new(execution_state: PowerElementContext, suspender: fhsuspend::SuspenderProxy) -> Self {
         Self {
             passive_dependency_token: execution_state.passive_dependency_token(),
@@ -86,29 +102,40 @@
         }
     }
 
+    /// Sets the suspend resume listener.
+    /// The listener can only be set once. Subsequent calls will result in a panic.
     fn set_suspend_resume_listener(&self, suspend_resume_listener: Rc<dyn SuspendResumeListener>) {
-        let _ = self.suspend_resume_listener.set(suspend_resume_listener);
+        self.suspend_resume_listener
+            .set(suspend_resume_listener)
+            .map_err(|_| anyhow::anyhow!("suspend_resume_listener is already set"))
+            .unwrap();
     }
 
+    /// Gets a copy of the passive dependency token.
     fn passive_dependency_token(&self) -> fbroker::DependencyToken {
         self.passive_dependency_token
             .duplicate_handle(zx::Rights::SAME_RIGHTS)
             .expect("failed to duplicate token")
     }
 
+    /// Sets the suspend state index that will be used when suspend is triggered.
     async fn set_suspend_state_index(&self, suspend_state_index: u64) {
         tracing::debug!(?suspend_state_index, "set_suspend_state_index: acquiring inner lock");
         self.inner.lock().await.suspend_state_index = suspend_state_index;
     }
 
+    /// Updates the power level of the execution state power element.
+    ///
+    /// Returns a Result that indicates whether the system should suspend or not.
+    /// If an error occurs while updating the power level, the error is forwarded to the caller.
     async fn update_current_level(&self, required_level: fbroker::PowerLevel) -> Result<bool> {
         tracing::debug!(?required_level, "update_current_level: acquiring inner lock");
         let mut inner = self.inner.lock().await;
-        tracing::debug!(?required_level, "update_current_level: updating current level");
 
+        tracing::debug!(?required_level, "update_current_level: updating current level");
         let res = inner.execution_state.current_level.update(required_level).await;
         if let Err(error) = res {
-            tracing::warn!(?error, "run_power_element: update_current_power_level failed");
+            tracing::warn!(?error, "update_current_level: current_level.update failed");
             return Err(error.into());
         }
 
@@ -124,14 +151,17 @@
         }
     }
 
+    /// Gets a copy of the name of the execution state power element.
     async fn name(&self) -> String {
         self.inner.lock().await.execution_state.name().to_string()
     }
 
+    /// Gets a copy of the RequiredLevelProxy of the execution state power element.
     async fn required_level_proxy(&self) -> fbroker::RequiredLevelProxy {
         self.inner.lock().await.execution_state.required_level.clone()
     }
 
+    /// Attempts to suspend the system.
     async fn trigger_suspend(&self) {
         let listener = self.suspend_resume_listener.get().unwrap();
         {
@@ -386,6 +416,8 @@
     listeners: RefCell<Vec<fsystem::ActivityGovernorListenerProxy>>,
     /// The manager used to modify execution_state and trigger suspend.
     execution_state_manager: ExecutionStateManager,
+    /// The context used to manage the boot_control power element.
+    boot_control: PowerElementContext,
 }
 
 impl SystemActivityGovernor {
@@ -461,6 +493,21 @@
         .await
         .expect("PowerElementContext encountered error while building wake_handling");
 
+        let boot_control = PowerElementContext::builder(
+            topology,
+            "boot_control",
+            &[BootControlLevel::Inactive.into(), BootControlLevel::Active.into()],
+        )
+        .dependencies(vec![fbroker::LevelDependency {
+            dependency_type: fbroker::DependencyType::Active,
+            dependent_level: BootControlLevel::Active.into(),
+            requires_token: execution_state.active_dependency_token(),
+            requires_level: ExecutionStateLevel::Active.into_primitive(),
+        }])
+        .build()
+        .await
+        .expect("PowerElementContext encountered error while building wake_handling");
+
         let resp = suspender
             .get_suspend_states()
             .await
@@ -497,6 +544,7 @@
             suspend_stats,
             listeners: RefCell::new(Vec::new()),
             execution_state_manager: ExecutionStateManager::new(execution_state, suspender),
+            boot_control,
         }))
     }
 
@@ -509,7 +557,7 @@
                 let (es_suspend_tx, es_suspend_rx) = mpsc::channel(1);
                 self.run_suspend_task(es_suspend_rx);
                 self.run_execution_state(&elements_node, es_suspend_tx);
-                self.run_application_activity(&elements_node);
+                self.run_application_activity(&elements_node, &node);
                 self.run_full_wake_handling(&elements_node);
                 self.run_wake_handling(&elements_node);
                 self.run_execution_resume_latency(elements_node);
@@ -574,17 +622,53 @@
         .detach();
     }
 
-    fn run_application_activity(self: &Rc<Self>, inspect_node: &fuchsia_inspect::Node) {
+    fn run_application_activity(
+        self: &Rc<Self>,
+        inspect_node: &fuchsia_inspect::Node,
+        root_node: &fuchsia_inspect::Node,
+    ) {
         let application_activity_node = inspect_node.create_child("application_activity");
+        let booting_node = Rc::new(root_node.create_bool("booting", false));
         let this = self.clone();
 
         fasync::Task::local(async move {
+            let update_fn = Rc::new(default_update_fn(&this.application_activity));
+
+            tracing::info!("System is booting. Acquiring boot control lease.");
+            let boot_control_lease = this
+                .boot_control
+                .lessor
+                .lease(BootControlLevel::Active.into())
+                .await
+                .expect("Failed to acquire boot control lease");
+            booting_node.set(true);
+            let boot_control_lease = Rc::new(RefCell::new(Some(boot_control_lease)));
+
             run_power_element(
                 this.application_activity.name(),
                 &this.application_activity.required_level,
                 ApplicationActivityLevel::Inactive.into_primitive(),
                 application_activity_node,
-                default_update_fn(&this.application_activity),
+                Box::new(move |new_power_level: fbroker::PowerLevel| {
+                    let update_fn = update_fn.clone();
+                    let boot_control_lease = boot_control_lease.clone();
+                    let booting_node = booting_node.clone();
+
+                    async move {
+                        update_fn(new_power_level).await;
+
+                        // TODO(https://fxbug.dev/333699275): When the boot indication API is
+                        // available, this logic should be removed in favor of that.
+                        if new_power_level != ApplicationActivityLevel::Inactive.into_primitive()
+                            && boot_control_lease.borrow().is_some()
+                        {
+                            tracing::info!("System has booted. Dropping boot control lease.");
+                            boot_control_lease.borrow_mut().take();
+                            booting_node.set(false);
+                        }
+                    }
+                    .boxed_local()
+                }),
             )
             .await;
         })
diff --git a/src/recovery/factory_reset/factory_reset_unittest.cc b/src/recovery/factory_reset/factory_reset_unittest.cc
index abdc61d..a8fe506 100644
--- a/src/recovery/factory_reset/factory_reset_unittest.cc
+++ b/src/recovery/factory_reset/factory_reset_unittest.cc
@@ -181,9 +181,8 @@
     ASSERT_TRUE(dev.is_ok()) << dev.status_string();
     MockAdmin mock_admin;
     fidl::ServerBindingGroup<fuchsia_hardware_power_statecontrol::Admin> binding;
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_power_statecontrol::Admin>();
-    ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
-    auto& [admin, server_end] = endpoints.value();
+    auto [admin, server_end] =
+        fidl::Endpoints<fuchsia_hardware_power_statecontrol::Admin>::Create();
     binding.AddBinding(dispatcher(), std::move(server_end), &mock_admin,
                        fidl::kIgnoreBindingClosure);
 
diff --git a/src/recovery/system/src/main.rs b/src/recovery/system/src/main.rs
index edfd1bc..5265fac 100644
--- a/src/recovery/system/src/main.rs
+++ b/src/recovery/system/src/main.rs
@@ -798,9 +798,7 @@
                         self.countdown_task = Some(fasync::Task::local(f));
                     }
                     FactoryResetState::CancelCountdown => {
-                        self.countdown_task
-                            .take()
-                            .and_then(|task| Some(fasync::Task::local(task.cancel())));
+                        self.countdown_task = None;
                         let state =
                             self.reset_state_machine.handle_event(ResetEvent::CountdownCancelled);
                         assert_eq!(state, fdr::FactoryResetState::Waiting);
diff --git a/src/security/lib/scrutiny/plugins/BUILD.gn b/src/security/lib/scrutiny/plugins/BUILD.gn
index ba75e89..b7b5973 100644
--- a/src/security/lib/scrutiny/plugins/BUILD.gn
+++ b/src/security/lib/scrutiny/plugins/BUILD.gn
@@ -59,7 +59,6 @@
       feature_set_level = "empty"
       build_type = "eng"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = "assembly"
           image_mode = "no_image"
@@ -184,6 +183,7 @@
         "//src/lib/fuchsia",
         "//src/security/lib/scrutiny/config",
         "//src/security/lib/scrutiny/testing",
+        "//src/sys/lib/cm_rust/testing",
         "//third_party/rust_crates:assert_matches",
         "//third_party/rust_crates:tempfile",
         "//third_party/rust_crates:uuid",
diff --git a/src/security/lib/scrutiny/plugins/src/core/package/reader.rs b/src/security/lib/scrutiny/plugins/src/core/package/reader.rs
index ac9fd68..53f20b2 100644
--- a/src/security/lib/scrutiny/plugins/src/core/package/reader.rs
+++ b/src/security/lib/scrutiny/plugins/src/core/package/reader.rs
@@ -199,7 +199,6 @@
         super::{PackageReader, PackagesFromUpdateReader},
         crate::core::util::types::ComponentManifest,
         fuchsia_archive::write,
-        fuchsia_merkle::MerkleTree,
         fuchsia_url::{PackageName, PackageVariant, PinnedAbsolutePackageUrl},
         scrutiny_testing::{artifact::MockArtifactReader, TEST_REPO_URL},
         scrutiny_utils::package::META_CONTENTS_PATH,
@@ -219,8 +218,7 @@
         pkg_urls: &[PinnedAbsolutePackageUrl],
     ) -> MockArtifactReader {
         let packages_json_contents = serialize_packages_json(pkg_urls).unwrap();
-        let packages_json_merkle =
-            MerkleTree::from_reader(packages_json_contents.as_slice()).unwrap().root();
+        let packages_json_merkle = fuchsia_merkle::from_slice(&packages_json_contents).root();
         let meta_contents_string = format!("packages.json={}\n", packages_json_merkle);
         let meta_contents_str = &meta_contents_string;
         let meta_contents_bytes = meta_contents_str.as_bytes();
@@ -256,9 +254,9 @@
         let a_path = PathBuf::from(a_str);
         let c_path = PathBuf::from(c_str);
         let one_path = PathBuf::from(one_str);
-        let a_hash = MerkleTree::from_reader(a_str.as_bytes()).unwrap().root();
-        let c_hash = MerkleTree::from_reader(c_str.as_bytes()).unwrap().root();
-        let one_hash = MerkleTree::from_reader(one_str.as_bytes()).unwrap().root();
+        let a_hash = fuchsia_merkle::from_slice(a_str.as_bytes()).root();
+        let c_hash = fuchsia_merkle::from_slice(c_str.as_bytes()).root();
+        let one_hash = fuchsia_merkle::from_slice(one_str.as_bytes()).root();
         let meta_contents_string =
             format!("{}={}\n{}={}\n{}={}\n", a_str, a_hash, c_str, c_hash, one_str, one_hash);
         let meta_contents_str = &meta_contents_string;
@@ -286,7 +284,7 @@
         let mut target = Cursor::new(Vec::new());
         write(&mut target, path_content_map).unwrap();
         let pkg_contents = target.get_ref();
-        let pkg_merkle = MerkleTree::from_reader(pkg_contents.as_slice()).unwrap().root();
+        let pkg_merkle = fuchsia_merkle::from_slice(&pkg_contents).root();
         let pkg_url = PinnedAbsolutePackageUrl::new(
             TEST_REPO_URL.clone(),
             PackageName::from_str("foo").unwrap(),
diff --git a/src/security/lib/scrutiny/plugins/src/static_pkgs/collector.rs b/src/security/lib/scrutiny/plugins/src/static_pkgs/collector.rs
index bc25606..d78f4d1 100644
--- a/src/security/lib/scrutiny/plugins/src/static_pkgs/collector.rs
+++ b/src/security/lib/scrutiny/plugins/src/static_pkgs/collector.rs
@@ -288,7 +288,7 @@
         },
         anyhow::{anyhow, Context, Result},
         fuchsia_archive::write as far_write,
-        fuchsia_merkle::{Hash, MerkleTree, HASH_SIZE},
+        fuchsia_merkle::{Hash, HASH_SIZE},
         fuchsia_url::{PackageName, PackageVariant},
         maplit::{btreemap, hashmap, hashset},
         scrutiny::model::collector::DataCollector,
@@ -533,8 +533,7 @@
         // `mock_artifact_reader`, but is not the correct hash for the file.
         let designated_system_image_hash = Hash::from([0; HASH_SIZE]);
         let system_image_contents = create_system_image_far(None);
-        let system_image_hash =
-            MerkleTree::from_reader(system_image_contents.as_slice()).unwrap().root();
+        let system_image_hash = fuchsia_merkle::from_slice(&system_image_contents).root();
         assert!(designated_system_image_hash != system_image_hash);
 
         // Incorrectly map `designated_system_image_hash` to `system_image_contents` (that's not its
@@ -565,8 +564,7 @@
 
         // `None` below implies no static packages entry in system image package.
         let system_image_contents = create_system_image_far(None);
-        let system_image_hash =
-            MerkleTree::from_reader(system_image_contents.as_slice()).unwrap().root();
+        let system_image_hash = fuchsia_merkle::from_slice(&system_image_contents).root();
 
         mock_artifact_reader
             .append_artifact(&PathBuf::from(system_image_hash.to_string()), system_image_contents);
@@ -592,12 +590,10 @@
 
         let static_pkgs = hashmap! {};
         let static_pkgs_contents = create_static_pkgs_listing(static_pkgs.clone());
-        let static_pkgs_hash =
-            MerkleTree::from_reader(static_pkgs_contents.as_slice()).unwrap().root();
+        let static_pkgs_hash = fuchsia_merkle::from_slice(&static_pkgs_contents).root();
 
         let system_image_contents = create_system_image_far(Some(static_pkgs_hash.clone()));
-        let system_image_hash =
-            MerkleTree::from_reader(system_image_contents.as_slice()).unwrap().root();
+        let system_image_hash = fuchsia_merkle::from_slice(&system_image_contents).root();
 
         // Note: `mock_artifact_reader does not have static packages manifest added, so it will
         // yield an error when code under test attempts to said manifest.
@@ -628,8 +624,7 @@
 
         let static_pkgs = hashmap! {};
         let static_pkgs_contents = create_static_pkgs_listing(static_pkgs.clone());
-        let static_pkgs_hash =
-            MerkleTree::from_reader(static_pkgs_contents.as_slice()).unwrap().root();
+        let static_pkgs_hash = fuchsia_merkle::from_slice(&static_pkgs_contents).root();
 
         // System image designates `designated_static_pkgs_hash` as "where to find static pkgs
         // listing". This value is mapped to the static pkgs file according to
@@ -637,8 +632,7 @@
         let designated_static_pkgs_hash = Hash::from([0; HASH_SIZE]);
         let system_image_contents =
             create_system_image_far(Some(designated_static_pkgs_hash.clone()));
-        let system_image_hash =
-            MerkleTree::from_reader(system_image_contents.as_slice()).unwrap().root();
+        let system_image_hash = fuchsia_merkle::from_slice(&system_image_contents).root();
         assert!(designated_static_pkgs_hash != static_pkgs_hash);
 
         // Incorrectly map `designated_static_pkgs_hash` to `static_pkgs_contents` (that's not its
@@ -672,12 +666,10 @@
 
         let static_pkgs = hashmap! {};
         let static_pkgs_contents = create_static_pkgs_listing(static_pkgs.clone());
-        let static_pkgs_hash =
-            MerkleTree::from_reader(static_pkgs_contents.as_slice()).unwrap().root();
+        let static_pkgs_hash = fuchsia_merkle::from_slice(&static_pkgs_contents).root();
 
         let system_image_contents = create_system_image_far(Some(static_pkgs_hash.clone()));
-        let system_image_hash =
-            MerkleTree::from_reader(system_image_contents.as_slice()).unwrap().root();
+        let system_image_hash = fuchsia_merkle::from_slice(&system_image_contents).root();
 
         mock_artifact_reader
             .append_artifact(&PathBuf::from(static_pkgs_hash.to_string()), static_pkgs_contents);
@@ -709,12 +701,10 @@
             (PackageName::from_str("beta").unwrap(), Some(PackageVariant::zero())) => beta_hash.clone(),
         };
         let static_pkgs_contents = create_static_pkgs_listing(static_pkgs.clone());
-        let static_pkgs_hash =
-            MerkleTree::from_reader(static_pkgs_contents.as_slice()).unwrap().root();
+        let static_pkgs_hash = fuchsia_merkle::from_slice(&static_pkgs_contents).root();
 
         let system_image_contents = create_system_image_far(Some(static_pkgs_hash.clone()));
-        let system_image_hash =
-            MerkleTree::from_reader(system_image_contents.as_slice()).unwrap().root();
+        let system_image_hash = fuchsia_merkle::from_slice(&system_image_contents).root();
 
         mock_artifact_reader
             .append_artifact(&PathBuf::from(static_pkgs_hash.to_string()), static_pkgs_contents);
diff --git a/src/security/lib/scrutiny/plugins/src/verify/controller/pre_signing.rs b/src/security/lib/scrutiny/plugins/src/verify/controller/pre_signing.rs
index 55ed4b0..91ae3ce 100644
--- a/src/security/lib/scrutiny/plugins/src/verify/controller/pre_signing.rs
+++ b/src/security/lib/scrutiny/plugins/src/verify/controller/pre_signing.rs
@@ -5,6 +5,7 @@
 use {
     crate::{
         additional_boot_args::AdditionalBootConfigCollection, static_pkgs::StaticPkgsCollection,
+        zbi::Zbi,
     },
     anyhow::{anyhow, Context, Result},
     scrutiny::{model::controller::DataController, model::model::*},
@@ -76,12 +77,16 @@
             .map(|((name, _variant), hash)| (name.as_ref().to_string(), hash.to_string()))
             .collect();
 
+        let zbi_data = model.get::<Zbi>().context("Failed to get ZbiCollection")?;
+        let bootfs_files = &zbi_data.bootfs_files.bootfs_files;
+
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(FileArtifactReader::new(&PathBuf::new(), &model.config().blobs_directory()));
 
         let validation_errors = build_checks::validate_build_checks(
             policy,
             boot_args_data,
+            bootfs_files,
             static_pkgs_map,
             &mut blobs_artifact_reader,
             &pre_signing_request.golden_files_dir,
diff --git a/src/security/lib/scrutiny/plugins/src/verify/controller/route_sources.rs b/src/security/lib/scrutiny/plugins/src/verify/controller/route_sources.rs
index 540fd80..6bbacf7 100644
--- a/src/security/lib/scrutiny/plugins/src/verify/controller/route_sources.rs
+++ b/src/security/lib/scrutiny/plugins/src/verify/controller/route_sources.rs
@@ -627,8 +627,9 @@
         cm_rust::{
             Availability, CapabilityTypeName, ChildDecl, ComponentDecl, DependencyType,
             DirectoryDecl, ExposeDirectoryDecl, ExposeSource, ExposeTarget, OfferDirectoryDecl,
-            OfferSource, OfferTarget, ProgramDecl, UseDirectoryDecl, UseSource, UseStorageDecl,
+            OfferSource, ProgramDecl, UseDirectoryDecl, UseSource, UseStorageDecl,
         },
+        cm_rust_testing::*,
         cm_types::Path,
         fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_io as fio,
         fuchsia_merkle::{Hash, HASH_SIZE},
@@ -799,10 +800,10 @@
                 ],
                 offers: vec![
                     OfferDirectoryDecl{
-                        source: OfferSource::static_child("one_dir_provider".to_string()),
+                        source: offer_source_static_child("one_dir_provider"),
                         source_name: "exposed_by_provider".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: OfferTarget::static_child("two_dir_user".to_string()),
+                        target: offer_target_static_child("two_dir_user"),
                         target_name: "routed_from_provider".parse().unwrap(),
                         dependency_type: DependencyType::Strong,
                         rights: Some(fio::Operations::CONNECT),
@@ -813,7 +814,7 @@
                         source: OfferSource::Self_,
                         source_name: "root_dir".parse().unwrap(),
                         source_dictionary: Default::default(),
-                        target: OfferTarget::static_child("two_dir_user".to_string()),
+                        target: offer_target_static_child("two_dir_user"),
                         target_name: "routed_from_root".parse().unwrap(),
                         dependency_type: DependencyType::Strong,
                         rights: Some(fio::Operations::CONNECT),
@@ -823,7 +824,7 @@
                 ],
                 children: vec![
                     ChildDecl{
-                        name: "two_dir_user".to_string(),
+                        name: "two_dir_user".parse().unwrap(),
                         url: two_dir_user_url.to_string(),
                         startup: fdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -831,7 +832,7 @@
                         config_overrides: None,
                     },
                     ChildDecl{
-                        name: "one_dir_provider".to_string(),
+                        name: "one_dir_provider".parse().unwrap(),
                         url: one_dir_provider_url.to_string(),
                         startup: fdecl::StartupMode::Lazy,
                         on_terminate: None,
diff --git a/src/security/lib/scrutiny/plugins/src/verify/mod.rs b/src/security/lib/scrutiny/plugins/src/verify/mod.rs
index e030cbd..6097689 100644
--- a/src/security/lib/scrutiny/plugins/src/verify/mod.rs
+++ b/src/security/lib/scrutiny/plugins/src/verify/mod.rs
@@ -201,6 +201,7 @@
             OfferSource, OfferTarget, ProgramDecl, UseDecl, UseDirectoryDecl, UseProtocolDecl,
             UseSource,
         },
+        cm_rust_testing::*,
         component_id_index::InstanceId,
         fidl::persist,
         fidl_fuchsia_component_decl as fdecl,
@@ -223,7 +224,7 @@
 
     fn new_child_decl(name: String, url: String) -> ChildDecl {
         ChildDecl {
-            name,
+            name: name.parse().unwrap(),
             url,
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -473,14 +474,14 @@
         let root_offer_good_dir = new_offer_directory_decl(
             OfferSource::Self_,
             good_dir_name.clone(),
-            OfferTarget::static_child(child_name.clone()),
+            offer_target_static_child(&child_name),
             good_dir_name.clone(),
             Some(offer_rights),
         );
         let root_offer_protocol = new_offer_protocol_decl(
-            OfferSource::static_child(missing_child_name.clone()),
+            offer_source_static_child(&missing_child_name),
             protocol_name.clone(),
-            OfferTarget::static_child(child_name.clone()),
+            offer_target_static_child(&child_name),
             protocol_name.clone(),
         );
         let root_good_dir_decl = new_directory_decl(good_dir_name.clone(), offer_rights);
diff --git a/src/security/lib/scrutiny/tests/route_verification/BUILD.gn b/src/security/lib/scrutiny/tests/route_verification/BUILD.gn
index 7b67434..a75d87d 100644
--- a/src/security/lib/scrutiny/tests/route_verification/BUILD.gn
+++ b/src/security/lib/scrutiny/tests/route_verification/BUILD.gn
@@ -86,7 +86,6 @@
       build_type = "user"
       feature_set_level = "utility"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = "assembly"
           volume = {
diff --git a/src/security/lib/scrutiny/tests/structured_config/BUILD.gn b/src/security/lib/scrutiny/tests/structured_config/BUILD.gn
index eb18d97..bb42a76 100644
--- a/src/security/lib/scrutiny/tests/structured_config/BUILD.gn
+++ b/src/security/lib/scrutiny/tests/structured_config/BUILD.gn
@@ -96,7 +96,6 @@
       build_type = "user"
       feature_set_level = "utility"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = "assembly"
           volume = {
diff --git a/src/security/lib/scrutiny/utils/src/build_checks.rs b/src/security/lib/scrutiny/utils/src/build_checks.rs
index 29f4f15..1350c73 100644
--- a/src/security/lib/scrutiny/utils/src/build_checks.rs
+++ b/src/security/lib/scrutiny/utils/src/build_checks.rs
@@ -186,19 +186,22 @@
 #[derive(Deserialize, Serialize)]
 pub enum FileSource {
     /// Name for the target file as a key in the meta/contents mapping from the package.
-    MetaContents(String),
+    PackageMetaContents(String),
     /// Possible paths within the package archive. If multiple files are found, validation will fail.
     /// Multiple paths are only supported to enable backwards compatibility during file migrations.
     PackageFar(Vec<String>),
+    /// Name for the target file in the bootfs file collection.
+    BootfsFile(String),
 }
 
 impl Display for FileSource {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
-            FileSource::MetaContents(path) => write!(f, "meta-contents: {}", path),
+            FileSource::PackageMetaContents(path) => write!(f, "meta-contents: {}", path),
             FileSource::PackageFar(paths) => {
                 write!(f, "package-far: {}", paths.join(", "))
             }
+            FileSource::BootfsFile(path) => write!(f, "bootfs-file: {}", path),
         }
     }
 }
@@ -217,6 +220,8 @@
     pub additional_boot_args_checks: Option<ContentCheckSpec>,
     /// Checks which involve reading the contents of specific packages in the build.
     pub package_checks: Vec<PackageCheckSpec>,
+    /// Checks which involve reading contents of boofs files.
+    pub bootfs_file_checks: Vec<FileCheckSpec>,
 }
 
 /// Package checks operate on the content of individual packages.
@@ -232,7 +237,7 @@
 
 #[derive(Deserialize, Serialize)]
 pub struct FileCheckSpec {
-    /// How the file is sourced from the package contents.
+    /// How the file is sourced from the package contents or bootfs file collection.
     pub source: FileSource,
     /// Expected state of the file: present, absent, absent or empty.
     pub state: FileState,
@@ -249,9 +254,10 @@
     pub must_contain: Option<Vec<ContentType>>,
     /// Set of items that must not be present in the target content.
     pub must_not_contain: Option<Vec<ContentType>>,
-    /// The name of a golden file. The directory path it resides in is provided elsewhere.
+    /// The name of possible golden files to match. One match is needed to pass this check.
+    /// The directory path they reside in is provided elsewhere.
     /// The contents of the golden file must match target content as a string.
-    pub matches_golden: Option<String>,
+    pub matches_golden: Option<Vec<String>>,
 }
 
 /// Validates the provided build artifacts according to the provided policy.
@@ -260,12 +266,14 @@
 ///
 /// * `validation_policy` - A policy file describing checks to perform
 /// * `boot_args_data` - Mapping of arg name to vector of values delimited by `+`
+/// * `bootfs_files` - Mapping of file name to contents of file
 /// * `static_pkgs` - Mapping of pkg name to merkle hash string
 /// * `blobs_artifact_reader` - ArtifactReader backed by a build's blob set
 /// * 'golden_files_dir` - Directory containing golden files for matching
 pub fn validate_build_checks(
     validation_policy: BuildCheckSpec,
     boot_args_data: HashMap<String, Vec<String>>,
+    bootfs_files: &HashMap<String, Vec<u8>>,
     static_pkgs: HashMap<String, String>,
     blobs_artifact_reader: &mut Box<dyn ArtifactReader>,
     golden_files_dir: &str,
@@ -279,6 +287,13 @@
         }
     }
 
+    // If the policy specifies bootfs file checks, run them.
+    for error in
+        validate_bootfs_files(validation_policy.bootfs_file_checks, &bootfs_files, golden_files_dir)
+    {
+        errors_found.push(error);
+    }
+
     for package_check in validation_policy.package_checks {
         // Resolve the package merkle string based on the source specified by the policy.
         let pkg_merkle_string = match package_check.source {
@@ -299,7 +314,7 @@
 
         // Run the validations specified by the policy.
         // Specification of the concrete PackageFileValidator impl should remain internal to build_checks.
-        for error in validate_package::<PackageFileValidator>(
+        for error in validate_package::<PackageFileChecker>(
             &package_check,
             &pkg_merkle_string,
             blobs_artifact_reader,
@@ -390,7 +405,42 @@
     errors
 }
 
-fn validate_package<FV: FileValidator>(
+fn validate_bootfs_files(
+    bootfs_file_checks: Vec<FileCheckSpec>,
+    bootfs_files: &HashMap<String, Vec<u8>>,
+    golden_files_dir: &str,
+) -> Vec<ValidationError> {
+    let mut errors = Vec::new();
+    for check in bootfs_file_checks {
+        match resolve_bootfs_file(&check.source, &bootfs_files) {
+            Ok((file_name, file_contents)) => {
+                for error in validate_file(&check, file_contents, &file_name, golden_files_dir) {
+                    errors.push(error);
+                }
+            }
+            Err(e) => {
+                // This error happens if the policy specified a package file source for a bootfs file check.
+                errors.push(e);
+            }
+        }
+    }
+    errors
+}
+
+/// File checker trait exists for easier testing.
+trait FileChecker {
+    /// check_file is responsible for both resolving and validating the file.
+    fn check_file(
+        check: &FileCheckSpec,
+        package_far_reader: &mut FarReader<Box<dyn ReadSeek>>,
+        blobs_artifact_reader: &mut Box<dyn ArtifactReader>,
+        golden_files_dir: &str,
+    ) -> Vec<ValidationError>
+    where
+        Self: Sized;
+}
+
+fn validate_package<FC: FileChecker>(
     check: &PackageCheckSpec,
     pkg_merkle_string: &String,
     blobs_artifact_reader: &mut Box<dyn ArtifactReader>,
@@ -424,7 +474,7 @@
 
     for file_check in &check.file_checks {
         errors.extend(
-            FV::validate_file(
+            FC::check_file(
                 &file_check,
                 &mut package_far_reader,
                 blobs_artifact_reader,
@@ -438,23 +488,29 @@
     errors
 }
 
-/// File validation trait exists for easier testing.
-trait FileValidator {
-    fn validate_file(
-        check: &FileCheckSpec,
-        package_far_reader: &mut FarReader<Box<dyn ReadSeek>>,
-        blobs_artifact_reader: &mut Box<dyn ArtifactReader>,
-        golden_files_dir: &str,
-    ) -> Vec<ValidationError>
-    where
-        Self: Sized;
+/// Given a `FileSource` (`BootfsFile`), return the contents from the bootfs_file map.
+fn resolve_bootfs_file(
+    source: &FileSource,
+    bootfs_files: &HashMap<String, Vec<u8>>,
+) -> Result<(String, Option<Vec<u8>>), ValidationError> {
+    match source {
+        FileSource::BootfsFile(file_name) => {
+            // File not found is represented by `None` for `bytes`.
+            let bytes = match bootfs_files.get(file_name) {
+                Some(bytes) => Some(bytes.clone()),
+                None => None,
+            };
+            Ok((file_name.to_string(), bytes))
+        }
+        _ => Err(ValidationError::InvalidPolicyConfiguration {
+            error: "Policy specified non-bootfs file source for a bootfs file check".to_string(),
+        }),
+    }
 }
 
-struct PackageFileValidator;
-
 /// Given a `FileSource` (`MetaContents` or `PackageFar`), find and read a file.
 /// Returns (file path found, optional bytes read) or `ValidationError`.
-fn resolve_file(
+fn resolve_package_file(
     source: &FileSource,
     package_far_reader: &mut FarReader<Box<dyn ReadSeek>>,
     blobs_artifact_reader: &mut Box<dyn ArtifactReader>,
@@ -462,7 +518,7 @@
     // First, find the file and read its contents if it is present.
     // File absence is represented by `file_contents_bytes` = `None`.
     match source {
-        FileSource::MetaContents(ref path) => {
+        FileSource::PackageMetaContents(ref path) => {
             // Read `meta/contents` to find merkle, then read the corresponding blob's bytes.
             match read_content_blob(package_far_reader, blobs_artifact_reader, &path) {
                 Ok(bytes) => {
@@ -507,9 +563,71 @@
 
             Ok((String::new(), None))
         }
+        _ => Err(ValidationError::InvalidPolicyConfiguration {
+            error: "Policy specified non-package file source for a package file check".to_string(),
+        }
+        .into()),
     }
 }
 
+/// Checks the state of the file (present, absent, absent or empty) before calling
+/// `validate_file_contents`, if content checks are specified.
+fn validate_file(
+    check: &FileCheckSpec,
+    content_bytes: Option<Vec<u8>>,
+    content_source: &str,
+    golden_files_dir: &str,
+) -> Vec<ValidationError> {
+    let mut errors = Vec::new();
+
+    // Check that the state of the file (present or absent) matches policy expectations.
+    match check.state {
+        FileState::Present => {
+            let bytes = match content_bytes {
+                Some(bytes) => bytes,
+                None => {
+                    errors.push(ValidationError::FailedToFindFile {
+                        file_paths: check.source.to_string(),
+                    });
+                    return errors;
+                }
+            };
+
+            // If we have content checks beyond just the file being there, run them.
+            if let Some(content_checks) = &check.content_checks {
+                for error_found in
+                    validate_file_contents(content_checks, bytes, content_source, golden_files_dir)
+                {
+                    errors.push(error_found);
+                }
+            }
+        }
+        FileState::Absent => {
+            // To pass this check, file_contents_bytes must be None, indicating that a file was not found.
+            if content_bytes.is_some() {
+                errors.push(ValidationError::UnexpectedFilePresence {
+                    // Package name is not known here and needs to be supplied by error handler.
+                    package_name: String::new(),
+                    file_path: content_source.to_string(),
+                });
+            }
+        }
+        FileState::AbsentOrEmpty => {
+            // To pass this check, file_contents_bytes must be either None or an empty byte vector.
+            if let Some(bytes) = content_bytes {
+                if bytes.len() > 0 {
+                    errors.push(ValidationError::UnexpectedFilePresenceOrHasContents {
+                        // Package name is not known here and needs to be supplied by error handler.
+                        package_name: String::new(),
+                        file_path: content_source.to_string(),
+                    });
+                }
+            }
+        }
+    }
+    errors
+}
+
 /// `content_source` is the file path from where the bytes were read.
 /// This method doesn't open or read files, so the file path is provided for error traceability.
 fn validate_file_contents(
@@ -697,41 +815,51 @@
     golden_files_dir: &str,
 ) -> Vec<ValidationError> {
     let mut errors = Vec::new();
-    if let Some(golden_file_name) = &checks.matches_golden {
-        let golden_path = Path::new(golden_files_dir).join(golden_file_name);
-        match read_to_string(&golden_path) {
-            Ok(golden_contents) => {
-                // Diffs are calculated and reported relative to the golden file.
-                let Changeset { diffs, distance, .. } =
-                    Changeset::new(&golden_contents, content_str, "\n");
-                if distance > 0 {
-                    let mut reported_diffs = String::new();
-                    for diff in diffs {
-                        match diff {
-                            Difference::Same(_) => {}
-                            Difference::Add(ref line) => {
-                                reported_diffs.push_str(&format!("+{}\n", line));
-                            }
-                            Difference::Rem(ref line) => {
-                                reported_diffs.push_str(&format!("-{}\n", line));
+    let mut match_found = false;
+    if let Some(golden_file_names) = &checks.matches_golden {
+        // Only one golden file must match to be successful.
+        for golden_file_name in golden_file_names {
+            let golden_path = Path::new(golden_files_dir).join(golden_file_name);
+            match read_to_string(&golden_path) {
+                Ok(golden_contents) => {
+                    // Diffs are calculated and reported relative to the golden file.
+                    let Changeset { diffs, distance, .. } =
+                        Changeset::new(&golden_contents, content_str, "\n");
+                    if distance == 0 {
+                        match_found = true;
+                    } else if distance > 0 {
+                        let mut reported_diffs = String::new();
+                        for diff in diffs {
+                            match diff {
+                                Difference::Same(_) => {}
+                                Difference::Add(ref line) => {
+                                    reported_diffs.push_str(&format!("+{}\n", line));
+                                }
+                                Difference::Rem(ref line) => {
+                                    reported_diffs.push_str(&format!("-{}\n", line));
+                                }
                             }
                         }
+                        errors.push(ValidationError::ContentGoldenFileMismatch {
+                            golden_path: golden_path.to_string_lossy().to_string(),
+                            content_source: content_source.to_string(),
+                            diffs: reported_diffs,
+                        });
                     }
-                    errors.push(ValidationError::ContentGoldenFileMismatch {
+                }
+                Err(e) => {
+                    errors.push(ValidationError::FailedToOpenGoldenFile {
                         golden_path: golden_path.to_string_lossy().to_string(),
-                        content_source: content_source.to_string(),
-                        diffs: reported_diffs,
+                        error: e.to_string(),
                     });
                 }
             }
-            Err(e) => {
-                errors.push(ValidationError::FailedToOpenGoldenFile {
-                    golden_path: golden_path.to_string_lossy().to_string(),
-                    error: e.to_string(),
-                });
-            }
         }
     }
+
+    if match_found {
+        return Vec::new();
+    }
     errors
 }
 
@@ -825,8 +953,10 @@
     }
 }
 
-impl FileValidator for PackageFileValidator {
-    fn validate_file(
+struct PackageFileChecker;
+
+impl FileChecker for PackageFileChecker {
+    fn check_file(
         check: &FileCheckSpec,
         package_far_reader: &mut FarReader<Box<dyn ReadSeek>>,
         blobs_artifact_reader: &mut Box<dyn ArtifactReader>,
@@ -836,7 +966,7 @@
         // First, find the file and read its contents if it is present.
         // File absence is represented by file_contents_bytes = None.
         let (file_path_found, file_contents_bytes) =
-            match resolve_file(&check.source, package_far_reader, blobs_artifact_reader) {
+            match resolve_package_file(&check.source, package_far_reader, blobs_artifact_reader) {
                 Ok((path, bytes)) => (path, bytes),
                 Err(e) => {
                     errors.push(ValidationError::FailedToPerformFileCheck {
@@ -848,54 +978,8 @@
                     return errors;
                 }
             };
-
-        // Second, check that the state of the file (present or absent) matches policy expectations.
-        match check.state {
-            FileState::Present => {
-                let bytes = match file_contents_bytes {
-                    Some(bytes) => bytes,
-                    None => {
-                        errors.push(ValidationError::FailedToFindFile {
-                            file_paths: check.source.to_string(),
-                        });
-                        return errors;
-                    }
-                };
-
-                // If we have content checks beyond just the file being there, run them.
-                if let Some(content_checks) = &check.content_checks {
-                    for error_found in validate_file_contents(
-                        content_checks,
-                        bytes,
-                        &file_path_found,
-                        golden_files_dir,
-                    ) {
-                        errors.push(error_found);
-                    }
-                }
-            }
-            FileState::Absent => {
-                // To pass this check, file_contents_bytes must be None, indicating that a file was not found.
-                if file_contents_bytes.is_some() {
-                    errors.push(ValidationError::UnexpectedFilePresence {
-                        // Package name is not known here and needs to be supplied by error handler.
-                        package_name: String::new(),
-                        file_path: file_path_found,
-                    });
-                }
-            }
-            FileState::AbsentOrEmpty => {
-                // To pass this check, file_contents_bytes must be either None or an empty byte vector.
-                if let Some(bytes) = file_contents_bytes {
-                    if bytes.len() > 0 {
-                        errors.push(ValidationError::UnexpectedFilePresenceOrHasContents {
-                            // Package name is not known here and needs to be supplied by error handler.
-                            package_name: String::new(),
-                            file_path: file_path_found,
-                        });
-                    }
-                }
-            }
+        for error in validate_file(check, file_contents_bytes, &file_path_found, golden_files_dir) {
+            errors.push(error);
         }
         errors
     }
@@ -948,10 +1032,10 @@
         }
     }
 
-    struct TestErrorFreeFileValidator;
+    struct TestErrorFreeFileChecker;
 
-    impl FileValidator for TestErrorFreeFileValidator {
-        fn validate_file(
+    impl FileChecker for TestErrorFreeFileChecker {
+        fn check_file(
             _check: &FileCheckSpec,
             _package_far_reader: &mut FarReader<Box<dyn ReadSeek>>,
             _blobs_artifact_reader: &mut Box<dyn ArtifactReader>,
@@ -993,6 +1077,7 @@
                 matches_golden: None,
             }),
             package_checks: Vec::new(),
+            bootfs_file_checks: Vec::new(),
         };
         let boot_args_data = hashmap! {
             expected_key.to_string() => vec![expected_value.to_string()]
@@ -1000,9 +1085,15 @@
 
         let mut artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
-        let errors =
-            validate_build_checks(policy, boot_args_data, HashMap::new(), &mut artifact_reader, "")
-                .unwrap();
+        let errors = validate_build_checks(
+            policy,
+            boot_args_data,
+            &HashMap::new(),
+            HashMap::new(),
+            &mut artifact_reader,
+            "",
+        )
+        .unwrap();
 
         assert_eq!(errors.len(), 0);
     }
@@ -1011,17 +1102,26 @@
     fn test_validate_build_checks_tolerates_absent_boot_args_policy() {
         let expected_key = "test_key";
         let expected_value = "test_value";
-        let policy =
-            BuildCheckSpec { additional_boot_args_checks: None, package_checks: Vec::new() };
+        let policy = BuildCheckSpec {
+            additional_boot_args_checks: None,
+            package_checks: Vec::new(),
+            bootfs_file_checks: Vec::new(),
+        };
         let boot_args_data = hashmap! {
             expected_key.to_string() => vec![expected_value.to_string()]
         };
 
         let mut artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
-        let errors =
-            validate_build_checks(policy, boot_args_data, HashMap::new(), &mut artifact_reader, "")
-                .unwrap();
+        let errors = validate_build_checks(
+            policy,
+            boot_args_data,
+            &HashMap::new(),
+            HashMap::new(),
+            &mut artifact_reader,
+            "",
+        )
+        .unwrap();
 
         assert_eq!(errors.len(), 0);
     }
@@ -1177,6 +1277,91 @@
     }
 
     #[test]
+    fn test_bootfs_file_check_success() {
+        let content_source = "bootfs_file_name";
+        let expected_string = "sample_contents";
+
+        let bootfs_files = hashmap![
+            content_source.to_string() => expected_string.as_bytes().to_vec()
+        ];
+        let bootfs_file_checks = vec![FileCheckSpec {
+            source: FileSource::BootfsFile(content_source.to_string()),
+            state: FileState::Present,
+            content_checks: Some(ContentCheckSpec {
+                must_not_contain: None,
+                must_contain: Some(vec![ContentType::String(expected_string.to_string())]),
+                matches_golden: None,
+            }),
+        }];
+
+        let errors = validate_bootfs_files(bootfs_file_checks, &bootfs_files, "");
+
+        assert_eq!(errors.len(), 0);
+    }
+
+    #[test]
+    fn test_bootfs_file_check_failure() {
+        let content_source = "bootfs_file_name";
+        let expected_string = "sample_contents";
+
+        let bootfs_files = hashmap![
+            content_source.to_string() => expected_string.as_bytes().to_vec()
+        ];
+        let bootfs_file_checks = vec![FileCheckSpec {
+            source: FileSource::BootfsFile(content_source.to_string()),
+            state: FileState::Present,
+            content_checks: Some(ContentCheckSpec {
+                must_not_contain: Some(vec![ContentType::String(expected_string.to_string())]),
+                must_contain: None,
+                matches_golden: None,
+            }),
+        }];
+
+        let errors = validate_bootfs_files(bootfs_file_checks, &bootfs_files, "");
+
+        assert_eq!(errors.len(), 1);
+
+        match &errors[0] {
+            ValidationError::ContentMustNotContainValuePresent {
+                value,
+                content_source: reported_source,
+            } => {
+                assert_eq!(expected_string, value);
+                assert_eq!(content_source, reported_source);
+            }
+            e => assert!(false, "Unexpected error from failure or error case test: {}", e),
+        }
+    }
+
+    #[test]
+    fn test_bootfs_file_check_error() {
+        let content_source = "bootfs_file_name";
+        let expected_string = "sample_contents";
+
+        let bootfs_files = hashmap![
+            content_source.to_string() => expected_string.as_bytes().to_vec()
+        ];
+        let bootfs_file_checks = vec![FileCheckSpec {
+            source: FileSource::PackageMetaContents(content_source.to_string()),
+            state: FileState::Present,
+            content_checks: Some(ContentCheckSpec {
+                must_not_contain: None,
+                must_contain: None,
+                matches_golden: None,
+            }),
+        }];
+
+        let errors = validate_bootfs_files(bootfs_file_checks, &bootfs_files, "");
+
+        assert_eq!(errors.len(), 1);
+
+        match &errors[0] {
+            ValidationError::InvalidPolicyConfiguration { .. } => {}
+            e => assert!(false, "Unexpected error from failure or error case test: {}", e),
+        }
+    }
+
+    #[test]
     fn test_package_check_fails_to_open_blob() {
         // Create mocks with nothing in them and verify validate_package returns an error.
         let check =
@@ -1185,7 +1370,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let validation_errors = validate_package::<TestErrorFreeFileValidator>(
+        let validation_errors = validate_package::<TestErrorFreeFileChecker>(
             &check,
             &pkg_merkle_string,
             &mut blobs_artifact_reader,
@@ -1211,7 +1396,7 @@
             ],
         ));
 
-        let validation_errors = validate_package::<TestErrorFreeFileValidator>(
+        let validation_errors = validate_package::<TestErrorFreeFileChecker>(
             &check,
             &pkg_merkle_string,
             &mut blobs_artifact_reader,
@@ -1233,7 +1418,7 @@
         let check = PackageCheckSpec {
             source: PackageSource::SystemImage,
             file_checks: vec![FileCheckSpec {
-                source: FileSource::MetaContents("sample/path".to_string()),
+                source: FileSource::PackageMetaContents("sample/path".to_string()),
                 state: FileState::Present,
                 content_checks: None,
             }],
@@ -1248,10 +1433,10 @@
             ]));
         // The mock file validator will return 4 errors to exercise the error handling code.
         // These 4 errors will not supply a package name to match the FileValidator's real impl.
-        struct TestFileValidatorWithErrors;
+        struct TestFileCheckerWithErrors;
 
-        impl FileValidator for TestFileValidatorWithErrors {
-            fn validate_file(
+        impl FileChecker for TestFileCheckerWithErrors {
+            fn check_file(
                 check: &FileCheckSpec,
                 _package_far_reader: &mut FarReader<Box<dyn ReadSeek>>,
                 _blobs_artifact_reader: &mut Box<dyn ArtifactReader>,
@@ -1279,7 +1464,7 @@
             }
         }
 
-        let validation_errors = validate_package::<TestFileValidatorWithErrors>(
+        let validation_errors = validate_package::<TestFileCheckerWithErrors>(
             &check,
             &pkg_merkle_string,
             &mut blobs_artifact_reader,
@@ -1328,7 +1513,7 @@
         let check = PackageCheckSpec {
             source: PackageSource::SystemImage,
             file_checks: vec![FileCheckSpec {
-                source: FileSource::MetaContents("sample/path".to_string()),
+                source: FileSource::PackageMetaContents("sample/path".to_string()),
                 state: FileState::Present,
                 content_checks: None,
             }],
@@ -1342,7 +1527,7 @@
                 PathBuf::from_str(&pkg_merkle_string).unwrap() => pkg_far_bytes
             ]));
 
-        let validation_errors = validate_package::<TestErrorFreeFileValidator>(
+        let validation_errors = validate_package::<TestErrorFreeFileChecker>(
             &check,
             &pkg_merkle_string,
             &mut blobs_artifact_reader,
@@ -1366,7 +1551,7 @@
                 PathBuf::from_str(&pkg_merkle_string).unwrap() => pkg_far_bytes
             ]));
 
-        let validation_errors = validate_package::<TestErrorFreeFileValidator>(
+        let validation_errors = validate_package::<TestErrorFreeFileChecker>(
             &check,
             &pkg_merkle_string,
             &mut blobs_artifact_reader,
@@ -1384,7 +1569,7 @@
         let file_name = "some/file";
         let file_merkle_string = "merkle";
         let file_contents_bytes = "some file contents".as_bytes();
-        let source: FileSource = FileSource::MetaContents(file_name.to_string());
+        let source: FileSource = FileSource::PackageMetaContents(file_name.to_string());
         let meta_contents_file_contents = format!("{}={}", file_name, file_merkle_string);
         let pkg_far_contents =
             hashmap![ META_CONTENTS_PATH => meta_contents_file_contents.as_bytes()];
@@ -1397,7 +1582,7 @@
             ]));
 
         let (file_found, bytes_found) =
-            resolve_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader).unwrap();
+            resolve_package_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader).unwrap();
 
         assert_eq!(file_found, file_name.to_string());
         assert_eq!(bytes_found.unwrap(), file_contents_bytes.to_vec());
@@ -1409,7 +1594,7 @@
         // Set up blobs artifact reader to be empty.
         // Verify resolve_file returns None for bytes found, indicating missing file.
         let file_name = "some/file";
-        let source = FileSource::MetaContents(file_name.to_string());
+        let source = FileSource::PackageMetaContents(file_name.to_string());
         let pkg_far_contents =
             hashmap![ META_CONTENTS_PATH => "random/other/file=othermerkle".as_bytes()];
         let pkg_far = create_package_far(pkg_far_contents);
@@ -1419,7 +1604,7 @@
             Box::new(TestArtifactReader::new(HashMap::new()));
 
         let (file_found, bytes_found) =
-            resolve_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader).unwrap();
+            resolve_package_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader).unwrap();
 
         assert!(file_found.is_empty());
         assert!(bytes_found.is_none());
@@ -1430,7 +1615,7 @@
         // Set up a package with meta/contents that isn't parseable as key-value pairs.
         // This is one of several ways to trigger the error flow we want to exercise.
         let file_name = "some/file";
-        let source = FileSource::MetaContents(file_name.to_string());
+        let source = FileSource::PackageMetaContents(file_name.to_string());
         let pkg_far_contents =
             hashmap![ META_CONTENTS_PATH => "something that is not a key value pair".as_bytes()];
         let pkg_far = create_package_far(pkg_far_contents);
@@ -1439,7 +1624,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let res = resolve_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader);
+        let res = resolve_package_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader);
 
         assert!(res.is_err());
     }
@@ -1459,7 +1644,7 @@
             Box::new(TestArtifactReader::new(HashMap::new()));
 
         let (file_found, bytes_found) =
-            resolve_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader).unwrap();
+            resolve_package_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader).unwrap();
 
         assert_eq!(file_found, file_name.to_string());
         assert_eq!(bytes_found.unwrap(), file_contents_bytes.to_vec());
@@ -1479,7 +1664,7 @@
             Box::new(TestArtifactReader::new(HashMap::new()));
 
         let (file_found, bytes_found) =
-            resolve_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader).unwrap();
+            resolve_package_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader).unwrap();
 
         assert!(file_found.is_empty());
         assert!(bytes_found.is_none());
@@ -1501,7 +1686,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let res = resolve_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader);
+        let res = resolve_package_file(&source, &mut pkg_far_reader, &mut blobs_artifact_reader);
 
         assert!(res.is_err());
     }
@@ -1945,7 +2130,44 @@
         let checks = ContentCheckSpec {
             must_contain: None,
             must_not_contain: None,
-            matches_golden: Some(golden_file.path().display().to_string()),
+            matches_golden: Some(vec![golden_file.path().display().to_string()]),
+        };
+
+        let content_bytes = content_string.as_bytes().to_vec();
+        let content_source = "content_source".to_string();
+
+        let errors = validate_file_contents(
+            &checks,
+            content_bytes,
+            &content_source,
+            std::env::temp_dir().to_str().unwrap(),
+        );
+
+        assert_eq!(errors.len(), 0);
+    }
+
+    #[test]
+    fn test_validate_file_matches_multiple_golden_success() {
+        let content_string = "some content
+        another line of stuff
+        third line";
+
+        // Set up a golden file to have the different than expected contents.
+        let failing_golden_content = "some unexpected content";
+        let mut failing_golden_file = NamedTempFile::new().unwrap();
+        failing_golden_file.write_all(failing_golden_content.as_bytes()).unwrap();
+
+        // Set up a golden file to have the same contents as expected contents.
+        let mut golden_file = NamedTempFile::new().unwrap();
+        golden_file.write_all(content_string.as_bytes()).unwrap();
+
+        let checks = ContentCheckSpec {
+            must_contain: None,
+            must_not_contain: None,
+            matches_golden: Some(vec![
+                failing_golden_file.path().display().to_string(),
+                golden_file.path().display().to_string(),
+            ]),
         };
 
         let content_bytes = content_string.as_bytes().to_vec();
@@ -1966,16 +2188,17 @@
         let content_string = "some content
         another line of stuff
         third line\n";
+
+        // Set up the golden file to have expected contents plus some extra.
         let extra_golden_content = "extra expected content";
-        // Set up the golden file to have the same contents as expected contents.
         let mut golden_file = NamedTempFile::new().unwrap();
         golden_file.write_all(content_string.as_bytes()).unwrap();
-        golden_file.write_all("extra expected content".as_bytes()).unwrap();
+        golden_file.write_all(extra_golden_content.as_bytes()).unwrap();
 
         let checks = ContentCheckSpec {
             must_contain: None,
             must_not_contain: None,
-            matches_golden: Some(golden_file.path().display().to_string()),
+            matches_golden: Some(vec![golden_file.path().display().to_string()]),
         };
 
         let content_bytes = content_string.as_bytes().to_vec();
@@ -2004,6 +2227,69 @@
     }
 
     #[test]
+    fn test_validate_file_matches_multiple_golden_failure() {
+        let content_string = "some content
+        another line of stuff
+        third line\n";
+
+        // Set up the golden file to have expected contents plus some extra.
+        let extra_golden_content = "extra expected content";
+        let mut golden_file = NamedTempFile::new().unwrap();
+        golden_file.write_all(content_string.as_bytes()).unwrap();
+        golden_file.write_all(extra_golden_content.as_bytes()).unwrap();
+
+        // Set up a second golden file with entirely unexpected contents.
+        let second_golden_content = "random unrelated text";
+        let mut second_golden_file = NamedTempFile::new().unwrap();
+        second_golden_file.write_all(second_golden_content.as_bytes()).unwrap();
+
+        let checks = ContentCheckSpec {
+            must_contain: None,
+            must_not_contain: None,
+            matches_golden: Some(vec![
+                golden_file.path().display().to_string(),
+                second_golden_file.path().display().to_string(),
+            ]),
+        };
+
+        let content_bytes = content_string.as_bytes().to_vec();
+        let content_source = "content_source".to_string();
+
+        let errors = validate_file_contents(
+            &checks,
+            content_bytes,
+            &content_source,
+            std::env::temp_dir().to_str().unwrap(),
+        );
+
+        assert_eq!(errors.len(), 2);
+        match &errors[0] {
+            ValidationError::ContentGoldenFileMismatch {
+                golden_path,
+                diffs,
+                content_source: reported_source,
+            } => {
+                assert_eq!(golden_file.path().display().to_string(), *golden_path);
+                assert!(diffs.contains(extra_golden_content));
+                assert_eq!(content_source, *reported_source);
+            }
+            e => assert!(false, "Unexpected error from failure or error case test: {}", e),
+        }
+        match &errors[1] {
+            ValidationError::ContentGoldenFileMismatch {
+                golden_path,
+                diffs,
+                content_source: reported_source,
+            } => {
+                assert_eq!(second_golden_file.path().display().to_string(), *golden_path);
+                assert!(diffs.contains(second_golden_content));
+                assert_eq!(content_source, *reported_source);
+            }
+            e => assert!(false, "Unexpected error from failure or error case test: {}", e),
+        }
+    }
+
+    #[test]
     fn test_validate_file_matches_golden_error_loading_golden() {
         let content_string = "some content
         another line of stuff
@@ -2013,7 +2299,7 @@
         let checks = ContentCheckSpec {
             must_contain: None,
             must_not_contain: None,
-            matches_golden: Some(golden_file_name.to_string()),
+            matches_golden: Some(vec![golden_file_name.to_string()]),
         };
 
         let content_bytes = content_string.as_bytes().to_vec();
@@ -2256,7 +2542,7 @@
         // This is one of several ways to trigger the error flow we want to exercise.
         // This is similar to the test scoped to resolve_file, except is for validate_file.
         let file_name = "some/file";
-        let source = FileSource::MetaContents(file_name.to_string());
+        let source = FileSource::PackageMetaContents(file_name.to_string());
         let file_check = FileCheckSpec { source, state: FileState::Present, content_checks: None };
         let pkg_far_contents =
             hashmap![ META_CONTENTS_PATH => "something that is not a key value pair".as_bytes()];
@@ -2266,7 +2552,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let errors = PackageFileValidator::validate_file(
+        let errors = PackageFileChecker::check_file(
             &file_check,
             &mut pkg_far_reader,
             &mut blobs_artifact_reader,
@@ -2299,7 +2585,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let errors = PackageFileValidator::validate_file(
+        let errors = PackageFileChecker::check_file(
             &file_check,
             &mut pkg_far_reader,
             &mut blobs_artifact_reader,
@@ -2323,7 +2609,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let errors = PackageFileValidator::validate_file(
+        let errors = PackageFileChecker::check_file(
             &file_check,
             &mut pkg_far_reader,
             &mut blobs_artifact_reader,
@@ -2355,7 +2641,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let errors = PackageFileValidator::validate_file(
+        let errors = PackageFileChecker::check_file(
             &file_check,
             &mut pkg_far_reader,
             &mut blobs_artifact_reader,
@@ -2380,7 +2666,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let errors = PackageFileValidator::validate_file(
+        let errors = PackageFileChecker::check_file(
             &file_check,
             &mut pkg_far_reader,
             &mut blobs_artifact_reader,
@@ -2411,7 +2697,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let errors = PackageFileValidator::validate_file(
+        let errors = PackageFileChecker::check_file(
             &file_check,
             &mut pkg_far_reader,
             &mut blobs_artifact_reader,
@@ -2435,7 +2721,7 @@
         let mut blobs_artifact_reader: Box<dyn ArtifactReader> =
             Box::new(TestArtifactReader::new(HashMap::new()));
 
-        let errors = PackageFileValidator::validate_file(
+        let errors = PackageFileChecker::check_file(
             &file_check,
             &mut pkg_far_reader,
             &mut blobs_artifact_reader,
diff --git a/src/security/lib/scrutiny/utils/src/package.rs b/src/security/lib/scrutiny/utils/src/package.rs
index d7e0f01..e430c80 100644
--- a/src/security/lib/scrutiny/utils/src/package.rs
+++ b/src/security/lib/scrutiny/utils/src/package.rs
@@ -337,7 +337,7 @@
         crate::io::ReadSeek,
         anyhow::{anyhow, Result},
         fuchsia_archive::write as far_write,
-        fuchsia_merkle::{Hash, MerkleTree, HASH_SIZE},
+        fuchsia_merkle::{Hash, HASH_SIZE},
         maplit::{btreemap, hashmap},
         std::{
             collections::{BTreeMap, HashMap, HashSet},
@@ -476,7 +476,7 @@
         // a merkle and match it against the given value (the `designated_package_hash`).
         let designated_package_hash = Hash::from([0; HASH_SIZE]);
         let package_contents = create_package_far();
-        let package_hash = MerkleTree::from_reader(package_contents.as_slice()).unwrap().root();
+        let package_hash = fuchsia_merkle::from_slice(&package_contents).root();
         assert!(designated_package_hash != package_hash);
 
         // Incorrectly map designated_package_hash` to `package_contents` (that's not its
diff --git a/src/security/lib/scrutiny/utils/test/lib.rs b/src/security/lib/scrutiny/utils/test/lib.rs
index 9fa44f4..8028daf 100644
--- a/src/security/lib/scrutiny/utils/test/lib.rs
+++ b/src/security/lib/scrutiny/utils/test/lib.rs
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 use {
-    fuchsia_merkle::MerkleTree,
     once_cell::sync::Lazy,
     scrutiny_utils::artifact::{ArtifactReader, BlobFsArtifactReader, CompoundArtifactReader},
     std::path::PathBuf,
@@ -33,11 +32,7 @@
 }
 
 fn merkle_as_path_buf(data: &[u8]) -> PathBuf {
-    MerkleTree::from_reader(data)
-        .expect("compute merkle for blobfs file name")
-        .root()
-        .to_string()
-        .into()
+    fuchsia_merkle::from_slice(data).root().to_string().into()
 }
 
 #[test]
diff --git a/src/security/lib/scrutiny/x/src/api.rs b/src/security/lib/scrutiny/x/src/api.rs
index 7eee1f6..a39106e 100644
--- a/src/security/lib/scrutiny/x/src/api.rs
+++ b/src/security/lib/scrutiny/x/src/api.rs
@@ -135,8 +135,6 @@
 
 #[derive(Debug, Error)]
 pub enum ZbiError {
-    #[error("failed to hash blobfs blob at bootfs path {bootfs_path:?}: {error}")]
-    Hash { bootfs_path: Box<dyn Path>, error: std::io::Error },
     #[error("expected to find exactly 1 bootfs section in zbi, but found {num_sections}")]
     BootfsSections { num_sections: usize },
     #[error("failed to parse bootfs image in zbi at path {path:?}: {error}")]
diff --git a/src/security/lib/scrutiny/x/src/blob.rs b/src/security/lib/scrutiny/x/src/blob.rs
index ad0b5cf..23bbf22 100644
--- a/src/security/lib/scrutiny/x/src/blob.rs
+++ b/src/security/lib/scrutiny/x/src/blob.rs
@@ -230,13 +230,13 @@
     pub fn new(
         data_sources: impl IntoIterator<Item = Box<dyn api::DataSource>>,
         bytes: Vec<u8>,
-    ) -> Result<Self, io::Error> {
-        let hash: Hash = FuchsiaMerkleTree::from_reader(bytes.as_slice())?.root().into();
-        Ok(Self(Rc::new(MemoryBlobData {
+    ) -> Self {
+        let hash: Hash = fuchsia_merkle::from_slice(&bytes).root().into();
+        Self(Rc::new(MemoryBlobData {
             data_sources: data_sources.into_iter().collect::<Vec<_>>(),
             hash: Box::new(hash),
             bytes,
-        })))
+        }))
     }
 }
 
@@ -511,8 +511,7 @@
                 .map(|mut blob| {
                     let mut bytes = vec![];
                     blob.read_to_end(&mut bytes).expect("read blob for memory blob set");
-                    let blob = VerifiedMemoryBlob::new(data_sources.clone(), bytes)
-                        .expect("hash blob for memory blob set");
+                    let blob = VerifiedMemoryBlob::new(data_sources.clone(), bytes);
                     (blob.hash(), blob)
                 })
                 .collect::<HashMap<_, _>>();
@@ -554,7 +553,6 @@
     use super::BlobOpenError;
     use fuchsia_hash::HASH_SIZE as FUCHSIA_HASH_SIZE;
     use fuchsia_merkle::Hash as FuchsiaMerkleHash;
-    use fuchsia_merkle::MerkleTree as FuchsiaMerkleTree;
     use maplit::hashmap;
     use std::fs;
     use std::io::Write as _;
@@ -568,7 +566,7 @@
 
     macro_rules! fuchsia_hash {
         ($bytes:expr) => {
-            FuchsiaMerkleTree::from_reader($bytes).unwrap().root()
+            fuchsia_merkle::from_slice($bytes).root()
         };
     }
 
diff --git a/src/security/lib/scrutiny/x/src/bootfs.rs b/src/security/lib/scrutiny/x/src/bootfs.rs
index d160cd3..aec84d5 100644
--- a/src/security/lib/scrutiny/x/src/bootfs.rs
+++ b/src/security/lib/scrutiny/x/src/bootfs.rs
@@ -340,13 +340,11 @@
         let blob_1 = VerifiedMemoryBlob::new(
             [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
             "blob_1".as_bytes().into(),
-        )
-        .expect("blob");
+        );
         let blob_2 = VerifiedMemoryBlob::new(
             [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
             "blob_2".as_bytes().into(),
-        )
-        .expect("blob");
+        );
         let blobs = [(path_1.clone(), blob_1.clone()), (path_2.clone(), blob_2.clone())];
         let bootfs = Bootfs::new(data_source, blobs.clone());
         let mut expected = blobs
@@ -389,13 +387,11 @@
         let blob_1 = VerifiedMemoryBlob::new(
             [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
             "blob_1".as_bytes().into(),
-        )
-        .expect("blob");
+        );
         let blob_2 = VerifiedMemoryBlob::new(
             [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
             "blob_2".as_bytes().into(),
-        )
-        .expect("blob");
+        );
         let blobs = [(path_1.clone(), blob_1.clone()), (path_2.clone(), blob_2.clone())];
         let bootfs = Bootfs::new(data_source, blobs.clone());
         let mut expected = blobs
@@ -439,13 +435,11 @@
         let blob_1 = VerifiedMemoryBlob::new(
             [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
             "blob_1".as_bytes().into(),
-        )
-        .expect("blob");
+        );
         let blob_2 = VerifiedMemoryBlob::new(
             [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
             "blob_2".as_bytes().into(),
-        )
-        .expect("blob");
+        );
         let blobs = [
             (blob_1_path_1.clone(), blob_1.clone()),
             (blob_1_path_2.clone(), blob_1.clone()),
@@ -536,8 +530,7 @@
             VerifiedMemoryBlob::new(
                 [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                 additional_boot_config_str.as_bytes().into(),
-            )
-            .expect("blob"),
+            ),
         )];
         let bootfs = Bootfs::new(data_source, blobs.clone());
         let additional_boot_config =
@@ -566,8 +559,7 @@
             VerifiedMemoryBlob::new(
                 [Box::new(data_source.clone()) as Box<dyn api::DataSource>].into_iter(),
                 additional_boot_config_str.as_bytes().into(),
-            )
-            .expect("blob"),
+            ),
         )];
         let bootfs = Bootfs::new(data_source, blobs.clone().into_iter());
         match bootfs.additional_boot_configuration() {
@@ -591,8 +583,7 @@
             VerifiedMemoryBlob::new(
                 [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                 additional_boot_config_str.as_bytes().into(),
-            )
-            .expect("blob"),
+            ),
         )];
         let bootfs = Bootfs::new(data_source, blobs.clone());
         match bootfs.additional_boot_configuration() {
@@ -619,8 +610,7 @@
             VerifiedMemoryBlob::new(
                 [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                 component_manager_config_bytes.into(),
-            )
-            .expect("blob"),
+            ),
         )];
         let bootfs = Bootfs::new(data_source, blobs.clone());
         let component_manager_config =
@@ -645,8 +635,7 @@
             VerifiedMemoryBlob::new(
                 [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                 component_manager_config_bytes.into(),
-            )
-            .expect("blob"),
+            ),
         )];
         let bootfs = Bootfs::new(data_source, blobs.clone());
         match bootfs.component_manager_configuration() {
@@ -674,16 +663,14 @@
                 VerifiedMemoryBlob::new(
                     [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                     pkg_index_str.into_bytes(),
-                )
-                .expect("package index blob"),
+                ),
             ),
             (
                 pkg_path,
                 VerifiedMemoryBlob::new(
                     [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                     far_bytes,
-                )
-                .expect("package blob"),
+                ),
             ),
         ];
         let bootfs = Bootfs::new(data_source, blobs.clone());
@@ -713,24 +700,21 @@
                 VerifiedMemoryBlob::new(
                     [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                     pkg_index_str.into_bytes(),
-                )
-                .expect("package index blob"),
+                ),
             ),
             (
                 pkg_path.clone(),
                 VerifiedMemoryBlob::new(
                     [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                     far_bytes.clone(),
-                )
-                .expect("package blob 1"),
+                ),
             ),
             (
                 pkg_path,
                 VerifiedMemoryBlob::new(
                     [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                     far_bytes,
-                )
-                .expect("package blob 2"),
+                ),
             ),
         ];
         let bootfs = Bootfs::new(data_source, blobs.clone());
@@ -760,16 +744,14 @@
                 VerifiedMemoryBlob::new(
                     [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                     pkg_index_str.into_bytes(),
-                )
-                .expect("package index blob"),
+                ),
             ),
             (
                 pkg_path,
                 VerifiedMemoryBlob::new(
                     [Box::new(data_source.clone()) as Box<dyn api::DataSource>],
                     far_bytes,
-                )
-                .expect("package blob"),
+                ),
             ),
         ];
         let bootfs = Bootfs::new(data_source, blobs.clone());
diff --git a/src/security/lib/scrutiny/x/src/hash.rs b/src/security/lib/scrutiny/x/src/hash.rs
index 315ab37..283201a 100644
--- a/src/security/lib/scrutiny/x/src/hash.rs
+++ b/src/security/lib/scrutiny/x/src/hash.rs
@@ -50,13 +50,12 @@
 #[cfg(test)]
 mod tests {
     use super::Hash;
-    use fuchsia_merkle::MerkleTree as FuchsiaMerkleTree;
 
     #[fuchsia::test]
     fn test_hex_merkle_root_fmt() {
         let contents = "hello_world";
         let hash = Hash::from_contents(contents.as_bytes());
-        let merkle_root = FuchsiaMerkleTree::from_reader(contents.as_bytes()).unwrap().root();
+        let merkle_root = fuchsia_merkle::from_slice(contents.as_bytes()).root();
         assert_eq!(format!("{}", hash), format!("{}", merkle_root));
     }
 
diff --git a/src/security/lib/scrutiny/x/src/package.rs b/src/security/lib/scrutiny/x/src/package.rs
index 7bb57b3b..fa75905 100644
--- a/src/security/lib/scrutiny/x/src/package.rs
+++ b/src/security/lib/scrutiny/x/src/package.rs
@@ -17,7 +17,6 @@
 use fidl_fuchsia_component_decl as fdecl;
 use fuchsia_archive::Error as FarError;
 use fuchsia_archive::Utf8Reader as FarReader;
-use fuchsia_merkle::MerkleTree as FuchsiaMerkleTree;
 use fuchsia_pkg::MetaContents as FuchsiaMetaContents;
 use fuchsia_pkg::MetaContentsError as FuchsiaMetaContentsError;
 use fuchsia_pkg::MetaPackage as FuchsiaMetaPackage;
@@ -146,10 +145,7 @@
             .into_iter()
             .map(|path_string| {
                 let contents = far_reader.read_file(&path_string)?;
-                let hash: Hash = FuchsiaMerkleTree::from_reader(contents.as_slice())
-                    .map_err(Error::from)?
-                    .root()
-                    .into();
+                let hash: Hash = fuchsia_merkle::from_slice(&contents).root().into();
                 Ok(BlobData {
                     data_sources: vec![Box::new(package_data_source.clone())],
                     path: Box::new(path_string),
@@ -388,7 +384,6 @@
     use cm_rust as cm;
     use cm_rust::NativeIntoFidl as _;
     use cm_rust_testing as cmt;
-    use fuchsia_merkle::MerkleTree as FuchsiaMerkleTree;
     use fuchsia_pkg::MetaContents as FuchsiaMetaContents;
     use fuchsia_pkg::MetaPackage as FuchsiaMetaPackage;
     use fuchsia_pkg::PackageName;
@@ -436,7 +431,10 @@
                 source: cm::OfferSource::Parent,
                 source_name: "test_protocol".parse().unwrap(),
                 source_dictionary: Default::default(),
-                target: cm::OfferTarget::static_child("test_child".to_string()),
+                target: cm::OfferTarget::Child(cm::ChildRef {
+                    name: "test_child".parse().unwrap(),
+                    collection: None,
+                }),
                 target_name: "test_protocol".parse().unwrap(),
                 dependency_type: cm::DependencyType::Strong,
                 availability: cm::Availability::Required,
@@ -500,7 +498,7 @@
         let mut far_bytes = vec![];
         fuchsia_archive::write(&mut far_bytes, far_map).unwrap();
 
-        let far_fuchsia_hash = FuchsiaMerkleTree::from_reader(far_bytes.as_slice()).unwrap().root();
+        let far_fuchsia_hash = fuchsia_merkle::from_slice(&far_bytes).root();
         let meta_far_hash: Box<dyn api::Hash> = Box::new(Hash::from(far_fuchsia_hash));
 
         (meta_far_hash, far_bytes)
@@ -553,7 +551,6 @@
     use super::MetaContents;
     use super::MetaPackage;
     use super::Package;
-    use fuchsia_merkle::MerkleTree as FuchsiaMerkleTree;
     use fuchsia_pkg::MetaContents as FuchsiaMetaContents;
     use fuchsia_pkg::MetaPackage as FuchsiaMetaPackage;
     use fuchsia_pkg::PackageName;
@@ -574,7 +571,7 @@
         let content_blob_content_str = "Hello, World!";
         let content_blob_path_str = "data";
         let content_blob_fuchsia_hash =
-            FuchsiaMerkleTree::from_reader(content_blob_content_str.as_bytes()).unwrap().root();
+            fuchsia_merkle::from_slice(content_blob_content_str.as_bytes()).root();
 
         // Define meta/package.
         let meta_package = FuchsiaMetaPackage::from_name_and_variant_zero(
@@ -599,7 +596,7 @@
         };
         let mut far_bytes = vec![];
         fuchsia_archive::write(&mut far_bytes, far_map).unwrap();
-        let far_fuchsia_hash = FuchsiaMerkleTree::from_reader(far_bytes.as_slice()).unwrap().root();
+        let far_fuchsia_hash = fuchsia_merkle::from_slice(&far_bytes).root();
         let far_fuchsia_hash_string = format!("{}", far_fuchsia_hash);
 
         // Construct blob set with content blob and package meta.far.
@@ -649,9 +646,8 @@
             blob.reader_seeker().unwrap().read_to_end(&mut actual_bytes).unwrap();
             assert_eq!(expected_bytes, actual_bytes.as_slice());
 
-            let expected_hash: Box<dyn api::Hash> = Box::new(Hash::from(
-                FuchsiaMerkleTree::from_reader(expected_bytes).unwrap().root(),
-            ));
+            let expected_hash: Box<dyn api::Hash> =
+                Box::new(Hash::from(fuchsia_merkle::from_slice(expected_bytes).root()));
             let actual_hash = blob.hash();
             assert_eq!(expected_hash.as_ref(), actual_hash.as_ref());
 
@@ -688,9 +684,8 @@
             blob.reader_seeker().unwrap().read_to_end(&mut actual_bytes).unwrap();
             assert_eq!(expected_bytes, actual_bytes.as_slice());
 
-            let expected_hash: Box<dyn api::Hash> = Box::new(Hash::from(
-                FuchsiaMerkleTree::from_reader(expected_bytes).unwrap().root(),
-            ));
+            let expected_hash: Box<dyn api::Hash> =
+                Box::new(Hash::from(fuchsia_merkle::from_slice(expected_bytes).root()));
             let actual_hash = blob.hash();
             assert_eq!(expected_hash.as_ref(), actual_hash.as_ref());
 
@@ -726,8 +721,7 @@
     #[fuchsia::test]
     fn bad_far() {
         let bad_far_contents = vec![];
-        let bad_far_blob =
-            VerifiedMemoryBlob::new([], bad_far_contents.clone()).expect("bad far blob");
+        let bad_far_blob = VerifiedMemoryBlob::new([], bad_far_contents.clone());
         match Package::new(
             None,
             placeholder_package_url(),
@@ -758,7 +752,7 @@
         };
         let mut far_bytes = vec![];
         fuchsia_archive::write(&mut far_bytes, far_map).unwrap();
-        let far_blob = VerifiedMemoryBlob::new([], far_bytes.clone()).expect("far blob");
+        let far_blob = VerifiedMemoryBlob::new([], far_bytes.clone());
 
         // Use empty blob set.
         let blob_set = VerifiedMemoryBlobSet::new([], iter::empty::<&[u8]>());
@@ -792,7 +786,7 @@
         };
         let mut far_bytes = vec![];
         fuchsia_archive::write(&mut far_bytes, far_map).unwrap();
-        let far_blob = VerifiedMemoryBlob::new([], far_bytes.clone()).expect("far blob");
+        let far_blob = VerifiedMemoryBlob::new([], far_bytes.clone());
 
         // Use empty blob set.
         let blob_set = VerifiedMemoryBlobSet::new([], iter::empty::<&[u8]>());
@@ -820,7 +814,7 @@
         let content_blob_content_str = "Hello, World!";
         let content_blob_path_str = "data";
         let content_blob_fuchsia_hash =
-            FuchsiaMerkleTree::from_reader(content_blob_content_str.as_bytes()).unwrap().root();
+            fuchsia_merkle::from_slice(content_blob_content_str.as_bytes()).root();
         let content_blob_hash: Box<dyn api::Hash> =
             Box::new(Hash::from(content_blob_fuchsia_hash.clone()));
 
@@ -851,7 +845,7 @@
         // Use empty blob set: Lookup of content blob will fail.
         let blob_set = VerifiedMemoryBlobSet::new([], iter::empty::<&[u8]>());
 
-        let far_blob = VerifiedMemoryBlob::new([], far_bytes.clone()).expect("far blob");
+        let far_blob = VerifiedMemoryBlob::new([], far_bytes.clone());
 
         // Attempt to construct package. This will construct content blobs that store their metadata
         // such as their data source. Locating the content blob that is missing from `blob_set`
diff --git a/src/security/lib/scrutiny/x/src/product_bundle.rs b/src/security/lib/scrutiny/x/src/product_bundle.rs
index ee32732..8376382 100644
--- a/src/security/lib/scrutiny/x/src/product_bundle.rs
+++ b/src/security/lib/scrutiny/x/src/product_bundle.rs
@@ -223,7 +223,7 @@
                 name: V2_SDK_A_PRODUCT_BUNDLE_REPOSITORY_NAME.to_string(),
                 metadata_path,
                 blobs_path,
-                delivery_blob_type: None,
+                delivery_blob_type: 1,
                 root_private_key_path: None,
                 targets_private_key_path: None,
                 snapshot_private_key_path: None,
@@ -269,7 +269,7 @@
                     name: V2_SDK_A_PRODUCT_BUNDLE_REPOSITORY_NAME.to_string(),
                     metadata_path: a_metadata_path,
                     blobs_path: a_blobs_path,
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
@@ -279,7 +279,7 @@
                     name: V2_SDK_B_PRODUCT_BUNDLE_REPOSITORY_NAME.to_string(),
                     metadata_path: b_metadata_path,
                     blobs_path: b_blobs_path,
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
@@ -289,7 +289,7 @@
                     name: V2_SDK_R_PRODUCT_BUNDLE_REPOSITORY_NAME.to_string(),
                     metadata_path: r_metadata_path,
                     blobs_path: r_blobs_path,
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
@@ -397,12 +397,7 @@
     }
 
     fn blob_path(blob: &[u8]) -> String {
-        format!(
-            "{}",
-            fuchsia_merkle::MerkleTree::from_reader(blob)
-                .expect("merkle tree from string bytes")
-                .root()
-        )
+        format!("{}", fuchsia_merkle::from_slice(blob).root())
     }
 
     fn blob_hash(blob: &[u8]) -> Box<dyn api::Hash> {
diff --git a/src/security/lib/scrutiny/x/src/system.rs b/src/security/lib/scrutiny/x/src/system.rs
index 469fcad..e8634f6 100644
--- a/src/security/lib/scrutiny/x/src/system.rs
+++ b/src/security/lib/scrutiny/x/src/system.rs
@@ -176,7 +176,6 @@
     use super::*;
     use dyn_clone::DynClone;
     use fuchsia_merkle::Hash;
-    use fuchsia_merkle::MerkleTree;
     use std::collections::HashMap;
     use std::fs;
     use std::path::Path;
@@ -187,7 +186,7 @@
     }
 
     fn write_blob<Dir: AsRef<Path>>(directory: Dir, contents: &[u8]) -> Hash {
-        let hash = MerkleTree::from_reader(contents).expect("compute fuchsia merkle tree").root();
+        let hash = fuchsia_merkle::from_slice(contents).root();
         let filename = format!("{}", hash);
         fs::write(directory.as_ref().join(filename), contents).expect("write blob to file");
         hash
diff --git a/src/security/lib/scrutiny/x/src/zbi.rs b/src/security/lib/scrutiny/x/src/zbi.rs
index d8d4ad0..8fcdfaf 100644
--- a/src/security/lib/scrutiny/x/src/zbi.rs
+++ b/src/security/lib/scrutiny/x/src/zbi.rs
@@ -88,8 +88,7 @@
             let blob = VerifiedMemoryBlob::new(
                 [Box::new(self.0.data_source.clone()) as Box<dyn api::DataSource>],
                 bytes,
-            )
-            .map_err(|error| api::ZbiError::Hash { bootfs_path: path.clone(), error })?;
+            );
             bootfs_files.push((path, blob));
         }
 
diff --git a/src/security/lib/zxcrypt/tests/test-device.cc b/src/security/lib/zxcrypt/tests/test-device.cc
index 4a2553e..f95b76a 100644
--- a/src/security/lib/zxcrypt/tests/test-device.cc
+++ b/src/security/lib/zxcrypt/tests/test-device.cc
@@ -412,9 +412,7 @@
     block_count_ = response.value()->info.block_count;
   }
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_block::Session>();
-  ASSERT_OK(endpoints);
-  auto& [client, server] = endpoints.value();
+  auto [client, server] = fidl::Endpoints<fuchsia_hardware_block::Session>::Create();
   ASSERT_OK(fidl::WireCall(zxcrypt_block())->OpenSession(std::move(server)));
 
   {
diff --git a/src/security/lib/zxcrypt/tests/test-device.h b/src/security/lib/zxcrypt/tests/test-device.h
index 7acc6df..899c901 100644
--- a/src/security/lib/zxcrypt/tests/test-device.h
+++ b/src/security/lib/zxcrypt/tests/test-device.h
@@ -93,12 +93,7 @@
   }
 
   fidl::ClientEnd<fuchsia_device::Controller> new_parent_controller() const {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_device::Controller>();
-    if (!endpoints.is_ok()) {
-      FX_PLOGS(ERROR, endpoints.error_value()) << "Failed to create endpoints";
-      return {};
-    }
-    auto& [client, server] = endpoints.value();
+    auto [client, server] = fidl::Endpoints<fuchsia_device::Controller>::Create();
 
     fidl::OneWayStatus status =
         fidl::WireCall(fvm_controller_)->ConnectToController(std::move(server));
@@ -110,12 +105,7 @@
   }
 
   fidl::ClientEnd<fuchsia_hardware_block_volume::Volume> new_parent() const {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_block_volume::Volume>();
-    if (!endpoints.is_ok()) {
-      FX_PLOGS(ERROR, endpoints.error_value()) << "Failed to create endpoints";
-      return {};
-    }
-    auto& [client, server] = endpoints.value();
+    auto [client, server] = fidl::Endpoints<fuchsia_hardware_block_volume::Volume>::Create();
 
     fidl::OneWayStatus status =
         fidl::WireCall(fvm_controller_)->ConnectToDeviceFidl(server.TakeChannel());
diff --git a/src/security/policy/component_manager_policy.json5 b/src/security/policy/component_manager_policy.json5
index ec43dd0..5a404a2 100644
--- a/src/security/policy/component_manager_policy.json5
+++ b/src/security/policy/component_manager_policy.json5
@@ -67,6 +67,16 @@
             {
                 source_moniker: "<component_manager>",
                 source: "component",
+                source_name: "fuchsia.kernel.DebuglogResource",
+                capability: "protocol",
+                target_monikers: [
+                    "/core/testing/system-tests:**",
+                    "/core/test_manager/system-tests:**",
+                ],
+            },
+            {
+                source_moniker: "<component_manager>",
+                source: "component",
                 source_name: "fuchsia.kernel.FramebufferResource",
                 capability: "protocol",
                 target_monikers: [
diff --git a/src/security/policy/component_manager_policy_base.json5 b/src/security/policy/component_manager_policy_base.json5
index f20bba7..efdfc44 100644
--- a/src/security/policy/component_manager_policy_base.json5
+++ b/src/security/policy/component_manager_policy_base.json5
@@ -44,6 +44,17 @@
             {
                 source_moniker: "<component_manager>",
                 source: "component",
+                source_name: "fuchsia.kernel.DebuglogResource",
+                capability: "protocol",
+                target_monikers: [
+                    "/bootstrap",
+                    "/bootstrap/console",
+                    "/bootstrap/svchost",
+                ],
+            },
+            {
+                source_moniker: "<component_manager>",
+                source: "component",
                 source_name: "fuchsia.kernel.FramebufferResource",
                 capability: "protocol",
                 target_monikers: [
diff --git a/src/security/policy/component_manager_policy_eng.json5 b/src/security/policy/component_manager_policy_eng.json5
index e824459..6720fd6 100644
--- a/src/security/policy/component_manager_policy_eng.json5
+++ b/src/security/policy/component_manager_policy_eng.json5
@@ -85,6 +85,16 @@
             {
                 source_moniker: "<component_manager>",
                 source: "component",
+                source_name: "fuchsia.kernel.DebuglogResource",
+                capability: "protocol",
+                target_monikers: [
+                    "/core/testing/vfs-compliance-tests:**",
+                    "/bootstrap/pkg-drivers:**",
+                ],
+            },
+            {
+                source_moniker: "<component_manager>",
+                source: "component",
                 source_name: "fuchsia.kernel.FramebufferResource",
                 capability: "protocol",
                 target_monikers: [
diff --git a/src/security/policy/component_manager_policy_userdebug.json5 b/src/security/policy/component_manager_policy_userdebug.json5
index 9a2c521..ee8473b 100644
--- a/src/security/policy/component_manager_policy_userdebug.json5
+++ b/src/security/policy/component_manager_policy_userdebug.json5
@@ -46,6 +46,16 @@
             {
                 source_moniker: "<component_manager>",
                 source: "component",
+                source_name: "fuchsia.kernel.DebuglogResource",
+                capability: "protocol",
+                target_monikers: [
+                    "/bootstrap",
+                    "/bootstrap/console",
+                ],
+            },
+            {
+                source_moniker: "<component_manager>",
+                source: "component",
                 source_name: "fuchsia.kernel.FramebufferResource",
                 capability: "protocol",
                 target_monikers: [
diff --git a/src/security/tests/pkg_test/assemblies/assemble_security_pkg_test_system.gni b/src/security/tests/pkg_test/assemblies/assemble_security_pkg_test_system.gni
index 7d5c934..17a3e7d 100644
--- a/src/security/tests/pkg_test/assemblies/assemble_security_pkg_test_system.gni
+++ b/src/security/tests/pkg_test/assemblies/assemble_security_pkg_test_system.gni
@@ -231,7 +231,6 @@
       # code from the "main" assembly.
       feature_set_level = "bootstrap"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = labels.assembly
           volume = {
@@ -262,7 +261,6 @@
       # code from the "main" assembly.
       feature_set_level = "bootstrap"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = labels.assembly
         }
@@ -377,8 +375,11 @@
       ":${labels.update_packages_manifests_lists}",
     ]
     args = [
+      "--output",
       rebase_path(outputs[0], root_build_dir),
+      "--paths",
       rebase_path(files.base_package_manifests_list, root_build_dir),
+      "--paths",
       rebase_path(files.update_packages_manifests_list, root_build_dir),
     ]
     inputs = [
diff --git a/src/security/tests/pkg_test/fake_boot_arguments/src/fake_boot_arguments.rs b/src/security/tests/pkg_test/fake_boot_arguments/src/fake_boot_arguments.rs
index 360429a..0c5f9d0 100644
--- a/src/security/tests/pkg_test/fake_boot_arguments/src/fake_boot_arguments.rs
+++ b/src/security/tests/pkg_test/fake_boot_arguments/src/fake_boot_arguments.rs
@@ -43,8 +43,7 @@
     .await
     .unwrap();
 
-    let system_image_merkle =
-        fuchsia_merkle::MerkleTree::from_reader(system_image.as_slice()).unwrap().root();
+    let system_image_merkle = fuchsia_merkle::from_slice(&system_image).root();
     let pkgfs_boot_arg_value = format!("{}{}", PKGFS_BOOT_ARG_VALUE_PREFIX, system_image_merkle);
 
     let mut fs = fuchsia_component::server::ServiceFs::new();
diff --git a/src/security/tests/scrutiny_ffx_integration/BUILD.gn b/src/security/tests/scrutiny_ffx_integration/BUILD.gn
index b0df5f4..6af191f 100644
--- a/src/security/tests/scrutiny_ffx_integration/BUILD.gn
+++ b/src/security/tests/scrutiny_ffx_integration/BUILD.gn
@@ -42,7 +42,6 @@
       build_type = "eng"
       feature_set_level = "bootstrap"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = _assemble_system_target_name
           volume = {
@@ -65,7 +64,6 @@
       build_type = "eng"
       feature_set_level = "bootstrap"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = _assemble_system_recovery_target_name
           volume = {
diff --git a/src/session/bin/session_manager/BUILD.gn b/src/session/bin/session_manager/BUILD.gn
index 52a3c64..a12fde54 100644
--- a/src/session/bin/session_manager/BUILD.gn
+++ b/src/session/bin/session_manager/BUILD.gn
@@ -87,6 +87,7 @@
 fuchsia_component_manifest("manifest") {
   component_name = "session_manager"
   manifest = "meta/session_manager.cml"
+  restricted_features = [ "dictionaries" ]
 }
 
 fuchsia_structured_config_rust_lib("session_manager_config") {
diff --git a/src/session/tests/session_manager/BUILD.gn b/src/session/tests/session_manager/BUILD.gn
index 21ba886..8af0146 100644
--- a/src/session/tests/session_manager/BUILD.gn
+++ b/src/session/tests/session_manager/BUILD.gn
@@ -18,16 +18,28 @@
 
   deps = [
     "//sdk/fidl/fuchsia.component:fuchsia.component_rust",
+    "//sdk/fidl/fuchsia.hardware.suspend:fuchsia.hardware.suspend_rust",
     "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
+    "//sdk/fidl/fuchsia.power.broker:fuchsia.power.broker_rust",
+    "//sdk/fidl/fuchsia.power.suspend:fuchsia.power.suspend_rust",
+    "//sdk/fidl/fuchsia.power.system:fuchsia.power.system_rust",
+    "//sdk/fidl/fuchsia.session:fuchsia.session_rust",
+    "//sdk/fidl/fuchsia.session.power:fuchsia.session.power_rust",
+    "//sdk/fidl/fuchsia.sys2:fuchsia.sys2_rust",
     "//src/lib/diagnostics/hierarchy/rust",
     "//src/lib/diagnostics/reader/rust",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia",
+    "//src/lib/fuchsia-async",
     "//src/lib/fuchsia-component",
     "//src/lib/fuchsia-component-test",
+    "//src/power/system-activity-governor/integration/testing/fidl:test.suspendcontrol_rust",
+    "//src/power/system-activity-governor/integration/testing/fidl:test.systemactivitygovernor_rust",
     "//src/session/bin/session_manager:lib",
     "//src/sys/lib/cm_rust",
+    "//src/testing/realm_proxy/client",
     "//third_party/rust_crates:anyhow",
+    "//third_party/rust_crates:futures",
   ]
 
   sources = [ "src/main.rs" ]
@@ -40,12 +52,22 @@
   deps = [ ":test" ]
 }
 
+fuchsia_component("use-power-fidl") {
+  testonly = true
+  component_name = "use-power-fidl"
+  manifest = "meta/use-power-fidl.cml"
+}
+
 fuchsia_test_package("package") {
   package_name = "session-manager-integration-tests"
   test_components = [ ":component" ]
-  subpackages = [ "//src/session/examples/hello-world-session" ]
+  subpackages = [
+    "//src/session/examples/hello-world-session",
+    "//src/power/system-activity-governor/integration/testing/realm-factory",
+  ]
   deps = [
     ":bogus_session_manager_test_config_values",
+    ":use-power-fidl",
     "//src/session/bin/session_manager:session_manager_comp",
   ]
 }
diff --git a/src/session/tests/session_manager/meta/session-manager-integration-test.cml b/src/session/tests/session_manager/meta/session-manager-integration-test.cml
index 584adc4..c0630b2 100644
--- a/src/session/tests/session_manager/meta/session-manager-integration-test.cml
+++ b/src/session/tests/session_manager/meta/session-manager-integration-test.cml
@@ -4,6 +4,7 @@
 {
     include: [
         "//src/sys/test_runners/rust/default.shard.cml",
+        "//src/testing/realm_proxy/client/meta/realm_proxy.shard.cml",
         "inspect/client.shard.cml",
         "sys/component/realm_builder.shard.cml",
         "syslog/client.shard.cml",
@@ -11,6 +12,12 @@
     program: {
         binary: "bin/session_manager_integration_test",
     },
+    children: [
+        {
+            name: "test_realm_factory",
+            url: "system-activity-governor-realm-factory#meta/realm-factory.cm",
+        },
+    ],
     collections: [
         {
             name: "session",
@@ -23,5 +30,9 @@
             from: "framework",
         },
         { protocol: "fuchsia.diagnostics.ArchiveAccessor" },
+        {
+            protocol: "test.systemactivitygovernor.RealmFactory",
+            from: "#test_realm_factory",
+        },
     ],
 }
diff --git a/src/session/tests/session_manager/meta/use-power-fidl.cml b/src/session/tests/session_manager/meta/use-power-fidl.cml
new file mode 100644
index 0000000..980e926
--- /dev/null
+++ b/src/session/tests/session_manager/meta/use-power-fidl.cml
@@ -0,0 +1,8 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    use: [
+        { protocol: "fuchsia.session.power.Handoff" },
+    ],
+}
diff --git a/src/session/tests/session_manager/src/main.rs b/src/session/tests/session_manager/src/main.rs
index 749f4ad..c662857 100644
--- a/src/session/tests/session_manager/src/main.rs
+++ b/src/session/tests/session_manager/src/main.rs
@@ -5,12 +5,22 @@
 use {
     diagnostics_hierarchy::DiagnosticsHierarchy,
     diagnostics_reader::{ArchiveReader, Inspect},
-    fidl::endpoints::create_proxy,
-    fidl_fuchsia_component as fcomponent, fidl_fuchsia_io as fio,
-    fuchsia_component::client::connect_to_protocol,
+    fidl::endpoints::{create_endpoints, create_proxy, ServerEnd},
+    fidl_fuchsia_component as fcomponent, fidl_fuchsia_hardware_suspend as fhsuspend,
+    fidl_fuchsia_io as fio, fidl_fuchsia_power_broker as fbroker,
+    fidl_fuchsia_power_suspend as fsuspend, fidl_fuchsia_power_system as fsystem,
+    fidl_fuchsia_session as fsession, fidl_fuchsia_session_power as fpower,
+    fidl_fuchsia_sys2 as fsys2, fidl_test_suspendcontrol as tsc,
+    fidl_test_systemactivitygovernor as ftest, fuchsia_async as fasync,
+    fuchsia_component::{client::connect_to_protocol, server::ServiceFs},
     fuchsia_component_test::{
-        Capability, ChildOptions, ChildRef, DirectoryContents, RealmBuilder, Ref, Route,
+        Capability, ChildOptions, ChildRef, DirectoryContents, RealmBuilder, RealmInstance, Ref,
+        Route,
     },
+    futures::{select, FutureExt, StreamExt},
+    realm_proxy_client::RealmProxyClient,
+    std::sync::{Arc, Mutex},
+    tsc::DeviceProxy,
 };
 
 const SESSION_URL: &'static str = "hello-world-session#meta/hello-world-session.cm";
@@ -26,7 +36,7 @@
     let session_url = String::from(SESSION_URL);
     println!("Session url: {}", &session_url);
 
-    // `launch_session()` requires an initial exposed-diretory request, so create, pass and
+    // `launch_session()` requires an initial exposed-directory request, so create, pass and
     // immediately close a `Directory` channel.
     let (_exposed_dir, exposed_dir_server_end) = create_proxy::<fio::DirectoryMarker>().unwrap();
 
@@ -41,6 +51,7 @@
     builder: &RealmBuilder,
     session_url: String,
     autolaunch: bool,
+    suspend_enabled: bool,
 ) -> anyhow::Result<ChildRef> {
     let child_ref = builder
         .add_child("session-manager", "#meta/session_manager.cm", ChildOptions::new().eager())
@@ -60,7 +71,7 @@
     builder
         .add_capability(cm_rust::CapabilityDecl::Config(cm_rust::ConfigurationDecl {
             name: "fuchsia.power.SuspendEnabled".to_string().parse()?,
-            value: false.into(),
+            value: suspend_enabled.into(),
         }))
         .await?;
 
@@ -103,6 +114,7 @@
         &builder,
         "hello-world-session#meta/hello-world-session.cm".to_string(),
         true,
+        false,
     )
     .await?;
 
@@ -132,6 +144,7 @@
         &builder,
         "hello-world-session#meta/hello-world-session.cm".to_string(),
         false,
+        false,
     )
     .await?;
 
@@ -154,6 +167,7 @@
         &builder,
         "hello-world-session#meta/hello-world-session.cm".to_string(),
         true,
+        false,
     )
     .await?;
 
@@ -175,3 +189,258 @@
     realm.destroy().await?;
     Ok(())
 }
+
+async fn create_system_activity_governor_realm(
+) -> anyhow::Result<(RealmProxyClient, String, tsc::DeviceProxy)> {
+    let realm_factory = connect_to_protocol::<ftest::RealmFactoryMarker>()?;
+    let (client, server) = create_endpoints();
+    let (result, suspend_control_client_end) = realm_factory
+        .create_realm(server)
+        .await?
+        .map_err(realm_proxy_client::Error::OperationError)?;
+    Ok((RealmProxyClient::from(client), result, suspend_control_client_end.into_proxy().unwrap()))
+}
+
+async fn set_up_default_suspender(device: &tsc::DeviceProxy) {
+    device
+        .set_suspend_states(&tsc::DeviceSetSuspendStatesRequest {
+            suspend_states: Some(vec![fhsuspend::SuspendState {
+                resume_latency: Some(0),
+                ..Default::default()
+            }]),
+            ..Default::default()
+        })
+        .await
+        .unwrap()
+        .unwrap()
+}
+
+struct SessionManagerPowerTest {
+    sag_realm: Arc<RealmProxyClient>,
+    suspend_device: DeviceProxy,
+    session_manager_realm: RealmInstance,
+    handoff: fpower::HandoffProxy,
+}
+
+impl SessionManagerPowerTest {
+    async fn new(suspend_enabled: bool) -> anyhow::Result<Self> {
+        let (sag_realm, _, suspend_device) = create_system_activity_governor_realm().await?;
+        let sag_realm = Arc::new(sag_realm);
+        set_up_default_suspender(&suspend_device).await;
+
+        // Build the `session-manager` realm.
+        let builder = RealmBuilder::new().await?;
+        builder
+            .add_route(
+                Route::new()
+                    .capability(Capability::protocol_by_name("fuchsia.sys2.RealmQuery"))
+                    .from(Ref::framework())
+                    .to(Ref::parent()),
+            )
+            .await?;
+        let session_manager =
+            add_session_manager(&builder, "".to_string(), false, suspend_enabled).await?;
+
+        // Route power protocols to `session-manager` using a proxying local child.
+        let sag_realm_1 = sag_realm.clone();
+        let sag_realm_2 = sag_realm.clone();
+        let mut fs = ServiceFs::new();
+        fs.dir("svc")
+            .add_service_connector(move |server_end: ServerEnd<fbroker::TopologyMarker>| {
+                let sag_realm_1 = sag_realm_1.clone();
+                fasync::Task::spawn(async move {
+                    sag_realm_1.connect_server_end_to_protocol(server_end).await.unwrap()
+                })
+                .detach();
+            })
+            .add_service_connector(
+                move |server_end: ServerEnd<fsystem::ActivityGovernorMarker>| {
+                    let sag_realm_2 = sag_realm_2.clone();
+                    fasync::Task::spawn(async move {
+                        sag_realm_2.connect_server_end_to_protocol(server_end).await.unwrap()
+                    })
+                    .detach();
+                },
+            );
+        let fs_holder = Mutex::new(Some(fs));
+        let sag_proxy = builder
+            .add_local_child(
+                "sag_proxy",
+                move |handles| {
+                    let mut rfs = fs_holder
+                        .lock()
+                        .unwrap()
+                        .take()
+                        .expect("mock component should only be launched once");
+                    async {
+                        rfs.serve_connection(handles.outgoing_dir).unwrap();
+                        Ok(rfs.collect().await)
+                    }
+                    .boxed()
+                },
+                ChildOptions::new(),
+            )
+            .await?;
+        builder
+            .add_route(
+                Route::new()
+                    .capability(Capability::protocol_by_name("fuchsia.power.broker.Topology"))
+                    .capability(Capability::protocol_by_name(
+                        "fuchsia.power.system.ActivityGovernor",
+                    ))
+                    .from(&sag_proxy)
+                    .to(&session_manager),
+            )
+            .await?;
+
+        // Launch a session that gives us access to the `fuchsia.session.power/Handoff` protocol.
+        builder
+            .add_route(
+                Route::new()
+                    .capability(Capability::protocol_by_name("fuchsia.session.Launcher"))
+                    .capability(Capability::protocol_by_name("fuchsia.session.Restarter"))
+                    .from(&session_manager)
+                    .to(Ref::parent()),
+            )
+            .await?;
+        let realm = builder.build().await?;
+        let launcher =
+            realm.root.connect_to_protocol_at_exposed_dir::<fsession::LauncherMarker>().unwrap();
+        launcher
+            .launch(&fsession::LaunchConfiguration {
+                session_url: Some("#meta/use-power-fidl.cm".to_string()),
+                ..Default::default()
+            })
+            .await
+            .unwrap()
+            .unwrap();
+        let inspect = get_session_manager_inspect(&realm, "root/session_started_at").await?;
+        assert_eq!(
+            1,
+            inspect
+                .get_child("session_started_at")
+                .expect("session_started_at is not none")
+                .children
+                .len()
+        );
+
+        // Open the session's namespace dir.
+        let realm_query =
+            realm.root.connect_to_protocol_at_exposed_dir::<fsys2::RealmQueryMarker>().unwrap();
+        let (namespace, server_end) = create_endpoints::<fio::DirectoryMarker>();
+        realm_query
+            .open(
+                "session-manager/session:session",
+                fsys2::OpenDirType::NamespaceDir,
+                fio::OpenFlags::empty(),
+                fio::ModeType::empty(),
+                ".",
+                server_end.into_channel().into(),
+            )
+            .await
+            .unwrap()
+            .unwrap();
+        let handoff = fuchsia_component::client::connect_to_protocol_at_dir_svc::<
+            fpower::HandoffMarker,
+        >(&namespace)
+        .unwrap();
+
+        Ok(Self { sag_realm, suspend_device, session_manager_realm: realm, handoff })
+    }
+}
+
+// If session manager is configured to not support suspend, taking the power lease should error.
+#[fuchsia::test]
+async fn take_power_lease_unsupported() -> anyhow::Result<()> {
+    let test = SessionManagerPowerTest::new(false).await?;
+    assert_eq!(test.handoff.take().await.unwrap().unwrap_err(), fpower::HandoffError::Unavailable);
+    Ok(())
+}
+
+/// An integration test that verifies a session can take the power lease from
+/// `session-manager`. Furthermore, dropping the lease will cause the system
+/// to suspend.
+#[fuchsia::test]
+async fn take_power_lease_and_suspend() -> anyhow::Result<()> {
+    let test = SessionManagerPowerTest::new(true).await?;
+
+    // Take the power lease.
+    let lease = test.handoff.take().await.unwrap().unwrap();
+
+    // Taking again should error.
+    assert_eq!(test.handoff.take().await.unwrap().unwrap_err(), fpower::HandoffError::AlreadyTaken);
+
+    // The system should not suspend. Wait a while for a suspend that should not happen.
+    // A timeout is not the most ideal. But if SAG incorrectly requested suspend, this test
+    // will flake. Having a flakily failing test should be better than no test.
+    let mut await_suspend = Box::pin(test.suspend_device.await_suspend().fuse());
+    select! {
+        suspended = &mut await_suspend => panic!("Unexpected suspend event {suspended:?}"),
+        _ = fasync::Timer::new(fasync::Duration::from_millis(400)).fuse() => {},
+    };
+    let stats = test.sag_realm.connect_to_protocol::<fsuspend::StatsMarker>().await?;
+    let current_stats = stats.watch().await?;
+    assert_eq!(Some(0), current_stats.success_count);
+    assert_eq!(Some(0), current_stats.fail_count);
+    assert_eq!(None, current_stats.last_failed_error);
+    assert_eq!(None, current_stats.last_time_in_suspend);
+
+    // Drop the power lease.
+    drop(lease);
+
+    // The system should then suspend.
+    assert_eq!(0, await_suspend.await.unwrap().unwrap().state_index.unwrap());
+    test.suspend_device
+        .resume(&tsc::DeviceResumeRequest::Result(tsc::SuspendResult {
+            suspend_duration: Some(2i64),
+            suspend_overhead: Some(1i64),
+            ..Default::default()
+        }))
+        .await
+        .unwrap()
+        .unwrap();
+
+    // When resumed we should see updated stats.
+    let current_stats = stats.watch().await?;
+    assert_eq!(Some(1), current_stats.success_count);
+    assert_eq!(Some(0), current_stats.fail_count);
+    assert_eq!(None, current_stats.last_failed_error);
+    assert_eq!(Some(2), current_stats.last_time_in_suspend);
+    Ok(())
+}
+
+/// If the session restarted after the lease is taken, the system should still not suspend.
+#[fuchsia::test]
+async fn take_power_lease_and_restart() -> anyhow::Result<()> {
+    let test = SessionManagerPowerTest::new(true).await?;
+
+    // Take the power lease.
+    let lease = test.handoff.take().await.unwrap().unwrap();
+
+    // Restart the session.
+    let restarter = test
+        .session_manager_realm
+        .root
+        .connect_to_protocol_at_exposed_dir::<fsession::RestarterMarker>()
+        .unwrap();
+    restarter.restart().await.unwrap().unwrap();
+
+    // Drop the power lease. This simulates the session getting killed as part of restart.
+    drop(lease);
+
+    // The system should not suspend. Wait a while for a suspend that should not happen.
+    // A timeout is not the most ideal. But if SAG incorrectly requested suspend, this test
+    // will flake. Having a flakily failing test should be better than no test.
+    let mut await_suspend = Box::pin(test.suspend_device.await_suspend().fuse());
+    select! {
+        suspended = &mut await_suspend => panic!("Unexpected suspend event {suspended:?}"),
+        _ = fasync::Timer::new(fasync::Duration::from_millis(400)).fuse() => {},
+    };
+    let stats = test.sag_realm.connect_to_protocol::<fsuspend::StatsMarker>().await?;
+    let current_stats = stats.watch().await?;
+    assert_eq!(Some(0), current_stats.success_count);
+    assert_eq!(Some(0), current_stats.fail_count);
+    assert_eq!(None, current_stats.last_failed_error);
+    assert_eq!(None, current_stats.last_time_in_suspend);
+    Ok(())
+}
diff --git a/src/settings/service/BUILD.gn b/src/settings/service/BUILD.gn
index 8a91b7d..8fd9c0a 100644
--- a/src/settings/service/BUILD.gn
+++ b/src/settings/service/BUILD.gn
@@ -56,7 +56,6 @@
     "//sdk/fidl/fuchsia.ui.types:fuchsia.ui.types_rust",
     "//src/lib/diagnostics/inspect/derive",
     "//src/lib/diagnostics/inspect/rust",
-    "//src/lib/fdio/rust:fdio",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia-async",
     "//src/lib/fuchsia-component",
@@ -81,7 +80,7 @@
 
   test_configs = [
     "//build/config/rust:codegen_units_16",
-    "//build/config/rust:lto_disabled",
+    "//build/config/lto:no-lto",
   ]
 
   test_deps = [
@@ -92,7 +91,6 @@
     "//src/lib/fuchsia-sync",
     "//src/storage/lib/vfs/rust:vfs",
     "//third_party/rust_crates:assert_matches",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:rand",
   ]
 
@@ -134,7 +132,6 @@
     "src/display/display_configuration.rs",
     "src/display/display_controller.rs",
     "src/display/display_fidl_handler.rs",
-    "src/display/light_sensor_config.rs",
     "src/display/types.rs",
     "src/do_not_disturb.rs",
     "src/do_not_disturb/do_not_disturb_controller.rs",
@@ -429,7 +426,6 @@
     "src/tests/testdata/input_device_configuration.json",
     "src/tests/testdata/interface_configuration.json",
     "src/tests/testdata/light_hardware_configuration.json",
-    "src/tests/testdata/light_sensor_configuration.json",
     "src/tests/testdata/service_flags.json",
   ]
   outputs = [ "data/{{source_file_part}}" ]
diff --git a/src/settings/service/integration_tests/input_tests/src/common.rs b/src/settings/service/integration_tests/input_tests/src/common.rs
index 9b390b5..3c80dbb 100644
--- a/src/settings/service/integration_tests/input_tests/src/common.rs
+++ b/src/settings/service/integration_tests/input_tests/src/common.rs
@@ -22,11 +22,7 @@
     ) -> Result<(), Error>;
 }
 
-pub struct InputTest {
-    // TODO(https://fxbug.dev/332407468): Remove or explain #[allow(dead_code)].
-    #[allow(dead_code)]
-    pub camera_sw_muted: Arc<AtomicBool>,
-}
+pub struct InputTest;
 
 impl InputTest {
     pub async fn create_realm(cam_muted: Arc<AtomicBool>) -> Result<RealmInstance, Error> {
diff --git a/src/settings/service/meta/sample_setui_config_test_all_args.cml b/src/settings/service/meta/sample_setui_config_test_all_args.cml
index 5172024..998cec7 100644
--- a/src/settings/service/meta/sample_setui_config_test_all_args.cml
+++ b/src/settings/service/meta/sample_setui_config_test_all_args.cml
@@ -17,8 +17,6 @@
             "/pkg/data/input_device_configuration.json",
             "--interface-config",
             "/pkg/data/interface_configuration.json",
-            "--light-sensor-config",
-            "/pkg/data/light_sensor_configuration.json",
             "--light-hardware-config",
             "/pkg/data/light_hardware_configuration.json",
             "--agent-config",
diff --git a/src/settings/service/meta/sample_setui_config_test_short_args.cml b/src/settings/service/meta/sample_setui_config_test_short_args.cml
index 6518604..b61c359 100644
--- a/src/settings/service/meta/sample_setui_config_test_short_args.cml
+++ b/src/settings/service/meta/sample_setui_config_test_short_args.cml
@@ -17,8 +17,6 @@
             "/pkg/data/input_device_configuration.json",
             "-x",
             "/pkg/data/interface_configuration.json",
-            "-l",
-            "/pkg/data/light_sensor_configuration.json",
             "-h",
             "/pkg/data/light_hardware_configuration.json",
             "-a",
diff --git a/src/settings/service/src/agent/earcons/utils.rs b/src/settings/service/src/agent/earcons/utils.rs
index a5ee088..dea7ee2 100644
--- a/src/settings/service/src/agent/earcons/utils.rs
+++ b/src/settings/service/src/agent/earcons/utils.rs
@@ -4,28 +4,25 @@
 use crate::call_async;
 use crate::event::Publisher;
 use crate::service_context::{ExternalServiceProxy, ServiceContext};
-use anyhow::{format_err, Context as _, Error};
+use anyhow::{anyhow, Context as _, Error};
+use fidl::endpoints::Proxy as _;
 use fidl_fuchsia_io as fio;
 use fidl_fuchsia_media::AudioRenderUsage;
 use fidl_fuchsia_media_sounds::{PlayerMarker, PlayerProxy};
 use fuchsia_async as fasync;
-use fuchsia_zircon as zx;
 use futures::lock::Mutex;
 use std::collections::HashSet;
-use std::fs::File;
 use std::sync::Arc;
 
 /// Creates a file-based sound from a resource file.
 fn resource_file(name: &str) -> Result<fidl::endpoints::ClientEnd<fio::FileMarker>, Error> {
-    // We try two paths here, because normal components see their config package data resources in
-    // /pkg/data and shell tools see them in /pkgfs/packages/config-data/0/meta/data/<pkg>.
-    Ok(fidl::endpoints::ClientEnd::<fio::FileMarker>::new(zx::Channel::from(fdio::transfer_fd(
-        File::open(format!("/config/data/{name}"))
-            .or_else(|_| {
-                File::open(format!("/pkgfs/packages/config-data/0/meta/data/setui_service/{name}"))
-            })
-            .context("Opening package data file")?,
-    )?)))
+    let path = format!("/config/data/{name}");
+    fuchsia_fs::file::open_in_namespace(&path, fio::OpenFlags::RIGHT_READABLE)
+        .with_context(|| format!("opening resource file: {path}"))?
+        .into_client_end()
+        .map_err(|_: fio::FileProxy| {
+            anyhow!("failed to convert new Proxy to ClientEnd for resource file {path}")
+        })
 }
 
 /// Establish a connection to the sound player and return the proxy representing the service.
@@ -60,13 +57,13 @@
     if added_files.lock().await.insert(file_name) {
         let sound_file_channel = match resource_file(file_name) {
             Ok(file) => Some(file),
-            Err(e) => return Err(format_err!("[earcons] Failed to convert sound file: {}", e)),
+            Err(e) => return Err(anyhow!("[earcons] Failed to convert sound file: {}", e)),
         };
         if let Some(file_channel) = sound_file_channel {
             match call_async!(sound_player_proxy => add_sound_from_file(id, file_channel)).await {
                 Ok(_) => tracing::debug!("[earcons] Added sound to Player: {}", file_name),
                 Err(e) => {
-                    return Err(format_err!("[earcons] Unable to add sound to Player: {}", e));
+                    return Err(anyhow!("[earcons] Unable to add sound to Player: {}", e));
                 }
             };
         }
diff --git a/src/settings/service/src/display.rs b/src/settings/service/src/display.rs
index 7c57db9..eea63e4 100644
--- a/src/settings/service/src/display.rs
+++ b/src/settings/service/src/display.rs
@@ -5,7 +5,4 @@
 pub mod display_configuration;
 pub mod display_controller;
 mod display_fidl_handler;
-mod light_sensor_config;
 pub mod types;
-
-pub use light_sensor_config::LightSensorConfig;
diff --git a/src/settings/service/src/display/light_sensor_config.rs b/src/settings/service/src/display/light_sensor_config.rs
deleted file mode 100644
index 08c8819..0000000
--- a/src/settings/service/src/display/light_sensor_config.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use serde::Deserialize;
-
-#[derive(Deserialize, Debug)]
-#[serde(untagged)]
-pub enum LightSensorConfig {
-    VendorAndProduct { vendor_id: u32, product_id: u32 },
-}
diff --git a/src/settings/service/src/ingress/fidl.rs b/src/settings/service/src/ingress/fidl.rs
index aefcfcd..7864e20 100644
--- a/src/settings/service/src/ingress/fidl.rs
+++ b/src/settings/service/src/ingress/fidl.rs
@@ -79,7 +79,6 @@
     }
 }
 
-// TODO(https://fxbug.dev/42074066) Remove light sensor flags after configs updated.
 pub mod display {
     use bitflags::bitflags;
     use serde::Deserialize;
@@ -91,14 +90,12 @@
         #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
         pub struct InterfaceFlags: u64 {
             const BASE = 1 << 0;
-            const LIGHT_SENSOR = 1 << 1;
         }
     }
 
     #[derive(Copy, Clone, Deserialize, PartialEq, Eq, Hash, Debug)]
     pub enum InterfaceSpec {
         Base,
-        LightSensor,
     }
 
     impl From<Vec<InterfaceSpec>> for InterfaceFlags {
@@ -107,7 +104,6 @@
                 flags
                     | match variant {
                         InterfaceSpec::Base => InterfaceFlags::BASE,
-                        InterfaceSpec::LightSensor => InterfaceFlags::LIGHT_SENSOR,
                     }
             })
         }
diff --git a/src/settings/service/src/lib.rs b/src/settings/service/src/lib.rs
index be976ed..c026f5d 100644
--- a/src/settings/service/src/lib.rs
+++ b/src/settings/service/src/lib.rs
@@ -32,7 +32,6 @@
 use settings_storage::fidl_storage::FidlStorage;
 
 pub use display::display_configuration::DisplayConfiguration;
-pub use display::LightSensorConfig;
 pub use handler::setting_proxy_inspect_info::SettingProxyInspectInfo;
 pub use input::input_device_configuration::InputConfiguration;
 pub use light::light_hardware_configuration::LightHardwareConfiguration;
@@ -178,27 +177,6 @@
 
     fn set_fidl_interfaces(&mut self, interfaces: HashSet<fidl::Interface>) {
         self.fidl_interfaces = interfaces;
-
-        let display_subinterfaces = [
-            fidl::Interface::Display(fidl::display::InterfaceFlags::LIGHT_SENSOR),
-            fidl::Interface::Display(fidl::display::InterfaceFlags::BASE),
-        ]
-        .into();
-
-        // Consolidate display type.
-        // TODO(https://fxbug.dev/42074066): Remove this special handling once light sensor is its own FIDL
-        // interface.
-        if self.fidl_interfaces.is_superset(&display_subinterfaces) {
-            self.fidl_interfaces = &self.fidl_interfaces - &display_subinterfaces;
-            let inserted = self.fidl_interfaces.insert(fidl::Interface::Display(
-                fidl::display::InterfaceFlags::BASE | fidl::display::InterfaceFlags::LIGHT_SENSOR,
-            ));
-            assert!(
-                inserted,
-                "Cannot insert the display interface twice. Please check the interface \
-                configuration"
-            );
-        }
     }
 
     fn set_controller_flags(&mut self, controller_flags: HashSet<ControllerFlag>) {
diff --git a/src/settings/service/src/setui_config_test.rs b/src/settings/service/src/setui_config_test.rs
index 7107bbf..01e84228 100644
--- a/src/settings/service/src/setui_config_test.rs
+++ b/src/settings/service/src/setui_config_test.rs
@@ -7,7 +7,7 @@
 use serde::de::DeserializeOwned;
 use settings::{
     AgentConfiguration, DisplayConfiguration, EnabledInterfacesConfiguration, InputConfiguration,
-    LightHardwareConfiguration, LightSensorConfig, ServiceFlags,
+    LightHardwareConfiguration, ServiceFlags,
 };
 use std::collections::hash_map::DefaultHasher;
 use std::collections::HashMap;
@@ -36,10 +36,6 @@
     #[argh(option, short = 'x')]
     interface_config: Vec<OsString>,
 
-    /// these configurations control specific settings within the light sensor controller.
-    #[argh(option, short = 'l')]
-    light_sensor_config: Vec<OsString>,
-
     /// these configurations control specific settings for light hardware.
     #[argh(option, short = 'h')]
     light_hardware_config: Vec<OsString>,
@@ -83,10 +79,6 @@
         let _ = read_config::<EnabledInterfacesConfiguration>(&config)?;
     }
 
-    for config in test_config.light_sensor_config.into_iter() {
-        let _ = read_config::<LightSensorConfig>(&config)?;
-    }
-
     for config in test_config.light_hardware_config.into_iter() {
         let light_config: LightHardwareConfiguration =
             read_config::<LightHardwareConfiguration>(&config)?;
diff --git a/src/settings/service/src/tests/environment_tests.rs b/src/settings/service/src/tests/environment_tests.rs
index 218f081..9cfedd3 100644
--- a/src/settings/service/src/tests/environment_tests.rs
+++ b/src/settings/service/src/tests/environment_tests.rs
@@ -149,21 +149,6 @@
 }
 
 #[fuchsia::test(allow_stalls = false)]
-async fn test_display_interface_consolidation() {
-    let Environment { entities, .. } =
-        EnvironmentBuilder::new(Arc::new(InMemoryStorageFactory::new()))
-            .fidl_interfaces(&[
-                fidl::Interface::Display(fidl::display::InterfaceFlags::BASE),
-                fidl::Interface::Display(fidl::display::InterfaceFlags::LIGHT_SENSOR),
-            ])
-            .spawn_nested(ENV_NAME)
-            .await
-            .expect("environment should be built");
-
-    assert!(entities.contains(&Entity::Handler(SettingType::Display)));
-}
-
-#[fuchsia::test(allow_stalls = false)]
 async fn test_job_sourcing() {
     // Create channel to send the current job state.
     let (job_state_tx, mut job_state_rx) = futures::channel::mpsc::unbounded::<channel::State>();
diff --git a/src/settings/service/src/tests/message_tests.rs b/src/settings/service/src/tests/message_tests.rs
index 408d703..649ff66 100644
--- a/src/settings/service/src/tests/message_tests.rs
+++ b/src/settings/service/src/tests/message_tests.rs
@@ -10,6 +10,7 @@
 use futures::future::BoxFuture;
 use futures::lock::Mutex;
 use futures::StreamExt;
+use std::pin::pin;
 use std::sync::Arc;
 use std::task::Poll;
 
@@ -260,7 +261,7 @@
     let mut executor = fuchsia_async::TestExecutor::new_with_fake_time();
     let timeout_ms = 1000;
 
-    let fut = async move {
+    let mut fut = pin!(async move {
         let delegate = test::MessageHub::create();
         let (messenger_client_1, _) =
             delegate.create(MessengerType::Addressable(crate::Address::Test(1))).await.unwrap();
@@ -285,9 +286,8 @@
         .await;
 
         verify_result(Status::Timeout, &mut reply_receptor).await;
-    };
+    });
 
-    pin_utils::pin_mut!(fut);
     loop {
         let new_time = fuchsia_async::Time::from_nanos(
             executor.now().into_nanos()
diff --git a/src/settings/service/src/tests/setting_proxy_tests.rs b/src/settings/service/src/tests/setting_proxy_tests.rs
index 63f26777e..5378c5e 100644
--- a/src/settings/service/src/tests/setting_proxy_tests.rs
+++ b/src/settings/service/src/tests/setting_proxy_tests.rs
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 use std::collections::HashMap;
+use std::pin::pin;
 use std::sync::Arc;
 use std::task::Poll;
 
@@ -1030,7 +1031,7 @@
 fn test_timeout() {
     let mut executor = fuchsia_async::TestExecutor::new_with_fake_time();
 
-    let fut = async move {
+    let mut fut = pin!(async move {
         let setting_type = SettingType::Unknown;
         let environment = TestEnvironmentBuilder::new(setting_type)
             .set_timeout(SETTING_PROXY_TIMEOUT_MS.millis(), true)
@@ -1111,9 +1112,8 @@
                 request.clone(),
             ),
         );
-    };
+    });
 
-    pin_utils::pin_mut!(fut);
     loop {
         let new_time = fuchsia_async::Time::from_nanos(
             executor.now().into_nanos()
@@ -1131,7 +1131,7 @@
 fn test_timeout_no_retry() {
     let mut executor = fuchsia_async::TestExecutor::new_with_fake_time();
 
-    let fut = async move {
+    let mut fut = pin!(async move {
         let setting_type = SettingType::Unknown;
         let environment = TestEnvironmentBuilder::new(setting_type)
             .set_timeout(SETTING_PROXY_TIMEOUT_MS.millis(), false)
@@ -1180,9 +1180,8 @@
                 .0,
             event::handler::Event::Request(event::handler::Action::Timeout, request),
         );
-    };
+    });
 
-    pin_utils::pin_mut!(fut);
     loop {
         let new_time = fuchsia_async::Time::from_nanos(
             executor.now().into_nanos()
diff --git a/src/starnix/kernel/BUILD.gn b/src/starnix/kernel/BUILD.gn
index 75c5d62..f113830 100644
--- a/src/starnix/kernel/BUILD.gn
+++ b/src/starnix/kernel/BUILD.gn
@@ -175,11 +175,10 @@
     "power/suspend_stats.rs",
     "power/sync_on_suspend.rs",
     "power/wakeup_count.rs",
-    "selinux/fs.rs",
-    "selinux/hooks/current_task_hooks.rs",
-    "selinux/hooks/mod.rs",
-    "selinux/hooks/thread_group_hooks.rs",
-    "selinux/mod.rs",
+    "security/fs.rs",
+    "security/hooks.rs",
+    "security/mod.rs",
+    "security/selinux_hooks/mod.rs",
     "signals/mod.rs",
     "signals/signal_handling.rs",
     "signals/signalfd.rs",
@@ -636,7 +635,10 @@
   # Force LTO so that functions are inlined when appropriate even across
   # different compilation units.
   if (!is_debug) {
-    configs = [ "//build/config/lto:thinlto" ]
+    # Add thinlto config if lto variants are not used.
+    if (!is_lto_variant) {
+      configs = [ "//build/config/lto:thinlto" ]
+    }
   }
 
   # Use a custom linker script to ensure only one PT_LOAD header.
diff --git a/src/starnix/kernel/arch/x64/syscalls.rs b/src/starnix/kernel/arch/x64/syscalls.rs
index 052686b..f4e8065 100644
--- a/src/starnix/kernel/arch/x64/syscalls.rs
+++ b/src/starnix/kernel/arch/x64/syscalls.rs
@@ -228,7 +228,7 @@
 }
 
 pub fn sys_getdents(
-    _locked: &mut Locked<'_, Unlocked>,
+    locked: &mut Locked<'_, Unlocked>,
     current_task: &CurrentTask,
     fd: FdNumber,
     user_buffer: UserAddress,
@@ -237,7 +237,7 @@
     let file = current_task.files.get(fd)?;
     let mut offset = file.offset.lock();
     let mut sink = DirentSink32::new(current_task, &mut offset, user_buffer, user_capacity);
-    let result = file.readdir(current_task, &mut sink);
+    let result = file.readdir(locked, current_task, &mut sink);
     sink.map_result_with_actual(result)
 }
 
diff --git a/src/starnix/kernel/bpf/fs.rs b/src/starnix/kernel/bpf/fs.rs
index f2e30ba..2c56d43 100644
--- a/src/starnix/kernel/bpf/fs.rs
+++ b/src/starnix/kernel/bpf/fs.rs
@@ -202,6 +202,7 @@
 
     fn mkdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         name: &FsStr,
@@ -231,6 +232,7 @@
 
     fn create_symlink(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         _node: &FsNode,
         _current_task: &CurrentTask,
         _name: &FsStr,
diff --git a/src/starnix/kernel/device/binder.rs b/src/starnix/kernel/device/binder.rs
index 2153ae4..4188c05 100644
--- a/src/starnix/kernel/device/binder.rs
+++ b/src/starnix/kernel/device/binder.rs
@@ -12,6 +12,7 @@
         MemoryAccessorExt, ProtectionFlags,
     },
     mutable_state::Guard,
+    security,
     task::{
         CurrentTask, EventHandler, Kernel, SchedulerPolicy, SimpleWaiter, Task, WaitCanceler,
         WaitQueue, Waiter,
@@ -36,8 +37,8 @@
     log_error, log_trace, log_warn, trace_duration, track_stub, CATEGORY_STARNIX,
 };
 use starnix_sync::{
-    DeviceOpen, FileOpsCore, InterruptibleEvent, Locked, Mutex, MutexGuard, RwLock, Unlocked,
-    WriteOps,
+    DeviceOpen, FileOpsCore, InterruptibleEvent, LockBefore, Locked, Mutex, MutexGuard,
+    ResourceAccessorAddFile, RwLock, Unlocked, WriteOps,
 };
 use starnix_syscalls::{SyscallArg, SyscallResult, SUCCESS};
 use starnix_uapi::{
@@ -242,7 +243,7 @@
 
     fn ioctl(
         &self,
-        _locked: &mut Locked<'_, Unlocked>,
+        locked: &mut Locked<'_, Unlocked>,
         _file: &FileObject,
         current_task: &CurrentTask,
         request: u32,
@@ -250,7 +251,7 @@
     ) -> Result<SyscallResult, Errno> {
         let binder_process = self.proc(current_task)?;
         release_after!(binder_process, current_task, {
-            self.device.ioctl(current_task, &binder_process, request, arg)
+            self.device.ioctl(locked, current_task, &binder_process, request, arg)
         })
     }
 
@@ -341,6 +342,7 @@
 
     pub fn ioctl(
         &self,
+        locked: &mut Locked<'_, Unlocked>,
         current_task: &CurrentTask,
         request: u32,
         arg: SyscallArg,
@@ -349,7 +351,7 @@
         release_after!(binder_process, current_task, {
             self.binder_connection
                 .device
-                .ioctl(current_task, &binder_process, request, arg)
+                .ioctl(locked, current_task, &binder_process, request, arg)
                 .map(|_| ())
         })
     }
@@ -2763,6 +2765,7 @@
     ) -> Result<(FileHandle, FdFlags), Errno>;
     fn add_file_with_flags(
         &self,
+        locked: &mut Locked<'_, ResourceAccessorAddFile>,
         current_task: &CurrentTask,
         file: FileHandle,
         flags: FdFlags,
@@ -2942,14 +2945,14 @@
 
     fn add_file_with_flags(
         &self,
+        locked: &mut Locked<'_, ResourceAccessorAddFile>,
         current_task: &CurrentTask,
         file: FileHandle,
         _flags: FdFlags,
     ) -> Result<FdNumber, Errno> {
         profile_duration!("RemoteAddFile");
-        let mut locked = Unlocked::new(); // TODO(https://fxbug.dev/333539667): ResourceAllocatorAddFile before FileOpsToHandle
         let flags: fbinder::FileFlags = file.flags().into();
-        let handle = file.to_handle(&mut locked, current_task)?;
+        let handle = file.to_handle(locked, current_task)?;
         let response = self.run_file_request(fbinder::FileRequest {
             add_requests: Some(vec![fbinder::FileHandle { file: handle, flags }]),
             ..Default::default()
@@ -2990,6 +2993,7 @@
     }
     fn add_file_with_flags(
         &self,
+        _locked: &mut Locked<'_, ResourceAccessorAddFile>,
         _current_task: &CurrentTask,
         file: FileHandle,
         flags: FdFlags,
@@ -3024,6 +3028,7 @@
     }
     fn add_file_with_flags(
         &self,
+        _locked: &mut Locked<'_, ResourceAccessorAddFile>,
         _current_task: &CurrentTask,
         file: FileHandle,
         flags: FdFlags,
@@ -3179,6 +3184,7 @@
 
     fn ioctl(
         &self,
+        locked: &mut Locked<'_, Unlocked>,
         current_task: &CurrentTask,
         binder_proc: &BinderProcess,
         request: u32,
@@ -3252,6 +3258,7 @@
                         // commands.
                         while cursor.bytes_read() < input.write_size as usize {
                             self.handle_thread_write(
+                                locked,
                                 current_task,
                                 binder_proc,
                                 &binder_thread,
@@ -3343,13 +3350,17 @@
 
     /// Consumes one command from the userspace binder_write_read buffer and handles it.
     /// This method will never block.
-    fn handle_thread_write(
+    fn handle_thread_write<L>(
         &self,
+        locked: &mut Locked<'_, L>,
         current_task: &CurrentTask,
         binder_proc: &BinderProcess,
         binder_thread: &BinderThread,
         cursor: &mut UserMemoryCursor,
-    ) -> Result<(), Errno> {
+    ) -> Result<(), Errno>
+    where
+        L: LockBefore<ResourceAccessorAddFile>,
+    {
         profile_duration!("ThreadWrite");
         let command = cursor.read_object::<binder_driver_command_protocol>()?;
         let result = match command {
@@ -3410,6 +3421,7 @@
                 profile_duration!("Transaction");
                 let data = cursor.read_object::<binder_transaction_data>()?;
                 self.handle_transaction(
+                    locked,
                     current_task,
                     binder_proc,
                     binder_thread,
@@ -3421,6 +3433,7 @@
                 profile_duration!("Reply");
                 let data = cursor.read_object::<binder_transaction_data>()?;
                 self.handle_reply(
+                    locked,
                     current_task,
                     binder_proc,
                     binder_thread,
@@ -3431,13 +3444,13 @@
             binder_driver_command_protocol_BC_TRANSACTION_SG => {
                 profile_duration!("Transaction");
                 let data = cursor.read_object::<binder_transaction_data_sg>()?;
-                self.handle_transaction(current_task, binder_proc, binder_thread, data)
+                self.handle_transaction(locked, current_task, binder_proc, binder_thread, data)
                     .or_else(|err| err.dispatch(binder_thread))
             }
             binder_driver_command_protocol_BC_REPLY_SG => {
                 profile_duration!("Reply");
                 let data = cursor.read_object::<binder_transaction_data_sg>()?;
-                self.handle_reply(current_task, binder_proc, binder_thread, data)
+                self.handle_reply(locked, current_task, binder_proc, binder_thread, data)
                     .or_else(|err| err.dispatch(binder_thread))
             }
             _ => {
@@ -3456,13 +3469,17 @@
     }
 
     /// A binder thread is starting a transaction on a remote binder object.
-    fn handle_transaction(
+    fn handle_transaction<L>(
         &self,
+        locked: &mut Locked<'_, L>,
         current_task: &CurrentTask,
         binder_proc: &BinderProcess,
         binder_thread: &BinderThread,
         data: binder_transaction_data_sg,
-    ) -> Result<(), TransactionError> {
+    ) -> Result<(), TransactionError>
+    where
+        L: LockBefore<ResourceAccessorAddFile>,
+    {
         // SAFETY: Transactions can only refer to handles.
         let handle = unsafe { data.transaction_data.target.handle }.into();
 
@@ -3488,15 +3505,10 @@
                 let target_task = weak_task.upgrade().ok_or_else(|| TransactionError::Dead)?;
                 let security_context: Option<FsString> =
                     if object.flags.contains(BinderObjectFlags::TXN_SECURITY_CTX) {
-                        let security_server = target_task
-                            .kernel()
-                            .security_server
-                            .as_ref()
-                            .expect("SELinux is not enabled");
-                        let sid = target_task.thread_group.read().selinux_state.current_sid.clone();
-                        let mut security_context = security_server
-                            .sid_to_security_context(sid)
-                            .map_or(FsString::default(), FsString::from);
+                        let mut security_context = FsString::from(
+                            security::get_task_context(&current_task, &target_task)
+                                .unwrap_or_default(),
+                        );
                         security_context.push(b'\0');
                         Some(security_context)
                     } else {
@@ -3505,6 +3517,7 @@
 
                 // Copy the transaction data to the target process.
                 let (buffers, mut transaction_state) = self.copy_transaction_buffers(
+                    locked,
                     current_task,
                     binder_proc.get_resource_accessor(current_task),
                     binder_proc,
@@ -3633,13 +3646,17 @@
     }
 
     /// A binder thread is sending a reply to a transaction.
-    fn handle_reply(
+    fn handle_reply<L>(
         &self,
+        locked: &mut Locked<'_, L>,
         current_task: &CurrentTask,
         binder_proc: &BinderProcess,
         binder_thread: &BinderThread,
         data: binder_transaction_data_sg,
-    ) -> Result<(), TransactionError> {
+    ) -> Result<(), TransactionError>
+    where
+        L: LockBefore<ResourceAccessorAddFile>,
+    {
         // Find the process and thread that initiated the transaction. This reply is for them.
         let (target_proc, target_thread, policy) =
             binder_thread.lock().pop_transaction_caller(current_task)?;
@@ -3649,6 +3666,7 @@
 
             // Copy the transaction data to the target process.
             let (buffers, transaction_state) = self.copy_transaction_buffers(
+                locked,
                 current_task,
                 binder_proc.get_resource_accessor(current_task),
                 binder_proc,
@@ -3833,8 +3851,9 @@
     /// Returns the transaction buffers in the target process, as well as the transaction state.
     ///
     /// If `security_context` is present, it must be null terminated.
-    fn copy_transaction_buffers<'a>(
+    fn copy_transaction_buffers<'a, L>(
         &self,
+        locked: &mut Locked<'_, L>,
         current_task: &CurrentTask,
         source_resource_accessor: &dyn ResourceAccessor,
         source_proc: &BinderProcess,
@@ -3843,8 +3862,12 @@
         target_proc: &BinderProcess,
         data: &binder_transaction_data_sg,
         security_context: Option<&FsStr>,
-    ) -> Result<(TransactionBuffers, TransientTransactionState<'a>), TransactionError> {
+    ) -> Result<(TransactionBuffers, TransientTransactionState<'a>), TransactionError>
+    where
+        L: LockBefore<ResourceAccessorAddFile>,
+    {
         profile_duration!("CopyTransactionBuffers");
+
         // Get the shared memory of the target process.
         let mut shared_memory_lock = target_proc.shared_memory.lock();
         let shared_memory = shared_memory_lock.as_mut().ok_or_else(|| errno!(ENOMEM))?;
@@ -3883,6 +3906,7 @@
         // Translate any handles/fds from the source process' handle table to the target process'
         // handle table.
         let transient_transaction_state = self.translate_objects(
+            locked,
             current_task,
             source_resource_accessor,
             source_proc,
@@ -3914,8 +3938,9 @@
     /// handle table for which temporary strong references were acquired, along with duped FDs. This
     /// object takes care of releasing these resources when dropped, due to an error or a
     /// `BC_FREE_BUFFER` command.
-    fn translate_objects<'a>(
+    fn translate_objects<'a, L>(
         &self,
+        locked: &mut Locked<'_, L>,
         current_task: &CurrentTask,
         source_resource_accessor: &dyn ResourceAccessor,
         source_proc: &BinderProcess,
@@ -3925,8 +3950,12 @@
         offsets: &[binder_uintptr_t],
         transaction_data: &mut [u8],
         sg_buffer: &mut SharedBuffer<'_, u8>,
-    ) -> Result<TransientTransactionState<'a>, TransactionError> {
+    ) -> Result<TransientTransactionState<'a>, TransactionError>
+    where
+        L: LockBefore<ResourceAccessorAddFile>,
+    {
         profile_duration!("TranslateObjects");
+
         let mut transaction_state =
             TransientTransactionState::new(target_resource_accessor, target_proc);
         release_on_error!(transaction_state, current_task, {
@@ -4012,7 +4041,9 @@
                     SerializedBinderObject::File { fd, flags, cookie } => {
                         let (file, fd_flags) =
                             source_resource_accessor.get_file_with_flags(current_task, fd)?;
+                        let mut locked = locked.cast_locked::<ResourceAccessorAddFile>();
                         let new_fd = target_resource_accessor.add_file_with_flags(
+                            &mut locked,
                             current_task,
                             file,
                             fd_flags,
@@ -4128,7 +4159,9 @@
                                 current_task,
                                 FdNumber::from_raw(*fd as i32),
                             )?;
+                            let mut locked = locked.cast_locked::<ResourceAccessorAddFile>();
                             let new_fd = target_resource_accessor.add_file_with_flags(
+                                &mut locked,
                                 current_task,
                                 file,
                                 flags,
@@ -4568,7 +4601,6 @@
     use fuchsia_async::LocalExecutor;
     use futures::TryStreamExt;
     use memoffset::offset_of;
-    use starnix_sync::LockBefore;
     use starnix_uapi::{
         binder_transaction_data__bindgen_ty_1, binder_transaction_data__bindgen_ty_2,
         errors::{EBADF, EINVAL},
@@ -4594,11 +4626,12 @@
         }
         fn add_file_with_flags(
             &self,
+            locked: &mut Locked<'_, ResourceAccessorAddFile>,
             current_task: &CurrentTask,
             file: FileHandle,
             flags: FdFlags,
         ) -> Result<FdNumber, Errno> {
-            self.deref().add_file_with_flags(current_task, file, flags)
+            self.deref().add_file_with_flags(locked, current_task, file, flags)
         }
         fn kernel(&self) -> &Arc<Kernel> {
             &self.deref().kernel()
@@ -5668,6 +5701,7 @@
         let (buffers, transaction_state) = test
             .device
             .copy_transaction_buffers(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -5738,6 +5772,7 @@
         let transaction_state = test
             .device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -5829,6 +5864,7 @@
 
         test.device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -5909,6 +5945,7 @@
         let transaction_state = test
             .device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -6027,6 +6064,7 @@
         let transaction_state = test
             .device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -6171,6 +6209,7 @@
         let (buffers, transaction_state) = test
             .device
             .copy_transaction_buffers(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -6275,6 +6314,7 @@
         // Perform the translation and copying.
         test.device
             .copy_transaction_buffers(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -6356,6 +6396,7 @@
         // Perform the translation and copying.
         test.device
             .copy_transaction_buffers(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -6479,7 +6520,7 @@
 
         // Perform the translation and copying.
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, input)
+            .handle_transaction(&mut locked, &sender.task, &sender.proc, &sender.thread, input)
             .expect("transaction queued");
 
         // Get the data buffer out of the receiver's queue.
@@ -6672,7 +6713,7 @@
 
             // Perform the translation and copying.
             test.device
-                .handle_transaction(&sender.task, &sender.proc, &sender.thread, input)
+                .handle_transaction(&mut locked, &sender.task, &sender.proc, &sender.thread, input)
                 .expect("transaction queued");
 
             // Clean up without calling BC_FREE_BUFFER. Should not panic.
@@ -6794,6 +6835,7 @@
         let (_, transient_state) = test
             .device
             .copy_transaction_buffers(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -6836,6 +6878,7 @@
         let transaction_ref_error = test
             .device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -6871,6 +6914,7 @@
         let transaction_ref_error = test
             .device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -6916,6 +6960,7 @@
 
         test.device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -7289,6 +7334,7 @@
         let transient_transaction_state = test
             .device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -7365,6 +7411,7 @@
         let transaction_state = test
             .device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -7416,6 +7463,7 @@
         let transaction_state = test
             .device
             .translate_objects(
+                &mut locked,
                 &sender.task,
                 &sender.task,
                 &sender.proc,
@@ -7507,7 +7555,13 @@
 
         // Submit the transaction.
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("failed to handle the transaction");
 
         // The thread is ineligible to take the command (not sleeping) so check the process queue.
@@ -7535,7 +7589,13 @@
             buffers_size: 0,
         };
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("transaction queued");
 
         // There should now be an entry in the queue.
@@ -7631,10 +7691,22 @@
 
         // Submit the transaction twice so that the queue is populated.
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("failed to handle the transaction");
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("failed to handle the transaction");
 
         // The thread is ineligible to take the command (not sleeping) so check (and dequeue)
@@ -7666,7 +7738,13 @@
             buffers_size: 0,
         };
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("sync transaction queued");
 
         assert_eq!(
@@ -7713,7 +7791,13 @@
 
         // Submit the transaction.
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("failed to handle the transaction");
 
         // Check that there are no commands waiting for the sending thread.
@@ -7764,7 +7848,13 @@
 
         // Submit the transaction.
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("failed to handle the transaction");
 
         // Check that there are no commands waiting for the sending thread.
@@ -7824,7 +7914,13 @@
 
         // Submit the transaction.
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("failed to handle the transaction");
 
         // Check that there are no commands waiting for the sending thread.
@@ -7899,7 +7995,13 @@
 
         // Submit the transaction.
         test.device
-            .handle_transaction(&sender.task, &sender.proc, &sender.thread, transaction)
+            .handle_transaction(
+                &mut locked,
+                &sender.task,
+                &sender.proc,
+                &sender.thread,
+                transaction,
+            )
             .expect("failed to handle the transaction");
 
         // Check that there are no commands waiting for the sending thread.
@@ -7938,7 +8040,7 @@
         // Submit the reply.
         assert_eq!(
             test.device
-                .handle_reply(&receiver.task, &receiver.proc, &receiver.thread, reply)
+                .handle_reply(&mut locked, &receiver.task, &receiver.proc, &receiver.thread, reply)
                 .expect_err("transaction should have failed"),
             TransactionError::Failure
         );
@@ -8041,7 +8143,7 @@
             process_accessor_client_end.into_channel(),
         );
 
-        let (kernel, task) = create_kernel_and_task();
+        let (kernel, task, mut locked) = create_kernel_task_and_unlocked();
         let process =
             fuchsia_runtime::process_self().duplicate(zx::Rights::SAME_RIGHTS).expect("process");
         let remote_binder_task =
@@ -8063,16 +8165,32 @@
         assert_eq!(vector[1], 1);
         assert_eq!(vector, other_vector);
 
+        let mut locked = locked.cast_locked::<ResourceAccessorAddFile>();
         let fd0 = remote_binder_task
-            .add_file_with_flags(&task, new_null_file(&task, OpenFlags::RDWR), FdFlags::empty())
+            .add_file_with_flags(
+                &mut locked,
+                &task,
+                new_null_file(&task, OpenFlags::RDWR),
+                FdFlags::empty(),
+            )
             .expect("add_file_with_flags");
         assert_eq!(fd0.raw(), 0);
         let fd1 = remote_binder_task
-            .add_file_with_flags(&task, new_null_file(&task, OpenFlags::WRONLY), FdFlags::empty())
+            .add_file_with_flags(
+                &mut locked,
+                &task,
+                new_null_file(&task, OpenFlags::WRONLY),
+                FdFlags::empty(),
+            )
             .expect("add_file_with_flags");
         assert_eq!(fd1.raw(), 1);
         let fd2 = remote_binder_task
-            .add_file_with_flags(&task, new_null_file(&task, OpenFlags::RDONLY), FdFlags::empty())
+            .add_file_with_flags(
+                &mut locked,
+                &task,
+                new_null_file(&task, OpenFlags::RDONLY),
+                FdFlags::empty(),
+            )
             .expect("add_file_with_flags");
         assert_eq!(fd2.raw(), 2);
 
diff --git a/src/starnix/kernel/device/remote_binder.rs b/src/starnix/kernel/device/remote_binder.rs
index 8bbd2bd..69f4401 100644
--- a/src/starnix/kernel/device/remote_binder.rs
+++ b/src/starnix/kernel/device/remote_binder.rs
@@ -124,13 +124,13 @@
 
     fn ioctl(
         &self,
-        _locked: &mut Locked<'_, Unlocked>,
+        locked: &mut Locked<'_, Unlocked>,
         _file: &FileObject,
         current_task: &CurrentTask,
         request: u32,
         arg: SyscallArg,
     ) -> Result<SyscallResult, Errno> {
-        self.0.ioctl(current_task, request, arg)
+        self.0.ioctl(locked, current_task, request, arg)
     }
 
     fn get_vmo(
@@ -477,6 +477,7 @@
 
     fn ioctl(
         self: &Arc<Self>,
+        locked: &mut Locked<'_, Unlocked>,
         current_task: &CurrentTask,
         request: u32,
         arg: SyscallArg,
@@ -484,7 +485,7 @@
         let user_addr = UserAddress::from(arg);
         match request {
             uapi::REMOTE_BINDER_START => self.start(current_task, user_addr.into())?,
-            uapi::REMOTE_BINDER_WAIT => self.wait(current_task, user_addr.into())?,
+            uapi::REMOTE_BINDER_WAIT => self.wait(locked, current_task, user_addr.into())?,
             _ => return error!(ENOTSUP),
         }
         Ok(SUCCESS)
@@ -964,6 +965,7 @@
     /// Implementation of the REMOTE_BINDER_WAIT ioctl.
     fn wait(
         &self,
+        locked: &mut Locked<'_, Unlocked>,
         current_task: &CurrentTask,
         wait_command_ref: UserRef<uapi::remote_binder_wait_command>,
     ) -> Result<(), Errno> {
@@ -1000,8 +1002,12 @@
                 } => {
                     trace_duration!(CATEGORY_STARNIX, NAME_REMOTE_BINDER_IOCTL_WORKER_PROCESS);
                     trace_flow_step!(CATEGORY_STARNIX, NAME_REMOTE_BINDER_IOCTL, koid.into());
-                    let result =
-                        remote_binder_connection.ioctl(current_task, request, parameter.into());
+                    let result = remote_binder_connection.ioctl(
+                        locked,
+                        current_task,
+                        request,
+                        parameter.into(),
+                    );
                     // Once the potentially blocking calls is made, the task is ready to handle the
                     // next request.
                     self.lock()
@@ -1147,6 +1153,7 @@
                 );
 
                 let start_result = remote_binder_handle.ioctl(
+                    locked,
                     &task,
                     uapi::REMOTE_BINDER_START,
                     start_command_address.into(),
@@ -1156,6 +1163,7 @@
                 }
                 loop {
                     let result = remote_binder_handle.ioctl(
+                        locked,
                         &task,
                         uapi::REMOTE_BINDER_WAIT,
                         wait_command_address.into(),
diff --git a/src/starnix/kernel/fs/devtmpfs.rs b/src/starnix/kernel/fs/devtmpfs.rs
index 0969ad9..214cda0 100644
--- a/src/starnix/kernel/fs/devtmpfs.rs
+++ b/src/starnix/kernel/fs/devtmpfs.rs
@@ -47,7 +47,7 @@
     };
 
     mkdir(locked, "shm".into());
-    create_symlink(current_task, root, "fd".into(), "/proc/self/fd".into()).unwrap();
+    create_symlink(locked, current_task, root, "fd".into(), "/proc/self/fd".into()).unwrap();
     fs
 }
 
@@ -187,18 +187,23 @@
 where
     L: LockBefore<FileOpsCore>,
 {
-    create_symlink(current_task, dev_tmp_fs(locked, current_task).root(), name, target)
+    let root = dev_tmp_fs(locked, current_task).root();
+    create_symlink(locked, current_task, root, name, target)
 }
 
-fn create_symlink(
+fn create_symlink<L>(
+    locked: &mut Locked<'_, L>,
     current_task: &CurrentTask,
     entry: &DirEntryHandle,
     name: &FsStr,
     target: &FsStr,
-) -> Result<DirEntryHandle, Errno> {
+) -> Result<DirEntryHandle, Errno>
+where
+    L: LockBefore<FileOpsCore>,
+{
     // This creates content inside the temporary FS. This doesn't depend on the mount
     // information.
     entry.create_entry(current_task, &MountInfo::detached(), name, |dir, mount, name| {
-        dir.create_symlink(current_task, mount, name, target, FsCred::root())
+        dir.create_symlink(locked, current_task, mount, name, target, FsCred::root())
     })
 }
diff --git a/src/starnix/kernel/fs/ext4/mod.rs b/src/starnix/kernel/fs/ext4/mod.rs
index 68fd59f..85973c3 100644
--- a/src/starnix/kernel/fs/ext4/mod.rs
+++ b/src/starnix/kernel/fs/ext4/mod.rs
@@ -308,6 +308,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         _current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
diff --git a/src/starnix/kernel/fs/fuchsia/remote.rs b/src/starnix/kernel/fs/fuchsia/remote.rs
index a6d1551..996824e 100644
--- a/src/starnix/kernel/fs/fuchsia/remote.rs
+++ b/src/starnix/kernel/fs/fuchsia/remote.rs
@@ -500,6 +500,7 @@
 
     fn mkdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         name: &FsStr,
@@ -719,7 +720,7 @@
         match mode {
             FallocMode::Allocate { keep_size: false } => {
                 let allocate_size = offset.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
-                let info = node.refresh_info(current_task)?;
+                let info = node.fetch_and_refresh_info(current_task)?;
                 if (info.size as u64) < allocate_size {
                     let mut locked = locked.cast_locked::<FileOpsCore>();
                     self.truncate(&mut locked, node, current_task, allocate_size)?;
@@ -730,7 +731,7 @@
         }
     }
 
-    fn refresh_info<'a>(
+    fn fetch_and_refresh_info<'a>(
         &self,
         node: &FsNode,
         _current_task: &CurrentTask,
@@ -802,6 +803,7 @@
 
     fn create_symlink(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         name: &FsStr,
@@ -1315,6 +1317,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         _current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
@@ -1810,7 +1813,7 @@
         let fixture = TestFixture::new().await;
 
         {
-            let (kernel, current_task) = create_kernel_and_task();
+            let (kernel, current_task, mut locked) = create_kernel_task_and_unlocked();
             let (server, client) = zx::Channel::create();
             fixture
                 .root()
@@ -1826,7 +1829,7 @@
             .expect("new_fs failed");
             let ns = Namespace::new(fs);
             let root = ns.root();
-            root.create_symlink(&current_task, "symlink".into(), "target".into())
+            root.create_symlink(&mut locked, &current_task, "symlink".into(), "target".into())
                 .expect("symlink failed");
 
             let mut context = LookupContext::new(SymlinkMode::NoFollow);
@@ -2052,7 +2055,7 @@
                         }
                     }
                     let mut sink = Sink::default();
-                    dir_handle.readdir(&current_task, &mut sink).expect("readdir failed");
+                    dir_handle.readdir(locked, &current_task, &mut sink).expect("readdir failed");
 
                     // inode_num for .. for the root should be the same as root.
                     assert_eq!(sink.dot_dot_inode_num, ns.root().entry.node.node_id);
@@ -2062,7 +2065,7 @@
                         .open_anonymous(locked, &current_task, OpenFlags::RDONLY)
                         .expect("open failed");
                     let mut sink = Sink::default();
-                    dir_handle.readdir(&current_task, &mut sink).expect("readdir failed");
+                    dir_handle.readdir(locked, &current_task, &mut sink).expect("readdir failed");
 
                     // inode_num for .. for the first sub directory should be the same as root.
                     assert_eq!(sink.dot_dot_inode_num, ns.root().entry.node.node_id);
@@ -2072,7 +2075,7 @@
                         .open_anonymous(locked, &current_task, OpenFlags::RDONLY)
                         .expect("open failed");
                     let mut sink = Sink::default();
-                    dir_handle.readdir(&current_task, &mut sink).expect("readdir failed");
+                    dir_handle.readdir(locked, &current_task, &mut sink).expect("readdir failed");
 
                     // inode_num for .. for the second sub directory should be the first sub directory.
                     assert_eq!(sink.dot_dot_inode_num, sub_dir1.entry.node.node_id);
@@ -2651,13 +2654,13 @@
                     let file = child
                         .open(locked, &current_task, OpenFlags::RDWR, true)
                         .expect("open failed");
-                    // Call `refresh_info(..)` to refresh `time_modify` with the time managed by the
+                    // Call `fetch_and_refresh_info(..)` to refresh `time_modify` with the time managed by the
                     // underlying filesystem
                     let time_before_write = child
                         .entry
                         .node
-                        .refresh_info(&current_task)
-                        .expect("refresh info failed")
+                        .fetch_and_refresh_info(&current_task)
+                        .expect("fetch_and_refresh_info failed")
                         .time_modify;
                     let write_bytes: [u8; 5] = [1, 2, 3, 4, 5];
                     let written = file
@@ -2667,8 +2670,8 @@
                     let last_modified = child
                         .entry
                         .node
-                        .refresh_info(&current_task)
-                        .expect("refresh info failed")
+                        .fetch_and_refresh_info(&current_task)
+                        .expect("fetch_and_refresh_info failed")
                         .time_modify;
                     assert!(last_modified > time_before_write);
                     last_modified
@@ -2718,8 +2721,8 @@
                     let last_modified = child
                         .entry
                         .node
-                        .refresh_info(&current_task)
-                        .expect("refresh info failed")
+                        .fetch_and_refresh_info(&current_task)
+                        .expect("fetch_and_refresh_info failed")
                         .time_modify;
                     last_modified
                 }
@@ -2767,8 +2770,8 @@
                     let info_original = child
                         .entry
                         .node
-                        .refresh_info(&current_task)
-                        .expect("refresh_info failed")
+                        .fetch_and_refresh_info(&current_task)
+                        .expect("fetch_and_refresh_info failed")
                         .clone();
 
                     child
@@ -2784,8 +2787,8 @@
                     let info_after_update = child
                         .entry
                         .node
-                        .refresh_info(&current_task)
-                        .expect("refresh info failed")
+                        .fetch_and_refresh_info(&current_task)
+                        .expect("fetch_and_refresh_info failed")
                         .clone();
                     assert_eq!(info_after_update.time_modify, info_original.time_modify);
                     assert_eq!(info_after_update.time_access, zx::Time::from_nanos(30));
@@ -2803,8 +2806,8 @@
                     let info_after_update2 = child
                         .entry
                         .node
-                        .refresh_info(&current_task)
-                        .expect("refresh_info failed")
+                        .fetch_and_refresh_info(&current_task)
+                        .expect("fetch_and_refresh_info failed")
                         .clone();
                     assert_eq!(info_after_update2.time_modify, zx::Time::from_nanos(50));
                     assert_eq!(info_after_update2.time_access, zx::Time::from_nanos(30));
@@ -2850,14 +2853,14 @@
                     let file = child
                         .open(locked, &current_task, OpenFlags::RDWR, true)
                         .expect("open failed");
-                    // Call `refresh_info(..)` to refresh ctime and mtime with the time managed by the
+                    // Call `fetch_and_refresh_info(..)` to refresh ctime and mtime with the time managed by the
                     // underlying filesystem
                     let (ctime_before_write, mtime_before_write) = {
                         let info = child
                             .entry
                             .node
-                            .refresh_info(&current_task)
-                            .expect("refresh info failed");
+                            .fetch_and_refresh_info(&current_task)
+                            .expect("fetch_and_refresh_info failed");
                         (info.time_status_change, info.time_modify)
                     };
 
@@ -2885,8 +2888,8 @@
                         let info = child
                             .entry
                             .node
-                            .refresh_info(&current_task)
-                            .expect("refresh info failed");
+                            .fetch_and_refresh_info(&current_task)
+                            .expect("fetch_and_refresh_info failed");
                         (info.time_status_change, info.time_modify)
                     };
                     assert_eq!(ctime_after_write_refresh, mtime_after_write_refresh);
diff --git a/src/starnix/kernel/fs/fuchsia/remote_bundle.rs b/src/starnix/kernel/fs/fuchsia/remote_bundle.rs
index 86f2e95..02f83c9 100644
--- a/src/starnix/kernel/fs/fuchsia/remote_bundle.rs
+++ b/src/starnix/kernel/fs/fuchsia/remote_bundle.rs
@@ -187,7 +187,7 @@
         Ok(Box::new(VmoFile { vmo, size }))
     }
 
-    fn refresh_info<'a>(
+    fn fetch_and_refresh_info<'a>(
         &self,
         _node: &FsNode,
         _current_task: &CurrentTask,
@@ -358,6 +358,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         _current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
@@ -632,7 +633,7 @@
         }
 
         let mut sink = Sink { offset: 0, entries: HashMap::new() };
-        opened_dir.readdir(&current_task, &mut sink).expect("readdir failed");
+        opened_dir.readdir(&mut locked, &current_task, &mut sink).expect("readdir failed");
 
         assert_eq!(
             sink.entries,
diff --git a/src/starnix/kernel/fs/functionfs.rs b/src/starnix/kernel/fs/functionfs.rs
index b71f468..fc6ca19 100644
--- a/src/starnix/kernel/fs/functionfs.rs
+++ b/src/starnix/kernel/fs/functionfs.rs
@@ -127,6 +127,10 @@
     // FunctionFs events that indicate the connection state, to be read through
     // the control endpoint.
     event_queue: VecDeque<usb_functionfs_event>,
+
+    // Whether FunctionFS has received the initial ADB header from the host.
+    // Used to reject unexpected payloads when an ADB header has not been read.
+    has_received_initial_adb_header: bool,
 }
 
 fn connect_to_device() -> Result<(fadb::DeviceSynchronousProxy, AdbHandle), Errno> {
@@ -197,6 +201,7 @@
             state.has_input_output_endpoints = false;
             state.adb_proxy = None;
             state.event_queue.clear();
+            state.has_received_initial_adb_header = false;
 
             let _ = state
                 .device_proxy
@@ -219,6 +224,33 @@
         }
         error!(ENODEV)
     }
+
+    // Hack for ADB: Discard ADB messages until the first ADB header is read.
+    // Returns false if an unexpected payload is received before the first ADB header.
+    //
+    // ADB daemon expects a 24-byte header message followed by 0 or more payload messages, and restarts
+    // if it reads an unexpected message. This resets FunctionFS, and causes ADB host to resend a connect
+    // request. The header of this request is likely to be missed again by FunctionFS as it comes back up,
+    // resulting in ADB daemon crash looping. See https://fxbug.dev/330386381 for details.
+    //
+    // This hack assumes that reads are not performed concurrently. While this is true for ADB daemon,
+    // where reads arrive from a read queue, there's nothing that guarantees this for other users.
+    fn should_forward_adb_message_to_daemon(&self, bytes: &[u8]) -> bool {
+        const ADB_HEADER_LEN: usize = 24;
+        let mut state = self.state.lock();
+
+        if state.has_received_initial_adb_header {
+            return true;
+        }
+
+        if bytes.len() == ADB_HEADER_LEN {
+            state.has_received_initial_adb_header = true;
+            true
+        } else {
+            log_warn!("Expected ADB header, instead got message of size {}", bytes.len());
+            false
+        }
+    }
 }
 
 impl FsNodeOps for FunctionFsRootDir {
@@ -516,7 +548,26 @@
                     // Instead of attempting this, we'll instead return error to the client.
                     return error!(EINVAL);
                 }
-                Ok(data.write(&payload).unwrap())
+
+                // Hack for ADB. See comment for `should_forward_adb_message_to_daemon`.
+                if rootdir.should_forward_adb_message_to_daemon(&payload) {
+                    data.write(&payload)
+                } else {
+                    log_warn!("Sending a reset message back to ADB host to force a retry.");
+
+                    // Arbitrary non-empty and non-zero message that does not look like a real ADB message.
+                    let garbage = [12, 23, 34, 45, 56, 67];
+                    match adb.queue_tx(&garbage, zx::Time::INFINITE) {
+                        Err(err) => {
+                            log_warn!("Failed to call UsbAdbImpl.QueueTx: {err}");
+                        }
+                        Ok(Err(err)) => {
+                            log_warn!("Failed to queue garbage message to adb driver: {err}");
+                        }
+                        Ok(Ok(_)) => {}
+                    }
+                    Ok(0)
+                }
             }
         }
     }
diff --git a/src/starnix/kernel/fs/layeredfs.rs b/src/starnix/kernel/fs/layeredfs.rs
index b38a4c7..60d9bfb 100644
--- a/src/starnix/kernel/fs/layeredfs.rs
+++ b/src/starnix/kernel/fs/layeredfs.rs
@@ -108,6 +108,7 @@
 
     fn readdir(
         &self,
+        locked: &mut Locked<'_, FileOpsCore>,
         _file: &FileObject,
         current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
@@ -155,7 +156,7 @@
         let mut wrapper =
             DirentSinkWrapper { sink, mappings: &self.fs.mappings, offset: &mut root_file_offset };
 
-        self.root_file.readdir(current_task, &mut wrapper)
+        self.root_file.readdir(locked, current_task, &mut wrapper)
     }
 }
 
@@ -194,7 +195,7 @@
         fs.root()
             .open_anonymous(locked, current_task, OpenFlags::RDONLY)
             .expect("open")
-            .readdir(current_task, &mut sink)
+            .readdir(locked, current_task, &mut sink)
             .expect("readdir");
         std::mem::take(&mut sink.names)
     }
diff --git a/src/starnix/kernel/fs/overlayfs.rs b/src/starnix/kernel/fs/overlayfs.rs
index e78b7ca..ee50a09 100644
--- a/src/starnix/kernel/fs/overlayfs.rs
+++ b/src/starnix/kernel/fs/overlayfs.rs
@@ -202,9 +202,11 @@
         L: LockEqualOrBefore<FileOpsCore>,
     {
         let mut sink = DirentSinkAdapter::default();
-        self.entry()
-            .open_anonymous(locked, current_task, OpenFlags::DIRECTORY)?
-            .readdir(current_task, &mut sink)?;
+        self.entry().open_anonymous(locked, current_task, OpenFlags::DIRECTORY)?.readdir(
+            locked,
+            current_task,
+            &mut sink,
+        )?;
         Ok(sink.items)
     }
 }
@@ -316,7 +318,14 @@
                     SymlinkTarget::Path(path) => path,
                 };
                 parent_upper.create_entry(current_task, name.as_ref(), |dir, mount, name| {
-                    dir.create_symlink(current_task, mount, name, link_path.as_ref(), info.cred())
+                    dir.create_symlink(
+                        locked,
+                        current_task,
+                        mount,
+                        name,
+                        link_path.as_ref(),
+                        info.cred(),
+                    )
                 })
             } else if info.mode.is_reg() && copy_mode == UpperCopyMode::CopyAll {
                 // Regular files need to be copied from lower FS to upper FS.
@@ -587,15 +596,15 @@
 
     fn mkdir(
         &self,
+        locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         name: &FsStr,
         mode: FileMode,
         owner: FsCred,
     ) -> Result<FsNodeHandle, Errno> {
-        let mut locked = Unlocked::new(); // TODO(https://fxbug.dev/320460258): Propagate Locked through FsNodeOps
         let new_upper_node =
-            self.create_entry(&mut locked, current_task, name, |locked, dir, temp_name| {
+            self.create_entry(locked, current_task, name, |locked, dir, temp_name| {
                 let entry =
                     dir.create_entry(current_task, temp_name, |dir_node, mount, name| {
                         dir_node.mknod(
@@ -620,17 +629,24 @@
 
     fn create_symlink(
         &self,
+        locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         name: &FsStr,
         target: &FsStr,
         owner: FsCred,
     ) -> Result<FsNodeHandle, Errno> {
-        let mut locked = Unlocked::new(); // TODO(https://fxbug.dev/320460258): Propagate Locked through FsNodeOps
         let new_upper_node =
-            self.create_entry(&mut locked, current_task, name, |_, dir, temp_name| {
+            self.create_entry(locked, current_task, name, |locked, dir, temp_name| {
                 dir.create_entry(current_task, temp_name, |dir_node, mount, name| {
-                    dir_node.create_symlink(current_task, mount, name, target, owner.clone())
+                    dir_node.create_symlink(
+                        locked,
+                        current_task,
+                        mount,
+                        name,
+                        target,
+                        owner.clone(),
+                    )
                 })
             })?;
         Ok(self.init_fs_node_for_child(current_task, node, None, Some(new_upper_node)))
@@ -692,14 +708,14 @@
         Ok(())
     }
 
-    fn refresh_info<'a>(
+    fn fetch_and_refresh_info<'a>(
         &self,
         _node: &FsNode,
         current_task: &CurrentTask,
         info: &'a RwLock<FsNodeInfo>,
     ) -> Result<RwLockReadGuard<'a, FsNodeInfo>, Errno> {
         let mut lock = info.write();
-        *lock = self.main_entry().entry().node.refresh_info(current_task)?.clone();
+        *lock = self.main_entry().entry().node.fetch_and_refresh_info(current_task)?.clone();
         Ok(RwLockWriteGuard::downgrade(lock))
     }
 
@@ -744,7 +760,7 @@
         current_task: &CurrentTask,
     ) -> Result<(), Errno>
     where
-        L: LockBefore<FileOpsCore>,
+        L: LockEqualOrBefore<FileOpsCore>,
     {
         let mut entries = DirEntries::new();
 
@@ -799,13 +815,13 @@
 
     fn readdir(
         &self,
+        locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
     ) -> Result<(), Errno> {
-        let mut locked = Unlocked::new(); // TODO(https://fxbug.dev/314138012): FileOpsReaddir before FileOpsCore
         if sink.offset() == 0 {
-            self.refresh_dir_entries(&mut locked, current_task)?;
+            self.refresh_dir_entries(locked, current_task)?;
         }
 
         emit_dotdot(file, sink)?;
diff --git a/src/starnix/kernel/fs/proc/pid_directory.rs b/src/starnix/kernel/fs/proc/pid_directory.rs
index a6f0fb1..d534c90 100644
--- a/src/starnix/kernel/fs/proc/pid_directory.rs
+++ b/src/starnix/kernel/fs/proc/pid_directory.rs
@@ -4,7 +4,7 @@
 
 use crate::{
     mm::{MemoryAccessor, MemoryAccessorExt, ProcMapsFile, ProcSmapsFile, PAGE_SIZE},
-    selinux::fs::selinux_proc_attrs,
+    security::fs::selinux_proc_attrs,
     task::{CurrentTask, Task, TaskPersistentInfo, TaskStateCode, ThreadGroup},
     vfs::{
         buffers::{InputBuffer, OutputBuffer},
@@ -139,11 +139,12 @@
 
     fn readdir(
         &self,
+        locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
     ) -> Result<(), Errno> {
-        self.file_ops.readdir(file, current_task, sink)
+        self.file_ops.readdir(locked, file, current_task, sink)
     }
 
     fn as_pid(&self, _file: &FileObject) -> Result<pid_t, Errno> {
@@ -275,6 +276,7 @@
         // owned by the effective user and effective group ID of the process."
         dir.entry_creds(task.creds().euid_as_fscred());
         dir.dir_creds(task.creds().euid_as_fscred());
+        // TODO(b/322850635): Add get/set_procattr hooks and move procattr impl here.
         selinux_proc_attrs(current_task, task, dir);
     });
     dir.entry(current_task, "ns", NsDirectory { task: task.into() }, mode!(IFDIR, 0o777));
diff --git a/src/starnix/kernel/fs/proc/proc_directory.rs b/src/starnix/kernel/fs/proc/proc_directory.rs
index 748855a..5695258 100644
--- a/src/starnix/kernel/fs/proc/proc_directory.rs
+++ b/src/starnix/kernel/fs/proc/proc_directory.rs
@@ -293,6 +293,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
diff --git a/src/starnix/kernel/fs/proc/sysrq.rs b/src/starnix/kernel/fs/proc/sysrq.rs
index cbadcc5..28ac27c 100644
--- a/src/starnix/kernel/fs/proc/sysrq.rs
+++ b/src/starnix/kernel/fs/proc/sysrq.rs
@@ -55,6 +55,7 @@
 
     fn mkdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         _node: &FsNode,
         _current_task: &CurrentTask,
         _name: &FsStr,
@@ -66,6 +67,7 @@
 
     fn create_symlink(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         _node: &FsNode,
         _current_task: &CurrentTask,
         _name: &FsStr,
diff --git a/src/starnix/kernel/fs/sysfs/cgroup.rs b/src/starnix/kernel/fs/sysfs/cgroup.rs
index 50ca3e8..41aad92 100644
--- a/src/starnix/kernel/fs/sysfs/cgroup.rs
+++ b/src/starnix/kernel/fs/sysfs/cgroup.rs
@@ -62,6 +62,7 @@
 
     fn mkdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         _name: &FsStr,
@@ -117,6 +118,7 @@
 
     fn create_symlink(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         _node: &FsNode,
         _current_task: &CurrentTask,
         _name: &FsStr,
diff --git a/src/starnix/kernel/fs/tmpfs.rs b/src/starnix/kernel/fs/tmpfs.rs
index 6ab4d75..e3f8e54 100644
--- a/src/starnix/kernel/fs/tmpfs.rs
+++ b/src/starnix/kernel/fs/tmpfs.rs
@@ -230,6 +230,7 @@
 
     fn mkdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         _name: &FsStr,
@@ -264,6 +265,7 @@
 
     fn create_symlink(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         _name: &FsStr,
diff --git a/src/starnix/kernel/lib.rs b/src/starnix/kernel/lib.rs
index bb328a8..5446dace 100644
--- a/src/starnix/kernel/lib.rs
+++ b/src/starnix/kernel/lib.rs
@@ -15,7 +15,7 @@
 pub mod mm;
 pub mod mutable_state;
 pub mod power;
-pub mod selinux;
+pub mod security;
 pub mod signals;
 pub mod syscalls;
 pub mod task;
diff --git a/src/starnix/kernel/loader.rs b/src/starnix/kernel/loader.rs
index 7965427..b143bfe2 100644
--- a/src/starnix/kernel/loader.rs
+++ b/src/starnix/kernel/loader.rs
@@ -7,7 +7,7 @@
         vmo::round_up_to_system_page_size, DesiredAddress, MappingName, MappingOptions,
         MemoryAccessor, MemoryManager, ProtectionFlags, PAGE_SIZE, VMEX_RESOURCE,
     },
-    selinux::hooks::thread_group_hooks::SeLinuxResolvedElfState,
+    security,
     task::CurrentTask,
     vfs::{FileHandle, FileWriteGuardMode, FileWriteGuardRef},
 };
@@ -249,7 +249,7 @@
     /// The environment to initialize for the new process.
     pub environ: Vec<CString>,
     /// The SELinux state for the new process. None if SELinux is disabled.
-    pub selinux_state: Option<SeLinuxResolvedElfState>,
+    pub security_state: Option<security::ResolvedElfState>,
     /// Exec/write lock.
     pub file_write_guard: FileWriteGuardRef,
 }
@@ -278,13 +278,13 @@
     path: CString,
     argv: Vec<CString>,
     environ: Vec<CString>,
-    selinux_state: Option<SeLinuxResolvedElfState>,
+    security_state: Option<security::ResolvedElfState>,
 ) -> Result<ResolvedElf, Errno>
 where
     L: LockBefore<FileOpsCore>,
     L: LockBefore<DeviceOpen>,
 {
-    resolve_executable_impl(locked, current_task, file, path, argv, environ, 0, selinux_state)
+    resolve_executable_impl(locked, current_task, file, path, argv, environ, 0, security_state)
 }
 
 /// Resolves a file into a validated executable ELF, following script interpreters to a fixed
@@ -297,7 +297,7 @@
     argv: Vec<CString>,
     environ: Vec<CString>,
     recursion_depth: usize,
-    selinux_state: Option<SeLinuxResolvedElfState>,
+    security_state: Option<security::ResolvedElfState>,
 ) -> Result<ResolvedElf, Errno>
 where
     L: LockBefore<FileOpsCore>,
@@ -324,10 +324,10 @@
             argv,
             environ,
             recursion_depth,
-            selinux_state,
+            security_state,
         )
     } else {
-        resolve_elf(locked, current_task, file, vmo, argv, environ, selinux_state)
+        resolve_elf(locked, current_task, file, vmo, argv, environ, security_state)
     }
 }
 
@@ -340,7 +340,7 @@
     argv: Vec<CString>,
     environ: Vec<CString>,
     recursion_depth: usize,
-    selinux_state: Option<SeLinuxResolvedElfState>,
+    security_state: Option<security::ResolvedElfState>,
 ) -> Result<ResolvedElf, Errno>
 where
     L: LockBefore<FileOpsCore>,
@@ -374,7 +374,7 @@
         args,
         environ,
         recursion_depth + 1,
-        selinux_state,
+        security_state,
     )
 }
 
@@ -424,7 +424,7 @@
     vmo: Arc<zx::Vmo>,
     argv: Vec<CString>,
     environ: Vec<CString>,
-    selinux_state: Option<SeLinuxResolvedElfState>,
+    security_state: Option<security::ResolvedElfState>,
 ) -> Result<ResolvedElf, Errno>
 where
     L: LockBefore<FileOpsCore>,
@@ -456,7 +456,7 @@
     };
     let file_write_guard =
         file.name.entry.node.create_write_guard(FileWriteGuardMode::Exec)?.into_ref();
-    Ok(ResolvedElf { file, vmo, interp, argv, environ, selinux_state, file_write_guard })
+    Ok(ResolvedElf { file, vmo, interp, argv, environ, security_state, file_write_guard })
 }
 
 /// Loads a resolved ELF into memory, along with an interpreter if one is defined, and initializes
diff --git a/src/starnix/kernel/selinux/OWNERS b/src/starnix/kernel/security/OWNERS
similarity index 100%
rename from src/starnix/kernel/selinux/OWNERS
rename to src/starnix/kernel/security/OWNERS
diff --git a/src/starnix/kernel/selinux/fs.rs b/src/starnix/kernel/security/fs.rs
similarity index 95%
rename from src/starnix/kernel/selinux/fs.rs
rename to src/starnix/kernel/security/fs.rs
index 1f0a474..9daaba9 100644
--- a/src/starnix/kernel/selinux/fs.rs
+++ b/src/starnix/kernel/security/fs.rs
@@ -472,6 +472,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         _current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
@@ -662,20 +663,20 @@
             }
         };
 
-        // SELinux is enabled, so the task must have `selinux_state`. Lock it for writing
+        // SELinux is enabled, so the task must have `security_state`. Lock it for writing
         // and update it.
         let mut tg = task.thread_group.write();
 
         use SeProcAttrNodeType::*;
         match self.attr {
-            Current => tg.selinux_state.current_sid = sid.ok_or(errno!(EINVAL))?,
-            Exec => tg.selinux_state.exec_sid = sid,
-            FsCreate => tg.selinux_state.fscreate_sid = sid,
-            KeyCreate => tg.selinux_state.keycreate_sid = sid,
+            Current => tg.security_state.0.current_sid = sid.ok_or(errno!(EINVAL))?,
+            Exec => tg.security_state.0.exec_sid = sid,
+            FsCreate => tg.security_state.0.fscreate_sid = sid,
+            KeyCreate => tg.security_state.0.keycreate_sid = sid,
             Previous => {
                 return error!(EINVAL);
             }
-            SockCreate => tg.selinux_state.sockcreate_sid = sid,
+            SockCreate => tg.security_state.0.sockcreate_sid = sid,
         };
 
         Ok(())
@@ -692,12 +693,12 @@
                 let sid = {
                     let tg = task.thread_group.read();
                     match self.attr {
-                        Current => Some(tg.selinux_state.current_sid),
-                        Exec => tg.selinux_state.exec_sid,
-                        FsCreate => tg.selinux_state.fscreate_sid,
-                        KeyCreate => tg.selinux_state.keycreate_sid,
-                        Previous => Some(tg.selinux_state.previous_sid),
-                        SockCreate => tg.selinux_state.sockcreate_sid,
+                        Current => Some(tg.security_state.0.current_sid),
+                        Exec => tg.security_state.0.exec_sid,
+                        FsCreate => tg.security_state.0.fscreate_sid,
+                        KeyCreate => tg.security_state.0.keycreate_sid,
+                        Previous => Some(tg.security_state.0.previous_sid),
+                        SockCreate => tg.security_state.0.sockcreate_sid,
                     }
                 };
 
diff --git a/src/starnix/kernel/selinux/hooks/current_task_hooks.rs b/src/starnix/kernel/security/hooks.rs
similarity index 80%
rename from src/starnix/kernel/selinux/hooks/current_task_hooks.rs
rename to src/starnix/kernel/security/hooks.rs
index 448d082..ff0f54c 100644
--- a/src/starnix/kernel/selinux/hooks/current_task_hooks.rs
+++ b/src/starnix/kernel/security/hooks.rs
@@ -2,19 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use std::sync::Arc;
-
-use super::thread_group_hooks::{self, SeLinuxResolvedElfState};
+use super::{selinux_hooks, ResolvedElfState, ThreadGroupState};
 use crate::{
-    task::{CurrentTask, Task, ThreadGroup},
+    task::{CurrentTask, Kernel, Task, ThreadGroup},
     vfs::{FsNode, FsNodeHandle, FsStr, ValueOrSize},
 };
 
-use selinux::{
-    security_server::{SecurityServer, SecurityServerStatus},
-    InitialSid, SecurityId,
+use {
+    selinux::{
+        security_server::{SecurityServer, SecurityServerStatus},
+        InitialSid, SecurityId,
+    },
+    starnix_uapi::{error, errors::Errno, signals::Signal},
+    std::sync::Arc,
 };
-use starnix_uapi::{errors::Errno, signals::Signal};
 
 /// Maximum supported size for the `"security.selinux"` value used to store SELinux security
 /// contexts in a filesystem node extended attributes.
@@ -27,12 +28,12 @@
 ///
 /// If SELinux is "permissive" (non-enforcing) then error results are logged and the default
 /// success result is returned.
-fn check_if_selinux<F, R>(current_task: &CurrentTask, hook: F) -> Result<R, Errno>
+fn check_if_selinux<F, R>(task: &Task, hook: F) -> Result<R, Errno>
 where
     F: FnOnce(&Arc<SecurityServer>) -> Result<R, Errno>,
     R: Default,
 {
-    if let Some(security_server) = &current_task.kernel().security_server {
+    if let Some(security_server) = &task.kernel().security_server {
         if !security_server.has_policy() {
             return Ok(R::default());
         }
@@ -51,20 +52,20 @@
 ///
 /// This is used for non-enforcing hooks, such as those responsible for generating security labels
 /// for new tasks.
-fn run_if_selinux<F, R>(current_task: &CurrentTask, hook: F) -> R
+fn run_if_selinux<F, R>(task: &Task, hook: F) -> R
 where
     F: FnOnce(&Arc<SecurityServer>) -> R,
     R: Default,
 {
-    run_if_selinux_else(current_task, hook, R::default)
+    run_if_selinux_else(task, hook, R::default)
 }
 
-fn run_if_selinux_else<F, R, D>(current_task: &CurrentTask, hook: F, default: D) -> R
+fn run_if_selinux_else<F, R, D>(task: &Task, hook: F, default: D) -> R
 where
     F: FnOnce(&Arc<SecurityServer>) -> R,
     D: Fn() -> R,
 {
-    current_task.kernel().security_server.as_ref().map_or_else(&default, |ss| {
+    task.kernel().security_server.as_ref().map_or_else(&default, |ss| {
         if ss.has_policy() {
             hook(ss)
         } else {
@@ -73,11 +74,38 @@
     })
 }
 
+/// Returns an `ThreadGroupState` instance for a new task.
+pub fn alloc_security(kernel: &Kernel, parent: Option<&ThreadGroupState>) -> ThreadGroupState {
+    ThreadGroupState(if kernel.security_server.is_none() {
+        selinux_hooks::ThreadGroupState::for_selinux_disabled()
+    } else {
+        selinux_hooks::alloc_security(parent.map(|tgs| &tgs.0))
+    })
+}
+
+fn get_current_sid(thread_group: &Arc<ThreadGroup>) -> SecurityId {
+    thread_group.read().security_state.0.current_sid
+}
+
+/// Returns the serialized Security Context associated with the specified task.
+/// If the task's current SID cannot be resolved then an empty string is returned.
+/// This combines the `task_getsecid()` and `secid_to_secctx()` hooks, in effect.
+pub fn get_task_context(current_task: &CurrentTask, target: &Task) -> Result<Vec<u8>, Errno> {
+    run_if_selinux_else(
+        current_task,
+        |security_server| {
+            let sid = get_current_sid(&target.thread_group);
+            Ok(security_server.sid_to_security_context(sid).unwrap_or_default())
+        },
+        || error!(ENOTSUP),
+    )
+}
+
 /// Check if creating a task is allowed.
 pub fn check_task_create_access(current_task: &CurrentTask) -> Result<(), Errno> {
     check_if_selinux(current_task, |security_server| {
-        let sid = current_task.get_current_sid();
-        thread_group_hooks::check_task_create_access(&security_server.as_permission_check(), sid)
+        let sid = get_current_sid(&current_task.thread_group);
+        selinux_hooks::check_task_create_access(&security_server.as_permission_check(), sid)
     })
 }
 
@@ -85,28 +113,29 @@
 pub fn check_exec_access(
     current_task: &CurrentTask,
     executable_node: &FsNodeHandle,
-) -> Result<Option<SeLinuxResolvedElfState>, Errno> {
+) -> Result<Option<ResolvedElfState>, Errno> {
     check_if_selinux(current_task, |security_server| {
         let executable_sid = executable_node.effective_sid(current_task);
         let group_state = current_task.thread_group.read();
-        thread_group_hooks::check_exec_access(
-            &security_server.as_permission_check(),
-            &group_state.selinux_state,
+        selinux_hooks::check_exec_access(
+            &security_server,
+            &group_state.security_state.0,
             executable_sid,
         )
+        .map(|s| s.map(|s| ResolvedElfState(s)))
     })
 }
 
 /// Updates the SELinux thread group state on exec.
 pub fn update_state_on_exec(
     current_task: &mut CurrentTask,
-    elf_selinux_state: &Option<SeLinuxResolvedElfState>,
+    elf_security_state: &Option<ResolvedElfState>,
 ) {
     run_if_selinux(current_task, |_| {
         let mut thread_group_state = current_task.thread_group.write();
-        thread_group_hooks::update_state_on_exec(
-            &mut thread_group_state.selinux_state,
-            elf_selinux_state,
+        selinux_hooks::update_state_on_exec(
+            &mut thread_group_state.security_state.0,
+            elf_security_state.as_ref().map(|s| s.0),
         );
     });
 }
@@ -116,9 +145,9 @@
     check_if_selinux(source, |security_server| {
         // TODO(b/323856891): Consider holding `source.thread_group` and `target.thread_group`
         // read locks for duration of access check.
-        let source_sid = source.get_current_sid();
-        let target_sid = target.get_current_sid();
-        thread_group_hooks::check_getsched_access(
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_getsched_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -129,9 +158,9 @@
 /// Checks if setsched is allowed.
 pub fn check_setsched_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
     check_if_selinux(source, |security_server| {
-        let source_sid = source.get_current_sid();
-        let target_sid = target.get_current_sid();
-        thread_group_hooks::check_setsched_access(
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_setsched_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -140,11 +169,11 @@
 }
 
 /// Checks if getpgid is allowed.
-pub fn check_getpgid_access(source_task: &CurrentTask, target_task: &Task) -> Result<(), Errno> {
-    check_if_selinux(source_task, |security_server| {
-        let source_sid = source_task.get_current_sid();
-        let target_sid = target_task.get_current_sid();
-        thread_group_hooks::check_getpgid_access(
+pub fn check_getpgid_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
+    check_if_selinux(source, |security_server| {
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_getpgid_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -153,11 +182,11 @@
 }
 
 /// Checks if setpgid is allowed.
-pub fn check_setpgid_access(source_task: &CurrentTask, target_task: &Task) -> Result<(), Errno> {
-    check_if_selinux(source_task, |security_server| {
-        let source_sid = source_task.get_current_sid();
-        let target_sid = target_task.get_current_sid();
-        thread_group_hooks::check_setpgid_access(
+pub fn check_setpgid_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
+    check_if_selinux(source, |security_server| {
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_setpgid_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -167,14 +196,14 @@
 
 /// Checks if sending a signal is allowed.
 pub fn check_signal_access(
-    source_task: &CurrentTask,
-    target_task: &Task,
+    source: &CurrentTask,
+    target: &Task,
     signal: Signal,
 ) -> Result<(), Errno> {
-    check_if_selinux(source_task, |security_server| {
-        let source_sid = source_task.get_current_sid();
-        let target_sid = target_task.get_current_sid();
-        thread_group_hooks::check_signal_access(
+    check_if_selinux(source, |security_server| {
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_signal_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -183,38 +212,48 @@
     })
 }
 
-/// Checks if tracing the current task is allowed.
-pub fn check_ptrace_traceme_access(
+/// Checks if tracing the current task is allowed, and update the thread group SELinux state to
+/// store the tracer SID.
+pub fn check_ptrace_traceme_access_and_update_state(
     parent: &Arc<ThreadGroup>,
     current_task: &CurrentTask,
 ) -> Result<(), Errno> {
     check_if_selinux(current_task, |security_server| {
-        let source_sid = parent.get_current_sid();
-        let target_sid = current_task.get_current_sid();
-        thread_group_hooks::check_ptrace_access(
+        let tracer_sid = get_current_sid(parent);
+        let mut thread_group_state = current_task.thread_group.write();
+        selinux_hooks::check_ptrace_access_and_update_state(
             &security_server.as_permission_check(),
-            source_sid,
-            target_sid,
+            tracer_sid,
+            &mut thread_group_state.security_state.0,
         )
     })
 }
 
-/// Checks if `current_task` is allowed to trace `tracee_task`.
-pub fn check_ptrace_attach_access(
+/// Checks if `current_task` is allowed to trace `tracee_task`, and update the thread group SELinux
+/// state to store the tracer SID.
+pub fn check_ptrace_attach_access_and_update_state(
     current_task: &CurrentTask,
     tracee_task: &Task,
 ) -> Result<(), Errno> {
     check_if_selinux(current_task, |security_server| {
-        let source_sid = current_task.get_current_sid();
-        let target_sid = tracee_task.get_current_sid();
-        thread_group_hooks::check_ptrace_access(
+        let tracer_sid = get_current_sid(&current_task.thread_group);
+        let mut thread_group_state = tracee_task.thread_group.write();
+        selinux_hooks::check_ptrace_access_and_update_state(
             &security_server.as_permission_check(),
-            source_sid,
-            target_sid,
+            tracer_sid,
+            &mut thread_group_state.security_state.0,
         )
     })
 }
 
+/// Clears the `ptrace_sid` for `tracee_task`.
+pub fn clear_ptracer_sid(tracee_task: &Task) {
+    run_if_selinux(tracee_task, |_| {
+        let mut thread_group_state = tracee_task.thread_group.write();
+        thread_group_state.security_state.0.ptracer_sid = None;
+    });
+}
+
 /// Attempts to update the security ID (SID) associated with `fs_node` when
 /// `name="security.selinux"` and `value` is a valid security context according to the current
 /// policy.
@@ -298,13 +337,12 @@
     use selinux::security_server::Mode;
     use starnix_sync::{Locked, Unlocked};
     use starnix_uapi::{device_type::DeviceType, error, file_mode::FileMode, signals::SIGTERM};
-    use tests::thread_group_hooks::SeLinuxThreadGroupState;
 
     const VALID_SECURITY_CONTEXT: &'static str = "u:object_r:test_valid_t:s0";
     const DIFFERENT_VALID_SECURITY_CONTEXT: &'static str = "u:object_r:test_different_valid_t:s0";
 
     const HOOKS_TESTS_BINARY_POLICY: &[u8] =
-        include_bytes!("../../../lib/selinux/testdata/micro_policies/hooks_tests_policy.pp");
+        include_bytes!("../../lib/selinux/testdata/micro_policies/hooks_tests_policy.pp");
 
     fn security_server_with_policy(mode: Mode) -> Arc<SecurityServer> {
         let policy_bytes = HOOKS_TESTS_BINARY_POLICY.to_vec();
@@ -405,6 +443,13 @@
         assert_eq!(run_else_result, TestHookResult::WasRun);
     }
 
+    #[fuchsia::test]
+    async fn alloc_security_selinux_disabled() {
+        let (kernel, _current_task) = create_kernel_and_task();
+
+        alloc_security(&kernel, None);
+    }
+
     fn failing_hook(_: &Arc<SecurityServer>) -> Result<(), Errno> {
         error!(EINVAL)
     }
@@ -496,13 +541,13 @@
         // Without SELinux enabled and a policy loaded, only `InitialSid` values exist
         // in the system.
         let kernel_sid = SecurityId::initial(InitialSid::Kernel);
-        let elf_state = SeLinuxResolvedElfState { sid: kernel_sid };
+        let elf_state = ResolvedElfState(kernel_sid);
 
-        assert!(task.thread_group.read().selinux_state.current_sid != kernel_sid);
+        assert!(task.thread_group.read().security_state.0.current_sid != kernel_sid);
 
-        let before_hook_sid = task.thread_group.read().selinux_state.current_sid;
+        let before_hook_sid = task.thread_group.read().security_state.0.current_sid;
         update_state_on_exec(&mut task, &Some(elf_state));
-        assert_eq!(task.thread_group.read().selinux_state.current_sid, before_hook_sid);
+        assert_eq!(task.thread_group.read().security_state.0.current_sid, before_hook_sid);
     }
 
     #[fuchsia::test]
@@ -513,21 +558,21 @@
 
         // Without SELinux enabled and a policy loaded, only `InitialSid` values exist
         // in the system.
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
+        let initial_state = selinux_hooks::ThreadGroupState::for_kernel();
         let elf_sid = SecurityId::initial(InitialSid::Unlabeled);
-        let elf_state = SeLinuxResolvedElfState { sid: elf_sid };
+        let elf_state = ResolvedElfState(elf_sid);
         assert_ne!(elf_sid, initial_state.current_sid);
         update_state_on_exec(&mut task, &Some(elf_state));
-        assert_eq!(task.thread_group.read().selinux_state, initial_state);
+        assert_eq!(task.thread_group.read().security_state.0, initial_state);
     }
 
     #[fuchsia::test]
     async fn state_update_for_fake_mode() {
         let security_server = security_server_with_policy(Mode::Fake);
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
+        let initial_state = selinux_hooks::ThreadGroupState::for_kernel();
         let (kernel, task) = create_kernel_and_task_with_selinux(security_server);
         let mut task = task;
-        task.thread_group.write().selinux_state = initial_state.clone();
+        task.thread_group.write().security_state.0 = initial_state.clone();
 
         let elf_sid = kernel
             .security_server
@@ -535,30 +580,30 @@
             .expect("missing security server")
             .security_context_to_sid(b"u:object_r:fork_no_t:s0")
             .expect("invalid security context");
-        let elf_state = SeLinuxResolvedElfState { sid: elf_sid };
+        let elf_state = ResolvedElfState(elf_sid);
         assert_ne!(elf_sid, initial_state.current_sid);
         update_state_on_exec(&mut task, &Some(elf_state));
-        assert_eq!(task.thread_group.read().selinux_state.current_sid, elf_sid);
+        assert_eq!(task.thread_group.read().security_state.0.current_sid, elf_sid);
     }
 
     #[fuchsia::test]
     async fn state_update_for_permissive_mode() {
         let security_server = security_server_with_policy(Mode::Enable);
         security_server.set_enforcing(false);
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
+        let initial_state = selinux_hooks::ThreadGroupState::for_kernel();
         let (kernel, task) = create_kernel_and_task_with_selinux(security_server);
         let mut task = task;
-        task.thread_group.write().selinux_state = initial_state.clone();
+        task.thread_group.write().security_state.0 = initial_state.clone();
         let elf_sid = kernel
             .security_server
             .as_ref()
             .expect("missing security server")
             .security_context_to_sid(b"u:object_r:fork_no_t:s0")
             .expect("invalid security context");
-        let elf_state = SeLinuxResolvedElfState { sid: elf_sid };
+        let elf_state = ResolvedElfState(elf_sid);
         assert_ne!(elf_sid, initial_state.current_sid);
         update_state_on_exec(&mut task, &Some(elf_state));
-        assert_eq!(task.thread_group.read().selinux_state.current_sid, elf_sid);
+        assert_eq!(task.thread_group.read().security_state.0.current_sid, elf_sid);
     }
 
     #[fuchsia::test]
@@ -654,37 +699,58 @@
     #[fuchsia::test]
     async fn ptrace_traceme_access_allowed_for_selinux_disabled() {
         let (tracee_task, tracer_task) = create_task_pair_with_selinux_disabled();
-        assert_eq!(check_ptrace_traceme_access(&tracer_task.thread_group, &tracee_task), Ok(()));
+        assert_eq!(
+            check_ptrace_traceme_access_and_update_state(&tracer_task.thread_group, &tracee_task),
+            Ok(())
+        );
     }
 
     #[fuchsia::test]
     async fn ptrace_traceme_access_allowed_for_fake_mode() {
         let (tracee_task, tracer_task) = create_task_pair_with_fake_selinux();
-        assert_eq!(check_ptrace_traceme_access(&tracer_task.thread_group, &tracee_task), Ok(()));
+        assert_eq!(
+            check_ptrace_traceme_access_and_update_state(&tracer_task.thread_group, &tracee_task),
+            Ok(())
+        );
     }
 
     #[fuchsia::test]
     async fn ptrace_traceme_access_allowed_for_permissive_mode() {
         let (tracee_task, tracer_task) = create_task_pair_with_permissive_selinux();
-        assert_eq!(check_ptrace_traceme_access(&tracer_task.thread_group, &tracee_task), Ok(()));
+        assert_eq!(
+            check_ptrace_traceme_access_and_update_state(&tracer_task.thread_group, &tracee_task),
+            Ok(())
+        );
     }
 
     #[fuchsia::test]
     async fn ptrace_attach_access_allowed_for_selinux_disabled() {
         let (tracer_task, tracee_task) = create_task_pair_with_selinux_disabled();
-        assert_eq!(check_ptrace_attach_access(&tracer_task, &tracee_task), Ok(()));
+        assert_eq!(check_ptrace_attach_access_and_update_state(&tracer_task, &tracee_task), Ok(()));
     }
 
     #[fuchsia::test]
     async fn ptrace_attach_access_allowed_for_fake_mode() {
         let (tracer_task, tracee_task) = create_task_pair_with_fake_selinux();
-        assert_eq!(check_ptrace_attach_access(&tracer_task, &tracee_task), Ok(()));
+        assert_eq!(check_ptrace_attach_access_and_update_state(&tracer_task, &tracee_task), Ok(()));
     }
 
     #[fuchsia::test]
     async fn ptrace_attach_access_allowed_for_permissive_mode() {
         let (tracer_task, tracee_task) = create_task_pair_with_permissive_selinux();
-        assert_eq!(check_ptrace_attach_access(&tracer_task, &tracee_task), Ok(()));
+        assert_eq!(check_ptrace_attach_access_and_update_state(&tracer_task, &tracee_task), Ok(()));
+    }
+
+    #[fuchsia::test]
+    async fn ptracer_sid_is_cleared() {
+        let security_server = security_server_with_policy(Mode::Enable);
+        security_server.set_enforcing(true);
+        let (_kernel, tracee_task) = create_kernel_and_task_with_selinux(security_server);
+        tracee_task.thread_group.write().security_state.0.ptracer_sid =
+            Some(SecurityId::initial(InitialSid::Unlabeled));
+
+        clear_ptracer_sid(tracee_task.as_ref());
+        assert!(tracee_task.thread_group.read().security_state.0.ptracer_sid.is_none());
     }
 
     #[fuchsia::test]
diff --git a/src/starnix/kernel/security/mod.rs b/src/starnix/kernel/security/mod.rs
new file mode 100644
index 0000000..7c106c9
--- /dev/null
+++ b/src/starnix/kernel/security/mod.rs
@@ -0,0 +1,32 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// This module provides types and hook APIs supporting Linux Security Modules
+/// functionality in Starnix.  LSM provides a generic set of hooks, and opaque
+/// types, used to decouple the rest of the kernel from the details of any
+/// specific security enforcement subsystem (e.g. SELinux, POSIX.1e, etc).
+///
+/// Although this module is hard-wired to the SELinux implementation, callers
+/// should treat the types as opaque; hook implementations necessarily have access
+/// to kernel structures, but not the other way around.
+use selinux::SecurityId;
+
+/// SELinux implementations called by the LSM hooks.
+mod selinux_hooks;
+
+/// Linux Security Modules hooks for use within the Starnix kernel.
+mod hooks;
+pub use hooks::*;
+
+/// Opaque structure encapsulating security state for a `ThreadGroup`.
+#[derive(Debug)]
+pub struct ThreadGroupState(selinux_hooks::ThreadGroupState);
+
+/// Opaque structure holding security state associated with a `ResolvedElf` instance.
+#[derive(Debug, PartialEq)]
+pub struct ResolvedElfState(SecurityId);
+
+// TODO(b/322850635): Create a clean separation between the procattr filesystem, and LSM hooks.
+// TODO(b/335397745): Move the SELinux filesystem bits under the selinux directory.
+pub mod fs;
diff --git a/src/starnix/kernel/selinux/hooks/thread_group_hooks.rs b/src/starnix/kernel/security/selinux_hooks/mod.rs
similarity index 70%
rename from src/starnix/kernel/selinux/hooks/thread_group_hooks.rs
rename to src/starnix/kernel/security/selinux_hooks/mod.rs
index 01e9999..840bf64 100644
--- a/src/starnix/kernel/selinux/hooks/thread_group_hooks.rs
+++ b/src/starnix/kernel/security/selinux_hooks/mod.rs
@@ -2,18 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use crate::task::Kernel;
-
-use selinux::{permission_check::PermissionCheck, InitialSid, SecurityId};
-use selinux_common::{FilePermission, ProcessPermission};
+use selinux::{
+    permission_check::PermissionCheck, security_server::SecurityServer, InitialSid, SecurityId,
+};
+use selinux_common::{FilePermission, ObjectClass, ProcessPermission};
+use starnix_logging::log_debug;
 use starnix_uapi::{
-    error,
+    errno, error,
     errors::Errno,
     signals::{Signal, SIGCHLD, SIGKILL, SIGSTOP},
 };
+use std::sync::Arc;
 
 /// Checks if creating a task is allowed.
-pub(crate) fn check_task_create_access(
+pub(super) fn check_task_create_access(
     permission_check: &impl PermissionCheck,
     task_sid: SecurityId,
 ) -> Result<(), Errno> {
@@ -25,62 +27,70 @@
 
 /// Checks the SELinux permissions required for exec. Returns the SELinux state of a resolved
 /// elf if all required permissions are allowed.
-pub(crate) fn check_exec_access(
-    permission_check: &impl PermissionCheck,
-    selinux_state: &SeLinuxThreadGroupState,
+pub(super) fn check_exec_access(
+    security_server: &Arc<SecurityServer>,
+    security_state: &ThreadGroupState,
     executable_sid: SecurityId,
-) -> Result<Option<SeLinuxResolvedElfState>, Errno> {
-    let current_sid = selinux_state.current_sid;
-    let new_sid = if let Some(exec_sid) = selinux_state.exec_sid {
+) -> Result<Option<SecurityId>, Errno> {
+    let current_sid = security_state.current_sid;
+    let new_sid = if let Some(exec_sid) = security_state.exec_sid {
         // Use the proc exec SID if set.
         exec_sid
     } else {
-        // TODO(http://b/320436714): Check typetransition rules from the current security
-        // context to the executable's security context. If none, use the current security
-        // context.
-        current_sid
+        security_server
+            .compute_new_sid(current_sid, executable_sid, ObjectClass::Process)
+            .map_err(|_| errno!(EACCES))?
+        // TODO(http://b/319232900): validate that the new context is valid, and return EACCESS if
+        // it's not.
     };
     if current_sid == new_sid {
         // To `exec()` a binary in the caller's domain, the caller must be granted
         // "execute_no_trans" permission to the binary.
-        if !permission_check.has_permission(
+        if !security_server.has_permission(
             current_sid,
             executable_sid,
             FilePermission::ExecuteNoTrans,
         ) {
             // TODO(http://b/330904217): once filesystems are labeled, deny access.
+            log_debug!("execute_no_trans permission is denied, ignoring.");
         }
     } else {
         // Domain transition, check that transition is allowed.
-        if !permission_check.has_permission(current_sid, new_sid, ProcessPermission::Transition) {
+        if !security_server.has_permission(current_sid, new_sid, ProcessPermission::Transition) {
             return error!(EACCES);
         }
-        // TODO(http://b/320436714): Check executable permissions:
-        // - allow rule from `new_sid` to the executable's security context for entrypoint
-        //   permissions
-        // - allow rule from `current_sid` to the executable's security context for read
-        //   and execute permissions
+        // Check that the executable file has an entry point into the new domain.
+        if !security_server.has_permission(new_sid, executable_sid, FilePermission::Entrypoint) {
+            // TODO(http://b/330904217): once filesystems are labeled, deny access.
+            log_debug!("entrypoint permission is denied, ignoring.");
+        }
+        // Check that ptrace permission is allowed if the process is traced.
+        if let Some(ptracer_sid) = security_state.ptracer_sid {
+            if !security_server.has_permission(ptracer_sid, new_sid, ProcessPermission::Ptrace) {
+                return error!(EACCES);
+            }
+        }
     }
-    Ok(Some(SeLinuxResolvedElfState { sid: new_sid }))
+    Ok(Some(new_sid))
 }
 
 /// Updates the SELinux thread group state on exec, using the security ID associated with the
 /// resolved elf.
-pub(crate) fn update_state_on_exec(
-    selinux_state: &mut SeLinuxThreadGroupState,
-    elf_selinux_state: &Option<SeLinuxResolvedElfState>,
+pub(super) fn update_state_on_exec(
+    security_state: &mut ThreadGroupState,
+    elf_security_state: Option<SecurityId>,
 ) {
     // TODO(http://b/316181721): check if the previous state needs to be updated regardless.
-    if let Some(elf_selinux_state) = elf_selinux_state {
-        selinux_state.previous_sid = selinux_state.current_sid;
-        selinux_state.current_sid = elf_selinux_state.sid;
+    if let Some(elf_security_state) = elf_security_state {
+        security_state.previous_sid = security_state.current_sid;
+        security_state.current_sid = elf_security_state;
     }
 }
 
 /// Checks if source with `source_sid` may exercise the "getsched" permission on target with
 /// `target_sid` according to SELinux server status `status` and permission checker
 /// `permission`.
-pub fn check_getsched_access(
+pub(super) fn check_getsched_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -90,7 +100,7 @@
 
 /// Checks if the task with `source_sid` is allowed to set scheduling parameters for the task with
 /// `target_sid`.
-pub(crate) fn check_setsched_access(
+pub(super) fn check_setsched_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -100,7 +110,7 @@
 
 /// Checks if the task with `source_sid` is allowed to get the process group ID of the task with
 /// `target_sid`.
-pub(crate) fn check_getpgid_access(
+pub(super) fn check_getpgid_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -110,7 +120,7 @@
 
 /// Checks if the task with `source_sid` is allowed to set the process group ID of the task with
 /// `target_sid`.
-pub(crate) fn check_setpgid_access(
+pub(super) fn check_setpgid_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -119,7 +129,7 @@
 }
 
 /// Checks if the task with `source_sid` is allowed to send `signal` to the task with `target_sid`.
-pub(crate) fn check_signal_access(
+pub(super) fn check_signal_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -145,12 +155,22 @@
 }
 
 /// Checks if the task with `source_sid` is allowed to trace the task with `target_sid`.
-pub(crate) fn check_ptrace_access(
+pub(super) fn check_ptrace_access_and_update_state(
     permission_check: &impl PermissionCheck,
-    source_sid: SecurityId,
-    target_sid: SecurityId,
+    tracer_sid: SecurityId,
+    tracee_security_state: &mut ThreadGroupState,
 ) -> Result<(), Errno> {
-    check_permission(permission_check, source_sid, target_sid, ProcessPermission::Ptrace)
+    check_permission(
+        permission_check,
+        tracer_sid,
+        tracee_security_state.current_sid,
+        ProcessPermission::Ptrace,
+    )
+    .and_then(|_| {
+        // If tracing is allowed, set the `ptracer_sid` of the tracee with the tracer's SID.
+        tracee_security_state.ptracer_sid = Some(tracer_sid);
+        Ok(())
+    })
 }
 
 /// Checks if `permission` is allowed from the task with `source_sid` to the task with `target_sid`.
@@ -166,23 +186,17 @@
     }
 }
 
-/// Returns an `SeLinuxThreadGroupState` instance for a new task.
-pub fn alloc_security(
-    kernel: &Kernel,
-    parent: Option<&SeLinuxThreadGroupState>,
-) -> SeLinuxThreadGroupState {
-    if kernel.security_server.is_none() {
-        return SeLinuxThreadGroupState::for_selinux_disabled();
-    };
+/// Returns a `ThreadGroupState` instance for a new task.
+pub(super) fn alloc_security(parent: Option<&ThreadGroupState>) -> ThreadGroupState {
     match parent {
         Some(parent) => parent.clone(),
-        None => SeLinuxThreadGroupState::for_kernel(),
+        None => ThreadGroupState::for_kernel(),
     }
 }
 
 /// The SELinux security structure for `ThreadGroup`.
 #[derive(Clone, Debug, PartialEq)]
-pub struct SeLinuxThreadGroupState {
+pub(super) struct ThreadGroupState {
     /// Current SID for the task.
     pub current_sid: SecurityId,
 
@@ -200,11 +214,14 @@
 
     /// SID for sockets created by the task.
     pub sockcreate_sid: Option<SecurityId>,
+
+    /// SID of the tracer, if the thread group is traced.
+    pub ptracer_sid: Option<SecurityId>,
 }
 
-impl SeLinuxThreadGroupState {
+impl ThreadGroupState {
     /// Returns initial state for the kernel's root thread group.
-    pub(crate) fn for_kernel() -> Self {
+    pub(super) fn for_kernel() -> Self {
         Self {
             current_sid: SecurityId::initial(InitialSid::Kernel),
             previous_sid: SecurityId::initial(InitialSid::Kernel),
@@ -212,11 +229,12 @@
             fscreate_sid: None,
             keycreate_sid: None,
             sockcreate_sid: None,
+            ptracer_sid: None,
         }
     }
 
     /// Returns placeholder state for use when SELinux is not enabled.
-    fn for_selinux_disabled() -> Self {
+    pub(super) fn for_selinux_disabled() -> Self {
         Self {
             current_sid: SecurityId::initial(InitialSid::Unlabeled),
             previous_sid: SecurityId::initial(InitialSid::Unlabeled),
@@ -224,24 +242,16 @@
             fscreate_sid: None,
             keycreate_sid: None,
             sockcreate_sid: None,
+            ptracer_sid: None,
         }
     }
 }
 
-/// The SELinux security structure for `ResolvedElf`.
-#[derive(Clone, Eq, PartialEq, Debug)]
-pub struct SeLinuxResolvedElfState {
-    /// Security ID for the transformed process.
-    pub sid: SecurityId,
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::testing::{create_kernel_and_task, create_kernel_and_task_with_selinux};
-    use selinux::security_server::{Mode, SecurityServer};
+    use selinux::security_server::Mode;
     use starnix_uapi::signals::SIGTERM;
-    use std::sync::Arc;
 
     const HOOKS_TESTS_BINARY_POLICY: &[u8] =
         include_bytes!("../../../lib/selinux/testdata/micro_policies/hooks_tests_policy.pp");
@@ -278,9 +288,8 @@
     }
 
     #[fuchsia::test]
-    fn exec_access_allowed_for_allowed_transition_type() {
+    fn exec_transition_allowed_for_allowed_transition_type() {
         let security_server = security_server_with_policy();
-
         let current_sid = security_server
             .security_context_to_sid(b"u:object_r:exec_transition_source_t:s0")
             .expect("invalid security context");
@@ -290,52 +299,76 @@
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_trans_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: Some(exec_sid),
             fscreate_sid: None,
             keycreate_sid: None,
             previous_sid: current_sid,
             sockcreate_sid: None,
+            ptracer_sid: None,
         };
 
         assert_eq!(
-            check_exec_access(
-                &security_server.as_permission_check(),
-                &selinux_state,
-                executable_sid
-            ),
-            Ok(Some(SeLinuxResolvedElfState { sid: exec_sid }))
+            check_exec_access(&security_server, &security_state, executable_sid),
+            Ok(Some(exec_sid))
         );
     }
 
     #[fuchsia::test]
-    fn exec_access_denied_for_denied_transition_type() {
+    fn exec_transition_denied_for_transition_denied_type() {
         let security_server = security_server_with_policy();
         let current_sid = security_server
-            .security_context_to_sid(b"u:object_r:exec_transition_target_t:s0")
+            .security_context_to_sid(b"u:object_r:exec_transition_source_t:s0")
             .expect("invalid security context");
         let exec_sid = security_server
-            .security_context_to_sid(b"u:object_r:exec_transition_source_t:s0")
+            .security_context_to_sid(b"u:object_r:exec_transition_denied_target_t:s0")
             .expect("invalid security context");
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_trans_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: Some(exec_sid),
             fscreate_sid: None,
             keycreate_sid: None,
             previous_sid: current_sid,
             sockcreate_sid: None,
+            ptracer_sid: None,
         };
 
         assert_eq!(
-            check_exec_access(
-                &security_server.as_permission_check(),
-                &selinux_state,
-                executable_sid
-            ),
+            check_exec_access(&security_server, &security_state, executable_sid),
+            error!(EACCES)
+        );
+    }
+
+    // TODO(http://b/330904217): reenable test once filesystems are labeled and access is denied.
+    #[ignore]
+    #[fuchsia::test]
+    fn exec_transition_denied_for_executable_with_no_entrypoint_perm() {
+        let security_server = security_server_with_policy();
+        let current_sid = security_server
+            .security_context_to_sid(b"u:object_r:exec_transition_source_t:s0")
+            .expect("invalid security context");
+        let exec_sid = security_server
+            .security_context_to_sid(b"u:object_r:exec_transition_target_t:s0")
+            .expect("invalid security context");
+        let executable_sid = security_server
+            .security_context_to_sid(b"u:object_r:executable_file_trans_no_entrypoint_t:s0")
+            .expect("invalid security context");
+        let security_state = ThreadGroupState {
+            current_sid: current_sid,
+            exec_sid: Some(exec_sid),
+            fscreate_sid: None,
+            keycreate_sid: None,
+            previous_sid: current_sid,
+            sockcreate_sid: None,
+            ptracer_sid: None,
+        };
+
+        assert_eq!(
+            check_exec_access(&security_server, &security_state, executable_sid),
             error!(EACCES)
         );
     }
@@ -350,22 +383,19 @@
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_no_trans_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: None,
             fscreate_sid: None,
             keycreate_sid: None,
             previous_sid: current_sid,
             sockcreate_sid: None,
+            ptracer_sid: None,
         };
 
         assert_eq!(
-            check_exec_access(
-                &security_server.as_permission_check(),
-                &selinux_state,
-                executable_sid
-            ),
-            Ok(Some(SeLinuxResolvedElfState { sid: current_sid }))
+            check_exec_access(&security_server, &security_state, executable_sid),
+            Ok(Some(current_sid))
         );
     }
 
@@ -380,56 +410,53 @@
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_no_trans_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: None,
             fscreate_sid: None,
             keycreate_sid: None,
             previous_sid: current_sid,
             sockcreate_sid: None,
+            ptracer_sid: None,
         };
 
         // There is no `execute_no_trans` allow statement from `current_sid` to `executable_sid`,
         // expect access denied.
         assert_eq!(
-            check_exec_access(
-                &security_server.as_permission_check(),
-                &selinux_state,
-                executable_sid
-            ),
+            check_exec_access(&security_server, &security_state, executable_sid),
             error!(EACCES)
         );
     }
 
     #[fuchsia::test]
     fn no_state_update_if_no_elf_state() {
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
-        let mut selinux_state = initial_state.clone();
-        update_state_on_exec(&mut selinux_state, &None);
-        assert_eq!(selinux_state, initial_state);
+        let initial_state = ThreadGroupState::for_kernel();
+        let mut security_state = initial_state.clone();
+        update_state_on_exec(&mut security_state, None);
+        assert_eq!(security_state, initial_state);
     }
 
     #[fuchsia::test]
     fn state_is_updated_on_exec() {
         let security_server = security_server_with_policy();
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
-        let mut selinux_state = initial_state.clone();
+        let initial_state = ThreadGroupState::for_kernel();
+        let mut security_state = initial_state.clone();
 
         let elf_sid = security_server
             .security_context_to_sid(b"u:object_r:test_valid_t:s0")
             .expect("invalid security context");
-        let elf_state = SeLinuxResolvedElfState { sid: elf_sid };
         assert_ne!(elf_sid, initial_state.current_sid);
-        update_state_on_exec(&mut selinux_state, &Some(elf_state));
+        update_state_on_exec(&mut security_state, Some(elf_sid));
         assert_eq!(
-            selinux_state,
-            SeLinuxThreadGroupState {
+            security_state,
+            ThreadGroupState {
                 current_sid: elf_sid,
                 exec_sid: initial_state.exec_sid,
                 fscreate_sid: initial_state.fscreate_sid,
                 keycreate_sid: initial_state.keycreate_sid,
                 previous_sid: initial_state.previous_sid,
                 sockcreate_sid: initial_state.sockcreate_sid,
+                ptracer_sid: initial_state.ptracer_sid,
             }
         );
     }
@@ -640,76 +667,106 @@
     }
 
     #[fuchsia::test]
-    fn ptrace_access_allowed_for_allowed_type() {
+    fn ptrace_access_allowed_for_allowed_type_and_state_is_updated() {
         let security_server = security_server_with_policy();
-        let source_sid = security_server
+        let tracer_sid = security_server
             .security_context_to_sid(b"u:object_r:test_ptrace_tracer_yes_t:s0")
             .expect("invalid security context");
-        let target_sid = security_server
+        let tracee_sid = security_server
             .security_context_to_sid(b"u:object_r:test_ptrace_traced_t:s0")
             .expect("invalid security context");
+        let initial_state = ThreadGroupState {
+            current_sid: tracee_sid.clone(),
+            exec_sid: None,
+            fscreate_sid: None,
+            keycreate_sid: None,
+            previous_sid: tracee_sid,
+            sockcreate_sid: None,
+            ptracer_sid: None,
+        };
+        let mut tracee_state = initial_state.clone();
 
         assert_eq!(
-            check_ptrace_access(&security_server.as_permission_check(), source_sid, target_sid),
+            check_ptrace_access_and_update_state(
+                &security_server.as_permission_check(),
+                tracer_sid.clone(),
+                &mut tracee_state
+            ),
             Ok(())
         );
-    }
-
-    #[fuchsia::test]
-    fn ptrace_access_denied_for_denied_type() {
-        let security_server = security_server_with_policy();
-        let source_sid = security_server
-            .security_context_to_sid(b"u:object_r:test_ptrace_tracer_no_t:s0")
-            .expect("invalid security context");
-        let target_sid = security_server
-            .security_context_to_sid(b"u:object_r:test_ptrace_traced_t:s0")
-            .expect("invalid security context");
-
         assert_eq!(
-            check_ptrace_access(&security_server.as_permission_check(), source_sid, target_sid),
-            error!(EACCES)
+            tracee_state,
+            ThreadGroupState {
+                current_sid: initial_state.current_sid,
+                exec_sid: initial_state.exec_sid,
+                fscreate_sid: initial_state.fscreate_sid,
+                keycreate_sid: initial_state.keycreate_sid,
+                previous_sid: initial_state.previous_sid,
+                sockcreate_sid: initial_state.sockcreate_sid,
+                ptracer_sid: Some(tracer_sid),
+            }
         );
     }
 
     #[fuchsia::test]
-    async fn alloc_security_selinux_disabled() {
-        let (kernel, _current_task) = create_kernel_and_task();
+    fn ptrace_access_denied_for_denied_type_and_state_is_not_updated() {
+        let security_server = security_server_with_policy();
+        let tracer_sid = security_server
+            .security_context_to_sid(b"u:object_r:test_ptrace_tracer_no_t:s0")
+            .expect("invalid security context");
+        let tracee_sid = security_server
+            .security_context_to_sid(b"u:object_r:test_ptrace_traced_t:s0")
+            .expect("invalid security context");
+        let initial_state = ThreadGroupState {
+            current_sid: tracee_sid.clone(),
+            exec_sid: None,
+            fscreate_sid: None,
+            keycreate_sid: None,
+            previous_sid: tracee_sid,
+            sockcreate_sid: None,
+            ptracer_sid: None,
+        };
+        let mut tracee_state = initial_state.clone();
 
-        alloc_security(&kernel, None);
+        assert_eq!(
+            check_ptrace_access_and_update_state(
+                &security_server.as_permission_check(),
+                tracer_sid,
+                &mut tracee_state
+            ),
+            error!(EACCES)
+        );
+        assert_eq!(initial_state, tracee_state);
     }
 
     #[fuchsia::test]
     async fn alloc_security_no_parent() {
-        let security_server = SecurityServer::new(Mode::Fake);
-        let (kernel, _current_task) = create_kernel_and_task_with_selinux(security_server);
-        let selinux_state = alloc_security(&kernel, None);
+        let security_state = alloc_security(None);
         assert_eq!(
-            selinux_state,
-            SeLinuxThreadGroupState {
+            security_state,
+            ThreadGroupState {
                 current_sid: SecurityId::initial(InitialSid::Kernel),
                 previous_sid: SecurityId::initial(InitialSid::Kernel),
                 exec_sid: None,
                 fscreate_sid: None,
                 keycreate_sid: None,
                 sockcreate_sid: None,
+                ptracer_sid: None,
             }
         );
     }
 
     #[fuchsia::test]
     async fn alloc_security_from_parent() {
-        let security_server = SecurityServer::new(Mode::Fake);
-        let (kernel, _current_task) = create_kernel_and_task_with_selinux(security_server);
-
         // Create a fake parent state, with values for some fields, to check for.
-        let mut parent_selinux_state = alloc_security(&kernel, None);
-        parent_selinux_state.current_sid = SecurityId::initial(InitialSid::Unlabeled);
-        parent_selinux_state.exec_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
-        parent_selinux_state.fscreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
-        parent_selinux_state.keycreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
-        parent_selinux_state.sockcreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
+        let mut parent_security_state = alloc_security(None);
+        parent_security_state.current_sid = SecurityId::initial(InitialSid::Unlabeled);
+        parent_security_state.exec_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
+        parent_security_state.fscreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
+        parent_security_state.keycreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
+        parent_security_state.sockcreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
 
-        let selinux_state = alloc_security(&kernel, Some(&parent_selinux_state));
-        assert_eq!(selinux_state, parent_selinux_state);
+        let security_state = alloc_security(Some(&parent_security_state));
+        assert_eq!(security_state, parent_security_state);
     }
 }
diff --git a/src/starnix/kernel/selinux/hooks/mod.rs b/src/starnix/kernel/selinux/hooks/mod.rs
deleted file mode 100644
index e8cfdfe..0000000
--- a/src/starnix/kernel/selinux/hooks/mod.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2024 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The hooks modules implement SELinux hooks to control and enforce access decisions, and define
-// SELinux security structs associated to objects in the system, holding state information used
-// by hooks to make access decisions.
-
-pub mod current_task_hooks;
-pub mod thread_group_hooks;
diff --git a/src/starnix/kernel/selinux/mod.rs b/src/starnix/kernel/selinux/mod.rs
deleted file mode 100644
index d71555f..0000000
--- a/src/starnix/kernel/selinux/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-pub mod fs;
-pub mod hooks;
diff --git a/src/starnix/kernel/signals/syscalls.rs b/src/starnix/kernel/signals/syscalls.rs
index 8f15f46..b9a8fa6 100644
--- a/src/starnix/kernel/signals/syscalls.rs
+++ b/src/starnix/kernel/signals/syscalls.rs
@@ -6,7 +6,7 @@
 use super::signalfd::SignalFd;
 use crate::{
     mm::{MemoryAccessor, MemoryAccessorExt},
-    selinux::hooks::current_task_hooks as selinux_hooks,
+    security,
     signals::{
         restore_from_signal_handler, send_signal, SignalDetail, SignalInfo, SignalInfoHeader,
         SI_HEADER_SIZE,
@@ -338,7 +338,7 @@
     }
 
     let signal = Signal::try_from(unchecked_signal)?;
-    selinux_hooks::check_signal_access(current_task, &target, signal)?;
+    security::check_signal_access(current_task, &target, signal)?;
 
     send_signal(
         target,
@@ -371,7 +371,7 @@
     }
 
     let signal = Signal::try_from(unchecked_signal)?;
-    selinux_hooks::check_signal_access(current_task, &target, signal)?;
+    security::check_signal_access(current_task, &target, signal)?;
 
     let siginfo = read_siginfo(current_task, signal, siginfo_ref)?;
     if target.get_pid() != current_task.get_pid() && (siginfo.code >= 0 || siginfo.code == SI_TKILL)
diff --git a/src/starnix/kernel/sync/lock_ordering.rs b/src/starnix/kernel/sync/lock_ordering.rs
index 7f8e500..1b95438 100644
--- a/src/starnix/kernel/sync/lock_ordering.rs
+++ b/src/starnix/kernel/sync/lock_ordering.rs
@@ -23,6 +23,9 @@
 lock_level!(WriteOps);
 lock_level!(FileOpsToHandle);
 
+// Lock levels for binder operations
+lock_level!(ResourceAccessorAddFile);
+
 // Lock level for DeviceOps.open. Must be before FileOpsCore because of get_or_create_loop_device
 lock_level!(DeviceOpen);
 lock_level!(FsNodeAllocate);
@@ -37,7 +40,8 @@
 impl_lock_after!(Unlocked => MmDumpable);
 
 impl_lock_after!(Unlocked => TaskRelease);
-impl_lock_after!(TaskRelease => FileOpsToHandle);
+impl_lock_after!(TaskRelease => ResourceAccessorAddFile);
+impl_lock_after!(ResourceAccessorAddFile => FileOpsToHandle);
 impl_lock_after!(FileOpsToHandle => DeviceOpen);
 impl_lock_after!(DeviceOpen => FsNodeAllocate);
 impl_lock_after!(FsNodeAllocate => FileOpsCore);
diff --git a/src/starnix/kernel/sync/lock_relations.rs b/src/starnix/kernel/sync/lock_relations.rs
index aa65b49..d293c2c 100644
--- a/src/starnix/kernel/sync/lock_relations.rs
+++ b/src/starnix/kernel/sync/lock_relations.rs
@@ -90,7 +90,7 @@
 ///
 /// This should be implemented for lock types to specify that, in the lock
 /// ordering graph, `A` comes before `Self`. So if `B: LockAfter<A>`, lock type
-/// `B` can be acquired after `A` but `A` cannot be acquired before `B`.
+/// `B` can be acquired after `A` but `A` cannot be acquired after `B`.
 ///
 /// Note, though, that it's preferred to use the [`impl_lock_after`] macro
 /// instead of writing trait impls directly to avoid the possibility of lock
diff --git a/src/starnix/kernel/task/current_task.rs b/src/starnix/kernel/task/current_task.rs
index 3bd6eda..33ffe3a 100644
--- a/src/starnix/kernel/task/current_task.rs
+++ b/src/starnix/kernel/task/current_task.rs
@@ -11,7 +11,7 @@
     fs::proc::pid_directory::TaskDirectory,
     loader::{load_executable, resolve_executable, ResolvedElf},
     mm::{MemoryAccessor, MemoryAccessorExt, MemoryManager, TaskMemoryAccessor},
-    selinux::hooks::current_task_hooks as selinux_hooks,
+    security,
     signals::{send_signal_first, send_standard_signal, RunState, SignalActions, SignalInfo},
     task::{
         ExitStatus, Kernel, PidTable, ProcessGroup, PtraceCoreState, PtraceEvent, PtraceEventData,
@@ -831,7 +831,7 @@
         // used in the `open` call.
         executable.name.check_access(self, Access::EXEC)?;
 
-        let elf_selinux_state = selinux_hooks::check_exec_access(self, executable.node())?;
+        let elf_security_state = security::check_exec_access(self, executable.node())?;
 
         let resolved_elf = resolve_executable(
             locked,
@@ -840,7 +840,7 @@
             path.clone(),
             argv,
             environ,
-            elf_selinux_state,
+            elf_security_state,
         )?;
 
         if self.thread_group.read().tasks_count() > 1 {
@@ -878,7 +878,7 @@
             .map_err(|status| from_status_like_fdio!(status))?;
 
         // Update the SELinux state, if enabled.
-        selinux_hooks::update_state_on_exec(self, &resolved_elf.selinux_state);
+        security::update_state_on_exec(self, &resolved_elf.security_state);
 
         let start_info = load_executable(self, resolved_elf, &path)?;
         let regs: zx_thread_state_general_regs_t = start_info.into();
diff --git a/src/starnix/kernel/task/net.rs b/src/starnix/kernel/task/net.rs
index a9373fe..e74ac2c 100644
--- a/src/starnix/kernel/task/net.rs
+++ b/src/starnix/kernel/task/net.rs
@@ -138,6 +138,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
diff --git a/src/starnix/kernel/task/ptrace.rs b/src/starnix/kernel/task/ptrace.rs
index 145d9e7..4268557 100644
--- a/src/starnix/kernel/task/ptrace.rs
+++ b/src/starnix/kernel/task/ptrace.rs
@@ -5,7 +5,7 @@
 use crate::{
     arch::execution::new_syscall_from_state,
     mm::{DumpPolicy, MemoryAccessor, MemoryAccessorExt},
-    selinux::hooks::current_task_hooks as selinux_hooks,
+    security,
     signals::{
         send_signal_first, send_standard_signal, syscalls::WaitingOptions, SignalDetail,
         SignalInfo, SignalInfoHeader, SI_HEADER_SIZE,
@@ -703,6 +703,7 @@
     if let Err(x) = ptrace_cont(&tracee, &data, true) {
         return Err(x);
     }
+    security::clear_ptracer_sid(tracee);
     let tid = tracee.get_tid();
     thread_group.ptracees.lock().remove(&tid);
     thread_group.write().zombie_ptracees.retain(&mut |zombie: &ZombieProcess| zombie.pid != tid);
@@ -1037,7 +1038,7 @@
 
     let parent = current_task.thread_group.read().parent.clone();
     if let Some(parent) = parent {
-        selinux_hooks::check_ptrace_traceme_access(&parent, current_task)?;
+        security::check_ptrace_traceme_access_and_update_state(&parent, current_task)?;
         let task_ref = OwnedRef::temp(&current_task.task);
         do_attach(&parent, (&task_ref).into(), PtraceAttachType::Attach, PtraceOptions::empty())?;
         Ok(starnix_syscalls::SUCCESS)
@@ -1061,7 +1062,7 @@
 
     let weak_task = current_task.kernel().pids.read().get_task(pid);
     let tracee = weak_task.upgrade().ok_or_else(|| errno!(ESRCH))?;
-    selinux_hooks::check_ptrace_attach_access(&current_task, &tracee)?;
+    security::check_ptrace_attach_access_and_update_state(&current_task, &tracee)?;
 
     if tracee.thread_group == current_task.thread_group {
         return error!(EPERM);
diff --git a/src/starnix/kernel/task/syscalls.rs b/src/starnix/kernel/task/syscalls.rs
index 7148b4c..59f5dfd 100644
--- a/src/starnix/kernel/task/syscalls.rs
+++ b/src/starnix/kernel/task/syscalls.rs
@@ -12,7 +12,7 @@
 use crate::{
     execution::execute_task,
     mm::{DumpPolicy, MemoryAccessor, MemoryAccessorExt, PAGE_SIZE},
-    selinux::hooks::current_task_hooks as selinux_hooks,
+    security,
     task::{
         max_priority_for_sched_policy, min_priority_for_sched_policy, ptrace_attach,
         ptrace_dispatch, ptrace_traceme, CurrentTask, ExitStatus, PtraceAllowedPtracers,
@@ -73,7 +73,7 @@
     L: LockBefore<MmDumpable>,
     L: LockBefore<TaskRelease>,
 {
-    selinux_hooks::check_task_create_access(current_task)?;
+    security::check_task_create_access(current_task)?;
 
     let child_exit_signal = if args.exit_signal == 0 {
         None
@@ -394,7 +394,7 @@
     let weak = get_task_or_current(current_task, pid);
     let task = Task::from_weak(&weak)?;
 
-    selinux_hooks::check_getpgid_access(current_task, &task)?;
+    security::check_getpgid_access(current_task, &task)?;
     let pgid = task.thread_group.read().process_group.leader;
     Ok(pgid)
 }
@@ -408,7 +408,7 @@
     let weak = get_task_or_current(current_task, pid);
     let task = Task::from_weak(&weak)?;
 
-    selinux_hooks::check_setpgid_access(current_task, &task)?;
+    security::check_setpgid_access(current_task, &task)?;
     current_task.thread_group.setpgid(locked, &task, pgid)?;
     Ok(())
 }
@@ -734,7 +734,7 @@
 
     let weak = get_task_or_current(current_task, pid);
     let target_task = Task::from_weak(&weak)?;
-    selinux_hooks::check_getsched_access(current_task, target_task.as_ref())?;
+    security::check_getsched_access(current_task, target_task.as_ref())?;
     let current_policy = target_task.read().scheduler_policy;
     Ok(current_policy.raw_policy())
 }
@@ -754,7 +754,7 @@
     let target_task = Task::from_weak(&weak)?;
     let rlimit = target_task.thread_group.get_rlimit(Resource::RTPRIO);
 
-    selinux_hooks::check_setsched_access(current_task, &target_task)?;
+    security::check_setsched_access(current_task, &target_task)?;
     let param: sched_param = current_task.read_object(param.into())?;
     let policy = SchedulerPolicy::from_sched_params(policy, param, rlimit)?;
     target_task.set_scheduler_policy(policy)?;
diff --git a/src/starnix/kernel/task/task.rs b/src/starnix/kernel/task/task.rs
index 915a7cc..ebe5a5d 100644
--- a/src/starnix/kernel/task/task.rs
+++ b/src/starnix/kernel/task/task.rs
@@ -21,7 +21,6 @@
 };
 use macro_rules_attribute::apply;
 use once_cell::sync::OnceCell;
-use selinux::SecurityId;
 use starnix_logging::{log_debug, log_warn, set_zx_name};
 use starnix_sync::{LockBefore, Locked, MmDumpable, Mutex, RwLock, TaskRelease};
 use starnix_uapi::{
@@ -1265,11 +1264,6 @@
         logging_span.clone()
     }
 
-    /// Get the SELinux security ID of the current task, or `None` if not set.
-    pub fn get_current_sid(&self) -> SecurityId {
-        self.thread_group.read().selinux_state.current_sid
-    }
-
     fn update_logging_span(&self, debug_info: &starnix_logging::TaskDebugInfo) {
         let logging_span =
             self.logging_span.get_or_init(|| starnix_logging::Span::new(&debug_info));
diff --git a/src/starnix/kernel/task/thread_group.rs b/src/starnix/kernel/task/thread_group.rs
index 3a0a618..71dc4bd 100644
--- a/src/starnix/kernel/task/thread_group.rs
+++ b/src/starnix/kernel/task/thread_group.rs
@@ -5,7 +5,7 @@
 use crate::{
     device::terminal::{ControllingSession, Terminal},
     mutable_state::{state_accessor, state_implementation},
-    selinux::hooks::thread_group_hooks,
+    security,
     signals::{
         send_signal, send_standard_signal, syscalls::WaitingOptions, SignalActions, SignalDetail,
         SignalInfo,
@@ -22,7 +22,6 @@
 use fuchsia_zircon as zx;
 use itertools::Itertools;
 use macro_rules_attribute::apply;
-use selinux::SecurityId;
 use starnix_lifecycle::{AtomicU64Counter, DropNotifier};
 use starnix_logging::{log_error, log_warn, track_stub};
 use starnix_sync::{LockBefore, Locked, Mutex, MutexGuard, ProcessGroupState, RwLock};
@@ -112,8 +111,8 @@
 
     pub terminating: bool,
 
-    /// The SELinux operations for this thread group.
-    pub selinux_state: thread_group_hooks::SeLinuxThreadGroupState,
+    /// The Linux Security Modules state for this thread group.
+    pub security_state: security::ThreadGroupState,
 
     /// Time statistics accumulated from the children.
     pub children_time_stats: TaskTimeStats,
@@ -376,8 +375,8 @@
     {
         let timers = TimerTable::new();
         let itimer_real_id = timers.create(CLOCK_REALTIME as ClockId, None).unwrap();
-        let selinux_state =
-            thread_group_hooks::alloc_security(&kernel, parent.as_ref().map(|p| &p.selinux_state));
+        let security_state =
+            security::alloc_security(&kernel, parent.as_ref().map(|p| &p.security_state));
         let mut thread_group = ThreadGroup {
             kernel,
             process,
@@ -409,7 +408,7 @@
                 last_signal: None,
                 leader_exit_info: None,
                 terminating: false,
-                selinux_state,
+                security_state,
                 children_time_stats: Default::default(),
                 personality: parent.as_ref().map(|p| p.personality).unwrap_or(Default::default()),
                 allowed_ptracers: PtraceAllowedPtracers::None,
@@ -1294,15 +1293,6 @@
         }
         None
     }
-
-    /// Get the SELinux security ID of the thread group.
-    /// Returns a placeholder value if SELinux is not enabled.
-    pub fn get_current_sid(&self) -> SecurityId {
-        // TODO(http://b/316181721): to avoid TOCTOU issues, once initial security contexts are
-        // propagated to tasks in the system, in some cases using this API will need to be replaced
-        // with call sites holding the state lock while making updates.
-        self.mutable_state.read().selinux_state.current_sid
-    }
 }
 
 #[apply(state_implementation!)]
diff --git a/src/starnix/kernel/vfs/directory_file.rs b/src/starnix/kernel/vfs/directory_file.rs
index 727c153..526e475c 100644
--- a/src/starnix/kernel/vfs/directory_file.rs
+++ b/src/starnix/kernel/vfs/directory_file.rs
@@ -9,7 +9,7 @@
         FsString, SeekTarget,
     },
 };
-use starnix_sync::Mutex;
+use starnix_sync::{FileOpsCore, Locked, Mutex};
 use starnix_uapi::{error, errors::Errno, off_t};
 use std::ops::Bound;
 
@@ -92,6 +92,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         _current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
diff --git a/src/starnix/kernel/vfs/file_object.rs b/src/starnix/kernel/vfs/file_object.rs
index 815ee8e..c834a10 100644
--- a/src/starnix/kernel/vfs/file_object.rs
+++ b/src/starnix/kernel/vfs/file_object.rs
@@ -297,6 +297,7 @@
     /// at `sink.offset()` to read the current offset into the file.
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         _file: &FileObject,
         _current_task: &CurrentTask,
         _sink: &mut dyn DirentSink,
@@ -481,11 +482,12 @@
 
     fn readdir(
         &self,
+        locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
     ) -> Result<(), Errno> {
-        self.deref().readdir(file, current_task, sink)
+        self.deref().readdir(locked, file, current_task, sink)
     }
 
     fn wait_async(
@@ -795,8 +797,13 @@
                 return error!(ENOTTY);
             }
 
-            let size =
-                file.name.entry.node.refresh_info(current_task).map_err(|_| errno!(EINVAL))?.size;
+            let size = file
+                .name
+                .entry
+                .node
+                .fetch_and_refresh_info(current_task)
+                .map_err(|_| errno!(EINVAL))?
+                .size;
             let offset = usize::try_from(*file.offset.lock()).map_err(|_| errno!(EINVAL))?;
             let remaining =
                 if size < offset { 0 } else { i32::try_from(size - offset).unwrap_or(i32::MAX) };
@@ -907,6 +914,7 @@
     }
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         _file: &FileObject,
         _current_task: &CurrentTask,
         _sink: &mut dyn DirentSink,
@@ -973,12 +981,6 @@
             options: MappingOptions,
             filename: NamespaceNode,
         ) -> Result<UserAddress, Errno>;
-        fn readdir(
-            &self,
-            _file: &FileObject,
-            _current_task: &CurrentTask,
-            _sink: &mut dyn DirentSink,
-        ) -> Result<(), Errno>;
         fn wait_async(
             &self,
             _file: &FileObject,
@@ -1040,6 +1042,15 @@
     ) -> Result<SyscallResult, Errno> {
         self.0.ops().ioctl(locked, &self.0, current_task, request, arg)
     }
+    fn readdir(
+        &self,
+        locked: &mut Locked<'_, FileOpsCore>,
+        _file: &FileObject,
+        current_task: &CurrentTask,
+        sink: &mut dyn DirentSink,
+    ) -> Result<(), Errno> {
+        self.0.ops().readdir(locked, &self.0, current_task, sink)
+    }
 }
 
 #[derive(Debug, Default, Copy, Clone)]
@@ -1472,16 +1483,21 @@
         self.ops().mmap(self, current_task, addr, vmo_offset, length, prot_flags, options, filename)
     }
 
-    pub fn readdir(
+    pub fn readdir<L>(
         &self,
+        locked: &mut Locked<'_, L>,
         current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
-    ) -> Result<(), Errno> {
+    ) -> Result<(), Errno>
+    where
+        L: LockEqualOrBefore<FileOpsCore>,
+    {
+        let mut locked = locked.cast_locked::<FileOpsCore>();
         if self.name.entry.is_dead() {
             return error!(ENOENT);
         }
 
-        self.ops().readdir(self, current_task, sink)?;
+        self.ops().readdir(&mut locked, self, current_task, sink)?;
         self.update_atime();
         Ok(())
     }
diff --git a/src/starnix/kernel/vfs/file_server.rs b/src/starnix/kernel/vfs/file_server.rs
index 4d4dfc5..92aeba4 100644
--- a/src/starnix/kernel/vfs/file_server.rs
+++ b/src/starnix/kernel/vfs/file_server.rs
@@ -214,7 +214,12 @@
             sink: Some(directory::dirents_sink::AppendResult::Ok(sink)),
             offset: &mut file_offset,
         };
-        self.file.readdir(&current_task, &mut dirent_sink)?;
+        let kernel = self.kernel().unwrap().clone();
+        self.file.readdir(
+            kernel.kthreads.unlocked_for_async().deref_mut(),
+            &current_task,
+            &mut dirent_sink,
+        )?;
         match dirent_sink.sink {
             Some(directory::dirents_sink::AppendResult::Sealed(seal)) => {
                 Ok((directory::traversal_position::TraversalPosition::End, seal))
diff --git a/src/starnix/kernel/vfs/fs_node.rs b/src/starnix/kernel/vfs/fs_node.rs
index 4cf9fa7..16a6093 100644
--- a/src/starnix/kernel/vfs/fs_node.rs
+++ b/src/starnix/kernel/vfs/fs_node.rs
@@ -5,7 +5,7 @@
 use crate::{
     device::DeviceMode,
     mm::PAGE_SIZE,
-    selinux::hooks::current_task_hooks::{get_fs_node_security_id, post_setxattr},
+    security::{get_fs_node_security_id, post_setxattr},
     signals::{send_standard_signal, SignalInfo},
     task::{CurrentTask, Kernel, WaitQueue, Waiter},
     time::utc,
@@ -557,6 +557,7 @@
     /// Create and return the given child node as a subdirectory.
     fn mkdir(
         &self,
+        locked: &mut Locked<'_, FileOpsCore>,
         _node: &FsNode,
         _current_task: &CurrentTask,
         _name: &FsStr,
@@ -567,6 +568,7 @@
     /// Creates a symlink with the given `target` path.
     fn create_symlink(
         &self,
+        locked: &mut Locked<'_, FileOpsCore>,
         _node: &FsNode,
         _current_task: &CurrentTask,
         _name: &FsStr,
@@ -662,8 +664,8 @@
     /// File systems that keep the FsNodeInfo up-to-date do not need to
     /// override this function.
     ///
-    /// Return a reader lock on the updated information.
-    fn refresh_info<'a>(
+    /// Return a read guard for the updated information.
+    fn fetch_and_refresh_info<'a>(
         &self,
         _node: &FsNode,
         _current_task: &CurrentTask,
@@ -676,7 +678,7 @@
     ///
     /// Starnix updates the timestamps in node.info directly. However, if the filesystem can manage
     /// the timestamps, then Starnix does not need to do so. `node.info`` will be refreshed with the
-    /// timestamps from the filesystem by calling `refresh_info(..)`.
+    /// timestamps from the filesystem by calling `fetch_and_refresh_info(..)`.
     fn filesystem_manages_timestamps(&self, _node: &FsNode) -> bool {
         false
     }
@@ -791,6 +793,7 @@
     () => {
         fn mkdir(
             &self,
+            _locked: &mut starnix_sync::Locked<'_, starnix_sync::FileOpsCore>,
             _node: &crate::vfs::FsNode,
             _current_task: &crate::task::CurrentTask,
             _name: &crate::vfs::FsStr,
@@ -815,6 +818,7 @@
 
         fn create_symlink(
             &self,
+            _locked: &mut starnix_sync::Locked<'_, starnix_sync::FileOpsCore>,
             _node: &crate::vfs::FsNode,
             _current_task: &crate::task::CurrentTask,
             _name: &crate::vfs::FsStr,
@@ -921,6 +925,7 @@
 
         fn mkdir(
             &self,
+            _locked: &mut starnix_sync::Locked<'_, starnix_sync::FileOpsCore>,
             _node: &crate::vfs::FsNode,
             _current_task: &crate::task::CurrentTask,
             _name: &crate::vfs::FsStr,
@@ -932,6 +937,7 @@
 
         fn create_symlink(
             &self,
+            _locked: &mut starnix_sync::Locked<'_, starnix_sync::FileOpsCore>,
             _node: &crate::vfs::FsNode,
             _current_task: &crate::task::CurrentTask,
             _name: &crate::vfs::FsStr,
@@ -1240,7 +1246,8 @@
         self.update_metadata_for_child(current_task, &mut mode, &mut owner);
 
         if mode.is_dir() {
-            self.ops().mkdir(self, current_task, name, mode, owner)
+            let mut locked = locked.cast_locked::<FileOpsCore>();
+            self.ops().mkdir(&mut locked, self, current_task, name, mode, owner)
         } else {
             // https://man7.org/linux/man-pages/man2/mknod.2.html says:
             //
@@ -1261,16 +1268,21 @@
         }
     }
 
-    pub fn create_symlink(
+    pub fn create_symlink<L>(
         &self,
+        locked: &mut Locked<'_, L>,
         current_task: &CurrentTask,
         mount: &MountInfo,
         name: &FsStr,
         target: &FsStr,
         owner: FsCred,
-    ) -> Result<FsNodeHandle, Errno> {
+    ) -> Result<FsNodeHandle, Errno>
+    where
+        L: LockEqualOrBefore<FileOpsCore>,
+    {
         self.check_access(current_task, mount, Access::WRITE)?;
-        self.ops().create_symlink(self, current_task, name, target, owner)
+        let mut locked = locked.cast_locked::<FileOpsCore>();
+        self.ops().create_symlink(&mut locked, self, current_task, name, target, owner)
     }
 
     pub fn create_tmpfile(
@@ -1748,7 +1760,7 @@
     }
 
     pub fn stat(&self, current_task: &CurrentTask) -> Result<uapi::stat, Errno> {
-        let info = self.refresh_info(current_task)?;
+        let info = self.fetch_and_refresh_info(current_task)?;
 
         let time_to_kernel_timespec_pair = |t| {
             let timespec { tv_sec, tv_nsec } = timespec_from_time(t);
@@ -1801,7 +1813,7 @@
         let info = if flags.contains(StatxFlags::AT_STATX_DONT_SYNC) {
             self.info()
         } else {
-            self.refresh_info(current_task)?
+            self.fetch_and_refresh_info(current_task)?
         };
         if mask & STATX__RESERVED == STATX__RESERVED {
             return error!(EINVAL);
@@ -1931,12 +1943,12 @@
         self.info.read()
     }
 
-    /// Refreshes the `FsNodeInfo` if necessary and returns a read lock.
-    pub fn refresh_info(
+    /// Refreshes the `FsNodeInfo` if necessary and returns a read guard.
+    pub fn fetch_and_refresh_info(
         &self,
         current_task: &CurrentTask,
     ) -> Result<RwLockReadGuard<'_, FsNodeInfo>, Errno> {
-        self.ops().refresh_info(self, current_task, &self.info)
+        self.ops().fetch_and_refresh_info(self, current_task, &self.info)
     }
 
     pub fn update_info<F, T>(&self, mutator: F) -> T
diff --git a/src/starnix/kernel/vfs/fsverity.rs b/src/starnix/kernel/vfs/fsverity.rs
index e426bf9..b6f5fd9 100644
--- a/src/starnix/kernel/vfs/fsverity.rs
+++ b/src/starnix/kernel/vfs/fsverity.rs
@@ -169,7 +169,7 @@
         // Nb: Lock order is important here.
         let args: fsverity_enable_arg = task.read_object(arg.into())?;
         let mut descriptor = fsverity_descriptor_from_enable_arg(task, block_size, &args)?;
-        descriptor.data_size = file.node().refresh_info(task)?.size as u64;
+        descriptor.data_size = file.node().fetch_and_refresh_info(task)?.size as u64;
         // The "Exec" writeguard mode means 'no writers'.
         let _guard = file.node().create_write_guard(FileWriteGuardMode::Exec)?;
         let mut fsverity = file.node().fsverity.lock();
diff --git a/src/starnix/kernel/vfs/fuse.rs b/src/starnix/kernel/vfs/fuse.rs
index f4b5305..6580337 100644
--- a/src/starnix/kernel/vfs/fuse.rs
+++ b/src/starnix/kernel/vfs/fuse.rs
@@ -18,11 +18,12 @@
     },
 };
 use bstr::B;
+use fuchsia_zircon as zx;
 use starnix_lifecycle::AtomicU64Counter;
 use starnix_logging::{log_error, log_trace, log_warn, track_stub};
 use starnix_sync::{
-    DeviceOpen, FileOpsCore, FsNodeAllocate, Locked, Mutex, MutexGuard, RwLock, RwLockReadGuard,
-    RwLockWriteGuard, Unlocked, WriteOps,
+    AtomicTime, DeviceOpen, FileOpsCore, FsNodeAllocate, Locked, Mutex, MutexGuard, RwLock,
+    RwLockReadGuard, RwLockWriteGuard, Unlocked, WriteOps,
 };
 use starnix_syscalls::{SyscallArg, SyscallResult};
 use starnix_uapi::{
@@ -34,14 +35,17 @@
     mode, off_t,
     open_flags::OpenFlags,
     statfs,
-    time::time_from_timespec,
+    time::{duration_from_timespec, time_from_timespec},
     uapi,
     vfs::{default_statfs, FdEvents},
     FUSE_SUPER_MAGIC,
 };
 use std::{
     collections::{hash_map::Entry, HashMap, VecDeque},
-    sync::{Arc, Weak},
+    sync::{
+        atomic::{AtomicBool, Ordering},
+        Arc, Weak,
+    },
 };
 use zerocopy::{AsBytes, FromBytes, NoCell};
 
@@ -64,6 +68,13 @@
     Ok(Box::new(DevFuse { connection }))
 }
 
+fn attr_valid_to_duration(attr_valid: u64, attr_valid_nsec: u32) -> Result<zx::Duration, Errno> {
+    duration_from_timespec(uapi::timespec {
+        tv_sec: i64::try_from(attr_valid).unwrap_or(i64::MAX),
+        tv_nsec: attr_valid_nsec.into(),
+    })
+}
+
 impl FileOps for DevFuse {
     fileops_impl_nonseekable!();
 
@@ -123,7 +134,7 @@
     let fd = fs_args::parse::<FdNumber>(
         mount_options.remove(B("fd")).ok_or_else(|| errno!(EINVAL))?.as_ref(),
     )?;
-    let default_permissions = mount_options.remove(B("default_permissions")).is_some();
+    let default_permissions = mount_options.remove(B("default_permissions")).is_some().into();
     let connection = current_task
         .files
         .get(fd)?
@@ -138,11 +149,7 @@
         FuseFs { connection: connection.clone(), default_permissions },
         options,
     );
-    let fuse_node = Arc::new(FuseNode {
-        connection: connection.clone(),
-        nodeid: uapi::FUSE_ROOT_ID as u64,
-        state: Default::default(),
-    });
+    let fuse_node = FuseNode::new(connection.clone(), uapi::FUSE_ROOT_ID as u64);
     fuse_node.state.lock().nlookup += 1;
 
     let mut root_node = FsNode::new_root(fuse_node.clone());
@@ -151,7 +158,11 @@
     {
         let mut state = connection.lock();
         state.connect();
-        state.execute_operation(current_task, &fuse_node, FuseOperation::Init)?;
+        state.execute_operation(
+            current_task,
+            &fuse_node,
+            FuseOperation::Init { fs: Arc::downgrade(&fs) },
+        )?;
     }
     Ok(fs)
 }
@@ -180,7 +191,7 @@
 #[derive(Debug)]
 struct FuseFs {
     connection: Arc<FuseConnection>,
-    default_permissions: bool,
+    default_permissions: AtomicBool,
 }
 
 impl FuseFs {
@@ -442,15 +453,86 @@
 struct FuseNode {
     connection: Arc<FuseConnection>,
     nodeid: u64,
+    attributes_valid_until: AtomicTime,
     state: Mutex<FuseNodeMutableState>,
 }
 
 impl FuseNode {
+    fn new(connection: Arc<FuseConnection>, nodeid: u64) -> Arc<Self> {
+        Arc::new(Self {
+            connection,
+            nodeid,
+            attributes_valid_until: zx::Time::INFINITE_PAST.into(),
+            state: Default::default(),
+        })
+    }
+
     fn from_node(node: &FsNode) -> Result<&Arc<FuseNode>, Errno> {
         node.downcast_ops::<Arc<FuseNode>>().ok_or_else(|| errno!(ENOENT))
     }
 
-    fn refresh_node_info(info: &mut FsNodeInfo, attributes: uapi::fuse_attr) -> Result<(), Errno> {
+    fn refresh_expired_node_attributes<'a>(
+        &self,
+        current_task: &CurrentTask,
+        info: &'a RwLock<FsNodeInfo>,
+    ) -> Result<RwLockReadGuard<'a, FsNodeInfo>, Errno> {
+        // Relaxed because the attributes valid until atomic is not used to synchronize
+        // anything. Its final access is protected by the info lock anyways.
+        const VALID_UNTIL_LOAD_ORDERING: Ordering = Ordering::Relaxed;
+
+        let now = zx::Time::get_monotonic();
+        if self.attributes_valid_until.load(VALID_UNTIL_LOAD_ORDERING) >= now {
+            let info = info.read();
+
+            // Check the valid_until again after taking the info lock to make sure
+            // that the attributes are still valid. We do this because after we
+            // checked the first time and now, the node's attributes could have been
+            // invalidated or expired.
+            //
+            // But why not only check if the attributes are valid after taking the
+            // lock? Because when we will impact FUSE implementations that don't
+            // support caching, or caching with small valid durations, by always
+            // taking a read lock which we then drop to acquire a write lock. We
+            // slightly pessimize the "happy" path with an extra atomic load so
+            // that we don't overly pessimize the uncached/"slower" path.
+            if self.attributes_valid_until.load(VALID_UNTIL_LOAD_ORDERING) >= now {
+                return Ok(info);
+            }
+        }
+
+        // Force a refresh of our cached attributes.
+        self.fetch_and_refresh_info_impl(current_task, info)
+    }
+
+    fn fetch_and_refresh_info_impl<'a>(
+        &self,
+        current_task: &CurrentTask,
+        info: &'a RwLock<FsNodeInfo>,
+    ) -> Result<RwLockReadGuard<'a, FsNodeInfo>, Errno> {
+        let response =
+            self.connection.lock().execute_operation(current_task, self, FuseOperation::GetAttr)?;
+        let uapi::fuse_attr_out { attr_valid, attr_valid_nsec, attr, .. } =
+            if let FuseResponse::Attr(attr) = response {
+                attr
+            } else {
+                return error!(EINVAL);
+            };
+        let mut info = info.write();
+        FuseNode::set_node_info(
+            &mut info,
+            attr,
+            attr_valid_to_duration(attr_valid, attr_valid_nsec)?,
+            &self.attributes_valid_until,
+        )?;
+        Ok(RwLockWriteGuard::downgrade(info))
+    }
+
+    fn set_node_info(
+        info: &mut FsNodeInfo,
+        attributes: uapi::fuse_attr,
+        attr_valid_duration: zx::Duration,
+        node_attributes_valid_until: &AtomicTime,
+    ) -> Result<(), Errno> {
         info.ino = attributes.ino as uapi::ino_t;
         info.mode = FileMode::from_bits(attributes.mode);
         info.size = attributes.size.try_into().map_err(|_| errno!(EINVAL))?;
@@ -472,6 +554,8 @@
             tv_nsec: attributes.mtimensec as i64,
         })?;
         info.rdev = DeviceType::from_bits(attributes.rdev as u64);
+
+        node_attributes_valid_until.store(zx::Time::after(attr_valid_duration), Ordering::Relaxed);
         Ok(())
     }
 
@@ -492,13 +576,14 @@
             return error!(ENOENT);
         }
         let node = node.fs().get_or_create_node(current_task, Some(entry.nodeid), |id| {
-            let fuse_node = Arc::new(FuseNode {
-                connection: self.connection.clone(),
-                nodeid: entry.nodeid,
-                state: Default::default(),
-            });
+            let fuse_node = FuseNode::new(self.connection.clone(), entry.nodeid);
             let mut info = FsNodeInfo::default();
-            FuseNode::refresh_node_info(&mut info, entry.attr)?;
+            FuseNode::set_node_info(
+                &mut info,
+                entry.attr,
+                attr_valid_to_duration(entry.attr_valid, entry.attr_valid_nsec)?,
+                &fuse_node.attributes_valid_until,
+            )?;
             Ok(FsNode::new_uncached(current_task, fuse_node, &node.fs(), id, info))
         })?;
         // . and .. do not get their lookup count increased.
@@ -708,6 +793,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
@@ -813,6 +899,9 @@
     }
 }
 
+// `FuseFs.default_permissions` is not used to synchronize anything.
+const DEFAULT_PERMISSIONS_ATOMIC_ORDERING: Ordering = Ordering::Relaxed;
+
 impl FsNodeOps for Arc<FuseNode> {
     fn check_access(
         &self,
@@ -821,8 +910,12 @@
         access: Access,
         info: &RwLock<FsNodeInfo>,
     ) -> Result<(), Errno> {
-        if FuseFs::from_fs(&node.fs())?.default_permissions {
-            return node.default_check_access_impl(current_task, access, info.read());
+        if FuseFs::from_fs(&node.fs())?
+            .default_permissions
+            .load(DEFAULT_PERMISSIONS_ATOMIC_ORDERING)
+        {
+            let info = self.refresh_expired_node_attributes(current_task, info)?;
+            return node.default_check_access_impl(current_task, access, info);
         }
 
         let response = self.connection.lock().execute_operation(
@@ -902,6 +995,7 @@
 
     fn mkdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         name: &FsStr,
@@ -924,6 +1018,7 @@
 
     fn create_symlink(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         node: &FsNode,
         current_task: &CurrentTask,
         name: &FsStr,
@@ -1008,12 +1103,18 @@
                 self,
                 FuseOperation::SetAttr(attributes),
             )?;
-            let attr = if let FuseResponse::Attr(attr) = response {
-                attr
-            } else {
-                return error!(EINVAL);
-            };
-            FuseNode::refresh_node_info(info, attr.attr)?;
+            let uapi::fuse_attr_out { attr_valid, attr_valid_nsec, attr, .. } =
+                if let FuseResponse::Attr(attr) = response {
+                    attr
+                } else {
+                    return error!(EINVAL);
+                };
+            FuseNode::set_node_info(
+                info,
+                attr,
+                attr_valid_to_duration(attr_valid, attr_valid_nsec)?,
+                &self.attributes_valid_until,
+            )?;
             Ok(())
         })
     }
@@ -1031,22 +1132,13 @@
         error!(ENOTSUP)
     }
 
-    fn refresh_info<'a>(
+    fn fetch_and_refresh_info<'a>(
         &self,
         _node: &FsNode,
         current_task: &CurrentTask,
         info: &'a RwLock<FsNodeInfo>,
     ) -> Result<RwLockReadGuard<'a, FsNodeInfo>, Errno> {
-        let response =
-            self.connection.lock().execute_operation(current_task, self, FuseOperation::GetAttr)?;
-        let attr = if let FuseResponse::Attr(attr) = response {
-            attr
-        } else {
-            return error!(EINVAL);
-        };
-        let mut info = info.write();
-        FuseNode::refresh_node_info(&mut info, attr.attr)?;
-        Ok(RwLockWriteGuard::downgrade(info))
+        self.fetch_and_refresh_info_impl(current_task, info)
     }
 
     fn get_xattr(
@@ -1250,12 +1342,13 @@
 }
 
 impl<'a> FuseMutableStateGuard<'a> {
-    fn get_configuration(
+    fn wait_for_configuration<T>(
         &mut self,
         current_task: &CurrentTask,
-    ) -> Result<FuseConfiguration, Errno> {
+        f: impl Fn(&FuseConfiguration) -> T,
+    ) -> Result<T, Errno> {
         if let Some(configuration) = self.configuration.as_ref() {
-            return Ok(configuration.clone());
+            return Ok(f(configuration));
         }
         loop {
             if !self.is_connected() {
@@ -1264,12 +1357,23 @@
             let waiter = Waiter::new();
             self.waiters.wait_async_value(&waiter, CONFIGURATION_AVAILABLE_EVENT);
             if let Some(configuration) = self.configuration.as_ref() {
-                return Ok(configuration.clone());
+                return Ok(f(configuration));
             }
             Self::unlocked(self, || waiter.wait(current_task))?;
         }
     }
 
+    fn get_configuration(
+        &mut self,
+        current_task: &CurrentTask,
+    ) -> Result<FuseConfiguration, Errno> {
+        self.wait_for_configuration(current_task, Clone::clone)
+    }
+
+    fn wait_for_configuration_ready(&mut self, current_task: &CurrentTask) -> Result<(), Errno> {
+        self.wait_for_configuration(current_task, |_| ())
+    }
+
     /// Execute the given operation on the `node`. If the operation is not asynchronous, this
     /// method will wait on the userspace process for a response. If the operation is interrupted,
     /// an interrupt will be sent to the userspace process and the operation will then block until
@@ -1281,6 +1385,14 @@
         node: &FuseNode,
         operation: FuseOperation,
     ) -> Result<FuseResponse, Errno> {
+        // Block until we have a valid configuration to make sure that the FUSE
+        // implementation has initialized, indicated by its response to the
+        // `FUSE_INIT` request. Obviously, we skip this check for the `FUSE_INIT`
+        // request itself.
+        if !matches!(operation, FuseOperation::Init { .. }) {
+            self.wait_for_configuration_ready(current_task)?;
+        }
+
         if let Some(result) = self.operations_state.get(&operation.opcode()) {
             return result.clone();
         }
@@ -1472,7 +1584,7 @@
             Entry::Occupied(e) => e,
             Entry::Vacant(_) => return error!(EINVAL),
         };
-        let operation = running_operation.get().operation;
+        let operation = &running_operation.get().operation;
         let is_async = operation.is_async();
         if header.error < 0 {
             log_trace!("Fuse: {operation:?} -> {header:?}");
@@ -1492,19 +1604,46 @@
             let response = operation.parse_response(buffer)?;
             log_trace!("Fuse: {operation:?} -> {response:?}");
             if is_async {
-                if let FuseResponse::Init(init_out) = response {
-                    running_operation.remove();
-                    self.set_configuration(init_out.try_into()?);
-                } else {
-                    // Init is the only async operation.
-                    return error!(EINVAL);
-                }
+                let operation = running_operation.remove();
+                self.handle_async(operation, response)?;
             } else {
                 running_operation.get_mut().response = Some(Ok(response));
             }
         }
         Ok(data.bytes_read())
     }
+
+    fn handle_async(
+        &mut self,
+        operation: RunningOperation,
+        response: FuseResponse,
+    ) -> Result<(), Errno> {
+        match (operation.operation, response) {
+            (RunningOperationKind::Init { fs }, FuseResponse::Init(init_out)) => {
+                let configuration = FuseConfiguration::try_from(init_out)?;
+                if configuration.flags.contains(FuseInitFlags::POSIX_ACL) {
+                    // Per libfuse's documentation on `FUSE_CAP_POSIX_ACL`,
+                    // the POSIX_ACL flag implicitly enables the
+                    // `default_permissions` mount option.
+                    if let Some(fs) = fs.upgrade() {
+                        FuseFs::from_fs(&fs)
+                            .expect("should only perform FUSE ops with FUSE fs")
+                            .default_permissions
+                            .store(true, DEFAULT_PERMISSIONS_ATOMIC_ORDERING)
+                    } else {
+                        log_warn!("failed to upgrade FuseFs when handling FUSE_INIT response");
+                        return error!(ENOTCONN);
+                    }
+                }
+                self.set_configuration(configuration);
+                Ok(())
+            }
+            operation => {
+                // Init is the only async operation.
+                panic!("Incompatible operation={operation:?}");
+            }
+        }
+    }
 }
 
 /// An operation that is either queued to be send to userspace, or already sent to userspace and
@@ -1521,12 +1660,6 @@
     }
 }
 
-impl RunningOperationKind {
-    fn is_async(&self) -> bool {
-        matches!(self, Self::Init)
-    }
-}
-
 #[derive(Debug)]
 struct FuseKernelMessage {
     header: uapi::fuse_in_header,
@@ -1575,29 +1708,46 @@
         const DO_READDIRPLUS = uapi::FUSE_DO_READDIRPLUS;
         const READDIRPLUS_AUTO = uapi::FUSE_READDIRPLUS_AUTO;
         const SETXATTR_EXT = uapi::FUSE_SETXATTR_EXT;
+        const POSIX_ACL = uapi::FUSE_POSIX_ACL;
     }
 }
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Clone, Debug)]
 enum RunningOperationKind {
     Access,
     Flush,
     Forget,
     GetAttr,
-    Init,
+    Init {
+        /// The FUSE fs that triggered this operation.
+        ///
+        /// `Weak` because the `FuseFs` holds an `Arc<FuseConnection>` which
+        /// may hold this operation.
+        fs: Weak<FileSystem>,
+    },
     Interrupt,
-    GetXAttr { size: u32 },
-    ListXAttr { size: u32 },
+    GetXAttr {
+        size: u32,
+    },
+    ListXAttr {
+        size: u32,
+    },
     Lookup,
     Mkdir,
     Mknod,
     Link,
-    Open { dir: bool },
+    Open {
+        dir: bool,
+    },
     Poll,
     Read,
-    Readdir { use_readdirplus: bool },
+    Readdir {
+        use_readdirplus: bool,
+    },
     Readlink,
-    Release { dir: bool },
+    Release {
+        dir: bool,
+    },
     RemoveXAttr,
     Seek,
     SetAttr,
@@ -1609,6 +1759,10 @@
 }
 
 impl RunningOperationKind {
+    fn is_async(&self) -> bool {
+        matches!(self, Self::Init { .. })
+    }
+
     fn opcode(&self) -> u32 {
         match self {
             Self::Access => uapi::fuse_opcode_FUSE_ACCESS,
@@ -1616,7 +1770,7 @@
             Self::Forget => uapi::fuse_opcode_FUSE_FORGET,
             Self::GetAttr => uapi::fuse_opcode_FUSE_GETATTR,
             Self::GetXAttr { .. } => uapi::fuse_opcode_FUSE_GETXATTR,
-            Self::Init => uapi::fuse_opcode_FUSE_INIT,
+            Self::Init { .. } => uapi::fuse_opcode_FUSE_INIT,
             Self::Interrupt => uapi::fuse_opcode_FUSE_INTERRUPT,
             Self::ListXAttr { .. } => uapi::fuse_opcode_FUSE_LISTXATTR,
             Self::Lookup => uapi::fuse_opcode_FUSE_LOOKUP,
@@ -1682,7 +1836,9 @@
                     Ok(FuseResponse::GetXAttr(FsString::new(buffer).into()))
                 }
             }
-            Self::Init => Ok(FuseResponse::Init(Self::to_response::<uapi::fuse_init_out>(&buffer))),
+            Self::Init { .. } => {
+                Ok(FuseResponse::Init(Self::to_response::<uapi::fuse_init_out>(&buffer)))
+            }
             Self::Lookup | Self::Mkdir | Self::Mknod | Self::Link | Self::Symlink => {
                 Ok(FuseResponse::Entry(Self::to_response::<uapi::fuse_entry_out>(&buffer)))
             }
@@ -1796,7 +1952,13 @@
     Flush(uapi::fuse_open_out),
     Forget(uapi::fuse_forget_in),
     GetAttr,
-    Init,
+    Init {
+        /// The FUSE fs that triggered this operation.
+        ///
+        /// `Weak` because the `FuseFs` holds an `Arc<FuseConnection>` which
+        /// may hold this operation.
+        fs: Weak<FileSystem>,
+    },
     Interrupt {
         /// Identifier of the operation to interrupt
         unique_id: u64,
@@ -1916,7 +2078,7 @@
                 len += Self::write_null_terminated(data, name)?;
                 Ok(len)
             }
-            Self::Init => {
+            Self::Init { .. } => {
                 let message = uapi::fuse_init_in {
                     major: uapi::FUSE_KERNEL_VERSION,
                     minor: uapi::FUSE_KERNEL_MINOR_VERSION,
@@ -2004,7 +2166,7 @@
             Self::Forget(_) => uapi::fuse_opcode_FUSE_FORGET,
             Self::GetAttr => uapi::fuse_opcode_FUSE_GETATTR,
             Self::GetXAttr { .. } => uapi::fuse_opcode_FUSE_GETXATTR,
-            Self::Init => uapi::fuse_opcode_FUSE_INIT,
+            Self::Init { .. } => uapi::fuse_opcode_FUSE_INIT,
             Self::Interrupt { .. } => uapi::fuse_opcode_FUSE_INTERRUPT,
             Self::ListXAttr(_) => uapi::fuse_opcode_FUSE_LISTXATTR,
             Self::Lookup { .. } => uapi::fuse_opcode_FUSE_LOOKUP,
@@ -2055,7 +2217,7 @@
             Self::GetXAttr { getxattr_in, .. } => {
                 RunningOperationKind::GetXAttr { size: getxattr_in.size }
             }
-            Self::Init => RunningOperationKind::Init,
+            Self::Init { fs } => RunningOperationKind::Init { fs: fs.clone() },
             Self::Interrupt { .. } => RunningOperationKind::Interrupt,
             Self::ListXAttr(getxattr_in) => {
                 RunningOperationKind::ListXAttr { size: getxattr_in.size }
@@ -2146,6 +2308,6 @@
     }
 
     fn is_async(&self) -> bool {
-        matches!(self, Self::Init)
+        matches!(self, Self::Init { .. })
     }
 }
diff --git a/src/starnix/kernel/vfs/namespace.rs b/src/starnix/kernel/vfs/namespace.rs
index 71ab34b..069148f 100644
--- a/src/starnix/kernel/vfs/namespace.rs
+++ b/src/starnix/kernel/vfs/namespace.rs
@@ -10,7 +10,7 @@
         overlayfs::OverlayFs, proc::proc_fs, sysfs::sys_fs, tmpfs::TmpFs, tracefs::trace_fs,
     },
     mutable_state::{state_accessor, state_implementation},
-    selinux::fs::selinux_fs,
+    security::fs::selinux_fs,
     task::{CurrentTask, EventHandler, Kernel, Task, WaitCanceler, Waiter},
     time::utc,
     vfs::{
@@ -1130,16 +1130,20 @@
     /// Create a symlink in the file system.
     ///
     /// To create another type of node, use `create_node`.
-    pub fn create_symlink(
+    pub fn create_symlink<L>(
         &self,
+        locked: &mut Locked<'_, L>,
         current_task: &CurrentTask,
         name: &FsStr,
         target: &FsStr,
-    ) -> Result<NamespaceNode, Errno> {
+    ) -> Result<NamespaceNode, Errno>
+    where
+        L: LockBefore<FileOpsCore>,
+    {
         let owner = current_task.as_fscred();
         let entry =
             self.entry.create_entry(current_task, &self.mount, name, |dir, mount, name| {
-                dir.create_symlink(current_task, mount, name, target, owner)
+                dir.create_symlink(locked, current_task, mount, name, target, owner)
             })?;
         Ok(self.with_new_entry(entry))
     }
diff --git a/src/starnix/kernel/vfs/static_directory.rs b/src/starnix/kernel/vfs/static_directory.rs
index 1006213..e582d3f 100644
--- a/src/starnix/kernel/vfs/static_directory.rs
+++ b/src/starnix/kernel/vfs/static_directory.rs
@@ -207,6 +207,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         _current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
diff --git a/src/starnix/kernel/vfs/syscalls.rs b/src/starnix/kernel/vfs/syscalls.rs
index 6c1eb5b..8f7c5df 100644
--- a/src/starnix/kernel/vfs/syscalls.rs
+++ b/src/starnix/kernel/vfs/syscalls.rs
@@ -755,7 +755,7 @@
 }
 
 pub fn sys_getdents64(
-    _locked: &mut Locked<'_, Unlocked>,
+    locked: &mut Locked<'_, Unlocked>,
     current_task: &CurrentTask,
     fd: FdNumber,
     user_buffer: UserAddress,
@@ -764,7 +764,7 @@
     let file = current_task.files.get(fd)?;
     let mut offset = file.offset.lock();
     let mut sink = DirentSink64::new(current_task, &mut offset, user_buffer, user_capacity);
-    let result = file.readdir(current_task, &mut sink);
+    let result = file.readdir(locked, current_task, &mut sink);
     sink.map_result_with_actual(result)
 }
 
@@ -1508,7 +1508,7 @@
         current_task,
         new_dir_fd,
         user_path,
-        |_, context, parent, basename| {
+        |locked, context, parent, basename| {
             // The path to a new symlink cannot end in `/`. That would imply that we are dereferencing
             // the symlink to a directory.
             //
@@ -1516,7 +1516,7 @@
             if context.must_be_directory {
                 return error!(ENOENT);
             }
-            parent.create_symlink(current_task, basename, target.as_ref())
+            parent.create_symlink(locked, current_task, basename, target.as_ref())
         },
     );
     res?;
diff --git a/src/starnix/kernel/vfs/vec_directory.rs b/src/starnix/kernel/vfs/vec_directory.rs
index d98639d..d5faf11 100644
--- a/src/starnix/kernel/vfs/vec_directory.rs
+++ b/src/starnix/kernel/vfs/vec_directory.rs
@@ -9,6 +9,7 @@
         FileObject, FileOps, FsString, SeekTarget,
     },
 };
+use starnix_sync::{FileOpsCore, Locked};
 use starnix_uapi::{errors::Errno, ino_t, off_t};
 
 /// A directory entry used for [`VecDirectory`].
@@ -48,6 +49,7 @@
 
     fn readdir(
         &self,
+        _locked: &mut Locked<'_, FileOpsCore>,
         file: &FileObject,
         _current_task: &CurrentTask,
         sink: &mut dyn DirentSink,
diff --git a/src/starnix/lib/linux_uapi/src/arm64.rs b/src/starnix/lib/linux_uapi/src/arm64.rs
index ff14cc4..8556263 100644
--- a/src/starnix/lib/linux_uapi/src/arm64.rs
+++ b/src/starnix/lib/linux_uapi/src/arm64.rs
@@ -3413,6 +3413,9 @@
 pub const NOTIFY_WOKENUP: u32 = 1;
 pub const NOTIFY_REMOVED: u32 = 2;
 pub const NOTIFY_COOKIE_LEN: u32 = 32;
+pub const AF_UNSPEC: u32 = 0;
+pub const AF_INET: u32 = 2;
+pub const AF_INET6: u32 = 10;
 pub const IFNAMSIZ: u32 = 16;
 pub const IFALIASZ: u32 = 256;
 pub const ALTIFNAMSIZ: u32 = 128;
@@ -4221,6 +4224,144 @@
 pub const RLIMIT_RTTIME: u32 = 15;
 pub const RLIM_NLIMITS: u32 = 16;
 pub const RLIM_INFINITY: i32 = -1;
+pub const MACVLAN_FLAG_NOPROMISC: u32 = 1;
+pub const MACVLAN_FLAG_NODST: u32 = 2;
+pub const IPVLAN_F_PRIVATE: u32 = 1;
+pub const IPVLAN_F_VEPA: u32 = 2;
+pub const TUNNEL_MSG_FLAG_STATS: u32 = 1;
+pub const TUNNEL_MSG_VALID_USER_FLAGS: u32 = 1;
+pub const MAX_VLAN_LIST_LEN: u32 = 1;
+pub const PORT_PROFILE_MAX: u32 = 40;
+pub const PORT_UUID_MAX: u32 = 16;
+pub const PORT_SELF_VF: i32 = -1;
+pub const XDP_FLAGS_UPDATE_IF_NOEXIST: u32 = 1;
+pub const XDP_FLAGS_SKB_MODE: u32 = 2;
+pub const XDP_FLAGS_DRV_MODE: u32 = 4;
+pub const XDP_FLAGS_HW_MODE: u32 = 8;
+pub const XDP_FLAGS_REPLACE: u32 = 16;
+pub const XDP_FLAGS_MODES: u32 = 14;
+pub const XDP_FLAGS_MASK: u32 = 31;
+pub const RMNET_FLAGS_INGRESS_DEAGGREGATION: u32 = 1;
+pub const RMNET_FLAGS_INGRESS_MAP_COMMANDS: u32 = 2;
+pub const RMNET_FLAGS_INGRESS_MAP_CKSUMV4: u32 = 4;
+pub const RMNET_FLAGS_EGRESS_MAP_CKSUMV4: u32 = 8;
+pub const RMNET_FLAGS_INGRESS_MAP_CKSUMV5: u32 = 16;
+pub const RMNET_FLAGS_EGRESS_MAP_CKSUMV5: u32 = 32;
+pub const IFA_F_SECONDARY: u32 = 1;
+pub const IFA_F_TEMPORARY: u32 = 1;
+pub const IFA_F_NODAD: u32 = 2;
+pub const IFA_F_OPTIMISTIC: u32 = 4;
+pub const IFA_F_DADFAILED: u32 = 8;
+pub const IFA_F_HOMEADDRESS: u32 = 16;
+pub const IFA_F_DEPRECATED: u32 = 32;
+pub const IFA_F_TENTATIVE: u32 = 64;
+pub const IFA_F_PERMANENT: u32 = 128;
+pub const IFA_F_MANAGETEMPADDR: u32 = 256;
+pub const IFA_F_NOPREFIXROUTE: u32 = 512;
+pub const IFA_F_MCAUTOJOIN: u32 = 1024;
+pub const IFA_F_STABLE_PRIVACY: u32 = 2048;
+pub const IFAPROT_UNSPEC: u32 = 0;
+pub const IFAPROT_KERNEL_LO: u32 = 1;
+pub const IFAPROT_KERNEL_RA: u32 = 2;
+pub const IFAPROT_KERNEL_LL: u32 = 3;
+pub const NTF_USE: u32 = 1;
+pub const NTF_SELF: u32 = 2;
+pub const NTF_MASTER: u32 = 4;
+pub const NTF_PROXY: u32 = 8;
+pub const NTF_EXT_LEARNED: u32 = 16;
+pub const NTF_OFFLOADED: u32 = 32;
+pub const NTF_STICKY: u32 = 64;
+pub const NTF_ROUTER: u32 = 128;
+pub const NTF_EXT_MANAGED: u32 = 1;
+pub const NTF_EXT_LOCKED: u32 = 2;
+pub const NUD_INCOMPLETE: u32 = 1;
+pub const NUD_REACHABLE: u32 = 2;
+pub const NUD_STALE: u32 = 4;
+pub const NUD_DELAY: u32 = 8;
+pub const NUD_PROBE: u32 = 16;
+pub const NUD_FAILED: u32 = 32;
+pub const NUD_NOARP: u32 = 64;
+pub const NUD_PERMANENT: u32 = 128;
+pub const NUD_NONE: u32 = 0;
+pub const RTNL_FAMILY_IPMR: u32 = 128;
+pub const RTNL_FAMILY_IP6MR: u32 = 129;
+pub const RTNL_FAMILY_MAX: u32 = 129;
+pub const RTA_ALIGNTO: u32 = 4;
+pub const RTPROT_UNSPEC: u32 = 0;
+pub const RTPROT_REDIRECT: u32 = 1;
+pub const RTPROT_KERNEL: u32 = 2;
+pub const RTPROT_BOOT: u32 = 3;
+pub const RTPROT_STATIC: u32 = 4;
+pub const RTPROT_GATED: u32 = 8;
+pub const RTPROT_RA: u32 = 9;
+pub const RTPROT_MRT: u32 = 10;
+pub const RTPROT_ZEBRA: u32 = 11;
+pub const RTPROT_BIRD: u32 = 12;
+pub const RTPROT_DNROUTED: u32 = 13;
+pub const RTPROT_XORP: u32 = 14;
+pub const RTPROT_NTK: u32 = 15;
+pub const RTPROT_DHCP: u32 = 16;
+pub const RTPROT_MROUTED: u32 = 17;
+pub const RTPROT_KEEPALIVED: u32 = 18;
+pub const RTPROT_BABEL: u32 = 42;
+pub const RTPROT_OPENR: u32 = 99;
+pub const RTPROT_BGP: u32 = 186;
+pub const RTPROT_ISIS: u32 = 187;
+pub const RTPROT_OSPF: u32 = 188;
+pub const RTPROT_RIP: u32 = 189;
+pub const RTPROT_EIGRP: u32 = 192;
+pub const RTM_F_NOTIFY: u32 = 256;
+pub const RTM_F_CLONED: u32 = 512;
+pub const RTM_F_EQUALIZE: u32 = 1024;
+pub const RTM_F_PREFIX: u32 = 2048;
+pub const RTM_F_LOOKUP_TABLE: u32 = 4096;
+pub const RTM_F_FIB_MATCH: u32 = 8192;
+pub const RTM_F_OFFLOAD: u32 = 16384;
+pub const RTM_F_TRAP: u32 = 32768;
+pub const RTM_F_OFFLOAD_FAILED: u32 = 536870912;
+pub const RTNH_F_DEAD: u32 = 1;
+pub const RTNH_F_PERVASIVE: u32 = 2;
+pub const RTNH_F_ONLINK: u32 = 4;
+pub const RTNH_F_OFFLOAD: u32 = 8;
+pub const RTNH_F_LINKDOWN: u32 = 16;
+pub const RTNH_F_UNRESOLVED: u32 = 32;
+pub const RTNH_F_TRAP: u32 = 64;
+pub const RTNH_COMPARE_MASK: u32 = 89;
+pub const RTNH_ALIGNTO: u32 = 4;
+pub const RTNETLINK_HAVE_PEERINFO: u32 = 1;
+pub const RTAX_FEATURE_ECN: u32 = 1;
+pub const RTAX_FEATURE_SACK: u32 = 2;
+pub const RTAX_FEATURE_TIMESTAMP: u32 = 4;
+pub const RTAX_FEATURE_ALLFRAG: u32 = 8;
+pub const RTAX_FEATURE_MASK: u32 = 15;
+pub const TCM_IFINDEX_MAGIC_BLOCK: u32 = 4294967295;
+pub const TCA_DUMP_FLAGS_TERSE: u32 = 1;
+pub const RTMGRP_LINK: u32 = 1;
+pub const RTMGRP_NOTIFY: u32 = 2;
+pub const RTMGRP_NEIGH: u32 = 4;
+pub const RTMGRP_TC: u32 = 8;
+pub const RTMGRP_IPV4_IFADDR: u32 = 16;
+pub const RTMGRP_IPV4_MROUTE: u32 = 32;
+pub const RTMGRP_IPV4_ROUTE: u32 = 64;
+pub const RTMGRP_IPV4_RULE: u32 = 128;
+pub const RTMGRP_IPV6_IFADDR: u32 = 256;
+pub const RTMGRP_IPV6_MROUTE: u32 = 512;
+pub const RTMGRP_IPV6_ROUTE: u32 = 1024;
+pub const RTMGRP_IPV6_IFINFO: u32 = 2048;
+pub const RTMGRP_DECnet_IFADDR: u32 = 4096;
+pub const RTMGRP_DECnet_ROUTE: u32 = 16384;
+pub const RTMGRP_IPV6_PREFIX: u32 = 131072;
+pub const TCA_FLAG_LARGE_DUMP_ON: u32 = 1;
+pub const TCA_ACT_FLAG_LARGE_DUMP_ON: u32 = 1;
+pub const TCA_ACT_FLAG_TERSE_DUMP: u32 = 2;
+pub const RTEXT_FILTER_VF: u32 = 1;
+pub const RTEXT_FILTER_BRVLAN: u32 = 2;
+pub const RTEXT_FILTER_BRVLAN_COMPRESSED: u32 = 4;
+pub const RTEXT_FILTER_SKIP_STATS: u32 = 8;
+pub const RTEXT_FILTER_MRP: u32 = 16;
+pub const RTEXT_FILTER_CFM_CONFIG: u32 = 32;
+pub const RTEXT_FILTER_CFM_STATUS: u32 = 64;
+pub const RTEXT_FILTER_MST: u32 = 128;
 pub const CSIGNAL: u32 = 255;
 pub const CLONE_VM: u32 = 256;
 pub const CLONE_FS: u32 = 512;
@@ -14332,6 +14473,1388 @@
 }
 #[repr(C)]
 #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_stats {
+    pub rx_packets: __u32,
+    pub tx_packets: __u32,
+    pub rx_bytes: __u32,
+    pub tx_bytes: __u32,
+    pub rx_errors: __u32,
+    pub tx_errors: __u32,
+    pub rx_dropped: __u32,
+    pub tx_dropped: __u32,
+    pub multicast: __u32,
+    pub collisions: __u32,
+    pub rx_length_errors: __u32,
+    pub rx_over_errors: __u32,
+    pub rx_crc_errors: __u32,
+    pub rx_frame_errors: __u32,
+    pub rx_fifo_errors: __u32,
+    pub rx_missed_errors: __u32,
+    pub tx_aborted_errors: __u32,
+    pub tx_carrier_errors: __u32,
+    pub tx_fifo_errors: __u32,
+    pub tx_heartbeat_errors: __u32,
+    pub tx_window_errors: __u32,
+    pub rx_compressed: __u32,
+    pub tx_compressed: __u32,
+    pub rx_nohandler: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_stats64 {
+    pub rx_packets: __u64,
+    pub tx_packets: __u64,
+    pub rx_bytes: __u64,
+    pub tx_bytes: __u64,
+    pub rx_errors: __u64,
+    pub tx_errors: __u64,
+    pub rx_dropped: __u64,
+    pub tx_dropped: __u64,
+    pub multicast: __u64,
+    pub collisions: __u64,
+    pub rx_length_errors: __u64,
+    pub rx_over_errors: __u64,
+    pub rx_crc_errors: __u64,
+    pub rx_frame_errors: __u64,
+    pub rx_fifo_errors: __u64,
+    pub rx_missed_errors: __u64,
+    pub tx_aborted_errors: __u64,
+    pub tx_carrier_errors: __u64,
+    pub tx_fifo_errors: __u64,
+    pub tx_heartbeat_errors: __u64,
+    pub tx_window_errors: __u64,
+    pub rx_compressed: __u64,
+    pub tx_compressed: __u64,
+    pub rx_nohandler: __u64,
+    pub rx_otherhost_dropped: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_hw_stats64 {
+    pub rx_packets: __u64,
+    pub tx_packets: __u64,
+    pub rx_bytes: __u64,
+    pub tx_bytes: __u64,
+    pub rx_errors: __u64,
+    pub tx_errors: __u64,
+    pub rx_dropped: __u64,
+    pub tx_dropped: __u64,
+    pub multicast: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_ifmap {
+    pub mem_start: __u64,
+    pub mem_end: __u64,
+    pub base_addr: __u64,
+    pub irq: __u16,
+    pub dma: __u8,
+    pub port: __u8,
+    pub __bindgen_padding_0: [u8; 4usize],
+}
+pub const IFLA_UNSPEC: _bindgen_ty_61 = 0;
+pub const IFLA_ADDRESS: _bindgen_ty_61 = 1;
+pub const IFLA_BROADCAST: _bindgen_ty_61 = 2;
+pub const IFLA_IFNAME: _bindgen_ty_61 = 3;
+pub const IFLA_MTU: _bindgen_ty_61 = 4;
+pub const IFLA_LINK: _bindgen_ty_61 = 5;
+pub const IFLA_QDISC: _bindgen_ty_61 = 6;
+pub const IFLA_STATS: _bindgen_ty_61 = 7;
+pub const IFLA_COST: _bindgen_ty_61 = 8;
+pub const IFLA_PRIORITY: _bindgen_ty_61 = 9;
+pub const IFLA_MASTER: _bindgen_ty_61 = 10;
+pub const IFLA_WIRELESS: _bindgen_ty_61 = 11;
+pub const IFLA_PROTINFO: _bindgen_ty_61 = 12;
+pub const IFLA_TXQLEN: _bindgen_ty_61 = 13;
+pub const IFLA_MAP: _bindgen_ty_61 = 14;
+pub const IFLA_WEIGHT: _bindgen_ty_61 = 15;
+pub const IFLA_OPERSTATE: _bindgen_ty_61 = 16;
+pub const IFLA_LINKMODE: _bindgen_ty_61 = 17;
+pub const IFLA_LINKINFO: _bindgen_ty_61 = 18;
+pub const IFLA_NET_NS_PID: _bindgen_ty_61 = 19;
+pub const IFLA_IFALIAS: _bindgen_ty_61 = 20;
+pub const IFLA_NUM_VF: _bindgen_ty_61 = 21;
+pub const IFLA_VFINFO_LIST: _bindgen_ty_61 = 22;
+pub const IFLA_STATS64: _bindgen_ty_61 = 23;
+pub const IFLA_VF_PORTS: _bindgen_ty_61 = 24;
+pub const IFLA_PORT_SELF: _bindgen_ty_61 = 25;
+pub const IFLA_AF_SPEC: _bindgen_ty_61 = 26;
+pub const IFLA_GROUP: _bindgen_ty_61 = 27;
+pub const IFLA_NET_NS_FD: _bindgen_ty_61 = 28;
+pub const IFLA_EXT_MASK: _bindgen_ty_61 = 29;
+pub const IFLA_PROMISCUITY: _bindgen_ty_61 = 30;
+pub const IFLA_NUM_TX_QUEUES: _bindgen_ty_61 = 31;
+pub const IFLA_NUM_RX_QUEUES: _bindgen_ty_61 = 32;
+pub const IFLA_CARRIER: _bindgen_ty_61 = 33;
+pub const IFLA_PHYS_PORT_ID: _bindgen_ty_61 = 34;
+pub const IFLA_CARRIER_CHANGES: _bindgen_ty_61 = 35;
+pub const IFLA_PHYS_SWITCH_ID: _bindgen_ty_61 = 36;
+pub const IFLA_LINK_NETNSID: _bindgen_ty_61 = 37;
+pub const IFLA_PHYS_PORT_NAME: _bindgen_ty_61 = 38;
+pub const IFLA_PROTO_DOWN: _bindgen_ty_61 = 39;
+pub const IFLA_GSO_MAX_SEGS: _bindgen_ty_61 = 40;
+pub const IFLA_GSO_MAX_SIZE: _bindgen_ty_61 = 41;
+pub const IFLA_PAD: _bindgen_ty_61 = 42;
+pub const IFLA_XDP: _bindgen_ty_61 = 43;
+pub const IFLA_EVENT: _bindgen_ty_61 = 44;
+pub const IFLA_NEW_NETNSID: _bindgen_ty_61 = 45;
+pub const IFLA_IF_NETNSID: _bindgen_ty_61 = 46;
+pub const IFLA_TARGET_NETNSID: _bindgen_ty_61 = 46;
+pub const IFLA_CARRIER_UP_COUNT: _bindgen_ty_61 = 47;
+pub const IFLA_CARRIER_DOWN_COUNT: _bindgen_ty_61 = 48;
+pub const IFLA_NEW_IFINDEX: _bindgen_ty_61 = 49;
+pub const IFLA_MIN_MTU: _bindgen_ty_61 = 50;
+pub const IFLA_MAX_MTU: _bindgen_ty_61 = 51;
+pub const IFLA_PROP_LIST: _bindgen_ty_61 = 52;
+pub const IFLA_ALT_IFNAME: _bindgen_ty_61 = 53;
+pub const IFLA_PERM_ADDRESS: _bindgen_ty_61 = 54;
+pub const IFLA_PROTO_DOWN_REASON: _bindgen_ty_61 = 55;
+pub const IFLA_PARENT_DEV_NAME: _bindgen_ty_61 = 56;
+pub const IFLA_PARENT_DEV_BUS_NAME: _bindgen_ty_61 = 57;
+pub const IFLA_GRO_MAX_SIZE: _bindgen_ty_61 = 58;
+pub const IFLA_TSO_MAX_SIZE: _bindgen_ty_61 = 59;
+pub const IFLA_TSO_MAX_SEGS: _bindgen_ty_61 = 60;
+pub const IFLA_ALLMULTI: _bindgen_ty_61 = 61;
+pub const IFLA_DEVLINK_PORT: _bindgen_ty_61 = 62;
+pub const IFLA_GSO_IPV4_MAX_SIZE: _bindgen_ty_61 = 63;
+pub const IFLA_GRO_IPV4_MAX_SIZE: _bindgen_ty_61 = 64;
+pub const __IFLA_MAX: _bindgen_ty_61 = 65;
+pub type _bindgen_ty_61 = crate::types::c_uint;
+pub const IFLA_PROTO_DOWN_REASON_UNSPEC: _bindgen_ty_62 = 0;
+pub const IFLA_PROTO_DOWN_REASON_MASK: _bindgen_ty_62 = 1;
+pub const IFLA_PROTO_DOWN_REASON_VALUE: _bindgen_ty_62 = 2;
+pub const __IFLA_PROTO_DOWN_REASON_CNT: _bindgen_ty_62 = 3;
+pub const IFLA_PROTO_DOWN_REASON_MAX: _bindgen_ty_62 = 2;
+pub type _bindgen_ty_62 = crate::types::c_uint;
+pub const IFLA_INET_UNSPEC: _bindgen_ty_63 = 0;
+pub const IFLA_INET_CONF: _bindgen_ty_63 = 1;
+pub const __IFLA_INET_MAX: _bindgen_ty_63 = 2;
+pub type _bindgen_ty_63 = crate::types::c_uint;
+pub const IFLA_INET6_UNSPEC: _bindgen_ty_64 = 0;
+pub const IFLA_INET6_FLAGS: _bindgen_ty_64 = 1;
+pub const IFLA_INET6_CONF: _bindgen_ty_64 = 2;
+pub const IFLA_INET6_STATS: _bindgen_ty_64 = 3;
+pub const IFLA_INET6_MCAST: _bindgen_ty_64 = 4;
+pub const IFLA_INET6_CACHEINFO: _bindgen_ty_64 = 5;
+pub const IFLA_INET6_ICMP6STATS: _bindgen_ty_64 = 6;
+pub const IFLA_INET6_TOKEN: _bindgen_ty_64 = 7;
+pub const IFLA_INET6_ADDR_GEN_MODE: _bindgen_ty_64 = 8;
+pub const IFLA_INET6_RA_MTU: _bindgen_ty_64 = 9;
+pub const __IFLA_INET6_MAX: _bindgen_ty_64 = 10;
+pub type _bindgen_ty_64 = crate::types::c_uint;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_EUI64: in6_addr_gen_mode = 0;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_NONE: in6_addr_gen_mode = 1;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_STABLE_PRIVACY: in6_addr_gen_mode = 2;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_RANDOM: in6_addr_gen_mode = 3;
+pub type in6_addr_gen_mode = crate::types::c_uint;
+pub const IFLA_BR_UNSPEC: _bindgen_ty_65 = 0;
+pub const IFLA_BR_FORWARD_DELAY: _bindgen_ty_65 = 1;
+pub const IFLA_BR_HELLO_TIME: _bindgen_ty_65 = 2;
+pub const IFLA_BR_MAX_AGE: _bindgen_ty_65 = 3;
+pub const IFLA_BR_AGEING_TIME: _bindgen_ty_65 = 4;
+pub const IFLA_BR_STP_STATE: _bindgen_ty_65 = 5;
+pub const IFLA_BR_PRIORITY: _bindgen_ty_65 = 6;
+pub const IFLA_BR_VLAN_FILTERING: _bindgen_ty_65 = 7;
+pub const IFLA_BR_VLAN_PROTOCOL: _bindgen_ty_65 = 8;
+pub const IFLA_BR_GROUP_FWD_MASK: _bindgen_ty_65 = 9;
+pub const IFLA_BR_ROOT_ID: _bindgen_ty_65 = 10;
+pub const IFLA_BR_BRIDGE_ID: _bindgen_ty_65 = 11;
+pub const IFLA_BR_ROOT_PORT: _bindgen_ty_65 = 12;
+pub const IFLA_BR_ROOT_PATH_COST: _bindgen_ty_65 = 13;
+pub const IFLA_BR_TOPOLOGY_CHANGE: _bindgen_ty_65 = 14;
+pub const IFLA_BR_TOPOLOGY_CHANGE_DETECTED: _bindgen_ty_65 = 15;
+pub const IFLA_BR_HELLO_TIMER: _bindgen_ty_65 = 16;
+pub const IFLA_BR_TCN_TIMER: _bindgen_ty_65 = 17;
+pub const IFLA_BR_TOPOLOGY_CHANGE_TIMER: _bindgen_ty_65 = 18;
+pub const IFLA_BR_GC_TIMER: _bindgen_ty_65 = 19;
+pub const IFLA_BR_GROUP_ADDR: _bindgen_ty_65 = 20;
+pub const IFLA_BR_FDB_FLUSH: _bindgen_ty_65 = 21;
+pub const IFLA_BR_MCAST_ROUTER: _bindgen_ty_65 = 22;
+pub const IFLA_BR_MCAST_SNOOPING: _bindgen_ty_65 = 23;
+pub const IFLA_BR_MCAST_QUERY_USE_IFADDR: _bindgen_ty_65 = 24;
+pub const IFLA_BR_MCAST_QUERIER: _bindgen_ty_65 = 25;
+pub const IFLA_BR_MCAST_HASH_ELASTICITY: _bindgen_ty_65 = 26;
+pub const IFLA_BR_MCAST_HASH_MAX: _bindgen_ty_65 = 27;
+pub const IFLA_BR_MCAST_LAST_MEMBER_CNT: _bindgen_ty_65 = 28;
+pub const IFLA_BR_MCAST_STARTUP_QUERY_CNT: _bindgen_ty_65 = 29;
+pub const IFLA_BR_MCAST_LAST_MEMBER_INTVL: _bindgen_ty_65 = 30;
+pub const IFLA_BR_MCAST_MEMBERSHIP_INTVL: _bindgen_ty_65 = 31;
+pub const IFLA_BR_MCAST_QUERIER_INTVL: _bindgen_ty_65 = 32;
+pub const IFLA_BR_MCAST_QUERY_INTVL: _bindgen_ty_65 = 33;
+pub const IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: _bindgen_ty_65 = 34;
+pub const IFLA_BR_MCAST_STARTUP_QUERY_INTVL: _bindgen_ty_65 = 35;
+pub const IFLA_BR_NF_CALL_IPTABLES: _bindgen_ty_65 = 36;
+pub const IFLA_BR_NF_CALL_IP6TABLES: _bindgen_ty_65 = 37;
+pub const IFLA_BR_NF_CALL_ARPTABLES: _bindgen_ty_65 = 38;
+pub const IFLA_BR_VLAN_DEFAULT_PVID: _bindgen_ty_65 = 39;
+pub const IFLA_BR_PAD: _bindgen_ty_65 = 40;
+pub const IFLA_BR_VLAN_STATS_ENABLED: _bindgen_ty_65 = 41;
+pub const IFLA_BR_MCAST_STATS_ENABLED: _bindgen_ty_65 = 42;
+pub const IFLA_BR_MCAST_IGMP_VERSION: _bindgen_ty_65 = 43;
+pub const IFLA_BR_MCAST_MLD_VERSION: _bindgen_ty_65 = 44;
+pub const IFLA_BR_VLAN_STATS_PER_PORT: _bindgen_ty_65 = 45;
+pub const IFLA_BR_MULTI_BOOLOPT: _bindgen_ty_65 = 46;
+pub const IFLA_BR_MCAST_QUERIER_STATE: _bindgen_ty_65 = 47;
+pub const __IFLA_BR_MAX: _bindgen_ty_65 = 48;
+pub type _bindgen_ty_65 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_bridge_id {
+    pub prio: [__u8; 2usize],
+    pub addr: [__u8; 6usize],
+}
+pub const BRIDGE_MODE_UNSPEC: _bindgen_ty_66 = 0;
+pub const BRIDGE_MODE_HAIRPIN: _bindgen_ty_66 = 1;
+pub type _bindgen_ty_66 = crate::types::c_uint;
+pub const IFLA_BRPORT_UNSPEC: _bindgen_ty_67 = 0;
+pub const IFLA_BRPORT_STATE: _bindgen_ty_67 = 1;
+pub const IFLA_BRPORT_PRIORITY: _bindgen_ty_67 = 2;
+pub const IFLA_BRPORT_COST: _bindgen_ty_67 = 3;
+pub const IFLA_BRPORT_MODE: _bindgen_ty_67 = 4;
+pub const IFLA_BRPORT_GUARD: _bindgen_ty_67 = 5;
+pub const IFLA_BRPORT_PROTECT: _bindgen_ty_67 = 6;
+pub const IFLA_BRPORT_FAST_LEAVE: _bindgen_ty_67 = 7;
+pub const IFLA_BRPORT_LEARNING: _bindgen_ty_67 = 8;
+pub const IFLA_BRPORT_UNICAST_FLOOD: _bindgen_ty_67 = 9;
+pub const IFLA_BRPORT_PROXYARP: _bindgen_ty_67 = 10;
+pub const IFLA_BRPORT_LEARNING_SYNC: _bindgen_ty_67 = 11;
+pub const IFLA_BRPORT_PROXYARP_WIFI: _bindgen_ty_67 = 12;
+pub const IFLA_BRPORT_ROOT_ID: _bindgen_ty_67 = 13;
+pub const IFLA_BRPORT_BRIDGE_ID: _bindgen_ty_67 = 14;
+pub const IFLA_BRPORT_DESIGNATED_PORT: _bindgen_ty_67 = 15;
+pub const IFLA_BRPORT_DESIGNATED_COST: _bindgen_ty_67 = 16;
+pub const IFLA_BRPORT_ID: _bindgen_ty_67 = 17;
+pub const IFLA_BRPORT_NO: _bindgen_ty_67 = 18;
+pub const IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: _bindgen_ty_67 = 19;
+pub const IFLA_BRPORT_CONFIG_PENDING: _bindgen_ty_67 = 20;
+pub const IFLA_BRPORT_MESSAGE_AGE_TIMER: _bindgen_ty_67 = 21;
+pub const IFLA_BRPORT_FORWARD_DELAY_TIMER: _bindgen_ty_67 = 22;
+pub const IFLA_BRPORT_HOLD_TIMER: _bindgen_ty_67 = 23;
+pub const IFLA_BRPORT_FLUSH: _bindgen_ty_67 = 24;
+pub const IFLA_BRPORT_MULTICAST_ROUTER: _bindgen_ty_67 = 25;
+pub const IFLA_BRPORT_PAD: _bindgen_ty_67 = 26;
+pub const IFLA_BRPORT_MCAST_FLOOD: _bindgen_ty_67 = 27;
+pub const IFLA_BRPORT_MCAST_TO_UCAST: _bindgen_ty_67 = 28;
+pub const IFLA_BRPORT_VLAN_TUNNEL: _bindgen_ty_67 = 29;
+pub const IFLA_BRPORT_BCAST_FLOOD: _bindgen_ty_67 = 30;
+pub const IFLA_BRPORT_GROUP_FWD_MASK: _bindgen_ty_67 = 31;
+pub const IFLA_BRPORT_NEIGH_SUPPRESS: _bindgen_ty_67 = 32;
+pub const IFLA_BRPORT_ISOLATED: _bindgen_ty_67 = 33;
+pub const IFLA_BRPORT_BACKUP_PORT: _bindgen_ty_67 = 34;
+pub const IFLA_BRPORT_MRP_RING_OPEN: _bindgen_ty_67 = 35;
+pub const IFLA_BRPORT_MRP_IN_OPEN: _bindgen_ty_67 = 36;
+pub const IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT: _bindgen_ty_67 = 37;
+pub const IFLA_BRPORT_MCAST_EHT_HOSTS_CNT: _bindgen_ty_67 = 38;
+pub const IFLA_BRPORT_LOCKED: _bindgen_ty_67 = 39;
+pub const IFLA_BRPORT_MAB: _bindgen_ty_67 = 40;
+pub const IFLA_BRPORT_MCAST_N_GROUPS: _bindgen_ty_67 = 41;
+pub const IFLA_BRPORT_MCAST_MAX_GROUPS: _bindgen_ty_67 = 42;
+pub const IFLA_BRPORT_NEIGH_VLAN_SUPPRESS: _bindgen_ty_67 = 43;
+pub const __IFLA_BRPORT_MAX: _bindgen_ty_67 = 44;
+pub type _bindgen_ty_67 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_cacheinfo {
+    pub max_reasm_len: __u32,
+    pub tstamp: __u32,
+    pub reachable_time: __u32,
+    pub retrans_time: __u32,
+}
+pub const IFLA_INFO_UNSPEC: _bindgen_ty_68 = 0;
+pub const IFLA_INFO_KIND: _bindgen_ty_68 = 1;
+pub const IFLA_INFO_DATA: _bindgen_ty_68 = 2;
+pub const IFLA_INFO_XSTATS: _bindgen_ty_68 = 3;
+pub const IFLA_INFO_SLAVE_KIND: _bindgen_ty_68 = 4;
+pub const IFLA_INFO_SLAVE_DATA: _bindgen_ty_68 = 5;
+pub const __IFLA_INFO_MAX: _bindgen_ty_68 = 6;
+pub type _bindgen_ty_68 = crate::types::c_uint;
+pub const IFLA_VLAN_UNSPEC: _bindgen_ty_69 = 0;
+pub const IFLA_VLAN_ID: _bindgen_ty_69 = 1;
+pub const IFLA_VLAN_FLAGS: _bindgen_ty_69 = 2;
+pub const IFLA_VLAN_EGRESS_QOS: _bindgen_ty_69 = 3;
+pub const IFLA_VLAN_INGRESS_QOS: _bindgen_ty_69 = 4;
+pub const IFLA_VLAN_PROTOCOL: _bindgen_ty_69 = 5;
+pub const __IFLA_VLAN_MAX: _bindgen_ty_69 = 6;
+pub type _bindgen_ty_69 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vlan_flags {
+    pub flags: __u32,
+    pub mask: __u32,
+}
+pub const IFLA_VLAN_QOS_UNSPEC: _bindgen_ty_70 = 0;
+pub const IFLA_VLAN_QOS_MAPPING: _bindgen_ty_70 = 1;
+pub const __IFLA_VLAN_QOS_MAX: _bindgen_ty_70 = 2;
+pub type _bindgen_ty_70 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vlan_qos_mapping {
+    pub from: __u32,
+    pub to: __u32,
+}
+pub const IFLA_MACVLAN_UNSPEC: _bindgen_ty_71 = 0;
+pub const IFLA_MACVLAN_MODE: _bindgen_ty_71 = 1;
+pub const IFLA_MACVLAN_FLAGS: _bindgen_ty_71 = 2;
+pub const IFLA_MACVLAN_MACADDR_MODE: _bindgen_ty_71 = 3;
+pub const IFLA_MACVLAN_MACADDR: _bindgen_ty_71 = 4;
+pub const IFLA_MACVLAN_MACADDR_DATA: _bindgen_ty_71 = 5;
+pub const IFLA_MACVLAN_MACADDR_COUNT: _bindgen_ty_71 = 6;
+pub const IFLA_MACVLAN_BC_QUEUE_LEN: _bindgen_ty_71 = 7;
+pub const IFLA_MACVLAN_BC_QUEUE_LEN_USED: _bindgen_ty_71 = 8;
+pub const IFLA_MACVLAN_BC_CUTOFF: _bindgen_ty_71 = 9;
+pub const __IFLA_MACVLAN_MAX: _bindgen_ty_71 = 10;
+pub type _bindgen_ty_71 = crate::types::c_uint;
+pub const macvlan_mode_MACVLAN_MODE_PRIVATE: macvlan_mode = 1;
+pub const macvlan_mode_MACVLAN_MODE_VEPA: macvlan_mode = 2;
+pub const macvlan_mode_MACVLAN_MODE_BRIDGE: macvlan_mode = 4;
+pub const macvlan_mode_MACVLAN_MODE_PASSTHRU: macvlan_mode = 8;
+pub const macvlan_mode_MACVLAN_MODE_SOURCE: macvlan_mode = 16;
+pub type macvlan_mode = crate::types::c_uint;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_ADD: macvlan_macaddr_mode = 0;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_DEL: macvlan_macaddr_mode = 1;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_FLUSH: macvlan_macaddr_mode = 2;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_SET: macvlan_macaddr_mode = 3;
+pub type macvlan_macaddr_mode = crate::types::c_uint;
+pub const IFLA_VRF_UNSPEC: _bindgen_ty_72 = 0;
+pub const IFLA_VRF_TABLE: _bindgen_ty_72 = 1;
+pub const __IFLA_VRF_MAX: _bindgen_ty_72 = 2;
+pub type _bindgen_ty_72 = crate::types::c_uint;
+pub const IFLA_VRF_PORT_UNSPEC: _bindgen_ty_73 = 0;
+pub const IFLA_VRF_PORT_TABLE: _bindgen_ty_73 = 1;
+pub const __IFLA_VRF_PORT_MAX: _bindgen_ty_73 = 2;
+pub type _bindgen_ty_73 = crate::types::c_uint;
+pub const IFLA_MACSEC_UNSPEC: _bindgen_ty_74 = 0;
+pub const IFLA_MACSEC_SCI: _bindgen_ty_74 = 1;
+pub const IFLA_MACSEC_PORT: _bindgen_ty_74 = 2;
+pub const IFLA_MACSEC_ICV_LEN: _bindgen_ty_74 = 3;
+pub const IFLA_MACSEC_CIPHER_SUITE: _bindgen_ty_74 = 4;
+pub const IFLA_MACSEC_WINDOW: _bindgen_ty_74 = 5;
+pub const IFLA_MACSEC_ENCODING_SA: _bindgen_ty_74 = 6;
+pub const IFLA_MACSEC_ENCRYPT: _bindgen_ty_74 = 7;
+pub const IFLA_MACSEC_PROTECT: _bindgen_ty_74 = 8;
+pub const IFLA_MACSEC_INC_SCI: _bindgen_ty_74 = 9;
+pub const IFLA_MACSEC_ES: _bindgen_ty_74 = 10;
+pub const IFLA_MACSEC_SCB: _bindgen_ty_74 = 11;
+pub const IFLA_MACSEC_REPLAY_PROTECT: _bindgen_ty_74 = 12;
+pub const IFLA_MACSEC_VALIDATION: _bindgen_ty_74 = 13;
+pub const IFLA_MACSEC_PAD: _bindgen_ty_74 = 14;
+pub const IFLA_MACSEC_OFFLOAD: _bindgen_ty_74 = 15;
+pub const __IFLA_MACSEC_MAX: _bindgen_ty_74 = 16;
+pub type _bindgen_ty_74 = crate::types::c_uint;
+pub const IFLA_XFRM_UNSPEC: _bindgen_ty_75 = 0;
+pub const IFLA_XFRM_LINK: _bindgen_ty_75 = 1;
+pub const IFLA_XFRM_IF_ID: _bindgen_ty_75 = 2;
+pub const IFLA_XFRM_COLLECT_METADATA: _bindgen_ty_75 = 3;
+pub const __IFLA_XFRM_MAX: _bindgen_ty_75 = 4;
+pub type _bindgen_ty_75 = crate::types::c_uint;
+pub const macsec_validation_type_MACSEC_VALIDATE_DISABLED: macsec_validation_type = 0;
+pub const macsec_validation_type_MACSEC_VALIDATE_CHECK: macsec_validation_type = 1;
+pub const macsec_validation_type_MACSEC_VALIDATE_STRICT: macsec_validation_type = 2;
+pub const macsec_validation_type___MACSEC_VALIDATE_END: macsec_validation_type = 3;
+pub const macsec_validation_type_MACSEC_VALIDATE_MAX: macsec_validation_type = 2;
+pub type macsec_validation_type = crate::types::c_uint;
+pub const macsec_offload_MACSEC_OFFLOAD_OFF: macsec_offload = 0;
+pub const macsec_offload_MACSEC_OFFLOAD_PHY: macsec_offload = 1;
+pub const macsec_offload_MACSEC_OFFLOAD_MAC: macsec_offload = 2;
+pub const macsec_offload___MACSEC_OFFLOAD_END: macsec_offload = 3;
+pub const macsec_offload_MACSEC_OFFLOAD_MAX: macsec_offload = 2;
+pub type macsec_offload = crate::types::c_uint;
+pub const IFLA_IPVLAN_UNSPEC: _bindgen_ty_76 = 0;
+pub const IFLA_IPVLAN_MODE: _bindgen_ty_76 = 1;
+pub const IFLA_IPVLAN_FLAGS: _bindgen_ty_76 = 2;
+pub const __IFLA_IPVLAN_MAX: _bindgen_ty_76 = 3;
+pub type _bindgen_ty_76 = crate::types::c_uint;
+pub const ipvlan_mode_IPVLAN_MODE_L2: ipvlan_mode = 0;
+pub const ipvlan_mode_IPVLAN_MODE_L3: ipvlan_mode = 1;
+pub const ipvlan_mode_IPVLAN_MODE_L3S: ipvlan_mode = 2;
+pub const ipvlan_mode_IPVLAN_MODE_MAX: ipvlan_mode = 3;
+pub type ipvlan_mode = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tunnel_msg {
+    pub family: __u8,
+    pub flags: __u8,
+    pub reserved2: __u16,
+    pub ifindex: __u32,
+}
+pub const VNIFILTER_ENTRY_STATS_UNSPEC: _bindgen_ty_77 = 0;
+pub const VNIFILTER_ENTRY_STATS_RX_BYTES: _bindgen_ty_77 = 1;
+pub const VNIFILTER_ENTRY_STATS_RX_PKTS: _bindgen_ty_77 = 2;
+pub const VNIFILTER_ENTRY_STATS_RX_DROPS: _bindgen_ty_77 = 3;
+pub const VNIFILTER_ENTRY_STATS_RX_ERRORS: _bindgen_ty_77 = 4;
+pub const VNIFILTER_ENTRY_STATS_TX_BYTES: _bindgen_ty_77 = 5;
+pub const VNIFILTER_ENTRY_STATS_TX_PKTS: _bindgen_ty_77 = 6;
+pub const VNIFILTER_ENTRY_STATS_TX_DROPS: _bindgen_ty_77 = 7;
+pub const VNIFILTER_ENTRY_STATS_TX_ERRORS: _bindgen_ty_77 = 8;
+pub const VNIFILTER_ENTRY_STATS_PAD: _bindgen_ty_77 = 9;
+pub const __VNIFILTER_ENTRY_STATS_MAX: _bindgen_ty_77 = 10;
+pub type _bindgen_ty_77 = crate::types::c_uint;
+pub const VXLAN_VNIFILTER_ENTRY_UNSPEC: _bindgen_ty_78 = 0;
+pub const VXLAN_VNIFILTER_ENTRY_START: _bindgen_ty_78 = 1;
+pub const VXLAN_VNIFILTER_ENTRY_END: _bindgen_ty_78 = 2;
+pub const VXLAN_VNIFILTER_ENTRY_GROUP: _bindgen_ty_78 = 3;
+pub const VXLAN_VNIFILTER_ENTRY_GROUP6: _bindgen_ty_78 = 4;
+pub const VXLAN_VNIFILTER_ENTRY_STATS: _bindgen_ty_78 = 5;
+pub const __VXLAN_VNIFILTER_ENTRY_MAX: _bindgen_ty_78 = 6;
+pub type _bindgen_ty_78 = crate::types::c_uint;
+pub const VXLAN_VNIFILTER_UNSPEC: _bindgen_ty_79 = 0;
+pub const VXLAN_VNIFILTER_ENTRY: _bindgen_ty_79 = 1;
+pub const __VXLAN_VNIFILTER_MAX: _bindgen_ty_79 = 2;
+pub type _bindgen_ty_79 = crate::types::c_uint;
+pub const IFLA_VXLAN_UNSPEC: _bindgen_ty_80 = 0;
+pub const IFLA_VXLAN_ID: _bindgen_ty_80 = 1;
+pub const IFLA_VXLAN_GROUP: _bindgen_ty_80 = 2;
+pub const IFLA_VXLAN_LINK: _bindgen_ty_80 = 3;
+pub const IFLA_VXLAN_LOCAL: _bindgen_ty_80 = 4;
+pub const IFLA_VXLAN_TTL: _bindgen_ty_80 = 5;
+pub const IFLA_VXLAN_TOS: _bindgen_ty_80 = 6;
+pub const IFLA_VXLAN_LEARNING: _bindgen_ty_80 = 7;
+pub const IFLA_VXLAN_AGEING: _bindgen_ty_80 = 8;
+pub const IFLA_VXLAN_LIMIT: _bindgen_ty_80 = 9;
+pub const IFLA_VXLAN_PORT_RANGE: _bindgen_ty_80 = 10;
+pub const IFLA_VXLAN_PROXY: _bindgen_ty_80 = 11;
+pub const IFLA_VXLAN_RSC: _bindgen_ty_80 = 12;
+pub const IFLA_VXLAN_L2MISS: _bindgen_ty_80 = 13;
+pub const IFLA_VXLAN_L3MISS: _bindgen_ty_80 = 14;
+pub const IFLA_VXLAN_PORT: _bindgen_ty_80 = 15;
+pub const IFLA_VXLAN_GROUP6: _bindgen_ty_80 = 16;
+pub const IFLA_VXLAN_LOCAL6: _bindgen_ty_80 = 17;
+pub const IFLA_VXLAN_UDP_CSUM: _bindgen_ty_80 = 18;
+pub const IFLA_VXLAN_UDP_ZERO_CSUM6_TX: _bindgen_ty_80 = 19;
+pub const IFLA_VXLAN_UDP_ZERO_CSUM6_RX: _bindgen_ty_80 = 20;
+pub const IFLA_VXLAN_REMCSUM_TX: _bindgen_ty_80 = 21;
+pub const IFLA_VXLAN_REMCSUM_RX: _bindgen_ty_80 = 22;
+pub const IFLA_VXLAN_GBP: _bindgen_ty_80 = 23;
+pub const IFLA_VXLAN_REMCSUM_NOPARTIAL: _bindgen_ty_80 = 24;
+pub const IFLA_VXLAN_COLLECT_METADATA: _bindgen_ty_80 = 25;
+pub const IFLA_VXLAN_LABEL: _bindgen_ty_80 = 26;
+pub const IFLA_VXLAN_GPE: _bindgen_ty_80 = 27;
+pub const IFLA_VXLAN_TTL_INHERIT: _bindgen_ty_80 = 28;
+pub const IFLA_VXLAN_DF: _bindgen_ty_80 = 29;
+pub const IFLA_VXLAN_VNIFILTER: _bindgen_ty_80 = 30;
+pub const IFLA_VXLAN_LOCALBYPASS: _bindgen_ty_80 = 31;
+pub const __IFLA_VXLAN_MAX: _bindgen_ty_80 = 32;
+pub type _bindgen_ty_80 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vxlan_port_range {
+    pub low: __be16,
+    pub high: __be16,
+}
+pub const ifla_vxlan_df_VXLAN_DF_UNSET: ifla_vxlan_df = 0;
+pub const ifla_vxlan_df_VXLAN_DF_SET: ifla_vxlan_df = 1;
+pub const ifla_vxlan_df_VXLAN_DF_INHERIT: ifla_vxlan_df = 2;
+pub const ifla_vxlan_df___VXLAN_DF_END: ifla_vxlan_df = 3;
+pub const ifla_vxlan_df_VXLAN_DF_MAX: ifla_vxlan_df = 2;
+pub type ifla_vxlan_df = crate::types::c_uint;
+pub const IFLA_GENEVE_UNSPEC: _bindgen_ty_81 = 0;
+pub const IFLA_GENEVE_ID: _bindgen_ty_81 = 1;
+pub const IFLA_GENEVE_REMOTE: _bindgen_ty_81 = 2;
+pub const IFLA_GENEVE_TTL: _bindgen_ty_81 = 3;
+pub const IFLA_GENEVE_TOS: _bindgen_ty_81 = 4;
+pub const IFLA_GENEVE_PORT: _bindgen_ty_81 = 5;
+pub const IFLA_GENEVE_COLLECT_METADATA: _bindgen_ty_81 = 6;
+pub const IFLA_GENEVE_REMOTE6: _bindgen_ty_81 = 7;
+pub const IFLA_GENEVE_UDP_CSUM: _bindgen_ty_81 = 8;
+pub const IFLA_GENEVE_UDP_ZERO_CSUM6_TX: _bindgen_ty_81 = 9;
+pub const IFLA_GENEVE_UDP_ZERO_CSUM6_RX: _bindgen_ty_81 = 10;
+pub const IFLA_GENEVE_LABEL: _bindgen_ty_81 = 11;
+pub const IFLA_GENEVE_TTL_INHERIT: _bindgen_ty_81 = 12;
+pub const IFLA_GENEVE_DF: _bindgen_ty_81 = 13;
+pub const IFLA_GENEVE_INNER_PROTO_INHERIT: _bindgen_ty_81 = 14;
+pub const __IFLA_GENEVE_MAX: _bindgen_ty_81 = 15;
+pub type _bindgen_ty_81 = crate::types::c_uint;
+pub const ifla_geneve_df_GENEVE_DF_UNSET: ifla_geneve_df = 0;
+pub const ifla_geneve_df_GENEVE_DF_SET: ifla_geneve_df = 1;
+pub const ifla_geneve_df_GENEVE_DF_INHERIT: ifla_geneve_df = 2;
+pub const ifla_geneve_df___GENEVE_DF_END: ifla_geneve_df = 3;
+pub const ifla_geneve_df_GENEVE_DF_MAX: ifla_geneve_df = 2;
+pub type ifla_geneve_df = crate::types::c_uint;
+pub const IFLA_BAREUDP_UNSPEC: _bindgen_ty_82 = 0;
+pub const IFLA_BAREUDP_PORT: _bindgen_ty_82 = 1;
+pub const IFLA_BAREUDP_ETHERTYPE: _bindgen_ty_82 = 2;
+pub const IFLA_BAREUDP_SRCPORT_MIN: _bindgen_ty_82 = 3;
+pub const IFLA_BAREUDP_MULTIPROTO_MODE: _bindgen_ty_82 = 4;
+pub const __IFLA_BAREUDP_MAX: _bindgen_ty_82 = 5;
+pub type _bindgen_ty_82 = crate::types::c_uint;
+pub const IFLA_PPP_UNSPEC: _bindgen_ty_83 = 0;
+pub const IFLA_PPP_DEV_FD: _bindgen_ty_83 = 1;
+pub const __IFLA_PPP_MAX: _bindgen_ty_83 = 2;
+pub type _bindgen_ty_83 = crate::types::c_uint;
+pub const ifla_gtp_role_GTP_ROLE_GGSN: ifla_gtp_role = 0;
+pub const ifla_gtp_role_GTP_ROLE_SGSN: ifla_gtp_role = 1;
+pub type ifla_gtp_role = crate::types::c_uint;
+pub const IFLA_GTP_UNSPEC: _bindgen_ty_84 = 0;
+pub const IFLA_GTP_FD0: _bindgen_ty_84 = 1;
+pub const IFLA_GTP_FD1: _bindgen_ty_84 = 2;
+pub const IFLA_GTP_PDP_HASHSIZE: _bindgen_ty_84 = 3;
+pub const IFLA_GTP_ROLE: _bindgen_ty_84 = 4;
+pub const IFLA_GTP_CREATE_SOCKETS: _bindgen_ty_84 = 5;
+pub const IFLA_GTP_RESTART_COUNT: _bindgen_ty_84 = 6;
+pub const __IFLA_GTP_MAX: _bindgen_ty_84 = 7;
+pub type _bindgen_ty_84 = crate::types::c_uint;
+pub const IFLA_BOND_UNSPEC: _bindgen_ty_85 = 0;
+pub const IFLA_BOND_MODE: _bindgen_ty_85 = 1;
+pub const IFLA_BOND_ACTIVE_SLAVE: _bindgen_ty_85 = 2;
+pub const IFLA_BOND_MIIMON: _bindgen_ty_85 = 3;
+pub const IFLA_BOND_UPDELAY: _bindgen_ty_85 = 4;
+pub const IFLA_BOND_DOWNDELAY: _bindgen_ty_85 = 5;
+pub const IFLA_BOND_USE_CARRIER: _bindgen_ty_85 = 6;
+pub const IFLA_BOND_ARP_INTERVAL: _bindgen_ty_85 = 7;
+pub const IFLA_BOND_ARP_IP_TARGET: _bindgen_ty_85 = 8;
+pub const IFLA_BOND_ARP_VALIDATE: _bindgen_ty_85 = 9;
+pub const IFLA_BOND_ARP_ALL_TARGETS: _bindgen_ty_85 = 10;
+pub const IFLA_BOND_PRIMARY: _bindgen_ty_85 = 11;
+pub const IFLA_BOND_PRIMARY_RESELECT: _bindgen_ty_85 = 12;
+pub const IFLA_BOND_FAIL_OVER_MAC: _bindgen_ty_85 = 13;
+pub const IFLA_BOND_XMIT_HASH_POLICY: _bindgen_ty_85 = 14;
+pub const IFLA_BOND_RESEND_IGMP: _bindgen_ty_85 = 15;
+pub const IFLA_BOND_NUM_PEER_NOTIF: _bindgen_ty_85 = 16;
+pub const IFLA_BOND_ALL_SLAVES_ACTIVE: _bindgen_ty_85 = 17;
+pub const IFLA_BOND_MIN_LINKS: _bindgen_ty_85 = 18;
+pub const IFLA_BOND_LP_INTERVAL: _bindgen_ty_85 = 19;
+pub const IFLA_BOND_PACKETS_PER_SLAVE: _bindgen_ty_85 = 20;
+pub const IFLA_BOND_AD_LACP_RATE: _bindgen_ty_85 = 21;
+pub const IFLA_BOND_AD_SELECT: _bindgen_ty_85 = 22;
+pub const IFLA_BOND_AD_INFO: _bindgen_ty_85 = 23;
+pub const IFLA_BOND_AD_ACTOR_SYS_PRIO: _bindgen_ty_85 = 24;
+pub const IFLA_BOND_AD_USER_PORT_KEY: _bindgen_ty_85 = 25;
+pub const IFLA_BOND_AD_ACTOR_SYSTEM: _bindgen_ty_85 = 26;
+pub const IFLA_BOND_TLB_DYNAMIC_LB: _bindgen_ty_85 = 27;
+pub const IFLA_BOND_PEER_NOTIF_DELAY: _bindgen_ty_85 = 28;
+pub const IFLA_BOND_AD_LACP_ACTIVE: _bindgen_ty_85 = 29;
+pub const IFLA_BOND_MISSED_MAX: _bindgen_ty_85 = 30;
+pub const IFLA_BOND_NS_IP6_TARGET: _bindgen_ty_85 = 31;
+pub const __IFLA_BOND_MAX: _bindgen_ty_85 = 32;
+pub type _bindgen_ty_85 = crate::types::c_uint;
+pub const IFLA_BOND_AD_INFO_UNSPEC: _bindgen_ty_86 = 0;
+pub const IFLA_BOND_AD_INFO_AGGREGATOR: _bindgen_ty_86 = 1;
+pub const IFLA_BOND_AD_INFO_NUM_PORTS: _bindgen_ty_86 = 2;
+pub const IFLA_BOND_AD_INFO_ACTOR_KEY: _bindgen_ty_86 = 3;
+pub const IFLA_BOND_AD_INFO_PARTNER_KEY: _bindgen_ty_86 = 4;
+pub const IFLA_BOND_AD_INFO_PARTNER_MAC: _bindgen_ty_86 = 5;
+pub const __IFLA_BOND_AD_INFO_MAX: _bindgen_ty_86 = 6;
+pub type _bindgen_ty_86 = crate::types::c_uint;
+pub const IFLA_BOND_SLAVE_UNSPEC: _bindgen_ty_87 = 0;
+pub const IFLA_BOND_SLAVE_STATE: _bindgen_ty_87 = 1;
+pub const IFLA_BOND_SLAVE_MII_STATUS: _bindgen_ty_87 = 2;
+pub const IFLA_BOND_SLAVE_LINK_FAILURE_COUNT: _bindgen_ty_87 = 3;
+pub const IFLA_BOND_SLAVE_PERM_HWADDR: _bindgen_ty_87 = 4;
+pub const IFLA_BOND_SLAVE_QUEUE_ID: _bindgen_ty_87 = 5;
+pub const IFLA_BOND_SLAVE_AD_AGGREGATOR_ID: _bindgen_ty_87 = 6;
+pub const IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE: _bindgen_ty_87 = 7;
+pub const IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE: _bindgen_ty_87 = 8;
+pub const IFLA_BOND_SLAVE_PRIO: _bindgen_ty_87 = 9;
+pub const __IFLA_BOND_SLAVE_MAX: _bindgen_ty_87 = 10;
+pub type _bindgen_ty_87 = crate::types::c_uint;
+pub const IFLA_VF_INFO_UNSPEC: _bindgen_ty_88 = 0;
+pub const IFLA_VF_INFO: _bindgen_ty_88 = 1;
+pub const __IFLA_VF_INFO_MAX: _bindgen_ty_88 = 2;
+pub type _bindgen_ty_88 = crate::types::c_uint;
+pub const IFLA_VF_UNSPEC: _bindgen_ty_89 = 0;
+pub const IFLA_VF_MAC: _bindgen_ty_89 = 1;
+pub const IFLA_VF_VLAN: _bindgen_ty_89 = 2;
+pub const IFLA_VF_TX_RATE: _bindgen_ty_89 = 3;
+pub const IFLA_VF_SPOOFCHK: _bindgen_ty_89 = 4;
+pub const IFLA_VF_LINK_STATE: _bindgen_ty_89 = 5;
+pub const IFLA_VF_RATE: _bindgen_ty_89 = 6;
+pub const IFLA_VF_RSS_QUERY_EN: _bindgen_ty_89 = 7;
+pub const IFLA_VF_STATS: _bindgen_ty_89 = 8;
+pub const IFLA_VF_TRUST: _bindgen_ty_89 = 9;
+pub const IFLA_VF_IB_NODE_GUID: _bindgen_ty_89 = 10;
+pub const IFLA_VF_IB_PORT_GUID: _bindgen_ty_89 = 11;
+pub const IFLA_VF_VLAN_LIST: _bindgen_ty_89 = 12;
+pub const IFLA_VF_BROADCAST: _bindgen_ty_89 = 13;
+pub const __IFLA_VF_MAX: _bindgen_ty_89 = 14;
+pub type _bindgen_ty_89 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_mac {
+    pub vf: __u32,
+    pub mac: [__u8; 32usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_broadcast {
+    pub broadcast: [__u8; 32usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_vlan {
+    pub vf: __u32,
+    pub vlan: __u32,
+    pub qos: __u32,
+}
+pub const IFLA_VF_VLAN_INFO_UNSPEC: _bindgen_ty_90 = 0;
+pub const IFLA_VF_VLAN_INFO: _bindgen_ty_90 = 1;
+pub const __IFLA_VF_VLAN_INFO_MAX: _bindgen_ty_90 = 2;
+pub type _bindgen_ty_90 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_vlan_info {
+    pub vf: __u32,
+    pub vlan: __u32,
+    pub qos: __u32,
+    pub vlan_proto: __be16,
+    pub __bindgen_padding_0: [u8; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_tx_rate {
+    pub vf: __u32,
+    pub rate: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_rate {
+    pub vf: __u32,
+    pub min_tx_rate: __u32,
+    pub max_tx_rate: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_spoofchk {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_guid {
+    pub vf: __u32,
+    pub __bindgen_padding_0: [u8; 4usize],
+    pub guid: __u64,
+}
+pub const IFLA_VF_LINK_STATE_AUTO: _bindgen_ty_91 = 0;
+pub const IFLA_VF_LINK_STATE_ENABLE: _bindgen_ty_91 = 1;
+pub const IFLA_VF_LINK_STATE_DISABLE: _bindgen_ty_91 = 2;
+pub const __IFLA_VF_LINK_STATE_MAX: _bindgen_ty_91 = 3;
+pub type _bindgen_ty_91 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_link_state {
+    pub vf: __u32,
+    pub link_state: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_rss_query_en {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+pub const IFLA_VF_STATS_RX_PACKETS: _bindgen_ty_92 = 0;
+pub const IFLA_VF_STATS_TX_PACKETS: _bindgen_ty_92 = 1;
+pub const IFLA_VF_STATS_RX_BYTES: _bindgen_ty_92 = 2;
+pub const IFLA_VF_STATS_TX_BYTES: _bindgen_ty_92 = 3;
+pub const IFLA_VF_STATS_BROADCAST: _bindgen_ty_92 = 4;
+pub const IFLA_VF_STATS_MULTICAST: _bindgen_ty_92 = 5;
+pub const IFLA_VF_STATS_PAD: _bindgen_ty_92 = 6;
+pub const IFLA_VF_STATS_RX_DROPPED: _bindgen_ty_92 = 7;
+pub const IFLA_VF_STATS_TX_DROPPED: _bindgen_ty_92 = 8;
+pub const __IFLA_VF_STATS_MAX: _bindgen_ty_92 = 9;
+pub type _bindgen_ty_92 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_trust {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+pub const IFLA_VF_PORT_UNSPEC: _bindgen_ty_93 = 0;
+pub const IFLA_VF_PORT: _bindgen_ty_93 = 1;
+pub const __IFLA_VF_PORT_MAX: _bindgen_ty_93 = 2;
+pub type _bindgen_ty_93 = crate::types::c_uint;
+pub const IFLA_PORT_UNSPEC: _bindgen_ty_94 = 0;
+pub const IFLA_PORT_VF: _bindgen_ty_94 = 1;
+pub const IFLA_PORT_PROFILE: _bindgen_ty_94 = 2;
+pub const IFLA_PORT_VSI_TYPE: _bindgen_ty_94 = 3;
+pub const IFLA_PORT_INSTANCE_UUID: _bindgen_ty_94 = 4;
+pub const IFLA_PORT_HOST_UUID: _bindgen_ty_94 = 5;
+pub const IFLA_PORT_REQUEST: _bindgen_ty_94 = 6;
+pub const IFLA_PORT_RESPONSE: _bindgen_ty_94 = 7;
+pub const __IFLA_PORT_MAX: _bindgen_ty_94 = 8;
+pub type _bindgen_ty_94 = crate::types::c_uint;
+pub const PORT_REQUEST_PREASSOCIATE: _bindgen_ty_95 = 0;
+pub const PORT_REQUEST_PREASSOCIATE_RR: _bindgen_ty_95 = 1;
+pub const PORT_REQUEST_ASSOCIATE: _bindgen_ty_95 = 2;
+pub const PORT_REQUEST_DISASSOCIATE: _bindgen_ty_95 = 3;
+pub type _bindgen_ty_95 = crate::types::c_uint;
+pub const PORT_VDP_RESPONSE_SUCCESS: _bindgen_ty_96 = 0;
+pub const PORT_VDP_RESPONSE_INVALID_FORMAT: _bindgen_ty_96 = 1;
+pub const PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES: _bindgen_ty_96 = 2;
+pub const PORT_VDP_RESPONSE_UNUSED_VTID: _bindgen_ty_96 = 3;
+pub const PORT_VDP_RESPONSE_VTID_VIOLATION: _bindgen_ty_96 = 4;
+pub const PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION: _bindgen_ty_96 = 5;
+pub const PORT_VDP_RESPONSE_OUT_OF_SYNC: _bindgen_ty_96 = 6;
+pub const PORT_PROFILE_RESPONSE_SUCCESS: _bindgen_ty_96 = 256;
+pub const PORT_PROFILE_RESPONSE_INPROGRESS: _bindgen_ty_96 = 257;
+pub const PORT_PROFILE_RESPONSE_INVALID: _bindgen_ty_96 = 258;
+pub const PORT_PROFILE_RESPONSE_BADSTATE: _bindgen_ty_96 = 259;
+pub const PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES: _bindgen_ty_96 = 260;
+pub const PORT_PROFILE_RESPONSE_ERROR: _bindgen_ty_96 = 261;
+pub type _bindgen_ty_96 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_port_vsi {
+    pub vsi_mgr_id: __u8,
+    pub vsi_type_id: [__u8; 3usize],
+    pub vsi_type_version: __u8,
+    pub pad: [__u8; 3usize],
+}
+pub const IFLA_IPOIB_UNSPEC: _bindgen_ty_97 = 0;
+pub const IFLA_IPOIB_PKEY: _bindgen_ty_97 = 1;
+pub const IFLA_IPOIB_MODE: _bindgen_ty_97 = 2;
+pub const IFLA_IPOIB_UMCAST: _bindgen_ty_97 = 3;
+pub const __IFLA_IPOIB_MAX: _bindgen_ty_97 = 4;
+pub type _bindgen_ty_97 = crate::types::c_uint;
+pub const IPOIB_MODE_DATAGRAM: _bindgen_ty_98 = 0;
+pub const IPOIB_MODE_CONNECTED: _bindgen_ty_98 = 1;
+pub type _bindgen_ty_98 = crate::types::c_uint;
+pub const HSR_PROTOCOL_HSR: _bindgen_ty_99 = 0;
+pub const HSR_PROTOCOL_PRP: _bindgen_ty_99 = 1;
+pub const HSR_PROTOCOL_MAX: _bindgen_ty_99 = 2;
+pub type _bindgen_ty_99 = crate::types::c_uint;
+pub const IFLA_HSR_UNSPEC: _bindgen_ty_100 = 0;
+pub const IFLA_HSR_SLAVE1: _bindgen_ty_100 = 1;
+pub const IFLA_HSR_SLAVE2: _bindgen_ty_100 = 2;
+pub const IFLA_HSR_MULTICAST_SPEC: _bindgen_ty_100 = 3;
+pub const IFLA_HSR_SUPERVISION_ADDR: _bindgen_ty_100 = 4;
+pub const IFLA_HSR_SEQ_NR: _bindgen_ty_100 = 5;
+pub const IFLA_HSR_VERSION: _bindgen_ty_100 = 6;
+pub const IFLA_HSR_PROTOCOL: _bindgen_ty_100 = 7;
+pub const __IFLA_HSR_MAX: _bindgen_ty_100 = 8;
+pub type _bindgen_ty_100 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct if_stats_msg {
+    pub family: __u8,
+    pub pad1: __u8,
+    pub pad2: __u16,
+    pub ifindex: __u32,
+    pub filter_mask: __u32,
+}
+pub const IFLA_STATS_UNSPEC: _bindgen_ty_101 = 0;
+pub const IFLA_STATS_LINK_64: _bindgen_ty_101 = 1;
+pub const IFLA_STATS_LINK_XSTATS: _bindgen_ty_101 = 2;
+pub const IFLA_STATS_LINK_XSTATS_SLAVE: _bindgen_ty_101 = 3;
+pub const IFLA_STATS_LINK_OFFLOAD_XSTATS: _bindgen_ty_101 = 4;
+pub const IFLA_STATS_AF_SPEC: _bindgen_ty_101 = 5;
+pub const __IFLA_STATS_MAX: _bindgen_ty_101 = 6;
+pub type _bindgen_ty_101 = crate::types::c_uint;
+pub const IFLA_STATS_GETSET_UNSPEC: _bindgen_ty_102 = 0;
+pub const IFLA_STATS_GET_FILTERS: _bindgen_ty_102 = 1;
+pub const IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS: _bindgen_ty_102 = 2;
+pub const __IFLA_STATS_GETSET_MAX: _bindgen_ty_102 = 3;
+pub type _bindgen_ty_102 = crate::types::c_uint;
+pub const LINK_XSTATS_TYPE_UNSPEC: _bindgen_ty_103 = 0;
+pub const LINK_XSTATS_TYPE_BRIDGE: _bindgen_ty_103 = 1;
+pub const LINK_XSTATS_TYPE_BOND: _bindgen_ty_103 = 2;
+pub const __LINK_XSTATS_TYPE_MAX: _bindgen_ty_103 = 3;
+pub type _bindgen_ty_103 = crate::types::c_uint;
+pub const IFLA_OFFLOAD_XSTATS_UNSPEC: _bindgen_ty_104 = 0;
+pub const IFLA_OFFLOAD_XSTATS_CPU_HIT: _bindgen_ty_104 = 1;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO: _bindgen_ty_104 = 2;
+pub const IFLA_OFFLOAD_XSTATS_L3_STATS: _bindgen_ty_104 = 3;
+pub const __IFLA_OFFLOAD_XSTATS_MAX: _bindgen_ty_104 = 4;
+pub type _bindgen_ty_104 = crate::types::c_uint;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC: _bindgen_ty_105 = 0;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST: _bindgen_ty_105 = 1;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED: _bindgen_ty_105 = 2;
+pub const __IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX: _bindgen_ty_105 = 3;
+pub type _bindgen_ty_105 = crate::types::c_uint;
+pub const XDP_ATTACHED_NONE: _bindgen_ty_106 = 0;
+pub const XDP_ATTACHED_DRV: _bindgen_ty_106 = 1;
+pub const XDP_ATTACHED_SKB: _bindgen_ty_106 = 2;
+pub const XDP_ATTACHED_HW: _bindgen_ty_106 = 3;
+pub const XDP_ATTACHED_MULTI: _bindgen_ty_106 = 4;
+pub type _bindgen_ty_106 = crate::types::c_uint;
+pub const IFLA_XDP_UNSPEC: _bindgen_ty_107 = 0;
+pub const IFLA_XDP_FD: _bindgen_ty_107 = 1;
+pub const IFLA_XDP_ATTACHED: _bindgen_ty_107 = 2;
+pub const IFLA_XDP_FLAGS: _bindgen_ty_107 = 3;
+pub const IFLA_XDP_PROG_ID: _bindgen_ty_107 = 4;
+pub const IFLA_XDP_DRV_PROG_ID: _bindgen_ty_107 = 5;
+pub const IFLA_XDP_SKB_PROG_ID: _bindgen_ty_107 = 6;
+pub const IFLA_XDP_HW_PROG_ID: _bindgen_ty_107 = 7;
+pub const IFLA_XDP_EXPECTED_FD: _bindgen_ty_107 = 8;
+pub const __IFLA_XDP_MAX: _bindgen_ty_107 = 9;
+pub type _bindgen_ty_107 = crate::types::c_uint;
+pub const IFLA_EVENT_NONE: _bindgen_ty_108 = 0;
+pub const IFLA_EVENT_REBOOT: _bindgen_ty_108 = 1;
+pub const IFLA_EVENT_FEATURES: _bindgen_ty_108 = 2;
+pub const IFLA_EVENT_BONDING_FAILOVER: _bindgen_ty_108 = 3;
+pub const IFLA_EVENT_NOTIFY_PEERS: _bindgen_ty_108 = 4;
+pub const IFLA_EVENT_IGMP_RESEND: _bindgen_ty_108 = 5;
+pub const IFLA_EVENT_BONDING_OPTIONS: _bindgen_ty_108 = 6;
+pub type _bindgen_ty_108 = crate::types::c_uint;
+pub const IFLA_TUN_UNSPEC: _bindgen_ty_109 = 0;
+pub const IFLA_TUN_OWNER: _bindgen_ty_109 = 1;
+pub const IFLA_TUN_GROUP: _bindgen_ty_109 = 2;
+pub const IFLA_TUN_TYPE: _bindgen_ty_109 = 3;
+pub const IFLA_TUN_PI: _bindgen_ty_109 = 4;
+pub const IFLA_TUN_VNET_HDR: _bindgen_ty_109 = 5;
+pub const IFLA_TUN_PERSIST: _bindgen_ty_109 = 6;
+pub const IFLA_TUN_MULTI_QUEUE: _bindgen_ty_109 = 7;
+pub const IFLA_TUN_NUM_QUEUES: _bindgen_ty_109 = 8;
+pub const IFLA_TUN_NUM_DISABLED_QUEUES: _bindgen_ty_109 = 9;
+pub const __IFLA_TUN_MAX: _bindgen_ty_109 = 10;
+pub type _bindgen_ty_109 = crate::types::c_uint;
+pub const IFLA_RMNET_UNSPEC: _bindgen_ty_110 = 0;
+pub const IFLA_RMNET_MUX_ID: _bindgen_ty_110 = 1;
+pub const IFLA_RMNET_FLAGS: _bindgen_ty_110 = 2;
+pub const __IFLA_RMNET_MAX: _bindgen_ty_110 = 3;
+pub type _bindgen_ty_110 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_rmnet_flags {
+    pub flags: __u32,
+    pub mask: __u32,
+}
+pub const IFLA_MCTP_UNSPEC: _bindgen_ty_111 = 0;
+pub const IFLA_MCTP_NET: _bindgen_ty_111 = 1;
+pub const __IFLA_MCTP_MAX: _bindgen_ty_111 = 2;
+pub type _bindgen_ty_111 = crate::types::c_uint;
+pub const IFLA_DSA_UNSPEC: _bindgen_ty_112 = 0;
+pub const IFLA_DSA_MASTER: _bindgen_ty_112 = 1;
+pub const __IFLA_DSA_MAX: _bindgen_ty_112 = 2;
+pub type _bindgen_ty_112 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifaddrmsg {
+    pub ifa_family: __u8,
+    pub ifa_prefixlen: __u8,
+    pub ifa_flags: __u8,
+    pub ifa_scope: __u8,
+    pub ifa_index: __u32,
+}
+pub const IFA_UNSPEC: _bindgen_ty_113 = 0;
+pub const IFA_ADDRESS: _bindgen_ty_113 = 1;
+pub const IFA_LOCAL: _bindgen_ty_113 = 2;
+pub const IFA_LABEL: _bindgen_ty_113 = 3;
+pub const IFA_BROADCAST: _bindgen_ty_113 = 4;
+pub const IFA_ANYCAST: _bindgen_ty_113 = 5;
+pub const IFA_CACHEINFO: _bindgen_ty_113 = 6;
+pub const IFA_MULTICAST: _bindgen_ty_113 = 7;
+pub const IFA_FLAGS: _bindgen_ty_113 = 8;
+pub const IFA_RT_PRIORITY: _bindgen_ty_113 = 9;
+pub const IFA_TARGET_NETNSID: _bindgen_ty_113 = 10;
+pub const IFA_PROTO: _bindgen_ty_113 = 11;
+pub const __IFA_MAX: _bindgen_ty_113 = 12;
+pub type _bindgen_ty_113 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifa_cacheinfo {
+    pub ifa_prefered: __u32,
+    pub ifa_valid: __u32,
+    pub cstamp: __u32,
+    pub tstamp: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndmsg {
+    pub ndm_family: __u8,
+    pub ndm_pad1: __u8,
+    pub ndm_pad2: __u16,
+    pub ndm_ifindex: __s32,
+    pub ndm_state: __u16,
+    pub ndm_flags: __u8,
+    pub ndm_type: __u8,
+}
+pub const NDA_UNSPEC: _bindgen_ty_114 = 0;
+pub const NDA_DST: _bindgen_ty_114 = 1;
+pub const NDA_LLADDR: _bindgen_ty_114 = 2;
+pub const NDA_CACHEINFO: _bindgen_ty_114 = 3;
+pub const NDA_PROBES: _bindgen_ty_114 = 4;
+pub const NDA_VLAN: _bindgen_ty_114 = 5;
+pub const NDA_PORT: _bindgen_ty_114 = 6;
+pub const NDA_VNI: _bindgen_ty_114 = 7;
+pub const NDA_IFINDEX: _bindgen_ty_114 = 8;
+pub const NDA_MASTER: _bindgen_ty_114 = 9;
+pub const NDA_LINK_NETNSID: _bindgen_ty_114 = 10;
+pub const NDA_SRC_VNI: _bindgen_ty_114 = 11;
+pub const NDA_PROTOCOL: _bindgen_ty_114 = 12;
+pub const NDA_NH_ID: _bindgen_ty_114 = 13;
+pub const NDA_FDB_EXT_ATTRS: _bindgen_ty_114 = 14;
+pub const NDA_FLAGS_EXT: _bindgen_ty_114 = 15;
+pub const NDA_NDM_STATE_MASK: _bindgen_ty_114 = 16;
+pub const NDA_NDM_FLAGS_MASK: _bindgen_ty_114 = 17;
+pub const __NDA_MAX: _bindgen_ty_114 = 18;
+pub type _bindgen_ty_114 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct nda_cacheinfo {
+    pub ndm_confirmed: __u32,
+    pub ndm_used: __u32,
+    pub ndm_updated: __u32,
+    pub ndm_refcnt: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndt_stats {
+    pub ndts_allocs: __u64,
+    pub ndts_destroys: __u64,
+    pub ndts_hash_grows: __u64,
+    pub ndts_res_failed: __u64,
+    pub ndts_lookups: __u64,
+    pub ndts_hits: __u64,
+    pub ndts_rcv_probes_mcast: __u64,
+    pub ndts_rcv_probes_ucast: __u64,
+    pub ndts_periodic_gc_runs: __u64,
+    pub ndts_forced_gc_runs: __u64,
+    pub ndts_table_fulls: __u64,
+}
+pub const NDTPA_UNSPEC: _bindgen_ty_115 = 0;
+pub const NDTPA_IFINDEX: _bindgen_ty_115 = 1;
+pub const NDTPA_REFCNT: _bindgen_ty_115 = 2;
+pub const NDTPA_REACHABLE_TIME: _bindgen_ty_115 = 3;
+pub const NDTPA_BASE_REACHABLE_TIME: _bindgen_ty_115 = 4;
+pub const NDTPA_RETRANS_TIME: _bindgen_ty_115 = 5;
+pub const NDTPA_GC_STALETIME: _bindgen_ty_115 = 6;
+pub const NDTPA_DELAY_PROBE_TIME: _bindgen_ty_115 = 7;
+pub const NDTPA_QUEUE_LEN: _bindgen_ty_115 = 8;
+pub const NDTPA_APP_PROBES: _bindgen_ty_115 = 9;
+pub const NDTPA_UCAST_PROBES: _bindgen_ty_115 = 10;
+pub const NDTPA_MCAST_PROBES: _bindgen_ty_115 = 11;
+pub const NDTPA_ANYCAST_DELAY: _bindgen_ty_115 = 12;
+pub const NDTPA_PROXY_DELAY: _bindgen_ty_115 = 13;
+pub const NDTPA_PROXY_QLEN: _bindgen_ty_115 = 14;
+pub const NDTPA_LOCKTIME: _bindgen_ty_115 = 15;
+pub const NDTPA_QUEUE_LENBYTES: _bindgen_ty_115 = 16;
+pub const NDTPA_MCAST_REPROBES: _bindgen_ty_115 = 17;
+pub const NDTPA_PAD: _bindgen_ty_115 = 18;
+pub const NDTPA_INTERVAL_PROBE_TIME_MS: _bindgen_ty_115 = 19;
+pub const __NDTPA_MAX: _bindgen_ty_115 = 20;
+pub type _bindgen_ty_115 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndtmsg {
+    pub ndtm_family: __u8,
+    pub ndtm_pad1: __u8,
+    pub ndtm_pad2: __u16,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndt_config {
+    pub ndtc_key_len: __u16,
+    pub ndtc_entry_size: __u16,
+    pub ndtc_entries: __u32,
+    pub ndtc_last_flush: __u32,
+    pub ndtc_last_rand: __u32,
+    pub ndtc_hash_rnd: __u32,
+    pub ndtc_hash_mask: __u32,
+    pub ndtc_hash_chain_gc: __u32,
+    pub ndtc_proxy_qlen: __u32,
+}
+pub const NDTA_UNSPEC: _bindgen_ty_116 = 0;
+pub const NDTA_NAME: _bindgen_ty_116 = 1;
+pub const NDTA_THRESH1: _bindgen_ty_116 = 2;
+pub const NDTA_THRESH2: _bindgen_ty_116 = 3;
+pub const NDTA_THRESH3: _bindgen_ty_116 = 4;
+pub const NDTA_CONFIG: _bindgen_ty_116 = 5;
+pub const NDTA_PARMS: _bindgen_ty_116 = 6;
+pub const NDTA_STATS: _bindgen_ty_116 = 7;
+pub const NDTA_GC_INTERVAL: _bindgen_ty_116 = 8;
+pub const NDTA_PAD: _bindgen_ty_116 = 9;
+pub const __NDTA_MAX: _bindgen_ty_116 = 10;
+pub type _bindgen_ty_116 = crate::types::c_uint;
+pub const FDB_NOTIFY_BIT: _bindgen_ty_117 = 1;
+pub const FDB_NOTIFY_INACTIVE_BIT: _bindgen_ty_117 = 2;
+pub type _bindgen_ty_117 = crate::types::c_uint;
+pub const NFEA_UNSPEC: _bindgen_ty_118 = 0;
+pub const NFEA_ACTIVITY_NOTIFY: _bindgen_ty_118 = 1;
+pub const NFEA_DONT_REFRESH: _bindgen_ty_118 = 2;
+pub const __NFEA_MAX: _bindgen_ty_118 = 3;
+pub type _bindgen_ty_118 = crate::types::c_uint;
+pub const RTM_BASE: _bindgen_ty_119 = 16;
+pub const RTM_NEWLINK: _bindgen_ty_119 = 16;
+pub const RTM_DELLINK: _bindgen_ty_119 = 17;
+pub const RTM_GETLINK: _bindgen_ty_119 = 18;
+pub const RTM_SETLINK: _bindgen_ty_119 = 19;
+pub const RTM_NEWADDR: _bindgen_ty_119 = 20;
+pub const RTM_DELADDR: _bindgen_ty_119 = 21;
+pub const RTM_GETADDR: _bindgen_ty_119 = 22;
+pub const RTM_NEWROUTE: _bindgen_ty_119 = 24;
+pub const RTM_DELROUTE: _bindgen_ty_119 = 25;
+pub const RTM_GETROUTE: _bindgen_ty_119 = 26;
+pub const RTM_NEWNEIGH: _bindgen_ty_119 = 28;
+pub const RTM_DELNEIGH: _bindgen_ty_119 = 29;
+pub const RTM_GETNEIGH: _bindgen_ty_119 = 30;
+pub const RTM_NEWRULE: _bindgen_ty_119 = 32;
+pub const RTM_DELRULE: _bindgen_ty_119 = 33;
+pub const RTM_GETRULE: _bindgen_ty_119 = 34;
+pub const RTM_NEWQDISC: _bindgen_ty_119 = 36;
+pub const RTM_DELQDISC: _bindgen_ty_119 = 37;
+pub const RTM_GETQDISC: _bindgen_ty_119 = 38;
+pub const RTM_NEWTCLASS: _bindgen_ty_119 = 40;
+pub const RTM_DELTCLASS: _bindgen_ty_119 = 41;
+pub const RTM_GETTCLASS: _bindgen_ty_119 = 42;
+pub const RTM_NEWTFILTER: _bindgen_ty_119 = 44;
+pub const RTM_DELTFILTER: _bindgen_ty_119 = 45;
+pub const RTM_GETTFILTER: _bindgen_ty_119 = 46;
+pub const RTM_NEWACTION: _bindgen_ty_119 = 48;
+pub const RTM_DELACTION: _bindgen_ty_119 = 49;
+pub const RTM_GETACTION: _bindgen_ty_119 = 50;
+pub const RTM_NEWPREFIX: _bindgen_ty_119 = 52;
+pub const RTM_GETMULTICAST: _bindgen_ty_119 = 58;
+pub const RTM_GETANYCAST: _bindgen_ty_119 = 62;
+pub const RTM_NEWNEIGHTBL: _bindgen_ty_119 = 64;
+pub const RTM_GETNEIGHTBL: _bindgen_ty_119 = 66;
+pub const RTM_SETNEIGHTBL: _bindgen_ty_119 = 67;
+pub const RTM_NEWNDUSEROPT: _bindgen_ty_119 = 68;
+pub const RTM_NEWADDRLABEL: _bindgen_ty_119 = 72;
+pub const RTM_DELADDRLABEL: _bindgen_ty_119 = 73;
+pub const RTM_GETADDRLABEL: _bindgen_ty_119 = 74;
+pub const RTM_GETDCB: _bindgen_ty_119 = 78;
+pub const RTM_SETDCB: _bindgen_ty_119 = 79;
+pub const RTM_NEWNETCONF: _bindgen_ty_119 = 80;
+pub const RTM_DELNETCONF: _bindgen_ty_119 = 81;
+pub const RTM_GETNETCONF: _bindgen_ty_119 = 82;
+pub const RTM_NEWMDB: _bindgen_ty_119 = 84;
+pub const RTM_DELMDB: _bindgen_ty_119 = 85;
+pub const RTM_GETMDB: _bindgen_ty_119 = 86;
+pub const RTM_NEWNSID: _bindgen_ty_119 = 88;
+pub const RTM_DELNSID: _bindgen_ty_119 = 89;
+pub const RTM_GETNSID: _bindgen_ty_119 = 90;
+pub const RTM_NEWSTATS: _bindgen_ty_119 = 92;
+pub const RTM_GETSTATS: _bindgen_ty_119 = 94;
+pub const RTM_SETSTATS: _bindgen_ty_119 = 95;
+pub const RTM_NEWCACHEREPORT: _bindgen_ty_119 = 96;
+pub const RTM_NEWCHAIN: _bindgen_ty_119 = 100;
+pub const RTM_DELCHAIN: _bindgen_ty_119 = 101;
+pub const RTM_GETCHAIN: _bindgen_ty_119 = 102;
+pub const RTM_NEWNEXTHOP: _bindgen_ty_119 = 104;
+pub const RTM_DELNEXTHOP: _bindgen_ty_119 = 105;
+pub const RTM_GETNEXTHOP: _bindgen_ty_119 = 106;
+pub const RTM_NEWLINKPROP: _bindgen_ty_119 = 108;
+pub const RTM_DELLINKPROP: _bindgen_ty_119 = 109;
+pub const RTM_GETLINKPROP: _bindgen_ty_119 = 110;
+pub const RTM_NEWVLAN: _bindgen_ty_119 = 112;
+pub const RTM_DELVLAN: _bindgen_ty_119 = 113;
+pub const RTM_GETVLAN: _bindgen_ty_119 = 114;
+pub const RTM_NEWNEXTHOPBUCKET: _bindgen_ty_119 = 116;
+pub const RTM_DELNEXTHOPBUCKET: _bindgen_ty_119 = 117;
+pub const RTM_GETNEXTHOPBUCKET: _bindgen_ty_119 = 118;
+pub const RTM_NEWTUNNEL: _bindgen_ty_119 = 120;
+pub const RTM_DELTUNNEL: _bindgen_ty_119 = 121;
+pub const RTM_GETTUNNEL: _bindgen_ty_119 = 122;
+pub const __RTM_MAX: _bindgen_ty_119 = 123;
+pub type _bindgen_ty_119 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtattr {
+    pub rta_len: crate::types::c_ushort,
+    pub rta_type: crate::types::c_ushort,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtmsg {
+    pub rtm_family: crate::types::c_uchar,
+    pub rtm_dst_len: crate::types::c_uchar,
+    pub rtm_src_len: crate::types::c_uchar,
+    pub rtm_tos: crate::types::c_uchar,
+    pub rtm_table: crate::types::c_uchar,
+    pub rtm_protocol: crate::types::c_uchar,
+    pub rtm_scope: crate::types::c_uchar,
+    pub rtm_type: crate::types::c_uchar,
+    pub rtm_flags: crate::types::c_uint,
+}
+pub const RTN_UNSPEC: _bindgen_ty_120 = 0;
+pub const RTN_UNICAST: _bindgen_ty_120 = 1;
+pub const RTN_LOCAL: _bindgen_ty_120 = 2;
+pub const RTN_BROADCAST: _bindgen_ty_120 = 3;
+pub const RTN_ANYCAST: _bindgen_ty_120 = 4;
+pub const RTN_MULTICAST: _bindgen_ty_120 = 5;
+pub const RTN_BLACKHOLE: _bindgen_ty_120 = 6;
+pub const RTN_UNREACHABLE: _bindgen_ty_120 = 7;
+pub const RTN_PROHIBIT: _bindgen_ty_120 = 8;
+pub const RTN_THROW: _bindgen_ty_120 = 9;
+pub const RTN_NAT: _bindgen_ty_120 = 10;
+pub const RTN_XRESOLVE: _bindgen_ty_120 = 11;
+pub const __RTN_MAX: _bindgen_ty_120 = 12;
+pub type _bindgen_ty_120 = crate::types::c_uint;
+pub const rt_scope_t_RT_SCOPE_UNIVERSE: rt_scope_t = 0;
+pub const rt_scope_t_RT_SCOPE_SITE: rt_scope_t = 200;
+pub const rt_scope_t_RT_SCOPE_LINK: rt_scope_t = 253;
+pub const rt_scope_t_RT_SCOPE_HOST: rt_scope_t = 254;
+pub const rt_scope_t_RT_SCOPE_NOWHERE: rt_scope_t = 255;
+pub type rt_scope_t = crate::types::c_uint;
+pub const rt_class_t_RT_TABLE_UNSPEC: rt_class_t = 0;
+pub const rt_class_t_RT_TABLE_COMPAT: rt_class_t = 252;
+pub const rt_class_t_RT_TABLE_DEFAULT: rt_class_t = 253;
+pub const rt_class_t_RT_TABLE_MAIN: rt_class_t = 254;
+pub const rt_class_t_RT_TABLE_LOCAL: rt_class_t = 255;
+pub const rt_class_t_RT_TABLE_MAX: rt_class_t = 4294967295;
+pub type rt_class_t = crate::types::c_uint;
+pub const rtattr_type_t_RTA_UNSPEC: rtattr_type_t = 0;
+pub const rtattr_type_t_RTA_DST: rtattr_type_t = 1;
+pub const rtattr_type_t_RTA_SRC: rtattr_type_t = 2;
+pub const rtattr_type_t_RTA_IIF: rtattr_type_t = 3;
+pub const rtattr_type_t_RTA_OIF: rtattr_type_t = 4;
+pub const rtattr_type_t_RTA_GATEWAY: rtattr_type_t = 5;
+pub const rtattr_type_t_RTA_PRIORITY: rtattr_type_t = 6;
+pub const rtattr_type_t_RTA_PREFSRC: rtattr_type_t = 7;
+pub const rtattr_type_t_RTA_METRICS: rtattr_type_t = 8;
+pub const rtattr_type_t_RTA_MULTIPATH: rtattr_type_t = 9;
+pub const rtattr_type_t_RTA_PROTOINFO: rtattr_type_t = 10;
+pub const rtattr_type_t_RTA_FLOW: rtattr_type_t = 11;
+pub const rtattr_type_t_RTA_CACHEINFO: rtattr_type_t = 12;
+pub const rtattr_type_t_RTA_SESSION: rtattr_type_t = 13;
+pub const rtattr_type_t_RTA_MP_ALGO: rtattr_type_t = 14;
+pub const rtattr_type_t_RTA_TABLE: rtattr_type_t = 15;
+pub const rtattr_type_t_RTA_MARK: rtattr_type_t = 16;
+pub const rtattr_type_t_RTA_MFC_STATS: rtattr_type_t = 17;
+pub const rtattr_type_t_RTA_VIA: rtattr_type_t = 18;
+pub const rtattr_type_t_RTA_NEWDST: rtattr_type_t = 19;
+pub const rtattr_type_t_RTA_PREF: rtattr_type_t = 20;
+pub const rtattr_type_t_RTA_ENCAP_TYPE: rtattr_type_t = 21;
+pub const rtattr_type_t_RTA_ENCAP: rtattr_type_t = 22;
+pub const rtattr_type_t_RTA_EXPIRES: rtattr_type_t = 23;
+pub const rtattr_type_t_RTA_PAD: rtattr_type_t = 24;
+pub const rtattr_type_t_RTA_UID: rtattr_type_t = 25;
+pub const rtattr_type_t_RTA_TTL_PROPAGATE: rtattr_type_t = 26;
+pub const rtattr_type_t_RTA_IP_PROTO: rtattr_type_t = 27;
+pub const rtattr_type_t_RTA_SPORT: rtattr_type_t = 28;
+pub const rtattr_type_t_RTA_DPORT: rtattr_type_t = 29;
+pub const rtattr_type_t_RTA_NH_ID: rtattr_type_t = 30;
+pub const rtattr_type_t___RTA_MAX: rtattr_type_t = 31;
+pub type rtattr_type_t = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnexthop {
+    pub rtnh_len: crate::types::c_ushort,
+    pub rtnh_flags: crate::types::c_uchar,
+    pub rtnh_hops: crate::types::c_uchar,
+    pub rtnh_ifindex: crate::types::c_int,
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct rtvia {
+    pub rtvia_family: __kernel_sa_family_t,
+    pub rtvia_addr: __IncompleteArrayField<__u8>,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_cacheinfo {
+    pub rta_clntref: __u32,
+    pub rta_lastuse: __u32,
+    pub rta_expires: __s32,
+    pub rta_error: __u32,
+    pub rta_used: __u32,
+    pub rta_id: __u32,
+    pub rta_ts: __u32,
+    pub rta_tsage: __u32,
+}
+pub const RTAX_UNSPEC: _bindgen_ty_121 = 0;
+pub const RTAX_LOCK: _bindgen_ty_121 = 1;
+pub const RTAX_MTU: _bindgen_ty_121 = 2;
+pub const RTAX_WINDOW: _bindgen_ty_121 = 3;
+pub const RTAX_RTT: _bindgen_ty_121 = 4;
+pub const RTAX_RTTVAR: _bindgen_ty_121 = 5;
+pub const RTAX_SSTHRESH: _bindgen_ty_121 = 6;
+pub const RTAX_CWND: _bindgen_ty_121 = 7;
+pub const RTAX_ADVMSS: _bindgen_ty_121 = 8;
+pub const RTAX_REORDERING: _bindgen_ty_121 = 9;
+pub const RTAX_HOPLIMIT: _bindgen_ty_121 = 10;
+pub const RTAX_INITCWND: _bindgen_ty_121 = 11;
+pub const RTAX_FEATURES: _bindgen_ty_121 = 12;
+pub const RTAX_RTO_MIN: _bindgen_ty_121 = 13;
+pub const RTAX_INITRWND: _bindgen_ty_121 = 14;
+pub const RTAX_QUICKACK: _bindgen_ty_121 = 15;
+pub const RTAX_CC_ALGO: _bindgen_ty_121 = 16;
+pub const RTAX_FASTOPEN_NO_COOKIE: _bindgen_ty_121 = 17;
+pub const __RTAX_MAX: _bindgen_ty_121 = 18;
+pub type _bindgen_ty_121 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct rta_session {
+    pub proto: __u8,
+    pub pad1: __u8,
+    pub pad2: __u16,
+    pub u: rta_session__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union rta_session__bindgen_ty_1 {
+    pub ports: rta_session__bindgen_ty_1__bindgen_ty_1,
+    pub icmpt: rta_session__bindgen_ty_1__bindgen_ty_2,
+    pub spi: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_session__bindgen_ty_1__bindgen_ty_1 {
+    pub sport: __u16,
+    pub dport: __u16,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_session__bindgen_ty_1__bindgen_ty_2 {
+    pub type_: __u8,
+    pub code: __u8,
+    pub ident: __u16,
+}
+impl Default for rta_session__bindgen_ty_1 {
+    fn default() -> Self {
+        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+impl Default for rta_session {
+    fn default() -> Self {
+        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_mfc_stats {
+    pub mfcs_packets: __u64,
+    pub mfcs_bytes: __u64,
+    pub mfcs_wrong_if: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtgenmsg {
+    pub rtgen_family: crate::types::c_uchar,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifinfomsg {
+    pub ifi_family: crate::types::c_uchar,
+    pub __ifi_pad: crate::types::c_uchar,
+    pub ifi_type: crate::types::c_ushort,
+    pub ifi_index: crate::types::c_int,
+    pub ifi_flags: crate::types::c_uint,
+    pub ifi_change: crate::types::c_uint,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct prefixmsg {
+    pub prefix_family: crate::types::c_uchar,
+    pub prefix_pad1: crate::types::c_uchar,
+    pub prefix_pad2: crate::types::c_ushort,
+    pub prefix_ifindex: crate::types::c_int,
+    pub prefix_type: crate::types::c_uchar,
+    pub prefix_len: crate::types::c_uchar,
+    pub prefix_flags: crate::types::c_uchar,
+    pub prefix_pad3: crate::types::c_uchar,
+}
+pub const PREFIX_UNSPEC: _bindgen_ty_122 = 0;
+pub const PREFIX_ADDRESS: _bindgen_ty_122 = 1;
+pub const PREFIX_CACHEINFO: _bindgen_ty_122 = 2;
+pub const __PREFIX_MAX: _bindgen_ty_122 = 3;
+pub type _bindgen_ty_122 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct prefix_cacheinfo {
+    pub preferred_time: __u32,
+    pub valid_time: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tcmsg {
+    pub tcm_family: crate::types::c_uchar,
+    pub tcm__pad1: crate::types::c_uchar,
+    pub tcm__pad2: crate::types::c_ushort,
+    pub tcm_ifindex: crate::types::c_int,
+    pub tcm_handle: __u32,
+    pub tcm_parent: __u32,
+    pub tcm_info: __u32,
+}
+pub const TCA_UNSPEC: _bindgen_ty_123 = 0;
+pub const TCA_KIND: _bindgen_ty_123 = 1;
+pub const TCA_OPTIONS: _bindgen_ty_123 = 2;
+pub const TCA_STATS: _bindgen_ty_123 = 3;
+pub const TCA_XSTATS: _bindgen_ty_123 = 4;
+pub const TCA_RATE: _bindgen_ty_123 = 5;
+pub const TCA_FCNT: _bindgen_ty_123 = 6;
+pub const TCA_STATS2: _bindgen_ty_123 = 7;
+pub const TCA_STAB: _bindgen_ty_123 = 8;
+pub const TCA_PAD: _bindgen_ty_123 = 9;
+pub const TCA_DUMP_INVISIBLE: _bindgen_ty_123 = 10;
+pub const TCA_CHAIN: _bindgen_ty_123 = 11;
+pub const TCA_HW_OFFLOAD: _bindgen_ty_123 = 12;
+pub const TCA_INGRESS_BLOCK: _bindgen_ty_123 = 13;
+pub const TCA_EGRESS_BLOCK: _bindgen_ty_123 = 14;
+pub const TCA_DUMP_FLAGS: _bindgen_ty_123 = 15;
+pub const TCA_EXT_WARN_MSG: _bindgen_ty_123 = 16;
+pub const __TCA_MAX: _bindgen_ty_123 = 17;
+pub type _bindgen_ty_123 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct nduseroptmsg {
+    pub nduseropt_family: crate::types::c_uchar,
+    pub nduseropt_pad1: crate::types::c_uchar,
+    pub nduseropt_opts_len: crate::types::c_ushort,
+    pub nduseropt_ifindex: crate::types::c_int,
+    pub nduseropt_icmp_type: __u8,
+    pub nduseropt_icmp_code: __u8,
+    pub nduseropt_pad2: crate::types::c_ushort,
+    pub nduseropt_pad3: crate::types::c_uint,
+}
+pub const NDUSEROPT_UNSPEC: _bindgen_ty_124 = 0;
+pub const NDUSEROPT_SRCADDR: _bindgen_ty_124 = 1;
+pub const __NDUSEROPT_MAX: _bindgen_ty_124 = 2;
+pub type _bindgen_ty_124 = crate::types::c_uint;
+pub const rtnetlink_groups_RTNLGRP_NONE: rtnetlink_groups = 0;
+pub const rtnetlink_groups_RTNLGRP_LINK: rtnetlink_groups = 1;
+pub const rtnetlink_groups_RTNLGRP_NOTIFY: rtnetlink_groups = 2;
+pub const rtnetlink_groups_RTNLGRP_NEIGH: rtnetlink_groups = 3;
+pub const rtnetlink_groups_RTNLGRP_TC: rtnetlink_groups = 4;
+pub const rtnetlink_groups_RTNLGRP_IPV4_IFADDR: rtnetlink_groups = 5;
+pub const rtnetlink_groups_RTNLGRP_IPV4_MROUTE: rtnetlink_groups = 6;
+pub const rtnetlink_groups_RTNLGRP_IPV4_ROUTE: rtnetlink_groups = 7;
+pub const rtnetlink_groups_RTNLGRP_IPV4_RULE: rtnetlink_groups = 8;
+pub const rtnetlink_groups_RTNLGRP_IPV6_IFADDR: rtnetlink_groups = 9;
+pub const rtnetlink_groups_RTNLGRP_IPV6_MROUTE: rtnetlink_groups = 10;
+pub const rtnetlink_groups_RTNLGRP_IPV6_ROUTE: rtnetlink_groups = 11;
+pub const rtnetlink_groups_RTNLGRP_IPV6_IFINFO: rtnetlink_groups = 12;
+pub const rtnetlink_groups_RTNLGRP_DECnet_IFADDR: rtnetlink_groups = 13;
+pub const rtnetlink_groups_RTNLGRP_NOP2: rtnetlink_groups = 14;
+pub const rtnetlink_groups_RTNLGRP_DECnet_ROUTE: rtnetlink_groups = 15;
+pub const rtnetlink_groups_RTNLGRP_DECnet_RULE: rtnetlink_groups = 16;
+pub const rtnetlink_groups_RTNLGRP_NOP4: rtnetlink_groups = 17;
+pub const rtnetlink_groups_RTNLGRP_IPV6_PREFIX: rtnetlink_groups = 18;
+pub const rtnetlink_groups_RTNLGRP_IPV6_RULE: rtnetlink_groups = 19;
+pub const rtnetlink_groups_RTNLGRP_ND_USEROPT: rtnetlink_groups = 20;
+pub const rtnetlink_groups_RTNLGRP_PHONET_IFADDR: rtnetlink_groups = 21;
+pub const rtnetlink_groups_RTNLGRP_PHONET_ROUTE: rtnetlink_groups = 22;
+pub const rtnetlink_groups_RTNLGRP_DCB: rtnetlink_groups = 23;
+pub const rtnetlink_groups_RTNLGRP_IPV4_NETCONF: rtnetlink_groups = 24;
+pub const rtnetlink_groups_RTNLGRP_IPV6_NETCONF: rtnetlink_groups = 25;
+pub const rtnetlink_groups_RTNLGRP_MDB: rtnetlink_groups = 26;
+pub const rtnetlink_groups_RTNLGRP_MPLS_ROUTE: rtnetlink_groups = 27;
+pub const rtnetlink_groups_RTNLGRP_NSID: rtnetlink_groups = 28;
+pub const rtnetlink_groups_RTNLGRP_MPLS_NETCONF: rtnetlink_groups = 29;
+pub const rtnetlink_groups_RTNLGRP_IPV4_MROUTE_R: rtnetlink_groups = 30;
+pub const rtnetlink_groups_RTNLGRP_IPV6_MROUTE_R: rtnetlink_groups = 31;
+pub const rtnetlink_groups_RTNLGRP_NEXTHOP: rtnetlink_groups = 32;
+pub const rtnetlink_groups_RTNLGRP_BRVLAN: rtnetlink_groups = 33;
+pub const rtnetlink_groups_RTNLGRP_MCTP_IFADDR: rtnetlink_groups = 34;
+pub const rtnetlink_groups_RTNLGRP_TUNNEL: rtnetlink_groups = 35;
+pub const rtnetlink_groups_RTNLGRP_STATS: rtnetlink_groups = 36;
+pub const rtnetlink_groups___RTNLGRP_MAX: rtnetlink_groups = 37;
+pub type rtnetlink_groups = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tcamsg {
+    pub tca_family: crate::types::c_uchar,
+    pub tca__pad1: crate::types::c_uchar,
+    pub tca__pad2: crate::types::c_ushort,
+}
+pub const TCA_ROOT_UNSPEC: _bindgen_ty_125 = 0;
+pub const TCA_ROOT_TAB: _bindgen_ty_125 = 1;
+pub const TCA_ROOT_FLAGS: _bindgen_ty_125 = 2;
+pub const TCA_ROOT_COUNT: _bindgen_ty_125 = 3;
+pub const TCA_ROOT_TIME_DELTA: _bindgen_ty_125 = 4;
+pub const TCA_ROOT_EXT_WARN_MSG: _bindgen_ty_125 = 5;
+pub const __TCA_ROOT_MAX: _bindgen_ty_125 = 6;
+pub type _bindgen_ty_125 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
 pub struct clone_args {
     pub flags: __u64,
     pub pidfd: __u64,
@@ -15385,10 +16908,10 @@
     pub u2_sel: __le16,
     pub u2_pel: __le16,
 }
-pub const FUNCTIONFS_DESCRIPTORS_MAGIC: _bindgen_ty_61 = 1;
-pub const FUNCTIONFS_STRINGS_MAGIC: _bindgen_ty_61 = 2;
-pub const FUNCTIONFS_DESCRIPTORS_MAGIC_V2: _bindgen_ty_61 = 3;
-pub type _bindgen_ty_61 = crate::types::c_uint;
+pub const FUNCTIONFS_DESCRIPTORS_MAGIC: _bindgen_ty_126 = 1;
+pub const FUNCTIONFS_STRINGS_MAGIC: _bindgen_ty_126 = 2;
+pub const FUNCTIONFS_DESCRIPTORS_MAGIC_V2: _bindgen_ty_126 = 3;
+pub type _bindgen_ty_126 = crate::types::c_uint;
 pub const functionfs_flags_FUNCTIONFS_HAS_FS_DESC: functionfs_flags = 1;
 pub const functionfs_flags_FUNCTIONFS_HAS_HS_DESC: functionfs_flags = 2;
 pub const functionfs_flags_FUNCTIONFS_HAS_SS_DESC: functionfs_flags = 4;
diff --git a/src/starnix/lib/linux_uapi/src/riscv64.rs b/src/starnix/lib/linux_uapi/src/riscv64.rs
index 24b3827..267fdcc 100644
--- a/src/starnix/lib/linux_uapi/src/riscv64.rs
+++ b/src/starnix/lib/linux_uapi/src/riscv64.rs
@@ -3275,6 +3275,9 @@
 pub const NOTIFY_WOKENUP: u32 = 1;
 pub const NOTIFY_REMOVED: u32 = 2;
 pub const NOTIFY_COOKIE_LEN: u32 = 32;
+pub const AF_UNSPEC: u32 = 0;
+pub const AF_INET: u32 = 2;
+pub const AF_INET6: u32 = 10;
 pub const IFNAMSIZ: u32 = 16;
 pub const IFALIASZ: u32 = 256;
 pub const ALTIFNAMSIZ: u32 = 128;
@@ -4083,6 +4086,144 @@
 pub const RLIMIT_RTTIME: u32 = 15;
 pub const RLIM_NLIMITS: u32 = 16;
 pub const RLIM_INFINITY: i32 = -1;
+pub const MACVLAN_FLAG_NOPROMISC: u32 = 1;
+pub const MACVLAN_FLAG_NODST: u32 = 2;
+pub const IPVLAN_F_PRIVATE: u32 = 1;
+pub const IPVLAN_F_VEPA: u32 = 2;
+pub const TUNNEL_MSG_FLAG_STATS: u32 = 1;
+pub const TUNNEL_MSG_VALID_USER_FLAGS: u32 = 1;
+pub const MAX_VLAN_LIST_LEN: u32 = 1;
+pub const PORT_PROFILE_MAX: u32 = 40;
+pub const PORT_UUID_MAX: u32 = 16;
+pub const PORT_SELF_VF: i32 = -1;
+pub const XDP_FLAGS_UPDATE_IF_NOEXIST: u32 = 1;
+pub const XDP_FLAGS_SKB_MODE: u32 = 2;
+pub const XDP_FLAGS_DRV_MODE: u32 = 4;
+pub const XDP_FLAGS_HW_MODE: u32 = 8;
+pub const XDP_FLAGS_REPLACE: u32 = 16;
+pub const XDP_FLAGS_MODES: u32 = 14;
+pub const XDP_FLAGS_MASK: u32 = 31;
+pub const RMNET_FLAGS_INGRESS_DEAGGREGATION: u32 = 1;
+pub const RMNET_FLAGS_INGRESS_MAP_COMMANDS: u32 = 2;
+pub const RMNET_FLAGS_INGRESS_MAP_CKSUMV4: u32 = 4;
+pub const RMNET_FLAGS_EGRESS_MAP_CKSUMV4: u32 = 8;
+pub const RMNET_FLAGS_INGRESS_MAP_CKSUMV5: u32 = 16;
+pub const RMNET_FLAGS_EGRESS_MAP_CKSUMV5: u32 = 32;
+pub const IFA_F_SECONDARY: u32 = 1;
+pub const IFA_F_TEMPORARY: u32 = 1;
+pub const IFA_F_NODAD: u32 = 2;
+pub const IFA_F_OPTIMISTIC: u32 = 4;
+pub const IFA_F_DADFAILED: u32 = 8;
+pub const IFA_F_HOMEADDRESS: u32 = 16;
+pub const IFA_F_DEPRECATED: u32 = 32;
+pub const IFA_F_TENTATIVE: u32 = 64;
+pub const IFA_F_PERMANENT: u32 = 128;
+pub const IFA_F_MANAGETEMPADDR: u32 = 256;
+pub const IFA_F_NOPREFIXROUTE: u32 = 512;
+pub const IFA_F_MCAUTOJOIN: u32 = 1024;
+pub const IFA_F_STABLE_PRIVACY: u32 = 2048;
+pub const IFAPROT_UNSPEC: u32 = 0;
+pub const IFAPROT_KERNEL_LO: u32 = 1;
+pub const IFAPROT_KERNEL_RA: u32 = 2;
+pub const IFAPROT_KERNEL_LL: u32 = 3;
+pub const NTF_USE: u32 = 1;
+pub const NTF_SELF: u32 = 2;
+pub const NTF_MASTER: u32 = 4;
+pub const NTF_PROXY: u32 = 8;
+pub const NTF_EXT_LEARNED: u32 = 16;
+pub const NTF_OFFLOADED: u32 = 32;
+pub const NTF_STICKY: u32 = 64;
+pub const NTF_ROUTER: u32 = 128;
+pub const NTF_EXT_MANAGED: u32 = 1;
+pub const NTF_EXT_LOCKED: u32 = 2;
+pub const NUD_INCOMPLETE: u32 = 1;
+pub const NUD_REACHABLE: u32 = 2;
+pub const NUD_STALE: u32 = 4;
+pub const NUD_DELAY: u32 = 8;
+pub const NUD_PROBE: u32 = 16;
+pub const NUD_FAILED: u32 = 32;
+pub const NUD_NOARP: u32 = 64;
+pub const NUD_PERMANENT: u32 = 128;
+pub const NUD_NONE: u32 = 0;
+pub const RTNL_FAMILY_IPMR: u32 = 128;
+pub const RTNL_FAMILY_IP6MR: u32 = 129;
+pub const RTNL_FAMILY_MAX: u32 = 129;
+pub const RTA_ALIGNTO: u32 = 4;
+pub const RTPROT_UNSPEC: u32 = 0;
+pub const RTPROT_REDIRECT: u32 = 1;
+pub const RTPROT_KERNEL: u32 = 2;
+pub const RTPROT_BOOT: u32 = 3;
+pub const RTPROT_STATIC: u32 = 4;
+pub const RTPROT_GATED: u32 = 8;
+pub const RTPROT_RA: u32 = 9;
+pub const RTPROT_MRT: u32 = 10;
+pub const RTPROT_ZEBRA: u32 = 11;
+pub const RTPROT_BIRD: u32 = 12;
+pub const RTPROT_DNROUTED: u32 = 13;
+pub const RTPROT_XORP: u32 = 14;
+pub const RTPROT_NTK: u32 = 15;
+pub const RTPROT_DHCP: u32 = 16;
+pub const RTPROT_MROUTED: u32 = 17;
+pub const RTPROT_KEEPALIVED: u32 = 18;
+pub const RTPROT_BABEL: u32 = 42;
+pub const RTPROT_OPENR: u32 = 99;
+pub const RTPROT_BGP: u32 = 186;
+pub const RTPROT_ISIS: u32 = 187;
+pub const RTPROT_OSPF: u32 = 188;
+pub const RTPROT_RIP: u32 = 189;
+pub const RTPROT_EIGRP: u32 = 192;
+pub const RTM_F_NOTIFY: u32 = 256;
+pub const RTM_F_CLONED: u32 = 512;
+pub const RTM_F_EQUALIZE: u32 = 1024;
+pub const RTM_F_PREFIX: u32 = 2048;
+pub const RTM_F_LOOKUP_TABLE: u32 = 4096;
+pub const RTM_F_FIB_MATCH: u32 = 8192;
+pub const RTM_F_OFFLOAD: u32 = 16384;
+pub const RTM_F_TRAP: u32 = 32768;
+pub const RTM_F_OFFLOAD_FAILED: u32 = 536870912;
+pub const RTNH_F_DEAD: u32 = 1;
+pub const RTNH_F_PERVASIVE: u32 = 2;
+pub const RTNH_F_ONLINK: u32 = 4;
+pub const RTNH_F_OFFLOAD: u32 = 8;
+pub const RTNH_F_LINKDOWN: u32 = 16;
+pub const RTNH_F_UNRESOLVED: u32 = 32;
+pub const RTNH_F_TRAP: u32 = 64;
+pub const RTNH_COMPARE_MASK: u32 = 89;
+pub const RTNH_ALIGNTO: u32 = 4;
+pub const RTNETLINK_HAVE_PEERINFO: u32 = 1;
+pub const RTAX_FEATURE_ECN: u32 = 1;
+pub const RTAX_FEATURE_SACK: u32 = 2;
+pub const RTAX_FEATURE_TIMESTAMP: u32 = 4;
+pub const RTAX_FEATURE_ALLFRAG: u32 = 8;
+pub const RTAX_FEATURE_MASK: u32 = 15;
+pub const TCM_IFINDEX_MAGIC_BLOCK: u32 = 4294967295;
+pub const TCA_DUMP_FLAGS_TERSE: u32 = 1;
+pub const RTMGRP_LINK: u32 = 1;
+pub const RTMGRP_NOTIFY: u32 = 2;
+pub const RTMGRP_NEIGH: u32 = 4;
+pub const RTMGRP_TC: u32 = 8;
+pub const RTMGRP_IPV4_IFADDR: u32 = 16;
+pub const RTMGRP_IPV4_MROUTE: u32 = 32;
+pub const RTMGRP_IPV4_ROUTE: u32 = 64;
+pub const RTMGRP_IPV4_RULE: u32 = 128;
+pub const RTMGRP_IPV6_IFADDR: u32 = 256;
+pub const RTMGRP_IPV6_MROUTE: u32 = 512;
+pub const RTMGRP_IPV6_ROUTE: u32 = 1024;
+pub const RTMGRP_IPV6_IFINFO: u32 = 2048;
+pub const RTMGRP_DECnet_IFADDR: u32 = 4096;
+pub const RTMGRP_DECnet_ROUTE: u32 = 16384;
+pub const RTMGRP_IPV6_PREFIX: u32 = 131072;
+pub const TCA_FLAG_LARGE_DUMP_ON: u32 = 1;
+pub const TCA_ACT_FLAG_LARGE_DUMP_ON: u32 = 1;
+pub const TCA_ACT_FLAG_TERSE_DUMP: u32 = 2;
+pub const RTEXT_FILTER_VF: u32 = 1;
+pub const RTEXT_FILTER_BRVLAN: u32 = 2;
+pub const RTEXT_FILTER_BRVLAN_COMPRESSED: u32 = 4;
+pub const RTEXT_FILTER_SKIP_STATS: u32 = 8;
+pub const RTEXT_FILTER_MRP: u32 = 16;
+pub const RTEXT_FILTER_CFM_CONFIG: u32 = 32;
+pub const RTEXT_FILTER_CFM_STATUS: u32 = 64;
+pub const RTEXT_FILTER_MST: u32 = 128;
 pub const CSIGNAL: u32 = 255;
 pub const CLONE_VM: u32 = 256;
 pub const CLONE_FS: u32 = 512;
@@ -14217,6 +14358,1388 @@
 }
 #[repr(C)]
 #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_stats {
+    pub rx_packets: __u32,
+    pub tx_packets: __u32,
+    pub rx_bytes: __u32,
+    pub tx_bytes: __u32,
+    pub rx_errors: __u32,
+    pub tx_errors: __u32,
+    pub rx_dropped: __u32,
+    pub tx_dropped: __u32,
+    pub multicast: __u32,
+    pub collisions: __u32,
+    pub rx_length_errors: __u32,
+    pub rx_over_errors: __u32,
+    pub rx_crc_errors: __u32,
+    pub rx_frame_errors: __u32,
+    pub rx_fifo_errors: __u32,
+    pub rx_missed_errors: __u32,
+    pub tx_aborted_errors: __u32,
+    pub tx_carrier_errors: __u32,
+    pub tx_fifo_errors: __u32,
+    pub tx_heartbeat_errors: __u32,
+    pub tx_window_errors: __u32,
+    pub rx_compressed: __u32,
+    pub tx_compressed: __u32,
+    pub rx_nohandler: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_stats64 {
+    pub rx_packets: __u64,
+    pub tx_packets: __u64,
+    pub rx_bytes: __u64,
+    pub tx_bytes: __u64,
+    pub rx_errors: __u64,
+    pub tx_errors: __u64,
+    pub rx_dropped: __u64,
+    pub tx_dropped: __u64,
+    pub multicast: __u64,
+    pub collisions: __u64,
+    pub rx_length_errors: __u64,
+    pub rx_over_errors: __u64,
+    pub rx_crc_errors: __u64,
+    pub rx_frame_errors: __u64,
+    pub rx_fifo_errors: __u64,
+    pub rx_missed_errors: __u64,
+    pub tx_aborted_errors: __u64,
+    pub tx_carrier_errors: __u64,
+    pub tx_fifo_errors: __u64,
+    pub tx_heartbeat_errors: __u64,
+    pub tx_window_errors: __u64,
+    pub rx_compressed: __u64,
+    pub tx_compressed: __u64,
+    pub rx_nohandler: __u64,
+    pub rx_otherhost_dropped: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_hw_stats64 {
+    pub rx_packets: __u64,
+    pub tx_packets: __u64,
+    pub rx_bytes: __u64,
+    pub tx_bytes: __u64,
+    pub rx_errors: __u64,
+    pub tx_errors: __u64,
+    pub rx_dropped: __u64,
+    pub tx_dropped: __u64,
+    pub multicast: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_ifmap {
+    pub mem_start: __u64,
+    pub mem_end: __u64,
+    pub base_addr: __u64,
+    pub irq: __u16,
+    pub dma: __u8,
+    pub port: __u8,
+    pub __bindgen_padding_0: [u8; 4usize],
+}
+pub const IFLA_UNSPEC: _bindgen_ty_61 = 0;
+pub const IFLA_ADDRESS: _bindgen_ty_61 = 1;
+pub const IFLA_BROADCAST: _bindgen_ty_61 = 2;
+pub const IFLA_IFNAME: _bindgen_ty_61 = 3;
+pub const IFLA_MTU: _bindgen_ty_61 = 4;
+pub const IFLA_LINK: _bindgen_ty_61 = 5;
+pub const IFLA_QDISC: _bindgen_ty_61 = 6;
+pub const IFLA_STATS: _bindgen_ty_61 = 7;
+pub const IFLA_COST: _bindgen_ty_61 = 8;
+pub const IFLA_PRIORITY: _bindgen_ty_61 = 9;
+pub const IFLA_MASTER: _bindgen_ty_61 = 10;
+pub const IFLA_WIRELESS: _bindgen_ty_61 = 11;
+pub const IFLA_PROTINFO: _bindgen_ty_61 = 12;
+pub const IFLA_TXQLEN: _bindgen_ty_61 = 13;
+pub const IFLA_MAP: _bindgen_ty_61 = 14;
+pub const IFLA_WEIGHT: _bindgen_ty_61 = 15;
+pub const IFLA_OPERSTATE: _bindgen_ty_61 = 16;
+pub const IFLA_LINKMODE: _bindgen_ty_61 = 17;
+pub const IFLA_LINKINFO: _bindgen_ty_61 = 18;
+pub const IFLA_NET_NS_PID: _bindgen_ty_61 = 19;
+pub const IFLA_IFALIAS: _bindgen_ty_61 = 20;
+pub const IFLA_NUM_VF: _bindgen_ty_61 = 21;
+pub const IFLA_VFINFO_LIST: _bindgen_ty_61 = 22;
+pub const IFLA_STATS64: _bindgen_ty_61 = 23;
+pub const IFLA_VF_PORTS: _bindgen_ty_61 = 24;
+pub const IFLA_PORT_SELF: _bindgen_ty_61 = 25;
+pub const IFLA_AF_SPEC: _bindgen_ty_61 = 26;
+pub const IFLA_GROUP: _bindgen_ty_61 = 27;
+pub const IFLA_NET_NS_FD: _bindgen_ty_61 = 28;
+pub const IFLA_EXT_MASK: _bindgen_ty_61 = 29;
+pub const IFLA_PROMISCUITY: _bindgen_ty_61 = 30;
+pub const IFLA_NUM_TX_QUEUES: _bindgen_ty_61 = 31;
+pub const IFLA_NUM_RX_QUEUES: _bindgen_ty_61 = 32;
+pub const IFLA_CARRIER: _bindgen_ty_61 = 33;
+pub const IFLA_PHYS_PORT_ID: _bindgen_ty_61 = 34;
+pub const IFLA_CARRIER_CHANGES: _bindgen_ty_61 = 35;
+pub const IFLA_PHYS_SWITCH_ID: _bindgen_ty_61 = 36;
+pub const IFLA_LINK_NETNSID: _bindgen_ty_61 = 37;
+pub const IFLA_PHYS_PORT_NAME: _bindgen_ty_61 = 38;
+pub const IFLA_PROTO_DOWN: _bindgen_ty_61 = 39;
+pub const IFLA_GSO_MAX_SEGS: _bindgen_ty_61 = 40;
+pub const IFLA_GSO_MAX_SIZE: _bindgen_ty_61 = 41;
+pub const IFLA_PAD: _bindgen_ty_61 = 42;
+pub const IFLA_XDP: _bindgen_ty_61 = 43;
+pub const IFLA_EVENT: _bindgen_ty_61 = 44;
+pub const IFLA_NEW_NETNSID: _bindgen_ty_61 = 45;
+pub const IFLA_IF_NETNSID: _bindgen_ty_61 = 46;
+pub const IFLA_TARGET_NETNSID: _bindgen_ty_61 = 46;
+pub const IFLA_CARRIER_UP_COUNT: _bindgen_ty_61 = 47;
+pub const IFLA_CARRIER_DOWN_COUNT: _bindgen_ty_61 = 48;
+pub const IFLA_NEW_IFINDEX: _bindgen_ty_61 = 49;
+pub const IFLA_MIN_MTU: _bindgen_ty_61 = 50;
+pub const IFLA_MAX_MTU: _bindgen_ty_61 = 51;
+pub const IFLA_PROP_LIST: _bindgen_ty_61 = 52;
+pub const IFLA_ALT_IFNAME: _bindgen_ty_61 = 53;
+pub const IFLA_PERM_ADDRESS: _bindgen_ty_61 = 54;
+pub const IFLA_PROTO_DOWN_REASON: _bindgen_ty_61 = 55;
+pub const IFLA_PARENT_DEV_NAME: _bindgen_ty_61 = 56;
+pub const IFLA_PARENT_DEV_BUS_NAME: _bindgen_ty_61 = 57;
+pub const IFLA_GRO_MAX_SIZE: _bindgen_ty_61 = 58;
+pub const IFLA_TSO_MAX_SIZE: _bindgen_ty_61 = 59;
+pub const IFLA_TSO_MAX_SEGS: _bindgen_ty_61 = 60;
+pub const IFLA_ALLMULTI: _bindgen_ty_61 = 61;
+pub const IFLA_DEVLINK_PORT: _bindgen_ty_61 = 62;
+pub const IFLA_GSO_IPV4_MAX_SIZE: _bindgen_ty_61 = 63;
+pub const IFLA_GRO_IPV4_MAX_SIZE: _bindgen_ty_61 = 64;
+pub const __IFLA_MAX: _bindgen_ty_61 = 65;
+pub type _bindgen_ty_61 = crate::types::c_uint;
+pub const IFLA_PROTO_DOWN_REASON_UNSPEC: _bindgen_ty_62 = 0;
+pub const IFLA_PROTO_DOWN_REASON_MASK: _bindgen_ty_62 = 1;
+pub const IFLA_PROTO_DOWN_REASON_VALUE: _bindgen_ty_62 = 2;
+pub const __IFLA_PROTO_DOWN_REASON_CNT: _bindgen_ty_62 = 3;
+pub const IFLA_PROTO_DOWN_REASON_MAX: _bindgen_ty_62 = 2;
+pub type _bindgen_ty_62 = crate::types::c_uint;
+pub const IFLA_INET_UNSPEC: _bindgen_ty_63 = 0;
+pub const IFLA_INET_CONF: _bindgen_ty_63 = 1;
+pub const __IFLA_INET_MAX: _bindgen_ty_63 = 2;
+pub type _bindgen_ty_63 = crate::types::c_uint;
+pub const IFLA_INET6_UNSPEC: _bindgen_ty_64 = 0;
+pub const IFLA_INET6_FLAGS: _bindgen_ty_64 = 1;
+pub const IFLA_INET6_CONF: _bindgen_ty_64 = 2;
+pub const IFLA_INET6_STATS: _bindgen_ty_64 = 3;
+pub const IFLA_INET6_MCAST: _bindgen_ty_64 = 4;
+pub const IFLA_INET6_CACHEINFO: _bindgen_ty_64 = 5;
+pub const IFLA_INET6_ICMP6STATS: _bindgen_ty_64 = 6;
+pub const IFLA_INET6_TOKEN: _bindgen_ty_64 = 7;
+pub const IFLA_INET6_ADDR_GEN_MODE: _bindgen_ty_64 = 8;
+pub const IFLA_INET6_RA_MTU: _bindgen_ty_64 = 9;
+pub const __IFLA_INET6_MAX: _bindgen_ty_64 = 10;
+pub type _bindgen_ty_64 = crate::types::c_uint;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_EUI64: in6_addr_gen_mode = 0;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_NONE: in6_addr_gen_mode = 1;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_STABLE_PRIVACY: in6_addr_gen_mode = 2;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_RANDOM: in6_addr_gen_mode = 3;
+pub type in6_addr_gen_mode = crate::types::c_uint;
+pub const IFLA_BR_UNSPEC: _bindgen_ty_65 = 0;
+pub const IFLA_BR_FORWARD_DELAY: _bindgen_ty_65 = 1;
+pub const IFLA_BR_HELLO_TIME: _bindgen_ty_65 = 2;
+pub const IFLA_BR_MAX_AGE: _bindgen_ty_65 = 3;
+pub const IFLA_BR_AGEING_TIME: _bindgen_ty_65 = 4;
+pub const IFLA_BR_STP_STATE: _bindgen_ty_65 = 5;
+pub const IFLA_BR_PRIORITY: _bindgen_ty_65 = 6;
+pub const IFLA_BR_VLAN_FILTERING: _bindgen_ty_65 = 7;
+pub const IFLA_BR_VLAN_PROTOCOL: _bindgen_ty_65 = 8;
+pub const IFLA_BR_GROUP_FWD_MASK: _bindgen_ty_65 = 9;
+pub const IFLA_BR_ROOT_ID: _bindgen_ty_65 = 10;
+pub const IFLA_BR_BRIDGE_ID: _bindgen_ty_65 = 11;
+pub const IFLA_BR_ROOT_PORT: _bindgen_ty_65 = 12;
+pub const IFLA_BR_ROOT_PATH_COST: _bindgen_ty_65 = 13;
+pub const IFLA_BR_TOPOLOGY_CHANGE: _bindgen_ty_65 = 14;
+pub const IFLA_BR_TOPOLOGY_CHANGE_DETECTED: _bindgen_ty_65 = 15;
+pub const IFLA_BR_HELLO_TIMER: _bindgen_ty_65 = 16;
+pub const IFLA_BR_TCN_TIMER: _bindgen_ty_65 = 17;
+pub const IFLA_BR_TOPOLOGY_CHANGE_TIMER: _bindgen_ty_65 = 18;
+pub const IFLA_BR_GC_TIMER: _bindgen_ty_65 = 19;
+pub const IFLA_BR_GROUP_ADDR: _bindgen_ty_65 = 20;
+pub const IFLA_BR_FDB_FLUSH: _bindgen_ty_65 = 21;
+pub const IFLA_BR_MCAST_ROUTER: _bindgen_ty_65 = 22;
+pub const IFLA_BR_MCAST_SNOOPING: _bindgen_ty_65 = 23;
+pub const IFLA_BR_MCAST_QUERY_USE_IFADDR: _bindgen_ty_65 = 24;
+pub const IFLA_BR_MCAST_QUERIER: _bindgen_ty_65 = 25;
+pub const IFLA_BR_MCAST_HASH_ELASTICITY: _bindgen_ty_65 = 26;
+pub const IFLA_BR_MCAST_HASH_MAX: _bindgen_ty_65 = 27;
+pub const IFLA_BR_MCAST_LAST_MEMBER_CNT: _bindgen_ty_65 = 28;
+pub const IFLA_BR_MCAST_STARTUP_QUERY_CNT: _bindgen_ty_65 = 29;
+pub const IFLA_BR_MCAST_LAST_MEMBER_INTVL: _bindgen_ty_65 = 30;
+pub const IFLA_BR_MCAST_MEMBERSHIP_INTVL: _bindgen_ty_65 = 31;
+pub const IFLA_BR_MCAST_QUERIER_INTVL: _bindgen_ty_65 = 32;
+pub const IFLA_BR_MCAST_QUERY_INTVL: _bindgen_ty_65 = 33;
+pub const IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: _bindgen_ty_65 = 34;
+pub const IFLA_BR_MCAST_STARTUP_QUERY_INTVL: _bindgen_ty_65 = 35;
+pub const IFLA_BR_NF_CALL_IPTABLES: _bindgen_ty_65 = 36;
+pub const IFLA_BR_NF_CALL_IP6TABLES: _bindgen_ty_65 = 37;
+pub const IFLA_BR_NF_CALL_ARPTABLES: _bindgen_ty_65 = 38;
+pub const IFLA_BR_VLAN_DEFAULT_PVID: _bindgen_ty_65 = 39;
+pub const IFLA_BR_PAD: _bindgen_ty_65 = 40;
+pub const IFLA_BR_VLAN_STATS_ENABLED: _bindgen_ty_65 = 41;
+pub const IFLA_BR_MCAST_STATS_ENABLED: _bindgen_ty_65 = 42;
+pub const IFLA_BR_MCAST_IGMP_VERSION: _bindgen_ty_65 = 43;
+pub const IFLA_BR_MCAST_MLD_VERSION: _bindgen_ty_65 = 44;
+pub const IFLA_BR_VLAN_STATS_PER_PORT: _bindgen_ty_65 = 45;
+pub const IFLA_BR_MULTI_BOOLOPT: _bindgen_ty_65 = 46;
+pub const IFLA_BR_MCAST_QUERIER_STATE: _bindgen_ty_65 = 47;
+pub const __IFLA_BR_MAX: _bindgen_ty_65 = 48;
+pub type _bindgen_ty_65 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_bridge_id {
+    pub prio: [__u8; 2usize],
+    pub addr: [__u8; 6usize],
+}
+pub const BRIDGE_MODE_UNSPEC: _bindgen_ty_66 = 0;
+pub const BRIDGE_MODE_HAIRPIN: _bindgen_ty_66 = 1;
+pub type _bindgen_ty_66 = crate::types::c_uint;
+pub const IFLA_BRPORT_UNSPEC: _bindgen_ty_67 = 0;
+pub const IFLA_BRPORT_STATE: _bindgen_ty_67 = 1;
+pub const IFLA_BRPORT_PRIORITY: _bindgen_ty_67 = 2;
+pub const IFLA_BRPORT_COST: _bindgen_ty_67 = 3;
+pub const IFLA_BRPORT_MODE: _bindgen_ty_67 = 4;
+pub const IFLA_BRPORT_GUARD: _bindgen_ty_67 = 5;
+pub const IFLA_BRPORT_PROTECT: _bindgen_ty_67 = 6;
+pub const IFLA_BRPORT_FAST_LEAVE: _bindgen_ty_67 = 7;
+pub const IFLA_BRPORT_LEARNING: _bindgen_ty_67 = 8;
+pub const IFLA_BRPORT_UNICAST_FLOOD: _bindgen_ty_67 = 9;
+pub const IFLA_BRPORT_PROXYARP: _bindgen_ty_67 = 10;
+pub const IFLA_BRPORT_LEARNING_SYNC: _bindgen_ty_67 = 11;
+pub const IFLA_BRPORT_PROXYARP_WIFI: _bindgen_ty_67 = 12;
+pub const IFLA_BRPORT_ROOT_ID: _bindgen_ty_67 = 13;
+pub const IFLA_BRPORT_BRIDGE_ID: _bindgen_ty_67 = 14;
+pub const IFLA_BRPORT_DESIGNATED_PORT: _bindgen_ty_67 = 15;
+pub const IFLA_BRPORT_DESIGNATED_COST: _bindgen_ty_67 = 16;
+pub const IFLA_BRPORT_ID: _bindgen_ty_67 = 17;
+pub const IFLA_BRPORT_NO: _bindgen_ty_67 = 18;
+pub const IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: _bindgen_ty_67 = 19;
+pub const IFLA_BRPORT_CONFIG_PENDING: _bindgen_ty_67 = 20;
+pub const IFLA_BRPORT_MESSAGE_AGE_TIMER: _bindgen_ty_67 = 21;
+pub const IFLA_BRPORT_FORWARD_DELAY_TIMER: _bindgen_ty_67 = 22;
+pub const IFLA_BRPORT_HOLD_TIMER: _bindgen_ty_67 = 23;
+pub const IFLA_BRPORT_FLUSH: _bindgen_ty_67 = 24;
+pub const IFLA_BRPORT_MULTICAST_ROUTER: _bindgen_ty_67 = 25;
+pub const IFLA_BRPORT_PAD: _bindgen_ty_67 = 26;
+pub const IFLA_BRPORT_MCAST_FLOOD: _bindgen_ty_67 = 27;
+pub const IFLA_BRPORT_MCAST_TO_UCAST: _bindgen_ty_67 = 28;
+pub const IFLA_BRPORT_VLAN_TUNNEL: _bindgen_ty_67 = 29;
+pub const IFLA_BRPORT_BCAST_FLOOD: _bindgen_ty_67 = 30;
+pub const IFLA_BRPORT_GROUP_FWD_MASK: _bindgen_ty_67 = 31;
+pub const IFLA_BRPORT_NEIGH_SUPPRESS: _bindgen_ty_67 = 32;
+pub const IFLA_BRPORT_ISOLATED: _bindgen_ty_67 = 33;
+pub const IFLA_BRPORT_BACKUP_PORT: _bindgen_ty_67 = 34;
+pub const IFLA_BRPORT_MRP_RING_OPEN: _bindgen_ty_67 = 35;
+pub const IFLA_BRPORT_MRP_IN_OPEN: _bindgen_ty_67 = 36;
+pub const IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT: _bindgen_ty_67 = 37;
+pub const IFLA_BRPORT_MCAST_EHT_HOSTS_CNT: _bindgen_ty_67 = 38;
+pub const IFLA_BRPORT_LOCKED: _bindgen_ty_67 = 39;
+pub const IFLA_BRPORT_MAB: _bindgen_ty_67 = 40;
+pub const IFLA_BRPORT_MCAST_N_GROUPS: _bindgen_ty_67 = 41;
+pub const IFLA_BRPORT_MCAST_MAX_GROUPS: _bindgen_ty_67 = 42;
+pub const IFLA_BRPORT_NEIGH_VLAN_SUPPRESS: _bindgen_ty_67 = 43;
+pub const __IFLA_BRPORT_MAX: _bindgen_ty_67 = 44;
+pub type _bindgen_ty_67 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_cacheinfo {
+    pub max_reasm_len: __u32,
+    pub tstamp: __u32,
+    pub reachable_time: __u32,
+    pub retrans_time: __u32,
+}
+pub const IFLA_INFO_UNSPEC: _bindgen_ty_68 = 0;
+pub const IFLA_INFO_KIND: _bindgen_ty_68 = 1;
+pub const IFLA_INFO_DATA: _bindgen_ty_68 = 2;
+pub const IFLA_INFO_XSTATS: _bindgen_ty_68 = 3;
+pub const IFLA_INFO_SLAVE_KIND: _bindgen_ty_68 = 4;
+pub const IFLA_INFO_SLAVE_DATA: _bindgen_ty_68 = 5;
+pub const __IFLA_INFO_MAX: _bindgen_ty_68 = 6;
+pub type _bindgen_ty_68 = crate::types::c_uint;
+pub const IFLA_VLAN_UNSPEC: _bindgen_ty_69 = 0;
+pub const IFLA_VLAN_ID: _bindgen_ty_69 = 1;
+pub const IFLA_VLAN_FLAGS: _bindgen_ty_69 = 2;
+pub const IFLA_VLAN_EGRESS_QOS: _bindgen_ty_69 = 3;
+pub const IFLA_VLAN_INGRESS_QOS: _bindgen_ty_69 = 4;
+pub const IFLA_VLAN_PROTOCOL: _bindgen_ty_69 = 5;
+pub const __IFLA_VLAN_MAX: _bindgen_ty_69 = 6;
+pub type _bindgen_ty_69 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vlan_flags {
+    pub flags: __u32,
+    pub mask: __u32,
+}
+pub const IFLA_VLAN_QOS_UNSPEC: _bindgen_ty_70 = 0;
+pub const IFLA_VLAN_QOS_MAPPING: _bindgen_ty_70 = 1;
+pub const __IFLA_VLAN_QOS_MAX: _bindgen_ty_70 = 2;
+pub type _bindgen_ty_70 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vlan_qos_mapping {
+    pub from: __u32,
+    pub to: __u32,
+}
+pub const IFLA_MACVLAN_UNSPEC: _bindgen_ty_71 = 0;
+pub const IFLA_MACVLAN_MODE: _bindgen_ty_71 = 1;
+pub const IFLA_MACVLAN_FLAGS: _bindgen_ty_71 = 2;
+pub const IFLA_MACVLAN_MACADDR_MODE: _bindgen_ty_71 = 3;
+pub const IFLA_MACVLAN_MACADDR: _bindgen_ty_71 = 4;
+pub const IFLA_MACVLAN_MACADDR_DATA: _bindgen_ty_71 = 5;
+pub const IFLA_MACVLAN_MACADDR_COUNT: _bindgen_ty_71 = 6;
+pub const IFLA_MACVLAN_BC_QUEUE_LEN: _bindgen_ty_71 = 7;
+pub const IFLA_MACVLAN_BC_QUEUE_LEN_USED: _bindgen_ty_71 = 8;
+pub const IFLA_MACVLAN_BC_CUTOFF: _bindgen_ty_71 = 9;
+pub const __IFLA_MACVLAN_MAX: _bindgen_ty_71 = 10;
+pub type _bindgen_ty_71 = crate::types::c_uint;
+pub const macvlan_mode_MACVLAN_MODE_PRIVATE: macvlan_mode = 1;
+pub const macvlan_mode_MACVLAN_MODE_VEPA: macvlan_mode = 2;
+pub const macvlan_mode_MACVLAN_MODE_BRIDGE: macvlan_mode = 4;
+pub const macvlan_mode_MACVLAN_MODE_PASSTHRU: macvlan_mode = 8;
+pub const macvlan_mode_MACVLAN_MODE_SOURCE: macvlan_mode = 16;
+pub type macvlan_mode = crate::types::c_uint;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_ADD: macvlan_macaddr_mode = 0;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_DEL: macvlan_macaddr_mode = 1;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_FLUSH: macvlan_macaddr_mode = 2;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_SET: macvlan_macaddr_mode = 3;
+pub type macvlan_macaddr_mode = crate::types::c_uint;
+pub const IFLA_VRF_UNSPEC: _bindgen_ty_72 = 0;
+pub const IFLA_VRF_TABLE: _bindgen_ty_72 = 1;
+pub const __IFLA_VRF_MAX: _bindgen_ty_72 = 2;
+pub type _bindgen_ty_72 = crate::types::c_uint;
+pub const IFLA_VRF_PORT_UNSPEC: _bindgen_ty_73 = 0;
+pub const IFLA_VRF_PORT_TABLE: _bindgen_ty_73 = 1;
+pub const __IFLA_VRF_PORT_MAX: _bindgen_ty_73 = 2;
+pub type _bindgen_ty_73 = crate::types::c_uint;
+pub const IFLA_MACSEC_UNSPEC: _bindgen_ty_74 = 0;
+pub const IFLA_MACSEC_SCI: _bindgen_ty_74 = 1;
+pub const IFLA_MACSEC_PORT: _bindgen_ty_74 = 2;
+pub const IFLA_MACSEC_ICV_LEN: _bindgen_ty_74 = 3;
+pub const IFLA_MACSEC_CIPHER_SUITE: _bindgen_ty_74 = 4;
+pub const IFLA_MACSEC_WINDOW: _bindgen_ty_74 = 5;
+pub const IFLA_MACSEC_ENCODING_SA: _bindgen_ty_74 = 6;
+pub const IFLA_MACSEC_ENCRYPT: _bindgen_ty_74 = 7;
+pub const IFLA_MACSEC_PROTECT: _bindgen_ty_74 = 8;
+pub const IFLA_MACSEC_INC_SCI: _bindgen_ty_74 = 9;
+pub const IFLA_MACSEC_ES: _bindgen_ty_74 = 10;
+pub const IFLA_MACSEC_SCB: _bindgen_ty_74 = 11;
+pub const IFLA_MACSEC_REPLAY_PROTECT: _bindgen_ty_74 = 12;
+pub const IFLA_MACSEC_VALIDATION: _bindgen_ty_74 = 13;
+pub const IFLA_MACSEC_PAD: _bindgen_ty_74 = 14;
+pub const IFLA_MACSEC_OFFLOAD: _bindgen_ty_74 = 15;
+pub const __IFLA_MACSEC_MAX: _bindgen_ty_74 = 16;
+pub type _bindgen_ty_74 = crate::types::c_uint;
+pub const IFLA_XFRM_UNSPEC: _bindgen_ty_75 = 0;
+pub const IFLA_XFRM_LINK: _bindgen_ty_75 = 1;
+pub const IFLA_XFRM_IF_ID: _bindgen_ty_75 = 2;
+pub const IFLA_XFRM_COLLECT_METADATA: _bindgen_ty_75 = 3;
+pub const __IFLA_XFRM_MAX: _bindgen_ty_75 = 4;
+pub type _bindgen_ty_75 = crate::types::c_uint;
+pub const macsec_validation_type_MACSEC_VALIDATE_DISABLED: macsec_validation_type = 0;
+pub const macsec_validation_type_MACSEC_VALIDATE_CHECK: macsec_validation_type = 1;
+pub const macsec_validation_type_MACSEC_VALIDATE_STRICT: macsec_validation_type = 2;
+pub const macsec_validation_type___MACSEC_VALIDATE_END: macsec_validation_type = 3;
+pub const macsec_validation_type_MACSEC_VALIDATE_MAX: macsec_validation_type = 2;
+pub type macsec_validation_type = crate::types::c_uint;
+pub const macsec_offload_MACSEC_OFFLOAD_OFF: macsec_offload = 0;
+pub const macsec_offload_MACSEC_OFFLOAD_PHY: macsec_offload = 1;
+pub const macsec_offload_MACSEC_OFFLOAD_MAC: macsec_offload = 2;
+pub const macsec_offload___MACSEC_OFFLOAD_END: macsec_offload = 3;
+pub const macsec_offload_MACSEC_OFFLOAD_MAX: macsec_offload = 2;
+pub type macsec_offload = crate::types::c_uint;
+pub const IFLA_IPVLAN_UNSPEC: _bindgen_ty_76 = 0;
+pub const IFLA_IPVLAN_MODE: _bindgen_ty_76 = 1;
+pub const IFLA_IPVLAN_FLAGS: _bindgen_ty_76 = 2;
+pub const __IFLA_IPVLAN_MAX: _bindgen_ty_76 = 3;
+pub type _bindgen_ty_76 = crate::types::c_uint;
+pub const ipvlan_mode_IPVLAN_MODE_L2: ipvlan_mode = 0;
+pub const ipvlan_mode_IPVLAN_MODE_L3: ipvlan_mode = 1;
+pub const ipvlan_mode_IPVLAN_MODE_L3S: ipvlan_mode = 2;
+pub const ipvlan_mode_IPVLAN_MODE_MAX: ipvlan_mode = 3;
+pub type ipvlan_mode = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tunnel_msg {
+    pub family: __u8,
+    pub flags: __u8,
+    pub reserved2: __u16,
+    pub ifindex: __u32,
+}
+pub const VNIFILTER_ENTRY_STATS_UNSPEC: _bindgen_ty_77 = 0;
+pub const VNIFILTER_ENTRY_STATS_RX_BYTES: _bindgen_ty_77 = 1;
+pub const VNIFILTER_ENTRY_STATS_RX_PKTS: _bindgen_ty_77 = 2;
+pub const VNIFILTER_ENTRY_STATS_RX_DROPS: _bindgen_ty_77 = 3;
+pub const VNIFILTER_ENTRY_STATS_RX_ERRORS: _bindgen_ty_77 = 4;
+pub const VNIFILTER_ENTRY_STATS_TX_BYTES: _bindgen_ty_77 = 5;
+pub const VNIFILTER_ENTRY_STATS_TX_PKTS: _bindgen_ty_77 = 6;
+pub const VNIFILTER_ENTRY_STATS_TX_DROPS: _bindgen_ty_77 = 7;
+pub const VNIFILTER_ENTRY_STATS_TX_ERRORS: _bindgen_ty_77 = 8;
+pub const VNIFILTER_ENTRY_STATS_PAD: _bindgen_ty_77 = 9;
+pub const __VNIFILTER_ENTRY_STATS_MAX: _bindgen_ty_77 = 10;
+pub type _bindgen_ty_77 = crate::types::c_uint;
+pub const VXLAN_VNIFILTER_ENTRY_UNSPEC: _bindgen_ty_78 = 0;
+pub const VXLAN_VNIFILTER_ENTRY_START: _bindgen_ty_78 = 1;
+pub const VXLAN_VNIFILTER_ENTRY_END: _bindgen_ty_78 = 2;
+pub const VXLAN_VNIFILTER_ENTRY_GROUP: _bindgen_ty_78 = 3;
+pub const VXLAN_VNIFILTER_ENTRY_GROUP6: _bindgen_ty_78 = 4;
+pub const VXLAN_VNIFILTER_ENTRY_STATS: _bindgen_ty_78 = 5;
+pub const __VXLAN_VNIFILTER_ENTRY_MAX: _bindgen_ty_78 = 6;
+pub type _bindgen_ty_78 = crate::types::c_uint;
+pub const VXLAN_VNIFILTER_UNSPEC: _bindgen_ty_79 = 0;
+pub const VXLAN_VNIFILTER_ENTRY: _bindgen_ty_79 = 1;
+pub const __VXLAN_VNIFILTER_MAX: _bindgen_ty_79 = 2;
+pub type _bindgen_ty_79 = crate::types::c_uint;
+pub const IFLA_VXLAN_UNSPEC: _bindgen_ty_80 = 0;
+pub const IFLA_VXLAN_ID: _bindgen_ty_80 = 1;
+pub const IFLA_VXLAN_GROUP: _bindgen_ty_80 = 2;
+pub const IFLA_VXLAN_LINK: _bindgen_ty_80 = 3;
+pub const IFLA_VXLAN_LOCAL: _bindgen_ty_80 = 4;
+pub const IFLA_VXLAN_TTL: _bindgen_ty_80 = 5;
+pub const IFLA_VXLAN_TOS: _bindgen_ty_80 = 6;
+pub const IFLA_VXLAN_LEARNING: _bindgen_ty_80 = 7;
+pub const IFLA_VXLAN_AGEING: _bindgen_ty_80 = 8;
+pub const IFLA_VXLAN_LIMIT: _bindgen_ty_80 = 9;
+pub const IFLA_VXLAN_PORT_RANGE: _bindgen_ty_80 = 10;
+pub const IFLA_VXLAN_PROXY: _bindgen_ty_80 = 11;
+pub const IFLA_VXLAN_RSC: _bindgen_ty_80 = 12;
+pub const IFLA_VXLAN_L2MISS: _bindgen_ty_80 = 13;
+pub const IFLA_VXLAN_L3MISS: _bindgen_ty_80 = 14;
+pub const IFLA_VXLAN_PORT: _bindgen_ty_80 = 15;
+pub const IFLA_VXLAN_GROUP6: _bindgen_ty_80 = 16;
+pub const IFLA_VXLAN_LOCAL6: _bindgen_ty_80 = 17;
+pub const IFLA_VXLAN_UDP_CSUM: _bindgen_ty_80 = 18;
+pub const IFLA_VXLAN_UDP_ZERO_CSUM6_TX: _bindgen_ty_80 = 19;
+pub const IFLA_VXLAN_UDP_ZERO_CSUM6_RX: _bindgen_ty_80 = 20;
+pub const IFLA_VXLAN_REMCSUM_TX: _bindgen_ty_80 = 21;
+pub const IFLA_VXLAN_REMCSUM_RX: _bindgen_ty_80 = 22;
+pub const IFLA_VXLAN_GBP: _bindgen_ty_80 = 23;
+pub const IFLA_VXLAN_REMCSUM_NOPARTIAL: _bindgen_ty_80 = 24;
+pub const IFLA_VXLAN_COLLECT_METADATA: _bindgen_ty_80 = 25;
+pub const IFLA_VXLAN_LABEL: _bindgen_ty_80 = 26;
+pub const IFLA_VXLAN_GPE: _bindgen_ty_80 = 27;
+pub const IFLA_VXLAN_TTL_INHERIT: _bindgen_ty_80 = 28;
+pub const IFLA_VXLAN_DF: _bindgen_ty_80 = 29;
+pub const IFLA_VXLAN_VNIFILTER: _bindgen_ty_80 = 30;
+pub const IFLA_VXLAN_LOCALBYPASS: _bindgen_ty_80 = 31;
+pub const __IFLA_VXLAN_MAX: _bindgen_ty_80 = 32;
+pub type _bindgen_ty_80 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vxlan_port_range {
+    pub low: __be16,
+    pub high: __be16,
+}
+pub const ifla_vxlan_df_VXLAN_DF_UNSET: ifla_vxlan_df = 0;
+pub const ifla_vxlan_df_VXLAN_DF_SET: ifla_vxlan_df = 1;
+pub const ifla_vxlan_df_VXLAN_DF_INHERIT: ifla_vxlan_df = 2;
+pub const ifla_vxlan_df___VXLAN_DF_END: ifla_vxlan_df = 3;
+pub const ifla_vxlan_df_VXLAN_DF_MAX: ifla_vxlan_df = 2;
+pub type ifla_vxlan_df = crate::types::c_uint;
+pub const IFLA_GENEVE_UNSPEC: _bindgen_ty_81 = 0;
+pub const IFLA_GENEVE_ID: _bindgen_ty_81 = 1;
+pub const IFLA_GENEVE_REMOTE: _bindgen_ty_81 = 2;
+pub const IFLA_GENEVE_TTL: _bindgen_ty_81 = 3;
+pub const IFLA_GENEVE_TOS: _bindgen_ty_81 = 4;
+pub const IFLA_GENEVE_PORT: _bindgen_ty_81 = 5;
+pub const IFLA_GENEVE_COLLECT_METADATA: _bindgen_ty_81 = 6;
+pub const IFLA_GENEVE_REMOTE6: _bindgen_ty_81 = 7;
+pub const IFLA_GENEVE_UDP_CSUM: _bindgen_ty_81 = 8;
+pub const IFLA_GENEVE_UDP_ZERO_CSUM6_TX: _bindgen_ty_81 = 9;
+pub const IFLA_GENEVE_UDP_ZERO_CSUM6_RX: _bindgen_ty_81 = 10;
+pub const IFLA_GENEVE_LABEL: _bindgen_ty_81 = 11;
+pub const IFLA_GENEVE_TTL_INHERIT: _bindgen_ty_81 = 12;
+pub const IFLA_GENEVE_DF: _bindgen_ty_81 = 13;
+pub const IFLA_GENEVE_INNER_PROTO_INHERIT: _bindgen_ty_81 = 14;
+pub const __IFLA_GENEVE_MAX: _bindgen_ty_81 = 15;
+pub type _bindgen_ty_81 = crate::types::c_uint;
+pub const ifla_geneve_df_GENEVE_DF_UNSET: ifla_geneve_df = 0;
+pub const ifla_geneve_df_GENEVE_DF_SET: ifla_geneve_df = 1;
+pub const ifla_geneve_df_GENEVE_DF_INHERIT: ifla_geneve_df = 2;
+pub const ifla_geneve_df___GENEVE_DF_END: ifla_geneve_df = 3;
+pub const ifla_geneve_df_GENEVE_DF_MAX: ifla_geneve_df = 2;
+pub type ifla_geneve_df = crate::types::c_uint;
+pub const IFLA_BAREUDP_UNSPEC: _bindgen_ty_82 = 0;
+pub const IFLA_BAREUDP_PORT: _bindgen_ty_82 = 1;
+pub const IFLA_BAREUDP_ETHERTYPE: _bindgen_ty_82 = 2;
+pub const IFLA_BAREUDP_SRCPORT_MIN: _bindgen_ty_82 = 3;
+pub const IFLA_BAREUDP_MULTIPROTO_MODE: _bindgen_ty_82 = 4;
+pub const __IFLA_BAREUDP_MAX: _bindgen_ty_82 = 5;
+pub type _bindgen_ty_82 = crate::types::c_uint;
+pub const IFLA_PPP_UNSPEC: _bindgen_ty_83 = 0;
+pub const IFLA_PPP_DEV_FD: _bindgen_ty_83 = 1;
+pub const __IFLA_PPP_MAX: _bindgen_ty_83 = 2;
+pub type _bindgen_ty_83 = crate::types::c_uint;
+pub const ifla_gtp_role_GTP_ROLE_GGSN: ifla_gtp_role = 0;
+pub const ifla_gtp_role_GTP_ROLE_SGSN: ifla_gtp_role = 1;
+pub type ifla_gtp_role = crate::types::c_uint;
+pub const IFLA_GTP_UNSPEC: _bindgen_ty_84 = 0;
+pub const IFLA_GTP_FD0: _bindgen_ty_84 = 1;
+pub const IFLA_GTP_FD1: _bindgen_ty_84 = 2;
+pub const IFLA_GTP_PDP_HASHSIZE: _bindgen_ty_84 = 3;
+pub const IFLA_GTP_ROLE: _bindgen_ty_84 = 4;
+pub const IFLA_GTP_CREATE_SOCKETS: _bindgen_ty_84 = 5;
+pub const IFLA_GTP_RESTART_COUNT: _bindgen_ty_84 = 6;
+pub const __IFLA_GTP_MAX: _bindgen_ty_84 = 7;
+pub type _bindgen_ty_84 = crate::types::c_uint;
+pub const IFLA_BOND_UNSPEC: _bindgen_ty_85 = 0;
+pub const IFLA_BOND_MODE: _bindgen_ty_85 = 1;
+pub const IFLA_BOND_ACTIVE_SLAVE: _bindgen_ty_85 = 2;
+pub const IFLA_BOND_MIIMON: _bindgen_ty_85 = 3;
+pub const IFLA_BOND_UPDELAY: _bindgen_ty_85 = 4;
+pub const IFLA_BOND_DOWNDELAY: _bindgen_ty_85 = 5;
+pub const IFLA_BOND_USE_CARRIER: _bindgen_ty_85 = 6;
+pub const IFLA_BOND_ARP_INTERVAL: _bindgen_ty_85 = 7;
+pub const IFLA_BOND_ARP_IP_TARGET: _bindgen_ty_85 = 8;
+pub const IFLA_BOND_ARP_VALIDATE: _bindgen_ty_85 = 9;
+pub const IFLA_BOND_ARP_ALL_TARGETS: _bindgen_ty_85 = 10;
+pub const IFLA_BOND_PRIMARY: _bindgen_ty_85 = 11;
+pub const IFLA_BOND_PRIMARY_RESELECT: _bindgen_ty_85 = 12;
+pub const IFLA_BOND_FAIL_OVER_MAC: _bindgen_ty_85 = 13;
+pub const IFLA_BOND_XMIT_HASH_POLICY: _bindgen_ty_85 = 14;
+pub const IFLA_BOND_RESEND_IGMP: _bindgen_ty_85 = 15;
+pub const IFLA_BOND_NUM_PEER_NOTIF: _bindgen_ty_85 = 16;
+pub const IFLA_BOND_ALL_SLAVES_ACTIVE: _bindgen_ty_85 = 17;
+pub const IFLA_BOND_MIN_LINKS: _bindgen_ty_85 = 18;
+pub const IFLA_BOND_LP_INTERVAL: _bindgen_ty_85 = 19;
+pub const IFLA_BOND_PACKETS_PER_SLAVE: _bindgen_ty_85 = 20;
+pub const IFLA_BOND_AD_LACP_RATE: _bindgen_ty_85 = 21;
+pub const IFLA_BOND_AD_SELECT: _bindgen_ty_85 = 22;
+pub const IFLA_BOND_AD_INFO: _bindgen_ty_85 = 23;
+pub const IFLA_BOND_AD_ACTOR_SYS_PRIO: _bindgen_ty_85 = 24;
+pub const IFLA_BOND_AD_USER_PORT_KEY: _bindgen_ty_85 = 25;
+pub const IFLA_BOND_AD_ACTOR_SYSTEM: _bindgen_ty_85 = 26;
+pub const IFLA_BOND_TLB_DYNAMIC_LB: _bindgen_ty_85 = 27;
+pub const IFLA_BOND_PEER_NOTIF_DELAY: _bindgen_ty_85 = 28;
+pub const IFLA_BOND_AD_LACP_ACTIVE: _bindgen_ty_85 = 29;
+pub const IFLA_BOND_MISSED_MAX: _bindgen_ty_85 = 30;
+pub const IFLA_BOND_NS_IP6_TARGET: _bindgen_ty_85 = 31;
+pub const __IFLA_BOND_MAX: _bindgen_ty_85 = 32;
+pub type _bindgen_ty_85 = crate::types::c_uint;
+pub const IFLA_BOND_AD_INFO_UNSPEC: _bindgen_ty_86 = 0;
+pub const IFLA_BOND_AD_INFO_AGGREGATOR: _bindgen_ty_86 = 1;
+pub const IFLA_BOND_AD_INFO_NUM_PORTS: _bindgen_ty_86 = 2;
+pub const IFLA_BOND_AD_INFO_ACTOR_KEY: _bindgen_ty_86 = 3;
+pub const IFLA_BOND_AD_INFO_PARTNER_KEY: _bindgen_ty_86 = 4;
+pub const IFLA_BOND_AD_INFO_PARTNER_MAC: _bindgen_ty_86 = 5;
+pub const __IFLA_BOND_AD_INFO_MAX: _bindgen_ty_86 = 6;
+pub type _bindgen_ty_86 = crate::types::c_uint;
+pub const IFLA_BOND_SLAVE_UNSPEC: _bindgen_ty_87 = 0;
+pub const IFLA_BOND_SLAVE_STATE: _bindgen_ty_87 = 1;
+pub const IFLA_BOND_SLAVE_MII_STATUS: _bindgen_ty_87 = 2;
+pub const IFLA_BOND_SLAVE_LINK_FAILURE_COUNT: _bindgen_ty_87 = 3;
+pub const IFLA_BOND_SLAVE_PERM_HWADDR: _bindgen_ty_87 = 4;
+pub const IFLA_BOND_SLAVE_QUEUE_ID: _bindgen_ty_87 = 5;
+pub const IFLA_BOND_SLAVE_AD_AGGREGATOR_ID: _bindgen_ty_87 = 6;
+pub const IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE: _bindgen_ty_87 = 7;
+pub const IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE: _bindgen_ty_87 = 8;
+pub const IFLA_BOND_SLAVE_PRIO: _bindgen_ty_87 = 9;
+pub const __IFLA_BOND_SLAVE_MAX: _bindgen_ty_87 = 10;
+pub type _bindgen_ty_87 = crate::types::c_uint;
+pub const IFLA_VF_INFO_UNSPEC: _bindgen_ty_88 = 0;
+pub const IFLA_VF_INFO: _bindgen_ty_88 = 1;
+pub const __IFLA_VF_INFO_MAX: _bindgen_ty_88 = 2;
+pub type _bindgen_ty_88 = crate::types::c_uint;
+pub const IFLA_VF_UNSPEC: _bindgen_ty_89 = 0;
+pub const IFLA_VF_MAC: _bindgen_ty_89 = 1;
+pub const IFLA_VF_VLAN: _bindgen_ty_89 = 2;
+pub const IFLA_VF_TX_RATE: _bindgen_ty_89 = 3;
+pub const IFLA_VF_SPOOFCHK: _bindgen_ty_89 = 4;
+pub const IFLA_VF_LINK_STATE: _bindgen_ty_89 = 5;
+pub const IFLA_VF_RATE: _bindgen_ty_89 = 6;
+pub const IFLA_VF_RSS_QUERY_EN: _bindgen_ty_89 = 7;
+pub const IFLA_VF_STATS: _bindgen_ty_89 = 8;
+pub const IFLA_VF_TRUST: _bindgen_ty_89 = 9;
+pub const IFLA_VF_IB_NODE_GUID: _bindgen_ty_89 = 10;
+pub const IFLA_VF_IB_PORT_GUID: _bindgen_ty_89 = 11;
+pub const IFLA_VF_VLAN_LIST: _bindgen_ty_89 = 12;
+pub const IFLA_VF_BROADCAST: _bindgen_ty_89 = 13;
+pub const __IFLA_VF_MAX: _bindgen_ty_89 = 14;
+pub type _bindgen_ty_89 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_mac {
+    pub vf: __u32,
+    pub mac: [__u8; 32usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_broadcast {
+    pub broadcast: [__u8; 32usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_vlan {
+    pub vf: __u32,
+    pub vlan: __u32,
+    pub qos: __u32,
+}
+pub const IFLA_VF_VLAN_INFO_UNSPEC: _bindgen_ty_90 = 0;
+pub const IFLA_VF_VLAN_INFO: _bindgen_ty_90 = 1;
+pub const __IFLA_VF_VLAN_INFO_MAX: _bindgen_ty_90 = 2;
+pub type _bindgen_ty_90 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_vlan_info {
+    pub vf: __u32,
+    pub vlan: __u32,
+    pub qos: __u32,
+    pub vlan_proto: __be16,
+    pub __bindgen_padding_0: [u8; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_tx_rate {
+    pub vf: __u32,
+    pub rate: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_rate {
+    pub vf: __u32,
+    pub min_tx_rate: __u32,
+    pub max_tx_rate: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_spoofchk {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_guid {
+    pub vf: __u32,
+    pub __bindgen_padding_0: [u8; 4usize],
+    pub guid: __u64,
+}
+pub const IFLA_VF_LINK_STATE_AUTO: _bindgen_ty_91 = 0;
+pub const IFLA_VF_LINK_STATE_ENABLE: _bindgen_ty_91 = 1;
+pub const IFLA_VF_LINK_STATE_DISABLE: _bindgen_ty_91 = 2;
+pub const __IFLA_VF_LINK_STATE_MAX: _bindgen_ty_91 = 3;
+pub type _bindgen_ty_91 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_link_state {
+    pub vf: __u32,
+    pub link_state: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_rss_query_en {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+pub const IFLA_VF_STATS_RX_PACKETS: _bindgen_ty_92 = 0;
+pub const IFLA_VF_STATS_TX_PACKETS: _bindgen_ty_92 = 1;
+pub const IFLA_VF_STATS_RX_BYTES: _bindgen_ty_92 = 2;
+pub const IFLA_VF_STATS_TX_BYTES: _bindgen_ty_92 = 3;
+pub const IFLA_VF_STATS_BROADCAST: _bindgen_ty_92 = 4;
+pub const IFLA_VF_STATS_MULTICAST: _bindgen_ty_92 = 5;
+pub const IFLA_VF_STATS_PAD: _bindgen_ty_92 = 6;
+pub const IFLA_VF_STATS_RX_DROPPED: _bindgen_ty_92 = 7;
+pub const IFLA_VF_STATS_TX_DROPPED: _bindgen_ty_92 = 8;
+pub const __IFLA_VF_STATS_MAX: _bindgen_ty_92 = 9;
+pub type _bindgen_ty_92 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_trust {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+pub const IFLA_VF_PORT_UNSPEC: _bindgen_ty_93 = 0;
+pub const IFLA_VF_PORT: _bindgen_ty_93 = 1;
+pub const __IFLA_VF_PORT_MAX: _bindgen_ty_93 = 2;
+pub type _bindgen_ty_93 = crate::types::c_uint;
+pub const IFLA_PORT_UNSPEC: _bindgen_ty_94 = 0;
+pub const IFLA_PORT_VF: _bindgen_ty_94 = 1;
+pub const IFLA_PORT_PROFILE: _bindgen_ty_94 = 2;
+pub const IFLA_PORT_VSI_TYPE: _bindgen_ty_94 = 3;
+pub const IFLA_PORT_INSTANCE_UUID: _bindgen_ty_94 = 4;
+pub const IFLA_PORT_HOST_UUID: _bindgen_ty_94 = 5;
+pub const IFLA_PORT_REQUEST: _bindgen_ty_94 = 6;
+pub const IFLA_PORT_RESPONSE: _bindgen_ty_94 = 7;
+pub const __IFLA_PORT_MAX: _bindgen_ty_94 = 8;
+pub type _bindgen_ty_94 = crate::types::c_uint;
+pub const PORT_REQUEST_PREASSOCIATE: _bindgen_ty_95 = 0;
+pub const PORT_REQUEST_PREASSOCIATE_RR: _bindgen_ty_95 = 1;
+pub const PORT_REQUEST_ASSOCIATE: _bindgen_ty_95 = 2;
+pub const PORT_REQUEST_DISASSOCIATE: _bindgen_ty_95 = 3;
+pub type _bindgen_ty_95 = crate::types::c_uint;
+pub const PORT_VDP_RESPONSE_SUCCESS: _bindgen_ty_96 = 0;
+pub const PORT_VDP_RESPONSE_INVALID_FORMAT: _bindgen_ty_96 = 1;
+pub const PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES: _bindgen_ty_96 = 2;
+pub const PORT_VDP_RESPONSE_UNUSED_VTID: _bindgen_ty_96 = 3;
+pub const PORT_VDP_RESPONSE_VTID_VIOLATION: _bindgen_ty_96 = 4;
+pub const PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION: _bindgen_ty_96 = 5;
+pub const PORT_VDP_RESPONSE_OUT_OF_SYNC: _bindgen_ty_96 = 6;
+pub const PORT_PROFILE_RESPONSE_SUCCESS: _bindgen_ty_96 = 256;
+pub const PORT_PROFILE_RESPONSE_INPROGRESS: _bindgen_ty_96 = 257;
+pub const PORT_PROFILE_RESPONSE_INVALID: _bindgen_ty_96 = 258;
+pub const PORT_PROFILE_RESPONSE_BADSTATE: _bindgen_ty_96 = 259;
+pub const PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES: _bindgen_ty_96 = 260;
+pub const PORT_PROFILE_RESPONSE_ERROR: _bindgen_ty_96 = 261;
+pub type _bindgen_ty_96 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_port_vsi {
+    pub vsi_mgr_id: __u8,
+    pub vsi_type_id: [__u8; 3usize],
+    pub vsi_type_version: __u8,
+    pub pad: [__u8; 3usize],
+}
+pub const IFLA_IPOIB_UNSPEC: _bindgen_ty_97 = 0;
+pub const IFLA_IPOIB_PKEY: _bindgen_ty_97 = 1;
+pub const IFLA_IPOIB_MODE: _bindgen_ty_97 = 2;
+pub const IFLA_IPOIB_UMCAST: _bindgen_ty_97 = 3;
+pub const __IFLA_IPOIB_MAX: _bindgen_ty_97 = 4;
+pub type _bindgen_ty_97 = crate::types::c_uint;
+pub const IPOIB_MODE_DATAGRAM: _bindgen_ty_98 = 0;
+pub const IPOIB_MODE_CONNECTED: _bindgen_ty_98 = 1;
+pub type _bindgen_ty_98 = crate::types::c_uint;
+pub const HSR_PROTOCOL_HSR: _bindgen_ty_99 = 0;
+pub const HSR_PROTOCOL_PRP: _bindgen_ty_99 = 1;
+pub const HSR_PROTOCOL_MAX: _bindgen_ty_99 = 2;
+pub type _bindgen_ty_99 = crate::types::c_uint;
+pub const IFLA_HSR_UNSPEC: _bindgen_ty_100 = 0;
+pub const IFLA_HSR_SLAVE1: _bindgen_ty_100 = 1;
+pub const IFLA_HSR_SLAVE2: _bindgen_ty_100 = 2;
+pub const IFLA_HSR_MULTICAST_SPEC: _bindgen_ty_100 = 3;
+pub const IFLA_HSR_SUPERVISION_ADDR: _bindgen_ty_100 = 4;
+pub const IFLA_HSR_SEQ_NR: _bindgen_ty_100 = 5;
+pub const IFLA_HSR_VERSION: _bindgen_ty_100 = 6;
+pub const IFLA_HSR_PROTOCOL: _bindgen_ty_100 = 7;
+pub const __IFLA_HSR_MAX: _bindgen_ty_100 = 8;
+pub type _bindgen_ty_100 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct if_stats_msg {
+    pub family: __u8,
+    pub pad1: __u8,
+    pub pad2: __u16,
+    pub ifindex: __u32,
+    pub filter_mask: __u32,
+}
+pub const IFLA_STATS_UNSPEC: _bindgen_ty_101 = 0;
+pub const IFLA_STATS_LINK_64: _bindgen_ty_101 = 1;
+pub const IFLA_STATS_LINK_XSTATS: _bindgen_ty_101 = 2;
+pub const IFLA_STATS_LINK_XSTATS_SLAVE: _bindgen_ty_101 = 3;
+pub const IFLA_STATS_LINK_OFFLOAD_XSTATS: _bindgen_ty_101 = 4;
+pub const IFLA_STATS_AF_SPEC: _bindgen_ty_101 = 5;
+pub const __IFLA_STATS_MAX: _bindgen_ty_101 = 6;
+pub type _bindgen_ty_101 = crate::types::c_uint;
+pub const IFLA_STATS_GETSET_UNSPEC: _bindgen_ty_102 = 0;
+pub const IFLA_STATS_GET_FILTERS: _bindgen_ty_102 = 1;
+pub const IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS: _bindgen_ty_102 = 2;
+pub const __IFLA_STATS_GETSET_MAX: _bindgen_ty_102 = 3;
+pub type _bindgen_ty_102 = crate::types::c_uint;
+pub const LINK_XSTATS_TYPE_UNSPEC: _bindgen_ty_103 = 0;
+pub const LINK_XSTATS_TYPE_BRIDGE: _bindgen_ty_103 = 1;
+pub const LINK_XSTATS_TYPE_BOND: _bindgen_ty_103 = 2;
+pub const __LINK_XSTATS_TYPE_MAX: _bindgen_ty_103 = 3;
+pub type _bindgen_ty_103 = crate::types::c_uint;
+pub const IFLA_OFFLOAD_XSTATS_UNSPEC: _bindgen_ty_104 = 0;
+pub const IFLA_OFFLOAD_XSTATS_CPU_HIT: _bindgen_ty_104 = 1;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO: _bindgen_ty_104 = 2;
+pub const IFLA_OFFLOAD_XSTATS_L3_STATS: _bindgen_ty_104 = 3;
+pub const __IFLA_OFFLOAD_XSTATS_MAX: _bindgen_ty_104 = 4;
+pub type _bindgen_ty_104 = crate::types::c_uint;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC: _bindgen_ty_105 = 0;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST: _bindgen_ty_105 = 1;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED: _bindgen_ty_105 = 2;
+pub const __IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX: _bindgen_ty_105 = 3;
+pub type _bindgen_ty_105 = crate::types::c_uint;
+pub const XDP_ATTACHED_NONE: _bindgen_ty_106 = 0;
+pub const XDP_ATTACHED_DRV: _bindgen_ty_106 = 1;
+pub const XDP_ATTACHED_SKB: _bindgen_ty_106 = 2;
+pub const XDP_ATTACHED_HW: _bindgen_ty_106 = 3;
+pub const XDP_ATTACHED_MULTI: _bindgen_ty_106 = 4;
+pub type _bindgen_ty_106 = crate::types::c_uint;
+pub const IFLA_XDP_UNSPEC: _bindgen_ty_107 = 0;
+pub const IFLA_XDP_FD: _bindgen_ty_107 = 1;
+pub const IFLA_XDP_ATTACHED: _bindgen_ty_107 = 2;
+pub const IFLA_XDP_FLAGS: _bindgen_ty_107 = 3;
+pub const IFLA_XDP_PROG_ID: _bindgen_ty_107 = 4;
+pub const IFLA_XDP_DRV_PROG_ID: _bindgen_ty_107 = 5;
+pub const IFLA_XDP_SKB_PROG_ID: _bindgen_ty_107 = 6;
+pub const IFLA_XDP_HW_PROG_ID: _bindgen_ty_107 = 7;
+pub const IFLA_XDP_EXPECTED_FD: _bindgen_ty_107 = 8;
+pub const __IFLA_XDP_MAX: _bindgen_ty_107 = 9;
+pub type _bindgen_ty_107 = crate::types::c_uint;
+pub const IFLA_EVENT_NONE: _bindgen_ty_108 = 0;
+pub const IFLA_EVENT_REBOOT: _bindgen_ty_108 = 1;
+pub const IFLA_EVENT_FEATURES: _bindgen_ty_108 = 2;
+pub const IFLA_EVENT_BONDING_FAILOVER: _bindgen_ty_108 = 3;
+pub const IFLA_EVENT_NOTIFY_PEERS: _bindgen_ty_108 = 4;
+pub const IFLA_EVENT_IGMP_RESEND: _bindgen_ty_108 = 5;
+pub const IFLA_EVENT_BONDING_OPTIONS: _bindgen_ty_108 = 6;
+pub type _bindgen_ty_108 = crate::types::c_uint;
+pub const IFLA_TUN_UNSPEC: _bindgen_ty_109 = 0;
+pub const IFLA_TUN_OWNER: _bindgen_ty_109 = 1;
+pub const IFLA_TUN_GROUP: _bindgen_ty_109 = 2;
+pub const IFLA_TUN_TYPE: _bindgen_ty_109 = 3;
+pub const IFLA_TUN_PI: _bindgen_ty_109 = 4;
+pub const IFLA_TUN_VNET_HDR: _bindgen_ty_109 = 5;
+pub const IFLA_TUN_PERSIST: _bindgen_ty_109 = 6;
+pub const IFLA_TUN_MULTI_QUEUE: _bindgen_ty_109 = 7;
+pub const IFLA_TUN_NUM_QUEUES: _bindgen_ty_109 = 8;
+pub const IFLA_TUN_NUM_DISABLED_QUEUES: _bindgen_ty_109 = 9;
+pub const __IFLA_TUN_MAX: _bindgen_ty_109 = 10;
+pub type _bindgen_ty_109 = crate::types::c_uint;
+pub const IFLA_RMNET_UNSPEC: _bindgen_ty_110 = 0;
+pub const IFLA_RMNET_MUX_ID: _bindgen_ty_110 = 1;
+pub const IFLA_RMNET_FLAGS: _bindgen_ty_110 = 2;
+pub const __IFLA_RMNET_MAX: _bindgen_ty_110 = 3;
+pub type _bindgen_ty_110 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_rmnet_flags {
+    pub flags: __u32,
+    pub mask: __u32,
+}
+pub const IFLA_MCTP_UNSPEC: _bindgen_ty_111 = 0;
+pub const IFLA_MCTP_NET: _bindgen_ty_111 = 1;
+pub const __IFLA_MCTP_MAX: _bindgen_ty_111 = 2;
+pub type _bindgen_ty_111 = crate::types::c_uint;
+pub const IFLA_DSA_UNSPEC: _bindgen_ty_112 = 0;
+pub const IFLA_DSA_MASTER: _bindgen_ty_112 = 1;
+pub const __IFLA_DSA_MAX: _bindgen_ty_112 = 2;
+pub type _bindgen_ty_112 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifaddrmsg {
+    pub ifa_family: __u8,
+    pub ifa_prefixlen: __u8,
+    pub ifa_flags: __u8,
+    pub ifa_scope: __u8,
+    pub ifa_index: __u32,
+}
+pub const IFA_UNSPEC: _bindgen_ty_113 = 0;
+pub const IFA_ADDRESS: _bindgen_ty_113 = 1;
+pub const IFA_LOCAL: _bindgen_ty_113 = 2;
+pub const IFA_LABEL: _bindgen_ty_113 = 3;
+pub const IFA_BROADCAST: _bindgen_ty_113 = 4;
+pub const IFA_ANYCAST: _bindgen_ty_113 = 5;
+pub const IFA_CACHEINFO: _bindgen_ty_113 = 6;
+pub const IFA_MULTICAST: _bindgen_ty_113 = 7;
+pub const IFA_FLAGS: _bindgen_ty_113 = 8;
+pub const IFA_RT_PRIORITY: _bindgen_ty_113 = 9;
+pub const IFA_TARGET_NETNSID: _bindgen_ty_113 = 10;
+pub const IFA_PROTO: _bindgen_ty_113 = 11;
+pub const __IFA_MAX: _bindgen_ty_113 = 12;
+pub type _bindgen_ty_113 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifa_cacheinfo {
+    pub ifa_prefered: __u32,
+    pub ifa_valid: __u32,
+    pub cstamp: __u32,
+    pub tstamp: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndmsg {
+    pub ndm_family: __u8,
+    pub ndm_pad1: __u8,
+    pub ndm_pad2: __u16,
+    pub ndm_ifindex: __s32,
+    pub ndm_state: __u16,
+    pub ndm_flags: __u8,
+    pub ndm_type: __u8,
+}
+pub const NDA_UNSPEC: _bindgen_ty_114 = 0;
+pub const NDA_DST: _bindgen_ty_114 = 1;
+pub const NDA_LLADDR: _bindgen_ty_114 = 2;
+pub const NDA_CACHEINFO: _bindgen_ty_114 = 3;
+pub const NDA_PROBES: _bindgen_ty_114 = 4;
+pub const NDA_VLAN: _bindgen_ty_114 = 5;
+pub const NDA_PORT: _bindgen_ty_114 = 6;
+pub const NDA_VNI: _bindgen_ty_114 = 7;
+pub const NDA_IFINDEX: _bindgen_ty_114 = 8;
+pub const NDA_MASTER: _bindgen_ty_114 = 9;
+pub const NDA_LINK_NETNSID: _bindgen_ty_114 = 10;
+pub const NDA_SRC_VNI: _bindgen_ty_114 = 11;
+pub const NDA_PROTOCOL: _bindgen_ty_114 = 12;
+pub const NDA_NH_ID: _bindgen_ty_114 = 13;
+pub const NDA_FDB_EXT_ATTRS: _bindgen_ty_114 = 14;
+pub const NDA_FLAGS_EXT: _bindgen_ty_114 = 15;
+pub const NDA_NDM_STATE_MASK: _bindgen_ty_114 = 16;
+pub const NDA_NDM_FLAGS_MASK: _bindgen_ty_114 = 17;
+pub const __NDA_MAX: _bindgen_ty_114 = 18;
+pub type _bindgen_ty_114 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct nda_cacheinfo {
+    pub ndm_confirmed: __u32,
+    pub ndm_used: __u32,
+    pub ndm_updated: __u32,
+    pub ndm_refcnt: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndt_stats {
+    pub ndts_allocs: __u64,
+    pub ndts_destroys: __u64,
+    pub ndts_hash_grows: __u64,
+    pub ndts_res_failed: __u64,
+    pub ndts_lookups: __u64,
+    pub ndts_hits: __u64,
+    pub ndts_rcv_probes_mcast: __u64,
+    pub ndts_rcv_probes_ucast: __u64,
+    pub ndts_periodic_gc_runs: __u64,
+    pub ndts_forced_gc_runs: __u64,
+    pub ndts_table_fulls: __u64,
+}
+pub const NDTPA_UNSPEC: _bindgen_ty_115 = 0;
+pub const NDTPA_IFINDEX: _bindgen_ty_115 = 1;
+pub const NDTPA_REFCNT: _bindgen_ty_115 = 2;
+pub const NDTPA_REACHABLE_TIME: _bindgen_ty_115 = 3;
+pub const NDTPA_BASE_REACHABLE_TIME: _bindgen_ty_115 = 4;
+pub const NDTPA_RETRANS_TIME: _bindgen_ty_115 = 5;
+pub const NDTPA_GC_STALETIME: _bindgen_ty_115 = 6;
+pub const NDTPA_DELAY_PROBE_TIME: _bindgen_ty_115 = 7;
+pub const NDTPA_QUEUE_LEN: _bindgen_ty_115 = 8;
+pub const NDTPA_APP_PROBES: _bindgen_ty_115 = 9;
+pub const NDTPA_UCAST_PROBES: _bindgen_ty_115 = 10;
+pub const NDTPA_MCAST_PROBES: _bindgen_ty_115 = 11;
+pub const NDTPA_ANYCAST_DELAY: _bindgen_ty_115 = 12;
+pub const NDTPA_PROXY_DELAY: _bindgen_ty_115 = 13;
+pub const NDTPA_PROXY_QLEN: _bindgen_ty_115 = 14;
+pub const NDTPA_LOCKTIME: _bindgen_ty_115 = 15;
+pub const NDTPA_QUEUE_LENBYTES: _bindgen_ty_115 = 16;
+pub const NDTPA_MCAST_REPROBES: _bindgen_ty_115 = 17;
+pub const NDTPA_PAD: _bindgen_ty_115 = 18;
+pub const NDTPA_INTERVAL_PROBE_TIME_MS: _bindgen_ty_115 = 19;
+pub const __NDTPA_MAX: _bindgen_ty_115 = 20;
+pub type _bindgen_ty_115 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndtmsg {
+    pub ndtm_family: __u8,
+    pub ndtm_pad1: __u8,
+    pub ndtm_pad2: __u16,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndt_config {
+    pub ndtc_key_len: __u16,
+    pub ndtc_entry_size: __u16,
+    pub ndtc_entries: __u32,
+    pub ndtc_last_flush: __u32,
+    pub ndtc_last_rand: __u32,
+    pub ndtc_hash_rnd: __u32,
+    pub ndtc_hash_mask: __u32,
+    pub ndtc_hash_chain_gc: __u32,
+    pub ndtc_proxy_qlen: __u32,
+}
+pub const NDTA_UNSPEC: _bindgen_ty_116 = 0;
+pub const NDTA_NAME: _bindgen_ty_116 = 1;
+pub const NDTA_THRESH1: _bindgen_ty_116 = 2;
+pub const NDTA_THRESH2: _bindgen_ty_116 = 3;
+pub const NDTA_THRESH3: _bindgen_ty_116 = 4;
+pub const NDTA_CONFIG: _bindgen_ty_116 = 5;
+pub const NDTA_PARMS: _bindgen_ty_116 = 6;
+pub const NDTA_STATS: _bindgen_ty_116 = 7;
+pub const NDTA_GC_INTERVAL: _bindgen_ty_116 = 8;
+pub const NDTA_PAD: _bindgen_ty_116 = 9;
+pub const __NDTA_MAX: _bindgen_ty_116 = 10;
+pub type _bindgen_ty_116 = crate::types::c_uint;
+pub const FDB_NOTIFY_BIT: _bindgen_ty_117 = 1;
+pub const FDB_NOTIFY_INACTIVE_BIT: _bindgen_ty_117 = 2;
+pub type _bindgen_ty_117 = crate::types::c_uint;
+pub const NFEA_UNSPEC: _bindgen_ty_118 = 0;
+pub const NFEA_ACTIVITY_NOTIFY: _bindgen_ty_118 = 1;
+pub const NFEA_DONT_REFRESH: _bindgen_ty_118 = 2;
+pub const __NFEA_MAX: _bindgen_ty_118 = 3;
+pub type _bindgen_ty_118 = crate::types::c_uint;
+pub const RTM_BASE: _bindgen_ty_119 = 16;
+pub const RTM_NEWLINK: _bindgen_ty_119 = 16;
+pub const RTM_DELLINK: _bindgen_ty_119 = 17;
+pub const RTM_GETLINK: _bindgen_ty_119 = 18;
+pub const RTM_SETLINK: _bindgen_ty_119 = 19;
+pub const RTM_NEWADDR: _bindgen_ty_119 = 20;
+pub const RTM_DELADDR: _bindgen_ty_119 = 21;
+pub const RTM_GETADDR: _bindgen_ty_119 = 22;
+pub const RTM_NEWROUTE: _bindgen_ty_119 = 24;
+pub const RTM_DELROUTE: _bindgen_ty_119 = 25;
+pub const RTM_GETROUTE: _bindgen_ty_119 = 26;
+pub const RTM_NEWNEIGH: _bindgen_ty_119 = 28;
+pub const RTM_DELNEIGH: _bindgen_ty_119 = 29;
+pub const RTM_GETNEIGH: _bindgen_ty_119 = 30;
+pub const RTM_NEWRULE: _bindgen_ty_119 = 32;
+pub const RTM_DELRULE: _bindgen_ty_119 = 33;
+pub const RTM_GETRULE: _bindgen_ty_119 = 34;
+pub const RTM_NEWQDISC: _bindgen_ty_119 = 36;
+pub const RTM_DELQDISC: _bindgen_ty_119 = 37;
+pub const RTM_GETQDISC: _bindgen_ty_119 = 38;
+pub const RTM_NEWTCLASS: _bindgen_ty_119 = 40;
+pub const RTM_DELTCLASS: _bindgen_ty_119 = 41;
+pub const RTM_GETTCLASS: _bindgen_ty_119 = 42;
+pub const RTM_NEWTFILTER: _bindgen_ty_119 = 44;
+pub const RTM_DELTFILTER: _bindgen_ty_119 = 45;
+pub const RTM_GETTFILTER: _bindgen_ty_119 = 46;
+pub const RTM_NEWACTION: _bindgen_ty_119 = 48;
+pub const RTM_DELACTION: _bindgen_ty_119 = 49;
+pub const RTM_GETACTION: _bindgen_ty_119 = 50;
+pub const RTM_NEWPREFIX: _bindgen_ty_119 = 52;
+pub const RTM_GETMULTICAST: _bindgen_ty_119 = 58;
+pub const RTM_GETANYCAST: _bindgen_ty_119 = 62;
+pub const RTM_NEWNEIGHTBL: _bindgen_ty_119 = 64;
+pub const RTM_GETNEIGHTBL: _bindgen_ty_119 = 66;
+pub const RTM_SETNEIGHTBL: _bindgen_ty_119 = 67;
+pub const RTM_NEWNDUSEROPT: _bindgen_ty_119 = 68;
+pub const RTM_NEWADDRLABEL: _bindgen_ty_119 = 72;
+pub const RTM_DELADDRLABEL: _bindgen_ty_119 = 73;
+pub const RTM_GETADDRLABEL: _bindgen_ty_119 = 74;
+pub const RTM_GETDCB: _bindgen_ty_119 = 78;
+pub const RTM_SETDCB: _bindgen_ty_119 = 79;
+pub const RTM_NEWNETCONF: _bindgen_ty_119 = 80;
+pub const RTM_DELNETCONF: _bindgen_ty_119 = 81;
+pub const RTM_GETNETCONF: _bindgen_ty_119 = 82;
+pub const RTM_NEWMDB: _bindgen_ty_119 = 84;
+pub const RTM_DELMDB: _bindgen_ty_119 = 85;
+pub const RTM_GETMDB: _bindgen_ty_119 = 86;
+pub const RTM_NEWNSID: _bindgen_ty_119 = 88;
+pub const RTM_DELNSID: _bindgen_ty_119 = 89;
+pub const RTM_GETNSID: _bindgen_ty_119 = 90;
+pub const RTM_NEWSTATS: _bindgen_ty_119 = 92;
+pub const RTM_GETSTATS: _bindgen_ty_119 = 94;
+pub const RTM_SETSTATS: _bindgen_ty_119 = 95;
+pub const RTM_NEWCACHEREPORT: _bindgen_ty_119 = 96;
+pub const RTM_NEWCHAIN: _bindgen_ty_119 = 100;
+pub const RTM_DELCHAIN: _bindgen_ty_119 = 101;
+pub const RTM_GETCHAIN: _bindgen_ty_119 = 102;
+pub const RTM_NEWNEXTHOP: _bindgen_ty_119 = 104;
+pub const RTM_DELNEXTHOP: _bindgen_ty_119 = 105;
+pub const RTM_GETNEXTHOP: _bindgen_ty_119 = 106;
+pub const RTM_NEWLINKPROP: _bindgen_ty_119 = 108;
+pub const RTM_DELLINKPROP: _bindgen_ty_119 = 109;
+pub const RTM_GETLINKPROP: _bindgen_ty_119 = 110;
+pub const RTM_NEWVLAN: _bindgen_ty_119 = 112;
+pub const RTM_DELVLAN: _bindgen_ty_119 = 113;
+pub const RTM_GETVLAN: _bindgen_ty_119 = 114;
+pub const RTM_NEWNEXTHOPBUCKET: _bindgen_ty_119 = 116;
+pub const RTM_DELNEXTHOPBUCKET: _bindgen_ty_119 = 117;
+pub const RTM_GETNEXTHOPBUCKET: _bindgen_ty_119 = 118;
+pub const RTM_NEWTUNNEL: _bindgen_ty_119 = 120;
+pub const RTM_DELTUNNEL: _bindgen_ty_119 = 121;
+pub const RTM_GETTUNNEL: _bindgen_ty_119 = 122;
+pub const __RTM_MAX: _bindgen_ty_119 = 123;
+pub type _bindgen_ty_119 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtattr {
+    pub rta_len: crate::types::c_ushort,
+    pub rta_type: crate::types::c_ushort,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtmsg {
+    pub rtm_family: crate::types::c_uchar,
+    pub rtm_dst_len: crate::types::c_uchar,
+    pub rtm_src_len: crate::types::c_uchar,
+    pub rtm_tos: crate::types::c_uchar,
+    pub rtm_table: crate::types::c_uchar,
+    pub rtm_protocol: crate::types::c_uchar,
+    pub rtm_scope: crate::types::c_uchar,
+    pub rtm_type: crate::types::c_uchar,
+    pub rtm_flags: crate::types::c_uint,
+}
+pub const RTN_UNSPEC: _bindgen_ty_120 = 0;
+pub const RTN_UNICAST: _bindgen_ty_120 = 1;
+pub const RTN_LOCAL: _bindgen_ty_120 = 2;
+pub const RTN_BROADCAST: _bindgen_ty_120 = 3;
+pub const RTN_ANYCAST: _bindgen_ty_120 = 4;
+pub const RTN_MULTICAST: _bindgen_ty_120 = 5;
+pub const RTN_BLACKHOLE: _bindgen_ty_120 = 6;
+pub const RTN_UNREACHABLE: _bindgen_ty_120 = 7;
+pub const RTN_PROHIBIT: _bindgen_ty_120 = 8;
+pub const RTN_THROW: _bindgen_ty_120 = 9;
+pub const RTN_NAT: _bindgen_ty_120 = 10;
+pub const RTN_XRESOLVE: _bindgen_ty_120 = 11;
+pub const __RTN_MAX: _bindgen_ty_120 = 12;
+pub type _bindgen_ty_120 = crate::types::c_uint;
+pub const rt_scope_t_RT_SCOPE_UNIVERSE: rt_scope_t = 0;
+pub const rt_scope_t_RT_SCOPE_SITE: rt_scope_t = 200;
+pub const rt_scope_t_RT_SCOPE_LINK: rt_scope_t = 253;
+pub const rt_scope_t_RT_SCOPE_HOST: rt_scope_t = 254;
+pub const rt_scope_t_RT_SCOPE_NOWHERE: rt_scope_t = 255;
+pub type rt_scope_t = crate::types::c_uint;
+pub const rt_class_t_RT_TABLE_UNSPEC: rt_class_t = 0;
+pub const rt_class_t_RT_TABLE_COMPAT: rt_class_t = 252;
+pub const rt_class_t_RT_TABLE_DEFAULT: rt_class_t = 253;
+pub const rt_class_t_RT_TABLE_MAIN: rt_class_t = 254;
+pub const rt_class_t_RT_TABLE_LOCAL: rt_class_t = 255;
+pub const rt_class_t_RT_TABLE_MAX: rt_class_t = 4294967295;
+pub type rt_class_t = crate::types::c_uint;
+pub const rtattr_type_t_RTA_UNSPEC: rtattr_type_t = 0;
+pub const rtattr_type_t_RTA_DST: rtattr_type_t = 1;
+pub const rtattr_type_t_RTA_SRC: rtattr_type_t = 2;
+pub const rtattr_type_t_RTA_IIF: rtattr_type_t = 3;
+pub const rtattr_type_t_RTA_OIF: rtattr_type_t = 4;
+pub const rtattr_type_t_RTA_GATEWAY: rtattr_type_t = 5;
+pub const rtattr_type_t_RTA_PRIORITY: rtattr_type_t = 6;
+pub const rtattr_type_t_RTA_PREFSRC: rtattr_type_t = 7;
+pub const rtattr_type_t_RTA_METRICS: rtattr_type_t = 8;
+pub const rtattr_type_t_RTA_MULTIPATH: rtattr_type_t = 9;
+pub const rtattr_type_t_RTA_PROTOINFO: rtattr_type_t = 10;
+pub const rtattr_type_t_RTA_FLOW: rtattr_type_t = 11;
+pub const rtattr_type_t_RTA_CACHEINFO: rtattr_type_t = 12;
+pub const rtattr_type_t_RTA_SESSION: rtattr_type_t = 13;
+pub const rtattr_type_t_RTA_MP_ALGO: rtattr_type_t = 14;
+pub const rtattr_type_t_RTA_TABLE: rtattr_type_t = 15;
+pub const rtattr_type_t_RTA_MARK: rtattr_type_t = 16;
+pub const rtattr_type_t_RTA_MFC_STATS: rtattr_type_t = 17;
+pub const rtattr_type_t_RTA_VIA: rtattr_type_t = 18;
+pub const rtattr_type_t_RTA_NEWDST: rtattr_type_t = 19;
+pub const rtattr_type_t_RTA_PREF: rtattr_type_t = 20;
+pub const rtattr_type_t_RTA_ENCAP_TYPE: rtattr_type_t = 21;
+pub const rtattr_type_t_RTA_ENCAP: rtattr_type_t = 22;
+pub const rtattr_type_t_RTA_EXPIRES: rtattr_type_t = 23;
+pub const rtattr_type_t_RTA_PAD: rtattr_type_t = 24;
+pub const rtattr_type_t_RTA_UID: rtattr_type_t = 25;
+pub const rtattr_type_t_RTA_TTL_PROPAGATE: rtattr_type_t = 26;
+pub const rtattr_type_t_RTA_IP_PROTO: rtattr_type_t = 27;
+pub const rtattr_type_t_RTA_SPORT: rtattr_type_t = 28;
+pub const rtattr_type_t_RTA_DPORT: rtattr_type_t = 29;
+pub const rtattr_type_t_RTA_NH_ID: rtattr_type_t = 30;
+pub const rtattr_type_t___RTA_MAX: rtattr_type_t = 31;
+pub type rtattr_type_t = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnexthop {
+    pub rtnh_len: crate::types::c_ushort,
+    pub rtnh_flags: crate::types::c_uchar,
+    pub rtnh_hops: crate::types::c_uchar,
+    pub rtnh_ifindex: crate::types::c_int,
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct rtvia {
+    pub rtvia_family: __kernel_sa_family_t,
+    pub rtvia_addr: __IncompleteArrayField<__u8>,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_cacheinfo {
+    pub rta_clntref: __u32,
+    pub rta_lastuse: __u32,
+    pub rta_expires: __s32,
+    pub rta_error: __u32,
+    pub rta_used: __u32,
+    pub rta_id: __u32,
+    pub rta_ts: __u32,
+    pub rta_tsage: __u32,
+}
+pub const RTAX_UNSPEC: _bindgen_ty_121 = 0;
+pub const RTAX_LOCK: _bindgen_ty_121 = 1;
+pub const RTAX_MTU: _bindgen_ty_121 = 2;
+pub const RTAX_WINDOW: _bindgen_ty_121 = 3;
+pub const RTAX_RTT: _bindgen_ty_121 = 4;
+pub const RTAX_RTTVAR: _bindgen_ty_121 = 5;
+pub const RTAX_SSTHRESH: _bindgen_ty_121 = 6;
+pub const RTAX_CWND: _bindgen_ty_121 = 7;
+pub const RTAX_ADVMSS: _bindgen_ty_121 = 8;
+pub const RTAX_REORDERING: _bindgen_ty_121 = 9;
+pub const RTAX_HOPLIMIT: _bindgen_ty_121 = 10;
+pub const RTAX_INITCWND: _bindgen_ty_121 = 11;
+pub const RTAX_FEATURES: _bindgen_ty_121 = 12;
+pub const RTAX_RTO_MIN: _bindgen_ty_121 = 13;
+pub const RTAX_INITRWND: _bindgen_ty_121 = 14;
+pub const RTAX_QUICKACK: _bindgen_ty_121 = 15;
+pub const RTAX_CC_ALGO: _bindgen_ty_121 = 16;
+pub const RTAX_FASTOPEN_NO_COOKIE: _bindgen_ty_121 = 17;
+pub const __RTAX_MAX: _bindgen_ty_121 = 18;
+pub type _bindgen_ty_121 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct rta_session {
+    pub proto: __u8,
+    pub pad1: __u8,
+    pub pad2: __u16,
+    pub u: rta_session__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union rta_session__bindgen_ty_1 {
+    pub ports: rta_session__bindgen_ty_1__bindgen_ty_1,
+    pub icmpt: rta_session__bindgen_ty_1__bindgen_ty_2,
+    pub spi: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_session__bindgen_ty_1__bindgen_ty_1 {
+    pub sport: __u16,
+    pub dport: __u16,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_session__bindgen_ty_1__bindgen_ty_2 {
+    pub type_: __u8,
+    pub code: __u8,
+    pub ident: __u16,
+}
+impl Default for rta_session__bindgen_ty_1 {
+    fn default() -> Self {
+        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+impl Default for rta_session {
+    fn default() -> Self {
+        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_mfc_stats {
+    pub mfcs_packets: __u64,
+    pub mfcs_bytes: __u64,
+    pub mfcs_wrong_if: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtgenmsg {
+    pub rtgen_family: crate::types::c_uchar,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifinfomsg {
+    pub ifi_family: crate::types::c_uchar,
+    pub __ifi_pad: crate::types::c_uchar,
+    pub ifi_type: crate::types::c_ushort,
+    pub ifi_index: crate::types::c_int,
+    pub ifi_flags: crate::types::c_uint,
+    pub ifi_change: crate::types::c_uint,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct prefixmsg {
+    pub prefix_family: crate::types::c_uchar,
+    pub prefix_pad1: crate::types::c_uchar,
+    pub prefix_pad2: crate::types::c_ushort,
+    pub prefix_ifindex: crate::types::c_int,
+    pub prefix_type: crate::types::c_uchar,
+    pub prefix_len: crate::types::c_uchar,
+    pub prefix_flags: crate::types::c_uchar,
+    pub prefix_pad3: crate::types::c_uchar,
+}
+pub const PREFIX_UNSPEC: _bindgen_ty_122 = 0;
+pub const PREFIX_ADDRESS: _bindgen_ty_122 = 1;
+pub const PREFIX_CACHEINFO: _bindgen_ty_122 = 2;
+pub const __PREFIX_MAX: _bindgen_ty_122 = 3;
+pub type _bindgen_ty_122 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct prefix_cacheinfo {
+    pub preferred_time: __u32,
+    pub valid_time: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tcmsg {
+    pub tcm_family: crate::types::c_uchar,
+    pub tcm__pad1: crate::types::c_uchar,
+    pub tcm__pad2: crate::types::c_ushort,
+    pub tcm_ifindex: crate::types::c_int,
+    pub tcm_handle: __u32,
+    pub tcm_parent: __u32,
+    pub tcm_info: __u32,
+}
+pub const TCA_UNSPEC: _bindgen_ty_123 = 0;
+pub const TCA_KIND: _bindgen_ty_123 = 1;
+pub const TCA_OPTIONS: _bindgen_ty_123 = 2;
+pub const TCA_STATS: _bindgen_ty_123 = 3;
+pub const TCA_XSTATS: _bindgen_ty_123 = 4;
+pub const TCA_RATE: _bindgen_ty_123 = 5;
+pub const TCA_FCNT: _bindgen_ty_123 = 6;
+pub const TCA_STATS2: _bindgen_ty_123 = 7;
+pub const TCA_STAB: _bindgen_ty_123 = 8;
+pub const TCA_PAD: _bindgen_ty_123 = 9;
+pub const TCA_DUMP_INVISIBLE: _bindgen_ty_123 = 10;
+pub const TCA_CHAIN: _bindgen_ty_123 = 11;
+pub const TCA_HW_OFFLOAD: _bindgen_ty_123 = 12;
+pub const TCA_INGRESS_BLOCK: _bindgen_ty_123 = 13;
+pub const TCA_EGRESS_BLOCK: _bindgen_ty_123 = 14;
+pub const TCA_DUMP_FLAGS: _bindgen_ty_123 = 15;
+pub const TCA_EXT_WARN_MSG: _bindgen_ty_123 = 16;
+pub const __TCA_MAX: _bindgen_ty_123 = 17;
+pub type _bindgen_ty_123 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct nduseroptmsg {
+    pub nduseropt_family: crate::types::c_uchar,
+    pub nduseropt_pad1: crate::types::c_uchar,
+    pub nduseropt_opts_len: crate::types::c_ushort,
+    pub nduseropt_ifindex: crate::types::c_int,
+    pub nduseropt_icmp_type: __u8,
+    pub nduseropt_icmp_code: __u8,
+    pub nduseropt_pad2: crate::types::c_ushort,
+    pub nduseropt_pad3: crate::types::c_uint,
+}
+pub const NDUSEROPT_UNSPEC: _bindgen_ty_124 = 0;
+pub const NDUSEROPT_SRCADDR: _bindgen_ty_124 = 1;
+pub const __NDUSEROPT_MAX: _bindgen_ty_124 = 2;
+pub type _bindgen_ty_124 = crate::types::c_uint;
+pub const rtnetlink_groups_RTNLGRP_NONE: rtnetlink_groups = 0;
+pub const rtnetlink_groups_RTNLGRP_LINK: rtnetlink_groups = 1;
+pub const rtnetlink_groups_RTNLGRP_NOTIFY: rtnetlink_groups = 2;
+pub const rtnetlink_groups_RTNLGRP_NEIGH: rtnetlink_groups = 3;
+pub const rtnetlink_groups_RTNLGRP_TC: rtnetlink_groups = 4;
+pub const rtnetlink_groups_RTNLGRP_IPV4_IFADDR: rtnetlink_groups = 5;
+pub const rtnetlink_groups_RTNLGRP_IPV4_MROUTE: rtnetlink_groups = 6;
+pub const rtnetlink_groups_RTNLGRP_IPV4_ROUTE: rtnetlink_groups = 7;
+pub const rtnetlink_groups_RTNLGRP_IPV4_RULE: rtnetlink_groups = 8;
+pub const rtnetlink_groups_RTNLGRP_IPV6_IFADDR: rtnetlink_groups = 9;
+pub const rtnetlink_groups_RTNLGRP_IPV6_MROUTE: rtnetlink_groups = 10;
+pub const rtnetlink_groups_RTNLGRP_IPV6_ROUTE: rtnetlink_groups = 11;
+pub const rtnetlink_groups_RTNLGRP_IPV6_IFINFO: rtnetlink_groups = 12;
+pub const rtnetlink_groups_RTNLGRP_DECnet_IFADDR: rtnetlink_groups = 13;
+pub const rtnetlink_groups_RTNLGRP_NOP2: rtnetlink_groups = 14;
+pub const rtnetlink_groups_RTNLGRP_DECnet_ROUTE: rtnetlink_groups = 15;
+pub const rtnetlink_groups_RTNLGRP_DECnet_RULE: rtnetlink_groups = 16;
+pub const rtnetlink_groups_RTNLGRP_NOP4: rtnetlink_groups = 17;
+pub const rtnetlink_groups_RTNLGRP_IPV6_PREFIX: rtnetlink_groups = 18;
+pub const rtnetlink_groups_RTNLGRP_IPV6_RULE: rtnetlink_groups = 19;
+pub const rtnetlink_groups_RTNLGRP_ND_USEROPT: rtnetlink_groups = 20;
+pub const rtnetlink_groups_RTNLGRP_PHONET_IFADDR: rtnetlink_groups = 21;
+pub const rtnetlink_groups_RTNLGRP_PHONET_ROUTE: rtnetlink_groups = 22;
+pub const rtnetlink_groups_RTNLGRP_DCB: rtnetlink_groups = 23;
+pub const rtnetlink_groups_RTNLGRP_IPV4_NETCONF: rtnetlink_groups = 24;
+pub const rtnetlink_groups_RTNLGRP_IPV6_NETCONF: rtnetlink_groups = 25;
+pub const rtnetlink_groups_RTNLGRP_MDB: rtnetlink_groups = 26;
+pub const rtnetlink_groups_RTNLGRP_MPLS_ROUTE: rtnetlink_groups = 27;
+pub const rtnetlink_groups_RTNLGRP_NSID: rtnetlink_groups = 28;
+pub const rtnetlink_groups_RTNLGRP_MPLS_NETCONF: rtnetlink_groups = 29;
+pub const rtnetlink_groups_RTNLGRP_IPV4_MROUTE_R: rtnetlink_groups = 30;
+pub const rtnetlink_groups_RTNLGRP_IPV6_MROUTE_R: rtnetlink_groups = 31;
+pub const rtnetlink_groups_RTNLGRP_NEXTHOP: rtnetlink_groups = 32;
+pub const rtnetlink_groups_RTNLGRP_BRVLAN: rtnetlink_groups = 33;
+pub const rtnetlink_groups_RTNLGRP_MCTP_IFADDR: rtnetlink_groups = 34;
+pub const rtnetlink_groups_RTNLGRP_TUNNEL: rtnetlink_groups = 35;
+pub const rtnetlink_groups_RTNLGRP_STATS: rtnetlink_groups = 36;
+pub const rtnetlink_groups___RTNLGRP_MAX: rtnetlink_groups = 37;
+pub type rtnetlink_groups = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tcamsg {
+    pub tca_family: crate::types::c_uchar,
+    pub tca__pad1: crate::types::c_uchar,
+    pub tca__pad2: crate::types::c_ushort,
+}
+pub const TCA_ROOT_UNSPEC: _bindgen_ty_125 = 0;
+pub const TCA_ROOT_TAB: _bindgen_ty_125 = 1;
+pub const TCA_ROOT_FLAGS: _bindgen_ty_125 = 2;
+pub const TCA_ROOT_COUNT: _bindgen_ty_125 = 3;
+pub const TCA_ROOT_TIME_DELTA: _bindgen_ty_125 = 4;
+pub const TCA_ROOT_EXT_WARN_MSG: _bindgen_ty_125 = 5;
+pub const __TCA_ROOT_MAX: _bindgen_ty_125 = 6;
+pub type _bindgen_ty_125 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
 pub struct clone_args {
     pub flags: __u64,
     pub pidfd: __u64,
@@ -15270,10 +16793,10 @@
     pub u2_sel: __le16,
     pub u2_pel: __le16,
 }
-pub const FUNCTIONFS_DESCRIPTORS_MAGIC: _bindgen_ty_61 = 1;
-pub const FUNCTIONFS_STRINGS_MAGIC: _bindgen_ty_61 = 2;
-pub const FUNCTIONFS_DESCRIPTORS_MAGIC_V2: _bindgen_ty_61 = 3;
-pub type _bindgen_ty_61 = crate::types::c_uint;
+pub const FUNCTIONFS_DESCRIPTORS_MAGIC: _bindgen_ty_126 = 1;
+pub const FUNCTIONFS_STRINGS_MAGIC: _bindgen_ty_126 = 2;
+pub const FUNCTIONFS_DESCRIPTORS_MAGIC_V2: _bindgen_ty_126 = 3;
+pub type _bindgen_ty_126 = crate::types::c_uint;
 pub const functionfs_flags_FUNCTIONFS_HAS_FS_DESC: functionfs_flags = 1;
 pub const functionfs_flags_FUNCTIONFS_HAS_HS_DESC: functionfs_flags = 2;
 pub const functionfs_flags_FUNCTIONFS_HAS_SS_DESC: functionfs_flags = 4;
diff --git a/src/starnix/lib/linux_uapi/src/x86_64.rs b/src/starnix/lib/linux_uapi/src/x86_64.rs
index 39bb7c8..b087947 100644
--- a/src/starnix/lib/linux_uapi/src/x86_64.rs
+++ b/src/starnix/lib/linux_uapi/src/x86_64.rs
@@ -3415,6 +3415,9 @@
 pub const NOTIFY_WOKENUP: u32 = 1;
 pub const NOTIFY_REMOVED: u32 = 2;
 pub const NOTIFY_COOKIE_LEN: u32 = 32;
+pub const AF_UNSPEC: u32 = 0;
+pub const AF_INET: u32 = 2;
+pub const AF_INET6: u32 = 10;
 pub const IFNAMSIZ: u32 = 16;
 pub const IFALIASZ: u32 = 256;
 pub const ALTIFNAMSIZ: u32 = 128;
@@ -4165,6 +4168,144 @@
 pub const RLIMIT_RTTIME: u32 = 15;
 pub const RLIM_NLIMITS: u32 = 16;
 pub const RLIM_INFINITY: i32 = -1;
+pub const MACVLAN_FLAG_NOPROMISC: u32 = 1;
+pub const MACVLAN_FLAG_NODST: u32 = 2;
+pub const IPVLAN_F_PRIVATE: u32 = 1;
+pub const IPVLAN_F_VEPA: u32 = 2;
+pub const TUNNEL_MSG_FLAG_STATS: u32 = 1;
+pub const TUNNEL_MSG_VALID_USER_FLAGS: u32 = 1;
+pub const MAX_VLAN_LIST_LEN: u32 = 1;
+pub const PORT_PROFILE_MAX: u32 = 40;
+pub const PORT_UUID_MAX: u32 = 16;
+pub const PORT_SELF_VF: i32 = -1;
+pub const XDP_FLAGS_UPDATE_IF_NOEXIST: u32 = 1;
+pub const XDP_FLAGS_SKB_MODE: u32 = 2;
+pub const XDP_FLAGS_DRV_MODE: u32 = 4;
+pub const XDP_FLAGS_HW_MODE: u32 = 8;
+pub const XDP_FLAGS_REPLACE: u32 = 16;
+pub const XDP_FLAGS_MODES: u32 = 14;
+pub const XDP_FLAGS_MASK: u32 = 31;
+pub const RMNET_FLAGS_INGRESS_DEAGGREGATION: u32 = 1;
+pub const RMNET_FLAGS_INGRESS_MAP_COMMANDS: u32 = 2;
+pub const RMNET_FLAGS_INGRESS_MAP_CKSUMV4: u32 = 4;
+pub const RMNET_FLAGS_EGRESS_MAP_CKSUMV4: u32 = 8;
+pub const RMNET_FLAGS_INGRESS_MAP_CKSUMV5: u32 = 16;
+pub const RMNET_FLAGS_EGRESS_MAP_CKSUMV5: u32 = 32;
+pub const IFA_F_SECONDARY: u32 = 1;
+pub const IFA_F_TEMPORARY: u32 = 1;
+pub const IFA_F_NODAD: u32 = 2;
+pub const IFA_F_OPTIMISTIC: u32 = 4;
+pub const IFA_F_DADFAILED: u32 = 8;
+pub const IFA_F_HOMEADDRESS: u32 = 16;
+pub const IFA_F_DEPRECATED: u32 = 32;
+pub const IFA_F_TENTATIVE: u32 = 64;
+pub const IFA_F_PERMANENT: u32 = 128;
+pub const IFA_F_MANAGETEMPADDR: u32 = 256;
+pub const IFA_F_NOPREFIXROUTE: u32 = 512;
+pub const IFA_F_MCAUTOJOIN: u32 = 1024;
+pub const IFA_F_STABLE_PRIVACY: u32 = 2048;
+pub const IFAPROT_UNSPEC: u32 = 0;
+pub const IFAPROT_KERNEL_LO: u32 = 1;
+pub const IFAPROT_KERNEL_RA: u32 = 2;
+pub const IFAPROT_KERNEL_LL: u32 = 3;
+pub const NTF_USE: u32 = 1;
+pub const NTF_SELF: u32 = 2;
+pub const NTF_MASTER: u32 = 4;
+pub const NTF_PROXY: u32 = 8;
+pub const NTF_EXT_LEARNED: u32 = 16;
+pub const NTF_OFFLOADED: u32 = 32;
+pub const NTF_STICKY: u32 = 64;
+pub const NTF_ROUTER: u32 = 128;
+pub const NTF_EXT_MANAGED: u32 = 1;
+pub const NTF_EXT_LOCKED: u32 = 2;
+pub const NUD_INCOMPLETE: u32 = 1;
+pub const NUD_REACHABLE: u32 = 2;
+pub const NUD_STALE: u32 = 4;
+pub const NUD_DELAY: u32 = 8;
+pub const NUD_PROBE: u32 = 16;
+pub const NUD_FAILED: u32 = 32;
+pub const NUD_NOARP: u32 = 64;
+pub const NUD_PERMANENT: u32 = 128;
+pub const NUD_NONE: u32 = 0;
+pub const RTNL_FAMILY_IPMR: u32 = 128;
+pub const RTNL_FAMILY_IP6MR: u32 = 129;
+pub const RTNL_FAMILY_MAX: u32 = 129;
+pub const RTA_ALIGNTO: u32 = 4;
+pub const RTPROT_UNSPEC: u32 = 0;
+pub const RTPROT_REDIRECT: u32 = 1;
+pub const RTPROT_KERNEL: u32 = 2;
+pub const RTPROT_BOOT: u32 = 3;
+pub const RTPROT_STATIC: u32 = 4;
+pub const RTPROT_GATED: u32 = 8;
+pub const RTPROT_RA: u32 = 9;
+pub const RTPROT_MRT: u32 = 10;
+pub const RTPROT_ZEBRA: u32 = 11;
+pub const RTPROT_BIRD: u32 = 12;
+pub const RTPROT_DNROUTED: u32 = 13;
+pub const RTPROT_XORP: u32 = 14;
+pub const RTPROT_NTK: u32 = 15;
+pub const RTPROT_DHCP: u32 = 16;
+pub const RTPROT_MROUTED: u32 = 17;
+pub const RTPROT_KEEPALIVED: u32 = 18;
+pub const RTPROT_BABEL: u32 = 42;
+pub const RTPROT_OPENR: u32 = 99;
+pub const RTPROT_BGP: u32 = 186;
+pub const RTPROT_ISIS: u32 = 187;
+pub const RTPROT_OSPF: u32 = 188;
+pub const RTPROT_RIP: u32 = 189;
+pub const RTPROT_EIGRP: u32 = 192;
+pub const RTM_F_NOTIFY: u32 = 256;
+pub const RTM_F_CLONED: u32 = 512;
+pub const RTM_F_EQUALIZE: u32 = 1024;
+pub const RTM_F_PREFIX: u32 = 2048;
+pub const RTM_F_LOOKUP_TABLE: u32 = 4096;
+pub const RTM_F_FIB_MATCH: u32 = 8192;
+pub const RTM_F_OFFLOAD: u32 = 16384;
+pub const RTM_F_TRAP: u32 = 32768;
+pub const RTM_F_OFFLOAD_FAILED: u32 = 536870912;
+pub const RTNH_F_DEAD: u32 = 1;
+pub const RTNH_F_PERVASIVE: u32 = 2;
+pub const RTNH_F_ONLINK: u32 = 4;
+pub const RTNH_F_OFFLOAD: u32 = 8;
+pub const RTNH_F_LINKDOWN: u32 = 16;
+pub const RTNH_F_UNRESOLVED: u32 = 32;
+pub const RTNH_F_TRAP: u32 = 64;
+pub const RTNH_COMPARE_MASK: u32 = 89;
+pub const RTNH_ALIGNTO: u32 = 4;
+pub const RTNETLINK_HAVE_PEERINFO: u32 = 1;
+pub const RTAX_FEATURE_ECN: u32 = 1;
+pub const RTAX_FEATURE_SACK: u32 = 2;
+pub const RTAX_FEATURE_TIMESTAMP: u32 = 4;
+pub const RTAX_FEATURE_ALLFRAG: u32 = 8;
+pub const RTAX_FEATURE_MASK: u32 = 15;
+pub const TCM_IFINDEX_MAGIC_BLOCK: u32 = 4294967295;
+pub const TCA_DUMP_FLAGS_TERSE: u32 = 1;
+pub const RTMGRP_LINK: u32 = 1;
+pub const RTMGRP_NOTIFY: u32 = 2;
+pub const RTMGRP_NEIGH: u32 = 4;
+pub const RTMGRP_TC: u32 = 8;
+pub const RTMGRP_IPV4_IFADDR: u32 = 16;
+pub const RTMGRP_IPV4_MROUTE: u32 = 32;
+pub const RTMGRP_IPV4_ROUTE: u32 = 64;
+pub const RTMGRP_IPV4_RULE: u32 = 128;
+pub const RTMGRP_IPV6_IFADDR: u32 = 256;
+pub const RTMGRP_IPV6_MROUTE: u32 = 512;
+pub const RTMGRP_IPV6_ROUTE: u32 = 1024;
+pub const RTMGRP_IPV6_IFINFO: u32 = 2048;
+pub const RTMGRP_DECnet_IFADDR: u32 = 4096;
+pub const RTMGRP_DECnet_ROUTE: u32 = 16384;
+pub const RTMGRP_IPV6_PREFIX: u32 = 131072;
+pub const TCA_FLAG_LARGE_DUMP_ON: u32 = 1;
+pub const TCA_ACT_FLAG_LARGE_DUMP_ON: u32 = 1;
+pub const TCA_ACT_FLAG_TERSE_DUMP: u32 = 2;
+pub const RTEXT_FILTER_VF: u32 = 1;
+pub const RTEXT_FILTER_BRVLAN: u32 = 2;
+pub const RTEXT_FILTER_BRVLAN_COMPRESSED: u32 = 4;
+pub const RTEXT_FILTER_SKIP_STATS: u32 = 8;
+pub const RTEXT_FILTER_MRP: u32 = 16;
+pub const RTEXT_FILTER_CFM_CONFIG: u32 = 32;
+pub const RTEXT_FILTER_CFM_STATUS: u32 = 64;
+pub const RTEXT_FILTER_MST: u32 = 128;
 pub const CSIGNAL: u32 = 255;
 pub const CLONE_VM: u32 = 256;
 pub const CLONE_FS: u32 = 512;
@@ -14504,6 +14645,1388 @@
 }
 #[repr(C)]
 #[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_stats {
+    pub rx_packets: __u32,
+    pub tx_packets: __u32,
+    pub rx_bytes: __u32,
+    pub tx_bytes: __u32,
+    pub rx_errors: __u32,
+    pub tx_errors: __u32,
+    pub rx_dropped: __u32,
+    pub tx_dropped: __u32,
+    pub multicast: __u32,
+    pub collisions: __u32,
+    pub rx_length_errors: __u32,
+    pub rx_over_errors: __u32,
+    pub rx_crc_errors: __u32,
+    pub rx_frame_errors: __u32,
+    pub rx_fifo_errors: __u32,
+    pub rx_missed_errors: __u32,
+    pub tx_aborted_errors: __u32,
+    pub tx_carrier_errors: __u32,
+    pub tx_fifo_errors: __u32,
+    pub tx_heartbeat_errors: __u32,
+    pub tx_window_errors: __u32,
+    pub rx_compressed: __u32,
+    pub tx_compressed: __u32,
+    pub rx_nohandler: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_stats64 {
+    pub rx_packets: __u64,
+    pub tx_packets: __u64,
+    pub rx_bytes: __u64,
+    pub tx_bytes: __u64,
+    pub rx_errors: __u64,
+    pub tx_errors: __u64,
+    pub rx_dropped: __u64,
+    pub tx_dropped: __u64,
+    pub multicast: __u64,
+    pub collisions: __u64,
+    pub rx_length_errors: __u64,
+    pub rx_over_errors: __u64,
+    pub rx_crc_errors: __u64,
+    pub rx_frame_errors: __u64,
+    pub rx_fifo_errors: __u64,
+    pub rx_missed_errors: __u64,
+    pub tx_aborted_errors: __u64,
+    pub tx_carrier_errors: __u64,
+    pub tx_fifo_errors: __u64,
+    pub tx_heartbeat_errors: __u64,
+    pub tx_window_errors: __u64,
+    pub rx_compressed: __u64,
+    pub tx_compressed: __u64,
+    pub rx_nohandler: __u64,
+    pub rx_otherhost_dropped: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_hw_stats64 {
+    pub rx_packets: __u64,
+    pub tx_packets: __u64,
+    pub rx_bytes: __u64,
+    pub tx_bytes: __u64,
+    pub rx_errors: __u64,
+    pub tx_errors: __u64,
+    pub rx_dropped: __u64,
+    pub tx_dropped: __u64,
+    pub multicast: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnl_link_ifmap {
+    pub mem_start: __u64,
+    pub mem_end: __u64,
+    pub base_addr: __u64,
+    pub irq: __u16,
+    pub dma: __u8,
+    pub port: __u8,
+    pub __bindgen_padding_0: [u8; 4usize],
+}
+pub const IFLA_UNSPEC: _bindgen_ty_61 = 0;
+pub const IFLA_ADDRESS: _bindgen_ty_61 = 1;
+pub const IFLA_BROADCAST: _bindgen_ty_61 = 2;
+pub const IFLA_IFNAME: _bindgen_ty_61 = 3;
+pub const IFLA_MTU: _bindgen_ty_61 = 4;
+pub const IFLA_LINK: _bindgen_ty_61 = 5;
+pub const IFLA_QDISC: _bindgen_ty_61 = 6;
+pub const IFLA_STATS: _bindgen_ty_61 = 7;
+pub const IFLA_COST: _bindgen_ty_61 = 8;
+pub const IFLA_PRIORITY: _bindgen_ty_61 = 9;
+pub const IFLA_MASTER: _bindgen_ty_61 = 10;
+pub const IFLA_WIRELESS: _bindgen_ty_61 = 11;
+pub const IFLA_PROTINFO: _bindgen_ty_61 = 12;
+pub const IFLA_TXQLEN: _bindgen_ty_61 = 13;
+pub const IFLA_MAP: _bindgen_ty_61 = 14;
+pub const IFLA_WEIGHT: _bindgen_ty_61 = 15;
+pub const IFLA_OPERSTATE: _bindgen_ty_61 = 16;
+pub const IFLA_LINKMODE: _bindgen_ty_61 = 17;
+pub const IFLA_LINKINFO: _bindgen_ty_61 = 18;
+pub const IFLA_NET_NS_PID: _bindgen_ty_61 = 19;
+pub const IFLA_IFALIAS: _bindgen_ty_61 = 20;
+pub const IFLA_NUM_VF: _bindgen_ty_61 = 21;
+pub const IFLA_VFINFO_LIST: _bindgen_ty_61 = 22;
+pub const IFLA_STATS64: _bindgen_ty_61 = 23;
+pub const IFLA_VF_PORTS: _bindgen_ty_61 = 24;
+pub const IFLA_PORT_SELF: _bindgen_ty_61 = 25;
+pub const IFLA_AF_SPEC: _bindgen_ty_61 = 26;
+pub const IFLA_GROUP: _bindgen_ty_61 = 27;
+pub const IFLA_NET_NS_FD: _bindgen_ty_61 = 28;
+pub const IFLA_EXT_MASK: _bindgen_ty_61 = 29;
+pub const IFLA_PROMISCUITY: _bindgen_ty_61 = 30;
+pub const IFLA_NUM_TX_QUEUES: _bindgen_ty_61 = 31;
+pub const IFLA_NUM_RX_QUEUES: _bindgen_ty_61 = 32;
+pub const IFLA_CARRIER: _bindgen_ty_61 = 33;
+pub const IFLA_PHYS_PORT_ID: _bindgen_ty_61 = 34;
+pub const IFLA_CARRIER_CHANGES: _bindgen_ty_61 = 35;
+pub const IFLA_PHYS_SWITCH_ID: _bindgen_ty_61 = 36;
+pub const IFLA_LINK_NETNSID: _bindgen_ty_61 = 37;
+pub const IFLA_PHYS_PORT_NAME: _bindgen_ty_61 = 38;
+pub const IFLA_PROTO_DOWN: _bindgen_ty_61 = 39;
+pub const IFLA_GSO_MAX_SEGS: _bindgen_ty_61 = 40;
+pub const IFLA_GSO_MAX_SIZE: _bindgen_ty_61 = 41;
+pub const IFLA_PAD: _bindgen_ty_61 = 42;
+pub const IFLA_XDP: _bindgen_ty_61 = 43;
+pub const IFLA_EVENT: _bindgen_ty_61 = 44;
+pub const IFLA_NEW_NETNSID: _bindgen_ty_61 = 45;
+pub const IFLA_IF_NETNSID: _bindgen_ty_61 = 46;
+pub const IFLA_TARGET_NETNSID: _bindgen_ty_61 = 46;
+pub const IFLA_CARRIER_UP_COUNT: _bindgen_ty_61 = 47;
+pub const IFLA_CARRIER_DOWN_COUNT: _bindgen_ty_61 = 48;
+pub const IFLA_NEW_IFINDEX: _bindgen_ty_61 = 49;
+pub const IFLA_MIN_MTU: _bindgen_ty_61 = 50;
+pub const IFLA_MAX_MTU: _bindgen_ty_61 = 51;
+pub const IFLA_PROP_LIST: _bindgen_ty_61 = 52;
+pub const IFLA_ALT_IFNAME: _bindgen_ty_61 = 53;
+pub const IFLA_PERM_ADDRESS: _bindgen_ty_61 = 54;
+pub const IFLA_PROTO_DOWN_REASON: _bindgen_ty_61 = 55;
+pub const IFLA_PARENT_DEV_NAME: _bindgen_ty_61 = 56;
+pub const IFLA_PARENT_DEV_BUS_NAME: _bindgen_ty_61 = 57;
+pub const IFLA_GRO_MAX_SIZE: _bindgen_ty_61 = 58;
+pub const IFLA_TSO_MAX_SIZE: _bindgen_ty_61 = 59;
+pub const IFLA_TSO_MAX_SEGS: _bindgen_ty_61 = 60;
+pub const IFLA_ALLMULTI: _bindgen_ty_61 = 61;
+pub const IFLA_DEVLINK_PORT: _bindgen_ty_61 = 62;
+pub const IFLA_GSO_IPV4_MAX_SIZE: _bindgen_ty_61 = 63;
+pub const IFLA_GRO_IPV4_MAX_SIZE: _bindgen_ty_61 = 64;
+pub const __IFLA_MAX: _bindgen_ty_61 = 65;
+pub type _bindgen_ty_61 = crate::types::c_uint;
+pub const IFLA_PROTO_DOWN_REASON_UNSPEC: _bindgen_ty_62 = 0;
+pub const IFLA_PROTO_DOWN_REASON_MASK: _bindgen_ty_62 = 1;
+pub const IFLA_PROTO_DOWN_REASON_VALUE: _bindgen_ty_62 = 2;
+pub const __IFLA_PROTO_DOWN_REASON_CNT: _bindgen_ty_62 = 3;
+pub const IFLA_PROTO_DOWN_REASON_MAX: _bindgen_ty_62 = 2;
+pub type _bindgen_ty_62 = crate::types::c_uint;
+pub const IFLA_INET_UNSPEC: _bindgen_ty_63 = 0;
+pub const IFLA_INET_CONF: _bindgen_ty_63 = 1;
+pub const __IFLA_INET_MAX: _bindgen_ty_63 = 2;
+pub type _bindgen_ty_63 = crate::types::c_uint;
+pub const IFLA_INET6_UNSPEC: _bindgen_ty_64 = 0;
+pub const IFLA_INET6_FLAGS: _bindgen_ty_64 = 1;
+pub const IFLA_INET6_CONF: _bindgen_ty_64 = 2;
+pub const IFLA_INET6_STATS: _bindgen_ty_64 = 3;
+pub const IFLA_INET6_MCAST: _bindgen_ty_64 = 4;
+pub const IFLA_INET6_CACHEINFO: _bindgen_ty_64 = 5;
+pub const IFLA_INET6_ICMP6STATS: _bindgen_ty_64 = 6;
+pub const IFLA_INET6_TOKEN: _bindgen_ty_64 = 7;
+pub const IFLA_INET6_ADDR_GEN_MODE: _bindgen_ty_64 = 8;
+pub const IFLA_INET6_RA_MTU: _bindgen_ty_64 = 9;
+pub const __IFLA_INET6_MAX: _bindgen_ty_64 = 10;
+pub type _bindgen_ty_64 = crate::types::c_uint;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_EUI64: in6_addr_gen_mode = 0;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_NONE: in6_addr_gen_mode = 1;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_STABLE_PRIVACY: in6_addr_gen_mode = 2;
+pub const in6_addr_gen_mode_IN6_ADDR_GEN_MODE_RANDOM: in6_addr_gen_mode = 3;
+pub type in6_addr_gen_mode = crate::types::c_uint;
+pub const IFLA_BR_UNSPEC: _bindgen_ty_65 = 0;
+pub const IFLA_BR_FORWARD_DELAY: _bindgen_ty_65 = 1;
+pub const IFLA_BR_HELLO_TIME: _bindgen_ty_65 = 2;
+pub const IFLA_BR_MAX_AGE: _bindgen_ty_65 = 3;
+pub const IFLA_BR_AGEING_TIME: _bindgen_ty_65 = 4;
+pub const IFLA_BR_STP_STATE: _bindgen_ty_65 = 5;
+pub const IFLA_BR_PRIORITY: _bindgen_ty_65 = 6;
+pub const IFLA_BR_VLAN_FILTERING: _bindgen_ty_65 = 7;
+pub const IFLA_BR_VLAN_PROTOCOL: _bindgen_ty_65 = 8;
+pub const IFLA_BR_GROUP_FWD_MASK: _bindgen_ty_65 = 9;
+pub const IFLA_BR_ROOT_ID: _bindgen_ty_65 = 10;
+pub const IFLA_BR_BRIDGE_ID: _bindgen_ty_65 = 11;
+pub const IFLA_BR_ROOT_PORT: _bindgen_ty_65 = 12;
+pub const IFLA_BR_ROOT_PATH_COST: _bindgen_ty_65 = 13;
+pub const IFLA_BR_TOPOLOGY_CHANGE: _bindgen_ty_65 = 14;
+pub const IFLA_BR_TOPOLOGY_CHANGE_DETECTED: _bindgen_ty_65 = 15;
+pub const IFLA_BR_HELLO_TIMER: _bindgen_ty_65 = 16;
+pub const IFLA_BR_TCN_TIMER: _bindgen_ty_65 = 17;
+pub const IFLA_BR_TOPOLOGY_CHANGE_TIMER: _bindgen_ty_65 = 18;
+pub const IFLA_BR_GC_TIMER: _bindgen_ty_65 = 19;
+pub const IFLA_BR_GROUP_ADDR: _bindgen_ty_65 = 20;
+pub const IFLA_BR_FDB_FLUSH: _bindgen_ty_65 = 21;
+pub const IFLA_BR_MCAST_ROUTER: _bindgen_ty_65 = 22;
+pub const IFLA_BR_MCAST_SNOOPING: _bindgen_ty_65 = 23;
+pub const IFLA_BR_MCAST_QUERY_USE_IFADDR: _bindgen_ty_65 = 24;
+pub const IFLA_BR_MCAST_QUERIER: _bindgen_ty_65 = 25;
+pub const IFLA_BR_MCAST_HASH_ELASTICITY: _bindgen_ty_65 = 26;
+pub const IFLA_BR_MCAST_HASH_MAX: _bindgen_ty_65 = 27;
+pub const IFLA_BR_MCAST_LAST_MEMBER_CNT: _bindgen_ty_65 = 28;
+pub const IFLA_BR_MCAST_STARTUP_QUERY_CNT: _bindgen_ty_65 = 29;
+pub const IFLA_BR_MCAST_LAST_MEMBER_INTVL: _bindgen_ty_65 = 30;
+pub const IFLA_BR_MCAST_MEMBERSHIP_INTVL: _bindgen_ty_65 = 31;
+pub const IFLA_BR_MCAST_QUERIER_INTVL: _bindgen_ty_65 = 32;
+pub const IFLA_BR_MCAST_QUERY_INTVL: _bindgen_ty_65 = 33;
+pub const IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: _bindgen_ty_65 = 34;
+pub const IFLA_BR_MCAST_STARTUP_QUERY_INTVL: _bindgen_ty_65 = 35;
+pub const IFLA_BR_NF_CALL_IPTABLES: _bindgen_ty_65 = 36;
+pub const IFLA_BR_NF_CALL_IP6TABLES: _bindgen_ty_65 = 37;
+pub const IFLA_BR_NF_CALL_ARPTABLES: _bindgen_ty_65 = 38;
+pub const IFLA_BR_VLAN_DEFAULT_PVID: _bindgen_ty_65 = 39;
+pub const IFLA_BR_PAD: _bindgen_ty_65 = 40;
+pub const IFLA_BR_VLAN_STATS_ENABLED: _bindgen_ty_65 = 41;
+pub const IFLA_BR_MCAST_STATS_ENABLED: _bindgen_ty_65 = 42;
+pub const IFLA_BR_MCAST_IGMP_VERSION: _bindgen_ty_65 = 43;
+pub const IFLA_BR_MCAST_MLD_VERSION: _bindgen_ty_65 = 44;
+pub const IFLA_BR_VLAN_STATS_PER_PORT: _bindgen_ty_65 = 45;
+pub const IFLA_BR_MULTI_BOOLOPT: _bindgen_ty_65 = 46;
+pub const IFLA_BR_MCAST_QUERIER_STATE: _bindgen_ty_65 = 47;
+pub const __IFLA_BR_MAX: _bindgen_ty_65 = 48;
+pub type _bindgen_ty_65 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_bridge_id {
+    pub prio: [__u8; 2usize],
+    pub addr: [__u8; 6usize],
+}
+pub const BRIDGE_MODE_UNSPEC: _bindgen_ty_66 = 0;
+pub const BRIDGE_MODE_HAIRPIN: _bindgen_ty_66 = 1;
+pub type _bindgen_ty_66 = crate::types::c_uint;
+pub const IFLA_BRPORT_UNSPEC: _bindgen_ty_67 = 0;
+pub const IFLA_BRPORT_STATE: _bindgen_ty_67 = 1;
+pub const IFLA_BRPORT_PRIORITY: _bindgen_ty_67 = 2;
+pub const IFLA_BRPORT_COST: _bindgen_ty_67 = 3;
+pub const IFLA_BRPORT_MODE: _bindgen_ty_67 = 4;
+pub const IFLA_BRPORT_GUARD: _bindgen_ty_67 = 5;
+pub const IFLA_BRPORT_PROTECT: _bindgen_ty_67 = 6;
+pub const IFLA_BRPORT_FAST_LEAVE: _bindgen_ty_67 = 7;
+pub const IFLA_BRPORT_LEARNING: _bindgen_ty_67 = 8;
+pub const IFLA_BRPORT_UNICAST_FLOOD: _bindgen_ty_67 = 9;
+pub const IFLA_BRPORT_PROXYARP: _bindgen_ty_67 = 10;
+pub const IFLA_BRPORT_LEARNING_SYNC: _bindgen_ty_67 = 11;
+pub const IFLA_BRPORT_PROXYARP_WIFI: _bindgen_ty_67 = 12;
+pub const IFLA_BRPORT_ROOT_ID: _bindgen_ty_67 = 13;
+pub const IFLA_BRPORT_BRIDGE_ID: _bindgen_ty_67 = 14;
+pub const IFLA_BRPORT_DESIGNATED_PORT: _bindgen_ty_67 = 15;
+pub const IFLA_BRPORT_DESIGNATED_COST: _bindgen_ty_67 = 16;
+pub const IFLA_BRPORT_ID: _bindgen_ty_67 = 17;
+pub const IFLA_BRPORT_NO: _bindgen_ty_67 = 18;
+pub const IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: _bindgen_ty_67 = 19;
+pub const IFLA_BRPORT_CONFIG_PENDING: _bindgen_ty_67 = 20;
+pub const IFLA_BRPORT_MESSAGE_AGE_TIMER: _bindgen_ty_67 = 21;
+pub const IFLA_BRPORT_FORWARD_DELAY_TIMER: _bindgen_ty_67 = 22;
+pub const IFLA_BRPORT_HOLD_TIMER: _bindgen_ty_67 = 23;
+pub const IFLA_BRPORT_FLUSH: _bindgen_ty_67 = 24;
+pub const IFLA_BRPORT_MULTICAST_ROUTER: _bindgen_ty_67 = 25;
+pub const IFLA_BRPORT_PAD: _bindgen_ty_67 = 26;
+pub const IFLA_BRPORT_MCAST_FLOOD: _bindgen_ty_67 = 27;
+pub const IFLA_BRPORT_MCAST_TO_UCAST: _bindgen_ty_67 = 28;
+pub const IFLA_BRPORT_VLAN_TUNNEL: _bindgen_ty_67 = 29;
+pub const IFLA_BRPORT_BCAST_FLOOD: _bindgen_ty_67 = 30;
+pub const IFLA_BRPORT_GROUP_FWD_MASK: _bindgen_ty_67 = 31;
+pub const IFLA_BRPORT_NEIGH_SUPPRESS: _bindgen_ty_67 = 32;
+pub const IFLA_BRPORT_ISOLATED: _bindgen_ty_67 = 33;
+pub const IFLA_BRPORT_BACKUP_PORT: _bindgen_ty_67 = 34;
+pub const IFLA_BRPORT_MRP_RING_OPEN: _bindgen_ty_67 = 35;
+pub const IFLA_BRPORT_MRP_IN_OPEN: _bindgen_ty_67 = 36;
+pub const IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT: _bindgen_ty_67 = 37;
+pub const IFLA_BRPORT_MCAST_EHT_HOSTS_CNT: _bindgen_ty_67 = 38;
+pub const IFLA_BRPORT_LOCKED: _bindgen_ty_67 = 39;
+pub const IFLA_BRPORT_MAB: _bindgen_ty_67 = 40;
+pub const IFLA_BRPORT_MCAST_N_GROUPS: _bindgen_ty_67 = 41;
+pub const IFLA_BRPORT_MCAST_MAX_GROUPS: _bindgen_ty_67 = 42;
+pub const IFLA_BRPORT_NEIGH_VLAN_SUPPRESS: _bindgen_ty_67 = 43;
+pub const __IFLA_BRPORT_MAX: _bindgen_ty_67 = 44;
+pub type _bindgen_ty_67 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_cacheinfo {
+    pub max_reasm_len: __u32,
+    pub tstamp: __u32,
+    pub reachable_time: __u32,
+    pub retrans_time: __u32,
+}
+pub const IFLA_INFO_UNSPEC: _bindgen_ty_68 = 0;
+pub const IFLA_INFO_KIND: _bindgen_ty_68 = 1;
+pub const IFLA_INFO_DATA: _bindgen_ty_68 = 2;
+pub const IFLA_INFO_XSTATS: _bindgen_ty_68 = 3;
+pub const IFLA_INFO_SLAVE_KIND: _bindgen_ty_68 = 4;
+pub const IFLA_INFO_SLAVE_DATA: _bindgen_ty_68 = 5;
+pub const __IFLA_INFO_MAX: _bindgen_ty_68 = 6;
+pub type _bindgen_ty_68 = crate::types::c_uint;
+pub const IFLA_VLAN_UNSPEC: _bindgen_ty_69 = 0;
+pub const IFLA_VLAN_ID: _bindgen_ty_69 = 1;
+pub const IFLA_VLAN_FLAGS: _bindgen_ty_69 = 2;
+pub const IFLA_VLAN_EGRESS_QOS: _bindgen_ty_69 = 3;
+pub const IFLA_VLAN_INGRESS_QOS: _bindgen_ty_69 = 4;
+pub const IFLA_VLAN_PROTOCOL: _bindgen_ty_69 = 5;
+pub const __IFLA_VLAN_MAX: _bindgen_ty_69 = 6;
+pub type _bindgen_ty_69 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vlan_flags {
+    pub flags: __u32,
+    pub mask: __u32,
+}
+pub const IFLA_VLAN_QOS_UNSPEC: _bindgen_ty_70 = 0;
+pub const IFLA_VLAN_QOS_MAPPING: _bindgen_ty_70 = 1;
+pub const __IFLA_VLAN_QOS_MAX: _bindgen_ty_70 = 2;
+pub type _bindgen_ty_70 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vlan_qos_mapping {
+    pub from: __u32,
+    pub to: __u32,
+}
+pub const IFLA_MACVLAN_UNSPEC: _bindgen_ty_71 = 0;
+pub const IFLA_MACVLAN_MODE: _bindgen_ty_71 = 1;
+pub const IFLA_MACVLAN_FLAGS: _bindgen_ty_71 = 2;
+pub const IFLA_MACVLAN_MACADDR_MODE: _bindgen_ty_71 = 3;
+pub const IFLA_MACVLAN_MACADDR: _bindgen_ty_71 = 4;
+pub const IFLA_MACVLAN_MACADDR_DATA: _bindgen_ty_71 = 5;
+pub const IFLA_MACVLAN_MACADDR_COUNT: _bindgen_ty_71 = 6;
+pub const IFLA_MACVLAN_BC_QUEUE_LEN: _bindgen_ty_71 = 7;
+pub const IFLA_MACVLAN_BC_QUEUE_LEN_USED: _bindgen_ty_71 = 8;
+pub const IFLA_MACVLAN_BC_CUTOFF: _bindgen_ty_71 = 9;
+pub const __IFLA_MACVLAN_MAX: _bindgen_ty_71 = 10;
+pub type _bindgen_ty_71 = crate::types::c_uint;
+pub const macvlan_mode_MACVLAN_MODE_PRIVATE: macvlan_mode = 1;
+pub const macvlan_mode_MACVLAN_MODE_VEPA: macvlan_mode = 2;
+pub const macvlan_mode_MACVLAN_MODE_BRIDGE: macvlan_mode = 4;
+pub const macvlan_mode_MACVLAN_MODE_PASSTHRU: macvlan_mode = 8;
+pub const macvlan_mode_MACVLAN_MODE_SOURCE: macvlan_mode = 16;
+pub type macvlan_mode = crate::types::c_uint;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_ADD: macvlan_macaddr_mode = 0;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_DEL: macvlan_macaddr_mode = 1;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_FLUSH: macvlan_macaddr_mode = 2;
+pub const macvlan_macaddr_mode_MACVLAN_MACADDR_SET: macvlan_macaddr_mode = 3;
+pub type macvlan_macaddr_mode = crate::types::c_uint;
+pub const IFLA_VRF_UNSPEC: _bindgen_ty_72 = 0;
+pub const IFLA_VRF_TABLE: _bindgen_ty_72 = 1;
+pub const __IFLA_VRF_MAX: _bindgen_ty_72 = 2;
+pub type _bindgen_ty_72 = crate::types::c_uint;
+pub const IFLA_VRF_PORT_UNSPEC: _bindgen_ty_73 = 0;
+pub const IFLA_VRF_PORT_TABLE: _bindgen_ty_73 = 1;
+pub const __IFLA_VRF_PORT_MAX: _bindgen_ty_73 = 2;
+pub type _bindgen_ty_73 = crate::types::c_uint;
+pub const IFLA_MACSEC_UNSPEC: _bindgen_ty_74 = 0;
+pub const IFLA_MACSEC_SCI: _bindgen_ty_74 = 1;
+pub const IFLA_MACSEC_PORT: _bindgen_ty_74 = 2;
+pub const IFLA_MACSEC_ICV_LEN: _bindgen_ty_74 = 3;
+pub const IFLA_MACSEC_CIPHER_SUITE: _bindgen_ty_74 = 4;
+pub const IFLA_MACSEC_WINDOW: _bindgen_ty_74 = 5;
+pub const IFLA_MACSEC_ENCODING_SA: _bindgen_ty_74 = 6;
+pub const IFLA_MACSEC_ENCRYPT: _bindgen_ty_74 = 7;
+pub const IFLA_MACSEC_PROTECT: _bindgen_ty_74 = 8;
+pub const IFLA_MACSEC_INC_SCI: _bindgen_ty_74 = 9;
+pub const IFLA_MACSEC_ES: _bindgen_ty_74 = 10;
+pub const IFLA_MACSEC_SCB: _bindgen_ty_74 = 11;
+pub const IFLA_MACSEC_REPLAY_PROTECT: _bindgen_ty_74 = 12;
+pub const IFLA_MACSEC_VALIDATION: _bindgen_ty_74 = 13;
+pub const IFLA_MACSEC_PAD: _bindgen_ty_74 = 14;
+pub const IFLA_MACSEC_OFFLOAD: _bindgen_ty_74 = 15;
+pub const __IFLA_MACSEC_MAX: _bindgen_ty_74 = 16;
+pub type _bindgen_ty_74 = crate::types::c_uint;
+pub const IFLA_XFRM_UNSPEC: _bindgen_ty_75 = 0;
+pub const IFLA_XFRM_LINK: _bindgen_ty_75 = 1;
+pub const IFLA_XFRM_IF_ID: _bindgen_ty_75 = 2;
+pub const IFLA_XFRM_COLLECT_METADATA: _bindgen_ty_75 = 3;
+pub const __IFLA_XFRM_MAX: _bindgen_ty_75 = 4;
+pub type _bindgen_ty_75 = crate::types::c_uint;
+pub const macsec_validation_type_MACSEC_VALIDATE_DISABLED: macsec_validation_type = 0;
+pub const macsec_validation_type_MACSEC_VALIDATE_CHECK: macsec_validation_type = 1;
+pub const macsec_validation_type_MACSEC_VALIDATE_STRICT: macsec_validation_type = 2;
+pub const macsec_validation_type___MACSEC_VALIDATE_END: macsec_validation_type = 3;
+pub const macsec_validation_type_MACSEC_VALIDATE_MAX: macsec_validation_type = 2;
+pub type macsec_validation_type = crate::types::c_uint;
+pub const macsec_offload_MACSEC_OFFLOAD_OFF: macsec_offload = 0;
+pub const macsec_offload_MACSEC_OFFLOAD_PHY: macsec_offload = 1;
+pub const macsec_offload_MACSEC_OFFLOAD_MAC: macsec_offload = 2;
+pub const macsec_offload___MACSEC_OFFLOAD_END: macsec_offload = 3;
+pub const macsec_offload_MACSEC_OFFLOAD_MAX: macsec_offload = 2;
+pub type macsec_offload = crate::types::c_uint;
+pub const IFLA_IPVLAN_UNSPEC: _bindgen_ty_76 = 0;
+pub const IFLA_IPVLAN_MODE: _bindgen_ty_76 = 1;
+pub const IFLA_IPVLAN_FLAGS: _bindgen_ty_76 = 2;
+pub const __IFLA_IPVLAN_MAX: _bindgen_ty_76 = 3;
+pub type _bindgen_ty_76 = crate::types::c_uint;
+pub const ipvlan_mode_IPVLAN_MODE_L2: ipvlan_mode = 0;
+pub const ipvlan_mode_IPVLAN_MODE_L3: ipvlan_mode = 1;
+pub const ipvlan_mode_IPVLAN_MODE_L3S: ipvlan_mode = 2;
+pub const ipvlan_mode_IPVLAN_MODE_MAX: ipvlan_mode = 3;
+pub type ipvlan_mode = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tunnel_msg {
+    pub family: __u8,
+    pub flags: __u8,
+    pub reserved2: __u16,
+    pub ifindex: __u32,
+}
+pub const VNIFILTER_ENTRY_STATS_UNSPEC: _bindgen_ty_77 = 0;
+pub const VNIFILTER_ENTRY_STATS_RX_BYTES: _bindgen_ty_77 = 1;
+pub const VNIFILTER_ENTRY_STATS_RX_PKTS: _bindgen_ty_77 = 2;
+pub const VNIFILTER_ENTRY_STATS_RX_DROPS: _bindgen_ty_77 = 3;
+pub const VNIFILTER_ENTRY_STATS_RX_ERRORS: _bindgen_ty_77 = 4;
+pub const VNIFILTER_ENTRY_STATS_TX_BYTES: _bindgen_ty_77 = 5;
+pub const VNIFILTER_ENTRY_STATS_TX_PKTS: _bindgen_ty_77 = 6;
+pub const VNIFILTER_ENTRY_STATS_TX_DROPS: _bindgen_ty_77 = 7;
+pub const VNIFILTER_ENTRY_STATS_TX_ERRORS: _bindgen_ty_77 = 8;
+pub const VNIFILTER_ENTRY_STATS_PAD: _bindgen_ty_77 = 9;
+pub const __VNIFILTER_ENTRY_STATS_MAX: _bindgen_ty_77 = 10;
+pub type _bindgen_ty_77 = crate::types::c_uint;
+pub const VXLAN_VNIFILTER_ENTRY_UNSPEC: _bindgen_ty_78 = 0;
+pub const VXLAN_VNIFILTER_ENTRY_START: _bindgen_ty_78 = 1;
+pub const VXLAN_VNIFILTER_ENTRY_END: _bindgen_ty_78 = 2;
+pub const VXLAN_VNIFILTER_ENTRY_GROUP: _bindgen_ty_78 = 3;
+pub const VXLAN_VNIFILTER_ENTRY_GROUP6: _bindgen_ty_78 = 4;
+pub const VXLAN_VNIFILTER_ENTRY_STATS: _bindgen_ty_78 = 5;
+pub const __VXLAN_VNIFILTER_ENTRY_MAX: _bindgen_ty_78 = 6;
+pub type _bindgen_ty_78 = crate::types::c_uint;
+pub const VXLAN_VNIFILTER_UNSPEC: _bindgen_ty_79 = 0;
+pub const VXLAN_VNIFILTER_ENTRY: _bindgen_ty_79 = 1;
+pub const __VXLAN_VNIFILTER_MAX: _bindgen_ty_79 = 2;
+pub type _bindgen_ty_79 = crate::types::c_uint;
+pub const IFLA_VXLAN_UNSPEC: _bindgen_ty_80 = 0;
+pub const IFLA_VXLAN_ID: _bindgen_ty_80 = 1;
+pub const IFLA_VXLAN_GROUP: _bindgen_ty_80 = 2;
+pub const IFLA_VXLAN_LINK: _bindgen_ty_80 = 3;
+pub const IFLA_VXLAN_LOCAL: _bindgen_ty_80 = 4;
+pub const IFLA_VXLAN_TTL: _bindgen_ty_80 = 5;
+pub const IFLA_VXLAN_TOS: _bindgen_ty_80 = 6;
+pub const IFLA_VXLAN_LEARNING: _bindgen_ty_80 = 7;
+pub const IFLA_VXLAN_AGEING: _bindgen_ty_80 = 8;
+pub const IFLA_VXLAN_LIMIT: _bindgen_ty_80 = 9;
+pub const IFLA_VXLAN_PORT_RANGE: _bindgen_ty_80 = 10;
+pub const IFLA_VXLAN_PROXY: _bindgen_ty_80 = 11;
+pub const IFLA_VXLAN_RSC: _bindgen_ty_80 = 12;
+pub const IFLA_VXLAN_L2MISS: _bindgen_ty_80 = 13;
+pub const IFLA_VXLAN_L3MISS: _bindgen_ty_80 = 14;
+pub const IFLA_VXLAN_PORT: _bindgen_ty_80 = 15;
+pub const IFLA_VXLAN_GROUP6: _bindgen_ty_80 = 16;
+pub const IFLA_VXLAN_LOCAL6: _bindgen_ty_80 = 17;
+pub const IFLA_VXLAN_UDP_CSUM: _bindgen_ty_80 = 18;
+pub const IFLA_VXLAN_UDP_ZERO_CSUM6_TX: _bindgen_ty_80 = 19;
+pub const IFLA_VXLAN_UDP_ZERO_CSUM6_RX: _bindgen_ty_80 = 20;
+pub const IFLA_VXLAN_REMCSUM_TX: _bindgen_ty_80 = 21;
+pub const IFLA_VXLAN_REMCSUM_RX: _bindgen_ty_80 = 22;
+pub const IFLA_VXLAN_GBP: _bindgen_ty_80 = 23;
+pub const IFLA_VXLAN_REMCSUM_NOPARTIAL: _bindgen_ty_80 = 24;
+pub const IFLA_VXLAN_COLLECT_METADATA: _bindgen_ty_80 = 25;
+pub const IFLA_VXLAN_LABEL: _bindgen_ty_80 = 26;
+pub const IFLA_VXLAN_GPE: _bindgen_ty_80 = 27;
+pub const IFLA_VXLAN_TTL_INHERIT: _bindgen_ty_80 = 28;
+pub const IFLA_VXLAN_DF: _bindgen_ty_80 = 29;
+pub const IFLA_VXLAN_VNIFILTER: _bindgen_ty_80 = 30;
+pub const IFLA_VXLAN_LOCALBYPASS: _bindgen_ty_80 = 31;
+pub const __IFLA_VXLAN_MAX: _bindgen_ty_80 = 32;
+pub type _bindgen_ty_80 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vxlan_port_range {
+    pub low: __be16,
+    pub high: __be16,
+}
+pub const ifla_vxlan_df_VXLAN_DF_UNSET: ifla_vxlan_df = 0;
+pub const ifla_vxlan_df_VXLAN_DF_SET: ifla_vxlan_df = 1;
+pub const ifla_vxlan_df_VXLAN_DF_INHERIT: ifla_vxlan_df = 2;
+pub const ifla_vxlan_df___VXLAN_DF_END: ifla_vxlan_df = 3;
+pub const ifla_vxlan_df_VXLAN_DF_MAX: ifla_vxlan_df = 2;
+pub type ifla_vxlan_df = crate::types::c_uint;
+pub const IFLA_GENEVE_UNSPEC: _bindgen_ty_81 = 0;
+pub const IFLA_GENEVE_ID: _bindgen_ty_81 = 1;
+pub const IFLA_GENEVE_REMOTE: _bindgen_ty_81 = 2;
+pub const IFLA_GENEVE_TTL: _bindgen_ty_81 = 3;
+pub const IFLA_GENEVE_TOS: _bindgen_ty_81 = 4;
+pub const IFLA_GENEVE_PORT: _bindgen_ty_81 = 5;
+pub const IFLA_GENEVE_COLLECT_METADATA: _bindgen_ty_81 = 6;
+pub const IFLA_GENEVE_REMOTE6: _bindgen_ty_81 = 7;
+pub const IFLA_GENEVE_UDP_CSUM: _bindgen_ty_81 = 8;
+pub const IFLA_GENEVE_UDP_ZERO_CSUM6_TX: _bindgen_ty_81 = 9;
+pub const IFLA_GENEVE_UDP_ZERO_CSUM6_RX: _bindgen_ty_81 = 10;
+pub const IFLA_GENEVE_LABEL: _bindgen_ty_81 = 11;
+pub const IFLA_GENEVE_TTL_INHERIT: _bindgen_ty_81 = 12;
+pub const IFLA_GENEVE_DF: _bindgen_ty_81 = 13;
+pub const IFLA_GENEVE_INNER_PROTO_INHERIT: _bindgen_ty_81 = 14;
+pub const __IFLA_GENEVE_MAX: _bindgen_ty_81 = 15;
+pub type _bindgen_ty_81 = crate::types::c_uint;
+pub const ifla_geneve_df_GENEVE_DF_UNSET: ifla_geneve_df = 0;
+pub const ifla_geneve_df_GENEVE_DF_SET: ifla_geneve_df = 1;
+pub const ifla_geneve_df_GENEVE_DF_INHERIT: ifla_geneve_df = 2;
+pub const ifla_geneve_df___GENEVE_DF_END: ifla_geneve_df = 3;
+pub const ifla_geneve_df_GENEVE_DF_MAX: ifla_geneve_df = 2;
+pub type ifla_geneve_df = crate::types::c_uint;
+pub const IFLA_BAREUDP_UNSPEC: _bindgen_ty_82 = 0;
+pub const IFLA_BAREUDP_PORT: _bindgen_ty_82 = 1;
+pub const IFLA_BAREUDP_ETHERTYPE: _bindgen_ty_82 = 2;
+pub const IFLA_BAREUDP_SRCPORT_MIN: _bindgen_ty_82 = 3;
+pub const IFLA_BAREUDP_MULTIPROTO_MODE: _bindgen_ty_82 = 4;
+pub const __IFLA_BAREUDP_MAX: _bindgen_ty_82 = 5;
+pub type _bindgen_ty_82 = crate::types::c_uint;
+pub const IFLA_PPP_UNSPEC: _bindgen_ty_83 = 0;
+pub const IFLA_PPP_DEV_FD: _bindgen_ty_83 = 1;
+pub const __IFLA_PPP_MAX: _bindgen_ty_83 = 2;
+pub type _bindgen_ty_83 = crate::types::c_uint;
+pub const ifla_gtp_role_GTP_ROLE_GGSN: ifla_gtp_role = 0;
+pub const ifla_gtp_role_GTP_ROLE_SGSN: ifla_gtp_role = 1;
+pub type ifla_gtp_role = crate::types::c_uint;
+pub const IFLA_GTP_UNSPEC: _bindgen_ty_84 = 0;
+pub const IFLA_GTP_FD0: _bindgen_ty_84 = 1;
+pub const IFLA_GTP_FD1: _bindgen_ty_84 = 2;
+pub const IFLA_GTP_PDP_HASHSIZE: _bindgen_ty_84 = 3;
+pub const IFLA_GTP_ROLE: _bindgen_ty_84 = 4;
+pub const IFLA_GTP_CREATE_SOCKETS: _bindgen_ty_84 = 5;
+pub const IFLA_GTP_RESTART_COUNT: _bindgen_ty_84 = 6;
+pub const __IFLA_GTP_MAX: _bindgen_ty_84 = 7;
+pub type _bindgen_ty_84 = crate::types::c_uint;
+pub const IFLA_BOND_UNSPEC: _bindgen_ty_85 = 0;
+pub const IFLA_BOND_MODE: _bindgen_ty_85 = 1;
+pub const IFLA_BOND_ACTIVE_SLAVE: _bindgen_ty_85 = 2;
+pub const IFLA_BOND_MIIMON: _bindgen_ty_85 = 3;
+pub const IFLA_BOND_UPDELAY: _bindgen_ty_85 = 4;
+pub const IFLA_BOND_DOWNDELAY: _bindgen_ty_85 = 5;
+pub const IFLA_BOND_USE_CARRIER: _bindgen_ty_85 = 6;
+pub const IFLA_BOND_ARP_INTERVAL: _bindgen_ty_85 = 7;
+pub const IFLA_BOND_ARP_IP_TARGET: _bindgen_ty_85 = 8;
+pub const IFLA_BOND_ARP_VALIDATE: _bindgen_ty_85 = 9;
+pub const IFLA_BOND_ARP_ALL_TARGETS: _bindgen_ty_85 = 10;
+pub const IFLA_BOND_PRIMARY: _bindgen_ty_85 = 11;
+pub const IFLA_BOND_PRIMARY_RESELECT: _bindgen_ty_85 = 12;
+pub const IFLA_BOND_FAIL_OVER_MAC: _bindgen_ty_85 = 13;
+pub const IFLA_BOND_XMIT_HASH_POLICY: _bindgen_ty_85 = 14;
+pub const IFLA_BOND_RESEND_IGMP: _bindgen_ty_85 = 15;
+pub const IFLA_BOND_NUM_PEER_NOTIF: _bindgen_ty_85 = 16;
+pub const IFLA_BOND_ALL_SLAVES_ACTIVE: _bindgen_ty_85 = 17;
+pub const IFLA_BOND_MIN_LINKS: _bindgen_ty_85 = 18;
+pub const IFLA_BOND_LP_INTERVAL: _bindgen_ty_85 = 19;
+pub const IFLA_BOND_PACKETS_PER_SLAVE: _bindgen_ty_85 = 20;
+pub const IFLA_BOND_AD_LACP_RATE: _bindgen_ty_85 = 21;
+pub const IFLA_BOND_AD_SELECT: _bindgen_ty_85 = 22;
+pub const IFLA_BOND_AD_INFO: _bindgen_ty_85 = 23;
+pub const IFLA_BOND_AD_ACTOR_SYS_PRIO: _bindgen_ty_85 = 24;
+pub const IFLA_BOND_AD_USER_PORT_KEY: _bindgen_ty_85 = 25;
+pub const IFLA_BOND_AD_ACTOR_SYSTEM: _bindgen_ty_85 = 26;
+pub const IFLA_BOND_TLB_DYNAMIC_LB: _bindgen_ty_85 = 27;
+pub const IFLA_BOND_PEER_NOTIF_DELAY: _bindgen_ty_85 = 28;
+pub const IFLA_BOND_AD_LACP_ACTIVE: _bindgen_ty_85 = 29;
+pub const IFLA_BOND_MISSED_MAX: _bindgen_ty_85 = 30;
+pub const IFLA_BOND_NS_IP6_TARGET: _bindgen_ty_85 = 31;
+pub const __IFLA_BOND_MAX: _bindgen_ty_85 = 32;
+pub type _bindgen_ty_85 = crate::types::c_uint;
+pub const IFLA_BOND_AD_INFO_UNSPEC: _bindgen_ty_86 = 0;
+pub const IFLA_BOND_AD_INFO_AGGREGATOR: _bindgen_ty_86 = 1;
+pub const IFLA_BOND_AD_INFO_NUM_PORTS: _bindgen_ty_86 = 2;
+pub const IFLA_BOND_AD_INFO_ACTOR_KEY: _bindgen_ty_86 = 3;
+pub const IFLA_BOND_AD_INFO_PARTNER_KEY: _bindgen_ty_86 = 4;
+pub const IFLA_BOND_AD_INFO_PARTNER_MAC: _bindgen_ty_86 = 5;
+pub const __IFLA_BOND_AD_INFO_MAX: _bindgen_ty_86 = 6;
+pub type _bindgen_ty_86 = crate::types::c_uint;
+pub const IFLA_BOND_SLAVE_UNSPEC: _bindgen_ty_87 = 0;
+pub const IFLA_BOND_SLAVE_STATE: _bindgen_ty_87 = 1;
+pub const IFLA_BOND_SLAVE_MII_STATUS: _bindgen_ty_87 = 2;
+pub const IFLA_BOND_SLAVE_LINK_FAILURE_COUNT: _bindgen_ty_87 = 3;
+pub const IFLA_BOND_SLAVE_PERM_HWADDR: _bindgen_ty_87 = 4;
+pub const IFLA_BOND_SLAVE_QUEUE_ID: _bindgen_ty_87 = 5;
+pub const IFLA_BOND_SLAVE_AD_AGGREGATOR_ID: _bindgen_ty_87 = 6;
+pub const IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE: _bindgen_ty_87 = 7;
+pub const IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE: _bindgen_ty_87 = 8;
+pub const IFLA_BOND_SLAVE_PRIO: _bindgen_ty_87 = 9;
+pub const __IFLA_BOND_SLAVE_MAX: _bindgen_ty_87 = 10;
+pub type _bindgen_ty_87 = crate::types::c_uint;
+pub const IFLA_VF_INFO_UNSPEC: _bindgen_ty_88 = 0;
+pub const IFLA_VF_INFO: _bindgen_ty_88 = 1;
+pub const __IFLA_VF_INFO_MAX: _bindgen_ty_88 = 2;
+pub type _bindgen_ty_88 = crate::types::c_uint;
+pub const IFLA_VF_UNSPEC: _bindgen_ty_89 = 0;
+pub const IFLA_VF_MAC: _bindgen_ty_89 = 1;
+pub const IFLA_VF_VLAN: _bindgen_ty_89 = 2;
+pub const IFLA_VF_TX_RATE: _bindgen_ty_89 = 3;
+pub const IFLA_VF_SPOOFCHK: _bindgen_ty_89 = 4;
+pub const IFLA_VF_LINK_STATE: _bindgen_ty_89 = 5;
+pub const IFLA_VF_RATE: _bindgen_ty_89 = 6;
+pub const IFLA_VF_RSS_QUERY_EN: _bindgen_ty_89 = 7;
+pub const IFLA_VF_STATS: _bindgen_ty_89 = 8;
+pub const IFLA_VF_TRUST: _bindgen_ty_89 = 9;
+pub const IFLA_VF_IB_NODE_GUID: _bindgen_ty_89 = 10;
+pub const IFLA_VF_IB_PORT_GUID: _bindgen_ty_89 = 11;
+pub const IFLA_VF_VLAN_LIST: _bindgen_ty_89 = 12;
+pub const IFLA_VF_BROADCAST: _bindgen_ty_89 = 13;
+pub const __IFLA_VF_MAX: _bindgen_ty_89 = 14;
+pub type _bindgen_ty_89 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_mac {
+    pub vf: __u32,
+    pub mac: [__u8; 32usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_broadcast {
+    pub broadcast: [__u8; 32usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_vlan {
+    pub vf: __u32,
+    pub vlan: __u32,
+    pub qos: __u32,
+}
+pub const IFLA_VF_VLAN_INFO_UNSPEC: _bindgen_ty_90 = 0;
+pub const IFLA_VF_VLAN_INFO: _bindgen_ty_90 = 1;
+pub const __IFLA_VF_VLAN_INFO_MAX: _bindgen_ty_90 = 2;
+pub type _bindgen_ty_90 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_vlan_info {
+    pub vf: __u32,
+    pub vlan: __u32,
+    pub qos: __u32,
+    pub vlan_proto: __be16,
+    pub __bindgen_padding_0: [u8; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_tx_rate {
+    pub vf: __u32,
+    pub rate: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_rate {
+    pub vf: __u32,
+    pub min_tx_rate: __u32,
+    pub max_tx_rate: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_spoofchk {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_guid {
+    pub vf: __u32,
+    pub __bindgen_padding_0: [u8; 4usize],
+    pub guid: __u64,
+}
+pub const IFLA_VF_LINK_STATE_AUTO: _bindgen_ty_91 = 0;
+pub const IFLA_VF_LINK_STATE_ENABLE: _bindgen_ty_91 = 1;
+pub const IFLA_VF_LINK_STATE_DISABLE: _bindgen_ty_91 = 2;
+pub const __IFLA_VF_LINK_STATE_MAX: _bindgen_ty_91 = 3;
+pub type _bindgen_ty_91 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_link_state {
+    pub vf: __u32,
+    pub link_state: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_rss_query_en {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+pub const IFLA_VF_STATS_RX_PACKETS: _bindgen_ty_92 = 0;
+pub const IFLA_VF_STATS_TX_PACKETS: _bindgen_ty_92 = 1;
+pub const IFLA_VF_STATS_RX_BYTES: _bindgen_ty_92 = 2;
+pub const IFLA_VF_STATS_TX_BYTES: _bindgen_ty_92 = 3;
+pub const IFLA_VF_STATS_BROADCAST: _bindgen_ty_92 = 4;
+pub const IFLA_VF_STATS_MULTICAST: _bindgen_ty_92 = 5;
+pub const IFLA_VF_STATS_PAD: _bindgen_ty_92 = 6;
+pub const IFLA_VF_STATS_RX_DROPPED: _bindgen_ty_92 = 7;
+pub const IFLA_VF_STATS_TX_DROPPED: _bindgen_ty_92 = 8;
+pub const __IFLA_VF_STATS_MAX: _bindgen_ty_92 = 9;
+pub type _bindgen_ty_92 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_vf_trust {
+    pub vf: __u32,
+    pub setting: __u32,
+}
+pub const IFLA_VF_PORT_UNSPEC: _bindgen_ty_93 = 0;
+pub const IFLA_VF_PORT: _bindgen_ty_93 = 1;
+pub const __IFLA_VF_PORT_MAX: _bindgen_ty_93 = 2;
+pub type _bindgen_ty_93 = crate::types::c_uint;
+pub const IFLA_PORT_UNSPEC: _bindgen_ty_94 = 0;
+pub const IFLA_PORT_VF: _bindgen_ty_94 = 1;
+pub const IFLA_PORT_PROFILE: _bindgen_ty_94 = 2;
+pub const IFLA_PORT_VSI_TYPE: _bindgen_ty_94 = 3;
+pub const IFLA_PORT_INSTANCE_UUID: _bindgen_ty_94 = 4;
+pub const IFLA_PORT_HOST_UUID: _bindgen_ty_94 = 5;
+pub const IFLA_PORT_REQUEST: _bindgen_ty_94 = 6;
+pub const IFLA_PORT_RESPONSE: _bindgen_ty_94 = 7;
+pub const __IFLA_PORT_MAX: _bindgen_ty_94 = 8;
+pub type _bindgen_ty_94 = crate::types::c_uint;
+pub const PORT_REQUEST_PREASSOCIATE: _bindgen_ty_95 = 0;
+pub const PORT_REQUEST_PREASSOCIATE_RR: _bindgen_ty_95 = 1;
+pub const PORT_REQUEST_ASSOCIATE: _bindgen_ty_95 = 2;
+pub const PORT_REQUEST_DISASSOCIATE: _bindgen_ty_95 = 3;
+pub type _bindgen_ty_95 = crate::types::c_uint;
+pub const PORT_VDP_RESPONSE_SUCCESS: _bindgen_ty_96 = 0;
+pub const PORT_VDP_RESPONSE_INVALID_FORMAT: _bindgen_ty_96 = 1;
+pub const PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES: _bindgen_ty_96 = 2;
+pub const PORT_VDP_RESPONSE_UNUSED_VTID: _bindgen_ty_96 = 3;
+pub const PORT_VDP_RESPONSE_VTID_VIOLATION: _bindgen_ty_96 = 4;
+pub const PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION: _bindgen_ty_96 = 5;
+pub const PORT_VDP_RESPONSE_OUT_OF_SYNC: _bindgen_ty_96 = 6;
+pub const PORT_PROFILE_RESPONSE_SUCCESS: _bindgen_ty_96 = 256;
+pub const PORT_PROFILE_RESPONSE_INPROGRESS: _bindgen_ty_96 = 257;
+pub const PORT_PROFILE_RESPONSE_INVALID: _bindgen_ty_96 = 258;
+pub const PORT_PROFILE_RESPONSE_BADSTATE: _bindgen_ty_96 = 259;
+pub const PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES: _bindgen_ty_96 = 260;
+pub const PORT_PROFILE_RESPONSE_ERROR: _bindgen_ty_96 = 261;
+pub type _bindgen_ty_96 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_port_vsi {
+    pub vsi_mgr_id: __u8,
+    pub vsi_type_id: [__u8; 3usize],
+    pub vsi_type_version: __u8,
+    pub pad: [__u8; 3usize],
+}
+pub const IFLA_IPOIB_UNSPEC: _bindgen_ty_97 = 0;
+pub const IFLA_IPOIB_PKEY: _bindgen_ty_97 = 1;
+pub const IFLA_IPOIB_MODE: _bindgen_ty_97 = 2;
+pub const IFLA_IPOIB_UMCAST: _bindgen_ty_97 = 3;
+pub const __IFLA_IPOIB_MAX: _bindgen_ty_97 = 4;
+pub type _bindgen_ty_97 = crate::types::c_uint;
+pub const IPOIB_MODE_DATAGRAM: _bindgen_ty_98 = 0;
+pub const IPOIB_MODE_CONNECTED: _bindgen_ty_98 = 1;
+pub type _bindgen_ty_98 = crate::types::c_uint;
+pub const HSR_PROTOCOL_HSR: _bindgen_ty_99 = 0;
+pub const HSR_PROTOCOL_PRP: _bindgen_ty_99 = 1;
+pub const HSR_PROTOCOL_MAX: _bindgen_ty_99 = 2;
+pub type _bindgen_ty_99 = crate::types::c_uint;
+pub const IFLA_HSR_UNSPEC: _bindgen_ty_100 = 0;
+pub const IFLA_HSR_SLAVE1: _bindgen_ty_100 = 1;
+pub const IFLA_HSR_SLAVE2: _bindgen_ty_100 = 2;
+pub const IFLA_HSR_MULTICAST_SPEC: _bindgen_ty_100 = 3;
+pub const IFLA_HSR_SUPERVISION_ADDR: _bindgen_ty_100 = 4;
+pub const IFLA_HSR_SEQ_NR: _bindgen_ty_100 = 5;
+pub const IFLA_HSR_VERSION: _bindgen_ty_100 = 6;
+pub const IFLA_HSR_PROTOCOL: _bindgen_ty_100 = 7;
+pub const __IFLA_HSR_MAX: _bindgen_ty_100 = 8;
+pub type _bindgen_ty_100 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct if_stats_msg {
+    pub family: __u8,
+    pub pad1: __u8,
+    pub pad2: __u16,
+    pub ifindex: __u32,
+    pub filter_mask: __u32,
+}
+pub const IFLA_STATS_UNSPEC: _bindgen_ty_101 = 0;
+pub const IFLA_STATS_LINK_64: _bindgen_ty_101 = 1;
+pub const IFLA_STATS_LINK_XSTATS: _bindgen_ty_101 = 2;
+pub const IFLA_STATS_LINK_XSTATS_SLAVE: _bindgen_ty_101 = 3;
+pub const IFLA_STATS_LINK_OFFLOAD_XSTATS: _bindgen_ty_101 = 4;
+pub const IFLA_STATS_AF_SPEC: _bindgen_ty_101 = 5;
+pub const __IFLA_STATS_MAX: _bindgen_ty_101 = 6;
+pub type _bindgen_ty_101 = crate::types::c_uint;
+pub const IFLA_STATS_GETSET_UNSPEC: _bindgen_ty_102 = 0;
+pub const IFLA_STATS_GET_FILTERS: _bindgen_ty_102 = 1;
+pub const IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS: _bindgen_ty_102 = 2;
+pub const __IFLA_STATS_GETSET_MAX: _bindgen_ty_102 = 3;
+pub type _bindgen_ty_102 = crate::types::c_uint;
+pub const LINK_XSTATS_TYPE_UNSPEC: _bindgen_ty_103 = 0;
+pub const LINK_XSTATS_TYPE_BRIDGE: _bindgen_ty_103 = 1;
+pub const LINK_XSTATS_TYPE_BOND: _bindgen_ty_103 = 2;
+pub const __LINK_XSTATS_TYPE_MAX: _bindgen_ty_103 = 3;
+pub type _bindgen_ty_103 = crate::types::c_uint;
+pub const IFLA_OFFLOAD_XSTATS_UNSPEC: _bindgen_ty_104 = 0;
+pub const IFLA_OFFLOAD_XSTATS_CPU_HIT: _bindgen_ty_104 = 1;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO: _bindgen_ty_104 = 2;
+pub const IFLA_OFFLOAD_XSTATS_L3_STATS: _bindgen_ty_104 = 3;
+pub const __IFLA_OFFLOAD_XSTATS_MAX: _bindgen_ty_104 = 4;
+pub type _bindgen_ty_104 = crate::types::c_uint;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_UNSPEC: _bindgen_ty_105 = 0;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST: _bindgen_ty_105 = 1;
+pub const IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED: _bindgen_ty_105 = 2;
+pub const __IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX: _bindgen_ty_105 = 3;
+pub type _bindgen_ty_105 = crate::types::c_uint;
+pub const XDP_ATTACHED_NONE: _bindgen_ty_106 = 0;
+pub const XDP_ATTACHED_DRV: _bindgen_ty_106 = 1;
+pub const XDP_ATTACHED_SKB: _bindgen_ty_106 = 2;
+pub const XDP_ATTACHED_HW: _bindgen_ty_106 = 3;
+pub const XDP_ATTACHED_MULTI: _bindgen_ty_106 = 4;
+pub type _bindgen_ty_106 = crate::types::c_uint;
+pub const IFLA_XDP_UNSPEC: _bindgen_ty_107 = 0;
+pub const IFLA_XDP_FD: _bindgen_ty_107 = 1;
+pub const IFLA_XDP_ATTACHED: _bindgen_ty_107 = 2;
+pub const IFLA_XDP_FLAGS: _bindgen_ty_107 = 3;
+pub const IFLA_XDP_PROG_ID: _bindgen_ty_107 = 4;
+pub const IFLA_XDP_DRV_PROG_ID: _bindgen_ty_107 = 5;
+pub const IFLA_XDP_SKB_PROG_ID: _bindgen_ty_107 = 6;
+pub const IFLA_XDP_HW_PROG_ID: _bindgen_ty_107 = 7;
+pub const IFLA_XDP_EXPECTED_FD: _bindgen_ty_107 = 8;
+pub const __IFLA_XDP_MAX: _bindgen_ty_107 = 9;
+pub type _bindgen_ty_107 = crate::types::c_uint;
+pub const IFLA_EVENT_NONE: _bindgen_ty_108 = 0;
+pub const IFLA_EVENT_REBOOT: _bindgen_ty_108 = 1;
+pub const IFLA_EVENT_FEATURES: _bindgen_ty_108 = 2;
+pub const IFLA_EVENT_BONDING_FAILOVER: _bindgen_ty_108 = 3;
+pub const IFLA_EVENT_NOTIFY_PEERS: _bindgen_ty_108 = 4;
+pub const IFLA_EVENT_IGMP_RESEND: _bindgen_ty_108 = 5;
+pub const IFLA_EVENT_BONDING_OPTIONS: _bindgen_ty_108 = 6;
+pub type _bindgen_ty_108 = crate::types::c_uint;
+pub const IFLA_TUN_UNSPEC: _bindgen_ty_109 = 0;
+pub const IFLA_TUN_OWNER: _bindgen_ty_109 = 1;
+pub const IFLA_TUN_GROUP: _bindgen_ty_109 = 2;
+pub const IFLA_TUN_TYPE: _bindgen_ty_109 = 3;
+pub const IFLA_TUN_PI: _bindgen_ty_109 = 4;
+pub const IFLA_TUN_VNET_HDR: _bindgen_ty_109 = 5;
+pub const IFLA_TUN_PERSIST: _bindgen_ty_109 = 6;
+pub const IFLA_TUN_MULTI_QUEUE: _bindgen_ty_109 = 7;
+pub const IFLA_TUN_NUM_QUEUES: _bindgen_ty_109 = 8;
+pub const IFLA_TUN_NUM_DISABLED_QUEUES: _bindgen_ty_109 = 9;
+pub const __IFLA_TUN_MAX: _bindgen_ty_109 = 10;
+pub type _bindgen_ty_109 = crate::types::c_uint;
+pub const IFLA_RMNET_UNSPEC: _bindgen_ty_110 = 0;
+pub const IFLA_RMNET_MUX_ID: _bindgen_ty_110 = 1;
+pub const IFLA_RMNET_FLAGS: _bindgen_ty_110 = 2;
+pub const __IFLA_RMNET_MAX: _bindgen_ty_110 = 3;
+pub type _bindgen_ty_110 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifla_rmnet_flags {
+    pub flags: __u32,
+    pub mask: __u32,
+}
+pub const IFLA_MCTP_UNSPEC: _bindgen_ty_111 = 0;
+pub const IFLA_MCTP_NET: _bindgen_ty_111 = 1;
+pub const __IFLA_MCTP_MAX: _bindgen_ty_111 = 2;
+pub type _bindgen_ty_111 = crate::types::c_uint;
+pub const IFLA_DSA_UNSPEC: _bindgen_ty_112 = 0;
+pub const IFLA_DSA_MASTER: _bindgen_ty_112 = 1;
+pub const __IFLA_DSA_MAX: _bindgen_ty_112 = 2;
+pub type _bindgen_ty_112 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifaddrmsg {
+    pub ifa_family: __u8,
+    pub ifa_prefixlen: __u8,
+    pub ifa_flags: __u8,
+    pub ifa_scope: __u8,
+    pub ifa_index: __u32,
+}
+pub const IFA_UNSPEC: _bindgen_ty_113 = 0;
+pub const IFA_ADDRESS: _bindgen_ty_113 = 1;
+pub const IFA_LOCAL: _bindgen_ty_113 = 2;
+pub const IFA_LABEL: _bindgen_ty_113 = 3;
+pub const IFA_BROADCAST: _bindgen_ty_113 = 4;
+pub const IFA_ANYCAST: _bindgen_ty_113 = 5;
+pub const IFA_CACHEINFO: _bindgen_ty_113 = 6;
+pub const IFA_MULTICAST: _bindgen_ty_113 = 7;
+pub const IFA_FLAGS: _bindgen_ty_113 = 8;
+pub const IFA_RT_PRIORITY: _bindgen_ty_113 = 9;
+pub const IFA_TARGET_NETNSID: _bindgen_ty_113 = 10;
+pub const IFA_PROTO: _bindgen_ty_113 = 11;
+pub const __IFA_MAX: _bindgen_ty_113 = 12;
+pub type _bindgen_ty_113 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifa_cacheinfo {
+    pub ifa_prefered: __u32,
+    pub ifa_valid: __u32,
+    pub cstamp: __u32,
+    pub tstamp: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndmsg {
+    pub ndm_family: __u8,
+    pub ndm_pad1: __u8,
+    pub ndm_pad2: __u16,
+    pub ndm_ifindex: __s32,
+    pub ndm_state: __u16,
+    pub ndm_flags: __u8,
+    pub ndm_type: __u8,
+}
+pub const NDA_UNSPEC: _bindgen_ty_114 = 0;
+pub const NDA_DST: _bindgen_ty_114 = 1;
+pub const NDA_LLADDR: _bindgen_ty_114 = 2;
+pub const NDA_CACHEINFO: _bindgen_ty_114 = 3;
+pub const NDA_PROBES: _bindgen_ty_114 = 4;
+pub const NDA_VLAN: _bindgen_ty_114 = 5;
+pub const NDA_PORT: _bindgen_ty_114 = 6;
+pub const NDA_VNI: _bindgen_ty_114 = 7;
+pub const NDA_IFINDEX: _bindgen_ty_114 = 8;
+pub const NDA_MASTER: _bindgen_ty_114 = 9;
+pub const NDA_LINK_NETNSID: _bindgen_ty_114 = 10;
+pub const NDA_SRC_VNI: _bindgen_ty_114 = 11;
+pub const NDA_PROTOCOL: _bindgen_ty_114 = 12;
+pub const NDA_NH_ID: _bindgen_ty_114 = 13;
+pub const NDA_FDB_EXT_ATTRS: _bindgen_ty_114 = 14;
+pub const NDA_FLAGS_EXT: _bindgen_ty_114 = 15;
+pub const NDA_NDM_STATE_MASK: _bindgen_ty_114 = 16;
+pub const NDA_NDM_FLAGS_MASK: _bindgen_ty_114 = 17;
+pub const __NDA_MAX: _bindgen_ty_114 = 18;
+pub type _bindgen_ty_114 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct nda_cacheinfo {
+    pub ndm_confirmed: __u32,
+    pub ndm_used: __u32,
+    pub ndm_updated: __u32,
+    pub ndm_refcnt: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndt_stats {
+    pub ndts_allocs: __u64,
+    pub ndts_destroys: __u64,
+    pub ndts_hash_grows: __u64,
+    pub ndts_res_failed: __u64,
+    pub ndts_lookups: __u64,
+    pub ndts_hits: __u64,
+    pub ndts_rcv_probes_mcast: __u64,
+    pub ndts_rcv_probes_ucast: __u64,
+    pub ndts_periodic_gc_runs: __u64,
+    pub ndts_forced_gc_runs: __u64,
+    pub ndts_table_fulls: __u64,
+}
+pub const NDTPA_UNSPEC: _bindgen_ty_115 = 0;
+pub const NDTPA_IFINDEX: _bindgen_ty_115 = 1;
+pub const NDTPA_REFCNT: _bindgen_ty_115 = 2;
+pub const NDTPA_REACHABLE_TIME: _bindgen_ty_115 = 3;
+pub const NDTPA_BASE_REACHABLE_TIME: _bindgen_ty_115 = 4;
+pub const NDTPA_RETRANS_TIME: _bindgen_ty_115 = 5;
+pub const NDTPA_GC_STALETIME: _bindgen_ty_115 = 6;
+pub const NDTPA_DELAY_PROBE_TIME: _bindgen_ty_115 = 7;
+pub const NDTPA_QUEUE_LEN: _bindgen_ty_115 = 8;
+pub const NDTPA_APP_PROBES: _bindgen_ty_115 = 9;
+pub const NDTPA_UCAST_PROBES: _bindgen_ty_115 = 10;
+pub const NDTPA_MCAST_PROBES: _bindgen_ty_115 = 11;
+pub const NDTPA_ANYCAST_DELAY: _bindgen_ty_115 = 12;
+pub const NDTPA_PROXY_DELAY: _bindgen_ty_115 = 13;
+pub const NDTPA_PROXY_QLEN: _bindgen_ty_115 = 14;
+pub const NDTPA_LOCKTIME: _bindgen_ty_115 = 15;
+pub const NDTPA_QUEUE_LENBYTES: _bindgen_ty_115 = 16;
+pub const NDTPA_MCAST_REPROBES: _bindgen_ty_115 = 17;
+pub const NDTPA_PAD: _bindgen_ty_115 = 18;
+pub const NDTPA_INTERVAL_PROBE_TIME_MS: _bindgen_ty_115 = 19;
+pub const __NDTPA_MAX: _bindgen_ty_115 = 20;
+pub type _bindgen_ty_115 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndtmsg {
+    pub ndtm_family: __u8,
+    pub ndtm_pad1: __u8,
+    pub ndtm_pad2: __u16,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ndt_config {
+    pub ndtc_key_len: __u16,
+    pub ndtc_entry_size: __u16,
+    pub ndtc_entries: __u32,
+    pub ndtc_last_flush: __u32,
+    pub ndtc_last_rand: __u32,
+    pub ndtc_hash_rnd: __u32,
+    pub ndtc_hash_mask: __u32,
+    pub ndtc_hash_chain_gc: __u32,
+    pub ndtc_proxy_qlen: __u32,
+}
+pub const NDTA_UNSPEC: _bindgen_ty_116 = 0;
+pub const NDTA_NAME: _bindgen_ty_116 = 1;
+pub const NDTA_THRESH1: _bindgen_ty_116 = 2;
+pub const NDTA_THRESH2: _bindgen_ty_116 = 3;
+pub const NDTA_THRESH3: _bindgen_ty_116 = 4;
+pub const NDTA_CONFIG: _bindgen_ty_116 = 5;
+pub const NDTA_PARMS: _bindgen_ty_116 = 6;
+pub const NDTA_STATS: _bindgen_ty_116 = 7;
+pub const NDTA_GC_INTERVAL: _bindgen_ty_116 = 8;
+pub const NDTA_PAD: _bindgen_ty_116 = 9;
+pub const __NDTA_MAX: _bindgen_ty_116 = 10;
+pub type _bindgen_ty_116 = crate::types::c_uint;
+pub const FDB_NOTIFY_BIT: _bindgen_ty_117 = 1;
+pub const FDB_NOTIFY_INACTIVE_BIT: _bindgen_ty_117 = 2;
+pub type _bindgen_ty_117 = crate::types::c_uint;
+pub const NFEA_UNSPEC: _bindgen_ty_118 = 0;
+pub const NFEA_ACTIVITY_NOTIFY: _bindgen_ty_118 = 1;
+pub const NFEA_DONT_REFRESH: _bindgen_ty_118 = 2;
+pub const __NFEA_MAX: _bindgen_ty_118 = 3;
+pub type _bindgen_ty_118 = crate::types::c_uint;
+pub const RTM_BASE: _bindgen_ty_119 = 16;
+pub const RTM_NEWLINK: _bindgen_ty_119 = 16;
+pub const RTM_DELLINK: _bindgen_ty_119 = 17;
+pub const RTM_GETLINK: _bindgen_ty_119 = 18;
+pub const RTM_SETLINK: _bindgen_ty_119 = 19;
+pub const RTM_NEWADDR: _bindgen_ty_119 = 20;
+pub const RTM_DELADDR: _bindgen_ty_119 = 21;
+pub const RTM_GETADDR: _bindgen_ty_119 = 22;
+pub const RTM_NEWROUTE: _bindgen_ty_119 = 24;
+pub const RTM_DELROUTE: _bindgen_ty_119 = 25;
+pub const RTM_GETROUTE: _bindgen_ty_119 = 26;
+pub const RTM_NEWNEIGH: _bindgen_ty_119 = 28;
+pub const RTM_DELNEIGH: _bindgen_ty_119 = 29;
+pub const RTM_GETNEIGH: _bindgen_ty_119 = 30;
+pub const RTM_NEWRULE: _bindgen_ty_119 = 32;
+pub const RTM_DELRULE: _bindgen_ty_119 = 33;
+pub const RTM_GETRULE: _bindgen_ty_119 = 34;
+pub const RTM_NEWQDISC: _bindgen_ty_119 = 36;
+pub const RTM_DELQDISC: _bindgen_ty_119 = 37;
+pub const RTM_GETQDISC: _bindgen_ty_119 = 38;
+pub const RTM_NEWTCLASS: _bindgen_ty_119 = 40;
+pub const RTM_DELTCLASS: _bindgen_ty_119 = 41;
+pub const RTM_GETTCLASS: _bindgen_ty_119 = 42;
+pub const RTM_NEWTFILTER: _bindgen_ty_119 = 44;
+pub const RTM_DELTFILTER: _bindgen_ty_119 = 45;
+pub const RTM_GETTFILTER: _bindgen_ty_119 = 46;
+pub const RTM_NEWACTION: _bindgen_ty_119 = 48;
+pub const RTM_DELACTION: _bindgen_ty_119 = 49;
+pub const RTM_GETACTION: _bindgen_ty_119 = 50;
+pub const RTM_NEWPREFIX: _bindgen_ty_119 = 52;
+pub const RTM_GETMULTICAST: _bindgen_ty_119 = 58;
+pub const RTM_GETANYCAST: _bindgen_ty_119 = 62;
+pub const RTM_NEWNEIGHTBL: _bindgen_ty_119 = 64;
+pub const RTM_GETNEIGHTBL: _bindgen_ty_119 = 66;
+pub const RTM_SETNEIGHTBL: _bindgen_ty_119 = 67;
+pub const RTM_NEWNDUSEROPT: _bindgen_ty_119 = 68;
+pub const RTM_NEWADDRLABEL: _bindgen_ty_119 = 72;
+pub const RTM_DELADDRLABEL: _bindgen_ty_119 = 73;
+pub const RTM_GETADDRLABEL: _bindgen_ty_119 = 74;
+pub const RTM_GETDCB: _bindgen_ty_119 = 78;
+pub const RTM_SETDCB: _bindgen_ty_119 = 79;
+pub const RTM_NEWNETCONF: _bindgen_ty_119 = 80;
+pub const RTM_DELNETCONF: _bindgen_ty_119 = 81;
+pub const RTM_GETNETCONF: _bindgen_ty_119 = 82;
+pub const RTM_NEWMDB: _bindgen_ty_119 = 84;
+pub const RTM_DELMDB: _bindgen_ty_119 = 85;
+pub const RTM_GETMDB: _bindgen_ty_119 = 86;
+pub const RTM_NEWNSID: _bindgen_ty_119 = 88;
+pub const RTM_DELNSID: _bindgen_ty_119 = 89;
+pub const RTM_GETNSID: _bindgen_ty_119 = 90;
+pub const RTM_NEWSTATS: _bindgen_ty_119 = 92;
+pub const RTM_GETSTATS: _bindgen_ty_119 = 94;
+pub const RTM_SETSTATS: _bindgen_ty_119 = 95;
+pub const RTM_NEWCACHEREPORT: _bindgen_ty_119 = 96;
+pub const RTM_NEWCHAIN: _bindgen_ty_119 = 100;
+pub const RTM_DELCHAIN: _bindgen_ty_119 = 101;
+pub const RTM_GETCHAIN: _bindgen_ty_119 = 102;
+pub const RTM_NEWNEXTHOP: _bindgen_ty_119 = 104;
+pub const RTM_DELNEXTHOP: _bindgen_ty_119 = 105;
+pub const RTM_GETNEXTHOP: _bindgen_ty_119 = 106;
+pub const RTM_NEWLINKPROP: _bindgen_ty_119 = 108;
+pub const RTM_DELLINKPROP: _bindgen_ty_119 = 109;
+pub const RTM_GETLINKPROP: _bindgen_ty_119 = 110;
+pub const RTM_NEWVLAN: _bindgen_ty_119 = 112;
+pub const RTM_DELVLAN: _bindgen_ty_119 = 113;
+pub const RTM_GETVLAN: _bindgen_ty_119 = 114;
+pub const RTM_NEWNEXTHOPBUCKET: _bindgen_ty_119 = 116;
+pub const RTM_DELNEXTHOPBUCKET: _bindgen_ty_119 = 117;
+pub const RTM_GETNEXTHOPBUCKET: _bindgen_ty_119 = 118;
+pub const RTM_NEWTUNNEL: _bindgen_ty_119 = 120;
+pub const RTM_DELTUNNEL: _bindgen_ty_119 = 121;
+pub const RTM_GETTUNNEL: _bindgen_ty_119 = 122;
+pub const __RTM_MAX: _bindgen_ty_119 = 123;
+pub type _bindgen_ty_119 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtattr {
+    pub rta_len: crate::types::c_ushort,
+    pub rta_type: crate::types::c_ushort,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtmsg {
+    pub rtm_family: crate::types::c_uchar,
+    pub rtm_dst_len: crate::types::c_uchar,
+    pub rtm_src_len: crate::types::c_uchar,
+    pub rtm_tos: crate::types::c_uchar,
+    pub rtm_table: crate::types::c_uchar,
+    pub rtm_protocol: crate::types::c_uchar,
+    pub rtm_scope: crate::types::c_uchar,
+    pub rtm_type: crate::types::c_uchar,
+    pub rtm_flags: crate::types::c_uint,
+}
+pub const RTN_UNSPEC: _bindgen_ty_120 = 0;
+pub const RTN_UNICAST: _bindgen_ty_120 = 1;
+pub const RTN_LOCAL: _bindgen_ty_120 = 2;
+pub const RTN_BROADCAST: _bindgen_ty_120 = 3;
+pub const RTN_ANYCAST: _bindgen_ty_120 = 4;
+pub const RTN_MULTICAST: _bindgen_ty_120 = 5;
+pub const RTN_BLACKHOLE: _bindgen_ty_120 = 6;
+pub const RTN_UNREACHABLE: _bindgen_ty_120 = 7;
+pub const RTN_PROHIBIT: _bindgen_ty_120 = 8;
+pub const RTN_THROW: _bindgen_ty_120 = 9;
+pub const RTN_NAT: _bindgen_ty_120 = 10;
+pub const RTN_XRESOLVE: _bindgen_ty_120 = 11;
+pub const __RTN_MAX: _bindgen_ty_120 = 12;
+pub type _bindgen_ty_120 = crate::types::c_uint;
+pub const rt_scope_t_RT_SCOPE_UNIVERSE: rt_scope_t = 0;
+pub const rt_scope_t_RT_SCOPE_SITE: rt_scope_t = 200;
+pub const rt_scope_t_RT_SCOPE_LINK: rt_scope_t = 253;
+pub const rt_scope_t_RT_SCOPE_HOST: rt_scope_t = 254;
+pub const rt_scope_t_RT_SCOPE_NOWHERE: rt_scope_t = 255;
+pub type rt_scope_t = crate::types::c_uint;
+pub const rt_class_t_RT_TABLE_UNSPEC: rt_class_t = 0;
+pub const rt_class_t_RT_TABLE_COMPAT: rt_class_t = 252;
+pub const rt_class_t_RT_TABLE_DEFAULT: rt_class_t = 253;
+pub const rt_class_t_RT_TABLE_MAIN: rt_class_t = 254;
+pub const rt_class_t_RT_TABLE_LOCAL: rt_class_t = 255;
+pub const rt_class_t_RT_TABLE_MAX: rt_class_t = 4294967295;
+pub type rt_class_t = crate::types::c_uint;
+pub const rtattr_type_t_RTA_UNSPEC: rtattr_type_t = 0;
+pub const rtattr_type_t_RTA_DST: rtattr_type_t = 1;
+pub const rtattr_type_t_RTA_SRC: rtattr_type_t = 2;
+pub const rtattr_type_t_RTA_IIF: rtattr_type_t = 3;
+pub const rtattr_type_t_RTA_OIF: rtattr_type_t = 4;
+pub const rtattr_type_t_RTA_GATEWAY: rtattr_type_t = 5;
+pub const rtattr_type_t_RTA_PRIORITY: rtattr_type_t = 6;
+pub const rtattr_type_t_RTA_PREFSRC: rtattr_type_t = 7;
+pub const rtattr_type_t_RTA_METRICS: rtattr_type_t = 8;
+pub const rtattr_type_t_RTA_MULTIPATH: rtattr_type_t = 9;
+pub const rtattr_type_t_RTA_PROTOINFO: rtattr_type_t = 10;
+pub const rtattr_type_t_RTA_FLOW: rtattr_type_t = 11;
+pub const rtattr_type_t_RTA_CACHEINFO: rtattr_type_t = 12;
+pub const rtattr_type_t_RTA_SESSION: rtattr_type_t = 13;
+pub const rtattr_type_t_RTA_MP_ALGO: rtattr_type_t = 14;
+pub const rtattr_type_t_RTA_TABLE: rtattr_type_t = 15;
+pub const rtattr_type_t_RTA_MARK: rtattr_type_t = 16;
+pub const rtattr_type_t_RTA_MFC_STATS: rtattr_type_t = 17;
+pub const rtattr_type_t_RTA_VIA: rtattr_type_t = 18;
+pub const rtattr_type_t_RTA_NEWDST: rtattr_type_t = 19;
+pub const rtattr_type_t_RTA_PREF: rtattr_type_t = 20;
+pub const rtattr_type_t_RTA_ENCAP_TYPE: rtattr_type_t = 21;
+pub const rtattr_type_t_RTA_ENCAP: rtattr_type_t = 22;
+pub const rtattr_type_t_RTA_EXPIRES: rtattr_type_t = 23;
+pub const rtattr_type_t_RTA_PAD: rtattr_type_t = 24;
+pub const rtattr_type_t_RTA_UID: rtattr_type_t = 25;
+pub const rtattr_type_t_RTA_TTL_PROPAGATE: rtattr_type_t = 26;
+pub const rtattr_type_t_RTA_IP_PROTO: rtattr_type_t = 27;
+pub const rtattr_type_t_RTA_SPORT: rtattr_type_t = 28;
+pub const rtattr_type_t_RTA_DPORT: rtattr_type_t = 29;
+pub const rtattr_type_t_RTA_NH_ID: rtattr_type_t = 30;
+pub const rtattr_type_t___RTA_MAX: rtattr_type_t = 31;
+pub type rtattr_type_t = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtnexthop {
+    pub rtnh_len: crate::types::c_ushort,
+    pub rtnh_flags: crate::types::c_uchar,
+    pub rtnh_hops: crate::types::c_uchar,
+    pub rtnh_ifindex: crate::types::c_int,
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct rtvia {
+    pub rtvia_family: __kernel_sa_family_t,
+    pub rtvia_addr: __IncompleteArrayField<__u8>,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_cacheinfo {
+    pub rta_clntref: __u32,
+    pub rta_lastuse: __u32,
+    pub rta_expires: __s32,
+    pub rta_error: __u32,
+    pub rta_used: __u32,
+    pub rta_id: __u32,
+    pub rta_ts: __u32,
+    pub rta_tsage: __u32,
+}
+pub const RTAX_UNSPEC: _bindgen_ty_121 = 0;
+pub const RTAX_LOCK: _bindgen_ty_121 = 1;
+pub const RTAX_MTU: _bindgen_ty_121 = 2;
+pub const RTAX_WINDOW: _bindgen_ty_121 = 3;
+pub const RTAX_RTT: _bindgen_ty_121 = 4;
+pub const RTAX_RTTVAR: _bindgen_ty_121 = 5;
+pub const RTAX_SSTHRESH: _bindgen_ty_121 = 6;
+pub const RTAX_CWND: _bindgen_ty_121 = 7;
+pub const RTAX_ADVMSS: _bindgen_ty_121 = 8;
+pub const RTAX_REORDERING: _bindgen_ty_121 = 9;
+pub const RTAX_HOPLIMIT: _bindgen_ty_121 = 10;
+pub const RTAX_INITCWND: _bindgen_ty_121 = 11;
+pub const RTAX_FEATURES: _bindgen_ty_121 = 12;
+pub const RTAX_RTO_MIN: _bindgen_ty_121 = 13;
+pub const RTAX_INITRWND: _bindgen_ty_121 = 14;
+pub const RTAX_QUICKACK: _bindgen_ty_121 = 15;
+pub const RTAX_CC_ALGO: _bindgen_ty_121 = 16;
+pub const RTAX_FASTOPEN_NO_COOKIE: _bindgen_ty_121 = 17;
+pub const __RTAX_MAX: _bindgen_ty_121 = 18;
+pub type _bindgen_ty_121 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct rta_session {
+    pub proto: __u8,
+    pub pad1: __u8,
+    pub pad2: __u16,
+    pub u: rta_session__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union rta_session__bindgen_ty_1 {
+    pub ports: rta_session__bindgen_ty_1__bindgen_ty_1,
+    pub icmpt: rta_session__bindgen_ty_1__bindgen_ty_2,
+    pub spi: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_session__bindgen_ty_1__bindgen_ty_1 {
+    pub sport: __u16,
+    pub dport: __u16,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_session__bindgen_ty_1__bindgen_ty_2 {
+    pub type_: __u8,
+    pub code: __u8,
+    pub ident: __u16,
+}
+impl Default for rta_session__bindgen_ty_1 {
+    fn default() -> Self {
+        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+impl Default for rta_session {
+    fn default() -> Self {
+        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rta_mfc_stats {
+    pub mfcs_packets: __u64,
+    pub mfcs_bytes: __u64,
+    pub mfcs_wrong_if: __u64,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct rtgenmsg {
+    pub rtgen_family: crate::types::c_uchar,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct ifinfomsg {
+    pub ifi_family: crate::types::c_uchar,
+    pub __ifi_pad: crate::types::c_uchar,
+    pub ifi_type: crate::types::c_ushort,
+    pub ifi_index: crate::types::c_int,
+    pub ifi_flags: crate::types::c_uint,
+    pub ifi_change: crate::types::c_uint,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct prefixmsg {
+    pub prefix_family: crate::types::c_uchar,
+    pub prefix_pad1: crate::types::c_uchar,
+    pub prefix_pad2: crate::types::c_ushort,
+    pub prefix_ifindex: crate::types::c_int,
+    pub prefix_type: crate::types::c_uchar,
+    pub prefix_len: crate::types::c_uchar,
+    pub prefix_flags: crate::types::c_uchar,
+    pub prefix_pad3: crate::types::c_uchar,
+}
+pub const PREFIX_UNSPEC: _bindgen_ty_122 = 0;
+pub const PREFIX_ADDRESS: _bindgen_ty_122 = 1;
+pub const PREFIX_CACHEINFO: _bindgen_ty_122 = 2;
+pub const __PREFIX_MAX: _bindgen_ty_122 = 3;
+pub type _bindgen_ty_122 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct prefix_cacheinfo {
+    pub preferred_time: __u32,
+    pub valid_time: __u32,
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tcmsg {
+    pub tcm_family: crate::types::c_uchar,
+    pub tcm__pad1: crate::types::c_uchar,
+    pub tcm__pad2: crate::types::c_ushort,
+    pub tcm_ifindex: crate::types::c_int,
+    pub tcm_handle: __u32,
+    pub tcm_parent: __u32,
+    pub tcm_info: __u32,
+}
+pub const TCA_UNSPEC: _bindgen_ty_123 = 0;
+pub const TCA_KIND: _bindgen_ty_123 = 1;
+pub const TCA_OPTIONS: _bindgen_ty_123 = 2;
+pub const TCA_STATS: _bindgen_ty_123 = 3;
+pub const TCA_XSTATS: _bindgen_ty_123 = 4;
+pub const TCA_RATE: _bindgen_ty_123 = 5;
+pub const TCA_FCNT: _bindgen_ty_123 = 6;
+pub const TCA_STATS2: _bindgen_ty_123 = 7;
+pub const TCA_STAB: _bindgen_ty_123 = 8;
+pub const TCA_PAD: _bindgen_ty_123 = 9;
+pub const TCA_DUMP_INVISIBLE: _bindgen_ty_123 = 10;
+pub const TCA_CHAIN: _bindgen_ty_123 = 11;
+pub const TCA_HW_OFFLOAD: _bindgen_ty_123 = 12;
+pub const TCA_INGRESS_BLOCK: _bindgen_ty_123 = 13;
+pub const TCA_EGRESS_BLOCK: _bindgen_ty_123 = 14;
+pub const TCA_DUMP_FLAGS: _bindgen_ty_123 = 15;
+pub const TCA_EXT_WARN_MSG: _bindgen_ty_123 = 16;
+pub const __TCA_MAX: _bindgen_ty_123 = 17;
+pub type _bindgen_ty_123 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct nduseroptmsg {
+    pub nduseropt_family: crate::types::c_uchar,
+    pub nduseropt_pad1: crate::types::c_uchar,
+    pub nduseropt_opts_len: crate::types::c_ushort,
+    pub nduseropt_ifindex: crate::types::c_int,
+    pub nduseropt_icmp_type: __u8,
+    pub nduseropt_icmp_code: __u8,
+    pub nduseropt_pad2: crate::types::c_ushort,
+    pub nduseropt_pad3: crate::types::c_uint,
+}
+pub const NDUSEROPT_UNSPEC: _bindgen_ty_124 = 0;
+pub const NDUSEROPT_SRCADDR: _bindgen_ty_124 = 1;
+pub const __NDUSEROPT_MAX: _bindgen_ty_124 = 2;
+pub type _bindgen_ty_124 = crate::types::c_uint;
+pub const rtnetlink_groups_RTNLGRP_NONE: rtnetlink_groups = 0;
+pub const rtnetlink_groups_RTNLGRP_LINK: rtnetlink_groups = 1;
+pub const rtnetlink_groups_RTNLGRP_NOTIFY: rtnetlink_groups = 2;
+pub const rtnetlink_groups_RTNLGRP_NEIGH: rtnetlink_groups = 3;
+pub const rtnetlink_groups_RTNLGRP_TC: rtnetlink_groups = 4;
+pub const rtnetlink_groups_RTNLGRP_IPV4_IFADDR: rtnetlink_groups = 5;
+pub const rtnetlink_groups_RTNLGRP_IPV4_MROUTE: rtnetlink_groups = 6;
+pub const rtnetlink_groups_RTNLGRP_IPV4_ROUTE: rtnetlink_groups = 7;
+pub const rtnetlink_groups_RTNLGRP_IPV4_RULE: rtnetlink_groups = 8;
+pub const rtnetlink_groups_RTNLGRP_IPV6_IFADDR: rtnetlink_groups = 9;
+pub const rtnetlink_groups_RTNLGRP_IPV6_MROUTE: rtnetlink_groups = 10;
+pub const rtnetlink_groups_RTNLGRP_IPV6_ROUTE: rtnetlink_groups = 11;
+pub const rtnetlink_groups_RTNLGRP_IPV6_IFINFO: rtnetlink_groups = 12;
+pub const rtnetlink_groups_RTNLGRP_DECnet_IFADDR: rtnetlink_groups = 13;
+pub const rtnetlink_groups_RTNLGRP_NOP2: rtnetlink_groups = 14;
+pub const rtnetlink_groups_RTNLGRP_DECnet_ROUTE: rtnetlink_groups = 15;
+pub const rtnetlink_groups_RTNLGRP_DECnet_RULE: rtnetlink_groups = 16;
+pub const rtnetlink_groups_RTNLGRP_NOP4: rtnetlink_groups = 17;
+pub const rtnetlink_groups_RTNLGRP_IPV6_PREFIX: rtnetlink_groups = 18;
+pub const rtnetlink_groups_RTNLGRP_IPV6_RULE: rtnetlink_groups = 19;
+pub const rtnetlink_groups_RTNLGRP_ND_USEROPT: rtnetlink_groups = 20;
+pub const rtnetlink_groups_RTNLGRP_PHONET_IFADDR: rtnetlink_groups = 21;
+pub const rtnetlink_groups_RTNLGRP_PHONET_ROUTE: rtnetlink_groups = 22;
+pub const rtnetlink_groups_RTNLGRP_DCB: rtnetlink_groups = 23;
+pub const rtnetlink_groups_RTNLGRP_IPV4_NETCONF: rtnetlink_groups = 24;
+pub const rtnetlink_groups_RTNLGRP_IPV6_NETCONF: rtnetlink_groups = 25;
+pub const rtnetlink_groups_RTNLGRP_MDB: rtnetlink_groups = 26;
+pub const rtnetlink_groups_RTNLGRP_MPLS_ROUTE: rtnetlink_groups = 27;
+pub const rtnetlink_groups_RTNLGRP_NSID: rtnetlink_groups = 28;
+pub const rtnetlink_groups_RTNLGRP_MPLS_NETCONF: rtnetlink_groups = 29;
+pub const rtnetlink_groups_RTNLGRP_IPV4_MROUTE_R: rtnetlink_groups = 30;
+pub const rtnetlink_groups_RTNLGRP_IPV6_MROUTE_R: rtnetlink_groups = 31;
+pub const rtnetlink_groups_RTNLGRP_NEXTHOP: rtnetlink_groups = 32;
+pub const rtnetlink_groups_RTNLGRP_BRVLAN: rtnetlink_groups = 33;
+pub const rtnetlink_groups_RTNLGRP_MCTP_IFADDR: rtnetlink_groups = 34;
+pub const rtnetlink_groups_RTNLGRP_TUNNEL: rtnetlink_groups = 35;
+pub const rtnetlink_groups_RTNLGRP_STATS: rtnetlink_groups = 36;
+pub const rtnetlink_groups___RTNLGRP_MAX: rtnetlink_groups = 37;
+pub type rtnetlink_groups = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
+pub struct tcamsg {
+    pub tca_family: crate::types::c_uchar,
+    pub tca__pad1: crate::types::c_uchar,
+    pub tca__pad2: crate::types::c_ushort,
+}
+pub const TCA_ROOT_UNSPEC: _bindgen_ty_125 = 0;
+pub const TCA_ROOT_TAB: _bindgen_ty_125 = 1;
+pub const TCA_ROOT_FLAGS: _bindgen_ty_125 = 2;
+pub const TCA_ROOT_COUNT: _bindgen_ty_125 = 3;
+pub const TCA_ROOT_TIME_DELTA: _bindgen_ty_125 = 4;
+pub const TCA_ROOT_EXT_WARN_MSG: _bindgen_ty_125 = 5;
+pub const __TCA_ROOT_MAX: _bindgen_ty_125 = 6;
+pub type _bindgen_ty_125 = crate::types::c_uint;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone, AsBytes, FromBytes, NoCell, FromZeros)]
 pub struct clone_args {
     pub flags: __u64,
     pub pidfd: __u64,
@@ -15557,10 +17080,10 @@
     pub u2_sel: __le16,
     pub u2_pel: __le16,
 }
-pub const FUNCTIONFS_DESCRIPTORS_MAGIC: _bindgen_ty_61 = 1;
-pub const FUNCTIONFS_STRINGS_MAGIC: _bindgen_ty_61 = 2;
-pub const FUNCTIONFS_DESCRIPTORS_MAGIC_V2: _bindgen_ty_61 = 3;
-pub type _bindgen_ty_61 = crate::types::c_uint;
+pub const FUNCTIONFS_DESCRIPTORS_MAGIC: _bindgen_ty_126 = 1;
+pub const FUNCTIONFS_STRINGS_MAGIC: _bindgen_ty_126 = 2;
+pub const FUNCTIONFS_DESCRIPTORS_MAGIC_V2: _bindgen_ty_126 = 3;
+pub type _bindgen_ty_126 = crate::types::c_uint;
 pub const functionfs_flags_FUNCTIONFS_HAS_FS_DESC: functionfs_flags = 1;
 pub const functionfs_flags_FUNCTIONFS_HAS_HS_DESC: functionfs_flags = 2;
 pub const functionfs_flags_FUNCTIONFS_HAS_SS_DESC: functionfs_flags = 4;
diff --git a/src/starnix/lib/linux_uapi/stub/sys/socket.h b/src/starnix/lib/linux_uapi/stub/sys/socket.h
index e69de29..64bd3b1 100644
--- a/src/starnix/lib/linux_uapi/stub/sys/socket.h
+++ b/src/starnix/lib/linux_uapi/stub/sys/socket.h
@@ -0,0 +1,12 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_STARNIX_LIB_LINUX_UAPI_STUB_SYS_SOCKET_H_
+#define SRC_STARNIX_LIB_LINUX_UAPI_STUB_SYS_SOCKET_H_
+
+#define AF_UNSPEC 0
+#define AF_INET 2
+#define AF_INET6 10
+
+#endif  // SRC_STARNIX_LIB_LINUX_UAPI_STUB_SYS_SOCKET_H_
diff --git a/src/starnix/lib/linux_uapi/wrapper.h b/src/starnix/lib/linux_uapi/wrapper.h
index 6ed7caf..b273ced 100644
--- a/src/starnix/lib/linux_uapi/wrapper.h
+++ b/src/starnix/lib/linux_uapi/wrapper.h
@@ -63,6 +63,7 @@
 #include <linux/random.h>
 #include <linux/reboot.h>
 #include <linux/resource.h>
+#include <linux/rtnetlink.h>
 #include <linux/sched.h>
 #include <linux/sched/types.h>
 #include <linux/seccomp.h>
diff --git a/src/starnix/lib/selinux/common/lib.rs b/src/starnix/lib/selinux/common/lib.rs
index 2237540..59096fc 100644
--- a/src/starnix/lib/selinux/common/lib.rs
+++ b/src/starnix/lib/selinux/common/lib.rs
@@ -264,6 +264,8 @@
         /// Permission to use a file as an entry point to the calling domain without performing a
         /// transition.
         ExecuteNoTrans("execute_no_trans"),
+        /// Permission to use a file as an entry point into the new domain on transition.
+        Entrypoint("entrypoint"),
     }
 }
 
diff --git a/src/starnix/lib/selinux/core/security_server.rs b/src/starnix/lib/selinux/core/security_server.rs
index 0277950..c79350c 100644
--- a/src/starnix/lib/selinux/core/security_server.rs
+++ b/src/starnix/lib/selinux/core/security_server.rs
@@ -12,7 +12,8 @@
 use anyhow::Context as _;
 use fuchsia_zircon::{self as zx};
 use selinux_common::{
-    AbstractObjectClass, ClassPermission, FileClass, InitialSid, Permission, FIRST_UNUSED_SID,
+    AbstractObjectClass, ClassPermission, FileClass, InitialSid, ObjectClass, Permission,
+    FIRST_UNUSED_SID,
 };
 use selinux_policy::{
     metadata::HandleUnknown, parse_policy_by_value, parser::ByValue, AccessVector,
@@ -414,6 +415,28 @@
             .context("computing new file security context from policy")
     }
 
+    pub fn compute_new_sid(
+        &self,
+        source_sid: SecurityId,
+        target_sid: SecurityId,
+        target_class: ObjectClass,
+    ) -> Result<SecurityId, anyhow::Error> {
+        let mut state = self.state.lock();
+
+        let policy = state.policy.as_ref().expect("policy should be loaded");
+
+        // Policy is loaded, so `sid_to_security_context()` will not panic.
+        let source_context = state.sid_to_security_context(source_sid);
+        let target_context = state.sid_to_security_context(target_sid);
+
+        policy
+            .parsed
+            .new_security_context(source_context, target_context, &target_class)
+            .map(|sc| state.security_context_to_sid(sc))
+            .map_err(anyhow::Error::from)
+            .context("computing new security context from policy")
+    }
+
     /// Returns a read-only VMO containing the SELinux "status" structure.
     pub fn get_status_vmo(&self) -> Arc<zx::Vmo> {
         self.state.lock().status.get_readonly_vmo()
@@ -528,7 +551,6 @@
     use super::*;
 
     use fuchsia_zircon::AsHandleRef as _;
-    use selinux_common::ObjectClass;
     use std::mem::size_of;
     use zerocopy::{FromBytes, FromZeroes};
 
diff --git a/src/starnix/lib/selinux/policy/host_tests/lib.rs b/src/starnix/lib/selinux/policy/host_tests/lib.rs
index 82e6611..cdd740c 100644
--- a/src/starnix/lib/selinux/policy/host_tests/lib.rs
+++ b/src/starnix/lib/selinux/policy/host_tests/lib.rs
@@ -8,7 +8,7 @@
 };
 
 use anyhow::Context as _;
-use selinux_common::{FileClass, InitialSid, Permission, ProcessPermission};
+use selinux_common::{FileClass, InitialSid, ObjectClass, Permission, ProcessPermission};
 use serde::Deserialize;
 use std::io::Read as _;
 
@@ -303,6 +303,29 @@
 }
 
 #[test]
+fn new_security_context_minimal() {
+    let policy_path =
+        format!("{}/{}/compiled/minimal_policy.pp", TESTDATA_DIR, COMPOSITE_POLICIES_SUBDIR);
+    let policy_bytes = std::fs::read(&policy_path).expect("read policy from file");
+    let policy = parse_policy_by_reference(policy_bytes.as_slice())
+        .expect("parse policy")
+        .validate()
+        .expect("validate policy");
+    let source = policy
+        .parse_security_context("source_u:source_r:source_t:s0:c0-s2:c0.c1".as_bytes())
+        .expect("valid source security context");
+    let target = policy
+        .parse_security_context("target_u:target_r:target_t:s1:c1".as_bytes())
+        .expect("valid target security context");
+
+    let actual = policy
+        .new_security_context(&source, &target, &ObjectClass::Process)
+        .expect("compute new context for new file");
+
+    assert_eq!(source, actual);
+}
+
+#[test]
 fn new_file_security_context_class_defaults() {
     let policy_path =
         format!("{}/{}/compiled/class_defaults_policy.pp", TESTDATA_DIR, COMPOSITE_POLICIES_SUBDIR);
@@ -329,6 +352,32 @@
 }
 
 #[test]
+fn new_security_context_class_defaults() {
+    let policy_path =
+        format!("{}/{}/compiled/class_defaults_policy.pp", TESTDATA_DIR, COMPOSITE_POLICIES_SUBDIR);
+    let policy_bytes = std::fs::read(&policy_path).expect("read policy from file");
+    let policy = parse_policy_by_reference(policy_bytes.as_slice())
+        .expect("parse policy")
+        .validate()
+        .expect("validate policy");
+    let source = policy
+        .parse_security_context("source_u:source_r:source_t:s0:c0-s2:c0.c1".as_bytes())
+        .expect("valid source security context");
+    let target = policy
+        .parse_security_context("target_u:target_r:target_t:s1:c0-s1:c0.c1".as_bytes())
+        .expect("valid target security context");
+
+    let actual = policy
+        .new_security_context(&source, &target, &ObjectClass::Process)
+        .expect("compute new context for new file");
+    let expected: SecurityContext = policy
+        .parse_security_context("target_u:source_r:source_t:s1:c0-s1:c0.c1".as_bytes())
+        .expect("valid expected security context");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
 fn new_file_security_context_role_transition() {
     let policy_path = format!(
         "{}/{}/compiled/role_transition_policy.pp",
@@ -357,6 +406,36 @@
 }
 
 #[test]
+fn new_security_context_role_transition() {
+    let policy_path = format!(
+        "{}/{}/compiled/role_transition_policy.pp",
+        TESTDATA_DIR, COMPOSITE_POLICIES_SUBDIR
+    );
+    let policy_bytes = std::fs::read(&policy_path).expect("read policy from file");
+    let policy = parse_policy_by_reference(policy_bytes.as_slice())
+        .expect("parse policy")
+        .validate()
+        .expect("validate policy");
+    let source = policy
+        .parse_security_context("source_u:source_r:source_t:s0:c0-s2:c0.c1".as_bytes())
+        .expect("valid source security context");
+    let target = policy
+        .parse_security_context("target_u:target_r:target_t:s1:c1".as_bytes())
+        .expect("valid target security context");
+
+    let actual = policy
+        .new_security_context(&source, &target, &ObjectClass::Process)
+        .expect("compute new context for new file");
+    let expected: SecurityContext = policy
+        .parse_security_context("source_u:transition_r:source_t:s0:c0-s2:c0.c1".as_bytes())
+        .expect("valid expected security context");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+// TODO(http://b/334968228): check role allowed separate from SID calculation.
+#[ignore]
 fn new_file_security_context_role_transition_not_allowed() {
     let policy_path = format!(
         "{}/{}/compiled/role_transition_not_allowed_policy.pp",
@@ -417,6 +496,34 @@
 }
 
 #[test]
+fn new_security_context_type_transition() {
+    let policy_path = format!(
+        "{}/{}/compiled/type_transition_policy.pp",
+        TESTDATA_DIR, COMPOSITE_POLICIES_SUBDIR
+    );
+    let policy_bytes = std::fs::read(&policy_path).expect("read policy from file");
+    let policy = parse_policy_by_reference(policy_bytes.as_slice())
+        .expect("parse policy")
+        .validate()
+        .expect("validate policy");
+    let source = policy
+        .parse_security_context("source_u:source_r:source_t:s0:c0-s2:c0.c1".as_bytes())
+        .expect("valid source security context");
+    let target = policy
+        .parse_security_context("target_u:target_r:target_t:s1:c1".as_bytes())
+        .expect("valid target security context");
+
+    let actual = policy
+        .new_security_context(&source, &target, &ObjectClass::Process)
+        .expect("compute new context for new file");
+    let expected: SecurityContext = policy
+        .parse_security_context("source_u:source_r:transition_t:s0:c0-s2:c0.c1".as_bytes())
+        .expect("valid expected security context");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
 fn new_file_security_context_range_transition() {
     let policy_path = format!(
         "{}/{}/compiled/range_transition_policy.pp",
@@ -443,3 +550,31 @@
 
     assert_eq!(expected, actual);
 }
+
+#[test]
+fn new_security_context_range_transition() {
+    let policy_path = format!(
+        "{}/{}/compiled/range_transition_policy.pp",
+        TESTDATA_DIR, COMPOSITE_POLICIES_SUBDIR
+    );
+    let policy_bytes = std::fs::read(&policy_path).expect("read policy from file");
+    let policy = parse_policy_by_reference(policy_bytes.as_slice())
+        .expect("parse policy")
+        .validate()
+        .expect("validate policy");
+    let source = policy
+        .parse_security_context("source_u:source_r:source_t:s0:c0-s2:c0.c1".as_bytes())
+        .expect("valid source security context");
+    let target = policy
+        .parse_security_context("target_u:target_r:target_t:s1:c1".as_bytes())
+        .expect("valid target security context");
+
+    let actual = policy
+        .new_security_context(&source, &target, &ObjectClass::Process)
+        .expect("compute new context for new file");
+    let expected: SecurityContext = policy
+        .parse_security_context("source_u:source_r:source_t:s1:c1-s2:c1.c2".as_bytes())
+        .expect("valid expected security context");
+
+    assert_eq!(expected, actual);
+}
diff --git a/src/starnix/lib/selinux/policy/src/arrays.rs b/src/starnix/lib/selinux/policy/src/arrays.rs
index 3db9f69..8b68961 100644
--- a/src/starnix/lib/selinux/policy/src/arrays.rs
+++ b/src/starnix/lib/selinux/policy/src/arrays.rs
@@ -392,10 +392,16 @@
 }
 
 impl RoleAllow {
+    #[allow(dead_code)]
+    // TODO(http://b/334968228): fn to be used again when checking role allow rules separately from
+    // SID calculation.
     pub(crate) fn source_role(&self) -> RoleId {
         RoleId(NonZeroU32::new(self.role.get()).unwrap())
     }
 
+    #[allow(dead_code)]
+    // TODO(http://b/334968228): fn to be used again when checking role allow rules separately from
+    // SID calculation.
     pub(crate) fn new_role(&self) -> RoleId {
         RoleId(NonZeroU32::new(self.new_role.get()).unwrap())
     }
diff --git a/src/starnix/lib/selinux/policy/src/index.rs b/src/starnix/lib/selinux/policy/src/index.rs
index f3310df..66ce891 100644
--- a/src/starnix/lib/selinux/policy/src/index.rs
+++ b/src/starnix/lib/selinux/policy/src/index.rs
@@ -6,7 +6,7 @@
     error::NewSecurityContextError,
     extensible_bitmap::ExtensibleBitmapSpan,
     parser::ParseStrategy,
-    security_context,
+    security_context::{self, SecurityLevel},
     symbols::{
         Class, ClassDefault, ClassDefaultRange, Classes, CommonSymbol, CommonSymbols, MlsLevel,
         Permission,
@@ -137,77 +137,80 @@
         class: &sc::FileClass,
     ) -> Result<SecurityContext, NewSecurityContextError> {
         let object_class = sc::ObjectClass::from(class.clone());
-        let policy_class = self.class(&object_class);
+        self.new_security_context(
+            source,
+            target,
+            &object_class,
+            // The SELinux notebook states the role component defaults to the object_r role.
+            self.cached_object_r_role,
+            // The SELinux notebook states the type component defaults to the type of the parent
+            // directory.
+            target.type_(),
+            // The SELinux notebook states the range/level component defaults to the low/current
+            // level of the creating process.
+            source.low_level(),
+            None,
+        )
+    }
+
+    /// Calculates a new security context, as follows:
+    ///
+    /// - user: the `source` user, unless the policy contains a default_user statement for `class`.
+    /// - role:
+    ///     - if the policy contains a role_transition from the `source` role to the `target` type,
+    ///       use the transition role
+    ///     - otherwise, if the policy contains a default_role for `class`, use that default role
+    ///     - lastly, if the policy does not contain either, use `default_role`.
+    /// - type:
+    ///     - if the policy contains a type_transition from the `source` type to the `target` type,
+    ///       use the transition type
+    ///     - otherwise, if the policy contains a default_type for `class`, use that default type
+    ///     - lastly, if the policy does not contain either, use `default_type`.
+    /// - range
+    ///     - if the policy contains a range_transition from the `source` type to the `target` type,
+    ///       use the transition range
+    ///     - otherwise, if the policy contains a default_range for `class`, use that default range
+    ///     - lastly, if the policy does not contain either, use the `default_low_level` -
+    ///       `default_high_level` range.
+    pub fn new_security_context(
+        &self,
+        source: &SecurityContext,
+        target: &SecurityContext,
+        class: &sc::ObjectClass,
+        default_role: RoleId,
+        default_type: TypeId,
+        default_low_level: &SecurityLevel,
+        default_high_level: Option<&SecurityLevel>,
+    ) -> Result<SecurityContext, NewSecurityContextError> {
+        let policy_class = self.class(&class);
         let class_defaults = policy_class.defaults();
 
-        // The SELinux notebook states:
-        //
-        // The user component is inherited from the creating process (policy version 27 allows a
-        // default_user of source or target to be defined for each object class).
         let user = match class_defaults.user() {
             ClassDefault::Source => source.user(),
             ClassDefault::Target => target.user(),
             _ => source.user(),
         };
 
-        // The SELinux notebook states:
-        //
-        // The role component generally defaults to the object_r role (policy version 26 allows a
-        // role_transition and version 27 allows a default_role of source or target to be defined
-        // for each object class).
         let role = match self.role_transition_new_role(source.role(), target.type_(), policy_class)
         {
-            Some(new_role) => {
-                if !self.role_transition_is_explicitly_allowed(source.role(), new_role) {
-                    return Err(NewSecurityContextError::RoleTransitionNotAllowed {
-                        source_security_context: source.clone(),
-                        target_security_context: target.clone(),
-                        source_role: String::from_utf8(
-                            self.parsed_policy.role(source.role()).name_bytes().to_vec(),
-                        )
-                        .unwrap(),
-                        new_role: String::from_utf8(
-                            self.parsed_policy.role(new_role).name_bytes().to_vec(),
-                        )
-                        .unwrap(),
-                    });
-                }
-
-                new_role
-            }
+            Some(new_role) => new_role,
             None => match class_defaults.role() {
                 ClassDefault::Source => source.role(),
                 ClassDefault::Target => target.role(),
-                _ => self.cached_object_r_role,
+                _ => default_role,
             },
         };
 
-        // The SELinux notebook states:
-        //
-        // The type component defaults to the type of the parent directory if no matching
-        // type_transition rule was specified in the policy (policy version 25 allows a filename
-        // type_transition rule and version 28 allows a default_type of source or target to be
-        // defined for each object class).
         let type_ =
             match self.type_transition_new_type(source.type_(), target.type_(), policy_class) {
                 Some(new_type) => new_type,
-                None => {
-                    match class_defaults.type_() {
-                        ClassDefault::Source => source.type_(),
-                        ClassDefault::Target => target.type_(),
-                        // The "parent directory" in this context is the target. (The source is the
-                        // process creating the file-like object.)
-                        _ => target.type_(),
-                    }
-                }
+                None => match class_defaults.type_() {
+                    ClassDefault::Source => source.type_(),
+                    ClassDefault::Target => target.type_(),
+                    _ => default_type,
+                },
             };
 
-        // The SELinux notebook states:
-        //
-        // The range/level component defaults to the low/current level of the creating process if no
-        // matching range_transition rule was specified in the policy (policy version 27 allows a
-        // default_range of source or target with the selected range being low, high or low-high to
-        // be defined for each object class).
         let (low_level, high_level) =
             match self.range_transition_new_range(source.type_(), target.type_(), policy_class) {
                 Some((low_level, high_level)) => (low_level, high_level),
@@ -226,7 +229,7 @@
                     ClassDefaultRange::TargetLowHigh => {
                         (target.low_level().clone(), target.high_level().map(Clone::clone))
                     }
-                    _ => (source.low_level().clone(), None),
+                    _ => (default_low_level.clone(), default_high_level.map(Clone::clone)),
                 },
             };
 
@@ -287,6 +290,9 @@
             .map(|x| x.new_role())
     }
 
+    #[allow(dead_code)]
+    // TODO(http://b/334968228): fn to be used again when checking role allow rules separately from
+    // SID calculation.
     fn role_transition_is_explicitly_allowed(&self, source_role: RoleId, new_role: RoleId) -> bool {
         self.parsed_policy
             .role_allowlist()
diff --git a/src/starnix/lib/selinux/policy/src/lib.rs b/src/starnix/lib/selinux/policy/src/lib.rs
index 1245187..0e4c97f 100644
--- a/src/starnix/lib/selinux/policy/src/lib.rs
+++ b/src/starnix/lib/selinux/policy/src/lib.rs
@@ -23,7 +23,7 @@
     parsed_policy::ParsedPolicy,
     parser::ByValue,
     parser::{ByRef, ParseStrategy},
-    selinux_common::{self as sc, ClassPermission as _, FileClass},
+    selinux_common::{self as sc, ClassPermission as _, FileClass, ObjectClass},
     std::{fmt::Debug, marker::PhantomData, num::NonZeroU32, ops::Deref},
     zerocopy::{little_endian as le, ByteSlice, FromBytes, NoCell, Ref, Unaligned},
 };
@@ -218,6 +218,31 @@
         self.0.new_file_security_context(source, target, class)
     }
 
+    /// Returns the security context that should be applied to a newly created SELinux
+    /// object according to `source` and `target` security contexts, as well as the new object's
+    /// `class`.
+    /// Defaults to the `source` security context if the policy does not specify transitions or
+    /// defaults for the `source`, `target` or `class` components.
+    ///
+    /// Returns an error if the security context for such an object is not well-defined
+    /// by this [`Policy`].
+    pub fn new_security_context(
+        &self,
+        source: &SecurityContext,
+        target: &SecurityContext,
+        class: &ObjectClass,
+    ) -> Result<SecurityContext, NewSecurityContextError> {
+        self.0.new_security_context(
+            source,
+            target,
+            class,
+            source.role(),
+            source.type_(),
+            source.low_level(),
+            source.high_level(),
+        )
+    }
+
     /// Returns whether the input types are explicitly granted `permission` via an `allow [...];`
     /// policy statement.
     ///
diff --git a/src/starnix/lib/selinux/policy/src/parsed_policy.rs b/src/starnix/lib/selinux/policy/src/parsed_policy.rs
index 2a43ed5..6494f65 100644
--- a/src/starnix/lib/selinux/policy/src/parsed_policy.rs
+++ b/src/starnix/lib/selinux/policy/src/parsed_policy.rs
@@ -335,6 +335,9 @@
         &self.conditional_booleans.data
     }
 
+    #[allow(dead_code)]
+    // TODO(http://b/334968228): fn to be used again when checking role allow rules separately from
+    // SID calculation.
     pub(crate) fn role_allowlist(&self) -> &[RoleAllow] {
         PS::deref_slice(&self.role_allowlist.data)
     }
diff --git a/src/starnix/lib/selinux/testdata/composite_policies/compiled/class_defaults_policy.pp b/src/starnix/lib/selinux/testdata/composite_policies/compiled/class_defaults_policy.pp
index 06d2350..87b07b2 100644
--- a/src/starnix/lib/selinux/testdata/composite_policies/compiled/class_defaults_policy.pp
+++ b/src/starnix/lib/selinux/testdata/composite_policies/compiled/class_defaults_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/composite_policies/compiled/range_transition_policy.pp b/src/starnix/lib/selinux/testdata/composite_policies/compiled/range_transition_policy.pp
index 6d16324..8b0ccf4 100644
--- a/src/starnix/lib/selinux/testdata/composite_policies/compiled/range_transition_policy.pp
+++ b/src/starnix/lib/selinux/testdata/composite_policies/compiled/range_transition_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/composite_policies/compiled/role_transition_policy.pp b/src/starnix/lib/selinux/testdata/composite_policies/compiled/role_transition_policy.pp
index 76021a2..467a67c 100644
--- a/src/starnix/lib/selinux/testdata/composite_policies/compiled/role_transition_policy.pp
+++ b/src/starnix/lib/selinux/testdata/composite_policies/compiled/role_transition_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/composite_policies/compiled/type_transition_policy.pp b/src/starnix/lib/selinux/testdata/composite_policies/compiled/type_transition_policy.pp
index 15e3c5b..499d711 100644
--- a/src/starnix/lib/selinux/testdata/composite_policies/compiled/type_transition_policy.pp
+++ b/src/starnix/lib/selinux/testdata/composite_policies/compiled/type_transition_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/composite_policies/new_file/class_defaults_policy.conf b/src/starnix/lib/selinux/testdata/composite_policies/new_file/class_defaults_policy.conf
index a3a205c..29d981b 100644
--- a/src/starnix/lib/selinux/testdata/composite_policies/new_file/class_defaults_policy.conf
+++ b/src/starnix/lib/selinux/testdata/composite_policies/new_file/class_defaults_policy.conf
@@ -19,3 +19,8 @@
 default_role file source;
 default_type file source;
 default_range file target low-high;
+
+default_user process target;
+default_role process source;
+default_type process source;
+default_range process target low-high;
\ No newline at end of file
diff --git a/src/starnix/lib/selinux/testdata/composite_policies/new_file/range_transition_policy.conf b/src/starnix/lib/selinux/testdata/composite_policies/new_file/range_transition_policy.conf
index 7baccfd..50a104a 100644
--- a/src/starnix/lib/selinux/testdata/composite_policies/new_file/range_transition_policy.conf
+++ b/src/starnix/lib/selinux/testdata/composite_policies/new_file/range_transition_policy.conf
@@ -19,3 +19,4 @@
 user target_u roles { target_r } level s0 range s0 - s2:c0.c2;
 
 range_transition source_t target_t:file s1:c1 - s2:c1.c2;
+range_transition source_t target_t:process s1:c1 - s2:c1.c2;
diff --git a/src/starnix/lib/selinux/testdata/composite_policies/new_file/role_transition_policy.conf b/src/starnix/lib/selinux/testdata/composite_policies/new_file/role_transition_policy.conf
index f4c28b0..56a4b39 100644
--- a/src/starnix/lib/selinux/testdata/composite_policies/new_file/role_transition_policy.conf
+++ b/src/starnix/lib/selinux/testdata/composite_policies/new_file/role_transition_policy.conf
@@ -24,5 +24,7 @@
 # context, the parent directory) type is `target_t`, target class is `file`, new
 # file role should be `transition_r`.
 role_transition source_r target_t:file transition_r;
+# Similar for target class `process`.
+role_transition source_r target_t:process transition_r;
 # Allow the above-mentioned role transition.
 allow source_r transition_r;
diff --git a/src/starnix/lib/selinux/testdata/composite_policies/new_file/type_transition_policy.conf b/src/starnix/lib/selinux/testdata/composite_policies/new_file/type_transition_policy.conf
index 1b9c57b..35edf7c 100644
--- a/src/starnix/lib/selinux/testdata/composite_policies/new_file/type_transition_policy.conf
+++ b/src/starnix/lib/selinux/testdata/composite_policies/new_file/type_transition_policy.conf
@@ -20,3 +20,4 @@
 user target_u roles { target_r } level s0 range s0 - s2:c0.c2;
 
 type_transition source_t target_t:file transition_t;
+type_transition source_t target_t:process transition_t;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_no_defaults_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_no_defaults_policy.conf
index 77e255c..d7e5370 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_no_defaults_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_no_defaults_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 sensitivity s0;
 sensitivity s1;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_no_defaults_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_no_defaults_policy.pp
index a07f43c..83e63f9 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_no_defaults_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_no_defaults_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_high_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_high_policy.conf
index d725e58..09b7e77 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_high_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_high_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 default_range file source high;
 sensitivity s0;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_high_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_high_policy.pp
index e62e261..6697a45 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_high_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_high_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_high_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_high_policy.conf
index 7e47616..ef31f9e 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_high_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_high_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 default_range file source low-high;
 sensitivity s0;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_high_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_high_policy.pp
index 979fcf8..a9b6653 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_high_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_high_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_policy.conf
index b4f9413..5008e26 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 default_range file source low;
 sensitivity s0;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_policy.pp
index 564c36e..99cfb88 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_source_low_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_high_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_high_policy.conf
index 64dada1..f981664 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_high_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_high_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 default_range file target high;
 sensitivity s0;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_high_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_high_policy.pp
index e32d7ba..9c0c663 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_high_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_high_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_high_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_high_policy.conf
index 34527d1..2e36303 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_high_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_high_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 default_range file target low-high;
 sensitivity s0;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_high_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_high_policy.pp
index 8e62ff0..9723d93 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_high_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_high_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_policy.conf
index 05508e5..a7ef01b 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 default_range file target low;
 sensitivity s0;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_policy.pp
index fa52166..26f49d3 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_range_target_low_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_source_defaults_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_source_defaults_policy.conf
index 238101d..994f910 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_source_defaults_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_source_defaults_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 default_user file source;
 default_role file source;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_source_defaults_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_source_defaults_policy.pp
index c5f43c36..0d9fd17 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_source_defaults_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_source_defaults_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_target_defaults_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/file_target_defaults_policy.conf
index ba63a6f..db5e796 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_target_defaults_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_target_defaults_policy.conf
@@ -34,7 +34,7 @@
 sid scmp_packet
 sid devnull
 common file { create open }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
 default_user file target;
 default_role file target;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/file_target_defaults_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/file_target_defaults_policy.pp
index d8137d0..3d7f194 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/file_target_defaults_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/file_target_defaults_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/hooks_tests_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/hooks_tests_policy.conf
index e3c7e33..5407990 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/hooks_tests_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/hooks_tests_policy.conf
@@ -35,16 +35,18 @@
 sid devnull
 common file { create open }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 sensitivity s0;
 dominance { s0 }
 category c0;
 level s0:c0;
 mlsconstrain process { fork } l1 == l2;
 type exec_no_trans_source_t;
+type exec_transition_denied_target_t;
 type exec_transition_source_t;
 type exec_transition_target_t;
 type executable_file_no_trans_t;
+type executable_file_trans_no_entrypoint_t;
 type executable_file_trans_t;
 type fork_no_t;
 type fork_yes_t;
@@ -73,7 +75,9 @@
 type test_setsched_target_t;
 type test_setsched_yes_t;
 allow exec_no_trans_source_t executable_file_no_trans_t:file { execute_no_trans };
+allow exec_transition_denied_target_t executable_file_trans_t:file { entrypoint };
 allow exec_transition_source_t exec_transition_target_t:process { transition };
+allow exec_transition_target_t executable_file_trans_t:file { entrypoint };
 allow fork_yes_t self:process { fork };
 allow test_getpgid_yes_t test_getpgid_target_t:process { getpgid };
 allow test_getsched_yes_t test_getsched_target_t:process { getsched };
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/hooks_tests_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/hooks_tests_policy.pp
index 75f6284..5cd4b6a 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/hooks_tests_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/hooks_tests_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/multiple_levels_and_categories_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/multiple_levels_and_categories_policy.conf
index 71e79bc..b134a6c 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/multiple_levels_and_categories_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/multiple_levels_and_categories_policy.conf
@@ -36,7 +36,7 @@
 sid devnull
 common file { create open }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class class0 { perm0 }
 sensitivity s0;
 sensitivity s1;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/multiple_levels_and_categories_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/multiple_levels_and_categories_policy.pp
index bf8c760..ecaffc2 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/multiple_levels_and_categories_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/multiple_levels_and_categories_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/security_context_tests_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/security_context_tests_policy.conf
index 7c0574c..c1cea53 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/security_context_tests_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/security_context_tests_policy.conf
@@ -36,7 +36,7 @@
 sid devnull
 common file { create open }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class class0 { perm0 }
 sensitivity s0;
 sensitivity s1;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/security_context_tests_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/security_context_tests_policy.pp
index 85b7d8e..17dc1c9 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/security_context_tests_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/security_context_tests_policy.pp
Binary files differ
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/security_server_tests_policy.conf b/src/starnix/lib/selinux/testdata/micro_policies/security_server_tests_policy.conf
index c95ae20..485db84 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/security_server_tests_policy.conf
+++ b/src/starnix/lib/selinux/testdata/micro_policies/security_server_tests_policy.conf
@@ -36,7 +36,7 @@
 sid devnull
 common file { create open }
 class process { fork transition getsched setsched getpgid setpgid sigchld sigkill sigstop signal ptrace }
-class file inherits file { execute_no_trans }
+class file inherits file { execute_no_trans entrypoint }
 class class0 { perm0 }
 sensitivity s0;
 sensitivity s1;
diff --git a/src/starnix/lib/selinux/testdata/micro_policies/security_server_tests_policy.pp b/src/starnix/lib/selinux/testdata/micro_policies/security_server_tests_policy.pp
index 5ad99f9..71bd7c5 100644
--- a/src/starnix/lib/selinux/testdata/micro_policies/security_server_tests_policy.pp
+++ b/src/starnix/lib/selinux/testdata/micro_policies/security_server_tests_policy.pp
Binary files differ
diff --git a/src/starnix/tests/selinux/expectations/selinux.json5 b/src/starnix/tests/selinux/expectations/selinux.json5
index 7a73768..5a7e185 100644
--- a/src/starnix/tests/selinux/expectations/selinux.json5
+++ b/src/starnix/tests/selinux/expectations/selinux.json5
@@ -12,9 +12,9 @@
         {
             type: "expect_failure",
             matchers: [
+                // TODO(http://b/330904217): update `entrypoint` expectation to pass once filesystems are labeled correctly.
                 "*selinux_entrypoint*",
                 "*selinux_execshare*",
-                "*selinux_exectrace*",
 
                 // TODO(http://b/330904217): update `execute_no_trans` expectation to pass once filesystems are labeled correctly.
                 "*selinux_execute_no_trans*",
diff --git a/src/starnix/tests/syscalls/cpp/expectations/syscalls_cpp_test.json5 b/src/starnix/tests/syscalls/cpp/expectations/syscalls_cpp_test.json5
index c6dd1ad..7b971ad 100644
--- a/src/starnix/tests/syscalls/cpp/expectations/syscalls_cpp_test.json5
+++ b/src/starnix/tests/syscalls/cpp/expectations/syscalls_cpp_test.json5
@@ -53,6 +53,21 @@
                 // TODO(https://fxbug.dev/333037315)
                 "OverlayFs/FsMountTest.OpenWithTruncAndCreatWithExistingFileSucceeds/0",
                 "OverlayFs/FsMountTest.OpenWithTruncAndCreatOnReadOnlyFsReturnsEROFS/0",
+
+                // TODO(https://fxbug.dev/331965660)
+                "FuseServerPermissionCheck/FuseServerPermissionCheck.PermissionCheck/0",
+                "FuseServerPermissionCheck/FuseServerPermissionCheck.PermissionCheck/1",
+                "FuseServerPermissionCheck/FuseServerPermissionCheck.PermissionCheck/2",
+                "FuseServerPermissionCheck/FuseServerPermissionCheck.PermissionCheck/3",
+                "FuseServerPermissionCheck/FuseServerPermissionCheck.PermissionCheck/8",
+                "FuseServerPermissionCheck/FuseServerPermissionCheck.PermissionCheck/9",
+                "FuseServerPermissionCheck/FuseServerPermissionCheck.PermissionCheck/10",
+                "FuseServerPermissionCheck/FuseServerPermissionCheck.PermissionCheck/11",
+
+                // TODO(https://fxbug.dev/335701084)
+                "VmspliceTest.ModifyBufferInPipe",
+                "VmspliceTest.UnmapBufferInPipe",
+                "VmspliceTest.UnmapBufferInPipeThenMapInPlace",
             ],
         },
     ],
diff --git a/src/starnix/tests/syscalls/cpp/fuse_test.cc b/src/starnix/tests/syscalls/cpp/fuse_test.cc
index 806905c..7b7fe7f 100644
--- a/src/starnix/tests/syscalls/cpp/fuse_test.cc
+++ b/src/starnix/tests/syscalls/cpp/fuse_test.cc
@@ -13,9 +13,13 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
+#include <algorithm>
+#include <condition_variable>
 #include <cstddef>
 #include <cstdint>
 #include <memory>
+#include <mutex>
+#include <optional>
 #include <thread>
 #include <vector>
 
@@ -132,6 +136,10 @@
 
 class FuseServer {
  public:
+  FuseServer() : FuseServer(0, S_IFREG) {}
+  FuseServer(uint32_t want_init_flags, uint32_t file_type)
+      : want_init_flags_(want_init_flags), file_type_(file_type) {}
+
   virtual ~FuseServer() {}
 
   const test_helper::ScopedFD& fuse_fd() { return fuse_fd_; }
@@ -164,6 +172,25 @@
     return true;
   }
 
+  template <typename R = void>
+  R WaitForInit(std::function<R()> f = std::function<R()>()) {
+    std::unique_lock guard(init_mtx_);
+    init_cv_.wait(guard, [&]() { return init_done_; });
+    if (f) {
+      return f();
+    }
+    return R();
+  }
+
+  testing::AssertionResult SendInitResponse(const fuse_in_header* in_header, uint32_t flags) {
+    fuse_init_out init_out = {
+        .major = FUSE_KERNEL_VERSION,
+        .minor = FUSE_KERNEL_MINOR_VERSION,
+        .flags = flags,
+    };
+    return WriteStructResponse(in_header, init_out);
+  }
+
  protected:
   virtual testing::AssertionResult HandleFuseMessage(const std::vector<std::byte>& message) {
     const struct fuse_in_header* in_header =
@@ -183,10 +210,17 @@
         OK_OR_RETURN(HandleAccess(in_header, &access_in, message));
         break;
       }
+      case FUSE_GETATTR: {
+        struct fuse_getattr_in getattr_in = {};
+        memcpy(&getattr_in, in_payload, sizeof(getattr_in));
+        OK_OR_RETURN(HandleGetAttr(in_header, &getattr_in, message));
+        break;
+      }
       case FUSE_LOOKUP: {
         OK_OR_RETURN(HandleLookup(in_header, message));
         break;
       }
+      case FUSE_OPENDIR:
       case FUSE_OPEN: {
         struct fuse_open_in open_in = {};
         memcpy(&open_in, in_payload, sizeof(open_in));
@@ -199,25 +233,43 @@
         OK_OR_RETURN(HandleFlush(in_header, &flush_in, message));
         break;
       }
+      case FUSE_RELEASEDIR:
       case FUSE_RELEASE: {
         struct fuse_release_in release_in = {};
         memcpy(&release_in, in_payload, sizeof(release_in));
         OK_OR_RETURN(HandleRelease(in_header, &release_in, message));
         break;
       }
+      case FUSE_GETXATTR: {
+        OK_OR_RETURN(WriteDataFreeResponse(in_header, -ENOSYS));
+        break;
+      }
+      case FUSE_BATCH_FORGET:
+      case FUSE_FORGET:
+        // no-op; these don't expect a response.
+        break;
       default:
         return testing::AssertionFailure() << "Unknown FUSE opcode: " << in_header->opcode;
     }
     return testing::AssertionSuccess();
   }
 
+  void NotifyInitWaiters(std::function<void()> f = std::function<void()>()) {
+    std::unique_lock guard(init_mtx_);
+    init_done_ = true;
+    if (f) {
+      f();
+    }
+    init_cv_.notify_all();
+  }
+
   virtual testing::AssertionResult HandleInit(const struct fuse_in_header* in_header,
                                               const struct fuse_init_in* init_in,
                                               const std::vector<std::byte>& message) {
-    struct fuse_init_out init_out = {};
-    init_out.major = FUSE_KERNEL_VERSION;
-    init_out.minor = FUSE_KERNEL_MINOR_VERSION;
-    return WriteStructResponse(in_header, init_out);
+    EXPECT_EQ(init_in->flags & want_init_flags_, want_init_flags_);
+    OK_OR_RETURN(SendInitResponse(in_header, want_init_flags_));
+    NotifyInitWaiters();
+    return testing::AssertionSuccess();
   }
 
   virtual testing::AssertionResult HandleAccess(const struct fuse_in_header* in_header,
@@ -226,13 +278,18 @@
     return WriteAckResponse(in_header);
   }
 
+  virtual testing::AssertionResult HandleGetAttr(const struct fuse_in_header* in_header,
+                                                 const struct fuse_getattr_in* getattr_in,
+                                                 const std::vector<std::byte>& message) {
+    fuse_attr_out attr_out = {};
+    PopulateDefaultAttr(in_header->nodeid, attr_out.attr);
+    return WriteStructResponse(in_header, attr_out);
+  }
+
   virtual testing::AssertionResult HandleLookup(const struct fuse_in_header* in_header,
                                                 const std::vector<std::byte>& message) {
-    struct fuse_entry_out entry_out = {};
-    entry_out.nodeid = next_nodeid_++;
-    entry_out.generation = 1;
-    entry_out.attr.ino = entry_out.nodeid;
-    entry_out.attr.mode = S_IFREG;
+    fuse_entry_out entry_out;
+    PopulateDefaultEntry(entry_out);
     return WriteStructResponse(in_header, entry_out);
   }
 
@@ -298,6 +355,26 @@
 
   uint64_t GetNextFileHandle() { return next_fh_++; }
 
+  void PopulateDefaultEntry(fuse_entry_out& entry_out) {
+    entry_out = {
+        .nodeid = next_nodeid_++,
+        .generation = 1,
+    };
+    PopulateDefaultAttr(entry_out.nodeid, entry_out.attr);
+  }
+
+  void PopulateDefaultAttr(uint64_t ino, fuse_attr& attr) {
+    attr = {
+        .ino = ino,
+        // Consider the root node as a directory and everything else as the
+        // specified kind. The node will also have read/write/exec permissions
+        // for the owning user, group and world. For current testing needs,
+        // this is sufficient.
+        .mode = static_cast<uint32_t>(ino == FUSE_ROOT_ID ? S_IFDIR : file_type_) | S_IRWXU |
+                S_IRWXG | S_IRWXO,
+    };
+  }
+
  private:
   testing::AssertionResult ReadRequest(std::vector<std::byte>* request, bool* unmounted) {
     // There doesn't seem to be a good value to use for the max request size. We just pick
@@ -330,6 +407,13 @@
   test_helper::ScopedFD fuse_fd_;
   uint64_t next_fh_ = 1;
   uint64_t next_nodeid_ = 2;  // 1 is reserved for the root.
+
+  std::mutex init_mtx_;
+  std::condition_variable init_cv_;
+  bool init_done_ = false;
+
+  uint32_t want_init_flags_;
+  uint32_t file_type_;
 };
 
 class FuseServerTest : public ::testing::Test {
@@ -637,6 +721,49 @@
   ASSERT_EQ(errno, ENODATA);
 }
 
+TEST_F(FuseServerTest, NoReqsUntilInitResponse) {
+  class NoReqsUntilInitResponseServer : public FuseServer {
+   public:
+    fuse_in_header WaitForInitAndReturnRequestHeader() {
+      return WaitForInit(std::function<fuse_in_header()>([&]() { return init_hdr_; }));
+    }
+
+   protected:
+    testing::AssertionResult HandleInit(const struct fuse_in_header* in_header,
+                                        const struct fuse_init_in* init_in,
+                                        const std::vector<std::byte>& message) {
+      // Don't actually complete the request, just store the init request's header so
+      // that we can respond to it later.
+      NotifyInitWaiters([&]() { init_hdr_ = *in_header; });
+      return testing::AssertionSuccess();
+    }
+
+   private:
+    fuse_in_header init_hdr_;
+  };
+
+  std::shared_ptr<NoReqsUntilInitResponseServer> server(new NoReqsUntilInitResponseServer());
+  ASSERT_TRUE(Mount(server));
+  const fuse_in_header init_hdr = server->WaitForInitAndReturnRequestHeader();
+
+  // Create a new thread to perform a request against the FUSE server.
+  std::atomic_bool access_done = false;
+  std::thread thrd([&]() {
+    std::string filename = GetMountDir() + "/file";
+    EXPECT_EQ(access(filename.c_str(), R_OK), 0) << strerror(errno);
+    access_done = true;
+  });
+  // Make sure that the request is not completed.
+  sleep(1);
+  EXPECT_FALSE(access_done);
+
+  // Send our (delayed) response to the FUSE_INIT request and make sure that the
+  // access request is now completed.
+  server->SendInitResponse(&init_hdr, 0);
+  thrd.join();
+  EXPECT_TRUE(access_done);
+}
+
 TEST_F(FuseServerTest, OpenAndClose) {
   ASSERT_TRUE(Mount(std::make_shared<FuseServer>()));
 
@@ -700,40 +827,306 @@
   fd.reset();
 }
 
-TEST_F(FuseServerTest, BypassUnimplementedAccess) {
-  class BypassUnimplementedAccessServer : public FuseServer {
-   public:
-    uint64_t AccessCount() { return calls_to_access_.load(std::memory_order_relaxed); }
-
-   protected:
-    testing::AssertionResult HandleAccess(const struct fuse_in_header* in_header,
-                                          const struct fuse_access_in* access_in,
-                                          const std::vector<std::byte>& message) override {
-      calls_to_access_.fetch_add(1, std::memory_order_relaxed);
-      return WriteDataFreeResponse(in_header, -ENOSYS);
-    }
-
-   private:
-    std::atomic_uint64_t calls_to_access_;
-  };
-
-  std::shared_ptr<BypassUnimplementedAccessServer> server(new BypassUnimplementedAccessServer());
-  ASSERT_TRUE(Mount(server));
-  EXPECT_EQ(server->AccessCount(), 0u);
-
-  // Run the checks in a separate thread where we drop the |CAP_DAC_OVERRIDE|
-  // capability which bypasses file permission checks. See capabilities(7).
+// Run the checks in a separate thread where we drop the |CAP_DAC_OVERRIDE|
+// capability which bypasses file permission checks. See capabilities(7).
+template <typename F>
+void InThreadWithoutCapDacOverride(F f) {
   std::thread thrd([&]() {
     test_helper::UnsetCapability(CAP_DAC_OVERRIDE);
 
-    auto check_access = [&](const char* file) {
+    f();
+  });
+  thrd.join();
+}
+
+struct BypassAccessTestCase {
+  uint32_t want_init_flags;
+  int access_reply;
+  uint64_t max_access_count;
+};
+
+class CountingFuseServer : public FuseServer {
+ public:
+  CountingFuseServer(uint32_t want_init_flags, uint32_t file_type, int access_reply)
+      : FuseServer(want_init_flags, file_type), access_reply_(access_reply) {}
+
+  uint64_t LookupCount() { return calls_to_lookup_.load(std::memory_order_relaxed); }
+  uint64_t AccessCount() { return calls_to_access_.load(std::memory_order_relaxed); }
+  uint64_t NonRootGetAttrCount() {
+    return calls_to_non_root_getattr_.load(std::memory_order_relaxed);
+  }
+
+ protected:
+  testing::AssertionResult HandleLookup(const struct fuse_in_header* in_header,
+                                        const std::vector<std::byte>& message) override {
+    calls_to_lookup_.fetch_add(1, std::memory_order_relaxed);
+    return FuseServer::HandleLookup(in_header, message);
+  }
+
+  testing::AssertionResult HandleAccess(const struct fuse_in_header* in_header,
+                                        const struct fuse_access_in* access_in,
+                                        const std::vector<std::byte>& message) override {
+    calls_to_access_.fetch_add(1, std::memory_order_relaxed);
+    return WriteDataFreeResponse(in_header, access_reply_);
+  }
+
+  testing::AssertionResult HandleGetAttr(const struct fuse_in_header* in_header,
+                                         const struct fuse_getattr_in* getattr_in,
+                                         const std::vector<std::byte>& message) override {
+    if (in_header->nodeid != FUSE_ROOT_ID) {
+      calls_to_non_root_getattr_.fetch_add(1, std::memory_order_relaxed);
+    }
+    return FuseServer::HandleGetAttr(in_header, getattr_in, message);
+  }
+
+ private:
+  int access_reply_;
+  std::atomic_uint64_t calls_to_lookup_ = 0;
+  std::atomic_uint64_t calls_to_access_ = 0;
+  std::atomic_uint64_t calls_to_non_root_getattr_ = 0;
+};
+
+struct PermissionCheckTestCase {
+  std::optional<uint32_t> need_cap;
+  uint32_t want_init_flags;
+  uint32_t file_type;
+  std::function<void(const std::string&)> fn;
+  uint64_t expected_lookup_count;
+  uint64_t expected_access_count;
+  uint64_t expected_non_root_getattr_count;
+};
+
+class FuseServerPermissionCheck : public FuseServerTest,
+                                  public ::testing::WithParamInterface<PermissionCheckTestCase> {};
+
+TEST_P(FuseServerPermissionCheck, PermissionCheck) {
+  const PermissionCheckTestCase& test_case = GetParam();
+
+  if (test_case.need_cap && !test_helper::HasCapability(test_case.need_cap.value())) {
+    GTEST_SKIP() << "Need extra capability " << test_case.need_cap.value();
+  }
+
+  std::shared_ptr<CountingFuseServer> server(
+      new CountingFuseServer(test_case.want_init_flags, test_case.file_type, 0));
+  ASSERT_TRUE(Mount(server));
+  server->WaitForInit();
+  EXPECT_EQ(server->LookupCount(), 0u);
+  EXPECT_EQ(server->AccessCount(), 0u);
+  EXPECT_EQ(server->NonRootGetAttrCount(), 0u);
+
+  std::string path = GetMountDir() + "/node";
+  ASSERT_NO_FATAL_FAILURE(test_case.fn(path));
+  EXPECT_EQ(server->LookupCount(), test_case.expected_lookup_count);
+  EXPECT_EQ(server->AccessCount(), test_case.expected_access_count);
+  EXPECT_EQ(server->NonRootGetAttrCount(), test_case.expected_non_root_getattr_count);
+}
+
+void TestChdir(const std::string& path) {
+  test_helper::ForkHelper fork_helper;
+  // Run in a forked process to not modify the state of the current
+  // process which may run other tests.
+  fork_helper.RunInForkedProcess([&] { ASSERT_EQ(chdir(path.c_str()), 0) << strerror(errno); });
+  ASSERT_TRUE(fork_helper.WaitForChildren());
+}
+
+void TestChroot(const std::string& path) {
+  test_helper::ForkHelper fork_helper;
+  // Run in a forked process to not modify the state of the current
+  // process which may run other tests.
+  fork_helper.RunInForkedProcess([&] { ASSERT_EQ(chroot(path.c_str()), 0) << strerror(errno); });
+  ASSERT_TRUE(fork_helper.WaitForChildren());
+}
+
+void TestAccess(const std::string& path) {
+  ASSERT_EQ(access(path.c_str(), R_OK), 0) << strerror(errno);
+}
+
+void TestStat(const std::string& path) {
+  struct stat s;
+  ASSERT_EQ(stat(path.c_str(), &s), 0) << strerror(errno);
+}
+
+void TestOpenWithFlags(const std::string& path, int flags) {
+  test_helper::ScopedFD fd(open(path.c_str(), flags));
+  ASSERT_TRUE(fd.is_valid());
+}
+
+INSTANTIATE_TEST_SUITE_P(FuseServerPermissionCheck, FuseServerPermissionCheck,
+                         testing::Values(
+                             // When performing a path walk, we should only use |FUSE_LOOKUP|
+                             // for _initial_ permission/access checking.
+                             PermissionCheckTestCase{
+                                 .want_init_flags = 0,
+                                 .file_type = S_IFREG,
+                                 .fn =
+                                     [](const std::string& path) {
+                                       ASSERT_NO_FATAL_FAILURE(TestOpenWithFlags(path, O_RDWR));
+                                     },
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 0,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = 0,
+                                 .file_type = S_IFDIR,
+                                 .fn =
+                                     [](const std::string& path) {
+                                       ASSERT_NO_FATAL_FAILURE(TestOpenWithFlags(path, O_RDONLY));
+                                     },
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 0,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = 0,
+                                 .file_type = S_IFREG,
+                                 .fn = TestStat,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = 0,
+                                 .file_type = S_IFDIR,
+                                 .fn = TestStat,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+                             // These are the same as the above, but with the `FUSE_POSIX_ACL`
+                             // init flag set.
+                             PermissionCheckTestCase{
+                                 .want_init_flags = FUSE_POSIX_ACL,
+                                 .file_type = S_IFREG,
+                                 .fn =
+                                     [](const std::string& path) {
+                                       ASSERT_NO_FATAL_FAILURE(TestOpenWithFlags(path, O_RDWR));
+                                     },
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = FUSE_POSIX_ACL,
+                                 .file_type = S_IFDIR,
+                                 .fn =
+                                     [](const std::string& path) {
+                                       ASSERT_NO_FATAL_FAILURE(TestOpenWithFlags(path, O_RDONLY));
+                                     },
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = FUSE_POSIX_ACL,
+                                 .file_type = S_IFREG,
+                                 .fn = TestStat,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = FUSE_POSIX_ACL,
+                                 .file_type = S_IFDIR,
+                                 .fn = TestStat,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+
+                             // Only the |access|, |chdir| and |chroot| family of
+                             // syscalls may trigger |FUSE_ACCESS|.
+                             PermissionCheckTestCase{
+                                 .want_init_flags = 0,
+                                 .file_type = S_IFREG,
+                                 .fn = TestAccess,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 1,
+                                 .expected_non_root_getattr_count = 0,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = 0,
+                                 .file_type = S_IFDIR,
+                                 .fn = TestAccess,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 1,
+                                 .expected_non_root_getattr_count = 0,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = 0,
+                                 .file_type = S_IFDIR,
+                                 .fn = TestChdir,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 1,
+                                 .expected_non_root_getattr_count = 0,
+                             },
+                             PermissionCheckTestCase{
+                                 .need_cap = CAP_SYS_CHROOT,
+                                 .want_init_flags = 0,
+                                 .file_type = S_IFDIR,
+                                 .fn = TestChroot,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 1,
+                                 .expected_non_root_getattr_count = 0,
+                             },
+                             // These are the same as the above, but with the `FUSE_POSIX_ACL`
+                             // init flag set.
+                             PermissionCheckTestCase{
+                                 .want_init_flags = FUSE_POSIX_ACL,
+                                 .file_type = S_IFREG,
+                                 .fn = TestAccess,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = FUSE_POSIX_ACL,
+                                 .file_type = S_IFDIR,
+                                 .fn = TestAccess,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+                             PermissionCheckTestCase{
+                                 .want_init_flags = FUSE_POSIX_ACL,
+                                 .file_type = S_IFDIR,
+                                 .fn = TestChdir,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             },
+                             PermissionCheckTestCase{
+                                 .need_cap = CAP_SYS_CHROOT,
+                                 .want_init_flags = FUSE_POSIX_ACL,
+                                 .file_type = S_IFDIR,
+                                 .fn = TestChroot,
+                                 .expected_lookup_count = 1,
+                                 .expected_access_count = 0,
+                                 .expected_non_root_getattr_count = 1,
+                             }));
+
+class FuseServerBypassAccessTest : public FuseServerTest,
+                                   public ::testing::WithParamInterface<BypassAccessTestCase> {};
+
+TEST_P(FuseServerBypassAccessTest, BypassAccess) {
+  const BypassAccessTestCase& test_case = GetParam();
+
+  std::shared_ptr<CountingFuseServer> server(
+      new CountingFuseServer(test_case.want_init_flags, S_IFREG, test_case.access_reply));
+  ASSERT_TRUE(Mount(server));
+  server->WaitForInit();
+  EXPECT_EQ(server->AccessCount(), 0u);
+
+  InThreadWithoutCapDacOverride([&]() {
+    auto check_access = [&, max_access_count = test_case.max_access_count](const char* file) {
       const std::string filename = GetMountDir() + "/" + file;
       ASSERT_EQ(access(filename.c_str(), R_OK), 0) << strerror(errno);
-      EXPECT_EQ(server->AccessCount(), 1u);
+      EXPECT_EQ(server->AccessCount(), max_access_count);
     };
 
     // No matter how many times we access a file, we should have only ever made
-    // the |FUSE_ACCESS| request once for the lifetime of the connection/server.
+    // the |FUSE_ACCESS| request |params.max_access_count| times for the lifetime
+    // of the connection/server.
     for (int i = 0; i < 3; ++i) {
       ASSERT_NO_FATAL_FAILURE(check_access("somefile1"));
     }
@@ -742,5 +1135,143 @@
     // part of the same connection.
     ASSERT_NO_FATAL_FAILURE(check_access("somefile2"));
   });
-  thrd.join();
 }
+
+INSTANTIATE_TEST_SUITE_P(
+    FuseServerBypassAccessTest, FuseServerBypassAccessTest,
+    testing::Values(
+        // The kernel should stop sending |FUSE_ACCESS| requests once we send an
+        // |ENOSYS| response.
+        BypassAccessTestCase{.want_init_flags = 0, .access_reply = -ENOSYS, .max_access_count = 1},
+        // The kernel should never send a |FUSE_ACCESS| request if we set the
+        // |FUSE_POSIX_ACL| init flag.
+        BypassAccessTestCase{
+            .want_init_flags = FUSE_POSIX_ACL, .access_reply = 0, .max_access_count = 0}));
+
+enum class ExpectedGetAttrBehaviour {
+  kNone,
+  kOncePerFile,
+  kOncePerAccess,
+};
+
+uint64_t ExpectedGetAttrsValue(ExpectedGetAttrBehaviour behaviour, uint64_t access_count) {
+  switch (behaviour) {
+    case ExpectedGetAttrBehaviour::kNone:
+      return 0;
+    case ExpectedGetAttrBehaviour::kOncePerFile:
+      return std::min(access_count, 1ul);
+    case ExpectedGetAttrBehaviour::kOncePerAccess:
+      return access_count;
+  }
+}
+
+struct CacheAttributesTestCase {
+  uint64_t lookup_attr_timeout;
+  uint64_t getattr_attr_timeout;
+  ExpectedGetAttrBehaviour expected_getattr_behaviour;
+};
+
+class FuseServerCacheAttributesTest
+    : public FuseServerTest,
+      public ::testing::WithParamInterface<CacheAttributesTestCase> {};
+
+TEST_P(FuseServerCacheAttributesTest, CacheAttributes) {
+  const CacheAttributesTestCase& test_case = GetParam();
+
+  class CacheAttributesServer : public FuseServer {
+   public:
+    CacheAttributesServer(uint64_t lookup_attr_valid, uint64_t getattr_attr_valid)
+        : FuseServer(FUSE_POSIX_ACL, S_IFREG),
+          lookup_attr_valid_(lookup_attr_valid),
+          getattr_attr_valid_(getattr_attr_valid) {}
+
+    uint64_t NonRootGetAttrCount() {
+      return calls_to_non_root_getattr_.load(std::memory_order_relaxed);
+    }
+
+   protected:
+    testing::AssertionResult HandleLookup(const struct fuse_in_header* in_header,
+                                          const std::vector<std::byte>& message) override {
+      fuse_entry_out entry_out;
+      PopulateDefaultEntry(entry_out);
+      // Instruct the kernel to not immediately evict the |dcache| entry (|dentry|)
+      // for this node by setting a really high entry value. This value is used to
+      // determine when a FUSE-based |dentry| has gone stale. This test isn't focused
+      // on the |dcache| or |dentry| so this is ok. For more details, see:
+      //  - https://www.halolinux.us/kernel-reference/the-dentry-cache.html
+      //  - https://www.kernel.org/doc/html/latest/filesystems/path-lookup.html
+      //  - https://lwn.net/Articles/649115/
+      //  -
+      //  https://www.infradead.org/~mchehab/kernel_docs/filesystems/path-walking.html#dcache-name-lookup
+      entry_out.entry_valid = std::numeric_limits<uint64_t>::max();
+      entry_out.attr_valid = lookup_attr_valid_;
+      return WriteStructResponse(in_header, entry_out);
+    }
+
+    testing::AssertionResult HandleGetAttr(const struct fuse_in_header* in_header,
+                                           const struct fuse_getattr_in* getattr_in,
+                                           const std::vector<std::byte>& message) override {
+      if (in_header->nodeid != FUSE_ROOT_ID) {
+        calls_to_non_root_getattr_.fetch_add(1, std::memory_order_relaxed);
+      }
+      fuse_attr_out attr_out = {
+          .attr_valid = getattr_attr_valid_,
+      };
+      PopulateDefaultAttr(in_header->nodeid, attr_out.attr);
+      return WriteStructResponse(in_header, attr_out);
+    }
+
+   private:
+    uint64_t lookup_attr_valid_;
+    uint64_t getattr_attr_valid_;
+    std::atomic_uint64_t calls_to_non_root_getattr_ = 0;
+  };
+
+  std::shared_ptr<CacheAttributesServer> server(
+      new CacheAttributesServer(test_case.lookup_attr_timeout, test_case.getattr_attr_timeout));
+  ASSERT_TRUE(Mount(server));
+  server->WaitForInit();
+  EXPECT_EQ(server->NonRootGetAttrCount(), 0u);
+
+  InThreadWithoutCapDacOverride([&]() {
+    auto check_getattr = [&](const char* file, uint64_t expected_getattrs) {
+      const std::string filename = GetMountDir() + "/" + file;
+      ASSERT_EQ(access(filename.c_str(), R_OK), 0) << strerror(errno);
+      EXPECT_EQ(server->NonRootGetAttrCount(), expected_getattrs);
+    };
+
+    uint64_t count_after_file1;
+    for (uint64_t i = 1; i <= 3; ++i) {
+      count_after_file1 = ExpectedGetAttrsValue(test_case.expected_getattr_behaviour, i);
+      ASSERT_NO_FATAL_FAILURE(check_getattr("somefile1", count_after_file1));
+    }
+
+    for (uint64_t i = 1; i <= 5; ++i) {
+      ASSERT_NO_FATAL_FAILURE(check_getattr(
+          "somefile2",
+          count_after_file1 + ExpectedGetAttrsValue(test_case.expected_getattr_behaviour, i)));
+    }
+  });
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    FuseServerCacheAttributesTest, FuseServerCacheAttributesTest,
+    testing::Values(
+        // When we don't cache the attributes, expect the kernel to refresh the
+        // attributes each call.
+        CacheAttributesTestCase{
+            .lookup_attr_timeout = 0,
+            .getattr_attr_timeout = 0,
+            .expected_getattr_behaviour = ExpectedGetAttrBehaviour::kOncePerAccess},
+
+        // When we respond to the lookup request with a cache timeout, it should
+        // be respected.
+        CacheAttributesTestCase{.lookup_attr_timeout = std::numeric_limits<uint64_t>::max(),
+                                .getattr_attr_timeout = 0,
+                                .expected_getattr_behaviour = ExpectedGetAttrBehaviour::kNone},
+        // When don't provide a cache timeout with lookup, but do for getattr,
+        // respect the cached attributes after the getattr request.
+        CacheAttributesTestCase{
+            .lookup_attr_timeout = 0,
+            .getattr_attr_timeout = std::numeric_limits<uint64_t>::max(),
+            .expected_getattr_behaviour = ExpectedGetAttrBehaviour::kOncePerFile}));
diff --git a/src/starnix/tests/syscalls/cpp/vmsplice_test.cc b/src/starnix/tests/syscalls/cpp/vmsplice_test.cc
index 57ceef7..5fa5c8d 100644
--- a/src/starnix/tests/syscalls/cpp/vmsplice_test.cc
+++ b/src/starnix/tests/syscalls/cpp/vmsplice_test.cc
@@ -3,51 +3,176 @@
 // found in the LICENSE file.
 
 #include <fcntl.h>
+#include <lib/fit/defer.h>
 #include <stdlib.h>
+#include <sys/mman.h>
 #include <sys/socket.h>
 #include <unistd.h>
 
 #include <cstdlib>
 #include <string>
 
+#include <fbl/unique_fd.h>
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 namespace {
 
+constexpr size_t kNumPipeEndsCount = 2;
+
+void MakePipe(fbl::unique_fd (&fds)[kNumPipeEndsCount]) {
+  int raw_fds[kNumPipeEndsCount] = {};
+  ASSERT_EQ(pipe(raw_fds), 0) << strerror(errno);
+  for (size_t i = 0; i < kNumPipeEndsCount; ++i) {
+    fds[i] = fbl::unique_fd(raw_fds[i]);
+    ASSERT_TRUE(fds[i]);
+  }
+}
+
 TEST(VmspliceTest, VmspliceReadClosedPipe) {
-  int fds[2];
-  ASSERT_EQ(pipe(fds), 0);
-  ASSERT_EQ(close(fds[1]), 0);
+  fbl::unique_fd fds[kNumPipeEndsCount];
+  ASSERT_NO_FATAL_FAILURE(MakePipe(fds));
+  ASSERT_EQ(fds[1].reset(), 0) << strerror(errno);
   char buffer[4096] = {};
   iovec iov = {
       .iov_base = buffer,
       .iov_len = sizeof(buffer),
   };
-  ASSERT_EQ(vmsplice(fds[0], &iov, 1, SPLICE_F_NONBLOCK), 0);
-  ASSERT_EQ(vmsplice(fds[0], &iov, 1, 0), 0);
-  close(fds[0]);
+  ASSERT_EQ(vmsplice(fds[0].get(), &iov, 1, SPLICE_F_NONBLOCK), 0) << strerror(errno);
+  ASSERT_EQ(vmsplice(fds[0].get(), &iov, 1, 0), 0) << strerror(errno);
 }
 
 TEST(VmspliceTest, VmspliceWriteClosedPipe) {
+  constexpr int kRetCode = 42;
   EXPECT_EXIT(([]() {
                 signal(SIGPIPE, SIG_IGN);
 
-                int fds[2];
-                ASSERT_EQ(pipe(fds), 0);
-                ASSERT_EQ(close(fds[0]), 0);
+                fbl::unique_fd fds[kNumPipeEndsCount];
+                ASSERT_NO_FATAL_FAILURE(MakePipe(fds));
+                ASSERT_EQ(fds[0].reset(), 0) << strerror(errno);
                 char buffer[4096] = {};
                 iovec iov = {
                     .iov_base = buffer,
                     .iov_len = sizeof(buffer),
                 };
-                ASSERT_EQ(vmsplice(fds[1], &iov, 1, SPLICE_F_NONBLOCK), -1);
+                ASSERT_EQ(vmsplice(fds[1].get(), &iov, 1, SPLICE_F_NONBLOCK), -1);
                 ASSERT_EQ(errno, EPIPE);
-                ASSERT_EQ(vmsplice(fds[1], &iov, 1, 0), -1);
+                ASSERT_EQ(vmsplice(fds[1].get(), &iov, 1, 0), -1);
                 ASSERT_EQ(errno, EPIPE);
-                close(fds[1]);
-                exit(42);
+                exit(kRetCode);
               })(),
-              testing::ExitedWithCode(42), "");
+              testing::ExitedWithCode(kRetCode), "");
+}
+
+TEST(VmspliceTest, ModifyBufferInPipe) {
+  constexpr char kInitialByte = 'A';
+  constexpr char kModifiedByte = 'B';
+
+  fbl::unique_fd fds[kNumPipeEndsCount];
+  ASSERT_NO_FATAL_FAILURE(MakePipe(fds));
+  // Volatile to let the compiler know not to optimize out the final write we
+  // perform to `write_buffer` which is never directly read here.
+  volatile char write_buffer[10];
+  std::fill_n(&write_buffer[0], std::size(write_buffer), kInitialByte);
+  {
+    iovec iov = {
+        .iov_base = const_cast<char*>(write_buffer),
+        .iov_len = sizeof(write_buffer),
+    };
+    ASSERT_EQ(vmsplice(fds[1].get(), &iov, 1, 0), static_cast<ssize_t>(sizeof(write_buffer)))
+        << strerror(errno);
+  }
+  std::fill_n(&write_buffer[0], std::size(write_buffer), kModifiedByte);
+
+  char read_buffer[sizeof(write_buffer)] = {};
+  ASSERT_EQ(read(fds[0].get(), read_buffer, sizeof(read_buffer)),
+            static_cast<ssize_t>(sizeof(read_buffer)))
+      << strerror(errno);
+  EXPECT_THAT(read_buffer, testing::Each(kModifiedByte));
+}
+
+TEST(VmspliceTest, UnmapBufferInPipe) {
+  constexpr size_t kMmapSize = 4096;
+  constexpr char kInitialByte = 'A';
+  constexpr char kModifiedByte = 'B';
+
+  fbl::unique_fd fds[kNumPipeEndsCount];
+  ASSERT_NO_FATAL_FAILURE(MakePipe(fds));
+  {
+    // Volatile to let the compiler know not to optimize out the final write we
+    // perform to `write_buffer` which is never directly read here.
+    volatile char* write_buffer = reinterpret_cast<volatile char*>(
+        mmap(NULL, kMmapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+    ASSERT_NE(write_buffer, MAP_FAILED) << strerror(errno);
+    auto unmap_write_buffer = fit::defer([&]() {
+      EXPECT_EQ(munmap(const_cast<char*>(write_buffer), kMmapSize), 0) << strerror(errno);
+    });
+    std::fill_n(write_buffer, kMmapSize, kInitialByte);
+    {
+      iovec iov = {
+          .iov_base = const_cast<char*>(write_buffer),
+          .iov_len = kMmapSize,
+      };
+      ASSERT_EQ(vmsplice(fds[1].get(), &iov, 1, 0), static_cast<ssize_t>(kMmapSize))
+          << strerror(errno);
+    }
+    std::fill_n(&write_buffer[0], kMmapSize, kModifiedByte);
+  }
+
+  char read_buffer[kMmapSize] = {};
+  ASSERT_EQ(read(fds[0].get(), read_buffer, sizeof(read_buffer)),
+            static_cast<ssize_t>(sizeof(read_buffer)))
+      << strerror(errno);
+  EXPECT_THAT(read_buffer, testing::Each(kModifiedByte));
+}
+
+TEST(VmspliceTest, UnmapBufferInPipeThenMapInPlace) {
+  constexpr size_t kMmapSize = 4096;
+  constexpr char kInitialByte = 'A';
+  constexpr char kModifiedByte = 'B';
+
+  fbl::unique_fd fds[kNumPipeEndsCount];
+  ASSERT_NO_FATAL_FAILURE(MakePipe(fds));
+  // Volatile to let the compiler know not to optimize out the final write we
+  // perform to `write_buffer` which is never directly read here.
+  volatile char* write_buffer = reinterpret_cast<volatile char*>(
+      mmap(NULL, kMmapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+  {
+    ASSERT_NE(write_buffer, MAP_FAILED) << strerror(errno);
+    auto unmap_write_buffer = fit::defer([&]() {
+      EXPECT_EQ(munmap(const_cast<char*>(write_buffer), kMmapSize), 0) << strerror(errno);
+    });
+    std::fill_n(write_buffer, kMmapSize, kInitialByte);
+    {
+      iovec iov = {
+          .iov_base = const_cast<char*>(write_buffer),
+          .iov_len = kMmapSize,
+      };
+      ASSERT_EQ(vmsplice(fds[1].get(), &iov, 1, 0), static_cast<ssize_t>(kMmapSize))
+          << strerror(errno);
+    }
+    std::fill_n(&write_buffer[0], kMmapSize, kModifiedByte);
+  }
+
+  {
+    // Volatile to let the compiler know not to optimize out the final write we
+    // perform to `write_buffer_new` which is never read here.
+    volatile char* write_buffer_new = reinterpret_cast<volatile char*>(
+        mmap(const_cast<char*>(write_buffer), kMmapSize, PROT_READ | PROT_WRITE,
+             MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+    ASSERT_NE(write_buffer_new, MAP_FAILED) << strerror(errno);
+    ASSERT_EQ(write_buffer, write_buffer_new);
+    auto unmap_write_buffer = fit::defer([&]() {
+      EXPECT_EQ(munmap(const_cast<char*>(write_buffer_new), kMmapSize), 0) << strerror(errno);
+    });
+    std::fill_n(&write_buffer[0], kMmapSize, kInitialByte);
+  }
+
+  char read_buffer[kMmapSize] = {};
+  ASSERT_EQ(read(fds[0].get(), read_buffer, sizeof(read_buffer)),
+            static_cast<ssize_t>(sizeof(read_buffer)))
+      << strerror(errno);
+  EXPECT_THAT(read_buffer, testing::Each(kModifiedByte));
 }
 
 }  // namespace
diff --git a/src/storage/benchmarks/fuchsia/src/filesystems/mod.rs b/src/storage/benchmarks/fuchsia/src/filesystems/mod.rs
index 5358753..12e5d62 100644
--- a/src/storage/benchmarks/fuchsia/src/filesystems/mod.rs
+++ b/src/storage/benchmarks/fuchsia/src/filesystems/mod.rs
@@ -11,7 +11,7 @@
         filesystem::{ServingMultiVolumeFilesystem, ServingSingleVolumeFilesystem},
         FSConfig,
     },
-    fuchsia_merkle::{Hash, MerkleTree},
+    fuchsia_merkle::Hash,
     fuchsia_zircon as zx,
     std::path::Path,
     storage_benchmarks::{block_device::BlockDevice, CacheClearableFilesystem, Filesystem},
@@ -47,7 +47,7 @@
 
 impl DeliveryBlob {
     pub fn new(data: Vec<u8>, mode: CompressionMode) -> Self {
-        let name = MerkleTree::from_reader(data.as_slice()).unwrap().root();
+        let name = fuchsia_merkle::from_slice(&data).root();
         Self { data: Type1Blob::generate(&data, mode), name }
     }
 }
diff --git a/src/storage/benchmarks/verity/src/main.rs b/src/storage/benchmarks/verity/src/main.rs
index 4424be8..3b23083 100644
--- a/src/storage/benchmarks/verity/src/main.rs
+++ b/src/storage/benchmarks/verity/src/main.rs
@@ -39,6 +39,7 @@
         serde_json::to_string_pretty(&results).unwrap(),
     )
     .unwrap();
+    fxfs_admin_proxy.shutdown().await.unwrap();
 }
 
 async fn wait_for_results(
diff --git a/src/storage/benchmarks/verity/src/test.fxfs.test.fidl b/src/storage/benchmarks/verity/src/test.fxfs.test.fidl
index 3069cea..44b454f 100644
--- a/src/storage/benchmarks/verity/src/test.fxfs.test.fidl
+++ b/src/storage/benchmarks/verity/src/test.fxfs.test.fidl
@@ -6,10 +6,14 @@
 using fuchsia.io;
 using zx;
 
-/// Clears the cache of the running test filesystem instance and return the new root directory.
 @discoverable
 closed protocol TestFxfsAdmin {
+    /// Clears the cache of the running test filesystem instance and return the new root directory.
     strict ClearCache() -> (resource struct {
         root_dir client_end:fuchsia.io.Directory;
     }) error zx.Status;
+    /// Stops serving requests on the outgoing svc directory. The caller can now call shutdown on
+    /// the running test filesystem instance, which will clean up the filesystem. After shutdown is
+    /// called, the filesystem is no longer usuable.
+    strict Shutdown() -> ();
 };
diff --git a/src/storage/benchmarks/verity/src/test_fxfs.rs b/src/storage/benchmarks/verity/src/test_fxfs.rs
index e469aaf..0e131f9 100644
--- a/src/storage/benchmarks/verity/src/test_fxfs.rs
+++ b/src/storage/benchmarks/verity/src/test_fxfs.rs
@@ -35,7 +35,7 @@
     svc.dir("svc").add_fidl_service(IncomingRequest::TestAdmin);
 
     svc.take_and_serve_directory_handle().unwrap();
-    while let Some(request) = svc.next().await {
+    'outer: while let Some(request) = svc.next().await {
         match request {
             IncomingRequest::TestAdmin(mut stream) => {
                 while let Some(request) = stream.next().await {
@@ -72,9 +72,14 @@
                                 .send(Ok(root_dir_for_main.into_client_end().unwrap()))
                                 .unwrap();
                         }
+                        TestFxfsAdminRequest::Shutdown { responder } => {
+                            responder.send().unwrap();
+                            break 'outer;
+                        }
                     }
                 }
             }
         }
     }
+    fs.shutdown().await;
 }
diff --git a/src/storage/bin/disk-pave/disk-pave.cc b/src/storage/bin/disk-pave/disk-pave.cc
index d265e492..aef1769 100644
--- a/src/storage/bin/disk-pave/disk-pave.cc
+++ b/src/storage/bin/disk-pave/disk-pave.cc
@@ -289,20 +289,11 @@
 
   switch (flags.cmd) {
     case Command::kFvm: {
-      auto data_sink = fidl::CreateEndpoints<fuchsia_paver::DataSink>();
-      if (data_sink.is_error()) {
-        ERROR("Unable to create channels.\n");
-        return data_sink.status_value();
-      }
-      auto [data_sink_local, data_sink_remote] = std::move(*data_sink);
+      auto [data_sink_local, data_sink_remote] = fidl::Endpoints<fuchsia_paver::DataSink>::Create();
       // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
       (void)paver_client->FindDataSink(std::move(data_sink_remote));
 
-      auto streamer_endpoints = fidl::CreateEndpoints<fuchsia_paver::PayloadStream>();
-      if (streamer_endpoints.is_error()) {
-        return streamer_endpoints.status_value();
-      }
-      auto [client, server] = std::move(*streamer_endpoints);
+      auto [client, server] = fidl::Endpoints<fuchsia_paver::PayloadStream>::Create();
 
       // Launch thread which implements interface.
       async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
@@ -341,12 +332,8 @@
         return ZX_ERR_INVALID_ARGS;
       }
 
-      auto data_sink = fidl::CreateEndpoints<fuchsia_paver::DynamicDataSink>();
-      if (data_sink.is_error()) {
-        ERROR("Unable to create channels.\n");
-        return data_sink.status_value();
-      }
-      auto [data_sink_local, data_sink_remote] = std::move(*data_sink);
+      auto [data_sink_local, data_sink_remote] =
+          fidl::Endpoints<fuchsia_paver::DynamicDataSink>::Create();
 
       auto block_result =
           UseBlockDevice(paver_client, flags.block_device, std::move(data_sink_remote));
@@ -370,12 +357,8 @@
         return ZX_ERR_INVALID_ARGS;
       }
 
-      auto data_sink = fidl::CreateEndpoints<fuchsia_paver::DynamicDataSink>();
-      if (data_sink.is_error()) {
-        ERROR("Unable to create channels.\n");
-        return data_sink.status_value();
-      }
-      auto [data_sink_local, data_sink_remote] = std::move(*data_sink);
+      auto [data_sink_local, data_sink_remote] =
+          fidl::Endpoints<fuchsia_paver::DynamicDataSink>::Create();
 
       auto block_result =
           UseBlockDevice(paver_client, flags.block_device, std::move(data_sink_remote));
@@ -402,12 +385,7 @@
     return status;
   }
 
-  auto data_sink_endpoints = fidl::CreateEndpoints<fuchsia_paver::DataSink>();
-  if (data_sink_endpoints.is_error()) {
-    ERROR("Unable to create channels.\n");
-    return data_sink_endpoints.status_value();
-  }
-  auto [data_sink_local, data_sink_remote] = std::move(*data_sink_endpoints);
+  auto [data_sink_local, data_sink_remote] = fidl::Endpoints<fuchsia_paver::DataSink>::Create();
 
   // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
   (void)paver_client->FindDataSink(std::move(data_sink_remote));
diff --git a/src/storage/bin/disk-pave/test/payload-streamer-test.cc b/src/storage/bin/disk-pave/test/payload-streamer-test.cc
index 1e1abd3..0fb185e4 100644
--- a/src/storage/bin/disk-pave/test/payload-streamer-test.cc
+++ b/src/storage/bin/disk-pave/test/payload-streamer-test.cc
@@ -18,9 +18,8 @@
 
 TEST(PayloadStreamerTest, TrivialLifetime) {
   async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
-  auto stream = fidl::CreateEndpoints<fuchsia_paver::PayloadStream>();
-  ASSERT_OK(stream.status_value());
-  disk_pave::PayloadStreamer streamer(std::move(stream->server), fbl::unique_fd());
+  auto stream = fidl::Endpoints<fuchsia_paver::PayloadStream>::Create();
+  disk_pave::PayloadStreamer streamer(std::move(stream.server), fbl::unique_fd());
 }
 
 class PayloadStreamerTest : public zxtest::Test {
diff --git a/src/storage/blobfs/bin/blobfs_test.cc b/src/storage/blobfs/bin/blobfs_test.cc
index 041ba5a..14cda5a 100644
--- a/src/storage/blobfs/bin/blobfs_test.cc
+++ b/src/storage/blobfs/bin/blobfs_test.cc
@@ -48,14 +48,13 @@
     ASSERT_FALSE(create_res->is_error())
         << "create error: " << static_cast<uint32_t>(create_res->error_value());
 
-    auto exposed_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(exposed_endpoints.status_value(), ZX_OK);
+    auto exposed_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto open_exposed_res =
-        realm_->OpenExposedDir(kBlobfsChildRef, std::move(exposed_endpoints->server));
+        realm_->OpenExposedDir(kBlobfsChildRef, std::move(exposed_endpoints.server));
     ASSERT_EQ(open_exposed_res.status(), ZX_OK);
     ASSERT_FALSE(open_exposed_res->is_error())
         << "open exposed dir error: " << static_cast<uint32_t>(open_exposed_res->error_value());
-    exposed_dir_ = std::move(exposed_endpoints->client);
+    exposed_dir_ = std::move(exposed_endpoints.client);
 
     auto startup_client_end =
         component::ConnectAt<fuchsia_fs_startup::Startup>(exposed_dir_.borrow());
diff --git a/src/storage/blobfs/test/integration/blobfs_component_runner_test.cc b/src/storage/blobfs/test/integration/blobfs_component_runner_test.cc
index 3a1e601..1c90331 100644
--- a/src/storage/blobfs/test/integration/blobfs_component_runner_test.cc
+++ b/src/storage/blobfs/test/integration/blobfs_component_runner_test.cc
@@ -50,10 +50,9 @@
     device_ = std::make_unique<block_client::FakeBlockDevice>(kNumBlocks, kBlockSize);
     ASSERT_EQ(FormatFilesystem(device_.get(), FilesystemOptions{}), ZX_OK);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(endpoints.status_value(), ZX_OK);
-    root_ = std::move(endpoints->client);
-    server_end_ = std::move(endpoints->server);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    root_ = std::move(endpoints.client);
+    server_end_ = std::move(endpoints.server);
   }
   void TearDown() override {}
 
@@ -66,24 +65,22 @@
   }
 
   fidl::ClientEnd<fuchsia_io::Directory> GetSvcDir() const {
-    auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(svc_endpoints.status_value() == ZX_OK);
+    auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto status = fidl::WireCall(root_)->Open(
         fuchsia_io::wire::OpenFlags::kDirectory, {}, "svc",
-        fidl::ServerEnd<fuchsia_io::Node>(svc_endpoints->server.TakeChannel()));
+        fidl::ServerEnd<fuchsia_io::Node>(svc_endpoints.server.TakeChannel()));
     ZX_ASSERT(status.status() == ZX_OK);
-    return std::move(svc_endpoints->client);
+    return std::move(svc_endpoints.client);
   }
 
   fidl::ClientEnd<fuchsia_io::Directory> GetRootDir() const {
-    auto root_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ZX_ASSERT(root_endpoints.status_value() == ZX_OK);
+    auto root_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto status = fidl::WireCall(root_)->Open(
         fuchsia_io::wire::OpenFlags::kRightReadable | fuchsia_io::wire::OpenFlags::kRightWritable |
             fuchsia_io::wire::OpenFlags::kDirectory,
-        {}, "root", fidl::ServerEnd<fuchsia_io::Node>(root_endpoints->server.TakeChannel()));
+        {}, "root", fidl::ServerEnd<fuchsia_io::Node>(root_endpoints.server.TakeChannel()));
     ZX_ASSERT(status.status() == ZX_OK);
-    return std::move(root_endpoints->client);
+    return std::move(root_endpoints.client);
   }
 
   async::Loop loop_;
@@ -96,11 +93,10 @@
 
 TEST_F(BlobfsComponentRunnerTest, ServeAndConfigureStartsBlobfs) {
   FakeDriverManagerAdmin driver_admin;
-  auto admin_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::Administrator>();
-  ASSERT_TRUE(admin_endpoints.is_ok());
-  fidl::BindServer(loop_.dispatcher(), std::move(admin_endpoints->server), &driver_admin);
+  auto admin_endpoints = fidl::Endpoints<fuchsia_device_manager::Administrator>::Create();
+  fidl::BindServer(loop_.dispatcher(), std::move(admin_endpoints.server), &driver_admin);
 
-  ASSERT_NO_FATAL_FAILURE(StartServe(std::move(admin_endpoints->client)));
+  ASSERT_NO_FATAL_FAILURE(StartServe(std::move(admin_endpoints.client)));
 
   auto svc_dir = GetSvcDir();
   auto client_end = component::ConnectAt<fuchsia_fs_startup::Startup>(svc_dir.borrow());
@@ -145,9 +141,8 @@
 
 TEST_F(BlobfsComponentRunnerTest, RequestsBeforeStartupAreQueuedAndServicedAfter) {
   FakeDriverManagerAdmin driver_admin;
-  auto admin_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::Administrator>();
-  ASSERT_TRUE(admin_endpoints.is_ok());
-  fidl::BindServer(loop_.dispatcher(), std::move(admin_endpoints->server), &driver_admin);
+  auto admin_endpoints = fidl::Endpoints<fuchsia_device_manager::Administrator>::Create();
+  fidl::BindServer(loop_.dispatcher(), std::move(admin_endpoints.server), &driver_admin);
 
   // Start a call to the filesystem. We expect that this request will be queued and won't return
   // until Configure is called on the runner. Initially, GetSvcDir will fire off an open call on
@@ -171,7 +166,7 @@
   ASSERT_EQ(loop_.RunUntilIdle(), ZX_OK);
   ASSERT_FALSE(query_complete);
 
-  ASSERT_NO_FATAL_FAILURE(StartServe(std::move(admin_endpoints->client)));
+  ASSERT_NO_FATAL_FAILURE(StartServe(std::move(admin_endpoints.client)));
   ASSERT_EQ(loop_.RunUntilIdle(), ZX_OK);
   ASSERT_FALSE(query_complete);
 
@@ -198,11 +193,10 @@
 
 TEST_F(BlobfsComponentRunnerTest, DoubleShutdown) {
   FakeDriverManagerAdmin driver_admin;
-  auto admin_endpoints = fidl::CreateEndpoints<fuchsia_device_manager::Administrator>();
-  ASSERT_TRUE(admin_endpoints.is_ok());
-  fidl::BindServer(loop_.dispatcher(), std::move(admin_endpoints->server), &driver_admin);
+  auto admin_endpoints = fidl::Endpoints<fuchsia_device_manager::Administrator>::Create();
+  fidl::BindServer(loop_.dispatcher(), std::move(admin_endpoints.server), &driver_admin);
 
-  ASSERT_NO_FATAL_FAILURE(StartServe(std::move(admin_endpoints->client)));
+  ASSERT_NO_FATAL_FAILURE(StartServe(std::move(admin_endpoints.client)));
 
   auto svc_dir = GetSvcDir();
   auto client_end = component::ConnectAt<fuchsia_fs_startup::Startup>(svc_dir.borrow());
diff --git a/src/storage/blobfs/test/integration/executable_mount_test.cc b/src/storage/blobfs/test/integration/executable_mount_test.cc
index b52da4e..fd48883 100644
--- a/src/storage/blobfs/test/integration/executable_mount_test.cc
+++ b/src/storage/blobfs/test/integration/executable_mount_test.cc
@@ -35,9 +35,7 @@
 class ExecutableMountTest : public FdioTest {
  public:
   ExecutableMountTest() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_kernel::VmexResource>();
-    ZX_ASSERT(endpoints.status_value() == ZX_OK);
-    auto [local, remote] = *std::move(endpoints);
+    auto [local, remote] = fidl::Endpoints<fuchsia_kernel::VmexResource>::Create();
 
     zx_status_t status =
         fdio_service_connect("/svc/fuchsia.kernel.VmexResource", remote.TakeChannel().release());
diff --git a/src/storage/blobfs/test/integration/fdio_test.cc b/src/storage/blobfs/test/integration/fdio_test.cc
index 4ce20a4..f8c0830 100644
--- a/src/storage/blobfs/test/integration/fdio_test.cc
+++ b/src/storage/blobfs/test/integration/fdio_test.cc
@@ -41,9 +41,8 @@
                              }),
             ZX_OK);
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_EQ(endpoints.status_value(), ZX_OK);
-  auto [outgoing_dir_client, outgoing_dir_server] = *std::move(endpoints);
+  auto [outgoing_dir_client, outgoing_dir_server] =
+      fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   runner_ = std::make_unique<ComponentRunner>(
       *loop_, ComponentOptions{.pager_threads = mount_options_.paging_threads});
@@ -71,14 +70,13 @@
 
 void FdioTest::TearDown() {
   fdio_cpp::UnownedFdioCaller outgoing_dir(outgoing_dir_fd_);
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_EQ(endpoints.status_value(), ZX_OK);
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   ASSERT_EQ(fidl::WireCall(outgoing_dir.directory())
                 ->Open(fuchsia_io::OpenFlags(0), {}, "svc",
-                       fidl::ServerEnd<fuchsia_io::Node>(endpoints->server.TakeChannel()))
+                       fidl::ServerEnd<fuchsia_io::Node>(endpoints.server.TakeChannel()))
                 .status(),
             ZX_OK);
-  auto admin_client = component::ConnectAt<fuchsia_fs::Admin>(endpoints->client);
+  auto admin_client = component::ConnectAt<fuchsia_fs::Admin>(endpoints.client);
   ASSERT_EQ(admin_client.status_value(), ZX_OK);
   ASSERT_EQ(fidl::WireCall(*admin_client)->Shutdown().status(), ZX_OK);
 }
diff --git a/src/storage/blobfs/test/unit/blob_fuzzer.cc b/src/storage/blobfs/test/unit/blob_fuzzer.cc
index 0f8ba90..e4cab9f 100644
--- a/src/storage/blobfs/test/unit/blob_fuzzer.cc
+++ b/src/storage/blobfs/test/unit/blob_fuzzer.cc
@@ -39,25 +39,23 @@
 constexpr uint32_t kNumBlocks = kBlockDeviceSize / kBlockSize;
 
 fidl::ClientEnd<fuchsia_io::Directory> ServeOutgoingDirectory(ComponentRunner& runner) {
-  auto root_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ZX_ASSERT(root_endpoints.is_ok());
+  auto root_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   auto status = runner.ServeRoot(
-      std::move(root_endpoints->server), fidl::ServerEnd<fuchsia_process_lifecycle::Lifecycle>(),
+      std::move(root_endpoints.server), fidl::ServerEnd<fuchsia_process_lifecycle::Lifecycle>(),
       fidl::ClientEnd<fuchsia_device_manager::Administrator>(), zx::resource());
   ZX_ASSERT(status.is_ok());
-  return std::move(root_endpoints->client);
+  return std::move(root_endpoints.client);
 }
 
 fidl::ClientEnd<fuchsia_io::Directory> GetRootDirectory(
     fidl::ClientEnd<fuchsia_io::Directory>& outgoing) {
-  auto root_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ZX_ASSERT(root_endpoints.is_ok());
+  auto root_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   auto status = fidl::WireCall(outgoing)->Open(
       fuchsia_io::wire::OpenFlags::kRightReadable | fuchsia_io::wire::OpenFlags::kRightWritable |
           fuchsia_io::wire::OpenFlags::kDirectory,
-      {}, "root", fidl::ServerEnd<fuchsia_io::Node>(root_endpoints->server.TakeChannel()));
+      {}, "root", fidl::ServerEnd<fuchsia_io::Node>(root_endpoints.server.TakeChannel()));
   ZX_ASSERT(status.ok());
-  return std::move(root_endpoints->client);
+  return std::move(root_endpoints.client);
 }
 
 class BlobfsInstance {
diff --git a/src/storage/blobfs/test/unit/health_check_test.cc b/src/storage/blobfs/test/unit/health_check_test.cc
index e143742..10874c7 100644
--- a/src/storage/blobfs/test/unit/health_check_test.cc
+++ b/src/storage/blobfs/test/unit/health_check_test.cc
@@ -90,10 +90,9 @@
   }
 
   fidl::WireSyncClient<fuv::BlobfsVerifier> Client() {
-    auto endpoints = fidl::CreateEndpoints<fuv::BlobfsVerifier>();
-    EXPECT_EQ(endpoints.status_value(), ZX_OK);
-    EXPECT_EQ(setup_.vfs()->Serve(svc_, endpoints->server.TakeChannel(), {}), ZX_OK);
-    return fidl::WireSyncClient(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuv::BlobfsVerifier>::Create();
+    EXPECT_EQ(setup_.vfs()->Serve(svc_, endpoints.server.TakeChannel(), {}), ZX_OK);
+    return fidl::WireSyncClient(std::move(endpoints.client));
   }
 
   BlobfsTestSetupWithThread setup_;
diff --git a/src/storage/conformance/BUILD.gn b/src/storage/conformance/BUILD.gn
index 87f4647..5c1e79a 100644
--- a/src/storage/conformance/BUILD.gn
+++ b/src/storage/conformance/BUILD.gn
@@ -16,6 +16,7 @@
     ":io_conformance_util_tests",
     "//src/storage/conformance/conformance_harness/cppvfs:cppvfs-io1-conformance-test",
     "//src/storage/conformance/conformance_harness/fxfs:fxfs-conformance-test",
+    "//src/storage/conformance/conformance_harness/memfs:memfs-conformance-test",
     "//src/storage/conformance/conformance_harness/minfs:minfs-io1-conformance-test",
     "//src/storage/conformance/conformance_harness/rustvfs:rustvfs-io1-conformance-test",
     "//src/storage/conformance/conformance_harness/sdkcpp:sdkcpp-conformance-test",
@@ -59,7 +60,6 @@
   deps = [
     ":io_conformance_util",
     "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
-    "//sdk/fidl/fuchsia.io.test:fuchsia.io.test_rust",
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia",
     "//src/lib/fuchsia-fs",
diff --git a/src/storage/conformance/conformance_harness/cppvfs/harness.cc b/src/storage/conformance/conformance_harness/cppvfs/harness.cc
index a2d751d..d6c84776 100644
--- a/src/storage/conformance/conformance_harness/cppvfs/harness.cc
+++ b/src/storage/conformance/conformance_harness/cppvfs/harness.cc
@@ -52,7 +52,7 @@
     fio_test::Io1Config config;
 
     // Supported options
-    config.set_supports_vmo_file(true);
+    config.set_supports_get_backing_memory(true);
     config.set_supports_remote_dir(true);
     config.set_supports_get_token(true);
 
@@ -83,7 +83,7 @@
       }
     }
 
-    fs::VnodeConnectionOptions options = fs::VnodeConnectionOptions::FromIoV1Flags(
+    fs::VnodeConnectionOptions options = fs::VnodeConnectionOptions::FromOpen1Flags(
         fuchsia_io::OpenFlags{static_cast<uint32_t>(flags)});
     zx_status_t status = vfs_->Serve(std::move(dir), directory_request.TakeChannel(), options);
     if (status != ZX_OK) {
@@ -129,17 +129,6 @@
                                                        /*writable=*/true));
         break;
       }
-      case fio_test::DirectoryEntry::Tag::kVmoFile: {
-        fio_test::VmoFile vmo_file = std::move(entry.vmo_file());
-        zx::vmo& vmo = *vmo_file.mutable_vmo();
-        uint64_t size;
-        zx_status_t status = vmo.get_prop_content_size(&size);
-        ZX_ASSERT_MSG(status == ZX_OK, "Failed to get VMO content size: %s",
-                      zx_status_get_string(status));
-        dest.AddEntry(vmo_file.name(), fbl::MakeRefCounted<fs::VmoFile>(std::move(vmo), size,
-                                                                        /*writable=*/true));
-        break;
-      }
       case fio_test::DirectoryEntry::Tag::kExecutableFile:
         ZX_PANIC("Executable files are not supported");
         break;
diff --git a/src/storage/conformance/conformance_harness/fxfs/src/main.rs b/src/storage/conformance/conformance_harness/fxfs/src/main.rs
index 46e02be..44513d4 100644
--- a/src/storage/conformance/conformance_harness/fxfs/src/main.rs
+++ b/src/storage/conformance/conformance_harness/fxfs/src/main.rs
@@ -55,18 +55,6 @@
                             .context(format!("failed to write contents for {name}"))?;
                     }
                 }
-                io_test::DirectoryEntry::VmoFile(io_test::VmoFile {
-                    name: Some(name),
-                    vmo: Some(vmo),
-                    ..
-                }) => {
-                    let file = open_file(&dest, FLAGS, &name)
-                        .await
-                        .context(format!("failed to create file {name}"))?;
-                    fuchsia_fs::file::write(&file, &vmo.read_to_vec(0, vmo.get_content_size()?)?)
-                        .await
-                        .context(format!("failed to write contents for {name}"))?;
-                }
                 _ => panic!("Not supported"),
             }
         }
@@ -83,7 +71,7 @@
                 responder.send(&Io1Config {
                     supports_create: Some(true),
                     supports_executable_file: Some(false),
-                    supports_vmo_file: Some(false),
+                    supports_get_backing_memory: Some(true),
                     supports_remote_dir: Some(false),
                     supports_rename: Some(true),
                     supports_link: Some(true),
diff --git a/src/storage/conformance/conformance_harness/memfs/BUILD.gn b/src/storage/conformance/conformance_harness/memfs/BUILD.gn
new file mode 100644
index 0000000..7548a10
--- /dev/null
+++ b/src/storage/conformance/conformance_harness/memfs/BUILD.gn
@@ -0,0 +1,39 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/components.gni")
+
+executable("bin") {
+  testonly = true
+  output_name = "io_conformance_harness_memfs"
+  sources = [ "harness.cc" ]
+  deps = [
+    "//sdk/fidl/fuchsia.io.test:fuchsia.io.test_cpp",
+    "//sdk/lib/component/outgoing/cpp",
+    "//sdk/lib/syslog/cpp",
+    "//src/lib/fxl",
+    "//src/storage/lib/vfs/cpp",
+    "//src/storage/memfs:lib",
+    "//zircon/system/ulib/async-loop:async-loop-cpp",
+    "//zircon/system/ulib/fbl",
+    "//zircon/system/ulib/zx",
+  ]
+}
+
+fuchsia_component("memfs-harness") {
+  testonly = true
+  manifest = "meta/memfs_harness.cml"
+  deps = [ ":bin" ]
+}
+
+fuchsia_component("memfs-test") {
+  testonly = true
+  manifest = "//src/storage/conformance/meta/memfs_conformance_test.cml"
+  deps = [ "//src/storage/conformance:io1_conformance_test" ]
+}
+
+fuchsia_test_package("memfs-conformance-test") {
+  test_components = [ ":memfs-test" ]
+  deps = [ ":memfs-harness" ]
+}
diff --git a/src/storage/conformance/conformance_harness/memfs/harness.cc b/src/storage/conformance/conformance_harness/memfs/harness.cc
new file mode 100644
index 0000000..3efb0f9
--- /dev/null
+++ b/src/storage/conformance/conformance_harness/memfs/harness.cc
@@ -0,0 +1,150 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fidl/fuchsia.io.test/cpp/fidl.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/component/outgoing/cpp/outgoing_directory.h>
+#include <lib/syslog/cpp/log_settings.h>
+#include <lib/syslog/cpp/macros.h>
+#include <sys/stat.h>
+#include <zircon/status.h>
+#include <zircon/types.h>
+
+#include <atomic>
+#include <cstdlib>
+#include <memory>
+
+#include <fbl/ref_ptr.h>
+
+#include "src/lib/fxl/strings/string_printf.h"
+#include "src/storage/lib/vfs/cpp/vfs_types.h"
+#include "src/storage/lib/vfs/cpp/vnode.h"
+#include "src/storage/memfs/memfs.h"
+#include "src/storage/memfs/vnode_dir.h"
+#include "src/storage/memfs/vnode_file.h"
+
+namespace fio_test = fuchsia_io_test;
+
+void AddEntry(const fio_test::DirectoryEntry& entry, memfs::VnodeDir& dir) {
+  switch (entry.Which()) {
+    case fio_test::DirectoryEntry::Tag::kDirectory: {
+      fbl::RefPtr<fs::Vnode> node;
+      ZX_ASSERT(dir.Create(*entry.directory()->name(), S_IFDIR, &node) == ZX_OK);
+      auto sub_dir = fbl::RefPtr<memfs::VnodeDir>::Downcast(std::move(node));
+      if (entry.directory()->entries().has_value()) {
+        for (const auto& entry : *entry.directory()->entries()) {
+          AddEntry(*entry, *sub_dir);
+        }
+      }
+      break;
+    }
+    case fio_test::DirectoryEntry::Tag::kFile: {
+      fbl::RefPtr<fs::Vnode> node;
+      ZX_ASSERT(dir.Create(*entry.file()->name(), S_IFREG, &node) == ZX_OK);
+      auto file = fbl::RefPtr<memfs::VnodeFile>::Downcast(std::move(node));
+      const auto& contents = entry.file()->contents();
+      if (contents.has_value()) {
+        zx::result<zx::stream> stream = file->CreateStream(ZX_STREAM_MODE_WRITE);
+        ZX_ASSERT(stream.is_ok());
+        size_t actual;
+        zx_iovec_t iovec = {
+            .buffer = const_cast<uint8_t*>(contents->data()),
+            .capacity = contents->size(),
+        };
+        ZX_ASSERT(stream->writev(0, &iovec, 1, &actual) == ZX_OK);
+        ZX_ASSERT(actual == contents->size());
+      }
+      break;
+    }
+    case fio_test::DirectoryEntry::Tag::kRemoteDirectory:
+      ZX_PANIC("Remote directories are not supported");
+      break;
+    case fio_test::DirectoryEntry::Tag::kExecutableFile:
+      ZX_PANIC("Executable files are not supported");
+      break;
+  }
+}
+
+class TestHarness : public fidl::Server<fio_test::Io1Harness> {
+ public:
+  explicit TestHarness(std::unique_ptr<memfs::Memfs> memfs, fbl::RefPtr<memfs::VnodeDir> root)
+      : memfs_(std::move(memfs)), root_(std::move(root)) {}
+
+  void GetConfig(GetConfigCompleter::Sync& completer) final {
+    fio_test::Io1Config config;
+
+    // Supported options
+    config.supports_get_backing_memory(true);
+    config.supports_get_token(true);
+    config.supports_create(true);
+    config.supports_rename(true);
+    config.supports_link(true);
+    config.supports_unlink(true);
+    config.supports_directory_watchers(true);
+    config.supports_append(true);
+
+    config.supports_remote_dir(false);
+    config.supports_executable_file(false);
+    config.supports_open2(false);
+    config.supports_get_attributes(false);
+    config.supports_update_attributes(false);
+    // Only mtime is supported.
+    config.supports_set_attr(false);
+
+    completer.Reply(config);
+  }
+
+  void GetDirectory(GetDirectoryRequest& request, GetDirectoryCompleter::Sync& completer) final {
+    uint64_t test_id = test_counter_.fetch_add(1);
+    std::string directory_name = fxl::StringPrintf("test.%ld", test_id);
+    fbl::RefPtr<fs::Vnode> test_root;
+    ZX_ASSERT(root_->Create(directory_name, S_IFDIR, &test_root) == ZX_OK);
+    auto root_dir = fbl::RefPtr<memfs::VnodeDir>::Downcast(std::move(test_root));
+
+    if (request.root().entries().has_value()) {
+      for (auto& entry : *request.root().entries()) {
+        AddEntry(*entry, *root_dir);
+      }
+    }
+
+    fs::VnodeConnectionOptions options =
+        fs::VnodeConnectionOptions::FromOpen1Flags(request.flags());
+    ZX_ASSERT(memfs_->Serve(root_dir, request.directory_request().TakeChannel(), options) == ZX_OK);
+  }
+
+ private:
+  std::unique_ptr<memfs::Memfs> memfs_;
+  fbl::RefPtr<memfs::VnodeDir> root_;
+  std::atomic_uint64_t test_counter_ = 0;
+};
+
+int main(int argc, const char** argv) {
+  fuchsia_logging::SetTags({"io_conformance_harness_memfs"});
+
+  async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
+  async_dispatcher_t* dispatcher = loop.dispatcher();
+
+  component::OutgoingDirectory outgoing = component::OutgoingDirectory(dispatcher);
+
+  zx::result result = outgoing.ServeFromStartupInfo();
+  if (result.is_error()) {
+    FX_LOGS(ERROR) << "Failed to serve outgoing directory: " << result.status_string();
+    return EXIT_FAILURE;
+  }
+
+  auto memfs = memfs::Memfs::Create(dispatcher, "memfs");
+  if (memfs.is_error()) {
+    FX_LOGS(ERROR) << "Failed to create memfs: " << memfs.status_string();
+  }
+
+  result = outgoing.AddProtocol<fio_test::Io1Harness>(
+      std::make_unique<TestHarness>(std::move(memfs->first), std::move(memfs->second)));
+  if (result.is_error()) {
+    FX_LOGS(ERROR) << "Failed to server test harness: " << result.status_string();
+    return EXIT_FAILURE;
+  }
+
+  loop.Run();
+  return EXIT_SUCCESS;
+}
diff --git a/src/diagnostics/archivist/testing/puppet/meta/puppet.cml b/src/storage/conformance/conformance_harness/memfs/meta/memfs_harness.cml
similarity index 60%
rename from src/diagnostics/archivist/testing/puppet/meta/puppet.cml
rename to src/storage/conformance/conformance_harness/memfs/meta/memfs_harness.cml
index 8bb2ecb..a77af41 100644
--- a/src/diagnostics/archivist/testing/puppet/meta/puppet.cml
+++ b/src/storage/conformance/conformance_harness/memfs/meta/memfs_harness.cml
@@ -1,4 +1,4 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 {
@@ -8,14 +8,14 @@
     ],
     program: {
         runner: "elf",
-        binary: "bin/archivist_test_puppet",
+        binary: "bin/io_conformance_harness_memfs",
     },
     capabilities: [
-        { protocol: "fuchsia.archivist.test.Puppet" },
+        { protocol: "fuchsia.io.test.Io1Harness" },
     ],
     expose: [
         {
-            protocol: "fuchsia.archivist.test.Puppet",
+            protocol: "fuchsia.io.test.Io1Harness",
             from: "self",
         },
     ],
diff --git a/src/storage/conformance/conformance_harness/minfs/harness.cc b/src/storage/conformance/conformance_harness/minfs/harness.cc
index 410c952..e57af73f 100644
--- a/src/storage/conformance/conformance_harness/minfs/harness.cc
+++ b/src/storage/conformance/conformance_harness/minfs/harness.cc
@@ -81,7 +81,7 @@
 
     // Unsupported options
     config.set_supports_executable_file(false);
-    config.set_supports_vmo_file(false);
+    config.set_supports_get_backing_memory(false);
     config.set_supports_remote_dir(false);
     config.set_supports_get_attributes(false);
     config.set_supports_update_attributes(false);
@@ -97,7 +97,7 @@
     if (root.has_entries()) {
       PopulateDirectory(root.entries(), *directory);
     }
-    fs::VnodeConnectionOptions options = fs::VnodeConnectionOptions::FromIoV1Flags(
+    fs::VnodeConnectionOptions options = fs::VnodeConnectionOptions::FromOpen1Flags(
         fuchsia_io::OpenFlags{static_cast<uint32_t>(flags)});
     zx_status_t status =
         runner_->Serve(std::move(directory), directory_request.TakeChannel(), options);
@@ -146,8 +146,6 @@
       }
       case fuchsia::io::test::DirectoryEntry::Tag::kRemoteDirectory:
         ZX_PANIC("Remote directories are not supported");
-      case fuchsia::io::test::DirectoryEntry::Tag::kVmoFile:
-        ZX_PANIC("VMO files are not supported");
       case fuchsia::io::test::DirectoryEntry::Tag::kExecutableFile:
         ZX_PANIC("Executable files are not supported");
       case fuchsia::io::test::DirectoryEntry::Tag::Invalid:
diff --git a/src/storage/conformance/conformance_harness/rustvfs/BUILD.gn b/src/storage/conformance/conformance_harness/rustvfs/BUILD.gn
index b783c58..23f6e64 100644
--- a/src/storage/conformance/conformance_harness/rustvfs/BUILD.gn
+++ b/src/storage/conformance/conformance_harness/rustvfs/BUILD.gn
@@ -15,7 +15,6 @@
     "//src/lib/fdio/rust:fdio",
     "//src/lib/fuchsia",
     "//src/lib/fuchsia-component",
-    "//src/lib/zircon/rust:fuchsia-zircon",
     "//src/storage/lib/vfs/rust:vfs",
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:futures",
diff --git a/src/storage/conformance/conformance_harness/rustvfs/src/main.rs b/src/storage/conformance/conformance_harness/rustvfs/src/main.rs
index 910bc93..e1fdf0b 100644
--- a/src/storage/conformance/conformance_harness/rustvfs/src/main.rs
+++ b/src/storage/conformance/conformance_harness/rustvfs/src/main.rs
@@ -11,7 +11,6 @@
         self as io_test, Io1Config, Io1HarnessRequest, Io1HarnessRequestStream,
     },
     fuchsia_component::server::ServiceFs,
-    fuchsia_zircon as zx,
     futures::prelude::*,
     std::sync::Arc,
     tracing::error,
@@ -33,16 +32,6 @@
 
 const HARNESS_EXEC_PATH: &'static str = "/pkg/bin/io_conformance_harness_rustvfs";
 
-/// Creates and returns a Rust VFS VmoFile-backed file using the contents of the given buffer.
-///
-/// The VMO backing the buffer is duplicated so that tests can ensure the same VMO is returned by
-/// subsequent GetBackingMemory calls.
-fn new_vmo_file(vmo: zx::Vmo) -> Result<Arc<vmo::VmoFile>, Error> {
-    Ok(vmo::VmoFile::new(
-        vmo, /*readable*/ true, /*writable*/ true, /*executable*/ false,
-    ))
-}
-
 /// Creates and returns a Rust VFS VmoFile-backed executable file using the contents of the
 /// conformance test harness binary itself.
 fn new_executable_file() -> Result<Arc<vmo::VmoFile>, Error> {
@@ -89,12 +78,6 @@
             let new_file = vmo::read_write(contents);
             dest.add_entry(name, new_file)?;
         }
-        io_test::DirectoryEntry::VmoFile(io_test::VmoFile { name, vmo, .. }) => {
-            let name = name.expect("VMO file must have a name");
-            let vmo = vmo.expect("VMO file must have a VMO");
-            let vmo_file = new_vmo_file(vmo)?;
-            dest.add_entry(name, vmo_file)?;
-        }
         io_test::DirectoryEntry::ExecutableFile(io_test::ExecutableFile { name, .. }) => {
             let name = name.expect("Executable file must have a name");
             let executable_file = new_executable_file()?;
@@ -112,7 +95,7 @@
                     // Supported options:
                     supports_create: Some(true),
                     supports_executable_file: Some(true),
-                    supports_vmo_file: Some(true),
+                    supports_get_backing_memory: Some(true),
                     supports_remote_dir: Some(true),
                     supports_rename: Some(true),
                     supports_get_token: Some(true),
diff --git a/src/storage/conformance/conformance_harness/sdkcpp/harness.cc b/src/storage/conformance/conformance_harness/sdkcpp/harness.cc
index 3ec41d9..9284777 100644
--- a/src/storage/conformance/conformance_harness/sdkcpp/harness.cc
+++ b/src/storage/conformance/conformance_harness/sdkcpp/harness.cc
@@ -39,7 +39,7 @@
     // test harness should be the exact same as the current SDK VFS one.
 
     // Supported options:
-    config.supports_vmo_file(true);
+    config.supports_get_backing_memory(true);
     config.supports_remote_dir(true);
     config.supports_get_token(true);
 
@@ -116,19 +116,6 @@
                       "Failed to add File entry!");
         break;
       }
-      case fio_test::DirectoryEntry::Tag::kVmoFile: {
-        fio_test::VmoFile vmo_file = std::move(entry.vmo_file().value());
-        zx::vmo& vmo = *vmo_file.vmo();
-        uint64_t size;
-        zx_status_t status = vmo.get_prop_content_size(&size);
-        ZX_ASSERT_MSG(status == ZX_OK, "Failed to get VMO content size: %s",
-                      zx_status_get_string(status));
-        auto vmo_file_entry = std::make_unique<vfs::VmoFile>(std::move(vmo), size,
-                                                             vfs::VmoFile::WriteMode::kWritable);
-        ZX_ASSERT_MSG(dest.AddEntry(*vmo_file.name(), std::move(vmo_file_entry)) == ZX_OK,
-                      "Failed to add VmoFile entry!");
-        break;
-      }
       case fio_test::DirectoryEntry::Tag::kExecutableFile:
         ZX_PANIC("Executable files are not supported!");
         break;
diff --git a/src/storage/conformance/meta/memfs_conformance_test.cml b/src/storage/conformance/meta/memfs_conformance_test.cml
new file mode 100644
index 0000000..6b6e768
--- /dev/null
+++ b/src/storage/conformance/meta/memfs_conformance_test.cml
@@ -0,0 +1,40 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "//src/sys/test_runners/rust/default.shard.cml",
+        "inspect/offer.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/io1_conformance_test",
+    },
+    children: [
+        {
+            // TODO(https://fxbug.dev/42109125): Don't hardcode the URL here. This
+            // needs to work for all the different filesystem test harnesses.
+            name: "fs_test",
+            url: "fuchsia-pkg://fuchsia.com/memfs-conformance-test#meta/memfs-harness.cm",
+        },
+    ],
+    use: [
+        {
+            protocol: [ "fuchsia.process.Launcher" ],
+        },
+        {
+            protocol: "fuchsia.component.Realm",
+            from: "framework",
+        },
+    ],
+    offer: [
+        {
+            protocol: [
+                "fuchsia.logger.LogSink",
+                "fuchsia.process.Launcher",
+            ],
+            from: "parent",
+            to: "#fs_test",
+        },
+    ],
+}
diff --git a/src/storage/conformance/src/lib.rs b/src/storage/conformance/src/lib.rs
index 6c0423c..c2fd280 100644
--- a/src/storage/conformance/src/lib.rs
+++ b/src/storage/conformance/src/lib.rs
@@ -168,7 +168,6 @@
         DirectoryEntry::Directory(entry) => entry.name.as_ref(),
         DirectoryEntry::RemoteDirectory(entry) => entry.name.as_ref(),
         DirectoryEntry::File(entry) => entry.name.as_ref(),
-        DirectoryEntry::VmoFile(entry) => entry.name.as_ref(),
         DirectoryEntry::ExecutableFile(entry) => entry.name.as_ref(),
     }
     .expect("DirectoryEntry name is None!")
@@ -268,18 +267,6 @@
     })
 }
 
-/// Makes a vmo file to be placed in the test directory.
-pub fn vmo_file(name: &str, contents: &[u8], capacity: u64) -> io_test::DirectoryEntry {
-    let vmo = zx::Vmo::create(capacity).expect("Cannot create VMO");
-    let () = vmo.write(contents, 0).expect("Cannot write to VMO");
-    let () = vmo.set_content_size(&(contents.len() as u64)).expect("Cannot set VMO content size");
-    io_test::DirectoryEntry::VmoFile(io_test::VmoFile {
-        name: Some(name.to_string()),
-        vmo: Some(vmo),
-        ..Default::default()
-    })
-}
-
 /// Makes an executable file to be placed in the test directory.
 pub fn executable_file(name: &str) -> io_test::DirectoryEntry {
     io_test::DirectoryEntry::ExecutableFile(io_test::ExecutableFile {
diff --git a/src/storage/conformance/src/test_harness.rs b/src/storage/conformance/src/test_harness.rs
index 9ca96cc..1d0d5af 100644
--- a/src/storage/conformance/src/test_harness.rs
+++ b/src/storage/conformance/src/test_harness.rs
@@ -22,9 +22,6 @@
     /// All [`io_test::File`] rights supported by the filesystem.
     pub file_rights: Rights,
 
-    /// All [`io_test::VmoFile`] rights supported by the filesystem.
-    pub vmo_file_rights: Rights,
-
     /// All [`io_test::ExecutableFile`] rights supported by the filesystem.
     pub executable_file_rights: Rights,
 }
@@ -47,19 +44,10 @@
         let dir_rights = Rights::new(get_supported_dir_rights(&config));
         let file_rights =
             Rights::new(fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE);
-        let vmo_file_rights =
-            Rights::new(fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE);
         let executable_file_rights =
             Rights::new(fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_EXECUTABLE);
 
-        TestHarness {
-            proxy,
-            config,
-            dir_rights,
-            file_rights,
-            vmo_file_rights,
-            executable_file_rights,
-        }
+        TestHarness { proxy, config, dir_rights, file_rights, executable_file_rights }
     }
 
     /// Creates a [`fio::DirectoryProxy`] with the given root directory structure.
diff --git a/src/storage/conformance/tests/describe.rs b/src/storage/conformance/tests/describe.rs
index 59bc8790..6aaa970 100644
--- a/src/storage/conformance/tests/describe.rs
+++ b/src/storage/conformance/tests/describe.rs
@@ -59,32 +59,3 @@
         assert_eq!(std::str::from_utf8(&protocol), Ok(fio::FILE_PROTOCOL_NAME));
     }
 }
-
-#[fuchsia::test]
-async fn vmo_file_query() {
-    let harness = TestHarness::new().await;
-    if !harness.config.supports_vmo_file.unwrap_or_default() {
-        return;
-    }
-
-    let root = root_directory(vec![vmo_file(TEST_FILE, TEST_FILE_CONTENTS, 128 * 1024)]);
-    let test_dir = harness.get_directory(root, fio::OpenFlags::empty());
-    {
-        let file = open_node::<fio::FileMarker>(
-            &test_dir,
-            fio::OpenFlags::NODE_REFERENCE | fio::OpenFlags::NOT_DIRECTORY,
-            TEST_FILE,
-        )
-        .await;
-
-        let protocol = file.query().await.expect("query failed");
-        assert_eq!(std::str::from_utf8(&protocol), Ok(fio::NODE_PROTOCOL_NAME));
-    }
-    {
-        let file =
-            open_node::<fio::FileMarker>(&test_dir, fio::OpenFlags::NOT_DIRECTORY, TEST_FILE).await;
-
-        let protocol = file.query().await.expect("query failed");
-        assert_eq!(std::str::from_utf8(&protocol), Ok(fio::FILE_PROTOCOL_NAME));
-    }
-}
diff --git a/src/storage/conformance/tests/directory/open.rs b/src/storage/conformance/tests/directory/open.rs
index 3250d96..aac9c4e 100644
--- a/src/storage/conformance/tests/directory/open.rs
+++ b/src/storage/conformance/tests/directory/open.rs
@@ -130,32 +130,6 @@
         .expect_err("open succeeded");
 }
 
-// Validate allowed rights for VmoFile objects (ensures cannot be opened as executable).
-#[fuchsia::test]
-async fn validate_vmo_file_rights() {
-    let harness = TestHarness::new().await;
-    if !harness.config.supports_vmo_file.unwrap_or_default() {
-        return;
-    }
-    // Create a test directory with a VmoFile object, and ensure the directory has all rights.
-    let root = root_directory(vec![vmo_file(TEST_FILE, TEST_FILE_CONTENTS, 128 * 1024)]);
-    let root_dir = harness.get_directory(root, harness.dir_rights.all());
-    // Opening with READ/WRITE should succeed.
-    open_node::<fio::NodeMarker>(
-        &root_dir,
-        fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE,
-        TEST_FILE,
-    )
-    .await;
-    // Opening with EXECUTE must fail to ensure W^X enforcement.
-    assert!(matches!(
-        open_node_status::<fio::NodeMarker>(&root_dir, fio::OpenFlags::RIGHT_EXECUTABLE, TEST_FILE)
-            .await
-            .expect_err("open succeeded"),
-        zx::Status::ACCESS_DENIED | zx::Status::NOT_SUPPORTED
-    ));
-}
-
 // Validate allowed rights for ExecutableFile objects (ensures cannot be opened as writable).
 #[fuchsia::test]
 async fn validate_executable_file_rights() {
diff --git a/src/storage/conformance/tests/file/get_backing_memory.rs b/src/storage/conformance/tests/file/get_backing_memory.rs
index 7bdf920..f9216f7 100644
--- a/src/storage/conformance/tests/file/get_backing_memory.rs
+++ b/src/storage/conformance/tests/file/get_backing_memory.rs
@@ -3,23 +3,23 @@
 // found in the LICENSE file.
 
 use {
-    fidl_fuchsia_io as fio, fidl_fuchsia_io_test as io_test, fuchsia_zircon as zx,
+    fidl_fuchsia_io as fio, fuchsia_zircon as zx,
     io_conformance_util::{test_harness::TestHarness, *},
 };
 
 #[fuchsia::test]
 async fn file_get_readable_memory_with_sufficient_rights() {
     let harness = TestHarness::new().await;
-    if !harness.config.supports_vmo_file.unwrap_or_default() {
+    if !harness.config.supports_get_backing_memory.unwrap_or_default() {
         return;
     }
 
-    for file_flags in harness.vmo_file_rights.valid_combos_with(fio::OpenFlags::RIGHT_READABLE) {
+    for file_flags in harness.file_rights.valid_combos_with(fio::OpenFlags::RIGHT_READABLE) {
         // Should be able to get a readable VMO in default, exact, and private sharing modes.
         for sharing_mode in
             [fio::VmoFlags::empty(), fio::VmoFlags::SHARED_BUFFER, fio::VmoFlags::PRIVATE_CLONE]
         {
-            let file = vmo_file(TEST_FILE, TEST_FILE_CONTENTS, 128 * 1024);
+            let file = file(TEST_FILE, TEST_FILE_CONTENTS.to_owned());
             let (vmo, _) = create_file_and_get_backing_memory(
                 file,
                 &harness,
@@ -45,12 +45,12 @@
 #[fuchsia::test]
 async fn file_get_readable_memory_with_insufficient_rights() {
     let harness = TestHarness::new().await;
-    if !harness.config.supports_vmo_file.unwrap_or_default() {
+    if !harness.config.supports_get_backing_memory.unwrap_or_default() {
         return;
     }
 
-    for file_flags in harness.vmo_file_rights.valid_combos_without(fio::OpenFlags::RIGHT_READABLE) {
-        let file = vmo_file(TEST_FILE, TEST_FILE_CONTENTS, 128 * 1024);
+    for file_flags in harness.file_rights.valid_combos_without(fio::OpenFlags::RIGHT_READABLE) {
+        let file = file(TEST_FILE, TEST_FILE_CONTENTS.to_owned());
         assert_eq!(
             create_file_and_get_backing_memory(file, &harness, file_flags, fio::VmoFlags::READ)
                 .await
@@ -63,15 +63,15 @@
 #[fuchsia::test]
 async fn file_get_writable_memory_with_sufficient_rights() {
     let harness = TestHarness::new().await;
-    if !harness.config.supports_vmo_file.unwrap_or_default() {
+    if !harness.config.supports_get_backing_memory.unwrap_or_default() {
         return;
     }
     // Writable VMOs currently require private sharing mode.
     const VMO_FLAGS: fio::VmoFlags =
         fio::VmoFlags::empty().union(fio::VmoFlags::WRITE).union(fio::VmoFlags::PRIVATE_CLONE);
 
-    for file_flags in harness.vmo_file_rights.valid_combos_with(fio::OpenFlags::RIGHT_WRITABLE) {
-        let file = vmo_file(TEST_FILE, TEST_FILE_CONTENTS, 128 * 1024);
+    for file_flags in harness.file_rights.valid_combos_with(fio::OpenFlags::RIGHT_WRITABLE) {
+        let file = file(TEST_FILE, TEST_FILE_CONTENTS.to_owned());
         let (vmo, _) = create_file_and_get_backing_memory(file, &harness, file_flags, VMO_FLAGS)
             .await
             .expect("Failed to create file and obtain VMO");
@@ -87,14 +87,14 @@
 #[fuchsia::test]
 async fn file_get_writable_memory_with_insufficient_rights() {
     let harness = TestHarness::new().await;
-    if !harness.config.supports_vmo_file.unwrap_or_default() {
+    if !harness.config.supports_get_backing_memory.unwrap_or_default() {
         return;
     }
     const VMO_FLAGS: fio::VmoFlags =
         fio::VmoFlags::empty().union(fio::VmoFlags::WRITE).union(fio::VmoFlags::PRIVATE_CLONE);
 
-    for file_flags in harness.vmo_file_rights.valid_combos_without(fio::OpenFlags::RIGHT_WRITABLE) {
-        let file = vmo_file(TEST_FILE, TEST_FILE_CONTENTS, 128 * 1024);
+    for file_flags in harness.file_rights.valid_combos_without(fio::OpenFlags::RIGHT_WRITABLE) {
+        let file = file(TEST_FILE, TEST_FILE_CONTENTS.to_owned());
         assert_eq!(
             create_file_and_get_backing_memory(file, &harness, file_flags, VMO_FLAGS)
                 .await
@@ -170,19 +170,13 @@
 #[fuchsia::test]
 async fn file_get_backing_memory_shared_buffer() {
     let harness = TestHarness::new().await;
-    if !harness.config.supports_vmo_file.unwrap_or_default() {
+    if !harness.config.supports_get_backing_memory.unwrap_or_default() {
         return;
     }
 
-    let vmo = zx::Vmo::create(3).expect("Cannot create VMO");
-    let vmofile_object = io_test::DirectoryEntry::VmoFile(io_test::VmoFile {
-        name: Some(TEST_FILE.to_string()),
-        vmo: Some(vmo),
-        ..Default::default()
-    });
-
+    let file = file(TEST_FILE, TEST_FILE_CONTENTS.to_owned());
     let (vmo, (_, vmo_file)) = create_file_and_get_backing_memory(
-        vmofile_object,
+        file,
         &harness,
         fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE,
         fio::VmoFlags::READ | fio::VmoFlags::SHARED_BUFFER,
diff --git a/src/storage/conformance/tests/file/write.rs b/src/storage/conformance/tests/file/write.rs
index b428f3f..579193d 100644
--- a/src/storage/conformance/tests/file/write.rs
+++ b/src/storage/conformance/tests/file/write.rs
@@ -86,38 +86,3 @@
         assert_eq!(result, Err(zx::Status::BAD_HANDLE));
     }
 }
-
-#[fuchsia::test]
-async fn vmo_file_write_to_limits() {
-    let harness = TestHarness::new().await;
-    if !harness.config.supports_vmo_file.unwrap_or_default() {
-        return;
-    }
-
-    let capacity = 128 * 1024;
-    let root = root_directory(vec![vmo_file(TEST_FILE, TEST_FILE_CONTENTS, capacity)]);
-    let test_dir = harness
-        .get_directory(root, fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE);
-    let file = open_node::<fio::FileMarker>(
-        &test_dir,
-        fio::OpenFlags::RIGHT_READABLE
-            | fio::OpenFlags::RIGHT_WRITABLE
-            | fio::OpenFlags::NOT_DIRECTORY,
-        TEST_FILE,
-    )
-    .await;
-    let _: Vec<_> = file.query().await.expect("query failed");
-
-    let data = vec![0u8];
-
-    // The VMO file will have a capacity
-    file.write_at(&data[..], capacity)
-        .await
-        .expect("fidl call failed")
-        .expect_err("Write at end of file limit should fail");
-    // An empty write should still succeed even if it targets an out-of-bounds offset.
-    file.write_at(&[], capacity)
-        .await
-        .expect("fidl call failed")
-        .expect("Zero-byte write at end of file limit should succeed");
-}
diff --git a/src/storage/f2fs/bin/f2fs_test.cc b/src/storage/f2fs/bin/f2fs_test.cc
index 2726f27..c7c6313 100644
--- a/src/storage/f2fs/bin/f2fs_test.cc
+++ b/src/storage/f2fs/bin/f2fs_test.cc
@@ -44,14 +44,13 @@
     ASSERT_FALSE(create_res->is_error())
         << "create error: " << static_cast<uint32_t>(create_res->error_value());
 
-    auto exposed_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(exposed_endpoints.status_value(), ZX_OK);
+    auto exposed_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto open_exposed_res =
-        realm_->OpenExposedDir(kF2fsChildRef, std::move(exposed_endpoints->server));
+        realm_->OpenExposedDir(kF2fsChildRef, std::move(exposed_endpoints.server));
     ASSERT_EQ(open_exposed_res.status(), ZX_OK);
     ASSERT_FALSE(open_exposed_res->is_error())
         << "open exposed dir error: " << static_cast<uint32_t>(open_exposed_res->error_value());
-    exposed_dir_ = std::move(exposed_endpoints->client);
+    exposed_dir_ = std::move(exposed_endpoints.client);
 
     auto startup_client_end =
         component::ConnectAt<fuchsia_fs_startup::Startup>(exposed_dir_.borrow());
diff --git a/src/storage/f2fs/test/unit/component_runner_test.cc b/src/storage/f2fs/test/unit/component_runner_test.cc
index 7f7d199..731ec6a 100644
--- a/src/storage/f2fs/test/unit/component_runner_test.cc
+++ b/src/storage/f2fs/test/unit/component_runner_test.cc
@@ -30,10 +30,9 @@
     ASSERT_TRUE(bc_or.is_ok());
     bcache_ = std::move(*bc_or);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(endpoints.status_value(), ZX_OK);
-    root_ = std::move(endpoints->client);
-    server_end_ = std::move(endpoints->server);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    root_ = std::move(endpoints.client);
+    server_end_ = std::move(endpoints.server);
   }
 
   void StartServe() {
@@ -44,24 +43,22 @@
   }
 
   fidl::ClientEnd<fuchsia_io::Directory> GetSvcDir() const {
-    auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_EQ(svc_endpoints.status_value(), ZX_OK);
+    auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto status = fidl::WireCall(root_)->Open(
         fuchsia_io::wire::OpenFlags::kDirectory, {}, "svc",
-        fidl::ServerEnd<fuchsia_io::Node>(svc_endpoints->server.TakeChannel()));
+        fidl::ServerEnd<fuchsia_io::Node>(svc_endpoints.server.TakeChannel()));
     EXPECT_EQ(status.status(), ZX_OK);
-    return std::move(svc_endpoints->client);
+    return std::move(svc_endpoints.client);
   }
 
   fidl::ClientEnd<fuchsia_io::Directory> GetRootDir() const {
-    auto root_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_EQ(root_endpoints.status_value(), ZX_OK);
+    auto root_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto status = fidl::WireCall(root_)->Open(
         fuchsia_io::wire::OpenFlags::kRightReadable | fuchsia_io::wire::OpenFlags::kRightWritable |
             fuchsia_io::wire::OpenFlags::kDirectory,
-        {}, "root", fidl::ServerEnd<fuchsia_io::Node>(root_endpoints->server.TakeChannel()));
+        {}, "root", fidl::ServerEnd<fuchsia_io::Node>(root_endpoints.server.TakeChannel()));
     EXPECT_EQ(status.status(), ZX_OK);
-    return std::move(root_endpoints->client);
+    return std::move(root_endpoints.client);
   }
 
   void ResetRootDir() { root_.reset(); }
@@ -157,9 +154,8 @@
 }
 
 TEST_F(F2fsComponentRunnerTest, LifecycleChannelShutsDownRunner) {
-  auto lifecycle_endpoints = fidl::CreateEndpoints<fuchsia_process_lifecycle::Lifecycle>();
-  ASSERT_EQ(lifecycle_endpoints.status_value(), ZX_OK);
-  auto lifecycle = std::move(lifecycle_endpoints->client);
+  auto lifecycle_endpoints = fidl::Endpoints<fuchsia_process_lifecycle::Lifecycle>::Create();
+  auto lifecycle = std::move(lifecycle_endpoints.client);
 
   runner_ = std::make_unique<ComponentRunner>(loop_.dispatcher());
   std::atomic<bool> unmount_callback_called = false;
@@ -169,7 +165,7 @@
     unmount_callback_called = true;
   });
   zx::result status =
-      runner_->ServeRoot(std::move(server_end_), std::move(lifecycle_endpoints->server));
+      runner_->ServeRoot(std::move(server_end_), std::move(lifecycle_endpoints.server));
   ASSERT_EQ(status.status_value(), ZX_OK);
   ASSERT_EQ(loop_.RunUntilIdle(), ZX_OK);
   ASSERT_FALSE(unmount_callback_called);
diff --git a/src/storage/fs_test/access.cc b/src/storage/fs_test/access.cc
index 8f0b289..6952e97 100644
--- a/src/storage/fs_test/access.cc
+++ b/src/storage/fs_test/access.cc
@@ -183,18 +183,17 @@
   fdio_cpp::FdioCaller fdio_caller(std::move(in_fd));
 
   // Clone |in_fd| as read-only; the entire tree under the new connection now becomes read-only
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
 
   auto clone_result =
       fidl::WireCall(fdio_caller.borrow_as<fio::Node>())
-          ->Clone(fio::wire::OpenFlags::kRightReadable, std::move(std::move(endpoints->server)));
+          ->Clone(fio::wire::OpenFlags::kRightReadable, std::move(std::move(endpoints.server)));
   ASSERT_EQ(clone_result.status(), ZX_OK);
 
   // Turn the handle back to an fd to test posix functions
   fbl::unique_fd fd = ([&]() -> fbl::unique_fd {
     int tmp_fd = -1;
-    zx_status_t status = fdio_fd_create(endpoints->client.TakeChannel().release(), &tmp_fd);
+    zx_status_t status = fdio_fd_create(endpoints.client.TakeChannel().release(), &tmp_fd);
     EXPECT_GT(tmp_fd, 0);
     EXPECT_EQ(status, ZX_OK);
     return fbl::unique_fd(tmp_fd);
@@ -217,14 +216,13 @@
     // Obtain the underlying connection behind |foo_fd|.
     fdio_cpp::FdioCaller fdio_caller(std::move(foo_fd));
 
-    zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-    ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+    auto endpoints = fidl::Endpoints<fio::Node>::Create();
 
     auto clone_result =
         fidl::WireCall(fdio_caller.borrow_as<fio::Node>())
-            ->Clone(fio::wire::OpenFlags::kCloneSameRights | right, std::move(endpoints->server));
+            ->Clone(fio::wire::OpenFlags::kCloneSameRights | right, std::move(endpoints.server));
     ASSERT_EQ(clone_result.status(), ZX_OK);
-    auto describe_result = fidl::WireCall(endpoints->client)->Query();
+    auto describe_result = fidl::WireCall(endpoints.client)->Query();
     ASSERT_EQ(describe_result.status(), ZX_ERR_PEER_CLOSED);
   }
 }
@@ -239,15 +237,14 @@
   // Attempt to clone the read-only fd back to read-write.
   fdio_cpp::FdioCaller fdio_caller(std::move(foo_readonly));
 
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
 
   auto clone_result =
       fidl::WireCall(fdio_caller.borrow_as<fio::Node>())
           ->Clone(fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightWritable,
-                  std::move(endpoints->server));
+                  std::move(endpoints.server));
   ASSERT_EQ(clone_result.status(), ZX_OK);
-  auto describe_result = fidl::WireCall(endpoints->client)->Query();
+  auto describe_result = fidl::WireCall(endpoints.client)->Query();
   ASSERT_EQ(describe_result.status(), ZX_ERR_PEER_CLOSED);
 }
 
diff --git a/src/storage/fs_test/dot_dot.cc b/src/storage/fs_test/dot_dot.cc
index b5373b2..8e388aa 100644
--- a/src/storage/fs_test/dot_dot.cc
+++ b/src/storage/fs_test/dot_dot.cc
@@ -101,16 +101,15 @@
   fdio_cpp::FdioCaller caller(std::move(fd));
 
   // Opening with kOpenFlagCreate should succeed.
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
 
   auto result = fidl::WireCall(caller.borrow_as<fio::Directory>())
                     ->Open(fio::wire::OpenFlags::kRightReadable |
                                fio::wire::OpenFlags::kRightWritable | fio::wire::OpenFlags::kCreate,
-                           {}, fidl::StringView("."), std::move(endpoints->server));
+                           {}, fidl::StringView("."), std::move(endpoints.server));
   ASSERT_EQ(result.status(), ZX_OK);
 
-  const fidl::WireResult close_result = fidl::WireCall(endpoints->client)->Close();
+  const fidl::WireResult close_result = fidl::WireCall(endpoints.client)->Close();
   ASSERT_EQ(close_result.status(), ZX_OK);
   const fit::result close_response = close_result.value();
   ASSERT_TRUE(close_response.is_ok()) << close_response.error_value();
@@ -123,17 +122,16 @@
   fdio_cpp::FdioCaller caller(std::move(fd));
 
   // Opening with kOpenFlagCreateIfAbsent should fail.
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
 
   auto result =
       fidl::WireCall(caller.borrow_as<fio::Directory>())
           ->Open(fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightWritable |
                      fio::wire::OpenFlags::kCreate | fio::wire::OpenFlags::kCreateIfAbsent,
-                 {}, fidl::StringView("."), std::move(endpoints->server));
+                 {}, fidl::StringView("."), std::move(endpoints.server));
   ASSERT_EQ(result.status(), ZX_OK);
 
-  const fidl::WireResult close_result = fidl::WireCall(endpoints->client)->Close();
+  const fidl::WireResult close_result = fidl::WireCall(endpoints.client)->Close();
   // Can't get an epitaph with LLCPP bindings, so this will do for now.
   ASSERT_EQ(close_result.status(), ZX_ERR_PEER_CLOSED);
 }
diff --git a/src/storage/fs_test/open.cc b/src/storage/fs_test/open.cc
index fee1e3a..d9e7e00 100644
--- a/src/storage/fs_test/open.cc
+++ b/src/storage/fs_test/open.cc
@@ -26,14 +26,13 @@
                                                 const std::string& path) {
   EXPECT_EQ(mkdir(path.c_str(), 0755), 0);
 
-  auto endpoints = fidl::CreateEndpoints<fio::Directory>();
-  EXPECT_EQ(endpoints.status_value(), ZX_OK);
+  auto endpoints = fidl::Endpoints<fio::Directory>::Create();
   EXPECT_EQ(
       fdio_open(path.c_str(), static_cast<uint32_t>(dir_flags | fio::wire::OpenFlags::kDirectory),
-                endpoints->server.TakeChannel().release()),
+                endpoints.server.TakeChannel().release()),
       ZX_OK);
 
-  return std::move(endpoints->client);
+  return std::move(endpoints.client);
 }
 
 zx_status_t OpenFileWithCreate(const fidl::ClientEnd<fio::Directory>& dir,
@@ -41,12 +40,11 @@
   fio::wire::OpenFlags child_flags =
       fio::wire::OpenFlags::kCreate | fio::wire::OpenFlags::kRightReadable |
       fio::wire::OpenFlags::kNotDirectory | fio::wire::OpenFlags::kDescribe;
-  auto child_endpoints = fidl::CreateEndpoints<fio::Node>();
-  EXPECT_EQ(child_endpoints.status_value(), ZX_OK);
+  auto child_endpoints = fidl::Endpoints<fio::Node>::Create();
   auto open_res = fidl::WireCall(dir)->Open(child_flags, {}, fidl::StringView::FromExternal(path),
-                                            std::move(child_endpoints->server));
+                                            std::move(child_endpoints.server));
   EXPECT_EQ(open_res.status(), ZX_OK);
-  fidl::WireSyncClient child{std::move(child_endpoints->client)};
+  fidl::WireSyncClient child{std::move(child_endpoints.client)};
 
   class EventHandler : public fidl::testing::WireSyncEventHandlerTestBase<fio::Node> {
    public:
@@ -91,12 +89,11 @@
   flags = fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kPosixWritable |
           fio::wire::OpenFlags::kDirectory;
   std::string path = ".";
-  auto clone_endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_EQ(clone_endpoints.status_value(), ZX_OK);
+  auto clone_endpoints = fidl::Endpoints<fio::Node>::Create();
   auto clone_res = fidl::WireCall(parent)->Open(flags, {}, fidl::StringView::FromExternal(path),
-                                                std::move(clone_endpoints->server));
+                                                std::move(clone_endpoints.server));
   ASSERT_EQ(clone_res.status(), ZX_OK);
-  fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints->client.TakeChannel());
+  fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints.client.TakeChannel());
 
   EXPECT_EQ(OpenFileWithCreate(clone_dir, "b"), ZX_OK);
 }
@@ -108,12 +105,11 @@
   flags = fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kPosixWritable |
           fio::wire::OpenFlags::kDirectory;
   std::string path = ".";
-  auto clone_endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_EQ(clone_endpoints.status_value(), ZX_OK);
+  auto clone_endpoints = fidl::Endpoints<fio::Node>::Create();
   auto clone_res = fidl::WireCall(parent)->Open(flags, {}, fidl::StringView::FromExternal(path),
-                                                std::move(clone_endpoints->server));
+                                                std::move(clone_endpoints.server));
   ASSERT_EQ(clone_res.status(), ZX_OK);
-  fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints->client.TakeChannel());
+  fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints.client.TakeChannel());
 
   EXPECT_EQ(OpenFileWithCreate(clone_dir, "b"), ZX_ERR_ACCESS_DENIED);
 }
@@ -126,11 +122,10 @@
 
   flags = fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kPosixWritable |
           fio::wire::OpenFlags::kDirectory;
-  auto clone_endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_EQ(clone_endpoints.status_value(), ZX_OK);
-  auto clone_res = fidl::WireCall(parent)->Clone(flags, std::move(clone_endpoints->server));
+  auto clone_endpoints = fidl::Endpoints<fio::Node>::Create();
+  auto clone_res = fidl::WireCall(parent)->Clone(flags, std::move(clone_endpoints.server));
   ASSERT_EQ(clone_res.status(), ZX_OK);
-  fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints->client.TakeChannel());
+  fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints.client.TakeChannel());
 
   EXPECT_EQ(OpenFileWithCreate(clone_dir, "b"), ZX_ERR_ACCESS_DENIED);
 }
@@ -141,11 +136,10 @@
 
   flags = fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kPosixWritable |
           fio::wire::OpenFlags::kDirectory;
-  auto clone_endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_EQ(clone_endpoints.status_value(), ZX_OK);
-  auto clone_res = fidl::WireCall(parent)->Clone(flags, std::move(clone_endpoints->server));
+  auto clone_endpoints = fidl::Endpoints<fio::Node>::Create();
+  auto clone_res = fidl::WireCall(parent)->Clone(flags, std::move(clone_endpoints.server));
   ASSERT_EQ(clone_res.status(), ZX_OK);
-  fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints->client.TakeChannel());
+  fidl::ClientEnd<fio::Directory> clone_dir(clone_endpoints.client.TakeChannel());
 
   EXPECT_EQ(OpenFileWithCreate(clone_dir, "b"), ZX_ERR_ACCESS_DENIED);
 }
diff --git a/src/storage/fs_test/watcher.cc b/src/storage/fs_test/watcher.cc
index 76edf14..7d30e34 100644
--- a/src/storage/fs_test/watcher.cc
+++ b/src/storage/fs_test/watcher.cc
@@ -79,13 +79,12 @@
   DIR* dir = opendir(GetPath("dir").c_str());
   ASSERT_NE(dir, nullptr);
 
-  zx::result endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::DirectoryWatcher>::Create();
 
   fdio_cpp::FdioCaller caller(fbl::unique_fd(dirfd(dir)));
 
   auto watch_result = fidl::WireCall(caller.borrow_as<fio::Directory>())
-                          ->Watch(fio::wire::WatchMask::kAdded, 0, std::move(endpoints->server));
+                          ->Watch(fio::wire::WatchMask::kAdded, 0, std::move(endpoints.server));
   ASSERT_EQ(watch_result.status(), ZX_OK);
   ASSERT_EQ(watch_result->s, ZX_OK);
 
@@ -93,25 +92,25 @@
   memset(&wb, 0, sizeof(wb));
 
   // The channel should be empty
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   // Creating a file in the directory should trigger the watcher
   fbl::unique_fd fd(open(GetPath("dir/foo").c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
   ASSERT_TRUE(fd);
   ASSERT_EQ(close(fd.release()), 0);
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "foo", fio::wire::WatchEvent::kAdded));
+      CheckForEvent(&wb, endpoints.client, "foo", fio::wire::WatchEvent::kAdded));
 
   // Renaming into directory should trigger the watcher
   ASSERT_EQ(rename(GetPath("dir/foo").c_str(), GetPath("dir/bar").c_str()), 0);
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "bar", fio::wire::WatchEvent::kAdded));
+      CheckForEvent(&wb, endpoints.client, "bar", fio::wire::WatchEvent::kAdded));
 
   if (fs().GetTraits().supports_hard_links) {
     // Linking into directory should trigger the watcher
     ASSERT_EQ(link(GetPath("dir/bar").c_str(), GetPath("dir/blat").c_str()), 0);
     ASSERT_NO_FATAL_FAILURE(
-        CheckForEvent(&wb, endpoints->client, "blat", fio::wire::WatchEvent::kAdded));
+        CheckForEvent(&wb, endpoints.client, "blat", fio::wire::WatchEvent::kAdded));
     ASSERT_EQ(unlink(GetPath("dir/blat").c_str()), 0);
   }
 
@@ -119,7 +118,7 @@
   ASSERT_EQ(unlink(GetPath("dir/bar").c_str()), 0) << errno;
 
   // There shouldn't be anything else sitting around on the channel
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   // The fd is still owned by "dir".
   caller.release().release();
@@ -145,15 +144,14 @@
 
   // These files should be visible to the watcher through the "EXISTING"
   // mechanism.
-  zx::result endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::DirectoryWatcher>::Create();
 
   fdio_cpp::FdioCaller caller(fbl::unique_fd(dirfd(dir)));
   fio::wire::WatchMask mask =
       fio::wire::WatchMask::kAdded | fio::wire::WatchMask::kExisting | fio::wire::WatchMask::kIdle;
   {
     auto watch_result = fidl::WireCall(caller.borrow_as<fio::Directory>())
-                            ->Watch(mask, 0, std::move(endpoints->server));
+                            ->Watch(mask, 0, std::move(endpoints.server));
     ASSERT_EQ(watch_result.status(), ZX_OK);
     ASSERT_EQ(watch_result->s, ZX_OK);
   }
@@ -162,13 +160,13 @@
 
   // The channel should see the contents of the directory
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, ".", fio::wire::WatchEvent::kExisting));
+      CheckForEvent(&wb, endpoints.client, ".", fio::wire::WatchEvent::kExisting));
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "bar", fio::wire::WatchEvent::kExisting));
+      CheckForEvent(&wb, endpoints.client, "bar", fio::wire::WatchEvent::kExisting));
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "foo", fio::wire::WatchEvent::kExisting));
-  ASSERT_NO_FATAL_FAILURE(CheckForEvent(&wb, endpoints->client, "", fio::wire::WatchEvent::kIdle));
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+      CheckForEvent(&wb, endpoints.client, "foo", fio::wire::WatchEvent::kExisting));
+  ASSERT_NO_FATAL_FAILURE(CheckForEvent(&wb, endpoints.client, "", fio::wire::WatchEvent::kIdle));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   // Now, if we choose to add additional files, they'll show up separately
   // with an "ADD" event.
@@ -176,33 +174,31 @@
   ASSERT_TRUE(fd);
   ASSERT_EQ(close(fd.release()), 0);
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "goo", fio::wire::WatchEvent::kAdded));
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+      CheckForEvent(&wb, endpoints.client, "goo", fio::wire::WatchEvent::kAdded));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   // If we create a secondary watcher with the "EXISTING" request, we'll
   // see all files in the directory, but the first watcher won't see anything.
-  zx::result endpoints2 = fidl::CreateEndpoints<fio::DirectoryWatcher>();
-  ASSERT_TRUE(endpoints2.is_ok()) << endpoints.status_string();
+  auto endpoints2 = fidl::Endpoints<fio::DirectoryWatcher>::Create();
   {
     auto watch_result = fidl::WireCall(caller.borrow_as<fio::Directory>())
-                            ->Watch(mask, 0, std::move(endpoints2->server));
+                            ->Watch(mask, 0, std::move(endpoints2.server));
     ASSERT_EQ(watch_result.status(), ZX_OK);
     ASSERT_EQ(watch_result->s, ZX_OK);
   }
   WatchBuffer wb2;
   memset(&wb2, 0, sizeof(wb2));
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb2, endpoints2->client, ".", fio::wire::WatchEvent::kExisting));
+      CheckForEvent(&wb2, endpoints2.client, ".", fio::wire::WatchEvent::kExisting));
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb2, endpoints2->client, "bar", fio::wire::WatchEvent::kExisting));
+      CheckForEvent(&wb2, endpoints2.client, "bar", fio::wire::WatchEvent::kExisting));
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb2, endpoints2->client, "foo", fio::wire::WatchEvent::kExisting));
+      CheckForEvent(&wb2, endpoints2.client, "foo", fio::wire::WatchEvent::kExisting));
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb2, endpoints2->client, "goo", fio::wire::WatchEvent::kExisting));
-  ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb2, endpoints2->client, "", fio::wire::WatchEvent::kIdle));
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb2, endpoints2->client));
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+      CheckForEvent(&wb2, endpoints2.client, "goo", fio::wire::WatchEvent::kExisting));
+  ASSERT_NO_FATAL_FAILURE(CheckForEvent(&wb2, endpoints2.client, "", fio::wire::WatchEvent::kIdle));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb2, endpoints2.client));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   // Clean up
   ASSERT_EQ(unlink(GetPath("dir/bar").c_str()), 0);
@@ -210,8 +206,8 @@
   ASSERT_EQ(unlink(GetPath("dir/goo").c_str()), 0);
 
   // There shouldn't be anything else sitting around on either channel
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb2, endpoints2->client));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb2, endpoints2.client));
 
   // The fd is still owned by "dir".
   caller.release().release();
@@ -224,42 +220,41 @@
   DIR* dir = opendir(GetPath("dir").c_str());
   ASSERT_NE(dir, nullptr);
 
-  zx::result endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::DirectoryWatcher>::Create();
 
   fio::wire::WatchMask mask = fio::wire::WatchMask::kAdded | fio::wire::WatchMask::kRemoved;
   fdio_cpp::FdioCaller caller(fbl::unique_fd(dirfd(dir)));
 
   auto watch_result = fidl::WireCall(caller.borrow_as<fio::Directory>())
-                          ->Watch(mask, 0, std::move(endpoints->server));
+                          ->Watch(mask, 0, std::move(endpoints.server));
   ASSERT_EQ(watch_result.status(), ZX_OK);
   ASSERT_EQ(watch_result->s, ZX_OK);
 
   WatchBuffer wb;
   memset(&wb, 0, sizeof(wb));
 
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   fbl::unique_fd fd(openat(dirfd(dir), "foo", O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR));
   ASSERT_TRUE(fd);
   ASSERT_EQ(close(fd.release()), 0);
 
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "foo", fio::wire::WatchEvent::kAdded));
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+      CheckForEvent(&wb, endpoints.client, "foo", fio::wire::WatchEvent::kAdded));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   ASSERT_EQ(rename(GetPath("dir/foo").c_str(), GetPath("dir/bar").c_str()), 0);
 
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "foo", fio::wire::WatchEvent::kRemoved));
+      CheckForEvent(&wb, endpoints.client, "foo", fio::wire::WatchEvent::kRemoved));
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "bar", fio::wire::WatchEvent::kAdded));
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+      CheckForEvent(&wb, endpoints.client, "bar", fio::wire::WatchEvent::kAdded));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   ASSERT_EQ(unlink(GetPath("dir/bar").c_str()), 0);
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, "bar", fio::wire::WatchEvent::kRemoved));
-  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints->client));
+      CheckForEvent(&wb, endpoints.client, "bar", fio::wire::WatchEvent::kRemoved));
+  ASSERT_NO_FATAL_FAILURE(CheckForEmpty(&wb, endpoints.client));
 
   // The fd is still owned by "dir".
   caller.release().release();
@@ -278,13 +273,11 @@
   ASSERT_NE(dir, nullptr);
 
   {
-    zx::result endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
-    ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+    auto endpoints = fidl::Endpoints<fio::DirectoryWatcher>::Create();
 
     fdio_cpp::FdioCaller caller(fbl::unique_fd(dirfd(dir)));
-    auto watch_result =
-        fidl::WireCall(caller.borrow_as<fio::Directory>())
-            ->Watch(fio::wire::WatchMask::kDeleted, 0, std::move(endpoints->server));
+    auto watch_result = fidl::WireCall(caller.borrow_as<fio::Directory>())
+                            ->Watch(fio::wire::WatchMask::kDeleted, 0, std::move(endpoints.server));
     ASSERT_EQ(watch_result.status(), ZX_OK);
     ASSERT_EQ(watch_result->s, ZX_OK);
     std::string dir2_name = GetPath("dir2");
@@ -295,19 +288,18 @@
 
     WatchBuffer wb = {};
     ASSERT_NO_FATAL_FAILURE(
-        CheckForEvent(&wb, endpoints->client, ".", fio::wire::WatchEvent::kDeleted));
+        CheckForEvent(&wb, endpoints.client, ".", fio::wire::WatchEvent::kDeleted));
   }
 
   closedir(dir);
   dir = opendir(dir_name.c_str());
   ASSERT_NE(dir, nullptr);
 
-  zx::result endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
-  ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
+  auto endpoints = fidl::Endpoints<fio::DirectoryWatcher>::Create();
 
   fdio_cpp::FdioCaller caller(fbl::unique_fd(dirfd(dir)));
   auto watch_result = fidl::WireCall(caller.borrow_as<fio::Directory>())
-                          ->Watch(fio::wire::WatchMask::kDeleted, 0, std::move(endpoints->server));
+                          ->Watch(fio::wire::WatchMask::kDeleted, 0, std::move(endpoints.server));
   ASSERT_EQ(watch_result.status(), ZX_OK);
   ASSERT_EQ(watch_result->s, ZX_OK);
 
@@ -316,7 +308,7 @@
 
   WatchBuffer wb = {};
   ASSERT_NO_FATAL_FAILURE(
-      CheckForEvent(&wb, endpoints->client, ".", fio::wire::WatchEvent::kDeleted));
+      CheckForEvent(&wb, endpoints.client, ".", fio::wire::WatchEvent::kDeleted));
 
   closedir(dir);
 }
diff --git a/src/storage/fshost/integration/BUILD.gn b/src/storage/fshost/integration/BUILD.gn
index c464124..81139c7 100644
--- a/src/storage/fshost/integration/BUILD.gn
+++ b/src/storage/fshost/integration/BUILD.gn
@@ -62,82 +62,51 @@
   ]
 }
 
-# Generates an fshost integration test component. Includes the fshost component on which the test
-# is exectuted.
+# Generates an fshost integration test component based on one of the integration test files. The
+# binary also has config.rs included, and a couple of default dependencies, but the rest should be
+# specified as needed for the tests in the file.
 #
-#   extra_deps (optional)
-#     [array] A list of extra deps
+#   data_filesystem_variant (required)
+#     [string] A variant string passed to the integration test harness.
 #
-#   options.data_filesystem_format (required)
+#   data_filesystem_format (required)
 #     [string] The format of the data partition fshost exports. One of "fxfs", "minfs", or "f2fs".
-#              The options scope can also contain additional fshost options if required.
 #
-#   data_filesystem_variant (optional)
-#     [string] A variant string passed to the integration test harness. Defaults to the
-#              data_filesystem_format.
+#   fshost_target (required)
+#     [string] The target for the fshost under test.
 #
-template("fshost_integration_test") {
-  assert(defined(invoker.options), "fshost options not specified")
-  fshost_options = invoker.options
-  if (!defined(invoker.data_filesystem_variant)) {
-    invoker.data_filesystem_variant = fshost_options.data_filesystem_format
-  }
-
-  _fshost_target = "test-fshost-${target_name}"
-  fshost_component_and_config(_fshost_target) {
-    testonly = true
-    options = invoker.options
-    if (!defined(options.use_disk_migration)) {
-      options.use_disk_migration = true
-    }
-  }
-
-  _fshost_component_name = get_label_info(_fshost_target, "name")
+#   source_root (required)
+#     [string] The main file for the integration test. Likely one of the files under "tests".
+#
+#   deps (optional)
+#     [array] Dependencies for the rust test binary.
+#
+template("fshost_integration_test_component") {
+  _fshost_component_name = get_label_info(invoker.fshost_target, "name")
   _test_bin = string_replace(target_name, "-", "_")
   _test_bin = "${_test_bin}_bin"
   rustc_test(_test_bin) {
     edition = "2021"
-    source_root = "tests/fshost_integration_test.rs"
+    source_root = invoker.source_root
     sources = [
-      "tests/fshost_integration_test.rs",
-      "tests/migration.rs",
-      "tests/wipe_storage.rs",
-      "tests/write_data_file.rs",
+      "tests/config.rs",
+      invoker.source_root,
     ]
     rustenv = [
       "FSHOST_COMPONENT_NAME=${_fshost_component_name}",
-      "DATA_FILESYSTEM_FORMAT=${fshost_options.data_filesystem_format}",
+      "DATA_FILESYSTEM_FORMAT=${invoker.data_filesystem_format}",
       "DATA_FILESYSTEM_VARIANT=${invoker.data_filesystem_variant}",
     ]
     features = [
-      fshost_options.data_filesystem_format,
+      invoker.data_filesystem_format,
       invoker.data_filesystem_variant,
     ]
     deps = [
       ":fshost_test_fixture",
-      "//sdk/fidl/fuchsia.fshost:fuchsia.fshost_rust",
-      "//sdk/fidl/fuchsia.hardware.block:fuchsia.hardware.block_rust",
-      "//sdk/fidl/fuchsia.hardware.block.partition:fuchsia.hardware.block.partition_rust",
-      "//sdk/fidl/fuchsia.hardware.block.volume:fuchsia.hardware.block.volume_rust",
-      "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
-      "//sdk/lib/device-watcher/rust",
-      "//src/lib/fidl/rust/fidl",
       "//src/lib/fuchsia",
-      "//src/lib/fuchsia-async",
-      "//src/lib/fuchsia-component",
-      "//src/lib/fuchsia-fs",
-      "//src/lib/zircon/rust:fuchsia-zircon",
-      "//src/storage/fxfs/fidl/fuchsia.fxfs:fuchsia.fxfs_rust",
-      "//src/storage/lib/block_client/rust:remote-block-device",
-      "//src/storage/lib/delivery_blob",
-      "//src/storage/lib/fs_management/rust:fs_management",
-      "//src/sys/pkg/lib/fuchsia-merkle",
-      "//third_party/rust_crates:assert_matches",
-      "//third_party/rust_crates:futures",
-      "//third_party/rust_crates:tracing",
     ]
-    if (defined(invoker.extra_deps)) {
-      deps += invoker.extra_deps
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
     }
   }
 
@@ -171,14 +140,143 @@
   fuchsia_test_component(target_name) {
     manifest = _manifest
     deps = [
-      ":$_fshost_target",
       ":$_manifest_target",
       ":$_test_bin",
     ]
   }
 }
 
-fshost_integration_test("fshost_integration_tests_fxfs") {
+# Generates an fshost integration test package. Includes the fshost component on which the test is
+# executed.
+#
+#   extra_deps (optional)
+#     [array] A list of extra deps for the general integration test component. These deps are not
+#             added to any of the other components right now. NB: if other test components need
+#             extra deps then come up with a different solution here.
+#
+#   options.data_filesystem_format (required)
+#     [string] The format of the data partition fshost exports. One of "fxfs", "minfs", or "f2fs".
+#              The options scope can also contain additional fshost options if required.
+#
+#   data_filesystem_variant (optional)
+#     [string] A variant string passed to the integration test harness. Defaults to the
+#              data_filesystem_format.
+#
+template("fshost_integration_test_package") {
+  assert(defined(invoker.options), "fshost options not specified")
+  fshost_options = invoker.options
+  if (!defined(invoker.data_filesystem_variant)) {
+    invoker.data_filesystem_variant = fshost_options.data_filesystem_format
+  }
+
+  _fshost_target = "test-fshost-${target_name}"
+  fshost_component_and_config(_fshost_target) {
+    testonly = true
+    options = invoker.options
+    if (!defined(options.use_disk_migration)) {
+      options.use_disk_migration = true
+    }
+  }
+
+  _integration_component_target = "${target_name}_general"
+  fshost_integration_test_component(_integration_component_target) {
+    fshost_target = _fshost_target
+    data_filesystem_format = fshost_options.data_filesystem_format
+    data_filesystem_variant = invoker.data_filesystem_variant
+    source_root = "tests/fshost_integration_test.rs"
+    deps = [
+      "//sdk/fidl/fuchsia.fshost:fuchsia.fshost_rust",
+      "//sdk/fidl/fuchsia.hardware.block.volume:fuchsia.hardware.block.volume_rust",
+      "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
+      "//sdk/lib/device-watcher/rust",
+      "//src/lib/fidl/rust/fidl",
+      "//src/lib/fuchsia-async",
+      "//src/lib/fuchsia-component",
+      "//src/lib/fuchsia-fs",
+      "//src/lib/zircon/rust:fuchsia-zircon",
+      "//src/storage/fxfs/fidl/fuchsia.fxfs:fuchsia.fxfs_rust",
+      "//src/storage/lib/delivery_blob",
+      "//src/storage/lib/fs_management/rust:fs_management",
+      "//src/sys/pkg/lib/fuchsia-merkle",
+      "//third_party/rust_crates:assert_matches",
+      "//third_party/rust_crates:futures",
+      "//third_party/rust_crates:tracing",
+    ]
+    if (defined(invoker.extra_deps)) {
+      deps += invoker.extra_deps
+    }
+  }
+
+  _migration_component_target = "${target_name}_migration"
+  fshost_integration_test_component(_migration_component_target) {
+    fshost_target = _fshost_target
+    data_filesystem_format = fshost_options.data_filesystem_format
+    data_filesystem_variant = invoker.data_filesystem_variant
+    source_root = "tests/migration.rs"
+  }
+
+  _wipe_storage_component_target = "${target_name}_wipe_storage"
+  fshost_integration_test_component(_wipe_storage_component_target) {
+    fshost_target = _fshost_target
+    data_filesystem_format = fshost_options.data_filesystem_format
+    data_filesystem_variant = invoker.data_filesystem_variant
+    source_root = "tests/wipe_storage.rs"
+    deps = [
+      "//sdk/fidl/fuchsia.fshost:fuchsia.fshost_rust",
+      "//sdk/fidl/fuchsia.hardware.block:fuchsia.hardware.block_rust",
+      "//sdk/fidl/fuchsia.hardware.block.partition:fuchsia.hardware.block.partition_rust",
+      "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
+      "//sdk/lib/device-watcher/rust",
+      "//src/lib/fidl/rust/fidl",
+      "//src/lib/fuchsia-fs",
+      "//src/lib/zircon/rust:fuchsia-zircon",
+      "//src/storage/lib/block_client/rust:remote-block-device",
+      "//src/storage/lib/fs_management/rust:fs_management",
+    ]
+  }
+
+  _write_data_file_component_target = "${target_name}_write_data_file"
+  fshost_integration_test_component(_write_data_file_component_target) {
+    fshost_target = _fshost_target
+    data_filesystem_format = fshost_options.data_filesystem_format
+    data_filesystem_variant = invoker.data_filesystem_variant
+    source_root = "tests/write_data_file.rs"
+    deps = [
+      "//sdk/fidl/fuchsia.fshost:fuchsia.fshost_rust",
+      "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
+      "//src/lib/fuchsia-fs",
+      "//src/lib/zircon/rust:fuchsia-zircon",
+    ]
+  }
+
+  fuchsia_test_package(target_name) {
+    test_specs = {
+      log_settings = {
+        max_severity = "ERROR"
+      }
+    }
+    test_components = [
+      ":$_integration_component_target",
+      ":$_migration_component_target",
+      ":$_wipe_storage_component_target",
+      ":$_write_data_file_component_target",
+    ]
+    deps = [
+      ":$_fshost_target",
+      "//src/storage/testing:storage_driver_test_realm",
+
+      # We need to make sure we have all the filesystems available in the package for various tests
+      # of the migration paths.
+      "//src/storage/blobfs/bin:component",
+      "//src/storage/f2fs/bin:f2fs-component",
+      "//src/storage/fxfs:fxfs_component",
+      "//src/storage/fxfs-crypt",
+      "//src/storage/minfs/bin:minfs-component",
+    ]
+  }
+}
+
+fshost_integration_test_package("fshost_integration_tests_fxfs") {
   data_filesystem_variant = "fxblob"
   options = {
     data_filesystem_format = "fxfs"
@@ -190,28 +288,28 @@
   ]
 }
 
-fshost_integration_test("fshost_integration_tests_fxfs_no_fxblob") {
+fshost_integration_test_package("fshost_integration_tests_fxfs_no_fxblob") {
   options = {
     data_filesystem_format = "fxfs"
     fxfs_blob = false
   }
 }
 
-fshost_integration_test("fshost_integration_tests_f2fs") {
+fshost_integration_test_package("fshost_integration_tests_f2fs") {
   options = {
     data_filesystem_format = "f2fs"
     fxfs_blob = false
   }
 }
 
-fshost_integration_test("fshost_integration_tests_minfs") {
+fshost_integration_test_package("fshost_integration_tests_minfs") {
   options = {
     data_filesystem_format = "minfs"
     fxfs_blob = false
   }
 }
 
-fshost_integration_test("fshost_integration_tests_f2fs_no_zxcrypt") {
+fshost_integration_test_package("fshost_integration_tests_f2fs_no_zxcrypt") {
   data_filesystem_variant = "f2fs-no-zxcrypt"
   options = {
     no_zxcrypt = true
@@ -220,7 +318,7 @@
   }
 }
 
-fshost_integration_test("fshost_integration_tests_minfs_no_zxcrypt") {
+fshost_integration_test_package("fshost_integration_tests_minfs_no_zxcrypt") {
   data_filesystem_variant = "minfs-no-zxcrypt"
   options = {
     no_zxcrypt = true
@@ -229,26 +327,14 @@
   }
 }
 
-fuchsia_test_package("fshost_integration_tests") {
-  # Currently required because the data_formatted test causes Fxfs to log:
-  #   ERROR: ... handle_start failed error=Journal replay failed
-  test_specs = {
-    log_settings = {
-      max_severity = "ERROR"
-    }
-  }
-  test_components = [
-    ":fshost_integration_tests_fxfs",
-    ":fshost_integration_tests_f2fs",
-    ":fshost_integration_tests_minfs",
-    ":fshost_integration_tests_f2fs_no_zxcrypt",
-    ":fshost_integration_tests_minfs_no_zxcrypt",
-    ":fshost_integration_tests_fxfs_no_fxblob",
-  ]
-  deps = [ "//src/storage/testing:storage_driver_test_realm" ]
-}
-
 group("tests") {
   testonly = true
-  deps = [ ":fshost_integration_tests" ]
+  deps = [
+    ":fshost_integration_tests_f2fs",
+    ":fshost_integration_tests_f2fs_no_zxcrypt",
+    ":fshost_integration_tests_fxfs",
+    ":fshost_integration_tests_fxfs_no_fxblob",
+    ":fshost_integration_tests_minfs",
+    ":fshost_integration_tests_minfs_no_zxcrypt",
+  ]
 }
diff --git a/src/storage/fshost/integration/src/disk_builder.rs b/src/storage/fshost/integration/src/disk_builder.rs
index 9306af6..be646fe 100644
--- a/src/storage/fshost/integration/src/disk_builder.rs
+++ b/src/storage/fshost/integration/src/disk_builder.rs
@@ -23,7 +23,6 @@
     },
     fuchsia_component_test::{Capability, ChildOptions, RealmBuilder, RealmInstance, Ref, Route},
     fuchsia_hash::Hash,
-    fuchsia_merkle::MerkleTreeBuilder,
     fuchsia_runtime::vmar_root_self,
     fuchsia_zircon::{self as zx, HandleBased},
     gpt::{partition_types, GptConfig},
@@ -204,9 +203,7 @@
     data: &[u8],
     as_delivery_blob: bool,
 ) -> Hash {
-    let mut builder = MerkleTreeBuilder::new();
-    builder.write(&data);
-    let hash = builder.finish().root();
+    let hash = fuchsia_merkle::from_slice(data).root();
     let compressed_data = Type1Blob::generate(&data, CompressionMode::Always);
     let (name, data) = if as_delivery_blob {
         (delivery_blob_path(hash), compressed_data.as_slice())
@@ -235,9 +232,7 @@
 /// Write a blob to the fxfs blob volume to ensure that on format, the blob volume does not get
 /// wiped.
 pub async fn write_test_blob_fxblob(blob_creator: BlobCreatorProxy, data: &[u8]) -> Hash {
-    let mut builder = MerkleTreeBuilder::new();
-    builder.write(&data);
-    let hash = builder.finish().root();
+    let hash = fuchsia_merkle::from_slice(data).root();
     let compressed_data = Type1Blob::generate(&data, CompressionMode::Always);
 
     let blob_writer_client_end = blob_creator
diff --git a/src/storage/fshost/integration/src/lib.rs b/src/storage/fshost/integration/src/lib.rs
index a007ab4..322ef03 100644
--- a/src/storage/fshost/integration/src/lib.rs
+++ b/src/storage/fshost/integration/src/lib.rs
@@ -10,7 +10,6 @@
     fuchsia_async as fasync,
     fuchsia_component::client::connect_to_protocol_at_dir_root,
     fuchsia_component_test::{Capability, ChildOptions, RealmBuilder, RealmInstance, Ref, Route},
-    fuchsia_merkle::MerkleTreeBuilder,
     fuchsia_zircon as zx,
     futures::{
         channel::mpsc::{self},
@@ -26,6 +25,17 @@
 
 pub use disk_builder::{write_test_blob, write_test_blob_fxblob};
 
+pub const VFS_TYPE_BLOBFS: u32 = 0x9e694d21;
+pub const VFS_TYPE_MINFS: u32 = 0x6e694d21;
+pub const VFS_TYPE_MEMFS: u32 = 0x3e694d21;
+pub const VFS_TYPE_FXFS: u32 = 0x73667866;
+pub const VFS_TYPE_F2FS: u32 = 0xfe694d21;
+pub const BLOBFS_MAX_BYTES: u64 = 8765432;
+// DATA_MAX_BYTES must be greater than DEFAULT_F2FS_MIN_BYTES
+// (defined in device/constants.rs) to ensure that when f2fs is
+// the data filesystem format, we don't run out of space
+pub const DATA_MAX_BYTES: u64 = 109876543;
+
 pub struct TestFixtureBuilder {
     netboot: bool,
     no_fuchsia_boot: bool,
@@ -242,21 +252,14 @@
     }
 
     pub async fn check_test_blob(&self, use_fxblob: bool) {
+        let expected_blob_hash = fuchsia_merkle::from_slice(&disk_builder::BLOB_CONTENTS).root();
         if use_fxblob {
-            let mut builder = MerkleTreeBuilder::new();
-            builder.write(&disk_builder::BLOB_CONTENTS);
-            let expected_blob_hash = builder.finish().root();
-
             let reader = connect_to_protocol_at_dir_root::<BlobReaderMarker>(
                 self.realm.root.get_exposed_dir(),
             )
             .expect("failed to connect to the BlobReader");
             let _vmo = reader.get_vmo(&expected_blob_hash.into()).await.unwrap().unwrap();
         } else {
-            let mut builder = MerkleTreeBuilder::new();
-            builder.write(&disk_builder::BLOB_CONTENTS);
-            let expected_blob_hash = builder.finish().root();
-
             let (blob, server_end) =
                 create_proxy::<fio::FileMarker>().expect("create_proxy failed");
             let path = &format!("{}", expected_blob_hash);
diff --git a/src/storage/fshost/integration/tests/config.rs b/src/storage/fshost/integration/tests/config.rs
new file mode 100644
index 0000000..e8b518d
--- /dev/null
+++ b/src/storage/fshost/integration/tests/config.rs
@@ -0,0 +1,58 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//! The config module contains shared code that captures the environment to configure the test
+//! runs. It must live in the binary directly, instead of in the fixture crate, which is why it
+//! lives here and is recompiled into each separate test.
+
+use fshost_test_fixture::{
+    disk_builder::{DataSpec, VolumesSpec},
+    TestFixtureBuilder, VFS_TYPE_BLOBFS, VFS_TYPE_F2FS, VFS_TYPE_FXFS, VFS_TYPE_MINFS,
+};
+
+pub const FSHOST_COMPONENT_NAME: &'static str = std::env!("FSHOST_COMPONENT_NAME");
+pub const DATA_FILESYSTEM_FORMAT: &'static str = std::env!("DATA_FILESYSTEM_FORMAT");
+pub const DATA_FILESYSTEM_VARIANT: &'static str = std::env!("DATA_FILESYSTEM_VARIANT");
+
+pub fn new_builder() -> TestFixtureBuilder {
+    TestFixtureBuilder::new(FSHOST_COMPONENT_NAME)
+}
+
+pub fn blob_fs_type() -> u32 {
+    if DATA_FILESYSTEM_VARIANT == "fxblob" {
+        VFS_TYPE_FXFS
+    } else {
+        VFS_TYPE_BLOBFS
+    }
+}
+
+pub fn data_fs_type() -> u32 {
+    match DATA_FILESYSTEM_FORMAT {
+        "f2fs" => VFS_TYPE_F2FS,
+        "fxfs" => VFS_TYPE_FXFS,
+        "minfs" => VFS_TYPE_MINFS,
+        _ => panic!("invalid data filesystem format"),
+    }
+}
+
+pub fn data_fs_name() -> &'static str {
+    match DATA_FILESYSTEM_FORMAT {
+        "f2fs" => "f2fs",
+        "fxfs" => "fxfs",
+        "minfs" => "minfs",
+        _ => panic!("invalid data filesystem format"),
+    }
+}
+
+pub fn data_fs_zxcrypt() -> bool {
+    !DATA_FILESYSTEM_VARIANT.ends_with("no-zxcrypt")
+}
+
+pub fn volumes_spec() -> VolumesSpec {
+    VolumesSpec { fxfs_blob: DATA_FILESYSTEM_VARIANT == "fxblob", create_data_partition: true }
+}
+
+pub fn data_fs_spec() -> DataSpec {
+    DataSpec { format: Some(data_fs_name()), zxcrypt: data_fs_zxcrypt() }
+}
diff --git a/src/storage/fshost/integration/tests/fshost_integration_test.rs b/src/storage/fshost/integration/tests/fshost_integration_test.rs
index f1faadb..165c3fa 100644
--- a/src/storage/fshost/integration/tests/fshost_integration_test.rs
+++ b/src/storage/fshost/integration/tests/fshost_integration_test.rs
@@ -19,11 +19,10 @@
     fshost_test_fixture::disk_builder::DEFAULT_DATA_VOLUME_SIZE,
     fshost_test_fixture::{
         disk_builder::{DataSpec, VolumesSpec, FVM_SLICE_SIZE},
-        TestFixtureBuilder,
+        BLOBFS_MAX_BYTES, DATA_MAX_BYTES, VFS_TYPE_FXFS, VFS_TYPE_MEMFS, VFS_TYPE_MINFS,
     },
     fuchsia_async as fasync,
     fuchsia_component::client::connect_to_named_protocol_at_dir_root,
-    fuchsia_merkle::MerkleTreeBuilder,
     fuchsia_zircon::{self as zx, HandleBased},
     futures::FutureExt,
 };
@@ -35,68 +34,12 @@
     fidl_fuchsia_update_verify::{BlobfsVerifierMarker, VerifyOptions},
 };
 
-mod migration;
-mod wipe_storage;
-mod write_data_file;
+pub mod config;
 
-const FSHOST_COMPONENT_NAME: &'static str = std::env!("FSHOST_COMPONENT_NAME");
-const DATA_FILESYSTEM_FORMAT: &'static str = std::env!("DATA_FILESYSTEM_FORMAT");
-const DATA_FILESYSTEM_VARIANT: &'static str = std::env!("DATA_FILESYSTEM_VARIANT");
-
-fn new_builder() -> TestFixtureBuilder {
-    TestFixtureBuilder::new(FSHOST_COMPONENT_NAME)
-}
-
-// const VFS_TYPE_FATFS: u32 = 0xce694d21;
-const VFS_TYPE_BLOBFS: u32 = 0x9e694d21;
-const VFS_TYPE_MINFS: u32 = 0x6e694d21;
-const VFS_TYPE_MEMFS: u32 = 0x3e694d21;
-// const VFS_TYPE_FACTORYFS: u32 = 0x1e694d21;
-const VFS_TYPE_FXFS: u32 = 0x73667866;
-const VFS_TYPE_F2FS: u32 = 0xfe694d21;
-const BLOBFS_MAX_BYTES: u64 = 8765432;
-// DATA_MAX_BYTES must be greater than DEFAULT_F2FS_MIN_BYTES
-// (defined in device/constants.rs) to ensure that when f2fs is
-// the data filesystem format, we don't run out of space
-const DATA_MAX_BYTES: u64 = 109876543;
-
-fn blob_fs_type() -> u32 {
-    if DATA_FILESYSTEM_VARIANT == "fxblob" {
-        VFS_TYPE_FXFS
-    } else {
-        VFS_TYPE_BLOBFS
-    }
-}
-
-fn data_fs_type() -> u32 {
-    match DATA_FILESYSTEM_FORMAT {
-        "f2fs" => VFS_TYPE_F2FS,
-        "fxfs" => VFS_TYPE_FXFS,
-        "minfs" => VFS_TYPE_MINFS,
-        _ => panic!("invalid data filesystem format"),
-    }
-}
-
-fn data_fs_name() -> &'static str {
-    match DATA_FILESYSTEM_FORMAT {
-        "f2fs" => "f2fs",
-        "fxfs" => "fxfs",
-        "minfs" => "minfs",
-        _ => panic!("invalid data filesystem format"),
-    }
-}
-
-fn data_fs_zxcrypt() -> bool {
-    !DATA_FILESYSTEM_VARIANT.ends_with("no-zxcrypt")
-}
-
-fn volumes_spec() -> VolumesSpec {
-    VolumesSpec { fxfs_blob: DATA_FILESYSTEM_VARIANT == "fxblob", create_data_partition: true }
-}
-
-fn data_fs_spec() -> DataSpec {
-    DataSpec { format: Some(data_fs_name()), zxcrypt: data_fs_zxcrypt() }
-}
+use config::{
+    blob_fs_type, data_fs_name, data_fs_spec, data_fs_type, data_fs_zxcrypt, new_builder,
+    volumes_spec, DATA_FILESYSTEM_FORMAT, DATA_FILESYSTEM_VARIANT,
+};
 
 #[fuchsia::test]
 async fn blobfs_and_data_mounted() {
@@ -451,9 +394,7 @@
     fuchsia_fs::file::write(&file, "file contents!").await.unwrap();
 
     let blob_contents = vec![0; 8192];
-    let mut builder = MerkleTreeBuilder::new();
-    builder.write(&blob_contents);
-    let hash = builder.finish().root();
+    let hash = fuchsia_merkle::from_slice(&blob_contents).root();
 
     let blob_root = fixture.dir("blob", flags);
     let blob =
@@ -485,9 +426,7 @@
     fuchsia_fs::file::write(&file, "file contents!").await.unwrap();
 
     let blob_contents = vec![0; 8192];
-    let mut builder = MerkleTreeBuilder::new();
-    builder.write(&blob_contents);
-    let hash = builder.finish().root();
+    let hash = fuchsia_merkle::from_slice(&blob_contents).root();
     let compressed_data: Vec<u8> = Type1Blob::generate(&blob_contents, CompressionMode::Always);
 
     let blob_proxy = fixture
@@ -1118,9 +1057,7 @@
     let fixture = builder.build().await;
 
     let data: Vec<u8> = vec![0xff; 65536];
-    let mut merkle_tree_builder = MerkleTreeBuilder::new();
-    merkle_tree_builder.write(&data);
-    let hash = merkle_tree_builder.finish().root();
+    let hash = fuchsia_merkle::from_slice(&data).root();
     let payload = Type1Blob::generate(&data, CompressionMode::Always);
 
     let blob_creator = fixture
diff --git a/src/storage/fshost/integration/tests/migration.rs b/src/storage/fshost/integration/tests/migration.rs
index 84e537a..87f8fda 100644
--- a/src/storage/fshost/integration/tests/migration.rs
+++ b/src/storage/fshost/integration/tests/migration.rs
@@ -31,7 +31,9 @@
 //! filesystems which use zxcrypt, there is a set for both with and without zxcrypt. This covers
 //! all the goal states, so we just need one test for each original state.
 
-use crate::{data_fs_name, data_fs_type, new_builder, volumes_spec, DataSpec, DATA_MAX_BYTES};
+pub mod config;
+use config::{data_fs_name, data_fs_type, new_builder, volumes_spec};
+use fshost_test_fixture::{disk_builder::DataSpec, DATA_MAX_BYTES};
 
 /// f2fs requires more space than other filesystems so we use different values for it..
 fn data_max_bytes() -> u64 {
diff --git a/src/storage/fshost/integration/tests/wipe_storage.rs b/src/storage/fshost/integration/tests/wipe_storage.rs
index 6893177..ecb530d 100644
--- a/src/storage/fshost/integration/tests/wipe_storage.rs
+++ b/src/storage/fshost/integration/tests/wipe_storage.rs
@@ -6,7 +6,6 @@
 //! among other things, sets the ramdisk_image flag to prevent binding of the on-disk filesystems.)
 
 use {
-    crate::{blob_fs_type, data_fs_spec, data_fs_type, new_builder, volumes_spec, VolumesSpec},
     device_watcher::recursive_wait,
     fidl::endpoints::{create_proxy, Proxy as _},
     fidl_fuchsia_fshost as fshost,
@@ -14,11 +13,14 @@
     fidl_fuchsia_hardware_block_partition::PartitionMarker,
     fidl_fuchsia_io as fio,
     fs_management::partition::{find_partition_in, PartitionMatcher},
-    fshost_test_fixture::{write_test_blob, write_test_blob_fxblob},
+    fshost_test_fixture::{disk_builder::VolumesSpec, write_test_blob, write_test_blob_fxblob},
     fuchsia_zircon as zx,
     remote_block_device::{BlockClient, MutableBufferSlice, RemoteBlockClient},
 };
 
+pub mod config;
+use config::{blob_fs_type, data_fs_spec, data_fs_type, new_builder, volumes_spec};
+
 const TEST_BLOB_DATA: [u8; 8192] = [0xFF; 8192];
 // TODO(https://fxbug.dev/42072287): Remove hardcoded paths
 const GPT_PATH: &'static str = "/part-000/block";
diff --git a/src/storage/fshost/integration/tests/write_data_file.rs b/src/storage/fshost/integration/tests/write_data_file.rs
index 566c2bf..d7983ee 100644
--- a/src/storage/fshost/integration/tests/write_data_file.rs
+++ b/src/storage/fshost/integration/tests/write_data_file.rs
@@ -6,15 +6,18 @@
 //! among other things, sets the ramdisk_image flag to prevent binding of the on-disk filesystems.)
 
 use {
-    super::{
-        blob_fs_type, data_fs_name, data_fs_spec, data_fs_type, new_builder, volumes_spec,
-        VolumesSpec, DATA_FILESYSTEM_VARIANT,
-    },
     fidl_fuchsia_fshost as fshost, fidl_fuchsia_io as fio,
     fshost::{AdminProxy, AdminWriteDataFileResult},
+    fshost_test_fixture::disk_builder::VolumesSpec,
     fuchsia_zircon::{self as zx, HandleBased as _},
 };
 
+pub mod config;
+use config::{
+    blob_fs_type, data_fs_name, data_fs_spec, data_fs_type, new_builder, volumes_spec,
+    DATA_FILESYSTEM_VARIANT,
+};
+
 const PAYLOAD: &[u8] = b"top secret stuff";
 const SECRET_FILE_NAME: &'static str = "inconspicuous/secret.txt";
 const SMALL_DISK_SIZE: u64 = 25165824;
diff --git a/src/storage/fxfs/BUILD.gn b/src/storage/fxfs/BUILD.gn
index f97fca0..1ed3c43 100644
--- a/src/storage/fxfs/BUILD.gn
+++ b/src/storage/fxfs/BUILD.gn
@@ -204,10 +204,13 @@
   configs += [
     # Optimize for size
     "//build/config/rust:bootfs",
-
-    # Optimize for speed (Fxfs is split into several crates; apply optimizations across them).
-    "//build/config/rust:lto_thin",
   ]
+
+  # Add thinlto config if lto variants are not used.
+  if (!is_lto_variant) {
+    # Optimize for speed (Fxfs is split into several crates; apply optimizations across them).
+    configs += [ "//build/config/lto:thinlto" ]
+  }
 }
 
 fuchsia_component("fxfs_component") {
diff --git a/src/storage/fxfs/make-blob-image/src/lib.rs b/src/storage/fxfs/make-blob-image/src/lib.rs
index 7340d4f..1f81495 100644
--- a/src/storage/fxfs/make-blob-image/src/lib.rs
+++ b/src/storage/fxfs/make-blob-image/src/lib.rs
@@ -6,7 +6,7 @@
     anyhow::{anyhow, Context, Error},
     delivery_blob::compression::ChunkedArchive,
     fuchsia_async as fasync,
-    fuchsia_merkle::{Hash, MerkleTreeBuilder, HASH_SIZE},
+    fuchsia_merkle::{Hash, HASH_SIZE},
     futures::{try_join, SinkExt as _, StreamExt as _, TryStreamExt as _},
     fxfs::{
         errors::FxfsError,
@@ -321,9 +321,7 @@
         .with_context(|| format!("Unable to read contents of `{:?}'", &path))?;
     let hashes = {
         // TODO(https://fxbug.dev/42073036): Refactor to share implementation with blob.rs.
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&contents);
-        let tree = builder.finish();
+        let tree = fuchsia_merkle::from_slice(&contents);
         assert_eq!(tree.root(), hash);
         let mut hashes: Vec<[u8; HASH_SIZE]> = Vec::new();
         let levels = tree.as_ref();
@@ -376,7 +374,6 @@
         super::{make_blob_image, BlobsJsonOutput, BlobsJsonOutputEntry},
         assert_matches::assert_matches,
         fuchsia_async as fasync,
-        fuchsia_merkle::MerkleTreeBuilder,
         fxfs::{
             filesystem::FxFilesystem,
             object_store::{directory::Directory, volume::root_volume},
@@ -400,9 +397,7 @@
             let write_data = |path, data: &str| {
                 let mut file = File::create(&path).unwrap();
                 write!(file, "{}", data).unwrap();
-                let mut builder = MerkleTreeBuilder::new();
-                builder.write(data.as_bytes());
-                let tree = builder.finish();
+                let tree = fuchsia_merkle::from_slice(data.as_bytes());
                 (tree.root(), path)
             };
             vec![
diff --git a/src/storage/fxfs/platform/src/fuchsia/device.rs b/src/storage/fxfs/platform/src/fuchsia/device.rs
index d42e6c2..41e5e1f 100644
--- a/src/storage/fxfs/platform/src/fuchsia/device.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/device.rs
@@ -625,7 +625,6 @@
         fidl_fuchsia_hardware_block_volume::VolumeAndNodeMarker,
         fidl_fuchsia_io as fio,
         fs_management::{filesystem::Filesystem, Blobfs},
-        fuchsia_merkle::MerkleTree,
         fuchsia_zircon as zx,
         futures::join,
         remote_block_device::{BlockClient, RemoteBlockClient, VmoId},
@@ -1035,8 +1034,7 @@
                 let serving = blobfs.serve().await.expect("serve blobfs failed");
 
                 let content = String::from("Hello world!").into_bytes();
-                let merkle_root_hash =
-                    MerkleTree::from_reader(&content[..]).unwrap().root().to_string();
+                let merkle_root_hash = fuchsia_merkle::from_slice(&content).root().to_string();
                 {
                     let file = fuchsia_fs::directory::open_file(
                         serving.root(),
diff --git a/src/storage/fxfs/platform/src/fuchsia/directory.rs b/src/storage/fxfs/platform/src/fuchsia/directory.rs
index b391d08..5759b42 100644
--- a/src/storage/fxfs/platform/src/fuchsia/directory.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/directory.rs
@@ -699,18 +699,16 @@
         requested_attributes: fio::NodeAttributesQuery,
     ) -> Result<fio::NodeAttributes2, zx::Status> {
         let props = self.directory.get_properties().await.map_err(map_to_status)?;
-        // TODO(https://fxbug.dev/324112547): Missing POSIX attributes should not be reported (i.e.
-        // they should be set to `None` instead of `0`).
         Ok(attributes!(
             requested_attributes,
             Mutable {
                 creation_time: props.creation_time.as_nanos(),
                 modification_time: props.modification_time.as_nanos(),
                 access_time: props.access_time.as_nanos(),
-                mode: props.posix_attributes.map(|a| a.mode).unwrap_or(0),
-                uid: props.posix_attributes.map(|a| a.uid).unwrap_or(0),
-                gid: props.posix_attributes.map(|a| a.gid).unwrap_or(0),
-                rdev: props.posix_attributes.map(|a| a.rdev).unwrap_or(0),
+                mode: props.posix_attributes.map(|a| a.mode),
+                uid: props.posix_attributes.map(|a| a.uid),
+                gid: props.posix_attributes.map(|a| a.gid),
+                rdev: props.posix_attributes.map(|a| a.rdev),
             },
             Immutable {
                 protocols: fio::NodeProtocolKinds::DIRECTORY,
@@ -2133,6 +2131,8 @@
                 .await
                 .expect("FIDL call failed");
             assert_eq!(attrs.mutable_attributes.mode.unwrap(), mode);
+            // Since the POSIX mode attribute was set, we expect default values for the other POSIX
+            // attributes.
             assert_eq!(attrs.mutable_attributes.uid.unwrap(), 0);
             // Expect these attributes to be None as they were not queried in `get_attributes(..)`
             assert!(attrs.mutable_attributes.gid.is_none());
@@ -2205,8 +2205,9 @@
                 .get_attributes(fio::NodeAttributesQuery::MODE)
                 .await
                 .expect("FIDL call failed");
-            // As mode was requested, `get_attributes(..)` must return a (default) value.
-            assert_eq!(attrs.mutable_attributes.mode.unwrap(), 0);
+            // Although mode was requested, it was not set when creating the directory. So we
+            // expect None.
+            assert!(attrs.mutable_attributes.mode.is_none());
             // The attributes not requested should be None.
             assert!(attrs.mutable_attributes.uid.is_none());
             assert!(attrs.mutable_attributes.gid.is_none());
@@ -2339,8 +2340,9 @@
                 .get_attributes(fio::NodeAttributesQuery::MODE)
                 .await
                 .expect("FIDL call failed");
-            // As mode was requested, `get_attributes(..)` must return a (default) value.
-            assert_eq!(attrs.mutable_attributes.mode.unwrap(), 0);
+            // Although mode was requested, it was not set when creating the directory. So we
+            // expect that it is None.
+            assert!(attrs.mutable_attributes.mode.is_none());
             // The attributes not requested should be None.
             assert!(attrs.mutable_attributes.uid.is_none());
             assert!(attrs.mutable_attributes.gid.is_none());
diff --git a/src/storage/fxfs/platform/src/fuchsia/file.rs b/src/storage/fxfs/platform/src/fuchsia/file.rs
index 9a66fa7f..b8e74f3 100644
--- a/src/storage/fxfs/platform/src/fuchsia/file.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/file.rs
@@ -302,18 +302,16 @@
         let props = self.handle.get_properties().await.map_err(map_to_status)?;
         let descriptor =
             self.handle.uncached_handle().get_descriptor().await.map_err(map_to_status)?;
-        // TODO(https://fxbug.dev/324112547): Missing POSIX attributes should not be reported (i.e.
-        // they should be set to `None` instead of `0`).
         Ok(attributes!(
             requested_attributes,
             Mutable {
                 creation_time: props.creation_time.as_nanos(),
                 modification_time: props.modification_time.as_nanos(),
                 access_time: props.access_time.as_nanos(),
-                mode: props.posix_attributes.map(|a| a.mode).unwrap_or(0),
-                uid: props.posix_attributes.map(|a| a.uid).unwrap_or(0),
-                gid: props.posix_attributes.map(|a| a.gid).unwrap_or(0),
-                rdev: props.posix_attributes.map(|a| a.rdev).unwrap_or(0),
+                mode: props.posix_attributes.map(|a| a.mode),
+                uid: props.posix_attributes.map(|a| a.uid),
+                gid: props.posix_attributes.map(|a| a.gid),
+                rdev: props.posix_attributes.map(|a| a.rdev),
             },
             Immutable {
                 protocols: fio::NodeProtocolKinds::FILE,
@@ -588,7 +586,7 @@
         },
         anyhow::format_err,
         fidl_fuchsia_io as fio,
-        fsverity_merkle::{FsVerityHasher, FsVerityHasherOptions, MerkleTreeBuilder},
+        fsverity_merkle::{FsVerityHasher, FsVerityHasherOptions},
         fuchsia_async as fasync,
         fuchsia_fs::file,
         fuchsia_zircon::Status,
@@ -1714,11 +1712,10 @@
                 .expect("write failed");
         }
 
-        let mut builder = MerkleTreeBuilder::new(FsVerityHasher::Sha256(
-            FsVerityHasherOptions::new(vec![0xFF; 8], 4096),
-        ));
-        builder.write(data.as_slice());
-        let tree = builder.finish();
+        let tree = fsverity_merkle::from_slice(
+            &data,
+            FsVerityHasher::Sha256(FsVerityHasherOptions::new(vec![0xFF; 8], 4096)),
+        );
         let mut expected_root = tree.root().to_vec();
         expected_root.extend_from_slice(&[0; 32]);
 
diff --git a/src/storage/fxfs/platform/src/fuchsia/fxblob/blob.rs b/src/storage/fxfs/platform/src/fuchsia/fxblob/blob.rs
index 1927927..25762fd 100644
--- a/src/storage/fxfs/platform/src/fuchsia/fxblob/blob.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/fxblob/blob.rs
@@ -9,7 +9,7 @@
     crate::fuchsia::{
         directory::FxDirectory,
         errors::map_to_status,
-        node::FxNode,
+        node::{FxNode, OpenedNode},
         pager::{
             default_page_in, MarkDirtyRange, PageInRange, PagerBacked,
             PagerPacketReceiverRegistration,
@@ -107,24 +107,6 @@
         }
     }
 
-    /// Creates an immutable child VMO.
-    pub fn create_child_vmo(&self) -> Result<zx::Vmo, Status> {
-        let child_vmo = self.vmo.create_child(
-            zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE | zx::VmoChildOptions::NO_WRITE,
-            0,
-            self.uncompressed_size,
-        )?;
-        if self.handle.owner().pager().watch_for_zero_children(self).map_err(map_to_status)? {
-            // Take an open count so that we keep this object alive if it is otherwise closed.
-            self.open_count_add_one();
-        }
-        // Only allow read access to the VMO.
-        // TODO(https://fxbug.dev/329429293): Remove when RFC-0238 is implemented.
-        child_vmo.replace_handle(
-            zx::Rights::BASIC | zx::Rights::MAP | zx::Rights::GET_PROPERTY | zx::Rights::READ,
-        )
-    }
-
     pub fn root(&self) -> Hash {
         self.merkle_tree.root()
     }
@@ -137,7 +119,34 @@
     }
 }
 
-/// Implements VFS pseudo-filesystem entries for blobs.
+impl OpenedNode<FxBlob> {
+    /// Creates a read-only child VMO for this blob backed by the pager. The blob cannot be purged
+    /// until all child VMOs have been destroyed.
+    ///
+    /// *WARNING*: We need to ensure the open count is non-zero before invoking this function, so
+    /// it is only implemented for [`OpenedNode<FxBlob>`]. This prevents the blob from being purged
+    /// before we get a chance to register it with the pager for [`zx::Signals::VMO_ZERO_CHILDREN`].
+    pub fn create_child_vmo(&self) -> Result<zx::Vmo, Status> {
+        let blob = self.0.as_ref();
+        let child_vmo = blob.vmo.create_child(
+            zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE | zx::VmoChildOptions::NO_WRITE,
+            0,
+            blob.uncompressed_size,
+        )?;
+        if blob.handle.owner().pager().watch_for_zero_children(blob).map_err(map_to_status)? {
+            // Take an open count so that we keep this object alive if it is otherwise closed. This
+            // is only valid since we know the current open count is non-zero, otherwise we might
+            // increment the open count after the blob has been purged.
+            blob.open_count_add_one();
+        }
+        // Only allow read access to the VMO.
+        // TODO(https://fxbug.dev/329429293): Remove when RFC-0238 is implemented.
+        child_vmo.replace_handle(
+            zx::Rights::BASIC | zx::Rights::MAP | zx::Rights::GET_PROPERTY | zx::Rights::READ,
+        )
+    }
+}
+
 impl FxNode for FxBlob {
     fn object_id(&self) -> u64 {
         self.handle.object_id()
diff --git a/src/storage/fxfs/platform/src/fuchsia/fxblob/directory.rs b/src/storage/fxfs/platform/src/fuchsia/fxblob/directory.rs
index c88dade..9a9753f 100644
--- a/src/storage/fxfs/platform/src/fuchsia/fxblob/directory.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/fxblob/directory.rs
@@ -6,18 +6,16 @@
 //! content-addressable blobs.
 
 use {
-    crate::{
+    crate::fuchsia::{
         component::map_to_raw_status,
-        fuchsia::{
-            directory::FxDirectory,
-            fxblob::{blob::FxBlob, writer::FxDeliveryBlob},
-            node::{FxNode, GetResult, OpenedNode},
-            volume::{FxVolume, RootDir},
-        },
+        directory::FxDirectory,
+        fxblob::{blob::FxBlob, writer::DeliveryBlobWriter},
+        node::{FxNode, GetResult, OpenedNode},
+        volume::{FxVolume, RootDir},
     },
-    anyhow::{anyhow, bail, ensure, Error},
+    anyhow::{anyhow, ensure, Context as _, Error},
     async_trait::async_trait,
-    fidl::endpoints::{create_proxy, ClientEnd, Proxy as _, ServerEnd},
+    fidl::endpoints::{create_request_stream, ClientEnd, ServerEnd},
     fidl_fuchsia_fxfs::{
         BlobCreatorRequest, BlobCreatorRequestStream, BlobReaderRequest, BlobReaderRequestStream,
         BlobWriterMarker, CreateBlobError,
@@ -33,11 +31,10 @@
     futures::{FutureExt, TryStreamExt},
     fxfs::{
         errors::FxfsError,
-        log::*,
         object_handle::ReadObjectHandle,
         object_store::{
             self,
-            transaction::{lock_keys, LockKey, Options},
+            transaction::{lock_keys, LockKey},
             HandleOptions, ObjectDescriptor, ObjectStore, BLOB_MERKLE_ATTRIBUTE_ID,
         },
         serialized_types::BlobMetadata,
@@ -72,15 +69,18 @@
     pub hash: Hash,
 }
 
-impl Identifier {
-    pub fn from_str(string: &str) -> Result<Self, Error> {
+impl TryFrom<&str> for Identifier {
+    type Error = FxfsError;
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
         Ok(Self {
-            string: string.to_owned(),
-            hash: Hash::from_str(string).map_err(|_| FxfsError::InvalidArgs)?,
+            string: value.to_owned(),
+            hash: Hash::from_str(value).map_err(|_| FxfsError::InvalidArgs)?,
         })
     }
+}
 
-    pub fn from_hash(hash: Hash) -> Self {
+impl From<Hash> for Identifier {
+    fn from(hash: Hash) -> Self {
         Self { string: hash.to_string(), hash }
     }
 }
@@ -102,17 +102,18 @@
     fn on_open(self: Arc<Self>) {
         fasync::Task::spawn(async move {
             if let Err(e) = self.prefetch_blobs().await {
-                warn!("Failed to prefetch blobs: {:?}", e);
+                tracing::warn!("Failed to prefetch blobs: {:?}", e);
             }
         })
         .detach();
     }
 
+    /// Handle fuchsia.fxfs/BlobCreator requests for this [`BlobDirectory`].
     async fn handle_blob_creator_requests(self: Arc<Self>, mut requests: BlobCreatorRequestStream) {
         while let Ok(Some(request)) = requests.try_next().await {
             match request {
                 BlobCreatorRequest::Create { responder, hash, .. } => {
-                    responder.send(self.create_blob(Hash::from(hash)).await).unwrap_or_else(
+                    responder.send(self.create_blob_writer(Hash::from(hash)).await).unwrap_or_else(
                         |error| {
                             tracing::error!(?error, "failed to send Create response");
                         },
@@ -122,17 +123,13 @@
         }
     }
 
+    /// Handle fuchsia.fxfs/BlobReader requests for this [`BlobDirectory`].
     async fn handle_blob_reader_requests(self: Arc<Self>, mut requests: BlobReaderRequestStream) {
         while let Ok(Some(request)) = requests.try_next().await {
             match request {
                 BlobReaderRequest::GetVmo { blob_hash, responder } => {
                     responder
-                        .send(
-                            self.clone()
-                                .get_blob_vmo(blob_hash.into())
-                                .await
-                                .map_err(map_to_raw_status),
-                        )
+                        .send(self.get_blob_vmo(blob_hash.into()).await.map_err(map_to_raw_status))
                         .unwrap_or_else(|error| {
                             tracing::error!(?error, "failed to send GetVmo response");
                         });
@@ -179,7 +176,7 @@
             let mut num = 0;
             let limit = self.directory.directory().owner().dirent_cache().limit();
             while let Some((name, object_id, _)) = iter.get() {
-                dirents.push((Identifier::from_str(name)?, object_id));
+                dirents.push((name.try_into()?, object_id));
                 iter.advance().await?;
                 num += 1;
                 if num >= limit {
@@ -201,31 +198,34 @@
         Ok(())
     }
 
-    pub async fn open_blob(self: &Arc<Self>, hash: Hash) -> Result<Arc<FxBlob>, Error> {
-        self.lookup(fio::OpenFlags::RIGHT_READABLE, Identifier::from_hash(hash))
-            .await?
-            .take()
-            .into_any()
-            .downcast::<FxBlob>()
-            .map_err(|_| FxfsError::Inconsistent.into())
+    /// Attempt to lookup and cache the blob with `id` in this directory.
+    ///
+    /// *WARNING*: Use caution when performing operations on the returned node handle. Unlike
+    /// [`Self::open_blob`], this function doesn't modify the node's open count, so the underlying
+    /// node can still be purged/unlinked even if there are still references to the node.
+    pub(crate) async fn lookup_blob(self: &Arc<Self>, hash: Hash) -> Result<Arc<FxBlob>, Error> {
+        // For simplify lookup logic, we re-use `open_blob` just decrement the open count before
+        // returning the node handle.
+        self.open_blob(&hash.into()).await?.ok_or(FxfsError::NotFound.into()).map(|blob| {
+            let node = blob.take();
+            node.clone().open_count_sub_one();
+            node
+        })
     }
 
-    pub(crate) async fn lookup(
+    /// Attempt to open and cache the blob with `id` in this directory. Returns `Ok(None)` if no
+    /// blob matching `id` was found.
+    pub(crate) async fn open_blob(
         self: &Arc<Self>,
-        flags: fio::OpenFlags,
-        id: Identifier,
-    ) -> Result<OpenedNode<dyn FxNode>, Error> {
+        id: &Identifier,
+    ) -> Result<Option<OpenedNode<FxBlob>>, Error> {
         let store = self.store();
         let fs = store.filesystem();
-
-        // TODO(https://fxbug.dev/42073113): Create the transaction here if we might need to create the object
-        // so that we have a lock in place.
         let keys = lock_keys![LockKey::object(store.store_object_id(), self.directory.object_id())];
-
         // A lock needs to be held over searching the directory and incrementing the open count.
-        let guard = fs.lock_manager().read_lock(keys.clone()).await;
+        let _guard = fs.lock_manager().read_lock(keys.clone()).await;
 
-        let child_node = match self
+        let node = match self
             .directory
             .directory()
             .owner()
@@ -247,53 +247,18 @@
                 }
             }
         };
-        match child_node {
-            Some(node) => {
-                ensure!(
-                    !flags.contains(fio::OpenFlags::CREATE | fio::OpenFlags::CREATE_IF_ABSENT),
-                    FxfsError::AlreadyExists
-                );
-                ensure!(!flags.contains(fio::OpenFlags::RIGHT_WRITABLE), FxfsError::AccessDenied);
-                match node.object_descriptor() {
-                    ObjectDescriptor::File => {
-                        ensure!(!flags.contains(fio::OpenFlags::DIRECTORY), FxfsError::NotDir)
-                    }
-                    _ => bail!(FxfsError::Inconsistent),
-                }
-                // TODO(https://fxbug.dev/42073113): Test that we can't open a blob while still writing it.
-                Ok(OpenedNode::new(node))
-            }
-            None => {
-                std::mem::drop(guard);
-
-                ensure!(flags.contains(fio::OpenFlags::CREATE), FxfsError::NotFound);
-                ensure!(flags.contains(fio::OpenFlags::RIGHT_WRITABLE), FxfsError::AccessDenied);
-                let mut transaction = fs.clone().new_transaction(keys, Options::default()).await?;
-
-                let handle = ObjectStore::create_object(
-                    self.volume(),
-                    &mut transaction,
-                    // Checksums are redundant for blobs, which are already content-verified.
-                    HandleOptions { skip_checksums: true, ..Default::default() },
-                    None,
-                    None,
-                )
-                .await?;
-
-                let node = OpenedNode::new(
-                    FxDeliveryBlob::new(self.clone(), id.hash, handle) as Arc<dyn FxNode>
-                );
-
-                // Add the object to the graveyard so that it's cleaned up if we crash.
-                store.add_to_graveyard(&mut transaction, node.object_id());
-
-                // Note that we don't bother notifying watchers yet.  Nothing else should be able to
-                // see this object yet.
-                transaction.commit().await?;
-
-                Ok(node)
-            }
+        let Some(node) = node else {
+            return Ok(None);
+        };
+        if node.object_descriptor() != ObjectDescriptor::File {
+            return Err(FxfsError::Inconsistent)
+                .with_context(|| format!("Blob {} has invalid object descriptor!", id.string));
         }
+        node.into_any()
+            .downcast::<FxBlob>()
+            .map(|node| Some(OpenedNode::new(node)))
+            .map_err(|_| FxfsError::Inconsistent)
+            .with_context(|| format!("Blob {} has incorrect node type!", id.string))
     }
 
     // Attempts to get a node from the node cache. If the node wasn't present in the cache, loads
@@ -368,39 +333,37 @@
         }
     }
 
-    async fn create_blob(
+    /// Creates a [`ClientEnd<BlobWriterMarker>`] to write the delivery blob identified by `hash`.
+    /// It is safe to create multiple writers for a given `hash`, however only one will succeed.
+    /// Requests are handled asynchronously on this volume's execution scope.
+    async fn create_blob_writer(
         self: &Arc<Self>,
         hash: Hash,
     ) -> Result<ClientEnd<BlobWriterMarker>, CreateBlobError> {
-        let flags = fio::OpenFlags::CREATE
-            | fio::OpenFlags::CREATE_IF_ABSENT
-            | fio::OpenFlags::RIGHT_WRITABLE
-            | fio::OpenFlags::RIGHT_READABLE;
-        let node = match self.lookup(flags, Identifier::from_hash(hash)).await {
-            Ok(node) => node,
-            Err(e) => {
-                if FxfsError::AlreadyExists.matches(&e) {
-                    return Err(CreateBlobError::AlreadyExists);
-                } else {
-                    tracing::error!("lookup failed: {:?}", e);
-                    return Err(CreateBlobError::Internal);
-                }
-            }
-        };
-        let blob = node.downcast::<FxDeliveryBlob>().unwrap_or_else(|_| unreachable!());
-
-        let (client, server_end) = create_proxy::<BlobWriterMarker>().map_err(|e| {
-            tracing::error!("create_proxy failed for the BlobWriter protocol: {:?}", e);
+        let id = hash.into();
+        let blob_exists = self
+            .open_blob(&id)
+            .await
+            .map_err(|e| {
+                tracing::error!("Failed to lookup blob: {:?}", e);
+                CreateBlobError::Internal
+            })?
+            .is_some();
+        if blob_exists {
+            return Err(CreateBlobError::AlreadyExists);
+        }
+        let (client_end, request_stream) =
+            create_request_stream::<BlobWriterMarker>().map_err(|e| {
+                tracing::error!("Failed to create request stream for BlobWriter: {:?}", e);
+                CreateBlobError::Internal
+            })?;
+        let writer = DeliveryBlobWriter::new(self, hash).await.map_err(|e| {
+            tracing::error!("Failed to create blob writer: {:?}", e);
             CreateBlobError::Internal
         })?;
-        let client_channel = client.into_channel().map_err(|_| {
-            tracing::error!("failed to create client channel");
-            CreateBlobError::Internal
-        })?;
-        let client_end = ClientEnd::new(client_channel.into());
         self.volume().scope().spawn(async move {
-            if let Err(e) = blob.as_ref().handle_requests(server_end).await {
-                tracing::error!("Failed to handle blob writer requests: {}", e);
+            if let Err(e) = writer.handle_requests(request_stream).await {
+                tracing::error!("Failed to handle BlobWriter requests: {}", e);
             }
         });
         return Ok(client_end);
@@ -602,9 +565,7 @@
         let data = [0xab; 2];
         let hash;
         {
-            let mut builder = MerkleTreeBuilder::new();
-            builder.write(&data);
-            hash = builder.finish().root();
+            hash = fuchsia_merkle::from_slice(&data).root();
             let compressed_data: Vec<u8> = Type1Blob::generate(&data, CompressionMode::Always);
 
             let (blob_volume_outgoing_dir, server_end) =
@@ -671,9 +632,7 @@
         let mut hashes = vec![];
         let mut filenames = vec![];
         for datum in data {
-            let mut builder = MerkleTreeBuilder::new();
-            builder.write(&datum);
-            let hash = builder.finish().root();
+            let hash = fuchsia_merkle::from_slice(&datum).root();
             let filename = PathBuf::from(format!("{}", hash));
             hashes.push(hash.clone());
             filenames.push(filename.clone());
diff --git a/src/storage/fxfs/platform/src/fuchsia/fxblob/reader.rs b/src/storage/fxfs/platform/src/fuchsia/fxblob/reader.rs
index 034916f..6c76f10 100644
--- a/src/storage/fxfs/platform/src/fuchsia/fxblob/reader.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/fxblob/reader.rs
@@ -1,29 +1,23 @@
 // Copyright 2023 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
+//! Implements fuchsia.fxfs/BlobReader for reading blobs as VMOs from a [`BlobDirectory`].
+
 use {
-    crate::{
-        fuchsia::errors::map_to_status,
-        fxblob::{
-            blob::FxBlob,
-            directory::{BlobDirectory, Identifier},
-        },
-    },
+    crate::fxblob::directory::BlobDirectory,
     anyhow::Error,
-    fidl_fuchsia_io::{self as fio},
     fuchsia_hash::Hash,
     fuchsia_zircon::{self as zx},
     fxfs::errors::FxfsError,
     std::sync::Arc,
 };
 
-/// Implementation for VMO-backed FIDL interface for reading blobs
 impl BlobDirectory {
+    /// Get a pager-backed VMO for the blob identified by `hash` in this [`BlobDirectory`]. The blob
+    /// cannot be purged until all VMOs returned by this function are destroyed.
     pub async fn get_blob_vmo(self: &Arc<Self>, hash: Hash) -> Result<zx::Vmo, Error> {
-        let id = Identifier::from_hash(hash);
-        let node = self.lookup(fio::OpenFlags::RIGHT_READABLE, id).await.map_err(map_to_status)?;
-        let any_blob = node.clone().into_any();
-        let blob = any_blob.downcast_ref::<FxBlob>().ok_or(FxfsError::Internal)?;
+        let blob = self.open_blob(&hash.into()).await?.ok_or(FxfsError::NotFound)?;
         let vmo = blob.create_child_vmo()?;
         Ok(vmo)
     }
diff --git a/src/storage/fxfs/platform/src/fuchsia/fxblob/testing.rs b/src/storage/fxfs/platform/src/fuchsia/fxblob/testing.rs
index a2f8b22..83896f1 100644
--- a/src/storage/fxfs/platform/src/fuchsia/fxblob/testing.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/fxblob/testing.rs
@@ -12,7 +12,7 @@
     delivery_blob::{CompressionMode, Type1Blob},
     fidl_fuchsia_fxfs::{BlobCreatorMarker, BlobReaderMarker, BlobWriterProxy, CreateBlobError},
     fuchsia_component::client::connect_to_protocol_at_dir_svc,
-    fuchsia_merkle::{Hash, MerkleTreeBuilder},
+    fuchsia_merkle::Hash,
     fuchsia_zircon as zx,
     fxfs::object_store::{directory::Directory, DataObjectHandle, HandleOptions, ObjectStore},
     storage_device::{fake_device::FakeDevice, DeviceHolder},
@@ -50,9 +50,7 @@
 #[async_trait]
 impl BlobFixture for TestFixture {
     async fn write_blob(&self, data: &[u8], mode: CompressionMode) -> Hash {
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(data).root();
         let delivery_data: Vec<u8> = Type1Blob::generate(&data, mode);
         let writer = self.create_blob(&hash.into(), false).await.expect("failed to create blob");
         let mut blob_writer = BlobWriter::create(writer, delivery_data.len() as u64)
diff --git a/src/storage/fxfs/platform/src/fuchsia/fxblob/writer.rs b/src/storage/fxfs/platform/src/fuchsia/fxblob/writer.rs
index 2759d80..4cbd554 100644
--- a/src/storage/fxfs/platform/src/fuchsia/fxblob/writer.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/fxblob/writer.rs
@@ -2,70 +2,73 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-//! This module contains the [`FxUnsealedBlob`] node type used to represent an uncompressed blob
-//! in the process of being written/verified to persistent storage.
+//! Implements fuchsia.fxfs/BlobWriter for writing delivery blobs.
 
 use {
     crate::fuchsia::{
-        directory::FxDirectory, errors::map_to_status, fxblob::directory::BlobDirectory,
-        node::FxNode, volume::FxVolume,
+        directory::FxDirectory, errors::map_to_status, fxblob::BlobDirectory, node::FxNode,
+        volume::FxVolume,
     },
     anyhow::{Context as _, Error},
     delivery_blob::{
         compression::{decode_archive, ChunkInfo, ChunkedDecompressor},
         Type1Blob,
     },
-    fidl::endpoints::ServerEnd,
-    fidl_fuchsia_fxfs::{BlobWriterMarker, BlobWriterRequest},
+    fidl_fuchsia_fxfs::{BlobWriterRequest, BlobWriterRequestStream},
     fuchsia_hash::Hash,
     fuchsia_merkle::{MerkleTree, MerkleTreeBuilder},
     fuchsia_zircon::{self as zx, HandleBased as _, Status},
-    futures::{lock::Mutex as AsyncMutex, try_join, TryStreamExt},
+    futures::{try_join, TryStreamExt as _},
     fxfs::{
         errors::FxfsError,
         object_handle::{ObjectHandle, WriteObjectHandle},
         object_store::{
             directory::{replace_child_with_object, ReplacedChild},
-            DataObjectHandle, ObjectDescriptor, Timestamp, BLOB_MERKLE_ATTRIBUTE_ID,
+            transaction::{lock_keys, LockKey},
+            DataObjectHandle, HandleOptions, ObjectDescriptor, ObjectStore, Timestamp,
+            BLOB_MERKLE_ATTRIBUTE_ID,
         },
         round::{round_down, round_up},
         serialized_types::BlobMetadata,
     },
     lazy_static::lazy_static,
-    std::sync::{
-        atomic::{AtomicBool, AtomicUsize, Ordering},
-        Arc,
-    },
+    std::sync::Arc,
 };
 
 lazy_static! {
-    pub static ref RING_BUFFER_SIZE: u64 = 64 * (zx::system_get_page_size() as u64);
+    static ref RING_BUFFER_SIZE: u64 = 64 * (zx::system_get_page_size() as u64);
 }
 
 const PAYLOAD_BUFFER_FLUSH_THRESHOLD: usize = 131_072; /* 128 KiB */
 
-/// Represents an RFC-0207 compliant delivery blob that is being written.
-/// The blob cannot be read until writes complete and hash is verified.
-pub struct FxDeliveryBlob {
+/// Represents an RFC-0207 compliant delivery blob that is being written. Used to implement the
+/// fuchisa.fxfs/BlobWriter protocol (see [`Self::handle_requests`]).
+///
+/// Once all data for the delivery blob has been written, the calculated Merkle root is verified
+/// against [`Self::hash`]. On success, the blob is added under the [`Self::parent`] directory.
+pub struct DeliveryBlobWriter {
+    /// The expected hash for this blob. **MUST** match the Merkle root from [`Self::tree_builder`].
     hash: Hash,
+    /// Handle to this blob within the filesystem.
     handle: DataObjectHandle<FxVolume>,
-    parent: Arc<BlobDirectory>,
-    open_count: AtomicUsize,
-    is_completed: AtomicBool,
-    inner: AsyncMutex<Inner>,
-}
-
-struct Inner {
-    /// Total number of bytes we expect for the delivery blob to be fully written. This is the same
-    /// number of bytes passed to truncate. We expect this to be non-zero for a delivery blob.
-    delivery_size: Option<u64>,
-    /// Write offset with respect to the fuchsia.io protocol.
-    delivery_bytes_written: u64,
-    /// Vmo used for the blob writer protocol.
+    /// The parent directory we will add this blob to once verified.
+    parent: Arc<FxDirectory>,
+    /// Set to true once we have verified the blob and ensured it was added to the blob directory.
+    is_completed: bool,
+    /// Total number of bytes we expect for this delivery blob (via fuchsia.fxfs/BlobWriter.GetVmo).
+    /// This is checked against the header + payload size encoded within the delivery blob.
+    expected_size: Option<u64>,
+    /// Total number of bytes that have been written to this delivery blob so far. When this reaches
+    /// [`Self::expected_size`], the blob will be verified.
+    total_written: u64,
+    /// Vmo for the ring buffer used for the fuchsia.fxfs/BlobWriter protocol.
     vmo: Option<zx::Vmo>,
-    /// Internal buffer of data being written via the write protocols.
+    /// Temporary buffer used to copy data from [`Self::vmo`].
     buffer: Vec<u8>,
+    /// The header for this delivery blob. Decoded once we have enough data.
     header: Option<Type1Blob>,
+    /// The Merkle tree builder for this blob. Once the Merkle tree is complete, the root hash of
+    /// the blob is verified, before storing the Merkle tree as part of the blob's metadata.
     tree_builder: MerkleTreeBuilder,
     /// Set to true when we've allocated space for the blob payload on disk.
     allocated_space: bool,
@@ -73,15 +76,45 @@
     payload_persisted: u64,
     /// Offset within the delivery blob payload we started writing data to disk.
     payload_offset: u64,
-    /// Decompressor used when writing compressed delivery blobs.
+    /// Streaming decompressor used to calculate the Merkle tree of compressed delivery blobs.
+    /// Initialized once the seek table has been decoded and verified.
     decompressor: Option<ChunkedDecompressor>,
 }
 
-impl Default for Inner {
-    fn default() -> Self {
-        Self {
-            delivery_size: None,
-            delivery_bytes_written: 0,
+impl DeliveryBlobWriter {
+    /// Creates a new object in the `parent` object store that manages writing the blob `hash`.
+    /// After the blob is fully written and verified, it will be added as an entry under `parent`.
+    /// If this object is dropped before the blob is fully written/verified, it will be tombstoned.
+    pub(crate) async fn new(parent: &Arc<BlobDirectory>, hash: Hash) -> Result<Self, Error> {
+        let parent = parent.directory().clone();
+        let store = parent.store();
+        let keys = lock_keys![LockKey::object(store.store_object_id(), parent.object_id())];
+        let mut transaction = store
+            .filesystem()
+            .clone()
+            .new_transaction(keys, Default::default())
+            .await
+            .context("Failed to create transaction.")?;
+        let handle = ObjectStore::create_object(
+            parent.volume(),
+            &mut transaction,
+            // Checksums are redundant for blobs, which are already content-verified.
+            HandleOptions { skip_checksums: true, ..Default::default() },
+            None,
+            None,
+        )
+        .await
+        .context("Failed to create object.")?;
+        // Add the object to the graveyard so that it's cleaned up if we crash.
+        store.add_to_graveyard(&mut transaction, handle.object_id());
+        transaction.commit().await.context("Failed to commit transaction.")?;
+        Ok(Self {
+            hash,
+            handle,
+            parent,
+            is_completed: false,
+            expected_size: None,
+            total_written: 0,
             vmo: None,
             buffer: Default::default(),
             header: None,
@@ -90,11 +123,24 @@
             payload_persisted: 0,
             payload_offset: 0,
             decompressor: None,
+        })
+    }
+}
+
+impl Drop for DeliveryBlobWriter {
+    /// Tombstone the object if we didn't finish writing the blob or the hash didn't match.
+    fn drop(&mut self) {
+        if !self.is_completed {
+            let store = self.handle.store();
+            store
+                .filesystem()
+                .graveyard()
+                .queue_tombstone_object(store.store_object_id(), self.handle.object_id());
         }
     }
 }
 
-impl Inner {
+impl DeliveryBlobWriter {
     fn header(&self) -> &Type1Blob {
         self.header.as_ref().unwrap()
     }
@@ -118,11 +164,16 @@
         header.payload_length
     }
 
-    async fn write_payload(&mut self, handle: &DataObjectHandle<FxVolume>) -> Result<(), Error> {
-        debug_assert!(self.allocated_space);
+    async fn write_payload(&mut self) -> Result<(), Error> {
+        self.ensure_allocated().await.with_context(|| {
+            format!(
+                "Failed to allocate space for blob (required space = {} bytes)",
+                self.storage_size()
+            )
+        })?;
         let final_write =
             (self.payload_persisted as usize + self.buffer.len()) == self.header().payload_length;
-        let block_size = handle.block_size() as usize;
+        let block_size = self.handle.block_size() as usize;
         let flush_threshold = std::cmp::max(block_size, PAYLOAD_BUFFER_FLUSH_THRESHOLD);
         // If we expect more data but haven't met the flush threshold, wait for more.
         if !final_write && self.buffer.len() < flush_threshold {
@@ -149,13 +200,17 @@
 
         // Copy data into transfer buffer, zero pad if required.
         let aligned_len = round_up(len, block_size).ok_or(FxfsError::OutOfRange)?;
-        let mut buffer = handle.allocate_buffer(aligned_len).await;
+        let mut buffer = self.handle.allocate_buffer(aligned_len).await;
         buffer.as_mut_slice()[..len].copy_from_slice(&self.buffer[..len]);
         buffer.as_mut_slice()[len..].fill(0);
 
         // Overwrite allocated bytes in the object's handle.
-        let overwrite_fut =
-            handle.overwrite(self.payload_persisted - self.payload_offset, buffer.as_mut(), false);
+        let overwrite_fut = async {
+            self.handle
+                .overwrite(self.payload_persisted - self.payload_offset, buffer.as_mut(), false)
+                .await
+                .context("Failed to write data to object handle.")
+        };
         // NOTE: `overwrite_fut` needs to be polled first to initiate the asynchronous write to the
         // block device which will then run in parallel with the synchronous
         // `update_merkle_tree_fut`.
@@ -179,7 +234,8 @@
                 hashes.push(**hash);
             }
             let (uncompressed_size, chunk_size, compressed_offsets) = if is_compressed {
-                parse_seek_table(self.decompressor().seek_table())?
+                parse_seek_table(self.decompressor().seek_table())
+                    .context("Failed to parse seek table.")?
             } else {
                 (self.header().payload_length as u64, 0u64, vec![])
             };
@@ -189,53 +245,61 @@
             Ok(None)
         }
     }
-}
 
-impl FxDeliveryBlob {
-    pub(crate) fn new(
-        parent: Arc<BlobDirectory>,
-        hash: Hash,
-        handle: DataObjectHandle<FxVolume>,
-    ) -> Arc<Self> {
-        let file = Arc::new(Self {
-            hash,
-            handle,
-            parent,
-            open_count: AtomicUsize::new(0),
-            is_completed: AtomicBool::new(false),
-            inner: Default::default(),
-        });
-        file
-    }
-
-    async fn allocate(&self, size: usize) -> Result<(), Error> {
-        let size = size as u64;
+    async fn ensure_allocated(&mut self) -> Result<(), Error> {
+        if self.allocated_space {
+            return Ok(());
+        }
+        let size = self.storage_size() as u64;
         let mut range = 0..round_up(size, self.handle.block_size()).ok_or(FxfsError::OutOfRange)?;
         let mut first_time = true;
         while range.start < range.end {
-            let mut transaction = self.handle.new_transaction().await?;
+            let mut transaction =
+                self.handle.new_transaction().await.context("Failed to create transaction.")?;
             if first_time {
-                self.handle.grow(&mut transaction, 0, size).await?;
+                self.handle
+                    .grow(&mut transaction, 0, size)
+                    .await
+                    .with_context(|| format!("Failed to grow handle to {} bytes.", size))?;
                 first_time = false;
             }
-            self.handle.preallocate_range(&mut transaction, &mut range).await?;
-            transaction.commit().await?;
+            self.handle.preallocate_range(&mut transaction, &mut range).await.with_context(
+                || format!("Failed to allocate range ({} to {}).", range.start, range.end),
+            )?;
+            transaction.commit().await.context("Failed to commit transaction.")?;
         }
+        self.allocated_space = true;
         Ok(())
     }
 
-    async fn complete(&self, metadata: Option<BlobMetadata>) -> Result<(), Error> {
-        self.handle.flush().await?;
-
+    async fn complete(&mut self) -> Result<(), Error> {
+        debug_assert!(self.payload_persisted == self.header().payload_length as u64);
+        // Finish building Merkle tree and verify the hash matches the filename.
+        let merkle_tree = std::mem::take(&mut self.tree_builder).finish();
+        if merkle_tree.root() != self.hash {
+            return Err(FxfsError::IntegrityError).with_context(|| {
+                format!(
+                    "Calculated Merkle root ({}) does not match given hash ({}).",
+                    merkle_tree.root(),
+                    self.hash
+                )
+            });
+        }
+        // Write metadata and ensure everything is flushed to disk.
+        let metadata =
+            self.generate_metadata(merkle_tree).context("Failed to generate metadata for blob.")?;
         if let Some(metadata) = metadata {
             let mut serialized = vec![];
             bincode::serialize_into(&mut serialized, &metadata)?;
-            self.handle.write_attr(BLOB_MERKLE_ATTRIBUTE_ID, &serialized).await?;
+            self.handle
+                .write_attr(BLOB_MERKLE_ATTRIBUTE_ID, &serialized)
+                .await
+                .context("Failed to write metadata for blob.")?;
         }
+        self.handle.flush().await.context("Failed to flush blob.")?;
 
         let volume = self.handle.owner();
         let store = self.handle.store();
-
         let dir = volume
             .cache()
             .get(store.root_directory_object_id())
@@ -249,7 +313,8 @@
             .directory()
             .directory()
             .acquire_context_for_replace(None, &name, false)
-            .await?
+            .await
+            .context("Failed to acquire context for replacement.")?
             .transaction;
 
         let object_id = self.handle.object_id();
@@ -262,7 +327,8 @@
             0,
             Timestamp::now(),
         )
-        .await?
+        .await
+        .context("Replacing child failed.")?
         {
             ReplacedChild::None => {}
             _ => {
@@ -271,175 +337,84 @@
             }
         }
 
-        let parent = self.parent().unwrap();
         transaction
             .commit_with_callback(|_| {
-                self.is_completed.store(true, Ordering::Relaxed);
+                self.is_completed = true;
                 // This can't actually add the node to the cache, because it hasn't been created
                 // ever at this point. Passes in None for now as a result.
-                parent.did_add(&name, None);
+                self.parent.did_add(&name, None);
             })
-            .await?;
+            .await
+            .context("Failed to commit transaction!")?;
         Ok(())
     }
-}
 
-impl FxNode for FxDeliveryBlob {
-    fn object_id(&self) -> u64 {
-        self.handle.object_id()
-    }
-
-    fn parent(&self) -> Option<Arc<FxDirectory>> {
-        Some(self.parent.directory().clone())
-    }
-
-    fn set_parent(&self, _parent: Arc<FxDirectory>) {
-        unreachable!()
-    }
-
-    fn open_count_add_one(&self) {
-        self.open_count.fetch_add(1, Ordering::Relaxed);
-    }
-
-    fn open_count_sub_one(self: Arc<Self>) {
-        let old = self.open_count.fetch_sub(1, Ordering::Relaxed);
-        assert!(old > 0);
-        let is_completed = self.is_completed.load(Ordering::Relaxed);
-        if old == 1 && !is_completed {
-            let store = self.handle.store();
-            store
-                .filesystem()
-                .graveyard()
-                .queue_tombstone_object(store.store_object_id(), self.object_id());
-        }
-    }
-
-    fn object_descriptor(&self) -> ObjectDescriptor {
-        ObjectDescriptor::File
-    }
-}
-
-impl FxDeliveryBlob {
-    async fn truncate(&self, length: u64) -> Result<(), Error> {
-        let mut inner = self.inner.lock().await;
-        if inner.delivery_size.is_some() {
+    async fn truncate(&mut self, length: u64) -> Result<(), Error> {
+        if self.expected_size.is_some() {
             return Err(Status::BAD_STATE).context("Blob was already truncated.");
         }
         if length < Type1Blob::HEADER.header_length as u64 {
             return Err(Status::INVALID_ARGS).context("Invalid size (too small).");
         }
-        inner.delivery_size = Some(length);
+        self.expected_size = Some(length);
         Ok(())
     }
 
-    /// Appends |content| to this delivery blob.
-    ///
-    /// *WARNING*: If this function fails, the blob will remain in an invalid state. Errors should
-    /// be latched by the caller instead of calling this function again. The blob can be closed and
-    /// re-opened to attempt writing again.
-    async fn append(&self, content: &[u8], inner: &mut Inner) -> Result<u64, Error> {
-        let delivery_size = inner
-            .delivery_size
-            .ok_or(Status::BAD_STATE)
-            .context("Must truncate blob before writing.")?;
-        let content_len = content.len() as u64;
-        if (inner.delivery_bytes_written + content_len) > delivery_size {
-            return Err(Status::BUFFER_TOO_SMALL).with_context(|| {
-                format!(
-                    "Wrote more bytes than truncated size (truncated = {}, written = {}).",
-                    delivery_size,
-                    inner.delivery_bytes_written + content_len
-                )
-            });
+    /// Process the data that exists in the writer's buffer. The writer cannot recover from errors,
+    /// so this function should not be invoked after it returns any errors.
+    async fn process_buffer(&mut self) -> Result<(), Error> {
+        // Decode delivery blob header.
+        if self.header.is_none() {
+            let Some((header, payload)) =
+                Type1Blob::parse(&self.buffer).context("Failed to decode delivery blob header.")?
+            else {
+                return Ok(()); // Not enough data to decode header yet.
+            };
+            let expected_size = self.expected_size.unwrap_or_default() as usize;
+            let delivery_size = header.header.header_length as usize + header.payload_length;
+            if expected_size != delivery_size {
+                return Err(FxfsError::IntegrityError).with_context(|| {
+                    format!(
+                        "Expected size ({}) does not match size from blob header ({})!",
+                        expected_size, delivery_size
+                    )
+                });
+            }
+            self.buffer = Vec::from(payload);
+            self.header = Some(header);
         }
-        async {
-            inner.buffer.extend_from_slice(content);
-            inner.delivery_bytes_written += content_len;
 
-            // Decode delivery blob header.
-            if inner.header.is_none() {
-                let Some((header, payload)) = Type1Blob::parse(&inner.buffer)
-                    .context("Failed to decode delivery blob header.")?
-                else {
-                    return Ok(()); // Not enough data to decode header yet.
-                };
-                let expected_size = header.header.header_length as usize + header.payload_length;
-                if expected_size != delivery_size as usize {
-                    return Err(FxfsError::IntegrityError).with_context(|| {
-                        format!(
-                            "Truncated size ({}) does not match size from blob header ({})!",
-                            delivery_size, expected_size
-                        )
-                    });
-                }
-                inner.buffer = Vec::from(payload);
-                inner.header = Some(header);
-            }
-
-            // If blob is compressed, decode chunked archive header & initialize decompressor.
-            if inner.header().is_compressed && inner.decompressor.is_none() {
-                let prev_buff_len = inner.buffer.len();
-                let archive_length = inner.header().payload_length;
-                let Some((seek_table, chunk_data)) = decode_archive(&inner.buffer, archive_length)
-                    .context("Failed to decode archive header")?
-                else {
-                    return Ok(()); // Not enough data to decode archive header/seek table.
-                };
-                // We store the seek table out-of-line with the data, so we don't persist that
-                // part of the payload directly.
-                inner.buffer = Vec::from(chunk_data);
-                inner.payload_offset = (prev_buff_len - inner.buffer.len()) as u64;
-                inner.payload_persisted = inner.payload_offset;
-                inner.decompressor = Some(
-                    ChunkedDecompressor::new(seek_table)
-                        .context("Failed to create decompressor")?,
-                );
-            }
-
-            // Allocate storage space on the filesystem to write the blob payload.
-            if !inner.allocated_space {
-                let amount = inner.storage_size();
-                self.allocate(amount)
-                    .await
-                    .with_context(|| format!("Failed to allocate {} bytes", amount))?;
-                inner.allocated_space = true;
-            }
-
-            // Write payload to disk and update Merkle tree.
-            if !inner.buffer.is_empty() {
-                inner.write_payload(&self.handle).await?;
-            }
-
-            let blob_complete = inner.delivery_bytes_written == inner.delivery_size.unwrap();
-            if blob_complete {
-                debug_assert!(inner.payload_persisted == inner.header().payload_length as u64);
-                // Finish building Merkle tree and verify the hash matches the filename.
-                let merkle_tree = std::mem::take(&mut inner.tree_builder).finish();
-                if merkle_tree.root() != self.hash {
-                    return Err(FxfsError::IntegrityError).with_context(|| {
-                        format!(
-                            "Calculated Merkle root ({}) does not match blob name ({})",
-                            merkle_tree.root(),
-                            self.hash
-                        )
-                    });
-                }
-                // Calculate metadata and promote verified blob into a directory entry.
-                let metadata = inner.generate_metadata(merkle_tree)?;
-                self.complete(metadata).await?;
-            }
-            Ok(())
+        // If blob is compressed, decode chunked archive header & initialize decompressor.
+        if self.header().is_compressed && self.decompressor.is_none() {
+            let prev_buff_len = self.buffer.len();
+            let archive_length = self.header().payload_length;
+            let Some((seek_table, chunk_data)) = decode_archive(&self.buffer, archive_length)
+                .context("Failed to decode archive header")?
+            else {
+                return Ok(()); // Not enough data to decode archive header/seek table.
+            };
+            // We store the seek table out-of-line with the data, so we don't persist that
+            // part of the payload directly.
+            self.buffer = Vec::from(chunk_data);
+            self.payload_offset = (prev_buff_len - self.buffer.len()) as u64;
+            self.payload_persisted = self.payload_offset;
+            self.decompressor = Some(
+                ChunkedDecompressor::new(seek_table).context("Failed to create decompressor")?,
+            );
         }
-        .await?;
-        Ok(content_len)
+
+        // Write payload to disk and update Merkle tree.
+        if !self.buffer.is_empty() {
+            self.write_payload().await?;
+        }
+        Ok(())
     }
 
-    pub async fn get_vmo(&self, size: u64) -> Result<zx::Vmo, Error> {
+    async fn get_vmo(&mut self, size: u64) -> Result<zx::Vmo, Error> {
         self.truncate(size)
             .await
             .with_context(|| format!("Failed to truncate blob {} to size {}", self.hash, size))?;
-        let mut inner = self.inner.lock().await;
-        if inner.vmo.is_some() {
+        if self.vmo.is_some() {
             return Err(FxfsError::AlreadyExists)
                 .with_context(|| format!("VMO was already created for blob {}", self.hash));
         }
@@ -449,12 +424,17 @@
         let vmo_dup = vmo
             .duplicate_handle(zx::Rights::SAME_RIGHTS)
             .context("Failed to duplicate VMO handle")?;
-        inner.vmo = Some(vmo);
+        self.vmo = Some(vmo);
         Ok(vmo_dup)
     }
 
-    pub async fn bytes_ready(&self, bytes_written: u64) -> Result<(), Error> {
-        // TODO(https://fxbug.dev/42077275): Remove extra copy.
+    /// Called when there is more data in the ring buffer ready to be processed. Once all data has
+    /// been written and verified, it will be added to the parent directory.
+    ///
+    /// *WARNING*: If this function fails, the writer will remain in an invalid state. Errors should
+    /// be latched by the caller instead of calling this function again. The writer can be closed,
+    /// and a new one can be opened to attempt writing the delivery blob again.
+    async fn bytes_ready(&mut self, bytes_written: u64) -> Result<(), Error> {
         if bytes_written > *RING_BUFFER_SIZE {
             return Err(FxfsError::OutOfRange).with_context(|| {
                 format!(
@@ -463,70 +443,92 @@
                 )
             });
         }
-        let mut buf = vec![0; bytes_written as usize];
-        let mut inner = self.inner.lock().await;
-        let write_offset = inner.delivery_bytes_written;
-        {
-            let Some(ref vmo) = inner.vmo else {
-                return Err(Status::BAD_STATE)
-                    .context("BlobWriter.GetVmo must be called before BlobWriter.BytesReady.");
-            };
-            let vmo_offset = write_offset % *RING_BUFFER_SIZE;
-            if vmo_offset + bytes_written > *RING_BUFFER_SIZE {
-                let split = (*RING_BUFFER_SIZE - vmo_offset) as usize;
-                vmo.read(&mut buf[0..split], vmo_offset).context("failed to read from VMO")?;
-                vmo.read(&mut buf[split..], 0).context("failed to read from VMO")?;
-            } else {
-                vmo.read(&mut buf, vmo_offset).context("failed to read from VMO")?;
-            }
+        let expected_size = self
+            .expected_size
+            .ok_or(Status::BAD_STATE)
+            .context("Must call BlobWriter.GetVmo before writing data to blob.")?;
+        if (self.total_written + bytes_written) > expected_size {
+            return Err(Status::BUFFER_TOO_SMALL).with_context(|| {
+                format!(
+                    "Wrote more bytes than passed to BlobWriter.GetVmo (expected = {}, written = {}).",
+                    expected_size,
+                    self.total_written + bytes_written
+                )
+            });
         }
-        self.append(&buf, &mut inner).await.with_context(|| {
+        let Some(ref vmo) = self.vmo else {
+            return Err(Status::BAD_STATE)
+                .context("BlobWriter.GetVmo must be called before BlobWriter.BytesReady.");
+        };
+        // Extend our write buffer by the amount of data that was written.
+        let prev_len = self.buffer.len();
+        self.buffer.resize(prev_len + bytes_written as usize, 0);
+        let mut buf = &mut self.buffer[prev_len..];
+        let write_offset = self.total_written;
+        self.total_written += bytes_written;
+        // Copy data from the ring buffer into our internal buffer.
+        let vmo_offset = write_offset % *RING_BUFFER_SIZE;
+        if vmo_offset + bytes_written > *RING_BUFFER_SIZE {
+            let split = (*RING_BUFFER_SIZE - vmo_offset) as usize;
+            vmo.read(&mut buf[0..split], vmo_offset).context("failed to read from VMO")?;
+            vmo.read(&mut buf[split..], 0).context("failed to read from VMO")?;
+        } else {
+            vmo.read(&mut buf, vmo_offset).context("failed to read from VMO")?;
+        }
+        // Process the data from the buffer.
+        self.process_buffer().await.with_context(|| {
             format!(
                 "failed to write blob {} (bytes_written = {}, offset = {}, delivery_size = {})",
-                self.hash,
-                bytes_written,
-                write_offset,
-                inner.delivery_size.unwrap_or_default()
+                self.hash, bytes_written, write_offset, expected_size
             )
         })?;
+        // If all bytes for this delivery blob were written successfully, attempt to verify the blob
+        // and add it to the parent directory.
+        if self.total_written == expected_size {
+            self.complete().await?;
+        }
         Ok(())
     }
 
-    pub async fn handle_requests(
-        &self,
-        server_end: ServerEnd<BlobWriterMarker>,
+    /// Handle fuchsia.fxfs/BlobWriter requests for this delivery blob.
+    pub(crate) async fn handle_requests(
+        self,
+        mut request_stream: BlobWriterRequestStream,
     ) -> Result<(), Error> {
-        let mut latched_error = None;
-        let mut stream = server_end.into_stream()?;
-        while let Some(request) = stream.try_next().await? {
+        // Current state of the writer. If any unrecoverable errors are encountered, the writer is
+        // dropped and instead the error state is latched.
+        let mut writer = Ok(self);
+        while let Some(request) = request_stream.try_next().await? {
             match request {
                 BlobWriterRequest::GetVmo { size, responder } => {
-                    let res = match self.get_vmo(size).await {
-                        Ok(vmo) => Ok(vmo),
-                        Err(e) => {
+                    let result = match writer.as_mut() {
+                        Ok(writer) => writer.get_vmo(size).await.map_err(|e| {
                             tracing::error!("BlobWriter.GetVmo error: {:?}", e);
-                            Err(map_to_status(e).into_raw())
-                        }
+                            map_to_status(e).into_raw()
+                        }),
+                        Err(e) => Err(*e),
                     };
-                    responder.send(res).unwrap_or_else(|e| {
+                    responder.send(result).unwrap_or_else(|e| {
                         tracing::error!("Error sending BlobWriter.GetVmo response: {:?}", e);
                     });
                 }
                 BlobWriterRequest::BytesReady { bytes_written, responder } => {
-                    let res = if let Some(status) = &latched_error {
-                        Err(*status)
-                    } else {
-                        match self.bytes_ready(bytes_written).await {
-                            Ok(()) => Ok(()),
-                            Err(e) => {
-                                tracing::error!("BlobWriter.BytesReady error: {:?}", e);
-                                let status = map_to_status(e).into_raw();
-                                latched_error = Some(status);
-                                Err(status)
-                            }
-                        }
+                    let result = match writer.as_mut() {
+                        Ok(writer) => writer.bytes_ready(bytes_written).await.map_err(|e| {
+                            tracing::error!("BlobWriter.BytesReady error: {:?}", e);
+                            map_to_status(e).into_raw()
+                        }),
+                        Err(e) => Err(*e),
                     };
-                    responder.send(res).unwrap_or_else(|e| {
+                    if let Err(e) = result {
+                        // Latch the write error.
+                        //
+                        // *NOTE*: This drops the writer, immediately queuing a tombstone for this
+                        // blob. This will also happen automatically if the client drops their end
+                        // of the channel before the blob is fully written.
+                        writer = Err(e);
+                    }
+                    responder.send(result).unwrap_or_else(|e| {
                         tracing::error!("Error sending BlobWriter.BytesReady response: {:?}", e);
                     });
                 }
@@ -610,9 +612,7 @@
         let fixture = new_blob_fixture().await;
 
         let data = vec![];
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(&data).root();
         let compressed_data = Type1Blob::generate(&data, CompressionMode::Always);
 
         {
@@ -676,9 +676,7 @@
         let fixture = new_blob_fixture().await;
 
         let data = vec![3; 1_000];
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data[..data.len() - 1]);
-        let incorrect_hash = builder.finish().root();
+        let incorrect_hash = fuchsia_merkle::from_slice(&data[..data.len() - 1]).root();
         let delivery_data = Type1Blob::generate(&data, CompressionMode::Never);
 
         {
@@ -713,9 +711,7 @@
         let mut data = vec![1; 196608];
         thread_rng().fill(&mut data[..]);
 
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(&data).root();
         let compressed_data = Type1Blob::generate(&data, CompressionMode::Always);
 
         {
@@ -796,9 +792,7 @@
             // an OUT_OF_SPACE error on the second write.
             let data = vec![1; 4194304];
 
-            let mut builder = MerkleTreeBuilder::new();
-            builder.write(&data);
-            let hash = builder.finish().root();
+            let hash = fuchsia_merkle::from_slice(&data).root();
             let compressed_data = Type1Blob::generate(&data, CompressionMode::Never);
 
             {
@@ -842,9 +836,7 @@
         let mut data = vec![1; 196608];
         thread_rng().fill(&mut data[..]);
 
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(&data).root();
         let compressed_data = Type1Blob::generate(&data, CompressionMode::Always);
 
         {
@@ -884,9 +876,7 @@
 
         let data = vec![1; 65536];
 
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(&data).root();
         let delivery_data = Type1Blob::generate(&data, CompressionMode::Never);
 
         {
@@ -922,9 +912,7 @@
         let mut data = vec![1; 1024921];
         thread_rng().fill(&mut data[..]);
 
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(&data).root();
         let compressed_data = Type1Blob::generate(&data, CompressionMode::Always);
         assert!(compressed_data.len() as u64 > *RING_BUFFER_SIZE);
 
@@ -990,9 +978,7 @@
             let mut data = vec![1; 1024921];
             thread_rng().fill(&mut data[..]);
 
-            let mut builder = MerkleTreeBuilder::new();
-            builder.write(&data);
-            let hash = builder.finish().root();
+            let hash = fuchsia_merkle::from_slice(&data).root();
             let compressed_data = Type1Blob::generate(&data, CompressionMode::Always);
             assert!(compressed_data.len() as u64 > *RING_BUFFER_SIZE);
 
@@ -1035,9 +1021,7 @@
         // Generate a delivery blob (size doesn't matter).
         let mut data = vec![1; 196608];
         thread_rng().fill(&mut data[..]);
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(&data).root();
         let blob_data = Type1Blob::generate(&data, CompressionMode::Always);
         // To simplify the test, we make sure to write enough bytes on the first call to bytes_ready
         // so that the header can be decoded (and thus the length mismatch is detected).
diff --git a/src/storage/fxfs/platform/src/fuchsia/profile.rs b/src/storage/fxfs/platform/src/fuchsia/profile.rs
index 977f545..be1b6e9 100644
--- a/src/storage/fxfs/platform/src/fuchsia/profile.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/profile.rs
@@ -244,7 +244,7 @@
 
                 let file = match local_cache.entry(msg.hash) {
                     Entry::Occupied(entry) => entry.get().clone(),
-                    Entry::Vacant(entry) => match root_dir.open_blob(msg.hash).await {
+                    Entry::Vacant(entry) => match root_dir.lookup_blob(msg.hash).await {
                         Err(e) => {
                             warn!("Failed to open object {} from profile: {:?}", msg.hash, e);
                             continue;
@@ -536,7 +536,7 @@
                 .expect("Root should be BlobDirectory");
             // Ensure that nothing is paged in right now.
             for hash in &hashes {
-                let blob = dir.open_blob(*hash).await.expect("Opening blob");
+                let blob = dir.lookup_blob(*hash).await.expect("Opening blob");
                 assert_eq!(blob.vmo().info().unwrap().committed_bytes, 0);
             }
 
@@ -547,10 +547,13 @@
 
             // Await all data being played back by checking that things have paged in.
             for hash in &hashes {
-                let blob = dir.open_blob(*hash).await.expect("Opening blob");
+                let blob = dir.lookup_blob(*hash).await.expect("Opening blob");
                 while blob.vmo().info().unwrap().committed_bytes == 0 {
                     fasync::Timer::new(Duration::from_millis(25)).await;
                 }
+                // The replay task shouldn't increment the blob's open count. This ensures that we
+                // can still delete blobs while we are replaying a profile.
+                assert!(blob.mark_to_be_purged());
             }
             state.stop_profiler();
         }
diff --git a/src/storage/fxfs/platform/src/fuchsia/volume.rs b/src/storage/fxfs/platform/src/fuchsia/volume.rs
index 777a89b..552b2a9 100644
--- a/src/storage/fxfs/platform/src/fuchsia/volume.rs
+++ b/src/storage/fxfs/platform/src/fuchsia/volume.rs
@@ -2223,7 +2223,7 @@
 
             // Ensure that nothing is paged in right now.
             for hash in &hashes {
-                let blob = dir.open_blob(*hash).await.expect("Opening blob");
+                let blob = dir.lookup_blob(*hash).await.expect("Opening blob");
                 assert_eq!(blob.vmo().info().unwrap().committed_bytes, 0);
             }
 
@@ -2231,7 +2231,7 @@
 
             // Await all data being played back by checking that things have paged in.
             for hash in &hashes {
-                let blob = dir.open_blob(*hash).await.expect("Opening blob");
+                let blob = dir.lookup_blob(*hash).await.expect("Opening blob");
                 while blob.vmo().info().unwrap().committed_bytes == 0 {
                     fasync::Timer::new(Duration::from_millis(25)).await;
                 }
diff --git a/src/storage/fxfs/src/filesystem.rs b/src/storage/fxfs/src/filesystem.rs
index 744fe3f..c29edca 100644
--- a/src/storage/fxfs/src/filesystem.rs
+++ b/src/storage/fxfs/src/filesystem.rs
@@ -56,11 +56,10 @@
 // The maximum number of transactions that can be in-flight at any time.
 const MAX_IN_FLIGHT_TRANSACTIONS: u64 = 4;
 
-// Start trimming 5 minutes after boot.  The idea here is to wait until the initial flurry of
+// Start trimming 1 hour after boot.  The idea here is to wait until the initial flurry of
 // activity during boot is finished.  This is a rough heuristic and may need to change later if
 // performance is affected.
-// TODO(b/293964968): We probably also want to reschedule trimming, e.g. every day.
-const TRIM_AFTER_BOOT_TIMER: std::time::Duration = std::time::Duration::from_secs(5 * 60);
+const TRIM_AFTER_BOOT_TIMER: std::time::Duration = std::time::Duration::from_secs(60 * 60);
 
 // After the initial trim, perform another trim every 24 hours.
 const TRIM_INTERVAL_TIMER: std::time::Duration = std::time::Duration::from_secs(60 * 60 * 24);
@@ -830,11 +829,12 @@
     fs.close().await
 }
 
-/// Helper method for making a new filesystem with a default volume.
+/// Helper method for making a new filesystem with a single named volume.
 /// This shouldn't be used in production; instead volumes should be created with the Volumes
 /// protocol.
-pub async fn mkfs_with_default(
+pub async fn mkfs_with_volume(
     device: DeviceHolder,
+    volume_name: &str,
     crypt: Option<Arc<dyn Crypt>>,
 ) -> Result<(), Error> {
     let fs = FxFilesystem::new_empty(device).await?;
@@ -842,7 +842,7 @@
         // expect instead of propagating errors here, since otherwise we could drop |fs| before
         // close is called, which leads to confusing and unrelated error messages.
         let root_volume = root_volume(fs.clone()).await.expect("Open root_volume failed");
-        root_volume.new_volume("default", crypt).await.expect("Create volume failed");
+        root_volume.new_volume(volume_name, crypt).await.expect("Create volume failed");
     }
     fs.close().await?;
     Ok(())
diff --git a/src/storage/fxfs/testdata/fxfs_golden.38.0.img.zstd b/src/storage/fxfs/testdata/fxfs_golden.38.0.img.zstd
index afa7681..bf9096c 100644
--- a/src/storage/fxfs/testdata/fxfs_golden.38.0.img.zstd
+++ b/src/storage/fxfs/testdata/fxfs_golden.38.0.img.zstd
Binary files differ
diff --git a/src/storage/fxfs/testdata/images.gni b/src/storage/fxfs/testdata/images.gni
index 8f5d404..bdfacb8 100644
--- a/src/storage/fxfs/testdata/images.gni
+++ b/src/storage/fxfs/testdata/images.gni
@@ -1,7 +1,7 @@
 # Copyright 2024 The Fuchsia Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
-# Auto-generated by `fx fxfs create_golden` on 2024-03-07 00:14:14.201251104 +00:00
+# Auto-generated by `fx fxfs create_golden` on 2024-04-12 13:59:47.925783093 -04:00
 fxfs_golden_images = [
   "fxfs_golden.32.0.img.zstd",
   "fxfs_golden.33.0.img.zstd",
diff --git a/src/storage/fxfs/tools/src/golden.rs b/src/storage/fxfs/tools/src/golden.rs
index 7ecd202..6425c6d 100644
--- a/src/storage/fxfs/tools/src/golden.rs
+++ b/src/storage/fxfs/tools/src/golden.rs
@@ -7,8 +7,9 @@
     anyhow::{bail, ensure, Context, Error},
     chrono::Local,
     fxfs::{
-        filesystem::{mkfs_with_default, FxFilesystem, SyncOptions},
-        serialized_types::LATEST_VERSION,
+        filesystem::{mkfs_with_volume, FxFilesystem, OpenFxFilesystem, SyncOptions},
+        object_store::ObjectStore,
+        serialized_types::{Version, LATEST_VERSION},
     },
     fxfs_crypto::Crypt,
     fxfs_insecure_crypto::InsecureCrypt,
@@ -28,6 +29,11 @@
 const FXFS_GOLDEN_IMAGE_DIR: &str = "src/storage/fxfs/testdata";
 const FXFS_GOLDEN_IMAGE_MANIFEST: &str = "golden_image_manifest.json";
 const PROJECT_ID: u64 = 4;
+const DEFAULT_VOLUME: &str = "default";
+const UNENCRYPTED_VOLUME: &str = "unencrypted";
+const CHECK_FILE_PATH: &str = "some/test_file.txt";
+const CHECK_FILE_CONTENT: &[u8; 6] = &[0, 1, 2, 3, 4, 5];
+const SECOND_VOLUME_VERSION: Version = Version { major: 38, minor: 0 };
 
 /// Uses FUCHSIA_DIR environment variable to generate a path to the expected location of golden
 /// images. Note that we do this largely for ergonomics because this binary is typically invoked
@@ -67,6 +73,40 @@
     Ok(())
 }
 
+async fn activity_in_volume(fs: &OpenFxFilesystem, vol: &Arc<ObjectStore>) -> Result<(), Error> {
+    ops::mkdir(fs, vol, Path::new("some")).await?;
+    // Apply limit to project id and apply that both to the "some" directory to have it get applied
+    // everywhere else.
+    ops::set_project_limit(vol, PROJECT_ID, 102400, 1024).await?;
+    ops::set_project_for_node(vol, PROJECT_ID, &Path::new("some")).await?;
+
+    ops::put(fs, vol, &Path::new("some/file.txt"), EXPECTED_FILE_CONTENT.to_vec()).await?;
+    ops::put(fs, vol, &Path::new("some/deleted.txt"), EXPECTED_FILE_CONTENT.to_vec()).await?;
+    // Compact here and below so that there are some persistent files added.
+    fs.journal().compact().await?;
+    ops::unlink(fs, vol, &Path::new("some/deleted.txt")).await?;
+    ops::put(fs, vol, &Path::new("some/fsverity.txt"), EXPECTED_FILE_CONTENT.to_vec()).await?;
+    ops::enable_verity(vol, &Path::new("some/fsverity.txt")).await?;
+
+    fs.journal().compact().await?;
+
+    ops::set_extended_attribute_for_node(
+        vol,
+        &Path::new("some"),
+        b"security.selinux",
+        b"test value",
+    )
+    .await?;
+    ops::set_extended_attribute_for_node(
+        vol,
+        &Path::new("some/file.txt"),
+        b"user.hash",
+        b"different value",
+    )
+    .await?;
+    Ok(())
+}
+
 /// Create a new golden image (at the current version).
 pub async fn create_image() -> Result<(), Error> {
     let path = golden_image_dir()?.join(latest_image_filename());
@@ -75,49 +115,28 @@
     {
         let device_holder = DeviceHolder::new(FakeDevice::new(IMAGE_BLOCKS, IMAGE_BLOCK_SIZE));
         let device = device_holder.clone();
-        mkfs_with_default(device_holder, Some(crypt.clone())).await?;
+        mkfs_with_volume(device_holder, DEFAULT_VOLUME, Some(crypt.clone())).await?;
         device.reopen(false);
         save_device(device, path.as_path()).await?;
     }
     let device_holder = DeviceHolder::new(load_device(&path)?);
     let device = device_holder.clone();
     let fs = FxFilesystem::open(device_holder).await?;
-    let vol = ops::open_volume(&fs, crypt.clone()).await?;
-    ops::mkdir(&fs, &vol, Path::new("some")).await?;
-    // Apply limit to project id and apply that both to the "some" directory to have it get applied
-    // everywhere else.
-    ops::set_project_limit(&vol, PROJECT_ID, 102400, 1024).await?;
-    ops::set_project_for_node(&vol, PROJECT_ID, &Path::new("some")).await?;
-
-    ops::put(&fs, &vol, &Path::new("some/file.txt"), EXPECTED_FILE_CONTENT.to_vec()).await?;
-    ops::put(&fs, &vol, &Path::new("some/fsverity.txt"), EXPECTED_FILE_CONTENT.to_vec()).await?;
-    ops::enable_verity(&vol, &Path::new("some/fsverity.txt")).await?;
-    ops::put(&fs, &vol, &Path::new("some/deleted.txt"), EXPECTED_FILE_CONTENT.to_vec()).await?;
-    ops::unlink(&fs, &vol, &Path::new("some/deleted.txt")).await?;
-
-    ops::set_extended_attribute_for_node(
-        &vol,
-        &Path::new("some"),
-        b"security.selinux",
-        b"test value",
-    )
-    .await?;
-    ops::set_extended_attribute_for_node(
-        &vol,
-        &Path::new("some/file.txt"),
-        b"user.hash",
-        b"different value",
-    )
-    .await?;
+    let default_vol = ops::open_volume(&fs, DEFAULT_VOLUME, Some(crypt.clone())).await?;
+    let unencrypted_vol = ops::create_volume(&fs, UNENCRYPTED_VOLUME, None).await?;
+    for (vol, msg) in [(&default_vol, "default volume"), (&unencrypted_vol, "unencrypted volume")] {
+        activity_in_volume(&fs, vol).await.context(msg)?;
+    }
 
     // Write enough stuff to the journal (journal::BLOCK_SIZE per sync) to ensure we would fill
     // the disk without reclaim of both journal and file data.
     let num_iters = 2000;
     let before_generation = fs.super_block_header().generation;
     for _i in 0..num_iters {
-        ops::put(&fs, &vol, &Path::new("some/repeat.txt"), EXPECTED_FILE_CONTENT.to_vec()).await?;
+        ops::put(&fs, &default_vol, &Path::new("some/repeat.txt"), EXPECTED_FILE_CONTENT.to_vec())
+            .await?;
         fs.sync(SyncOptions { flush_device: true, precondition: None }).await?;
-        ops::unlink(&fs, &vol, &Path::new("some/repeat.txt")).await?;
+        ops::unlink(&fs, &default_vol, &Path::new("some/repeat.txt")).await?;
         fs.sync(SyncOptions { flush_device: true, precondition: None }).await?;
     }
     // Ensure that we have reclaimed the journal at least once.
@@ -149,6 +168,32 @@
     Ok(())
 }
 
+async fn check_volume(
+    fs: &OpenFxFilesystem,
+    vol: &Arc<ObjectStore>,
+    version: &Version,
+) -> Result<(), Error> {
+    if ops::get(&vol, &Path::new("some/file.txt")).await? != EXPECTED_FILE_CONTENT.to_vec() {
+        bail!("Expected file content incorrect.");
+    }
+    if version.major >= FSVERITY_VERSION_START {
+        if ops::get(&vol, &Path::new("some/fsverity.txt")).await? != EXPECTED_FILE_CONTENT.to_vec()
+        {
+            bail!("Expected fsverity content incorrect.");
+        }
+    }
+    if ops::get(&vol, &Path::new("some/deleted.txt")).await.is_ok() {
+        bail!("Found deleted file.");
+    }
+
+    // Make sure after writing a new file (using the latest format), the filesystem remains
+    // valid.
+    let mut content = vec![0u8; 6];
+    content.copy_from_slice(CHECK_FILE_CONTENT);
+    ops::put(&fs, &vol, &Path::new(CHECK_FILE_PATH), content).await?;
+    Ok(())
+}
+
 /// Validates an image by looking for expected data and performing an fsck.
 async fn check_image(path: &Path) -> Result<(), Error> {
     let crypt: Arc<dyn Crypt> = Arc::new(InsecureCrypt::new());
@@ -158,41 +203,34 @@
         ops::fsck(&fs, true).await.context("fsck failed")?;
         fs.journal().super_block_header().earliest_version
     };
-    {
-        let device = DeviceHolder::new(load_device(path)?);
-        let fs = FxFilesystem::open(device).await?;
-        let vol = ops::open_volume(&fs, crypt.clone()).await?;
-        if ops::get(&vol, &Path::new("some/file.txt")).await? != EXPECTED_FILE_CONTENT.to_vec() {
-            bail!("Expected file content incorrect.");
-        }
-        if version.major >= FSVERITY_VERSION_START {
-            if ops::get(&vol, &Path::new("some/fsverity.txt")).await?
-                != EXPECTED_FILE_CONTENT.to_vec()
-            {
-                bail!("Expected fsverity content incorrect.");
-            }
-        }
-        if ops::get(&vol, &Path::new("some/deleted.txt")).await.is_ok() {
-            bail!("Found deleted file.");
-        }
 
-        // Make sure after writing a new file (using the latest format), the filesystem remains
-        // valid.
-        let new_file = Path::new("some/test_file.txt");
-        let content = vec![0, 1, 2, 3, 4, 5];
-        ops::put(&fs, &vol, &new_file, content.clone()).await?;
-        fs.close().await?;
+    let device = DeviceHolder::new(load_device(path)?);
+    let fs = FxFilesystem::open(device).await?;
+    let mut volumes = vec![(DEFAULT_VOLUME, Some(crypt.clone()))];
+    if version >= SECOND_VOLUME_VERSION {
+        volumes.push((UNENCRYPTED_VOLUME, None));
+    }
+    for (vol_name, vol_crypt) in volumes.clone() {
+        let vol = ops::open_volume(&fs, vol_name, vol_crypt)
+            .await
+            .context(format!("Opening {}", vol_name))?;
+        check_volume(&fs, &vol, &version).await.context(format!("Checking {}", vol_name))?;
+    }
+    fs.close().await?;
 
-        let device = fs.take_device().await;
-        device.reopen(false);
-        let fs = FxFilesystem::open(device).await?;
-        ops::fsck(&fs, true).await.context("fsck failed")?;
-        let vol = ops::open_volume(&fs, crypt.clone()).await?;
-        if &ops::get(&vol, &new_file).await? != &content {
+    let device = fs.take_device().await;
+    device.reopen(false);
+    let fs = FxFilesystem::open(device).await?;
+    ops::fsck(&fs, true).await.context("fsck failed")?;
+    for (vol_name, vol_crypt) in volumes {
+        let vol = ops::open_volume(&fs, vol_name, vol_crypt).await.context(vol_name)?;
+        if &ops::get(&vol, &Path::new(CHECK_FILE_PATH)).await?.as_slice()
+            != &CHECK_FILE_CONTENT.as_slice()
+        {
             bail!("Unexpected file content in new file");
         }
-        fs.close().await
     }
+    fs.close().await
 }
 
 pub async fn check_images(image_root: Option<String>) -> Result<(), Error> {
diff --git a/src/storage/fxfs/tools/src/main.rs b/src/storage/fxfs/tools/src/main.rs
index 21ba399..09e61dd 100644
--- a/src/storage/fxfs/tools/src/main.rs
+++ b/src/storage/fxfs/tools/src/main.rs
@@ -6,7 +6,7 @@
     anyhow::Error,
     argh::FromArgs,
     fxfs::{
-        filesystem::{mkfs_with_default, FxFilesystem, FxFilesystemBuilder},
+        filesystem::{mkfs_with_volume, FxFilesystem, FxFilesystemBuilder},
         fsck,
     },
     fxfs_crypto::Crypt,
@@ -16,6 +16,8 @@
     tools::ops,
 };
 
+const DEFAULT_VOLUME: &str = "default";
+
 #[cfg(target_os = "linux")]
 use {
     fuse3::{raw::prelude::Session, MountOptions},
@@ -207,7 +209,7 @@
                         512,
                     ));
                     let fs = FxFilesystem::open(device).await?;
-                    let vol = ops::open_volume(&fs, crypt.clone()).await?;
+                    let vol = ops::open_volume(&fs, DEFAULT_VOLUME, Some(crypt.clone())).await?;
                     ops::unlink(&fs, &vol, &Path::new(&rmargs.path)).await?;
                     fs.close().await?;
                     let result = ops::fsck(&fs, args.verbose).await?;
@@ -220,7 +222,7 @@
                         512,
                     ));
                     let fs = FxFilesystemBuilder::new().read_only(true).open(device).await?;
-                    let vol = ops::open_volume(&fs, crypt).await?;
+                    let vol = ops::open_volume(&fs, DEFAULT_VOLUME, Some(crypt)).await?;
                     let data = ops::get(&vol, &Path::new(&getargs.src)).await?;
                     let mut reader = std::io::Cursor::new(&data);
                     let mut writer = std::fs::File::create(getargs.dst)?;
@@ -233,7 +235,7 @@
                         512,
                     ));
                     let fs = FxFilesystem::open(device).await?;
-                    let vol = ops::open_volume(&fs, crypt.clone()).await?;
+                    let vol = ops::open_volume(&fs, DEFAULT_VOLUME, Some(crypt.clone())).await?;
                     let mut data = Vec::new();
                     std::fs::File::open(&putargs.src)?.read_to_end(&mut data)?;
                     ops::put(&fs, &vol, &Path::new(&putargs.dst), data).await?;
@@ -246,7 +248,7 @@
                         std::fs::OpenOptions::new().read(true).write(true).open(cmd.file)?,
                         512,
                     ));
-                    mkfs_with_default(device, Some(crypt)).await?;
+                    mkfs_with_volume(device, DEFAULT_VOLUME, Some(crypt)).await?;
                     Ok(())
                 }
                 ImageSubCommand::Fsck(_) => {
@@ -269,7 +271,7 @@
                         512,
                     ));
                     let fs = FxFilesystemBuilder::new().read_only(true).open(device).await?;
-                    let vol = ops::open_volume(&fs, crypt).await?;
+                    let vol = ops::open_volume(&fs, DEFAULT_VOLUME, Some(crypt)).await?;
                     let dir = ops::walk_dir(&vol, &Path::new(&lsargs.path)).await?;
                     ops::print_ls(&dir).await?;
                     Ok(())
@@ -280,7 +282,7 @@
                         512,
                     ));
                     let fs = FxFilesystem::open(device).await?;
-                    let vol = ops::open_volume(&fs, crypt.clone()).await?;
+                    let vol = ops::open_volume(&fs, DEFAULT_VOLUME, Some(crypt.clone())).await?;
                     ops::mkdir(&fs, &vol, &Path::new(&mkdirargs.path)).await?;
                     fs.close().await?;
                     ops::fsck(&fs, args.verbose).await?;
@@ -292,7 +294,7 @@
                         512,
                     ));
                     let fs = FxFilesystem::open(device).await?;
-                    let vol = ops::open_volume(&fs, crypt.clone()).await?;
+                    let vol = ops::open_volume(&fs, DEFAULT_VOLUME, Some(crypt.clone())).await?;
                     ops::unlink(&fs, &vol, &Path::new(&rmdirargs.path)).await?;
                     fs.close().await?;
                     ops::fsck(&fs, args.verbose).await?;
diff --git a/src/storage/fxfs/tools/src/ops.rs b/src/storage/fxfs/tools/src/ops.rs
index 195815e..df67a0d 100644
--- a/src/storage/fxfs/tools/src/ops.rs
+++ b/src/storage/fxfs/tools/src/ops.rs
@@ -23,8 +23,6 @@
     std::{io::Write, ops::Deref, path::Path, sync::Arc},
 };
 
-const DEFAULT_VOLUME: &str = "default";
-
 pub async fn print_ls(dir: &Directory<ObjectStore>) -> Result<(), Error> {
     const DATE_FMT: &str = "%b %d %Y %T+00";
     let layer_set = dir.store().tree().layer_set();
@@ -78,13 +76,24 @@
     Ok(())
 }
 
+/// Make a volume
+pub async fn create_volume(
+    fs: &OpenFxFilesystem,
+    name: &str,
+    crypt: Option<Arc<dyn Crypt>>,
+) -> Result<Arc<ObjectStore>, Error> {
+    let root_volume = root_volume(fs.deref().clone()).await?;
+    root_volume.new_volume(name, crypt).await
+}
+
 /// Opens a volume on a device and returns a Directory to it's root.
 pub async fn open_volume(
     fs: &OpenFxFilesystem,
-    crypt: Arc<dyn Crypt>,
+    name: &str,
+    crypt: Option<Arc<dyn Crypt>>,
 ) -> Result<Arc<ObjectStore>, Error> {
     let root_volume = root_volume(fs.deref().clone()).await?;
-    root_volume.volume(DEFAULT_VOLUME, Some(crypt)).await.map(|v| v.into())
+    root_volume.volume(name, crypt).await.map(|v| v.into())
 }
 
 /// Walks a directory path from a given root.
diff --git a/src/storage/lib/blob_writer/tests/lib.rs b/src/storage/lib/blob_writer/tests/lib.rs
index a1041df..32d1a6f 100644
--- a/src/storage/lib/blob_writer/tests/lib.rs
+++ b/src/storage/lib/blob_writer/tests/lib.rs
@@ -10,7 +10,6 @@
         fidl_fuchsia_fxfs::MountOptions,
         fs_management::{filesystem::Filesystem, Fxfs},
         fuchsia_component::client::connect_to_protocol_at_dir_svc,
-        fuchsia_merkle::MerkleTreeBuilder,
         ramdevice_client::RamdiskClient,
         rand::{thread_rng, Rng},
     };
@@ -42,9 +41,7 @@
         let mut data = vec![1; 196608];
         thread_rng().fill(&mut data[..]);
 
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(&data).root();
 
         let compressed_data: Vec<u8> = Type1Blob::generate(&data, CompressionMode::Always);
 
@@ -94,9 +91,7 @@
         let mut data = vec![1; 499712];
         thread_rng().fill(&mut data[..]);
 
-        let mut builder = MerkleTreeBuilder::new();
-        builder.write(&data);
-        let hash = builder.finish().root();
+        let hash = fuchsia_merkle::from_slice(&data).root();
 
         let compressed_data = Type1Blob::generate(&data, CompressionMode::Always);
 
diff --git a/src/storage/lib/delivery_blob/src/compression.rs b/src/storage/lib/delivery_blob/src/compression.rs
index ba4ab50..2e7124b 100644
--- a/src/storage/lib/delivery_blob/src/compression.rs
+++ b/src/storage/lib/delivery_blob/src/compression.rs
@@ -10,7 +10,6 @@
     crc::Hasher32,
     itertools::Itertools,
     rayon::prelude::*,
-    static_assertions::assert_eq_size,
     std::ops::Range,
     thiserror::Error,
     zerocopy::{
@@ -19,8 +18,6 @@
     },
 };
 
-assert_eq_size!(usize, u64);
-
 #[derive(Debug, Error)]
 pub enum ChunkedArchiveError {
     #[error("Invalid or unsupported archive version.")]
diff --git a/src/storage/lib/delivery_blob/src/format.rs b/src/storage/lib/delivery_blob/src/format.rs
index 6573575..ac7f235 100644
--- a/src/storage/lib/delivery_blob/src/format.rs
+++ b/src/storage/lib/delivery_blob/src/format.rs
@@ -11,7 +11,7 @@
 use {
     bitflags::bitflags,
     crc::Hasher32 as _,
-    static_assertions::{assert_eq_size, const_assert_eq},
+    static_assertions::const_assert_eq,
     zerocopy::{
         byteorder::{LE, U32, U64},
         AsBytes, FromBytes, FromZeros, NoCell, Unaligned,
@@ -20,9 +20,6 @@
 
 use crate::{DeliveryBlobError, DeliveryBlobHeader, DeliveryBlobType, Type1Blob};
 
-// This library assumes usize is large enough to hold a u64.
-assert_eq_size!(usize, u64);
-
 /// Delivery blob magic number (0xfc1ab10b or "Fuchsia Blob" in big-endian).
 const DELIVERY_BLOB_MAGIC: [u8; 4] = [0xfc, 0x1a, 0xb1, 0x0b];
 
@@ -55,7 +52,7 @@
 /// Serialized header of an RFC 0207 compliant delivery blob.
 #[derive(AsBytes, FromZeros, FromBytes, NoCell, Unaligned, Clone, Copy, Debug)]
 #[repr(C)]
-struct SerializedHeader {
+pub(crate) struct SerializedHeader {
     magic: [u8; 4],
     delivery_type: U32<LE>,
     header_length: U32<LE>,
diff --git a/src/storage/lib/delivery_blob/src/lib.rs b/src/storage/lib/delivery_blob/src/lib.rs
index 9cf3465..9ee0b6f 100644
--- a/src/storage/lib/delivery_blob/src/lib.rs
+++ b/src/storage/lib/delivery_blob/src/lib.rs
@@ -22,7 +22,11 @@
 //! file.write_all(&payload).unwrap();
 
 use {
-    crate::{compression::ChunkedArchive, format::SerializedType1Blob},
+    crate::{
+        compression::{ChunkedArchive, ChunkedDecompressor},
+        format::SerializedType1Blob,
+    },
+    static_assertions::assert_eq_size,
     thiserror::Error,
     zerocopy::{AsBytes, Ref},
 };
@@ -33,6 +37,9 @@
 pub mod compression;
 mod format;
 
+// This library assumes usize is large enough to hold a u64.
+assert_eq_size!(usize, u64);
+
 /// Prefix used for writing delivery blobs. Should be prepended to the Merkle root of the blob.
 pub const DELIVERY_PATH_PREFIX: &'static str = "v1-";
 
@@ -57,6 +64,24 @@
     }
 }
 
+/// Returns the decompressed size of `delivery_blob`, delivery blob type is auto detected.
+pub fn decompressed_size(delivery_blob: &[u8]) -> Result<u64, DecompressError> {
+    let header = DeliveryBlobHeader::parse(delivery_blob)?.ok_or(DecompressError::NeedMoreData)?;
+    match header.delivery_type {
+        DeliveryBlobType::Type1 => Type1Blob::decompressed_size(delivery_blob),
+        _ => Err(DecompressError::DeliveryBlob(DeliveryBlobError::InvalidType)),
+    }
+}
+
+/// Decompress a delivery blob in `delivery_blob`, delivery blob type is auto detected.
+pub fn decompress(delivery_blob: &[u8]) -> Result<Vec<u8>, DecompressError> {
+    let header = DeliveryBlobHeader::parse(delivery_blob)?.ok_or(DecompressError::NeedMoreData)?;
+    match header.delivery_type {
+        DeliveryBlobType::Type1 => Type1Blob::decompress(delivery_blob),
+        _ => Err(DecompressError::DeliveryBlob(DeliveryBlobError::InvalidType)),
+    }
+}
+
 /// Obtain the file path to use when writing `blob_name` as a delivery blob.
 pub fn delivery_blob_path(blob_name: impl std::fmt::Display) -> String {
     format!("{}{}", DELIVERY_PATH_PREFIX, blob_name)
@@ -74,6 +99,18 @@
     IntegrityError,
 }
 
+#[derive(Debug, Error)]
+pub enum DecompressError {
+    #[error("DeliveryBlob error")]
+    DeliveryBlob(#[from] DeliveryBlobError),
+
+    #[error("ChunkedArchive error")]
+    ChunkedArchive(#[from] compression::ChunkedArchiveError),
+
+    #[error("Need more data")]
+    NeedMoreData,
+}
+
 #[cfg(target_os = "fuchsia")]
 impl From<DeliveryBlobError> for zx::Status {
     fn from(value: DeliveryBlobError) -> Self {
@@ -95,6 +132,20 @@
     pub header_length: u32,
 }
 
+impl DeliveryBlobHeader {
+    /// Attempt to parse `data` as a delivery blob. On success, returns validated blob header.
+    /// **WARNING**: This function does not verify that the payload is complete. Only the full
+    /// header of a delivery blob are required to be present in `data`.
+    pub fn parse(data: &[u8]) -> Result<Option<DeliveryBlobHeader>, DeliveryBlobError> {
+        let Some((serialized_header, _metadata_and_payload)) =
+            Ref::<_, format::SerializedHeader>::new_unaligned_from_prefix(data)
+        else {
+            return Ok(None);
+        };
+        serialized_header.decode().map(Some)
+    }
+}
+
 /// Type of delivery blob.
 ///
 /// **WARNING**: These constants are used when generating delivery blobs and should not be changed.
@@ -221,6 +272,35 @@
         };
         serialized_header.decode().map(|metadata| Some((metadata, payload)))
     }
+
+    /// Return the decompressed size of the blob without decompressing it.
+    pub fn decompressed_size(delivery_blob: &[u8]) -> Result<u64, DecompressError> {
+        let (header, payload) = Self::parse(delivery_blob)?.ok_or(DecompressError::NeedMoreData)?;
+        if !header.is_compressed {
+            return Ok(header.payload_length as u64);
+        }
+
+        let (seek_table, _chunk_data) =
+            compression::decode_archive(payload, header.payload_length)?
+                .ok_or(DecompressError::NeedMoreData)?;
+        Ok(seek_table.into_iter().map(|chunk| chunk.decompressed_range.len() as u64).sum())
+    }
+
+    /// Decompress a Type 1 delivery blob in `delivery_blob`.
+    pub fn decompress(delivery_blob: &[u8]) -> Result<Vec<u8>, DecompressError> {
+        let (header, payload) = Self::parse(delivery_blob)?.ok_or(DecompressError::NeedMoreData)?;
+        if !header.is_compressed {
+            return Ok(payload.into());
+        }
+
+        let (seek_table, chunk_data) = compression::decode_archive(payload, header.payload_length)?
+            .ok_or(DecompressError::NeedMoreData)?;
+        let mut decompressor = ChunkedDecompressor::new(seek_table)?;
+        let mut decompressed = vec![];
+        let mut chunk_callback = |chunk: &[u8]| decompressed.extend_from_slice(chunk);
+        decompressor.update(chunk_data, &mut chunk_callback)?;
+        Ok(decompressed)
+    }
 }
 
 #[cfg(test)]
@@ -238,6 +318,7 @@
         let (header, _) = Type1Blob::parse(&delivery_blob).unwrap().unwrap();
         assert!(!header.is_compressed);
         assert_eq!(header.payload_length, data.len());
+        assert_eq!(Type1Blob::decompress(&delivery_blob).unwrap(), data);
     }
 
     #[test]
@@ -251,6 +332,7 @@
         // Payload is not very compressible, so we expect it to be larger than the original.
         assert!(header.is_compressed);
         assert!(header.payload_length > data.len());
+        assert_eq!(Type1Blob::decompress(&delivery_blob).unwrap(), data);
     }
 
     #[test]
@@ -264,6 +346,7 @@
         let (header, _) = Type1Blob::parse(&delivery_blob).unwrap().unwrap();
         assert!(!header.is_compressed);
         assert_eq!(header.payload_length, data.len());
+        assert_eq!(Type1Blob::decompress(&delivery_blob).unwrap(), data);
     }
 
     #[test]
@@ -274,5 +357,6 @@
         // Payload should be compressed and smaller than the original input.
         assert!(header.is_compressed);
         assert!(header.payload_length < data.len());
+        assert_eq!(Type1Blob::decompress(&delivery_blob).unwrap(), data);
     }
 }
diff --git a/src/storage/lib/fs_management/cpp/admin_test.cc b/src/storage/lib/fs_management/cpp/admin_test.cc
index 60ffe31..be9a99c 100644
--- a/src/storage/lib/fs_management/cpp/admin_test.cc
+++ b/src/storage/lib/fs_management/cpp/admin_test.cc
@@ -201,9 +201,8 @@
 
  protected:
   void WriteTestFile() {
-    auto test_file_ends = fidl::CreateEndpoints<fio::File>();
-    ASSERT_TRUE(test_file_ends.is_ok()) << test_file_ends.status_string();
-    fidl::ServerEnd<fio::Node> test_file_server(test_file_ends->server.TakeChannel());
+    auto test_file_ends = fidl::Endpoints<fio::File>::Create();
+    fidl::ServerEnd<fio::Node> test_file_server(test_file_ends.server.TakeChannel());
 
     fio::wire::OpenFlags file_flags = fio::wire::OpenFlags::kRightReadable |
                                       fio::wire::OpenFlags::kRightWritable |
@@ -213,7 +212,7 @@
                   .status(),
               ZX_OK);
 
-    fidl::WireSyncClient<fio::File> file_client(std::move(test_file_ends->client));
+    fidl::WireSyncClient<fio::File> file_client(std::move(test_file_ends.client));
     std::vector<uint8_t> content{1, 2, 3, 4};
     const fidl::WireResult res =
         file_client->Write(fidl::VectorView<uint8_t>::FromExternal(content));
@@ -238,9 +237,8 @@
 
   auto data_root = DataRoot();
 
-  auto fail_file_ends = fidl::CreateEndpoints<fio::File>();
-  ASSERT_TRUE(fail_file_ends.is_ok()) << fail_file_ends.status_string();
-  fidl::ServerEnd<fio::Node> fail_test_file_server(fail_file_ends->server.TakeChannel());
+  auto fail_file_ends = fidl::Endpoints<fio::File>::Create();
+  fidl::ServerEnd<fio::Node> fail_test_file_server(fail_file_ends.server.TakeChannel());
 
   fio::wire::OpenFlags fail_file_flags =
       fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightWritable;
@@ -250,21 +248,20 @@
   ASSERT_TRUE(open_resp.ok()) << open_resp.status_string();
 
   // ...we can't actually use the channel
-  fidl::WireSyncClient<fio::File> fail_file_client(std::move(fail_file_ends->client));
+  fidl::WireSyncClient<fio::File> fail_file_client(std::move(fail_file_ends.client));
   const fidl::WireResult res1 = fail_file_client->Read(4);
   ASSERT_EQ(res1.status(), ZX_ERR_PEER_CLOSED) << res1.status_string();
 
   // the channel will be valid if we open the file read-only though
-  auto test_file_ends = fidl::CreateEndpoints<fio::File>();
-  ASSERT_TRUE(test_file_ends.is_ok()) << test_file_ends.status_string();
-  fidl::ServerEnd<fio::Node> test_file_server(test_file_ends->server.TakeChannel());
+  auto test_file_ends = fidl::Endpoints<fio::File>::Create();
+  fidl::ServerEnd<fio::Node> test_file_server(test_file_ends.server.TakeChannel());
 
   fio::wire::OpenFlags file_flags = fio::wire::OpenFlags::kRightReadable;
   auto open_resp2 =
       fidl::WireCall(data_root)->Open(file_flags, {}, kTestFilePath, std::move(test_file_server));
   ASSERT_TRUE(open_resp2.ok()) << open_resp2.status_string();
 
-  fidl::WireSyncClient<fio::File> file_client(std::move(test_file_ends->client));
+  fidl::WireSyncClient<fio::File> file_client(std::move(test_file_ends.client));
   const fidl::WireResult res2 = file_client->Read(4);
   ASSERT_TRUE(res2.ok()) << res2.status_string();
   const fit::result resp2 = res2.value();
@@ -280,9 +277,8 @@
   ASSERT_NO_FATAL_FAILURE(StartFilesystem({}));
   ASSERT_NO_FATAL_FAILURE(WriteTestFile());
 
-  auto test_file_ends = fidl::CreateEndpoints<fio::File>();
-  ASSERT_TRUE(test_file_ends.is_ok()) << test_file_ends.status_string();
-  fidl::ServerEnd<fio::Node> test_file_server(test_file_ends->server.TakeChannel());
+  auto test_file_ends = fidl::Endpoints<fio::File>::Create();
+  fidl::ServerEnd<fio::Node> test_file_server(test_file_ends.server.TakeChannel());
 
   fio::wire::OpenFlags file_flags = fio::wire::OpenFlags::kRightReadable |
                                     fio::wire::OpenFlags::kRightWritable |
@@ -291,7 +287,7 @@
                        ->Open(file_flags, {}, kTestFilePath, std::move(test_file_server));
   ASSERT_TRUE(open_resp.ok()) << open_resp.status_string();
 
-  fidl::WireSyncClient<fio::File> file_client(std::move(test_file_ends->client));
+  fidl::WireSyncClient<fio::File> file_client(std::move(test_file_ends.client));
   std::vector<uint8_t> content{1, 2, 3, 4};
   auto write_resp = file_client->Write(fidl::VectorView<uint8_t>::FromExternal(content));
   ASSERT_EQ(write_resp.status(), ZX_ERR_PEER_CLOSED) << write_resp.status_string();
diff --git a/src/storage/lib/fs_management/cpp/fvm.cc b/src/storage/lib/fs_management/cpp/fvm.cc
index dcc1cca..fa33fc7 100644
--- a/src/storage/lib/fs_management/cpp/fvm.cc
+++ b/src/storage/lib/fs_management/cpp/fvm.cc
@@ -218,12 +218,8 @@
             !matcher.detected_formats.empty() || !matcher.labels.empty() ||
             !matcher.parent_device.empty());
 
-  zx::result partition_endpoints =
-      fidl::CreateEndpoints<fuchsia_hardware_block_partition::Partition>();
-  if (partition_endpoints.is_error()) {
-    return partition_endpoints.take_error();
-  }
-  auto& [partition_client_end, partition_server_end] = partition_endpoints.value();
+  auto [partition_client_end, partition_server_end] =
+      fidl::Endpoints<fuchsia_hardware_block_partition::Partition>::Create();
   if (const fidl::OneWayStatus result =
           fidl::WireCall(channel)->ConnectToDeviceFidl(partition_server_end.TakeChannel());
       !result.ok()) {
diff --git a/src/storage/lib/fs_management/cpp/mount.cc b/src/storage/lib/fs_management/cpp/mount.cc
index 69122ff..3726902 100644
--- a/src/storage/lib/fs_management/cpp/mount.cc
+++ b/src/storage/lib/fs_management/cpp/mount.cc
@@ -185,10 +185,7 @@
   if (volumes_.find(name) != volumes_.end()) {
     return zx::error(ZX_ERR_ALREADY_BOUND);
   }
-  auto endpoints_or = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  if (endpoints_or.is_error())
-    return endpoints_or.take_error();
-  auto [client, server] = std::move(*endpoints_or);
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
   auto res = fs_management::OpenVolume(exposed_dir_, name, std::move(server), std::move(options));
   if (res.is_error()) {
     return res.take_error();
@@ -203,10 +200,7 @@
   if (volumes_.find(name) != volumes_.end()) {
     return zx::error(ZX_ERR_ALREADY_BOUND);
   }
-  auto endpoints_or = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  if (endpoints_or.is_error())
-    return endpoints_or.take_error();
-  auto [client, server] = std::move(*endpoints_or);
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
   auto res = fs_management::CreateVolume(exposed_dir_, name, std::move(server), std::move(options));
   if (res.is_error()) {
     return res.take_error();
@@ -294,11 +288,7 @@
     return outgoing_dir_or.take_error();
   }
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  if (endpoints.is_error()) {
-    return endpoints.take_error();
-  }
-  auto [client, server] = std::move(*endpoints);
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   auto volume = OpenVolume(
       *outgoing_dir_or, volume_name, std::move(server),
diff --git a/src/storage/lib/fs_management/cpp/volumes.cc b/src/storage/lib/fs_management/cpp/volumes.cc
index 2739474..5a70bc6 100644
--- a/src/storage/lib/fs_management/cpp/volumes.cc
+++ b/src/storage/lib/fs_management/cpp/volumes.cc
@@ -30,10 +30,7 @@
                          const std::string& path) {
   // Check if the volume exists.  This way, we can return an explicit NOT_FOUND if absent.
   // TODO(https://fxbug.dev/42174810): Check the epitaph of the call to Mount instead.
-  auto endpoints_or = fidl::CreateEndpoints<fuchsia_io::Node>();
-  if (endpoints_or.is_error())
-    return endpoints_or.take_error();
-  auto [client, server] = std::move(*endpoints_or);
+  auto [client, server] = fidl::Endpoints<fuchsia_io::Node>::Create();
   auto res = fidl::WireCall(exposed_dir)
                  ->Open(fuchsia_io::wire::OpenFlags::kNodeReference, {},
                         fidl::StringView::FromExternal(path), std::move(server));
diff --git a/src/storage/lib/paver/BUILD.gn b/src/storage/lib/paver/BUILD.gn
index ac9a063..37f9617 100644
--- a/src/storage/lib/paver/BUILD.gn
+++ b/src/storage/lib/paver/BUILD.gn
@@ -97,23 +97,21 @@
 # Board specific paver implementations.
 source_set("astro") {
   sources = [ "astro.cc" ]
-  deps = [
+  public_deps = [
     ":paver-core",
+    ":skip-block",
     "//sdk/fidl/fuchsia.boot:fuchsia.boot_cpp",
     "//sdk/lib/component/incoming/cpp",
     "//src/devices/lib/amlogic",
     "//src/lib/uuid",
     "//src/storage/gpt",
-  ]
-  public_deps = [
-    ":skip-block",
     "//zircon/system/ulib/sysconfig-client:sysconfig-sync-client",
   ]
 }
 
 source_set("sherlock") {
   sources = [ "sherlock.cc" ]
-  deps = [
+  public_deps = [
     ":gpt",
     ":paver-core",
     "//src/devices/lib/amlogic",
@@ -124,7 +122,7 @@
 
 source_set("nelson") {
   sources = [ "nelson.cc" ]
-  deps = [
+  public_deps = [
     ":gpt",
     ":paver-core",
     "//src/devices/lib/amlogic",
@@ -135,7 +133,7 @@
 
 source_set("luis") {
   sources = [ "luis.cc" ]
-  deps = [
+  public_deps = [
     ":gpt",
     ":paver-core",
     "//src/devices/lib/amlogic",
@@ -157,7 +155,7 @@
 
 source_set("violet") {
   sources = [ "violet.cc" ]
-  deps = [
+  public_deps = [
     ":gpt",
     ":paver-core",
     "//src/lib/uuid",
@@ -170,7 +168,7 @@
     "system_shutdown_state.cc",
     "x64.cc",
   ]
-  deps = [
+  public_deps = [
     ":gpt",
     ":paver-core",
     "//sdk/fidl/fuchsia.device.manager:fuchsia.device.manager_cpp",
diff --git a/src/storage/lib/paver/gpt.cc b/src/storage/lib/paver/gpt.cc
index 1123daf..553bf3d 100644
--- a/src/storage/lib/paver/gpt.cc
+++ b/src/storage/lib/paver/gpt.cc
@@ -336,12 +336,7 @@
       continue;
     }
 
-    zx::result controller_endpoints = fidl::CreateEndpoints<fuchsia_device::Controller>();
-    if (controller_endpoints.is_error()) {
-      ERROR("Failed to create controller endpoints %s\n", controller_endpoints.status_string());
-      continue;
-    }
-    auto& [controller, controller_server] = controller_endpoints.value();
+    auto [controller, controller_server] = fidl::Endpoints<fuchsia_device::Controller>::Create();
     if (fidl::OneWayStatus status = fidl::WireCall(gpt_device.controller)
                                         ->ConnectToController(std::move(controller_server));
         !status.ok()) {
diff --git a/src/storage/lib/paver/paver.cc b/src/storage/lib/paver/paver.cc
index cf05502..55195db 100644
--- a/src/storage/lib/paver/paver.cc
+++ b/src/storage/lib/paver/paver.cc
@@ -891,6 +891,7 @@
                                                             GetCurrentArch(), context_);
   if (partitioner.is_error()) {
     ERROR("Unable to initialize a partitioner: %s.\n", partitioner.status_string());
+    cb(partitioner.status_value());
     return;
   }
   zx::result res = partitioner->OnStop();
diff --git a/src/storage/lib/vfs/cpp/connection/connection.cc b/src/storage/lib/vfs/cpp/connection/connection.cc
index 8451e38..2de843f 100644
--- a/src/storage/lib/vfs/cpp/connection/connection.cc
+++ b/src/storage/lib/vfs/cpp/connection/connection.cc
@@ -34,26 +34,6 @@
 
 namespace fs::internal {
 
-bool PrevalidateFlags(fio::OpenFlags flags) {
-  if (flags & fio::OpenFlags::kNodeReference) {
-    // Explicitly reject VNODE_REF_ONLY together with any invalid flags.
-    if (flags - fio::kOpenFlagsAllowedWithNodeReference) {
-      return false;
-    }
-  }
-
-  if ((flags & fio::OpenFlags::kNotDirectory) && (flags & fio::OpenFlags::kDirectory)) {
-    return false;
-  }
-
-  // If CLONE_SAME_RIGHTS is specified, the client cannot request any specific rights.
-  if ((flags & fio::OpenFlags::kCloneSameRights) && (flags & kAllIo1Rights)) {
-    return false;
-  }
-
-  return true;
-}
-
 Connection::Connection(FuchsiaVfs* vfs, fbl::RefPtr<Vnode> vnode, fuchsia_io::Rights rights)
     : vfs_(vfs), vnode_(std::move(vnode)), rights_(rights) {
   ZX_DEBUG_ASSERT(vfs);
@@ -68,56 +48,71 @@
   }
 }
 
-void Connection::NodeClone(fio::OpenFlags flags, fidl::ServerEnd<fio::Node> server_end) {
-  auto write_error = [describe = flags & fio::OpenFlags::kDescribe](
-                         fidl::ServerEnd<fio::Node> channel, zx_status_t error) {
-    FS_PRETTY_TRACE_DEBUG("[NodeClone] error: ", zx_status_get_string(error));
-    if (describe) {
+void Connection::NodeClone(fio::OpenFlags flags, VnodeProtocol protocol,
+                           fidl::ServerEnd<fio::Node> server_end) {
+  auto clone_result = [=]() -> zx::result<std::tuple<fbl::RefPtr<Vnode>, VnodeConnectionOptions>> {
+    if (!ValidateCloneFlags(flags)) {
+      FS_PRETTY_TRACE_DEBUG("[NodeClone] invalid flags: ", flags);
+      return zx::error(ZX_ERR_INVALID_ARGS);
+    }
+    auto clone_options = VnodeConnectionOptions::FromCloneFlags(flags);
+    FS_PRETTY_TRACE_DEBUG("[NodeClone] our rights: ", rights(), ", clone options: ", clone_options);
+
+    // If CLONE_SAME_RIGHTS is requested, cloned connection will inherit the same rights as those
+    // from the originating connection.
+    if (clone_options.flags & fio::OpenFlags::kCloneSameRights) {
+      clone_options.rights = rights_;
+    } else if (clone_options.rights - rights_) {
+      // Return ACCESS_DENIED if the client asked for a right the parent connection doesn't have.
+      return zx::error(ZX_ERR_ACCESS_DENIED);
+    }
+
+    // Ensure we map the request to the correct flags based on the connection's protocol.
+    switch (protocol) {
+      case fs::VnodeProtocol::kNode: {
+        clone_options.flags |= fio::OpenFlags::kNodeReference;
+        break;
+      }
+      case fs::VnodeProtocol::kDirectory: {
+        clone_options.flags |= fio::OpenFlags::kDirectory;
+        break;
+      }
+      default: {
+        clone_options.flags |= fio::OpenFlags::kNotDirectory;
+        break;
+      }
+    }
+
+    if (zx::result validated = vnode()->ValidateOptions(clone_options); validated.is_error()) {
+      return validated.take_error();
+    }
+    fbl::RefPtr vn = vnode();
+    if (protocol != VnodeProtocol::kNode) {
+      // We only need to open the underlying Vnode again if this isn't a node reference connection.
+      if (zx_status_t open_status = OpenVnode(&vn); open_status != ZX_OK) {
+        return zx::error(open_status);
+      }
+    }
+
+    return zx::ok(std::make_tuple(std::move(vn), clone_options));
+  }();
+
+  if (clone_result.is_ok()) {
+    auto [vnode, options] = *std::move(clone_result);
+    vfs_->Serve(vnode, server_end.TakeChannel(), options);
+  } else {
+    FS_PRETTY_TRACE_DEBUG("[NodeClone] error: ", clone_result.status_string());
+    if (flags & fio::OpenFlags::kDescribe) {
       // Ignore errors since there is nothing we can do if this fails.
       [[maybe_unused]] auto result =
-          fidl::WireSendEvent(channel)->OnOpen(error, fio::wire::NodeInfoDeprecated());
-      channel.reset();
-    }
-  };
-
-  if (!PrevalidateFlags(flags)) {
-    FS_PRETTY_TRACE_DEBUG("[NodeClone] prevalidate failed", ", incoming flags: ", flags);
-    write_error(std::move(server_end), ZX_ERR_INVALID_ARGS);
-    return;
-  }
-  auto clone_options = VnodeConnectionOptions::FromIoV1Flags(flags);
-  FS_PRETTY_TRACE_DEBUG("[NodeClone] our options: ", options(),
-                        ", incoming options: ", clone_options);
-
-  // If CLONE_SAME_RIGHTS is requested, cloned connection will inherit the same rights as those from
-  // the originating connection.
-  if (clone_options.flags & fio::OpenFlags::kCloneSameRights) {
-    clone_options.rights = rights_;
-  } else {
-    // Return ACCESS_DENIED if the client asked for a right the parent connection doesn't have.
-    if (clone_options.rights - rights_) {
-      write_error(std::move(server_end), ZX_ERR_ACCESS_DENIED);
-      return;
+          fidl::WireSendEvent(server_end)
+              ->OnOpen(clone_result.error_value(), fio::wire::NodeInfoDeprecated());
     }
   }
-
-  fbl::RefPtr<Vnode> vn(vnode_);
-  if (zx::result validated = vn->ValidateOptions(clone_options); validated.is_error()) {
-    write_error(std::move(server_end), validated.error_value());
-    return;
-  }
-  if (!(clone_options.flags & fio::OpenFlags::kNodeReference)) {
-    if (zx_status_t open_status = OpenVnode(&vn); open_status != ZX_OK) {
-      write_error(std::move(server_end), open_status);
-      return;
-    }
-  }
-
-  vfs_->Serve(vn, server_end.TakeChannel(), clone_options);
 }
 
 zx::result<VnodeAttributes> Connection::NodeGetAttr() const {
-  FS_PRETTY_TRACE_DEBUG("[NodeGetAttr] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[NodeGetAttr] rights: ", rights());
   // TODO(https://fxbug.dev/324080764): This io1 operation should require the GET_ATTRIBUTES right.
   fs::VnodeAttributes attr;
   if (zx_status_t status = vnode_->GetAttributes(&attr); status != ZX_OK) {
@@ -128,7 +123,7 @@
 
 zx::result<> Connection::NodeSetAttr(fio::NodeAttributeFlags flags,
                                      const fio::wire::NodeAttributes& attributes) {
-  FS_PRETTY_TRACE_DEBUG("[NodeSetAttr] our options: ", options(), ", incoming flags: ", flags);
+  FS_PRETTY_TRACE_DEBUG("[NodeSetAttr] our rights: ", rights(), ", incoming flags: ", flags);
   if (!(rights_ & fio::Rights::kUpdateAttributes)) {
     return zx::error(ZX_ERR_BAD_HANDLE);
   }
diff --git a/src/storage/lib/vfs/cpp/connection/connection.h b/src/storage/lib/vfs/cpp/connection/connection.h
index a316b70..ab0acf3 100644
--- a/src/storage/lib/vfs/cpp/connection/connection.h
+++ b/src/storage/lib/vfs/cpp/connection/connection.h
@@ -112,7 +112,8 @@
   // methods, used by all connection subclasses. Use caution when working with FIDL wire types,
   // as certain wire types may reference external data.
 
-  void NodeClone(fuchsia_io::wire::OpenFlags flags, fidl::ServerEnd<fuchsia_io::Node> server_end);
+  void NodeClone(fuchsia_io::OpenFlags flags, VnodeProtocol protocol,
+                 fidl::ServerEnd<fuchsia_io::Node> server_end);
   zx::result<VnodeAttributes> NodeGetAttr() const;
   zx::result<> NodeSetAttr(fuchsia_io::wire::NodeAttributeFlags flags,
                            const fuchsia_io::wire::NodeAttributes& attributes);
diff --git a/src/storage/lib/vfs/cpp/connection/directory_connection.cc b/src/storage/lib/vfs/cpp/connection/directory_connection.cc
index bb49726..6530444 100644
--- a/src/storage/lib/vfs/cpp/connection/directory_connection.cc
+++ b/src/storage/lib/vfs/cpp/connection/directory_connection.cc
@@ -107,8 +107,7 @@
 }
 
 void DirectoryConnection::Clone(CloneRequestView request, CloneCompleter::Sync& completer) {
-  // TODO(https://fxbug.dev/42062619): test this.
-  Connection::NodeClone(request->flags | fio::OpenFlags::kDirectory, std::move(request->object));
+  Connection::NodeClone(request->flags, VnodeProtocol::kDirectory, std::move(request->object));
 }
 
 void DirectoryConnection::Close(CloseCompleter::Sync& completer) { completer.Reply(Unbind()); }
@@ -190,21 +189,17 @@
     flags |= fio::wire::OpenFlags::kDirectory;
   }
 
-  auto open_options = VnodeConnectionOptions::FromIoV1Flags(flags);
+  auto open_options = VnodeConnectionOptions::FromOpen1Flags(flags);
 
-  if (!PrevalidateFlags(flags)) {
-    FS_PRETTY_TRACE_DEBUG("[DirectoryOpen] prevalidate failed",
-                          ", incoming flags: ", request->flags, ", path: ", request->path);
+  if (!ValidateOpenFlags(flags)) {
+    FS_PRETTY_TRACE_DEBUG("[DirectoryOpen] Invalid open flags: ", request->flags,
+                          ", path: ", request->path);
     return write_error(std::move(request->object), ZX_ERR_INVALID_ARGS);
   }
 
-  FS_PRETTY_TRACE_DEBUG("[DirectoryOpen] our options: ", options(),
+  FS_PRETTY_TRACE_DEBUG("[DirectoryOpen] our rights ", rights(),
                         ", incoming options: ", open_options, ", path: ", request->path);
 
-  if (open_options.flags & fuchsia_io::OpenFlags::kCloneSameRights) {
-    return write_error(std::move(request->object), ZX_ERR_INVALID_ARGS);
-  }
-
   // The POSIX compatibility flags allow the child directory connection to inherit the writable
   // and executable rights.  If there exists a directory without the corresponding right along
   // the Open() chain, we remove that POSIX flag preventing it from being inherited down the line
@@ -226,7 +221,7 @@
 }
 
 void DirectoryConnection::Unlink(UnlinkRequestView request, UnlinkCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[DirectoryUnlink] our options: ", options(), ", name: ", request->name);
+  FS_PRETTY_TRACE_DEBUG("[DirectoryUnlink] our rights: ", rights(), ", name: ", request->name);
   // TODO(https://fxbug.dev/324080764): This operation should require ENUMERATE and MODIFY_DIRECTORY
   // rights, instead of WRITE_BYTES.
   if (!(rights() & fuchsia_io::Rights::kWriteBytes)) {
@@ -252,7 +247,7 @@
 
 void DirectoryConnection::ReadDirents(ReadDirentsRequestView request,
                                       ReadDirentsCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[DirectoryReadDirents] our options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[DirectoryReadDirents] our rights: ", rights());
   // TODO(https://fxbug.dev/324080764): This io1 operation should require the ENUMERATE right.
   if (request->max_bytes > fio::wire::kMaxBuf) {
     completer.Reply(ZX_ERR_BAD_HANDLE, fidl::VectorView<uint8_t>());
@@ -266,14 +261,14 @@
 }
 
 void DirectoryConnection::Rewind(RewindCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[DirectoryRewind] our options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[DirectoryRewind] our rights: ", rights());
   // TODO(https://fxbug.dev/324080764): This io1 operation should require the ENUMERATE right.
   dircookie_ = VdirCookie();
   completer.Reply(ZX_OK);
 }
 
 void DirectoryConnection::GetToken(GetTokenCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[DirectoryGetToken] our options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[DirectoryGetToken] our rights: ", rights());
   // TODO(https://fxbug.dev/324080764): This io1 operation should need ENUMERATE or another right.
   if (!(rights() & fuchsia_io::Rights::kWriteBytes)) {
     completer.Reply(ZX_ERR_BAD_HANDLE, zx::handle());
@@ -285,7 +280,7 @@
 }
 
 void DirectoryConnection::Rename(RenameRequestView request, RenameCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[DirectoryRename] our options: ", options(), ", src: ", request->src,
+  FS_PRETTY_TRACE_DEBUG("[DirectoryRename] our rights: ", rights(), ", src: ", request->src,
                         ", dst: ", request->dst);
   if (request->src.empty() || request->dst.empty()) {
     completer.ReplyError(ZX_ERR_INVALID_ARGS);
@@ -308,7 +303,7 @@
 }
 
 void DirectoryConnection::Link(LinkRequestView request, LinkCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[DirectoryLink] our options: ", options(), ", src: ", request->src,
+  FS_PRETTY_TRACE_DEBUG("[DirectoryLink] our rights: ", rights(), ", src: ", request->src,
                         ", dst: ", request->dst);
   // |fuchsia.io/Directory.Rename| only specified the token to be a generic handle; casting it here.
   zx::event token(request->dst_parent_token.release());
@@ -329,7 +324,7 @@
 }
 
 void DirectoryConnection::Watch(WatchRequestView request, WatchCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[DirectoryWatch] our options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[DirectoryWatch] our rights: ", rights());
   // TODO(https://fxbug.dev/324080764): This io1 operation should require the ENUMERATE right.
   zx_status_t status =
       vnode()->WatchDir(vfs(), request->mask, request->options, std::move(request->watcher));
@@ -337,7 +332,7 @@
 }
 
 void DirectoryConnection::QueryFilesystem(QueryFilesystemCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[DirectoryQueryFilesystem] our options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[DirectoryQueryFilesystem] our rights: ", rights());
 
   zx::result result = Connection::NodeQueryFilesystem();
   completer.Reply(result.status_value(),
diff --git a/src/storage/lib/vfs/cpp/connection/file_connection.cc b/src/storage/lib/vfs/cpp/connection/file_connection.cc
index 4ddc3e1..bc91fff 100644
--- a/src/storage/lib/vfs/cpp/connection/file_connection.cc
+++ b/src/storage/lib/vfs/cpp/connection/file_connection.cc
@@ -59,7 +59,8 @@
   if (append()) {
     inherited_flags |= fio::OpenFlags::kAppend;
   }
-  Connection::NodeClone(request->flags | inherited_flags, std::move(request->object));
+  Connection::NodeClone(request->flags | inherited_flags, VnodeProtocol::kFile,
+                        std::move(request->object));
 }
 
 void FileConnection::Close(CloseCompleter::Sync& completer) { completer.Reply(Unbind()); }
@@ -198,7 +199,7 @@
 }
 
 zx_status_t FileConnection::ResizeInternal(uint64_t length) {
-  FS_PRETTY_TRACE_DEBUG("[FileTruncate] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileTruncate] rights: ", rights(), ", append: ", append());
   if (!(rights() & fuchsia_io::Rights::kWriteBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
diff --git a/src/storage/lib/vfs/cpp/connection/node_connection.cc b/src/storage/lib/vfs/cpp/connection/node_connection.cc
index 894d5892..3f240b9 100644
--- a/src/storage/lib/vfs/cpp/connection/node_connection.cc
+++ b/src/storage/lib/vfs/cpp/connection/node_connection.cc
@@ -48,9 +48,7 @@
   return zx::ok();
 }
 void NodeConnection::Clone(CloneRequestView request, CloneCompleter::Sync& completer) {
-  // The NODE_REFERENCE flag should be preserved when cloning a node connection.
-  Connection::NodeClone(request->flags | fio::OpenFlags::kNodeReference,
-                        std::move(request->object));
+  Connection::NodeClone(request->flags, VnodeProtocol::kNode, std::move(request->object));
 }
 
 void NodeConnection::Close(CloseCompleter::Sync& completer) { completer.Reply(Unbind()); }
diff --git a/src/storage/lib/vfs/cpp/connection/remote_file_connection.cc b/src/storage/lib/vfs/cpp/connection/remote_file_connection.cc
index 13c0f7a..8ab028f 100644
--- a/src/storage/lib/vfs/cpp/connection/remote_file_connection.cc
+++ b/src/storage/lib/vfs/cpp/connection/remote_file_connection.cc
@@ -31,7 +31,7 @@
     : FileConnection(vfs, std::move(vnode), rights, append, koid) {}
 
 zx_status_t RemoteFileConnection::ReadInternal(void* data, size_t len, size_t* out_actual) {
-  FS_PRETTY_TRACE_DEBUG("[FileRead] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileRead] rights: ", rights());
   if (!(rights() & fuchsia_io::Rights::kReadBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
@@ -59,7 +59,7 @@
 
 zx_status_t RemoteFileConnection::ReadAtInternal(void* data, size_t len, size_t offset,
                                                  size_t* out_actual) {
-  FS_PRETTY_TRACE_DEBUG("[FileReadAt] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileReadAt] rights: ", rights());
   if (!(rights() & fuchsia_io::Rights::kReadBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
@@ -85,7 +85,7 @@
 }
 
 zx_status_t RemoteFileConnection::WriteInternal(const void* data, size_t len, size_t* out_actual) {
-  FS_PRETTY_TRACE_DEBUG("[FileWrite] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileWrite] rights: ", rights());
   if (!(rights() & fuchsia_io::Rights::kWriteBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
@@ -120,7 +120,7 @@
 
 zx_status_t RemoteFileConnection::WriteAtInternal(const void* data, size_t len, size_t offset,
                                                   size_t* out_actual) {
-  FS_PRETTY_TRACE_DEBUG("[FileWriteAt] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileWriteAt] rights: ", rights());
   if (!(rights() & fuchsia_io::Rights::kWriteBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
@@ -144,7 +144,7 @@
 
 zx_status_t RemoteFileConnection::SeekInternal(fuchsia_io::wire::SeekOrigin origin,
                                                int64_t requested_offset) {
-  FS_PRETTY_TRACE_DEBUG("[FileSeek] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileSeek] rights: ", rights());
   fs::VnodeAttributes attr;
   if (zx_status_t status = vnode()->GetAttributes(&attr); status != ZX_OK) {
     return ZX_ERR_STOP;
diff --git a/src/storage/lib/vfs/cpp/connection/stream_file_connection.cc b/src/storage/lib/vfs/cpp/connection/stream_file_connection.cc
index 30b4c89d9..460aaee 100644
--- a/src/storage/lib/vfs/cpp/connection/stream_file_connection.cc
+++ b/src/storage/lib/vfs/cpp/connection/stream_file_connection.cc
@@ -36,7 +36,7 @@
     : FileConnection(vfs, std::move(vnode), rights, append, koid), stream_(std::move(stream)) {}
 
 zx_status_t StreamFileConnection::ReadInternal(void* data, size_t len, size_t* out_actual) {
-  FS_PRETTY_TRACE_DEBUG("[FileRead] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileRead] rights: ", rights());
   if (!(rights() & fuchsia_io::Rights::kReadBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
@@ -67,7 +67,7 @@
 
 zx_status_t StreamFileConnection::ReadAtInternal(void* data, size_t len, size_t offset,
                                                  size_t* out_actual) {
-  FS_PRETTY_TRACE_DEBUG("[FileReadAt] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileReadAt] rights: ", rights());
   if (!(rights() & fuchsia_io::Rights::kReadBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
@@ -97,7 +97,7 @@
 }
 
 zx_status_t StreamFileConnection::WriteInternal(const void* data, size_t len, size_t* out_actual) {
-  FS_PRETTY_TRACE_DEBUG("[FileWrite] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileWrite] rights: ", rights());
   if (!(rights() & fuchsia_io::Rights::kWriteBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
@@ -125,7 +125,7 @@
 
 zx_status_t StreamFileConnection::WriteAtInternal(const void* data, size_t len, size_t offset,
                                                   size_t* out_actual) {
-  FS_PRETTY_TRACE_DEBUG("[FileWriteAt] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileWriteAt] rights: ", rights());
   if (!(rights() & fuchsia_io::Rights::kWriteBytes)) {
     return ZX_ERR_BAD_HANDLE;
   }
@@ -153,7 +153,7 @@
 }
 
 void StreamFileConnection::Seek(SeekRequestView request, SeekCompleter::Sync& completer) {
-  FS_PRETTY_TRACE_DEBUG("[FileSeek] options: ", options());
+  FS_PRETTY_TRACE_DEBUG("[FileSeek] rights: ", rights());
   zx_off_t seek = 0u;
   zx_status_t status =
       stream_.seek(static_cast<zx_stream_seek_origin_t>(request->origin), request->offset, &seek);
diff --git a/src/storage/lib/vfs/cpp/debug.h b/src/storage/lib/vfs/cpp/debug.h
index e93a3f8..8eebac2 100644
--- a/src/storage/lib/vfs/cpp/debug.h
+++ b/src/storage/lib/vfs/cpp/debug.h
@@ -10,6 +10,8 @@
 
 #ifdef FS_TRACE_DEBUG_ENABLED
 #include <fidl/fuchsia.io/cpp/natural_ostream.h>
+#include <fidl/fuchsia.io/cpp/type_conversions.h>
+#include <fidl/fuchsia.io/cpp/wire.h>
 
 #include <cstdlib>
 #include <iostream>
@@ -33,6 +35,8 @@
     stream << val;
   } else if constexpr (std::is_same_v<T, fidl::StringView>) {
     stream << val.get();
+  } else if constexpr (fidl::IsWire<T>()) {
+    stream << fidl::ostream::Formatted(fidl::ToNatural(val));
   } else {
     stream << fidl::ostream::Formatted(val);
   }
diff --git a/src/storage/lib/vfs/cpp/tests/advisory_lock_tests.cc b/src/storage/lib/vfs/cpp/tests/advisory_lock_tests.cc
index 7fa1fca..120325d 100644
--- a/src/storage/lib/vfs/cpp/tests/advisory_lock_tests.cc
+++ b/src/storage/lib/vfs/cpp/tests/advisory_lock_tests.cc
@@ -51,9 +51,7 @@
 
  protected:
   fbl::RefPtr<fs::RemoteDir> GetRemoteDir() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_TRUE(endpoints.is_ok());
-    auto [client, server] = *std::move(endpoints);
+    auto [client, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
     EXPECT_EQ(ZX_OK, fdio_open(kTmpfsPath,
                                static_cast<uint32_t>(fuchsia_io::wire::OpenFlags::kRightReadable |
                                                      fuchsia_io::wire::OpenFlags::kRightExecutable),
diff --git a/src/storage/lib/vfs/cpp/tests/connection_integration_tests.cc b/src/storage/lib/vfs/cpp/tests/connection_integration_tests.cc
index 377332b..2741341 100644
--- a/src/storage/lib/vfs/cpp/tests/connection_integration_tests.cc
+++ b/src/storage/lib/vfs/cpp/tests/connection_integration_tests.cc
@@ -12,7 +12,6 @@
 #include <stdio.h>
 #include <zircon/errors.h>
 
-#include <atomic>
 #include <string_view>
 #include <utility>
 #include <vector>
@@ -77,11 +76,12 @@
   // can lead to races with test teardown where binding the channel happens after the dispatcher has
   // been shutdown, which results in a panic in the FIDL runtime.
   {
-    const fidl::WireResult result = fidl::WireCall(channel)->Sync();
-    EXPECT_OK(result.status());
-    const fit::result response = result.value();
-    EXPECT_TRUE(response.is_error());
-    EXPECT_STATUS(ZX_ERR_NOT_SUPPORTED, response.error_value());
+    const fidl::WireResult result = fidl::WireCall(channel)->GetFlags();
+    zx_status_t status = result.ok() ? zx_status_t{result.value().s} : result.status();
+    if (status != ZX_OK) {
+      ADD_FAILURE("fuchisa.io/Node.GetFlags failed unexpectedly: %s", zx_status_get_string(status));
+      return zx::error(status);
+    }
   }
   return zx::ok(std::move(response.info.value()));
 }
@@ -124,14 +124,13 @@
 
 TEST_F(ConnectionTest, NodeGetSetFlagsOnFile) {
   // Create connection to vfs
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
   // Connect to File
   zx::result fc = fidl::CreateEndpoints<fio::File>();
   ASSERT_OK(fc.status_value());
-  ASSERT_OK(fdio_open_at(root->client.channel().get(), "file",
+  ASSERT_OK(fdio_open_at(root.client.channel().get(), "file",
                          static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable),
                          fc->server.TakeChannel().release()));
 
@@ -156,14 +155,13 @@
 
 TEST_F(ConnectionTest, NodeGetSetFlagsOnDirectory) {
   // Create connection to vfs
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
   // Connect to Directory
   zx::result dc = fidl::CreateEndpoints<fio::Directory>();
   ASSERT_OK(dc.status_value());
-  ASSERT_OK(fdio_open_at(root->client.channel().get(), "dir",
+  ASSERT_OK(fdio_open_at(root.client.channel().get(), "dir",
                          static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable |
                                                fio::wire::OpenFlags::kRightWritable),
                          dc->server.TakeChannel().release()));
@@ -181,9 +179,8 @@
 
 TEST_F(ConnectionTest, PosixFlagDirectoryRightExpansion) {
   // Create connection to VFS with all rights.
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
   // Combinations of POSIX flags to be tested.
   const fio::wire::OpenFlags OPEN_FLAG_COMBINATIONS[]{
@@ -194,7 +191,7 @@
     // Connect to drectory specifying the flag combination we want to test.
     zx::result dc = fidl::CreateEndpoints<fio::Directory>();
     ASSERT_OK(dc.status_value());
-    ASSERT_OK(fdio_open_at(root->client.channel().get(), "dir",
+    ASSERT_OK(fdio_open_at(root.client.channel().get(), "dir",
                            static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable | OPEN_FLAGS),
                            dc->server.TakeChannel().release()));
 
@@ -210,12 +207,11 @@
       EXPECT_TRUE(fio::wire::OpenFlags::kRightExecutable & dir_flags);
 
     // Repeat test, but for file, which should not have any expanded rights.
-    zx::result fc = fidl::CreateEndpoints<fio::File>();
-    ASSERT_OK(fc.status_value());
-    ASSERT_OK(fdio_open_at(root->client.channel().get(), "file",
+    auto fc = fidl::Endpoints<fio::File>::Create();
+    ASSERT_OK(fdio_open_at(root.client.channel().get(), "file",
                            static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable | OPEN_FLAGS),
-                           fc->server.TakeChannel().release()));
-    auto file_get_result = fidl::WireCall(fc->client)->GetFlags();
+                           fc.server.TakeChannel().release()));
+    auto file_get_result = fidl::WireCall(fc.client)->GetFlags();
     EXPECT_OK(file_get_result.status());
     EXPECT_EQ(fio::wire::OpenFlags::kRightReadable, file_get_result->flags);
   }
@@ -223,14 +219,13 @@
 
 TEST_F(ConnectionTest, FileGetSetFlagsOnFile) {
   // Create connection to vfs
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
   // Connect to File
   zx::result fc = fidl::CreateEndpoints<fio::File>();
   ASSERT_OK(fc.status_value());
-  ASSERT_OK(fdio_open_at(root->client.channel().get(), "file",
+  ASSERT_OK(fdio_open_at(root.client.channel().get(), "file",
                          static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable),
                          fc->server.TakeChannel().release()));
 
@@ -257,15 +252,14 @@
 
 TEST_F(ConnectionTest, FileSeekDirectory) {
   // Create connection to vfs
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
   // Interacting with a Directory connection using File protocol methods should fail.
   {
     zx::result dc = fidl::CreateEndpoints<fio::Directory>();
     ASSERT_OK(dc.status_value());
-    ASSERT_OK(fdio_open_at(root->client.channel().get(), "dir",
+    ASSERT_OK(fdio_open_at(root.client.channel().get(), "dir",
                            static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable |
                                                  fio::wire::OpenFlags::kRightWritable),
                            dc->server.TakeChannel().release()));
@@ -280,51 +274,88 @@
 
 TEST_F(ConnectionTest, NegotiateProtocol) {
   // Create connection to vfs
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
   // Connect to polymorphic node as a directory, by passing |kOpenFlagDirectory|.
-  zx::result dc = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_OK(dc.status_value());
-  ASSERT_OK(fidl::WireCall(root->client)
-                ->Open(fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kDescribe |
-                           fio::wire::OpenFlags::kDirectory,
-                       {}, fidl::StringView("file_or_dir"), std::move(dc->server))
-                .status());
-  zx::result<fio::wire::NodeInfoDeprecated> dir_info = GetOnOpenResponse(dc->client);
-  ASSERT_OK(dir_info);
-  ASSERT_TRUE(dir_info->is_directory());
-
-  // Connect to polymorphic node as a file, by passing |kOpenFlagNotDirectory|.
-  zx::result fc = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_OK(fc.status_value());
-  ASSERT_OK(fidl::WireCall(root->client)
-                ->Open(fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kDescribe |
-                           fio::wire::OpenFlags::kNotDirectory,
-                       {}, fidl::StringView("file_or_dir"), std::move(fc->server))
-                .status());
-  zx::result<fio::wire::NodeInfoDeprecated> file_info = GetOnOpenResponse(fc->client);
-  ASSERT_OK(file_info);
-  ASSERT_TRUE(file_info->is_file());
+  {
+    auto [dir_client, dir_server] = fidl::Endpoints<fio::Node>::Create();
+    ASSERT_OK(fidl::WireCall(root.client)
+                  ->Open(fio::OpenFlags::kRightReadable | fio::OpenFlags::kDescribe |
+                             fio::OpenFlags::kDirectory,
+                         {}, fidl::StringView("file_or_dir"), std::move(dir_server))
+                  .status());
+    zx::result<fio::wire::NodeInfoDeprecated> dir_info = GetOnOpenResponse(dir_client);
+    ASSERT_OK(dir_info);
+    ASSERT_TRUE(dir_info->is_directory());
+    // Check that if we clone the connection, we still get the directory protocol.
+    auto [clone_client, clone_server] = fidl::Endpoints<fio::Node>::Create();
+    ASSERT_OK(fidl::WireCall(dir_client)
+                  ->Clone(fio::OpenFlags::kDescribe | fio::OpenFlags::kCloneSameRights,
+                          std::move(clone_server))
+                  .status());
+    zx::result<fio::wire::NodeInfoDeprecated> cloned_info = GetOnOpenResponse(clone_client);
+    ASSERT_OK(cloned_info);
+    ASSERT_TRUE(cloned_info->is_directory());
+  }
+  {
+    // Connect to polymorphic node as a file, by passing |kOpenFlagNotDirectory|.
+    auto [file_client, file_server] = fidl::Endpoints<fio::Node>::Create();
+    ASSERT_OK(fidl::WireCall(root.client)
+                  ->Open(fio::OpenFlags::kRightReadable | fio::OpenFlags::kDescribe |
+                             fio::OpenFlags::kNotDirectory,
+                         {}, fidl::StringView("file_or_dir"), std::move(file_server))
+                  .status());
+    zx::result<fio::wire::NodeInfoDeprecated> file_info = GetOnOpenResponse(file_client);
+    ASSERT_OK(file_info);
+    ASSERT_TRUE(file_info->is_file());
+    // Check that if we clone the connection, we still get the file protocol.
+    auto [clone_client, clone_server] = fidl::Endpoints<fio::Node>::Create();
+    ASSERT_OK(fidl::WireCall(file_client)
+                  ->Clone(fio::OpenFlags::kDescribe | fio::OpenFlags::kCloneSameRights,
+                          std::move(clone_server))
+                  .status());
+    zx::result<fio::wire::NodeInfoDeprecated> cloned_info = GetOnOpenResponse(clone_client);
+    ASSERT_OK(cloned_info);
+    ASSERT_TRUE(cloned_info->is_file());
+  }
+  {
+    // Connect to polymorphic node as a node reference, by passing |kNodeReference|.
+    auto [node_client, node_server] = fidl::Endpoints<fio::Node>::Create();
+    ASSERT_OK(fidl::WireCall(root.client)
+                  ->Open(fio::OpenFlags::kNodeReference | fio::OpenFlags::kDescribe, {},
+                         fidl::StringView("file_or_dir"), std::move(node_server))
+                  .status());
+    zx::result<fio::wire::NodeInfoDeprecated> node_info = GetOnOpenResponse(node_client);
+    ASSERT_OK(node_info);
+    // In io1, node reference connections map to the service representation in the OnOpen event.
+    ASSERT_TRUE(node_info->is_service());
+    // Check that if we clone the connection, we still get the node protocol.
+    auto [clone_client, clone_server] = fidl::Endpoints<fio::Node>::Create();
+    ASSERT_OK(fidl::WireCall(node_client)
+                  ->Clone(fio::OpenFlags::kDescribe | fio::OpenFlags::kCloneSameRights,
+                          std::move(clone_server))
+                  .status());
+    zx::result<fio::wire::NodeInfoDeprecated> cloned_info = GetOnOpenResponse(clone_client);
+    ASSERT_OK(cloned_info);
+    ASSERT_TRUE(cloned_info->is_service());
+  }
 }
 
 TEST_F(ConnectionTest, PrevalidateFlagsOpenFailure) {
   // Create connection to vfs
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
-  // Flag combination which should return INVALID_ARGS (see PrevalidateFlags in connection.cc).
-  constexpr fio::wire::OpenFlags kInvalidFlagCombo =
-      fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kDescribe |
-      fio::wire::OpenFlags::kDirectory | fio::wire::OpenFlags::kNodeReference |
-      fio::wire::OpenFlags::kAppend;
+  // The only invalid flag combination for fuchsia.io/Node.Clone is specifying CLONE_SAME_RIGHTS
+  // with any other rights.
+  constexpr fio::OpenFlags kInvalidFlagCombo =
+      fio::OpenFlags::kCloneSameRights | fio::OpenFlags::kRightReadable | fio::OpenFlags::kDescribe;
   zx::result dc = fidl::CreateEndpoints<fio::Node>();
   ASSERT_OK(dc.status_value());
   // Ensure that invalid flag combination returns INVALID_ARGS.
   ASSERT_OK(
-      fidl::WireCall(root->client)
+      fidl::WireCall(root.client)
           ->Open(kInvalidFlagCombo, {}, fidl::StringView("file_or_dir"), std::move(dc->server))
           .status());
   ASSERT_EQ(GetOnOpenResponse(dc->client).status_value(), ZX_ERR_INVALID_ARGS);
@@ -378,9 +409,8 @@
 
 TEST_F(ConnectionClosingTest, ClosingChannelImpliesClosingNode) {
   // Create connection to vfs.
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
   constexpr int kNumActiveClients = 20;
 
@@ -391,7 +421,7 @@
   for (int i = 0; i < kNumActiveClients; i++) {
     zx::result fc = fidl::CreateEndpoints<fio::Node>();
     ASSERT_OK(fc.status_value());
-    ASSERT_OK(fidl::WireCall(root->client)
+    ASSERT_OK(fidl::WireCall(root.client)
                   ->Open(fio::wire::OpenFlags::kRightReadable, {},
                          fidl::StringView("count_outstanding_open_vnode"), std::move(fc->server))
                   .status());
@@ -411,24 +441,23 @@
 
 TEST_F(ConnectionClosingTest, ClosingNodeLeadsToClosingServerEndChannel) {
   // Create connection to vfs.
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
-  ASSERT_OK(ConnectClient(std::move(root->server)));
+  auto root = fidl::Endpoints<fio::Directory>::Create();
+  ASSERT_OK(ConnectClient(std::move(root.server)));
 
   zx_signals_t observed = ZX_SIGNAL_NONE;
-  ASSERT_STATUS(ZX_ERR_TIMED_OUT,
-                root->client.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite_past(),
-                                                &observed));
+  ASSERT_STATUS(
+      ZX_ERR_TIMED_OUT,
+      root.client.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite_past(), &observed));
   ASSERT_FALSE(observed & ZX_CHANNEL_PEER_CLOSED);
 
   ASSERT_OK(loop().StartThread());
-  auto result = fidl::WireCall(root->client)->Close();
+  auto result = fidl::WireCall(root.client)->Close();
   ASSERT_OK(result.status());
   ASSERT_TRUE(result->is_ok(), "%s", zx_status_get_string(result->error_value()));
 
   observed = ZX_SIGNAL_NONE;
   ASSERT_OK(
-      root->client.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite(), &observed));
+      root.client.channel().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::time::infinite(), &observed));
   ASSERT_TRUE(observed & ZX_CHANNEL_PEER_CLOSED);
 
   loop().Shutdown();
diff --git a/src/storage/lib/vfs/cpp/tests/connection_rights_tests.cc b/src/storage/lib/vfs/cpp/tests/connection_rights_tests.cc
index ff63c50..2b879c6 100644
--- a/src/storage/lib/vfs/cpp/tests/connection_rights_tests.cc
+++ b/src/storage/lib/vfs/cpp/tests/connection_rights_tests.cc
@@ -97,16 +97,15 @@
     auto vnode = fbl::AdoptRef<TestVNode>(new TestVNode());
     for (test_row_t& row : test_data) {
       // Set up a vfs connection with the testcase's connection flags
-      zx::result file = fidl::CreateEndpoints<fio::File>();
-      ASSERT_OK(file.status_value());
+      auto file = fidl::Endpoints<fio::File>::Create();
       fio::wire::OpenFlags flags = row.connection_flags;
-      vfs->Serve(vnode, file->server.TakeChannel(),
-                 fs::VnodeConnectionOptions::FromIoV1Flags(flags));
+      vfs->Serve(vnode, file.server.TakeChannel(),
+                 fs::VnodeConnectionOptions::FromOpen1Flags(flags));
 
       // Call FileGetBuffer on the channel with the testcase's request flags. Check that we get the
       // expected result.
       const fidl::WireResult result =
-          fidl::WireCall(file->client)->GetBackingMemory(row.request_flags);
+          fidl::WireCall(file.client)->GetBackingMemory(row.request_flags);
       EXPECT_TRUE(result.ok(), "%s", result.FormatDescription().c_str());
       const auto& response = result.value();
 
diff --git a/src/storage/lib/vfs/cpp/tests/paging_test.cc b/src/storage/lib/vfs/cpp/tests/paging_test.cc
index 44030ea..a49f334 100644
--- a/src/storage/lib/vfs/cpp/tests/paging_test.cc
+++ b/src/storage/lib/vfs/cpp/tests/paging_test.cc
@@ -270,13 +270,12 @@
     root_->AddEntry(kFileDirtyErrName, file_dirty_err_);
 
     // Connect to the root.
-    zx::result directory_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_OK(directory_endpoints.status_value());
-    vfs_->ServeDirectory(root_, std::move(directory_endpoints->server));
+    auto directory_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    vfs_->ServeDirectory(root_, std::move(directory_endpoints.server));
 
     // Convert to an FD.
     int root_dir_fd = -1;
-    EXPECT_OK(fdio_fd_create(directory_endpoints->client.TakeChannel().release(), &root_dir_fd));
+    EXPECT_OK(fdio_fd_create(directory_endpoints.client.TakeChannel().release(), &root_dir_fd));
 
     return root_dir_fd;
   }
diff --git a/src/storage/lib/vfs/cpp/tests/remote_dir_tests.cc b/src/storage/lib/vfs/cpp/tests/remote_dir_tests.cc
index dba41b7..40e8a14 100644
--- a/src/storage/lib/vfs/cpp/tests/remote_dir_tests.cc
+++ b/src/storage/lib/vfs/cpp/tests/remote_dir_tests.cc
@@ -11,11 +11,10 @@
 namespace {
 
 TEST(RemoteDir, ApiTest) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_EQ(ZX_OK, endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-  const fidl::UnownedClientEnd unowned_client = endpoints->client.borrow();
-  auto dir = fbl::MakeRefCounted<fs::RemoteDir>(std::move(endpoints->client));
+  const fidl::UnownedClientEnd unowned_client = endpoints.client.borrow();
+  auto dir = fbl::MakeRefCounted<fs::RemoteDir>(std::move(endpoints.client));
 
   // get attributes
   fs::VnodeAttributes attr;
diff --git a/src/storage/lib/vfs/cpp/tests/service_tests.cc b/src/storage/lib/vfs/cpp/tests/service_tests.cc
index b5dbe66..1eed85b 100644
--- a/src/storage/lib/vfs/cpp/tests/service_tests.cc
+++ b/src/storage/lib/vfs/cpp/tests/service_tests.cc
@@ -72,17 +72,16 @@
 }
 
 TEST(Service, ServeDirectory) {
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
+  auto root = fidl::Endpoints<fio::Directory>::Create();
 
   // open client
   zx::channel c1, c2;
   EXPECT_OK(zx::channel::create(0u, &c1, &c2));
-  EXPECT_OK(fdio_service_connect_at(root->client.borrow().channel()->get(), "abc", c2.release()));
+  EXPECT_OK(fdio_service_connect_at(root.client.borrow().channel()->get(), "abc", c2.release()));
 
   // Close client. We test the semantic that a pending open is processed even if the client has been
   // closed.
-  root->client.reset();
+  root.client.reset();
 
   // serve
   async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
@@ -95,14 +94,13 @@
   });
   directory->AddEntry("abc", vnode);
 
-  EXPECT_OK(vfs.ServeDirectory(directory, std::move(root->server)));
+  EXPECT_OK(vfs.ServeDirectory(directory, std::move(root.server)));
   EXPECT_EQ(ZX_ERR_BAD_STATE, loop.RunUntilIdle());
 }
 
 TEST(Service, ServiceNodeIsNotDirectory) {
   // Set up the server
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
+  auto root = fidl::Endpoints<fio::Directory>::Create();
 
   async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
   fs::SynchronousVfs vfs(loop.dispatcher());
@@ -115,7 +113,7 @@
     return ZX_OK;
   });
   directory->AddEntry("abc", vnode);
-  ASSERT_OK(vfs.ServeDirectory(directory, std::move(root->server)));
+  ASSERT_OK(vfs.ServeDirectory(directory, std::move(root.server)));
 
   // Call |ValidateOptions| with the directory flag should fail.
   auto result = vnode->ValidateOptions(fs::VnodeConnectionOptions{
@@ -132,7 +130,7 @@
   loop.StartThread();
 
   auto open_result =
-      fidl::WireCall(root->client)
+      fidl::WireCall(root.client)
           ->Open(fio::wire::OpenFlags::kDescribe | fio::wire::OpenFlags::kDirectory |
                      fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightWritable,
                  {}, fidl::StringView("abc"), std::move(abc->server));
@@ -161,8 +159,7 @@
 
 TEST(Service, OpeningServiceWithNodeReferenceFlag) {
   // Set up the server
-  zx::result root = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(root.status_value());
+  auto root = fidl::Endpoints<fio::Directory>::Create();
 
   async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
   fs::SynchronousVfs vfs(loop.dispatcher());
@@ -173,14 +170,14 @@
     return ZX_OK;
   });
   directory->AddEntry("abc", vnode);
-  ASSERT_OK(vfs.ServeDirectory(directory, std::move(root->server)));
+  ASSERT_OK(vfs.ServeDirectory(directory, std::move(root.server)));
 
   zx::result abc = fidl::CreateEndpoints<fio::Node>();
   ASSERT_OK(abc.status_value());
 
   loop.StartThread();
 
-  ASSERT_OK(fidl::WireCall(root->client)
+  ASSERT_OK(fidl::WireCall(root.client)
                 ->Open(fio::wire::OpenFlags::kNodeReference, {}, fidl::StringView("abc"),
                        std::move(abc->server))
                 .status());
diff --git a/src/storage/lib/vfs/cpp/tests/vfs_types_tests.cc b/src/storage/lib/vfs/cpp/tests/vfs_types_tests.cc
index 0d885ce..56a1a32 100644
--- a/src/storage/lib/vfs/cpp/tests/vfs_types_tests.cc
+++ b/src/storage/lib/vfs/cpp/tests/vfs_types_tests.cc
@@ -36,9 +36,9 @@
 
   TestDirectory vnode;
   EXPECT_RESULT_OK(vnode.ValidateOptions(
-      fs::VnodeConnectionOptions::FromIoV1Flags(fio::wire::OpenFlags::kDirectory)));
+      fs::VnodeConnectionOptions::FromOpen1Flags(fio::wire::OpenFlags::kDirectory)));
   EXPECT_RESULT_ERROR(ZX_ERR_NOT_FILE,
-                      vnode.ValidateOptions(fs::VnodeConnectionOptions::FromIoV1Flags(
+                      vnode.ValidateOptions(fs::VnodeConnectionOptions::FromOpen1Flags(
                           fio::wire::OpenFlags::kNotDirectory)));
 }
 
@@ -52,10 +52,10 @@
 
   TestConnector vnode;
   EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR,
-                      vnode.ValidateOptions(fs::VnodeConnectionOptions::FromIoV1Flags(
+                      vnode.ValidateOptions(fs::VnodeConnectionOptions::FromOpen1Flags(
                           fio::wire::OpenFlags::kDirectory)));
   EXPECT_RESULT_OK(vnode.ValidateOptions(
-      fs::VnodeConnectionOptions::FromIoV1Flags(fio::wire::OpenFlags::kNotDirectory)));
+      fs::VnodeConnectionOptions::FromOpen1Flags(fio::wire::OpenFlags::kNotDirectory)));
 }
 
 TEST(VnodeConnectionOptions, ValidateOptionsForFile) {
@@ -68,10 +68,10 @@
 
   TestFile vnode;
   EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR,
-                      vnode.ValidateOptions(fs::VnodeConnectionOptions::FromIoV1Flags(
+                      vnode.ValidateOptions(fs::VnodeConnectionOptions::FromOpen1Flags(
                           fio::wire::OpenFlags::kDirectory)));
   EXPECT_RESULT_OK(vnode.ValidateOptions(
-      fs::VnodeConnectionOptions::FromIoV1Flags(fio::wire::OpenFlags::kNotDirectory)));
+      fs::VnodeConnectionOptions::FromOpen1Flags(fio::wire::OpenFlags::kNotDirectory)));
 }
 
 }  // namespace
diff --git a/src/storage/lib/vfs/cpp/tests/watcher_test.cc b/src/storage/lib/vfs/cpp/tests/watcher_test.cc
index 863e6dc..4014ef8 100644
--- a/src/storage/lib/vfs/cpp/tests/watcher_test.cc
+++ b/src/storage/lib/vfs/cpp/tests/watcher_test.cc
@@ -33,9 +33,7 @@
   fbl::RefPtr<fs::PseudoDir>& root() { return root_; }
 
   fidl::ClientEnd<fio::DirectoryWatcher> WatchRootDir(fio::WatchMask mask) {
-    auto endpoints = fidl::CreateEndpoints<fio::DirectoryWatcher>();
-    EXPECT_OK(endpoints);
-    auto [client, server] = *std::move(endpoints);
+    auto [client, server] = fidl::Endpoints<fio::DirectoryWatcher>::Create();
     EXPECT_OK(root_->WatchDir(&vfs_, mask, 0, std::move(server)));
     return std::move(client);
   }
diff --git a/src/storage/lib/vfs/cpp/vfs_types.cc b/src/storage/lib/vfs/cpp/vfs_types.cc
index 197b438..1b874c9 100644
--- a/src/storage/lib/vfs/cpp/vfs_types.cc
+++ b/src/storage/lib/vfs/cpp/vfs_types.cc
@@ -14,24 +14,24 @@
 
 namespace fs {
 
-VnodeConnectionOptions VnodeConnectionOptions::FromIoV1Flags(fio::OpenFlags fidl_flags) {
+VnodeConnectionOptions VnodeConnectionOptions::FromOpen1Flags(fio::OpenFlags open1_flags) {
   VnodeConnectionOptions options;
   // Filter out io1 OpenFlags.RIGHT_* flags, translated to io2 Rights below.
-  options.flags = fidl_flags & ~kAllIo1Rights;
+  options.flags = open1_flags & ~kAllIo1Rights;
 
   // Using Open1 requires GET_ATTRIBUTES as this is not expressible via |fio::OpenFlags|.
   // TODO(https://fxbug.dev/324080764): Restrict GET_ATTRIBUTES.
   options.rights = fio::Rights::kGetAttributes;
 
-  // Approximate a set of io2 Rights corresponding to what is expected by |fidl_flags|.
+  // Approximate a set of io2 Rights corresponding to what is expected by |open1_flags|.
   if (!(options.flags & fio::OpenFlags::kNodeReference)) {
-    if (fidl_flags & fio::OpenFlags::kRightReadable) {
+    if (open1_flags & fio::OpenFlags::kRightReadable) {
       options.rights |= fio::kRStarDir;
     }
-    if (fidl_flags & fio::OpenFlags::kRightWritable) {
+    if (open1_flags & fio::OpenFlags::kRightWritable) {
       options.rights |= fio::kWStarDir;
     }
-    if (fidl_flags & fio::OpenFlags::kRightExecutable) {
+    if (open1_flags & fio::OpenFlags::kRightExecutable) {
       options.rights |= fio::kXStarDir;
     }
   }
@@ -39,6 +39,14 @@
   return options;
 }
 
+VnodeConnectionOptions VnodeConnectionOptions::FromCloneFlags(fio::OpenFlags clone_flags) {
+  constexpr fio::OpenFlags kValidCloneFlags = kAllIo1Rights | fio::OpenFlags::kAppend |
+                                              fio::OpenFlags::kDescribe |
+                                              fio::OpenFlags::kCloneSameRights;
+  // Any flags not present in |kValidCloneFlags| should be ignored.
+  return FromOpen1Flags(clone_flags & kValidCloneFlags);
+}
+
 fio::OpenFlags VnodeConnectionOptions::ToIoV1Flags() const {
   return flags | RightsToOpenFlags(rights);
 }
@@ -68,4 +76,31 @@
                                    .modification_time = modification_time};
 }
 
+namespace internal {
+
+bool ValidateCloneFlags(fio::OpenFlags flags) {
+  // If CLONE_SAME_RIGHTS is specified, the client cannot request any specific rights.
+  if (flags & fio::OpenFlags::kCloneSameRights) {
+    return !(flags & kAllIo1Rights);
+  }
+  // All other flags are ignored.
+  return true;
+}
+
+bool ValidateOpenFlags(fio::OpenFlags flags) {
+  if ((flags & fio::OpenFlags::kNodeReference) &&
+      (flags - fio::kOpenFlagsAllowedWithNodeReference)) {
+    return false;
+  }
+  if ((flags & fio::OpenFlags::kNotDirectory) && (flags & fio::OpenFlags::kDirectory)) {
+    return false;
+  }
+  if (flags & fio::OpenFlags::kCloneSameRights) {
+    return false;
+  }
+  return true;
+}
+
+}  // namespace internal
+
 }  // namespace fs
diff --git a/src/storage/lib/vfs/cpp/vfs_types.h b/src/storage/lib/vfs/cpp/vfs_types.h
index 3f63b08..0a2a2b3 100644
--- a/src/storage/lib/vfs/cpp/vfs_types.h
+++ b/src/storage/lib/vfs/cpp/vfs_types.h
@@ -164,9 +164,13 @@
   }
 
 #ifdef __Fuchsia__
-  // Converts from io1 OpenFlags flags to |VnodeConnectionOptions|. Note that in io1, certain
-  // operations were unprivileged, so they may be implicitly added to the resulting `rights`.
-  static VnodeConnectionOptions FromIoV1Flags(fuchsia_io::OpenFlags fidl_flags);
+  // Converts from fuchsia.io/Directory.Open1 flags to |VnodeConnectionOptions|. Note that in io1,
+  // certain operations were unprivileged so they may be implicitly added to the resulting `rights`.
+  static VnodeConnectionOptions FromOpen1Flags(fuchsia_io::OpenFlags open1_flags);
+
+  // Converts from fuchsia.io/Directory.Clone flags to |VnodeConnectionOptions|. Note that in io1,
+  // certain operations were unprivileged so they may be implicitly added to the resulting `rights`.
+  static VnodeConnectionOptions FromCloneFlags(fuchsia_io::OpenFlags clone_flags);
 
   // Converts from |VnodeConnectionOptions| to fuchsia.io flags.
   fuchsia_io::OpenFlags ToIoV1Flags() const;
@@ -239,6 +243,13 @@
   std::optional<uint64_t> modification_time_ = {};
 };
 
+namespace internal {
+
+bool ValidateCloneFlags(fuchsia_io::OpenFlags flags);
+bool ValidateOpenFlags(fuchsia_io::OpenFlags flags);
+
+}  // namespace internal
+
 }  // namespace fs
 
 #endif  // SRC_STORAGE_LIB_VFS_CPP_VFS_TYPES_H_
diff --git a/src/storage/lib/vfs/rust/src/common.rs b/src/storage/lib/vfs/rust/src/common.rs
index 59f5227..c3fec54 100644
--- a/src/storage/lib/vfs/rust/src/common.rs
+++ b/src/storage/lib/vfs/rust/src/common.rs
@@ -246,7 +246,7 @@
             fio::NodeAttributes2 {
                 mutable_attributes: fio::MutableNodeAttributes {
                     $($mut_a: if $requested.contains(attribute_query!($mut_a)) {
-                        Some($mut_v)
+                        Option::from($mut_v)
                     } else {
                         None
                     }),*,
diff --git a/src/storage/memfs/test/fidl-tests.cc b/src/storage/memfs/test/fidl-tests.cc
index bebb6a9..54b4c17 100644
--- a/src/storage/memfs/test/fidl-tests.cc
+++ b/src/storage/memfs/test/fidl-tests.cc
@@ -52,12 +52,11 @@
   ASSERT_EQ(write(fd.get(), data, datalen), datalen);
   fd.reset();
 
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_OK(endpoints.status_value());
-  ASSERT_OK(fdio_service_connect("/fidltmp/file-a", endpoints->server.TakeChannel().release()));
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
+  ASSERT_OK(fdio_service_connect("/fidltmp/file-a", endpoints.server.TakeChannel().release()));
 
   {
-    const fidl::WireResult result = fidl::WireCall(endpoints->client)->Query();
+    const fidl::WireResult result = fidl::WireCall(endpoints.client)->Query();
     ASSERT_OK(result.status());
     const fidl::WireResponse response = result.value();
     const cpp20::span data = response.protocol.get();
@@ -65,11 +64,11 @@
     ASSERT_EQ(protocol, fio::wire::kFileProtocolName);
   }
   const fidl::WireResult describe_result =
-      fidl::WireCall(fidl::UnownedClientEnd<fio::File>(endpoints->client.borrow().channel()))
+      fidl::WireCall(fidl::UnownedClientEnd<fio::File>(endpoints.client.borrow().channel()))
           ->Describe();
   ASSERT_OK(describe_result.status());
   ASSERT_FALSE(describe_result.value().has_observer());
-  endpoints->client.TakeChannel().reset();
+  endpoints.client.TakeChannel().reset();
 
   std::promise<zx_status_t> promise;
   memfs.value()->Shutdown([&promise](zx_status_t status) { promise.set_value(status); });
@@ -93,17 +92,16 @@
   ASSERT_GE(fd.get(), 0);
   fd.reset();
 
-  zx::result endpoints = fidl::CreateEndpoints<fio::Node>();
-  ASSERT_OK(endpoints.status_value());
+  auto endpoints = fidl::Endpoints<fio::Node>::Create();
   ASSERT_OK(fdio_open("/fidltmp-ro/file-ro",
                       static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable),
-                      endpoints->server.TakeChannel().release()));
+                      endpoints.server.TakeChannel().release()));
 
-  auto result = fidl::WireCall(endpoints->client)->GetFlags();
+  auto result = fidl::WireCall(endpoints.client)->GetFlags();
   ASSERT_OK(result.status());
   ASSERT_OK(result->s);
   ASSERT_EQ(result->flags, fio::wire::OpenFlags::kRightReadable);
-  endpoints->client.TakeChannel().reset();
+  endpoints.client.TakeChannel().reset();
 
   std::promise<zx_status_t> promise;
   memfs.value()->Shutdown([&promise](zx_status_t status) { promise.set_value(status); });
diff --git a/src/storage/memfs/test/vmofile-tests.cc b/src/storage/memfs/test/vmofile-tests.cc
index 06e1948..0ea2f3c 100644
--- a/src/storage/memfs/test/vmofile-tests.cc
+++ b/src/storage/memfs/test/vmofile-tests.cc
@@ -66,8 +66,7 @@
   ASSERT_OK(loop.StartThread());
   async_dispatcher_t* dispatcher = loop.dispatcher();
 
-  zx::result directory_endpoints = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(directory_endpoints.status_value());
+  auto directory_endpoints = fidl::Endpoints<fio::Directory>::Create();
 
   zx::result result = memfs::Memfs::Create(dispatcher, "<tmp>");
   ASSERT_OK(result);
@@ -77,11 +76,11 @@
   ASSERT_OK(zx::vmo::create(64, 0, &read_only_vmo));
   ASSERT_OK(read_only_vmo.write("hello, world!", 0, 13));
   ASSERT_OK(vfs->CreateFromVmo(root.get(), "greeting", read_only_vmo.get(), 0, 13));
-  ASSERT_OK(vfs->ServeDirectory(std::move(root), std::move(directory_endpoints->server)));
+  ASSERT_OK(vfs->ServeDirectory(std::move(root), std::move(directory_endpoints.server)));
 
   zx::result node_endpoints = fidl::CreateEndpoints<fio::Node>();
   ASSERT_OK(node_endpoints.status_value());
-  auto open_result = fidl::WireCall(directory_endpoints->client)
+  auto open_result = fidl::WireCall(directory_endpoints.client)
                          ->Open(fio::wire::OpenFlags::kRightReadable, {},
                                 fidl::StringView("greeting"), std::move(node_endpoints->server));
   ASSERT_OK(open_result.status());
@@ -159,8 +158,7 @@
   ASSERT_OK(loop.StartThread());
   async_dispatcher_t* dispatcher = loop.dispatcher();
 
-  zx::result directory_endpoints = fidl::CreateEndpoints<fio::Directory>();
-  ASSERT_OK(directory_endpoints.status_value());
+  auto directory_endpoints = fidl::Endpoints<fio::Directory>::Create();
 
   zx::result result = memfs::Memfs::Create(dispatcher, "<tmp>");
   ASSERT_OK(result);
@@ -179,13 +177,13 @@
 
     ASSERT_OK(read_exec_vmo.replace_as_executable(response.resource, &read_exec_vmo));
     ASSERT_OK(vfs->CreateFromVmo(root.get(), "read_exec", read_exec_vmo.get(), 0, 13));
-    ASSERT_OK(vfs->ServeDirectory(std::move(root), std::move(directory_endpoints->server)));
+    ASSERT_OK(vfs->ServeDirectory(std::move(root), std::move(directory_endpoints.server)));
   }
 
   zx::result node_endpoints = fidl::CreateEndpoints<fio::Node>();
   ASSERT_OK(node_endpoints.status_value());
   auto open_result =
-      fidl::WireCall(directory_endpoints->client)
+      fidl::WireCall(directory_endpoints.client)
           ->Open(fio::wire::OpenFlags::kRightReadable | fio::wire::OpenFlags::kRightExecutable, {},
                  fidl::StringView("read_exec"), std::move(node_endpoints->server));
   ASSERT_OK(open_result.status());
diff --git a/src/storage/minfs/bin/minfs_test.cc b/src/storage/minfs/bin/minfs_test.cc
index 5830c40..0240be1 100644
--- a/src/storage/minfs/bin/minfs_test.cc
+++ b/src/storage/minfs/bin/minfs_test.cc
@@ -48,14 +48,13 @@
     ASSERT_FALSE(create_res->is_error())
         << "create error: " << static_cast<uint32_t>(create_res->error_value());
 
-    auto exposed_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(exposed_endpoints.status_value(), ZX_OK);
+    auto exposed_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto open_exposed_res =
-        realm_->OpenExposedDir(kMinfsChildRef, std::move(exposed_endpoints->server));
+        realm_->OpenExposedDir(kMinfsChildRef, std::move(exposed_endpoints.server));
     ASSERT_EQ(open_exposed_res.status(), ZX_OK);
     ASSERT_FALSE(open_exposed_res->is_error())
         << "open exposed dir error: " << static_cast<uint32_t>(open_exposed_res->error_value());
-    exposed_dir_ = std::move(exposed_endpoints->client);
+    exposed_dir_ = std::move(exposed_endpoints.client);
 
     auto startup_client_end =
         component::ConnectAt<fuchsia_fs_startup::Startup>(exposed_dir_.borrow());
diff --git a/src/storage/minfs/test/integration/minfs_component_runner_test.cc b/src/storage/minfs/test/integration/minfs_component_runner_test.cc
index 03683117..f5465fa 100644
--- a/src/storage/minfs/test/integration/minfs_component_runner_test.cc
+++ b/src/storage/minfs/test/integration/minfs_component_runner_test.cc
@@ -32,10 +32,9 @@
     bcache_ = *std::move(bcache);
     ASSERT_EQ(Mkfs(bcache_.get()).status_value(), ZX_OK);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(endpoints.status_value(), ZX_OK);
-    root_ = std::move(endpoints->client);
-    server_end_ = std::move(endpoints->server);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    root_ = std::move(endpoints.client);
+    server_end_ = std::move(endpoints.server);
   }
 
   void StartServe() {
@@ -46,24 +45,22 @@
   }
 
   fidl::ClientEnd<fuchsia_io::Directory> GetSvcDir() const {
-    auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_EQ(svc_endpoints.status_value(), ZX_OK);
+    auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto status = fidl::WireCall(root_)->Open(
         fuchsia_io::wire::OpenFlags::kDirectory, {}, "svc",
-        fidl::ServerEnd<fuchsia_io::Node>(svc_endpoints->server.TakeChannel()));
+        fidl::ServerEnd<fuchsia_io::Node>(svc_endpoints.server.TakeChannel()));
     EXPECT_EQ(status.status(), ZX_OK);
-    return std::move(svc_endpoints->client);
+    return std::move(svc_endpoints.client);
   }
 
   fidl::ClientEnd<fuchsia_io::Directory> GetRootDir() const {
-    auto root_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_EQ(root_endpoints.status_value(), ZX_OK);
+    auto root_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
     auto status = fidl::WireCall(root_)->Open(
         fuchsia_io::wire::OpenFlags::kRightReadable | fuchsia_io::wire::OpenFlags::kRightWritable |
             fuchsia_io::wire::OpenFlags::kDirectory,
-        {}, "root", fidl::ServerEnd<fuchsia_io::Node>(root_endpoints->server.TakeChannel()));
+        {}, "root", fidl::ServerEnd<fuchsia_io::Node>(root_endpoints.server.TakeChannel()));
     EXPECT_EQ(status.status(), ZX_OK);
-    return std::move(root_endpoints->client);
+    return std::move(root_endpoints.client);
   }
 
  protected:
@@ -142,9 +139,8 @@
 }
 
 TEST_F(MinfsComponentRunnerTest, LifecycleChannelShutsDownRunner) {
-  auto lifecycle_endpoints = fidl::CreateEndpoints<fuchsia_process_lifecycle::Lifecycle>();
-  ASSERT_EQ(lifecycle_endpoints.status_value(), ZX_OK);
-  auto lifecycle = std::move(lifecycle_endpoints->client);
+  auto lifecycle_endpoints = fidl::Endpoints<fuchsia_process_lifecycle::Lifecycle>::Create();
+  auto lifecycle = std::move(lifecycle_endpoints.client);
 
   runner_ = std::make_unique<ComponentRunner>(loop_.dispatcher());
   std::atomic<bool> unmount_callback_called = false;
@@ -154,7 +150,7 @@
     unmount_callback_called = true;
   });
   zx::result status =
-      runner_->ServeRoot(std::move(server_end_), std::move(lifecycle_endpoints->server));
+      runner_->ServeRoot(std::move(server_end_), std::move(lifecycle_endpoints.server));
   ASSERT_EQ(status.status_value(), ZX_OK);
   ASSERT_EQ(loop_.RunUntilIdle(), ZX_OK);
   ASSERT_FALSE(unmount_callback_called);
diff --git a/src/storage/minfs/test/integration/mount_test.cc b/src/storage/minfs/test/integration/mount_test.cc
index b1a8031..aab60a0 100644
--- a/src/storage/minfs/test/integration/mount_test.cc
+++ b/src/storage/minfs/test/integration/mount_test.cc
@@ -60,10 +60,9 @@
     ASSERT_FALSE(bcache_read_only);
     bcache_ = std::move(bcache);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(endpoints.status_value(), ZX_OK);
-    root_client_end_ = std::move(endpoints->client);
-    root_server_end_ = std::move(endpoints->server);
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    root_client_end_ = std::move(endpoints.client);
+    root_server_end_ = std::move(endpoints.server);
     ASSERT_EQ(loop_.StartThread("minfs test dispatcher"), ZX_OK);
   }
 
@@ -105,9 +104,8 @@
   fidl::UnownedClientEnd<fuchsia_io::Directory> root_client_end() { return root_client_end_; }
 
   fidl::ClientEnd<fuchsia_io::Directory> clone_root_client_end() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    EXPECT_EQ(endpoints.status_value(), ZX_OK);
-    auto [clone_root_client_end, clone_root_server_end] = std::move(*endpoints);
+    auto [clone_root_client_end, clone_root_server_end] =
+        fidl::Endpoints<fuchsia_io::Directory>::Create();
     ZX_ASSERT(fidl::WireCall(root_client_end())
                   ->Clone(fio::wire::OpenFlags::kCloneSameRights,
                           fidl::ServerEnd<fuchsia_io::Node>(clone_root_server_end.TakeChannel()))
diff --git a/src/storage/stress-tests/blobfs/blob_actor.rs b/src/storage/stress-tests/blobfs/blob_actor.rs
index d159389..a330673 100644
--- a/src/storage/stress-tests/blobfs/blob_actor.rs
+++ b/src/storage/stress-tests/blobfs/blob_actor.rs
@@ -5,7 +5,6 @@
 use {
     async_trait::async_trait,
     fidl_fuchsia_io as fio,
-    fuchsia_merkle::MerkleTree,
     fuchsia_zircon::Status,
     storage_stress_test_utils::{data::FileFactory, io::Directory},
     stress_test::actor::{Actor, ActorError},
@@ -29,7 +28,7 @@
     async fn create_blob(&mut self) -> Result<(), Status> {
         // Create the root hash for the blob
         let data_bytes = self.factory.generate_bytes();
-        let tree = MerkleTree::from_reader(&data_bytes[..]).unwrap();
+        let tree = fuchsia_merkle::from_slice(&data_bytes);
         let merkle_root_hash = tree.root().to_string();
 
         // Write the file to disk
diff --git a/src/sys/bin/psutils/kstats.c b/src/sys/bin/psutils/kstats.c
index 5846477..03b4412 100644
--- a/src/sys/bin/psutils/kstats.c
+++ b/src/sys/bin/psutils/kstats.c
@@ -24,6 +24,8 @@
 
 #include "resources.h"
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 // TODO: dynamically compute this based on what it returns
 #define MAX_CPUS 32
 
@@ -261,7 +263,7 @@
       stats.other_bytes,
   };
   char line[128] = {};
-  for (unsigned int i = 0; i < countof(fields); i++) {
+  for (unsigned int i = 0; i < ARRAY_SIZE(fields); i++) {
     const char unit = 'M';
     char buf[MAX_FORMAT_SIZE_LEN];
     format_size_fixed(buf, sizeof(buf), fields[i], unit);
diff --git a/src/sys/component_manager/BUILD.gn b/src/sys/component_manager/BUILD.gn
index e54ed954..2eabdf7 100644
--- a/src/sys/component_manager/BUILD.gn
+++ b/src/sys/component_manager/BUILD.gn
@@ -46,6 +46,7 @@
     "//sdk/fidl/fuchsia.sys2:fuchsia.sys2_rust",
     "//sdk/fidl/fuchsia.time:fuchsia.time_rust",
     "//src/lib/async-utils",
+    "//src/lib/diagnostics/inspect/contrib/rust",
     "//src/lib/diagnostics/inspect/runtime/rust:unchecked_includes",
     "//src/lib/diagnostics/inspect/rust",
     "//src/lib/diagnostics/log/rust",
@@ -65,6 +66,7 @@
     "//src/lib/zircon/rust:fuchsia-zircon",
     "//src/lib/zircon/rust:fuchsia-zircon-status",
     "//src/storage/lib/vfs/rust:vfs",
+    "//src/sys/component_manager/lib/builtins",
     "//src/sys/component_manager/lib/logger",
     "//src/sys/component_manager/lib/sandbox",
     "//src/sys/component_manager/lib/serve_processargs",
@@ -130,7 +132,6 @@
     "//third_party/rust_crates:test-case",
     "//third_party/rust_crates:thiserror",
     "//third_party/rust_crates:tracing",
-    "//third_party/rust_crates:zerocopy",
   ]
 
   sources = [
@@ -138,45 +139,22 @@
     "src/bedrock/program/component_controller.rs",
     "src/bedrock/program/mod.rs",
     "src/bootfs.rs",
-    "src/builtin/arguments.rs",
     "src/builtin/builtin_resolver.rs",
     "src/builtin/builtin_runner.rs",
-    "src/builtin/capability.rs",
-    "src/builtin/cpu_resource.rs",
     "src/builtin/crash_introspect.rs",
-    "src/builtin/debug_resource.rs",
-    "src/builtin/energy_info_resource.rs",
-    "src/builtin/factory_items.rs",
-    "src/builtin/framebuffer_resource.rs",
     "src/builtin/fuchsia_boot_resolver.rs",
-    "src/builtin/hypervisor_resource.rs",
-    "src/builtin/info_resource.rs",
-    "src/builtin/iommu_resource.rs",
-    "src/builtin/ioport_resource.rs",
-    "src/builtin/irq_resource.rs",
-    "src/builtin/items.rs",
-    "src/builtin/kernel_stats.rs",
     "src/builtin/log.rs",
-    "src/builtin/mexec_resource.rs",
-    "src/builtin/mmio_resource.rs",
     "src/builtin/mod.rs",
-    "src/builtin/msi_resource.rs",
-    "src/builtin/power_resource.rs",
-    "src/builtin/profile_resource.rs",
     "src/builtin/realm_builder.rs",
-    "src/builtin/root_job.rs",
-    "src/builtin/root_resource.rs",
     "src/builtin/runner.rs",
-    "src/builtin/smc_resource.rs",
     "src/builtin/svc_stash_provider.rs",
     "src/builtin/system_controller.rs",
     "src/builtin/time.rs",
-    "src/builtin/vmex_resource.rs",
     "src/builtin_environment.rs",
     "src/capability.rs",
     "src/constants.rs",
+    "src/diagnostics/lifecycle.rs",
     "src/diagnostics/mod.rs",
-    "src/diagnostics/startup.rs",
     "src/diagnostics/task_metrics/component_stats.rs",
     "src/diagnostics/task_metrics/component_tree_stats.rs",
     "src/diagnostics/task_metrics/constants.rs",
@@ -236,6 +214,7 @@
     "src/model/routing/open.rs",
     "src/model/routing/providers.rs",
     "src/model/routing/router.rs",
+    "src/model/routing/router_ext.rs",
     "src/model/routing/service.rs",
     "src/model/routing_fns.rs",
     "src/model/start.rs",
diff --git a/src/sys/component_manager/configs/bootfs_config.json5 b/src/sys/component_manager/configs/bootfs_config.json5
index b2a287b..211c6e7 100644
--- a/src/sys/component_manager/configs/bootfs_config.json5
+++ b/src/sys/component_manager/configs/bootfs_config.json5
@@ -22,6 +22,7 @@
                 "fuchsia.boot.SvcStashProvider",
                 "fuchsia.kernel.CpuResource",
                 "fuchsia.kernel.DebugResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.boot.Items",
                 "fuchsia.boot.FactoryItems",
                 "fuchsia.kernel.FramebufferResource",
diff --git a/src/sys/component_manager/lib/BUILD.gn b/src/sys/component_manager/lib/BUILD.gn
index 2a4b758..1e2d6c4 100644
--- a/src/sys/component_manager/lib/BUILD.gn
+++ b/src/sys/component_manager/lib/BUILD.gn
@@ -4,7 +4,10 @@
 
 group("non_hermetic_tests") {
   testonly = true
-  deps = [ "logger:tests" ]
+  deps = [
+    "builtins:tests",
+    "logger:tests",
+  ]
 }
 
 group("hermetic_tests") {
diff --git a/src/sys/component_manager/lib/builtins/BUILD.gn b/src/sys/component_manager/lib/builtins/BUILD.gn
new file mode 100644
index 0000000..19ce940
--- /dev/null
+++ b/src/sys/component_manager/lib/builtins/BUILD.gn
@@ -0,0 +1,79 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/components.gni")
+import("//build/rust/rustc_library.gni")
+
+rustc_library("builtins") {
+  edition = "2021"
+  with_unit_tests = true
+
+  deps = [
+    "//sdk/fidl/fuchsia.boot:fuchsia.boot_rust",
+    "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
+    "//sdk/fidl/fuchsia.kernel:fuchsia.kernel_rust",
+    "//src/lib/fidl/rust/fidl",
+    "//src/lib/fuchsia-async",
+    "//src/lib/fuchsia-fs",
+    "//src/lib/fuchsia-fs",
+    "//src/lib/fuchsia-runtime",
+    "//src/lib/zircon/rust:fuchsia-zircon",
+    "//src/lib/zircon/rust:fuchsia-zircon-status",
+    "//src/sys/lib/cm_types",
+    "//src/sys/lib/fuchsia-zbi",
+    "//third_party/rust_crates:anyhow",
+    "//third_party/rust_crates:futures",
+    "//third_party/rust_crates:lazy_static",
+    "//third_party/rust_crates:tracing",
+  ]
+
+  test_deps = [
+    "//src/lib/fidl/rust/fidl",
+    "//src/lib/fuchsia",
+    "//src/lib/fuchsia-component",
+    "//third_party/rust_crates:anyhow",
+    "//third_party/rust_crates:assert_matches",
+    "//third_party/rust_crates:tempfile",
+    "//third_party/rust_crates:zerocopy",
+  ]
+
+  sources = [
+    "src/arguments.rs",
+    "src/cpu_resource.rs",
+    "src/debug_resource.rs",
+    "src/debuglog_resource.rs",
+    "src/energy_info_resource.rs",
+    "src/factory_items.rs",
+    "src/framebuffer_resource.rs",
+    "src/hypervisor_resource.rs",
+    "src/info_resource.rs",
+    "src/iommu_resource.rs",
+    "src/ioport_resource.rs",
+    "src/irq_resource.rs",
+    "src/items.rs",
+    "src/kernel_stats.rs",
+    "src/lib.rs",
+    "src/mexec_resource.rs",
+    "src/mmio_resource.rs",
+    "src/msi_resource.rs",
+    "src/power_resource.rs",
+    "src/profile_resource.rs",
+    "src/root_job.rs",
+    "src/root_resource.rs",
+    "src/smc_resource.rs",
+    "src/vmex_resource.rs",
+  ]
+}
+
+fuchsia_test_component("test_component") {
+  deps = [ ":builtins_test" ]
+  component_name = "builtins_tests"
+  manifest = "meta/test.cml"
+  test_type = "system"
+}
+
+fuchsia_test_package("tests") {
+  package_name = "builtins_tests"
+  test_components = [ ":test_component" ]
+}
diff --git a/src/sys/component_manager/lib/builtins/meta/test.cml b/src/sys/component_manager/lib/builtins/meta/test.cml
new file mode 100644
index 0000000..7a11576
--- /dev/null
+++ b/src/sys/component_manager/lib/builtins/meta/test.cml
@@ -0,0 +1,39 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "//src/sys/test_runners/rust/create_raw_processes.shard.cml",
+        "//src/sys/test_runners/tmp_storage.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/builtins_lib_test",
+    },
+    use: [
+        {
+            protocol: [
+                "fuchsia.boot.RootResource",
+                "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
+                "fuchsia.kernel.DebugResource",
+                "fuchsia.kernel.EnergyInfoResource",
+                "fuchsia.kernel.FramebufferResource",
+                "fuchsia.kernel.HypervisorResource",
+                "fuchsia.kernel.InfoResource",
+                "fuchsia.kernel.IommuResource",
+                "fuchsia.kernel.IoportResource",
+                "fuchsia.kernel.IrqResource",
+                "fuchsia.kernel.MexecResource",
+                "fuchsia.kernel.MmioResource",
+                "fuchsia.kernel.MsiResource",
+                "fuchsia.kernel.PowerResource",
+                "fuchsia.kernel.ProfileResource",
+                "fuchsia.kernel.RootJob",
+                "fuchsia.kernel.SmcResource",
+                "fuchsia.kernel.VmexResource",
+                "fuchsia.process.Launcher",
+            ],
+        },
+    ],
+}
diff --git a/src/sys/component_manager/src/builtin/arguments.rs b/src/sys/component_manager/lib/builtins/src/arguments.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/arguments.rs
rename to src/sys/component_manager/lib/builtins/src/arguments.rs
diff --git a/src/sys/component_manager/src/builtin/cpu_resource.rs b/src/sys/component_manager/lib/builtins/src/cpu_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/cpu_resource.rs
rename to src/sys/component_manager/lib/builtins/src/cpu_resource.rs
diff --git a/src/sys/component_manager/src/builtin/debug_resource.rs b/src/sys/component_manager/lib/builtins/src/debug_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/debug_resource.rs
rename to src/sys/component_manager/lib/builtins/src/debug_resource.rs
diff --git a/src/sys/component_manager/lib/builtins/src/debuglog_resource.rs b/src/sys/component_manager/lib/builtins/src/debuglog_resource.rs
new file mode 100644
index 0000000..581ce89
--- /dev/null
+++ b/src/sys/component_manager/lib/builtins/src/debuglog_resource.rs
@@ -0,0 +1,82 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {
+    anyhow::{format_err, Error},
+    fidl_fuchsia_kernel as fkernel,
+    fuchsia_zircon::{self as zx, HandleBased, Resource},
+    futures::prelude::*,
+    std::sync::Arc,
+};
+
+/// An implementation of fuchsia.kernel.DebuglogResource protocol.
+pub struct DebuglogResource {
+    resource: Resource,
+}
+
+impl DebuglogResource {
+    /// `resource` must be the Debuglog resource.
+    pub fn new(resource: Resource) -> Result<Arc<Self>, Error> {
+        let resource_info = resource.info()?;
+        if resource_info.kind != zx::sys::ZX_RSRC_KIND_SYSTEM
+            || resource_info.base != zx::sys::ZX_RSRC_SYSTEM_DEBUGLOG_BASE
+            || resource_info.size != 1
+        {
+            return Err(format_err!("Debuglog resource not available."));
+        }
+        Ok(Arc::new(Self { resource }))
+    }
+
+    pub async fn serve(
+        self: Arc<Self>,
+        mut stream: fkernel::DebuglogResourceRequestStream,
+    ) -> Result<(), Error> {
+        while let Some(fkernel::DebuglogResourceRequest::Get { responder }) =
+            stream.try_next().await?
+        {
+            responder.send(self.resource.duplicate_handle(zx::Rights::SAME_RIGHTS)?)?;
+        }
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use {
+        super::*, fidl_fuchsia_kernel as fkernel, fuchsia_async as fasync,
+        fuchsia_component::client::connect_to_protocol,
+    };
+
+    async fn get_debuglog_resource() -> Result<Resource, Error> {
+        let debuglog_resource_provider = connect_to_protocol::<fkernel::DebuglogResourceMarker>()?;
+        let debuglog_resource_handle = debuglog_resource_provider.get().await?;
+        Ok(Resource::from(debuglog_resource_handle))
+    }
+
+    async fn serve_debuglog_resource() -> Result<fkernel::DebuglogResourceProxy, Error> {
+        let debuglog_resource = get_debuglog_resource().await?;
+
+        let (proxy, stream) =
+            fidl::endpoints::create_proxy_and_stream::<fkernel::DebuglogResourceMarker>()?;
+        fasync::Task::local(
+            DebuglogResource::new(debuglog_resource)
+                .unwrap_or_else(|e| panic!("Error while creating debuglog resource service: {}", e))
+                .serve(stream)
+                .unwrap_or_else(|e| panic!("Error while serving debuglog resource service: {}", e)),
+        )
+        .detach();
+        Ok(proxy)
+    }
+
+    #[fuchsia::test]
+    async fn base_type_is_debuglog() -> Result<(), Error> {
+        let debuglog_resource_provider = serve_debuglog_resource().await?;
+        let debuglog_resource: Resource = debuglog_resource_provider.get().await?;
+        let resource_info = debuglog_resource.info()?;
+        assert_eq!(resource_info.kind, zx::sys::ZX_RSRC_KIND_SYSTEM);
+        assert_eq!(resource_info.base, zx::sys::ZX_RSRC_SYSTEM_DEBUGLOG_BASE);
+        assert_eq!(resource_info.size, 1);
+        Ok(())
+    }
+}
diff --git a/src/sys/component_manager/src/builtin/energy_info_resource.rs b/src/sys/component_manager/lib/builtins/src/energy_info_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/energy_info_resource.rs
rename to src/sys/component_manager/lib/builtins/src/energy_info_resource.rs
diff --git a/src/sys/component_manager/src/builtin/factory_items.rs b/src/sys/component_manager/lib/builtins/src/factory_items.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/factory_items.rs
rename to src/sys/component_manager/lib/builtins/src/factory_items.rs
diff --git a/src/sys/component_manager/src/builtin/framebuffer_resource.rs b/src/sys/component_manager/lib/builtins/src/framebuffer_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/framebuffer_resource.rs
rename to src/sys/component_manager/lib/builtins/src/framebuffer_resource.rs
diff --git a/src/sys/component_manager/src/builtin/hypervisor_resource.rs b/src/sys/component_manager/lib/builtins/src/hypervisor_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/hypervisor_resource.rs
rename to src/sys/component_manager/lib/builtins/src/hypervisor_resource.rs
diff --git a/src/sys/component_manager/src/builtin/info_resource.rs b/src/sys/component_manager/lib/builtins/src/info_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/info_resource.rs
rename to src/sys/component_manager/lib/builtins/src/info_resource.rs
diff --git a/src/sys/component_manager/src/builtin/iommu_resource.rs b/src/sys/component_manager/lib/builtins/src/iommu_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/iommu_resource.rs
rename to src/sys/component_manager/lib/builtins/src/iommu_resource.rs
diff --git a/src/sys/component_manager/src/builtin/ioport_resource.rs b/src/sys/component_manager/lib/builtins/src/ioport_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/ioport_resource.rs
rename to src/sys/component_manager/lib/builtins/src/ioport_resource.rs
diff --git a/src/sys/component_manager/src/builtin/irq_resource.rs b/src/sys/component_manager/lib/builtins/src/irq_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/irq_resource.rs
rename to src/sys/component_manager/lib/builtins/src/irq_resource.rs
diff --git a/src/sys/component_manager/src/builtin/items.rs b/src/sys/component_manager/lib/builtins/src/items.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/items.rs
rename to src/sys/component_manager/lib/builtins/src/items.rs
diff --git a/src/sys/component_manager/src/builtin/kernel_stats.rs b/src/sys/component_manager/lib/builtins/src/kernel_stats.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/kernel_stats.rs
rename to src/sys/component_manager/lib/builtins/src/kernel_stats.rs
diff --git a/src/sys/component_manager/lib/builtins/src/lib.rs b/src/sys/component_manager/lib/builtins/src/lib.rs
new file mode 100644
index 0000000..baa6ca2
--- /dev/null
+++ b/src/sys/component_manager/lib/builtins/src/lib.rs
@@ -0,0 +1,29 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+pub mod arguments;
+pub mod cpu_resource;
+pub mod debug_resource;
+pub mod debuglog_resource;
+pub mod energy_info_resource;
+pub mod factory_items;
+pub mod framebuffer_resource;
+pub mod hypervisor_resource;
+pub mod info_resource;
+pub mod iommu_resource;
+#[cfg(target_arch = "x86_64")]
+pub mod ioport_resource;
+pub mod irq_resource;
+pub mod items;
+pub mod kernel_stats;
+pub mod mexec_resource;
+pub mod mmio_resource;
+pub mod msi_resource;
+pub mod power_resource;
+pub mod profile_resource;
+pub mod root_job;
+pub mod root_resource;
+#[cfg(target_arch = "aarch64")]
+pub mod smc_resource;
+pub mod vmex_resource;
diff --git a/src/sys/component_manager/src/builtin/mexec_resource.rs b/src/sys/component_manager/lib/builtins/src/mexec_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/mexec_resource.rs
rename to src/sys/component_manager/lib/builtins/src/mexec_resource.rs
diff --git a/src/sys/component_manager/src/builtin/mmio_resource.rs b/src/sys/component_manager/lib/builtins/src/mmio_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/mmio_resource.rs
rename to src/sys/component_manager/lib/builtins/src/mmio_resource.rs
diff --git a/src/sys/component_manager/src/builtin/msi_resource.rs b/src/sys/component_manager/lib/builtins/src/msi_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/msi_resource.rs
rename to src/sys/component_manager/lib/builtins/src/msi_resource.rs
diff --git a/src/sys/component_manager/src/builtin/power_resource.rs b/src/sys/component_manager/lib/builtins/src/power_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/power_resource.rs
rename to src/sys/component_manager/lib/builtins/src/power_resource.rs
diff --git a/src/sys/component_manager/src/builtin/profile_resource.rs b/src/sys/component_manager/lib/builtins/src/profile_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/profile_resource.rs
rename to src/sys/component_manager/lib/builtins/src/profile_resource.rs
diff --git a/src/sys/component_manager/src/builtin/root_job.rs b/src/sys/component_manager/lib/builtins/src/root_job.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/root_job.rs
rename to src/sys/component_manager/lib/builtins/src/root_job.rs
diff --git a/src/sys/component_manager/src/builtin/root_resource.rs b/src/sys/component_manager/lib/builtins/src/root_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/root_resource.rs
rename to src/sys/component_manager/lib/builtins/src/root_resource.rs
diff --git a/src/sys/component_manager/src/builtin/smc_resource.rs b/src/sys/component_manager/lib/builtins/src/smc_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/smc_resource.rs
rename to src/sys/component_manager/lib/builtins/src/smc_resource.rs
diff --git a/src/sys/component_manager/src/builtin/vmex_resource.rs b/src/sys/component_manager/lib/builtins/src/vmex_resource.rs
similarity index 100%
rename from src/sys/component_manager/src/builtin/vmex_resource.rs
rename to src/sys/component_manager/lib/builtins/src/vmex_resource.rs
diff --git a/src/sys/component_manager/lib/sandbox/src/capability.rs b/src/sys/component_manager/lib/sandbox/src/capability.rs
index fbbc3fb..cd82ce9 100644
--- a/src/sys/component_manager/lib/sandbox/src/capability.rs
+++ b/src/sys/component_manager/lib/sandbox/src/capability.rs
@@ -121,50 +121,30 @@
                 try_from_handle_in_registry(client_end.as_handle_ref())
             }
             fsandbox::Capability::Dictionary(client_end) => {
-                let mut any = try_from_handle_in_registry(client_end.as_handle_ref())?;
-                // Cache the client end so it can be reused in future conversions to FIDL.
-                {
-                    match any {
-                        Capability::Dictionary(ref mut d) => {
-                            d.set_client_end(client_end);
-                        }
-                        _ => panic!("BUG: registry has a non-Dict capability under a Dict koid"),
-                    }
-                }
+                let any = try_from_handle_in_registry(client_end.as_handle_ref())?;
+                match &any {
+                    Capability::Dictionary(_) => (),
+                    _ => panic!("BUG: registry has a non-Dict capability under a Dict koid"),
+                };
                 Ok(any)
             }
             fsandbox::Capability::Sender(client_end) => {
-                let mut any = try_from_handle_in_registry(client_end.as_handle_ref())?;
-                // Cache the client end so it can be reused in future conversions to FIDL.
-                {
-                    match any {
-                        Capability::Sender(ref mut s) => {
-                            s.set_client_end(client_end);
-                        }
-                        _ => {
-                            panic!("BUG: registry has a non-Sender capability under a Sender koid")
-                        }
-                    }
-                }
+                let any = try_from_handle_in_registry(client_end.as_handle_ref())?;
+                match &any {
+                    Capability::Sender(_) => (),
+                    _ => panic!("BUG: registry has a non-Sender capability under a Sender koid"),
+                };
                 Ok(any)
             }
-            fsandbox::Capability::Open(client_end) => {
-                try_from_handle_in_registry(client_end.as_handle_ref())
-            }
             fsandbox::Capability::Directory(client_end) => {
-                let mut any = try_from_handle_in_registry(client_end.as_handle_ref())?;
-                // Cache the client end so it can be reused in future conversions to FIDL.
-                {
-                    match any {
-                        Capability::Directory(ref mut d) => {
-                            d.set_client_end(client_end);
-                        }
-                        _ => panic!(
-                            "BUG: registry has a non-Directory capability under a Directory koid"
-                        ),
-                    }
-                }
-                Ok(any)
+                let any = try_from_handle_in_registry(client_end.as_handle_ref())?;
+                match &any {
+                    Capability::Directory(_) => (),
+                    _ => panic!(
+                        "BUG: registry has a non-Directory capability under a Directory koid"
+                    ),
+                };
+                Ok(crate::Directory::new(client_end).into())
             }
             fsandbox::CapabilityUnknown!() => Err(RemoteError::UnknownVariant),
         }
diff --git a/src/sys/component_manager/lib/sandbox/src/dict.rs b/src/sys/component_manager/lib/sandbox/src/dict.rs
index da84f38..9febe8b 100644
--- a/src/sys/component_manager/lib/sandbox/src/dict.rs
+++ b/src/sys/component_manager/lib/sandbox/src/dict.rs
@@ -1,6 +1,7 @@
 // Copyright 2023 The Fuchsia Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
 use derivative::Derivative;
 use fidl::endpoints::{create_request_stream, ClientEnd, ServerEnd};
 use fidl_fuchsia_component_sandbox as fsandbox;
@@ -8,7 +9,10 @@
 use fuchsia_zircon::{self as zx, AsHandleRef};
 use futures::TryStreamExt;
 use std::{
-    collections::{btree_map::Entry, BTreeMap},
+    collections::{
+        btree_map::{IntoIter, Iter},
+        BTreeMap,
+    },
     sync::{Arc, Mutex, MutexGuard},
 };
 use tracing::warn;
@@ -29,7 +33,7 @@
 #[derive(Derivative)]
 #[derivative(Debug)]
 pub struct Dict {
-    entries: Arc<Mutex<BTreeMap<Key, Capability>>>,
+    entries: Arc<Mutex<DictEntries>>,
 
     /// When an external request tries to access a non-existent entry,
     /// this closure will be invoked with the name of the entry.
@@ -39,21 +43,14 @@
     /// Tasks that serve [DictionaryIterator]s.
     #[derivative(Debug = "ignore")]
     iterator_tasks: fasync::TaskGroup,
-
-    /// The FIDL representation of this `Dict`.
-    ///
-    /// This will be `Some` if was previously converted into a `ClientEnd`, such as by calling
-    /// [into_fidl], and the capability is not currently in the registry.
-    client_end: Option<ClientEnd<fsandbox::DictionaryMarker>>,
 }
 
 impl Default for Dict {
     fn default() -> Self {
         Self {
-            entries: Arc::new(Mutex::new(BTreeMap::new())),
+            entries: Arc::new(Mutex::new(DictEntries::new())),
             not_found: Arc::new(|_key: &str| {}),
             iterator_tasks: fasync::TaskGroup::new(),
-            client_end: None,
         }
     }
 }
@@ -64,7 +61,6 @@
             entries: self.entries.clone(),
             not_found: self.not_found.clone(),
             iterator_tasks: fasync::TaskGroup::new(),
-            client_end: None,
         }
     }
 }
@@ -79,14 +75,13 @@
     /// the name of the entry will be sent using `not_found`.
     pub fn new_with_not_found(not_found: impl Fn(&str) -> () + 'static + Send + Sync) -> Self {
         Self {
-            entries: Arc::new(Mutex::new(BTreeMap::new())),
+            entries: Arc::new(Mutex::new(DictEntries::new())),
             not_found: Arc::new(not_found),
             iterator_tasks: fasync::TaskGroup::new(),
-            client_end: None,
         }
     }
 
-    pub fn lock_entries(&self) -> MutexGuard<'_, BTreeMap<Key, Capability>> {
+    pub fn lock_entries(&self) -> MutexGuard<'_, DictEntries> {
         self.entries.lock().unwrap()
     }
 
@@ -110,35 +105,36 @@
                 fsandbox::DictionaryRequest::Insert { key, value, responder, .. } => {
                     let result = (|| {
                         let key = key.parse().map_err(|_| fsandbox::DictionaryError::InvalidKey)?;
-                        match self.lock_entries().entry(key) {
-                            Entry::Occupied(_) => Err(fsandbox::DictionaryError::AlreadyExists),
-                            Entry::Vacant(entry) => match Capability::try_from(value) {
-                                Ok(cap) => {
-                                    entry.insert(cap);
-                                    Ok(())
-                                }
-                                Err(_) => Err(fsandbox::DictionaryError::BadCapability),
-                            },
-                        }
+                        let cap = Capability::try_from(value)
+                            .map_err(|_| fsandbox::DictionaryError::BadCapability)?;
+                        self.lock_entries().insert(key, cap)
                     })();
                     responder.send(result)?;
                 }
                 fsandbox::DictionaryRequest::Get { key, responder } => {
-                    let result = (|| match self.entries.lock().unwrap().get(key.as_str()) {
-                        Some(cap) => Ok(cap.clone().into_fidl()),
-                        None => {
-                            (self.not_found)(key.as_str());
-                            Err(fsandbox::DictionaryError::NotFound)
+                    let result = (|| {
+                        let key =
+                            Key::new(key).map_err(|_| fsandbox::DictionaryError::InvalidKey)?;
+                        match self.lock_entries().get(&key) {
+                            Some(cap) => Ok(cap.clone().into_fidl()),
+                            None => {
+                                (self.not_found)(key.as_str());
+                                Err(fsandbox::DictionaryError::NotFound)
+                            }
                         }
                     })();
                     responder.send(result)?;
                 }
                 fsandbox::DictionaryRequest::Remove { key, responder } => {
-                    let result = (|| match self.entries.lock().unwrap().remove(key.as_str()) {
-                        Some(cap) => Ok(cap.into_fidl()),
-                        None => {
-                            (self.not_found)(key.as_str());
-                            Err(fsandbox::DictionaryError::NotFound)
+                    let result = (|| {
+                        let key =
+                            Key::new(key).map_err(|_| fsandbox::DictionaryError::InvalidKey)?;
+                        match self.lock_entries().remove(&key) {
+                            Some(cap) => Ok(cap.into_fidl()),
+                            None => {
+                                (self.not_found)(key.as_str());
+                                Err(fsandbox::DictionaryError::NotFound)
+                            }
                         }
                     })();
                     responder.send(result)?;
@@ -185,7 +181,7 @@
                     // They are dropped if the caller does not request an iterator.
                     let entries = {
                         let mut entries = self.lock_entries();
-                        std::mem::replace(&mut *entries, BTreeMap::new())
+                        std::mem::replace(&mut *entries, DictEntries::new())
                     };
                     if let Some(server_end) = server_end {
                         let items = entries.into_iter().collect();
@@ -211,24 +207,14 @@
             dict.serve_dict(stream).await.expect("failed to serve Dict");
         });
     }
-
-    /// Sets this Dict's client end to the provided one.
-    ///
-    /// This should only be used to put a remoted client end back into the Dict after it is removed
-    /// from the registry.
-    pub(crate) fn set_client_end(&mut self, client_end: ClientEnd<fsandbox::DictionaryMarker>) {
-        self.client_end = Some(client_end)
-    }
 }
 
 impl From<Dict> for ClientEnd<fsandbox::DictionaryMarker> {
-    fn from(mut dict: Dict) -> Self {
-        dict.client_end.take().unwrap_or_else(|| {
-            let (client_end, dict_stream) =
-                create_request_stream::<fsandbox::DictionaryMarker>().unwrap();
-            dict.serve_and_register(dict_stream, client_end.get_koid().unwrap());
-            client_end
-        })
+    fn from(dict: Dict) -> Self {
+        let (client_end, dict_stream) =
+            create_request_stream::<fsandbox::DictionaryMarker>().unwrap();
+        dict.serve_and_register(dict_stream, client_end.get_koid().unwrap());
+        client_end
     }
 }
 
@@ -264,6 +250,64 @@
     }
 }
 
+/// The entries contained by a dictionary capability.
+///
+/// `DictEntries` creates a facade around it's underlying data representation in
+/// order to restrict its operations to those provided by the
+/// `fuchsia.component.sandbox.Dictionary` API.
+#[derive(Clone, Debug)]
+pub struct DictEntries {
+    map: BTreeMap<Key, Capability>,
+}
+
+impl DictEntries {
+    /// Creates an empty `DictEntries`.
+    pub fn new() -> Self {
+        Self { map: BTreeMap::new() }
+    }
+
+    /// Inserts an entry, mapping `key` to `capability`. If an entry already
+    /// exists at `key`, a `fsandbox::DictionaryError::AlreadyExists` will be
+    /// returned.
+    pub fn insert(
+        &mut self,
+        key: Key,
+        capability: Capability,
+    ) -> Result<(), fsandbox::DictionaryError> {
+        match self.map.insert(key, capability) {
+            Some(_) => Err(fsandbox::DictionaryError::AlreadyExists),
+            None => Ok(()),
+        }
+    }
+
+    /// Returns a reference to the capability associated with `key`. If there is
+    /// no entry for `key`, `None` is returned.
+    pub fn get(&self, key: &Key) -> Option<&Capability> {
+        self.map.get(key)
+    }
+
+    /// Removes `key` from the entries, returning the capability at `key` if the
+    /// key was already in the entries.
+    pub fn remove(&mut self, key: &Key) -> Option<Capability> {
+        self.map.remove(key)
+    }
+
+    /// Returns an iterator over the entries, sorted by key.
+    pub fn iter(&self) -> Iter<'_, Key, Capability> {
+        self.map.iter()
+    }
+}
+
+impl IntoIterator for DictEntries {
+    type Item = (Key, Capability);
+
+    type IntoIter = IntoIter<Key, Capability>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.map.into_iter()
+    }
+}
+
 /// Serves the `fuchsia.sandbox.DictionaryIterator` protocol, providing items from the given iterator.
 async fn serve_dict_iterator(
     items: Vec<(Key, Capability)>,
@@ -353,7 +397,7 @@
         let mut entries = dict.lock_entries();
 
         // Inserting adds the entry to `entries`.
-        assert_eq!(entries.len(), 1);
+        assert_eq!(entries.map.len(), 1);
 
         // The entry that was inserted should now be in `entries`.
         let cap = entries.remove(&*CAP_KEY).expect("not in entries after insert");
@@ -372,8 +416,8 @@
         // Insert a Unit into the Dict.
         {
             let mut entries = dict.lock_entries();
-            entries.insert(CAP_KEY.clone(), Capability::Unit(Unit::default()));
-            assert_eq!(entries.len(), 1);
+            entries.insert(CAP_KEY.clone(), Capability::Unit(Unit::default())).unwrap();
+            assert_eq!(entries.map.len(), 1);
         }
 
         let (dict_proxy, dict_stream) = create_proxy_and_stream::<fsandbox::DictionaryMarker>()?;
@@ -395,7 +439,7 @@
         try_join!(client, server).unwrap();
 
         // Removing the entry with Remove should remove it from `entries`.
-        assert!(dict.lock_entries().is_empty());
+        assert!(dict.lock_entries().map.is_empty());
 
         Ok(())
     }
@@ -408,8 +452,8 @@
         // Insert a Unit into the Dict.
         {
             let mut entries = dict.lock_entries();
-            entries.insert(CAP_KEY.clone(), Capability::Unit(Unit::default()));
-            assert_eq!(entries.len(), 1);
+            entries.insert(CAP_KEY.clone(), Capability::Unit(Unit::default())).unwrap();
+            assert_eq!(entries.map.len(), 1);
         }
 
         let (dict_proxy, dict_stream) = create_proxy_and_stream::<fsandbox::DictionaryMarker>()?;
@@ -431,7 +475,7 @@
         try_join!(client, server).unwrap();
 
         // The capability should remain in the Dict.
-        assert_eq!(dict.lock_entries().len(), 1);
+        assert_eq!(dict.lock_entries().map.len(), 1);
 
         Ok(())
     }
@@ -539,22 +583,26 @@
     async fn copy() -> Result<()> {
         // Create a Dict with a Unit inside, and copy the Dict.
         let dict = Dict::new();
-        dict.lock_entries().insert("unit1".parse().unwrap(), Capability::Unit(Unit::default()));
+        dict.lock_entries()
+            .insert("unit1".parse().unwrap(), Capability::Unit(Unit::default()))
+            .unwrap();
 
         let copy = dict.shallow_copy();
 
         // Insert a Unit into the copy.
-        copy.lock_entries().insert("unit2".parse().unwrap(), Capability::Unit(Unit::default()));
+        copy.lock_entries()
+            .insert("unit2".parse().unwrap(), Capability::Unit(Unit::default()))
+            .unwrap();
 
         // The copy should have two Units.
         let copy_entries = copy.lock_entries();
-        assert_eq!(copy_entries.len(), 2);
-        assert!(copy_entries.values().all(|value| matches!(value, Capability::Unit(_))));
+        assert_eq!(copy_entries.map.len(), 2);
+        assert!(copy_entries.map.values().all(|value| matches!(value, Capability::Unit(_))));
 
         // The original Dict should have only one Unit.
         let entries = dict.lock_entries();
-        assert_eq!(entries.len(), 1);
-        assert!(entries.values().all(|value| matches!(value, Capability::Unit(_))));
+        assert_eq!(entries.map.len(), 1);
+        assert!(entries.map.values().all(|value| matches!(value, Capability::Unit(_))));
 
         Ok(())
     }
@@ -568,13 +616,13 @@
         // Add a Unit into the clone.
         {
             let mut clone_entries = dict_clone.lock_entries();
-            clone_entries.insert(CAP_KEY.clone(), Capability::Unit(Unit::default()));
-            assert_eq!(clone_entries.len(), 1);
+            clone_entries.insert(CAP_KEY.clone(), Capability::Unit(Unit::default())).unwrap();
+            assert_eq!(clone_entries.map.len(), 1);
         }
 
         // The original dict should now have an entry because it shares entries with the clone.
         let entries = dict.lock_entries();
-        assert_eq!(entries.len(), 1);
+        assert_eq!(entries.map.len(), 1);
 
         Ok(())
     }
@@ -583,7 +631,7 @@
     #[fuchsia::test]
     async fn fidl_clone() -> Result<()> {
         let dict = Dict::new();
-        dict.lock_entries().insert(CAP_KEY.clone(), Capability::Unit(Unit::default()));
+        dict.lock_entries().insert(CAP_KEY.clone(), Capability::Unit(Unit::default())).unwrap();
 
         let client_end: ClientEnd<fsandbox::DictionaryMarker> = dict.into();
         let dict_proxy = client_end.into_proxy().unwrap();
@@ -615,7 +663,7 @@
 
         // The original dict should now have zero entries because the Unit was removed.
         let entries = dict.lock_entries();
-        assert!(entries.is_empty());
+        assert!(entries.map.is_empty());
 
         Ok(())
     }
@@ -638,7 +686,8 @@
             let mut entries = dict.lock_entries();
             for i in 0..NUM_ENTRIES {
                 entries
-                    .insert(format!("{}", i).parse().unwrap(), Capability::Unit(Unit::default()));
+                    .insert(format!("{}", i).parse().unwrap(), Capability::Unit(Unit::default()))
+                    .unwrap();
             }
         }
 
@@ -675,7 +724,9 @@
     #[fuchsia::test]
     async fn try_into_open_error_not_supported() {
         let dict = Dict::new();
-        dict.lock_entries().insert(CAP_KEY.clone(), Capability::Unit(Unit::default()));
+        dict.lock_entries()
+            .insert(CAP_KEY.clone(), Capability::Unit(Unit::default()))
+            .expect("dict entry already exists");
         assert_matches!(
             dict.try_into_directory_entry().err(),
             Some(ConversionError::Nested { .. })
@@ -710,7 +761,9 @@
     async fn try_into_open_success() {
         let dict = Dict::new();
         let mock_dir = Arc::new(MockDir(Counter::new(0)));
-        dict.lock_entries().insert(CAP_KEY.clone(), Capability::Open(Open::new(mock_dir.clone())));
+        dict.lock_entries()
+            .insert(CAP_KEY.clone(), Capability::Open(Open::new(mock_dir.clone())))
+            .expect("dict entry already exists");
         let remote = dict.try_into_directory_entry().expect("convert dict into Open capability");
         let scope = ExecutionScope::new();
 
@@ -732,9 +785,10 @@
         let mock_dir = Arc::new(MockDir(Counter::new(0)));
         inner_dict
             .lock_entries()
-            .insert(CAP_KEY.clone(), Capability::Open(Open::new(mock_dir.clone())));
+            .insert(CAP_KEY.clone(), Capability::Open(Open::new(mock_dir.clone())))
+            .expect("dict entry already exists");
         let dict = Dict::new();
-        dict.lock_entries().insert(CAP_KEY.clone(), Capability::Dictionary(inner_dict));
+        dict.lock_entries().insert(CAP_KEY.clone(), Capability::Dictionary(inner_dict)).unwrap();
 
         let remote = dict.try_into_directory_entry().expect("convert dict into Open capability");
         let scope = ExecutionScope::new();
@@ -781,7 +835,9 @@
         };
         let directory = Directory::from(serve_vfs_dir(fs));
         let dict = Dict::new();
-        dict.lock_entries().insert(CAP_KEY.clone(), Capability::Directory(directory));
+        dict.lock_entries()
+            .insert(CAP_KEY.clone(), Capability::Directory(directory))
+            .expect("dict entry already exists");
 
         let remote = dict.try_into_directory_entry().unwrap();
 
diff --git a/src/sys/component_manager/lib/sandbox/src/directory.rs b/src/sys/component_manager/lib/sandbox/src/directory.rs
index a44f08b..22f816a 100644
--- a/src/sys/component_manager/lib/sandbox/src/directory.rs
+++ b/src/sys/component_manager/lib/sandbox/src/directory.rs
@@ -2,24 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 use core::fmt;
-use fidl::endpoints::{create_endpoints, ClientEnd};
+use fidl::endpoints::ClientEnd;
 use fidl_fuchsia_component_sandbox as fsandbox;
 use fidl_fuchsia_io as fio;
-use fuchsia_async as fasync;
 use fuchsia_zircon::{self as zx, AsHandleRef};
 use std::sync::Arc;
-use vfs::{directory::entry::DirectoryEntry, execution_scope::ExecutionScope, remote::RemoteLike};
+use vfs::{directory::entry::DirectoryEntry, remote::RemoteLike};
 
-use crate::{registry, CapabilityTrait, Open};
+use crate::{registry, CapabilityTrait};
 
 /// A capability that is a `fuchsia.io` directory.
 ///
 /// The directory may optionally be backed by a future that serves its contents.
 pub struct Directory {
     /// The FIDL representation of this [Directory].
-    ///
-    /// Invariant: Always Some when the Directory is outside of the registry.
-    client_end: Option<ClientEnd<fio::DirectoryMarker>>,
+    client_end: ClientEnd<fio::DirectoryMarker>,
 }
 
 impl Directory {
@@ -29,44 +26,7 @@
     ///
     /// * `client_end` - A `fuchsia.io/Directory` client endpoint.
     pub fn new(client_end: ClientEnd<fio::DirectoryMarker>) -> Self {
-        Directory { client_end: Some(client_end) }
-    }
-
-    /// Create a new [Directory] capability that will open entries using the [Open] capability.
-    ///
-    /// Arguments:
-    ///
-    /// * `open_flags` - The flags that will be used to open a new connection from the [Open]
-    ///   capability.
-    pub fn from_open(open: Open, open_flags: fio::OpenFlags, scope: ExecutionScope) -> Self {
-        let (client_end, server_end) = create_endpoints::<fio::DirectoryMarker>();
-        scope.clone().spawn(async move {
-            // Wait for the client endpoint to be written or closed. These are the only two
-            // operations the client could do that warrants our attention.
-            let server_end = fasync::Channel::from_channel(server_end.into_channel());
-            let on_signal_fut = fasync::OnSignals::new(
-                &server_end,
-                zx::Signals::CHANNEL_READABLE | zx::Signals::CHANNEL_PEER_CLOSED,
-            );
-            let signals = on_signal_fut.await.unwrap();
-            if signals & zx::Signals::CHANNEL_READABLE != zx::Signals::NONE {
-                open.open(
-                    scope.clone(),
-                    open_flags,
-                    vfs::path::Path::dot(),
-                    server_end.into_zx_channel().into(),
-                );
-            }
-        });
-        Self::new(client_end)
-    }
-
-    /// Sets this directory's client end to the provided one.
-    ///
-    /// This should only be used to put a remoted client end back into the Directory
-    /// after it is removed from the registry.
-    pub(crate) fn set_client_end(&mut self, client_end: ClientEnd<fio::DirectoryMarker>) {
-        self.client_end = Some(client_end)
+        Directory { client_end: client_end }
     }
 
     /// Turn the [Directory] into a remote VFS node.
@@ -88,7 +48,7 @@
         // This is necessary because we the conversion consumes the ClientEnd, but we can't take
         // it out of non-mut `&self`.
         let (clone_client_end, clone_server_end) = zx::Channel::create();
-        let raw_handle = self.client_end.as_ref().unwrap().as_handle_ref().raw_handle();
+        let raw_handle = self.client_end.as_handle_ref().raw_handle();
         // SAFETY: the channel is forgotten at the end of scope so it is not double closed.
         unsafe {
             let borrowed: zx::Channel = zx::Handle::from_raw(raw_handle).into();
@@ -97,7 +57,7 @@
             std::mem::forget(directory.into_channel());
         }
         let client_end: ClientEnd<fio::DirectoryMarker> = clone_client_end.into();
-        Self { client_end: Some(client_end) }
+        Self { client_end: client_end }
     }
 }
 
@@ -105,21 +65,22 @@
 
 impl From<ClientEnd<fio::DirectoryMarker>> for Directory {
     fn from(client_end: ClientEnd<fio::DirectoryMarker>) -> Self {
-        Directory { client_end: Some(client_end) }
+        Directory { client_end: client_end }
     }
 }
 
 impl From<Directory> for ClientEnd<fio::DirectoryMarker> {
-    /// Returns the `fuchsia.io.Directory` client stored in this Directory, taking it out,
-    /// and moves the capability into the registry.
-    ///
-    /// The client end is put back when the Directory is removed from the registry.
-    fn from(mut directory: Directory) -> Self {
-        let client_end = directory.client_end.take().expect("BUG: missing client end");
+    /// Return a channel to the Directory and store the channel in
+    /// the registry.
+    fn from(directory: Directory) -> Self {
+        let Directory { client_end } = directory;
+        // Create a null directory for the registry.
+        let new_dict =
+            Directory::new(ClientEnd::<fio::DirectoryMarker>::new(zx::Handle::invalid().into()));
 
         // Move this capability into the registry.
         let koid = client_end.get_koid().unwrap();
-        registry::insert(directory.into(), koid);
+        registry::insert(new_dict.into(), koid);
 
         client_end
     }
@@ -134,7 +95,8 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use fidl::endpoints::ServerEnd;
+    use crate::Open;
+    use fidl::endpoints::{create_endpoints, ServerEnd};
     use fidl_fuchsia_io as fio;
     use fuchsia_zircon as zx;
     use futures::channel::mpsc;
@@ -144,6 +106,7 @@
             entry::{EntryInfo, OpenRequest},
             entry_container::Directory as VfsDirectory,
         },
+        execution_scope::ExecutionScope,
         path::Path,
         pseudo_directory,
     };
diff --git a/src/sys/component_manager/lib/sandbox/src/lib.rs b/src/sys/component_manager/lib/sandbox/src/lib.rs
index 81414e3..da3872a 100644
--- a/src/sys/component_manager/lib/sandbox/src/lib.rs
+++ b/src/sys/component_manager/lib/sandbox/src/lib.rs
@@ -19,7 +19,7 @@
 pub use self::any::{AnyCapability, AnyCast, ErasedCapability};
 pub use self::capability::{Capability, CapabilityTrait, ConversionError, RemoteError};
 pub use self::data::Data;
-pub use self::dict::{Dict, Key as DictKey};
+pub use self::dict::{Dict, DictEntries, Key as DictKey};
 pub use self::directory::Directory;
 pub use self::handle::OneShotHandle;
 pub use self::open::Open;
diff --git a/src/sys/component_manager/lib/sandbox/src/open.rs b/src/sys/component_manager/lib/sandbox/src/open.rs
index c2012be..0905115 100644
--- a/src/sys/component_manager/lib/sandbox/src/open.rs
+++ b/src/sys/component_manager/lib/sandbox/src/open.rs
@@ -189,7 +189,7 @@
 
 impl From<Open> for fsandbox::Capability {
     fn from(open: Open) -> Self {
-        Self::Open(open.into())
+        Self::Sender(crate::Sender::new_sendable(open).into())
     }
 }
 
@@ -352,7 +352,9 @@
     async fn test_sender_into_open_via_dict() {
         let dict = Dict::new();
         let (receiver, sender) = Receiver::new();
-        dict.lock_entries().insert("echo".parse().unwrap(), Capability::Sender(sender));
+        dict.lock_entries()
+            .insert("echo".parse().unwrap(), Capability::Sender(sender))
+            .expect("dict entry already exists");
 
         let open = Open::new(dict.try_into_directory_entry().unwrap());
         let (client_end, server_end) = zx::Channel::create();
@@ -372,7 +374,9 @@
 
         let dict = Dict::new();
         let (receiver, sender) = Receiver::new();
-        dict.lock_entries().insert("echo".parse().unwrap(), Capability::Sender(sender));
+        dict.lock_entries()
+            .insert("echo".parse().unwrap(), Capability::Sender(sender))
+            .expect("dict entry already exists");
 
         let open = Open::new(dict.try_into_directory_entry().unwrap());
         let (client_end, server_end) = zx::Channel::create();
diff --git a/src/sys/component_manager/lib/sandbox/src/sender.rs b/src/sys/component_manager/lib/sandbox/src/sender.rs
index ab6ce36..7279d8c 100644
--- a/src/sys/component_manager/lib/sandbox/src/sender.rs
+++ b/src/sys/component_manager/lib/sandbox/src/sender.rs
@@ -34,30 +34,18 @@
 }
 
 /// A capability that transfers another capability to a [Receiver].
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct Sender {
     inner: std::sync::Arc<dyn Sendable>,
-
-    /// The FIDL representation of this `Sender`.
-    ///
-    /// This will be `Some` if was previously converted into a `ClientEnd`, such as by calling
-    /// [into_fidl], and the capability is not currently in the registry.
-    client_end: Option<ClientEnd<fsandbox::SenderMarker>>,
-}
-
-impl Clone for Sender {
-    fn clone(&self) -> Self {
-        Self { inner: self.inner.clone(), client_end: None }
-    }
 }
 
 impl Sender {
     pub fn new_sendable(sender: impl Sendable + 'static) -> Self {
-        Self { inner: std::sync::Arc::new(sender), client_end: None }
+        Self { inner: std::sync::Arc::new(sender) }
     }
 
     pub(crate) fn new(sender: mpsc::UnboundedSender<Message>) -> Self {
-        Self { inner: std::sync::Arc::new(sender), client_end: None }
+        Self { inner: std::sync::Arc::new(sender) }
     }
 
     pub(crate) fn send_channel(&self, channel: zx::Channel) -> Result<(), ()> {
@@ -99,14 +87,6 @@
         // Move this capability into the registry.
         registry::spawn_task(self.into(), koid, sender.serve_sender(stream));
     }
-
-    /// Sets this Sender's client end to the provided one.
-    ///
-    /// This should only be used to put a remoted client end back into the Sender after it is
-    /// removed from the registry.
-    pub(crate) fn set_client_end(&mut self, client_end: ClientEnd<fsandbox::SenderMarker>) {
-        self.client_end = Some(client_end)
-    }
 }
 
 impl From<Sender> for Open {
@@ -133,13 +113,11 @@
 
 impl From<Sender> for ClientEnd<fsandbox::SenderMarker> {
     /// Serves the `fuchsia.sandbox.Sender` protocol for this Sender and moves it into the registry.
-    fn from(mut sender: Sender) -> ClientEnd<fsandbox::SenderMarker> {
-        sender.client_end.take().unwrap_or_else(|| {
-            let (client_end, sender_stream) =
-                create_request_stream::<fsandbox::SenderMarker>().unwrap();
-            sender.serve_and_register(sender_stream, client_end.get_koid().unwrap());
-            client_end
-        })
+    fn from(sender: Sender) -> ClientEnd<fsandbox::SenderMarker> {
+        let (client_end, sender_stream) =
+            create_request_stream::<fsandbox::SenderMarker>().unwrap();
+        sender.serve_and_register(sender_stream, client_end.get_koid().unwrap());
+        client_end
     }
 }
 
diff --git a/src/sys/component_manager/lib/serve_processargs/src/lib.rs b/src/sys/component_manager/lib/serve_processargs/src/lib.rs
index b8a9322..f25b250 100644
--- a/src/sys/component_manager/lib/serve_processargs/src/lib.rs
+++ b/src/sys/component_manager/lib/serve_processargs/src/lib.rs
@@ -24,7 +24,7 @@
     /// As a result, a namespace entry will be created in the resulting processargs, corresponding
     /// to the parent directory, e.g. "/svc/foo".
     ///
-    /// For example, installing a `sandbox::Open` at "/svc/fuchsia.examples.Echo" will
+    /// For example, installing a `sandbox::Sender` at "/svc/fuchsia.examples.Echo" will
     /// cause the framework to spin up a `fuchsia.io/Directory` implementation backing "/svc",
     /// containing a filesystem object named "fuchsia.examples.Echo".
     ///
@@ -38,7 +38,7 @@
     /// [Delivery::NamespaceEntry] is that the former will create a namespace entry at the parent
     /// directory.
     ///
-    /// For example, installing a `sandbox::Open` at "/data" will result in a namespace entry
+    /// For example, installing a `sandbox::Directory` at "/data" will result in a namespace entry
     /// at "/data". A request will be sent to the capability when the user writes to the
     /// namespace entry.
     NamespaceEntry(cm_types::Path),
@@ -161,8 +161,8 @@
             None => return Err(DeliveryError::NotInDict(key.to_owned())),
         }
     }
-    if !entries.is_empty() {
-        let keys = entries.keys().cloned().collect();
+    if entries.iter().count() > 0 {
+        let keys = entries.iter().map(|(key, _)| key).cloned().collect();
         return Err(DeliveryError::UnusedCapabilities(keys));
     }
     Ok(())
@@ -181,35 +181,20 @@
 mod test_util {
     use {
         fidl::endpoints::ServerEnd,
-        fidl_fuchsia_io as fio, fuchsia_async as fasync, fuchsia_zircon as zx,
-        fuchsia_zircon::HandleBased,
-        sandbox::{OneShotHandle, Open},
+        fidl_fuchsia_io as fio, fuchsia_zircon as zx,
+        sandbox::{Receiver, Sender},
         std::sync::Arc,
         vfs::{
             directory::entry::{DirectoryEntry, EntryInfo, OpenRequest},
             execution_scope::ExecutionScope,
             path::Path,
             remote::RemoteLike,
-            service,
         },
     };
 
-    pub struct Receiver(pub async_channel::Receiver<OneShotHandle>);
-
-    pub fn multishot() -> (Open, Receiver) {
-        let (sender, receiver) = async_channel::unbounded::<OneShotHandle>();
-
-        let open_fn = move |scope: ExecutionScope, channel: fasync::Channel| {
-            let sender = sender.clone();
-            scope.spawn(async move {
-                let capability = OneShotHandle::from(channel.into_zx_channel().into_handle());
-                let _ = sender.send(capability).await;
-            });
-        };
-
-        let open = Open::new(service::endpoint(open_fn));
-
-        (open, Receiver(receiver))
+    pub fn multishot() -> (Sender, Receiver) {
+        let (receiver, sender) = Receiver::new();
+        (sender, receiver)
     }
 
     pub fn mock_dir() -> (Arc<impl DirectoryEntry>, async_channel::Receiver<(Path, zx::Channel)>) {
@@ -254,7 +239,7 @@
     use {
         super::*,
         crate::namespace::ignore_not_found as ignore,
-        anyhow::Result,
+        anyhow::{anyhow, Result},
         assert_matches::assert_matches,
         fidl::endpoints::{Proxy, ServerEnd},
         fidl_fuchsia_io as fio, fuchsia_async as fasync,
@@ -292,10 +277,12 @@
 
         let mut processargs = ProcessArgs::new();
         let dict = Dict::new();
-        dict.lock_entries().insert(
-            "stdin".parse().unwrap(),
-            Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle().into_handle())),
-        );
+        dict.lock_entries()
+            .insert(
+                "stdin".parse().unwrap(),
+                Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle().into_handle())),
+            )
+            .map_err(|e| anyhow!("{e:?}"))?;
         let delivery_map = hashmap! {
             "stdin".parse().unwrap() => DeliveryMapEntry::Delivery(
                 Delivery::Handle(HandleInfo::new(HandleType::FileDescriptor, 0))
@@ -332,12 +319,17 @@
 
         // Put a socket at "/handles/stdin". This implements a capability bundling pattern.
         let handles = Dict::new();
-        handles.lock_entries().insert(
-            "stdin".parse().unwrap(),
-            Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
-        );
+        handles
+            .lock_entries()
+            .insert(
+                "stdin".parse().unwrap(),
+                Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
+            )
+            .map_err(|e| anyhow!("{e:?}"))?;
         let dict = Dict::new();
-        dict.lock_entries().insert("handles".parse().unwrap(), Capability::Dictionary(handles));
+        dict.lock_entries()
+            .insert("handles".parse().unwrap(), Capability::Dictionary(handles))
+            .map_err(|e| anyhow!("{e:?}"))?;
 
         let delivery_map = hashmap! {
             "handles".parse().unwrap() => DeliveryMapEntry::Dict(hashmap! {
@@ -368,12 +360,17 @@
         let mut processargs = ProcessArgs::new();
 
         let handles = Dict::new();
-        handles.lock_entries().insert(
-            "stdin".parse().unwrap(),
-            Capability::OneShotHandle(OneShotHandle::from(ep0.into_handle())),
-        );
+        handles
+            .lock_entries()
+            .insert(
+                "stdin".parse().unwrap(),
+                Capability::OneShotHandle(OneShotHandle::from(ep0.into_handle())),
+            )
+            .map_err(|e| anyhow!("{e:?}"))?;
         let dict = Dict::new();
-        dict.lock_entries().insert("handles".parse().unwrap(), Capability::Dictionary(handles));
+        dict.lock_entries()
+            .insert("handles".parse().unwrap(), Capability::Dictionary(handles))
+            .map_err(|e| anyhow!("{e:?}"))?;
 
         let delivery_map = hashmap! {
             "handles".parse().unwrap() => DeliveryMapEntry::Dict(hashmap! {
@@ -410,10 +407,12 @@
         // The type of "/handles" is a socket capability but we try to open it as a dict and extract
         // a "stdin" inside. This should fail.
         let dict = Dict::new();
-        dict.lock_entries().insert(
-            "handles".parse().unwrap(),
-            Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
-        );
+        dict.lock_entries()
+            .insert(
+                "handles".parse().unwrap(),
+                Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
+            )
+            .expect("dict entry already exists");
 
         let delivery_map = hashmap! {
             "handles".parse().unwrap() => DeliveryMapEntry::Dict(hashmap! {
@@ -436,10 +435,12 @@
 
         let mut processargs = ProcessArgs::new();
         let dict = Dict::new();
-        dict.lock_entries().insert(
-            "stdin".parse().unwrap(),
-            Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
-        );
+        dict.lock_entries()
+            .insert(
+                "stdin".parse().unwrap(),
+                Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
+            )
+            .expect("dict entry already exists");
         let delivery_map = DeliveryMap::new();
 
         assert_matches!(
@@ -455,10 +456,12 @@
 
         let mut processargs = ProcessArgs::new();
         let dict = Dict::new();
-        dict.lock_entries().insert(
-            "stdin".parse().unwrap(),
-            Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
-        );
+        dict.lock_entries()
+            .insert(
+                "stdin".parse().unwrap(),
+                Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
+            )
+            .expect("dict entry already exists");
         let delivery_map = hashmap! {
             "stdin".parse().unwrap() => DeliveryMapEntry::Delivery(
                 Delivery::Handle(HandleInfo::new(HandleType::DirectoryRequest, 0))
@@ -494,15 +497,19 @@
     /// connections to that protocol.
     #[fuchsia::test]
     async fn test_namespace_object_end_to_end() -> Result<()> {
-        let (open, receiver) = multishot();
+        let (sender, receiver) = multishot();
         let peer_closed_open = multishot().0;
 
         let mut processargs = ProcessArgs::new();
         let dict = Dict::new();
         {
             let mut entries = dict.lock_entries();
-            entries.insert("normal".parse().unwrap(), Capability::Open(open));
-            entries.insert("closed".parse().unwrap(), Capability::Open(peer_closed_open));
+            entries
+                .insert("normal".parse().unwrap(), sender.into())
+                .expect("dict entry already exists");
+            entries
+                .insert("closed".parse().unwrap(), peer_closed_open.into())
+                .expect("dict entry already exists");
         }
         let delivery_map = hashmap! {
             "normal".parse().unwrap() => DeliveryMapEntry::Delivery(
@@ -538,7 +545,7 @@
         fdio::service_connect_at(&dir, "fuchsia.Normal", server_end).unwrap();
 
         // Make sure the server_end is received, and test connectivity.
-        let server_end: zx::Channel = receiver.0.recv().await.unwrap().get_handle().unwrap().into();
+        let server_end: zx::Channel = receiver.receive().await.unwrap().channel.into();
         client_end.signal_peer(zx::Signals::empty(), zx::Signals::USER_0).unwrap();
         server_end.wait_handle(zx::Signals::USER_0, zx::Time::INFINITE_PAST).unwrap();
 
@@ -556,13 +563,15 @@
 
     #[fuchsia::test]
     async fn test_namespace_scope_shutdown() -> Result<()> {
-        let (open, receiver) = multishot();
+        let (sender, receiver) = multishot();
 
         let mut processargs = ProcessArgs::new();
         let dict = Dict::new();
         {
             let mut entries = dict.lock_entries();
-            entries.insert("normal".parse().unwrap(), Capability::Open(open));
+            entries
+                .insert("normal".parse().unwrap(), sender.into())
+                .expect("dict entry already exists");
         }
         let delivery_map = hashmap! {
             "normal".parse().unwrap() => DeliveryMapEntry::Delivery(
@@ -585,7 +594,7 @@
         fdio::service_connect_at(&dir, "fuchsia.Normal", server_end).unwrap();
 
         // Make sure the server_end is received, and test connectivity.
-        let server_end: zx::Channel = receiver.0.recv().await.unwrap().get_handle().unwrap().into();
+        let server_end: zx::Channel = receiver.receive().await.unwrap().channel.into();
         client_end.signal_peer(zx::Signals::empty(), zx::Signals::USER_0).unwrap();
         server_end.wait_handle(zx::Signals::USER_0, zx::Time::INFINITE_PAST).unwrap();
 
@@ -618,10 +627,12 @@
 
         let mut processargs = ProcessArgs::new();
         let dict = Dict::new();
-        dict.lock_entries().insert(
-            "data".parse().unwrap(),
-            Capability::Directory(sandbox::Directory::new(dir_proxy)),
-        );
+        dict.lock_entries()
+            .insert(
+                "data".parse().unwrap(),
+                Capability::Directory(sandbox::Directory::new(dir_proxy)),
+            )
+            .map_err(|e| anyhow!("{e:?}"))?;
         let delivery_map = hashmap! {
             "data".parse().unwrap() => DeliveryMapEntry::Delivery(
                 Delivery::NamespaceEntry(cm_types::Path::from_str("/data").unwrap())
@@ -679,10 +690,12 @@
 
         let mut processargs = ProcessArgs::new();
         let dict = Dict::new();
-        dict.lock_entries().insert(
-            "stdin".parse().unwrap(),
-            Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
-        );
+        dict.lock_entries()
+            .insert(
+                "stdin".parse().unwrap(),
+                Capability::OneShotHandle(OneShotHandle::from(sock0.into_handle())),
+            )
+            .expect("dict entry already exists");
         let delivery_map = hashmap! {
             "stdin".parse().unwrap() => DeliveryMapEntry::Delivery(
                 Delivery::NamespacedObject(cm_types::Path::from_str("/svc/fuchsia.Normal").unwrap())
diff --git a/src/sys/component_manager/lib/serve_processargs/src/namespace.rs b/src/sys/component_manager/lib/serve_processargs/src/namespace.rs
index d5054d4..b1a5c67 100644
--- a/src/sys/component_manager/lib/serve_processargs/src/namespace.rs
+++ b/src/sys/component_manager/lib/serve_processargs/src/namespace.rs
@@ -79,14 +79,9 @@
         };
 
         // Insert the capability into the Dict.
-        {
-            let mut entries = dict.lock_entries();
-            if entries.contains_key(path.basename().as_str()) {
-                return Err(NamespaceError::Duplicate(path.clone().into()).into());
-            }
-            entries.insert(path.basename().clone(), cap);
-        }
-        Ok(())
+        dict.lock_entries()
+            .insert(path.basename().clone(), cap)
+            .map_err(|_| NamespaceError::Duplicate(path.clone().into()).into())
     }
 
     /// Add a capability `cap` at `path`. As a result, the framework will create a
@@ -174,16 +169,17 @@
         crate::test_util::multishot,
         anyhow::Result,
         assert_matches::assert_matches,
-        fidl::{endpoints::Proxy, AsHandleRef, Peered},
+        fidl::{endpoints::Proxy, Peered},
         fidl_fuchsia_io as fio, fuchsia_async as fasync,
         fuchsia_fs::directory::DirEntry,
         fuchsia_zircon as zx,
+        fuchsia_zircon::AsHandleRef,
         futures::StreamExt,
     };
 
-    fn open_cap() -> Capability {
-        let (open, _receiver) = multishot();
-        Capability::Open(open)
+    fn sender_cap() -> Capability {
+        let (sender, _receiver) = multishot();
+        Capability::Sender(sender)
     }
 
     fn ns_path(str: &str) -> NamespacePath {
@@ -197,7 +193,7 @@
     fn parents_valid(paths: Vec<&str>) -> Result<(), BuildNamespaceError> {
         let mut shadow = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
         for p in paths {
-            shadow.add_object(open_cap(), &path(p))?;
+            shadow.add_object(sender_cap(), &path(p))?;
         }
         Ok(())
     }
@@ -212,21 +208,21 @@
         assert_matches!(parents_valid(vec!["/a", "/b", "/c"]), Ok(()));
 
         let mut shadow = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        shadow.add_object(open_cap(), &path("/svc/foo")).unwrap();
-        assert_matches!(shadow.add_object(open_cap(), &path("/svc/foo/bar")), Err(_));
+        shadow.add_object(sender_cap(), &path("/svc/foo")).unwrap();
+        assert_matches!(shadow.add_object(sender_cap(), &path("/svc/foo/bar")), Err(_));
 
         let mut shadow = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        shadow.add_object(open_cap(), &path("/svc/foo")).unwrap();
-        assert_matches!(shadow.add_entry(open_cap(), &ns_path("/svc2")), Ok(_));
+        shadow.add_object(sender_cap(), &path("/svc/foo")).unwrap();
+        assert_matches!(shadow.add_entry(sender_cap(), &ns_path("/svc2")), Ok(_));
     }
 
     #[fuchsia::test]
     async fn test_duplicate_object() {
         let mut namespace = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        namespace.add_object(open_cap(), &path("/svc/a")).expect("");
+        namespace.add_object(sender_cap(), &path("/svc/a")).expect("");
         // Adding again will fail.
         assert_matches!(
-            namespace.add_object(open_cap(), &path("/svc/a")),
+            namespace.add_object(sender_cap(), &path("/svc/a")),
             Err(BuildNamespaceError::NamespaceError(NamespaceError::Duplicate(path)))
             if path.to_string() == "/svc/a"
         );
@@ -235,10 +231,10 @@
     #[fuchsia::test]
     async fn test_duplicate_entry() {
         let mut namespace = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        namespace.add_entry(open_cap(), &ns_path("/svc/a")).expect("");
+        namespace.add_entry(sender_cap(), &ns_path("/svc/a")).expect("");
         // Adding again will fail.
         assert_matches!(
-            namespace.add_entry(open_cap(), &ns_path("/svc/a")),
+            namespace.add_entry(sender_cap(), &ns_path("/svc/a")),
             Err(BuildNamespaceError::NamespaceError(NamespaceError::Duplicate(path)))
             if path.to_string() == "/svc/a"
         );
@@ -247,9 +243,9 @@
     #[fuchsia::test]
     async fn test_duplicate_object_and_entry() {
         let mut namespace = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        namespace.add_object(open_cap(), &path("/svc/a")).expect("");
+        namespace.add_object(sender_cap(), &path("/svc/a")).expect("");
         assert_matches!(
-            namespace.add_entry(open_cap(), &ns_path("/svc/a")),
+            namespace.add_entry(sender_cap(), &ns_path("/svc/a")),
             Err(BuildNamespaceError::NamespaceError(NamespaceError::Shadow(path)))
             if path.to_string() == "/svc/a"
         );
@@ -260,9 +256,9 @@
     #[fuchsia::test]
     async fn test_duplicate_entry_at_object_parent() {
         let mut namespace = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        namespace.add_object(open_cap(), &path("/foo/bar")).expect("");
+        namespace.add_object(sender_cap(), &path("/foo/bar")).expect("");
         assert_matches!(
-            namespace.add_entry(open_cap(), &ns_path("/foo")),
+            namespace.add_entry(sender_cap(), &ns_path("/foo")),
             Err(BuildNamespaceError::NamespaceError(NamespaceError::Duplicate(path)))
             if path.to_string() == "/foo"
         );
@@ -274,9 +270,9 @@
     #[fuchsia::test]
     async fn test_duplicate_object_parent_at_entry() {
         let mut namespace = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        namespace.add_entry(open_cap(), &ns_path("/foo")).expect("");
+        namespace.add_entry(sender_cap(), &ns_path("/foo")).expect("");
         assert_matches!(
-            namespace.add_object(open_cap(), &path("/foo/bar")),
+            namespace.add_object(sender_cap(), &path("/foo/bar")),
             Err(BuildNamespaceError::NamespaceError(NamespaceError::Duplicate(path)))
             if path.to_string() == "/foo/bar"
         );
@@ -291,10 +287,10 @@
 
     #[fuchsia::test]
     async fn test_one_sender_end_to_end() {
-        let (open, receiver) = multishot();
+        let (sender, receiver) = multishot();
 
         let mut namespace = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        namespace.add_object(Capability::Open(open), &path("/svc/a")).unwrap();
+        namespace.add_object(sender.into(), &path("/svc/a")).unwrap();
         let ns = namespace.serve().unwrap();
 
         let mut ns = ns.flatten();
@@ -315,7 +311,7 @@
             .unwrap();
 
         // Make sure the server_end is received, and test connectivity.
-        let server_end: zx::Channel = receiver.0.recv().await.unwrap().get_handle().unwrap().into();
+        let server_end: zx::Channel = receiver.receive().await.unwrap().channel.into();
         client_end.signal_peer(zx::Signals::empty(), zx::Signals::USER_0).unwrap();
         server_end.wait_handle(zx::Signals::USER_0, zx::Time::INFINITE_PAST).unwrap();
     }
@@ -324,8 +320,8 @@
     async fn test_two_senders_in_same_namespace_entry() {
         let scope = ExecutionScope::new();
         let mut namespace = NamespaceBuilder::new(scope.clone(), ignore_not_found());
-        namespace.add_object(open_cap(), &path("/svc/a")).unwrap();
-        namespace.add_object(open_cap(), &path("/svc/b")).unwrap();
+        namespace.add_object(sender_cap(), &path("/svc/a")).unwrap();
+        namespace.add_object(sender_cap(), &path("/svc/b")).unwrap();
         let ns = namespace.serve().unwrap();
 
         let mut ns = ns.flatten();
@@ -349,8 +345,8 @@
     #[fuchsia::test]
     async fn test_two_senders_in_different_namespace_entries() {
         let mut namespace = NamespaceBuilder::new(ExecutionScope::new(), ignore_not_found());
-        namespace.add_object(open_cap(), &path("/svc1/a")).unwrap();
-        namespace.add_object(open_cap(), &path("/svc2/b")).unwrap();
+        namespace.add_object(sender_cap(), &path("/svc1/a")).unwrap();
+        namespace.add_object(sender_cap(), &path("/svc2/b")).unwrap();
         let ns = namespace.serve().unwrap();
 
         let ns = ns.flatten();
@@ -384,7 +380,7 @@
     async fn test_not_found() {
         let (not_found_sender, mut not_found_receiver) = unbounded();
         let mut namespace = NamespaceBuilder::new(ExecutionScope::new(), not_found_sender);
-        namespace.add_object(open_cap(), &path("/svc/a")).unwrap();
+        namespace.add_object(sender_cap(), &path("/svc/a")).unwrap();
         let ns = namespace.serve().unwrap();
 
         let mut ns = ns.flatten();
diff --git a/src/sys/component_manager/meta/component_manager_tests.cml b/src/sys/component_manager/meta/component_manager_tests.cml
index 3b3a760..693ccf1 100644
--- a/src/sys/component_manager/meta/component_manager_tests.cml
+++ b/src/sys/component_manager/meta/component_manager_tests.cml
@@ -14,23 +14,8 @@
         {
             protocol: [
                 "fuchsia.boot.RootResource",
-                "fuchsia.kernel.CpuResource",
-                "fuchsia.kernel.DebugResource",
-                "fuchsia.kernel.EnergyInfoResource",
-                "fuchsia.kernel.FramebufferResource",
-                "fuchsia.kernel.HypervisorResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.InfoResource",
-                "fuchsia.kernel.IommuResource",
-                "fuchsia.kernel.IoportResource",
-                "fuchsia.kernel.IrqResource",
-                "fuchsia.kernel.MexecResource",
-                "fuchsia.kernel.MmioResource",
-                "fuchsia.kernel.MsiResource",
-                "fuchsia.kernel.PowerResource",
-                "fuchsia.kernel.ProfileResource",
-                "fuchsia.kernel.RootJob",
-                "fuchsia.kernel.SmcResource",
-                "fuchsia.kernel.VmexResource",
                 "fuchsia.process.Launcher",
             ],
         },
diff --git a/src/sys/component_manager/src/builtin/builtin_runner.rs b/src/sys/component_manager/src/builtin/builtin_runner.rs
index 7ad1d6e..c426317 100644
--- a/src/sys/component_manager/src/builtin/builtin_runner.rs
+++ b/src/sys/component_manager/src/builtin/builtin_runner.rs
@@ -258,16 +258,20 @@
         let svc = Dict::new();
         {
             let mut entries = svc.lock_entries();
-            entries.insert(
-                fcrunner::ComponentRunnerMarker::PROTOCOL_NAME.parse().unwrap(),
-                elf_runner.into_sender(WeakComponentInstance::invalid()).into(),
-            );
-            entries.insert(
-                fattribution::ProviderMarker::PROTOCOL_NAME.parse().unwrap(),
-                snapshot_provider.into_sender(WeakComponentInstance::invalid()).into(),
-            );
+            entries
+                .insert(
+                    fcrunner::ComponentRunnerMarker::PROTOCOL_NAME.parse().unwrap(),
+                    elf_runner.into_sender(WeakComponentInstance::invalid()).into(),
+                )
+                .ok();
+            entries
+                .insert(
+                    fattribution::ProviderMarker::PROTOCOL_NAME.parse().unwrap(),
+                    snapshot_provider.into_sender(WeakComponentInstance::invalid()).into(),
+                )
+                .ok();
         }
-        output.lock_entries().insert(SVC.parse().unwrap(), Capability::Dictionary(svc));
+        output.lock_entries().insert(SVC.parse().unwrap(), Capability::Dictionary(svc)).ok();
 
         let this = Self { task_group, execution_scope: ExecutionScope::new(), output, job };
         this
diff --git a/src/sys/component_manager/src/builtin/capability.rs b/src/sys/component_manager/src/builtin/capability.rs
deleted file mode 100644
index b421338..0000000
--- a/src/sys/component_manager/src/builtin/capability.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use {
-    anyhow::{format_err, Error},
-    async_trait::async_trait,
-    fidl::endpoints::ProtocolMarker,
-    fuchsia_zircon::{self as zx, ResourceInfo},
-    routing::capability_source::InternalCapability,
-    std::sync::Arc,
-};
-
-/// A builtin capability, whether it be a `framework` capability
-/// or a capability that originates above the root realm (from component_manager).
-///
-/// Implementing this trait takes care of certain boilerplate, like registering
-/// event hooks and the creation of a CapabilityProvider.
-#[async_trait]
-pub trait BuiltinCapability {
-    /// Name of the capability. Used for hook registration and logging.
-    const NAME: &'static str;
-
-    /// Service marker for the capability.
-    type Marker: ProtocolMarker;
-
-    /// Serves an instance of the capability given an appropriate RequestStream.
-    /// Returns when the channel backing the RequestStream is closed or an
-    /// unrecoverable error occurs.
-    #[allow(dead_code)]
-    async fn serve(
-        self: Arc<Self>,
-        mut stream: <Self::Marker as ProtocolMarker>::RequestStream,
-    ) -> Result<(), Error>;
-
-    /// Returns true if the builtin capability matches the requested `capability`
-    /// and should be served.
-    #[allow(dead_code)]
-    fn matches_routed_capability(&self, capability: &InternalCapability) -> bool;
-}
-
-#[async_trait]
-pub trait ResourceCapability {
-    /// The kind of resource.
-    const KIND: zx::sys::zx_rsrc_kind_t;
-
-    /// Name of the capability. Used for hook registration and logging.
-    const NAME: &'static str;
-
-    /// Service marker for the capability.
-    type Marker: ProtocolMarker;
-
-    fn get_resource_info(self: &Arc<Self>) -> Result<ResourceInfo, Error>;
-
-    async fn server_loop(
-        self: Arc<Self>,
-        mut stream: <Self::Marker as ProtocolMarker>::RequestStream,
-    ) -> Result<(), Error>;
-
-    fn matches_routed_capability(&self, capability: &InternalCapability) -> bool;
-}
-
-#[async_trait]
-impl<R: ResourceCapability + Send + Sync> BuiltinCapability for R {
-    const NAME: &'static str = R::NAME;
-    type Marker = R::Marker;
-
-    async fn serve(
-        self: Arc<Self>,
-        stream: <R::Marker as ProtocolMarker>::RequestStream,
-    ) -> Result<(), Error> {
-        let resource_info = self.get_resource_info()?;
-        if resource_info.kind != R::KIND || resource_info.base != 0 || resource_info.size != 0 {
-            return Err(format_err!("{} not available.", R::NAME));
-        }
-        self.server_loop(stream).await
-    }
-
-    fn matches_routed_capability(&self, capability: &InternalCapability) -> bool {
-        self.matches_routed_capability(capability)
-    }
-}
diff --git a/src/sys/component_manager/src/builtin/fuchsia_boot_resolver.rs b/src/sys/component_manager/src/builtin/fuchsia_boot_resolver.rs
index b6b5d36..55aef6c 100644
--- a/src/sys/component_manager/src/builtin/fuchsia_boot_resolver.rs
+++ b/src/sys/component_manager/src/builtin/fuchsia_boot_resolver.rs
@@ -676,7 +676,8 @@
             Arc::new(ModelContext::new_for_test()),
             Weak::new(),
             "fuchsia-boot:///#meta/root.cm".to_string(),
-        );
+        )
+        .await;
 
         let url = "fuchsia-boot:///#meta/has_config.cm";
         let err =
@@ -719,7 +720,8 @@
             Arc::new(ModelContext::new_for_test()),
             Weak::new(),
             "fuchsia-boot:///#meta/root.cm".to_string(),
-        );
+        )
+        .await;
         test_resolve_error!(resolver, "fuchsia-boot:///#meta/invalid.cm", root, ManifestInvalid);
     }
 }
diff --git a/src/sys/component_manager/src/builtin/log.rs b/src/sys/component_manager/src/builtin/log.rs
index 2502ff3..1bd247e 100644
--- a/src/sys/component_manager/src/builtin/log.rs
+++ b/src/sys/component_manager/src/builtin/log.rs
@@ -17,7 +17,7 @@
 
 impl ReadOnlyLog {
     /// Create a service to provide a read-only version of the kernel log.
-    /// Note that the root resource is passed in here, rather than a read-only log handle to be
+    /// Note that the debuglog resource is passed in here, rather than a read-only log handle to be
     /// duplicated, because a fresh debuglog (LogDispatcher) object needs to be returned for each call.
     /// This is because LogDispatcher holds the implicit read location for reading from the log, so if a
     /// handle to the same object was duplicated, this would mistakenly share read location amongst all
@@ -66,19 +66,19 @@
 #[cfg(test)]
 mod tests {
     use {
-        super::*, fuchsia_async as fasync, fuchsia_component::client::connect_to_protocol,
-        fuchsia_zircon::AsHandleRef,
+        super::*, fidl_fuchsia_kernel as fkernel, fuchsia_async as fasync,
+        fuchsia_component::client::connect_to_protocol, fuchsia_zircon::AsHandleRef,
     };
 
-    async fn get_root_resource() -> Result<zx::Resource, Error> {
-        let root_resource_provider = connect_to_protocol::<fboot::RootResourceMarker>()?;
-        let root_resource_handle = root_resource_provider.get().await?;
-        Ok(zx::Resource::from(root_resource_handle))
+    async fn get_debuglog_resource() -> Result<zx::Resource, Error> {
+        let debuglog_resource_provider = connect_to_protocol::<fkernel::DebuglogResourceMarker>()?;
+        let debuglog_resource_handle = debuglog_resource_provider.get().await?;
+        Ok(zx::Resource::from(debuglog_resource_handle))
     }
 
     #[fuchsia::test]
     async fn has_correct_rights_for_read_only() -> Result<(), Error> {
-        let resource = get_root_resource().await?;
+        let resource = get_debuglog_resource().await?;
         let read_only_log = ReadOnlyLog::new(resource);
         let (proxy, stream) =
             fidl::endpoints::create_proxy_and_stream::<fboot::ReadOnlyLogMarker>()?;
diff --git a/src/sys/component_manager/src/builtin/mod.rs b/src/sys/component_manager/src/builtin/mod.rs
index 7a78de0..98dfb97 100644
--- a/src/sys/component_manager/src/builtin/mod.rs
+++ b/src/sys/component_manager/src/builtin/mod.rs
@@ -2,38 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-pub mod arguments;
 pub mod builtin_resolver;
 pub mod builtin_runner;
-pub mod capability;
-pub mod cpu_resource;
 pub mod crash_introspect;
-pub mod debug_resource;
-pub mod energy_info_resource;
-pub mod factory_items;
-pub mod framebuffer_resource;
 pub mod fuchsia_boot_resolver;
-pub mod hypervisor_resource;
-pub mod info_resource;
-pub mod iommu_resource;
-#[cfg(target_arch = "x86_64")]
-pub mod ioport_resource;
-pub mod irq_resource;
-pub mod items;
-pub mod kernel_stats;
 pub mod log;
-pub mod mexec_resource;
-pub mod mmio_resource;
-pub mod msi_resource;
-pub mod power_resource;
-pub mod profile_resource;
 pub mod realm_builder;
-pub mod root_job;
-pub mod root_resource;
 pub mod runner;
-#[cfg(target_arch = "aarch64")]
-pub mod smc_resource;
 pub mod svc_stash_provider;
 pub mod system_controller;
 pub mod time;
-pub mod vmex_resource;
diff --git a/src/sys/component_manager/src/builtin_environment.rs b/src/sys/component_manager/src/builtin_environment.rs
index 2cfd9a8..89145283 100644
--- a/src/sys/component_manager/src/builtin_environment.rs
+++ b/src/sys/component_manager/src/builtin_environment.rs
@@ -3,51 +3,31 @@
 // found in the LICENSE file.
 
 #[cfg(target_arch = "aarch64")]
-use crate::builtin::smc_resource::SmcResource;
+use builtins::smc_resource::SmcResource;
 
-#[cfg(target_arch = "x86_64")]
-use crate::builtin::ioport_resource::IoportResource;
 use crate::model::component::WeakComponentInstance;
+#[cfg(target_arch = "x86_64")]
+use builtins::ioport_resource::IoportResource;
 
 use {
     crate::{
         bootfs::BootfsSvc,
         builtin::{
-            arguments::Arguments as BootArguments,
             builtin_resolver::{BuiltinResolver, SCHEME as BUILTIN_SCHEME},
-            cpu_resource::CpuResource,
             crash_introspect::CrashIntrospectSvc,
-            debug_resource::DebugResource,
-            energy_info_resource::EnergyInfoResource,
-            factory_items::FactoryItems,
-            framebuffer_resource::FramebufferResource,
             fuchsia_boot_resolver::{FuchsiaBootResolverBuiltinCapability, SCHEME as BOOT_SCHEME},
-            hypervisor_resource::HypervisorResource,
-            info_resource::InfoResource,
-            iommu_resource::IommuResource,
-            irq_resource::IrqResource,
-            items::Items,
-            kernel_stats::KernelStats,
             log::{ReadOnlyLog, WriteOnlyLog},
-            mexec_resource::MexecResource,
-            mmio_resource::MmioResource,
-            msi_resource::MsiResource,
-            power_resource::PowerResource,
-            profile_resource::ProfileResource,
             realm_builder::{
                 RealmBuilderResolver, RealmBuilderRunnerFactory,
                 RUNNER_NAME as REALM_BUILDER_RUNNER_NAME, SCHEME as REALM_BUILDER_SCHEME,
             },
-            root_job::RootJob,
-            root_resource::RootResource,
             runner::{BuiltinRunner, BuiltinRunnerFactory},
             svc_stash_provider::SvcStashCapability,
             system_controller::SystemController,
             time::{create_utc_clock, UtcTimeMaintainer},
-            vmex_resource::VmexResource,
         },
         capability::{BuiltinCapability, CapabilitySource, DerivedCapability, FrameworkCapability},
-        diagnostics::{startup::ComponentEarlyStartupTimeStats, task_metrics::ComponentTreeStats},
+        diagnostics::{lifecycle::ComponentLifecycleTimeStats, task_metrics::ComponentTreeStats},
         framework::{
             binder::BinderFrameworkCapability,
             factory::{FactoryCapabilityHost, FactoryFrameworkCapability},
@@ -88,6 +68,18 @@
         policy::GlobalPolicyChecker,
     },
     anyhow::{format_err, Context as _, Error},
+    builtins::{arguments::Arguments as BootArguments, root_job::RootJob},
+    builtins::{
+        cpu_resource::CpuResource, debug_resource::DebugResource,
+        debuglog_resource::DebuglogResource, energy_info_resource::EnergyInfoResource,
+        factory_items::FactoryItems, framebuffer_resource::FramebufferResource,
+        hypervisor_resource::HypervisorResource, info_resource::InfoResource,
+        iommu_resource::IommuResource, irq_resource::IrqResource, items::Items,
+        kernel_stats::KernelStats, mexec_resource::MexecResource, mmio_resource::MmioResource,
+        msi_resource::MsiResource, power_resource::PowerResource,
+        profile_resource::ProfileResource, root_resource::RootResource,
+        vmex_resource::VmexResource,
+    },
     cm_config::{RuntimeConfig, VmexSource},
     cm_rust::{Availability, RunnerRegistration, UseEventStreamDecl, UseSource},
     cm_types::Name,
@@ -107,7 +99,7 @@
     fuchsia_inspect::{component, health::Reporter, stats::InspectorExt, Inspector},
     fuchsia_runtime::{take_startup_handle, HandleInfo, HandleType},
     fuchsia_zbi::{ZbiParser, ZbiType},
-    fuchsia_zircon::{self as zx, Clock, HandleBased, Resource},
+    fuchsia_zircon::{self as zx, Clock, Resource},
     futures::{future::BoxFuture, FutureExt, StreamExt},
     moniker::{Moniker, MonikerBase},
     std::sync::Arc,
@@ -121,6 +113,11 @@
 // Allow shutdown to take up to an hour.
 pub static SHUTDOWN_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(60 * 60);
 
+// LINT.IfChange
+/// Set the size of the inspect VMO to be 350 KiB.
+const INSPECTOR_SIZE: usize = 350 * 1024;
+// LINT.ThenChange(/src/tests/diagnostics/meta/component_manager_status_tests.cml)
+
 pub struct BuiltinEnvironmentBuilder {
     // TODO(60804): Make component manager's namespace injectable here.
     runtime_config: Option<RuntimeConfig>,
@@ -365,7 +362,7 @@
             boot_resolver,
             realm_builder_resolver,
             self.utc_clock,
-            self.inspector.unwrap_or(component::inspector().clone()),
+            self.inspector.unwrap_or(component::init_inspector_with_size(INSPECTOR_SIZE).clone()),
             self.crash_records,
             capability_passthrough,
         )
@@ -424,17 +421,20 @@
 
         let launch = LaunchTaskOnReceive::new(
             self.top_instance.task_group().as_weak(),
-            name,
+            name.clone(),
             Some((self.policy_checker.clone(), capability_source)),
             Arc::new(move |server_end, _| {
                 task_to_launch(crate::sandbox_util::take_handle_as_stream::<P>(server_end)).boxed()
             }),
         );
 
-        self.input.insert_capability(
+        match self.input.insert_capability(
             &P::PROTOCOL_NAME.parse::<Name>().unwrap(),
             launch.into_router().into(),
-        );
+        ) {
+            Ok(()) => (),
+            Err(e) => warn!("failed to add {name} to root component input: {e:?}"),
+        }
     }
 
     fn add_namespace_protocol(&mut self, protocol: &cm_rust::ProtocolDecl) {
@@ -466,7 +466,10 @@
                 fut.boxed()
             }),
         );
-        self.input.insert_capability(&protocol.name, launch.into_router().into());
+        match self.input.insert_capability(&protocol.name, launch.into_router().into()) {
+            Ok(()) => (),
+            Err(e) => warn!("failed to add {} to root component input: {e:?}", protocol.name),
+        }
     }
 
     fn build(self) -> ComponentInput {
@@ -505,9 +508,8 @@
     // TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
     #[allow(dead_code)]
     pub component_tree_stats: Arc<ComponentTreeStats<DiagnosticsTask>>,
-    // TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
-    #[allow(dead_code)]
-    pub component_startup_time_stats: Arc<ComponentEarlyStartupTimeStats>,
+    // Keeps the inspect node alive.
+    _component_lifecycle_time_stats: Arc<ComponentLifecycleTimeStats>,
     pub debug: bool,
     // TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
     #[allow(dead_code)]
@@ -676,15 +678,26 @@
             );
         }
 
-        // Set up ReadOnlyLog service.
-        let read_only_log = root_resource_handle.as_ref().map(|handle| {
-            ReadOnlyLog::new(
-                handle
-                    .duplicate_handle(zx::Rights::SAME_RIGHTS)
-                    .expect("Failed to duplicate root resource handle"),
-            )
-        });
-        if let Some(read_only_log) = read_only_log {
+        // Set up the ReadOnlyLog service.
+        let debuglog_resource = system_resource_handle
+            .as_ref()
+            .map(|handle| {
+                match handle.create_child(
+                    zx::ResourceKind::SYSTEM,
+                    None,
+                    zx::sys::ZX_RSRC_SYSTEM_DEBUGLOG_BASE,
+                    1,
+                    b"debuglog",
+                ) {
+                    Ok(resource) => Some(resource),
+                    Err(_) => None,
+                }
+            })
+            .flatten();
+
+        if let Some(debuglog_resource) = debuglog_resource {
+            let read_only_log = ReadOnlyLog::new(debuglog_resource);
+
             root_input_builder.add_builtin_protocol_if_enabled::<fboot::ReadOnlyLogMarker>(
                 move |stream| read_only_log.clone().serve(stream).boxed(),
             );
@@ -816,6 +829,28 @@
             );
         }
 
+        // Set up the DebuglogResource service.
+        let debuglog_resource = system_resource_handle
+            .as_ref()
+            .and_then(|handle| {
+                handle
+                    .create_child(
+                        zx::ResourceKind::SYSTEM,
+                        None,
+                        zx::sys::ZX_RSRC_SYSTEM_DEBUGLOG_BASE,
+                        1,
+                        b"debuglog",
+                    )
+                    .ok()
+            })
+            .map(DebuglogResource::new)
+            .and_then(Result::ok);
+        if let Some(debuglog_resource) = debuglog_resource {
+            root_input_builder.add_builtin_protocol_if_enabled::<fkernel::DebuglogResourceMarker>(
+                move |stream| debuglog_resource.clone().serve(stream).boxed(),
+            );
+        }
+
         // Set up the FramebufferResource service.
         let framebuffer_resource = system_resource_handle
             .as_ref()
@@ -1126,10 +1161,9 @@
         component_tree_stats.start_measuring().await;
         model.root().hooks.install(component_tree_stats.hooks()).await;
 
-        let component_startup_time_stats = Arc::new(ComponentEarlyStartupTimeStats::new(
-            inspector.root().create_child("early_start_times"),
-        ));
-        model.root().hooks.install(component_startup_time_stats.hooks()).await;
+        let component_lifecycle_time_stats =
+            Arc::new(ComponentLifecycleTimeStats::new(inspector.root().create_child("lifecycle")));
+        model.root().hooks.install(component_lifecycle_time_stats.hooks()).await;
 
         // Serve stats about inspect in a lazy node.
         inspector.record_lazy_stats();
@@ -1148,7 +1182,7 @@
             event_stream_provider,
             event_logger,
             component_tree_stats,
-            component_startup_time_stats,
+            _component_lifecycle_time_stats: component_lifecycle_time_stats,
             debug,
             num_threads,
             realm_builder_resolver,
@@ -1393,7 +1427,7 @@
                 task_to_launch(crate::sandbox_util::take_handle_as_stream::<P>(server_end)).boxed()
             }),
         );
-        self.root_component_input.insert_capability(&name, launch.into_router().into());
+        self.root_component_input.insert_capability(&name, launch.into_router().into()).unwrap();
     }
 
     #[cfg(test)]
diff --git a/src/sys/component_manager/src/diagnostics/lifecycle.rs b/src/sys/component_manager/src/diagnostics/lifecycle.rs
new file mode 100644
index 0000000..19cc50a
--- /dev/null
+++ b/src/sys/component_manager/src/diagnostics/lifecycle.rs
@@ -0,0 +1,267 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {
+    crate::{
+        model::error::ModelError,
+        model::hooks::{Event, EventPayload, EventType, HasEventType, Hook, HooksRegistration},
+    },
+    async_trait::async_trait,
+    fuchsia_inspect as inspect, fuchsia_inspect_contrib as inspect_contrib,
+    fuchsia_sync::Mutex,
+    fuchsia_zircon as zx,
+    moniker::Moniker,
+    std::sync::{Arc, Weak},
+};
+
+const MAX_NUMBER_OF_LIFECYCLE_EVENTS: usize = 150;
+const MONIKER: &str = "moniker";
+const TYPE: &str = "type";
+const STARTED: &str = "started";
+const STOPPED: &str = "stopped";
+const TIME: &str = "time";
+const EARLY: &str = "early";
+const LATE: &str = "late";
+
+/// Tracks start and stop timestamps of components.
+pub struct ComponentLifecycleTimeStats {
+    // Keeps the inspect node alive.
+    _node: inspect::Node,
+    inner: Mutex<Inner>,
+}
+
+/// `early` maintains the first `MAX_NUMBER_OF_LIFECYCLE_EVENTS` start/stop events of
+/// components. After more than `MAX_NUMBER_OF_LIFECYCLE_EVENTS` events have occurred,
+/// `early` will stay unchanged, and `late` will maintain the the last
+/// `MAX_NUMBER_OF_LIFECYCLE_EVENTS` start/stop events of components. When more events are
+/// added, the earliest ones in `late` will be discarded. This enables our feedback
+/// snapshots to contain a recent history of started and stopped components.
+struct Inner {
+    early: inspect_contrib::nodes::BoundedListNode,
+    late: inspect_contrib::nodes::BoundedListNode,
+}
+
+impl Inner {
+    fn new(early: inspect::Node, late: inspect::Node) -> Self {
+        let early =
+            inspect_contrib::nodes::BoundedListNode::new(early, MAX_NUMBER_OF_LIFECYCLE_EVENTS);
+        let late =
+            inspect_contrib::nodes::BoundedListNode::new(late, MAX_NUMBER_OF_LIFECYCLE_EVENTS);
+        Self { early, late }
+    }
+
+    fn add_entry(&mut self, moniker: &Moniker, kind: &str, time: zx::Time) {
+        let node =
+            if self.early.len() < self.early.capacity() { &mut self.early } else { &mut self.late };
+        node.add_entry(|node| {
+            node.record_string(MONIKER, moniker.to_string());
+            node.record_string(TYPE, kind);
+            node.record_int(TIME, time.into_nanos());
+        });
+    }
+}
+
+impl ComponentLifecycleTimeStats {
+    /// Creates a new startup time tracker. Data will be written to the given inspect node.
+    pub fn new(node: inspect::Node) -> Self {
+        let early = node.create_child(EARLY);
+        let late = node.create_child(LATE);
+        Self { _node: node, inner: Mutex::new(Inner::new(early, late)) }
+    }
+
+    /// Provides the hook events that are needed to work.
+    pub fn hooks(self: &Arc<Self>) -> Vec<HooksRegistration> {
+        vec![HooksRegistration::new(
+            "ComponentLifecycleTimeStats",
+            vec![EventType::Started, EventType::Stopped],
+            Arc::downgrade(self) as Weak<dyn Hook>,
+        )]
+    }
+
+    fn on_component_started(self: &Arc<Self>, moniker: &Moniker, start_time: zx::Time) {
+        self.inner.lock().add_entry(moniker, STARTED, start_time);
+    }
+
+    fn on_component_stopped(self: &Arc<Self>, moniker: &Moniker, stop_time: zx::Time) {
+        self.inner.lock().add_entry(moniker, STOPPED, stop_time);
+    }
+}
+
+#[async_trait]
+impl Hook for ComponentLifecycleTimeStats {
+    async fn on(self: Arc<Self>, event: &Event) -> Result<(), ModelError> {
+        let target_moniker = event
+            .target_moniker
+            .unwrap_instance_moniker_or(ModelError::UnexpectedComponentManagerMoniker)?;
+        match event.event_type() {
+            EventType::Started => {
+                if let EventPayload::Started { runtime, .. } = &event.payload {
+                    self.on_component_started(target_moniker, runtime.start_time);
+                }
+            }
+            EventType::Stopped => {
+                if let EventPayload::Stopped { stop_time, .. } = &event.payload {
+                    self.on_component_stopped(target_moniker, *stop_time);
+                }
+            }
+            _ => {}
+        }
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::model::{
+        component::{ComponentInstance, StartReason},
+        testing::test_helpers::{component_decl_with_test_runner, ActionsTest},
+    };
+    use cm_rust_testing::ComponentDeclBuilder;
+    use diagnostics_assertions::{assert_data_tree, AnyProperty};
+    use fuchsia_inspect::DiagnosticsHierarchyGetter;
+    use itertools::Itertools;
+    use moniker::{ChildName, ChildNameBase, MonikerBase};
+
+    #[fuchsia::test]
+    async fn tracks_events() {
+        let components = vec![
+            ("root", ComponentDeclBuilder::new().child_default("a").build()),
+            ("a", ComponentDeclBuilder::new().child_default("b").build()),
+            ("b", component_decl_with_test_runner()),
+        ];
+        let test = ActionsTest::new("root", components, None).await;
+        let root = test.model.root();
+
+        let inspector = inspect::Inspector::default();
+        let stats =
+            Arc::new(ComponentLifecycleTimeStats::new(inspector.root().create_child("lifecycle")));
+        root.hooks.install(stats.hooks()).await;
+
+        let root_timestamp = start_and_get_timestamp(root, &Moniker::root()).await.into_nanos();
+        let a_timestamp = start_and_get_timestamp(root, &"a".parse().unwrap()).await.into_nanos();
+        let b_timestamp = start_and_get_timestamp(root, &"a/b".parse().unwrap()).await.into_nanos();
+        root.find(&"a/b".parse().unwrap()).await.unwrap().stop().await.unwrap();
+
+        assert_data_tree!(inspector, root: {
+            lifecycle: {
+                early: {
+                    "0": {
+                        moniker: ".",
+                        time: root_timestamp,
+                        "type": "started",
+                    },
+                    "1": {
+                        moniker: "a",
+                        time: a_timestamp,
+                        "type": "started",
+                    },
+                    "2": {
+                        moniker: "a/b",
+                        time: b_timestamp,
+                        "type": "started",
+                    },
+                    "3": contains {
+                        moniker: "a/b",
+                        "type": "stopped",
+                        time: AnyProperty,
+                    }
+                },
+                late: {
+                }
+            }
+        });
+    }
+
+    #[fuchsia::test]
+    async fn early_doesnt_track_more_than_limit() {
+        let inspector = inspect::Inspector::default();
+        let stats =
+            Arc::new(ComponentLifecycleTimeStats::new(inspector.root().create_child("lifecycle")));
+
+        for i in 0..2 * MAX_NUMBER_OF_LIFECYCLE_EVENTS {
+            stats.on_component_started(
+                &Moniker::new(vec![ChildName::parse(format!("{}", i)).unwrap()]),
+                zx::Time::from_nanos(i as i64),
+            );
+        }
+
+        let hierarchy = inspector.get_diagnostics_hierarchy();
+        let node = &hierarchy.children[0];
+        let early = node.children.iter().find_or_first(|c| c.name == "early").unwrap();
+        assert_eq!(early.children.len(), MAX_NUMBER_OF_LIFECYCLE_EVENTS);
+        assert_eq!(
+            early.children.iter().map(|c| c.name.parse::<i32>().unwrap()).sorted().last().unwrap(),
+            149
+        );
+    }
+
+    #[fuchsia::test]
+    async fn early_overflow_to_late() {
+        let inspector = inspect::Inspector::default();
+        let stats =
+            Arc::new(ComponentLifecycleTimeStats::new(inspector.root().create_child("lifecycle")));
+
+        for i in 0..MAX_NUMBER_OF_LIFECYCLE_EVENTS + 1 {
+            stats.on_component_started(
+                &Moniker::new(vec![ChildName::parse(format!("{}", i)).unwrap()]),
+                zx::Time::from_nanos(i as i64),
+            );
+        }
+
+        let hierarchy = inspector.get_diagnostics_hierarchy();
+        let node = &hierarchy.children[0];
+        let early = node.children.iter().find_or_first(|c| c.name == "early").unwrap();
+        let late = node.children.iter().find_or_first(|c| c.name == "late").unwrap();
+        assert_eq!(early.children.len(), MAX_NUMBER_OF_LIFECYCLE_EVENTS);
+        assert_eq!(
+            early.children.iter().map(|c| c.name.parse::<i32>().unwrap()).sorted().last().unwrap(),
+            149
+        );
+        assert_eq!(late.children.len(), 1);
+        assert_data_tree!(late, late: {
+            "0": contains {
+                moniker: "150",
+                "type": "started",
+            }
+        });
+    }
+
+    #[fuchsia::test]
+    async fn late_doesnt_track_more_than_limit() {
+        let inspector = inspect::Inspector::default();
+        let stats =
+            Arc::new(ComponentLifecycleTimeStats::new(inspector.root().create_child("lifecycle")));
+
+        for i in 0..4 * MAX_NUMBER_OF_LIFECYCLE_EVENTS {
+            stats.on_component_started(
+                &Moniker::new(vec![ChildName::parse(format!("{}", i)).unwrap()]),
+                zx::Time::from_nanos(i as i64),
+            );
+        }
+
+        let hierarchy = inspector.get_diagnostics_hierarchy();
+        let node = &hierarchy.children[0];
+        let early = node.children.iter().find_or_first(|c| c.name == "early").unwrap();
+        let late = node.children.iter().find_or_first(|c| c.name == "late").unwrap();
+        assert_eq!(early.children.len(), MAX_NUMBER_OF_LIFECYCLE_EVENTS);
+        assert_eq!(late.children.len(), MAX_NUMBER_OF_LIFECYCLE_EVENTS);
+        assert_eq!(
+            late.children.iter().map(|c| c.name.parse::<i32>().unwrap()).sorted().last().unwrap(),
+            449
+        );
+    }
+
+    async fn start_and_get_timestamp(
+        root_component: &Arc<ComponentInstance>,
+        moniker: &Moniker,
+    ) -> zx::Time {
+        let component = root_component
+            .start_instance(moniker, &StartReason::Root)
+            .await
+            .expect("failed to bind");
+        let state = component.lock_state().await;
+        state.get_started_state().unwrap().timestamp
+    }
+}
diff --git a/src/sys/component_manager/src/diagnostics/mod.rs b/src/sys/component_manager/src/diagnostics/mod.rs
index 7a384db1..c6bd668 100644
--- a/src/sys/component_manager/src/diagnostics/mod.rs
+++ b/src/sys/component_manager/src/diagnostics/mod.rs
@@ -2,5 +2,5 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-pub mod startup;
+pub mod lifecycle;
 pub mod task_metrics;
diff --git a/src/sys/component_manager/src/diagnostics/startup.rs b/src/sys/component_manager/src/diagnostics/startup.rs
deleted file mode 100644
index f648685..0000000
--- a/src/sys/component_manager/src/diagnostics/startup.rs
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use {
-    crate::{
-        model::error::ModelError,
-        model::hooks::{Event, EventPayload, EventType, HasEventType, Hook, HooksRegistration},
-    },
-    async_trait::async_trait,
-    fuchsia_inspect as inspect, fuchsia_zircon as zx,
-    lazy_static::lazy_static,
-    moniker::Moniker,
-    std::sync::{
-        atomic::{AtomicUsize, Ordering},
-        Arc, Weak,
-    },
-};
-
-const MAX_NUMBER_OF_STARTUP_TIME_TRACKED_COMPONENTS: usize = 75;
-
-lazy_static! {
-    static ref MONIKER: inspect::StringReference = "moniker".into();
-    static ref START_TIME: inspect::StringReference = "time".into();
-}
-
-/// Allows to track startup times of components that start early in the boot process (the first
-/// 75 components).
-pub struct ComponentEarlyStartupTimeStats {
-    node: inspect::Node,
-    next_id: AtomicUsize,
-}
-
-impl ComponentEarlyStartupTimeStats {
-    /// Creates a new startup time tracker. Data will be written to the given inspect node.
-    pub fn new(node: inspect::Node) -> Self {
-        Self { node, next_id: AtomicUsize::new(0) }
-    }
-
-    /// Provides the hook events that are needed to work.
-    pub fn hooks(self: &Arc<Self>) -> Vec<HooksRegistration> {
-        vec![HooksRegistration::new(
-            "ComponentEarlyStartupTimeStats",
-            vec![EventType::Started],
-            Arc::downgrade(self) as Weak<dyn Hook>,
-        )]
-    }
-
-    async fn on_component_started(self: &Arc<Self>, moniker: &Moniker, start_time: zx::Time) {
-        let id = self.next_id.fetch_add(1, Ordering::Relaxed);
-        if id >= MAX_NUMBER_OF_STARTUP_TIME_TRACKED_COMPONENTS {
-            return;
-        }
-        self.node.record_child(id.to_string(), |node| {
-            node.record_string(&*MONIKER, moniker.to_string());
-            node.record_int(&*START_TIME, start_time.into_nanos());
-        });
-    }
-}
-
-#[async_trait]
-impl Hook for ComponentEarlyStartupTimeStats {
-    async fn on(self: Arc<Self>, event: &Event) -> Result<(), ModelError> {
-        let target_moniker = event
-            .target_moniker
-            .unwrap_instance_moniker_or(ModelError::UnexpectedComponentManagerMoniker)?;
-        match event.event_type() {
-            EventType::Started => {
-                if let EventPayload::Started { runtime, .. } = &event.payload {
-                    self.on_component_started(target_moniker, runtime.start_time).await;
-                }
-            }
-            _ => {}
-        }
-        Ok(())
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::model::{
-        component::{ComponentInstance, StartReason},
-        testing::test_helpers::{component_decl_with_test_runner, ActionsTest},
-    };
-    use cm_rust_testing::ComponentDeclBuilder;
-    use diagnostics_assertions::assert_data_tree;
-    use fuchsia_inspect::DiagnosticsHierarchyGetter;
-    use moniker::{ChildName, ChildNameBase, MonikerBase};
-
-    #[fuchsia::test]
-    async fn tracks_started_components() {
-        let components = vec![
-            ("root", ComponentDeclBuilder::new().child_default("a").build()),
-            ("a", ComponentDeclBuilder::new().child_default("b").build()),
-            ("b", component_decl_with_test_runner()),
-        ];
-        let test = ActionsTest::new("root", components, None).await;
-        let root = test.model.root();
-
-        let inspector = inspect::Inspector::default();
-        let stats = Arc::new(ComponentEarlyStartupTimeStats::new(
-            inspector.root().create_child("start_times"),
-        ));
-        root.hooks.install(stats.hooks()).await;
-
-        let root_timestamp = start_and_get_timestamp(root, Moniker::root()).await.into_nanos();
-        let a_timestamp =
-            start_and_get_timestamp(root, vec!["a"].try_into().unwrap()).await.into_nanos();
-        let b_timestamp =
-            start_and_get_timestamp(root, vec!["a", "b"].try_into().unwrap()).await.into_nanos();
-
-        assert_data_tree!(inspector, root: {
-            start_times: {
-                "0": {
-                    moniker: ".",
-                    time: root_timestamp,
-                },
-                "1": {
-                    moniker: "a",
-                    time: a_timestamp,
-                },
-                "2": {
-                    moniker: "a/b",
-                    time: b_timestamp,
-                }
-            }
-        });
-    }
-
-    #[fuchsia::test]
-    async fn doesnt_track_more_than_75_components() {
-        let inspector = inspect::Inspector::default();
-        let stats = Arc::new(ComponentEarlyStartupTimeStats::new(
-            inspector.root().create_child("start_times"),
-        ));
-
-        for i in 0..2 * MAX_NUMBER_OF_STARTUP_TIME_TRACKED_COMPONENTS {
-            stats
-                .on_component_started(
-                    &Moniker::new(vec![ChildName::parse(format!("{}", i)).unwrap()]),
-                    zx::Time::from_nanos(i as i64),
-                )
-                .await;
-        }
-
-        let hierarchy = inspector.get_diagnostics_hierarchy();
-        let child_count = hierarchy.children[0].children.len();
-        assert_eq!(child_count, MAX_NUMBER_OF_STARTUP_TIME_TRACKED_COMPONENTS);
-    }
-
-    async fn start_and_get_timestamp(
-        root_component: &Arc<ComponentInstance>,
-        moniker: Moniker,
-    ) -> zx::Time {
-        let component = root_component
-            .start_instance(&moniker, &StartReason::Root)
-            .await
-            .expect("failed to bind");
-        let state = component.lock_state().await;
-        state.get_started_state().unwrap().timestamp
-    }
-}
diff --git a/src/sys/component_manager/src/framework/controller.rs b/src/sys/component_manager/src/framework/controller.rs
index 05b0a30..dd2168e 100644
--- a/src/sys/component_manager/src/framework/controller.rs
+++ b/src/sys/component_manager/src/framework/controller.rs
@@ -149,7 +149,7 @@
                 }
                 let component = component.unwrap();
                 let mut action_set = component.lock_actions().await;
-                let _ = action_set.register_no_wait(&component, StopAction::new(false));
+                let _ = action_set.register_no_wait(&component, StopAction::new(false)).await;
             }
             fcomponent::ExecutionControllerRequest::_UnknownMethod { ordinal, .. } => {
                 warn!(%ordinal, "fuchsia.component/ExecutionController received unknown method");
diff --git a/src/sys/component_manager/src/framework/factory.rs b/src/sys/component_manager/src/framework/factory.rs
index e95d24e..84188b1 100644
--- a/src/sys/component_manager/src/framework/factory.rs
+++ b/src/sys/component_manager/src/framework/factory.rs
@@ -11,12 +11,12 @@
     async_trait::async_trait,
     cm_types::Name,
     cm_util::TaskGroup,
-    fidl::endpoints::{ClientEnd, DiscoverableProtocolMarker, ServerEnd},
-    fidl_fuchsia_component_sandbox as fsandbox, fidl_fuchsia_io as fio, fuchsia_zircon as zx,
-    fuchsia_zircon::AsHandleRef,
+    fidl::endpoints::{self, ClientEnd, DiscoverableProtocolMarker, ServerEnd},
+    fidl_fuchsia_component_sandbox as fsandbox, fidl_fuchsia_io as fio,
+    fuchsia_zircon::{self as zx, AsHandleRef},
     futures::prelude::*,
     lazy_static::lazy_static,
-    sandbox::{Dict, Directory, Open, Receiver},
+    sandbox::{Dict, Directory, Receiver},
     std::sync::Arc,
     tracing::warn,
 };
@@ -79,17 +79,13 @@
 
     async fn handle_request(&self, request: fsandbox::FactoryRequest) -> Result<(), fidl::Error> {
         match request {
-            fsandbox::FactoryRequest::CreateSender { receiver, sender, responder } => {
-                self.create_sender(receiver, sender);
-                responder.send()?;
+            fsandbox::FactoryRequest::CreateSender { receiver, responder } => {
+                let client_end = self.create_sender(receiver);
+                responder.send(client_end)?;
             }
-            fsandbox::FactoryRequest::CreateDictionary { server_end, responder } => {
-                self.create_dictionary(server_end);
-                responder.send()?;
-            }
-            fsandbox::FactoryRequest::CreateOpen { client_end, server_end, responder } => {
-                self.create_open(client_end, server_end);
-                responder.send()?;
+            fsandbox::FactoryRequest::CreateDictionary { responder } => {
+                let client_end = self.create_dictionary();
+                responder.send(client_end)?;
             }
             fsandbox::FactoryRequest::CreateDirectory { client_end, responder } => {
                 let capability = self.create_directory(client_end);
@@ -105,24 +101,15 @@
     fn create_sender(
         &self,
         receiver_client: ClientEnd<fsandbox::ReceiverMarker>,
-        sender_server: ServerEnd<fsandbox::SenderMarker>,
-    ) {
+    ) -> ClientEnd<fsandbox::SenderMarker> {
+        let (sender_client, sender_server) = endpoints::create_endpoints();
         let (receiver, sender) = Receiver::new();
         self.tasks.spawn(async move {
             receiver.handle_receiver(receiver_client.into_proxy().unwrap()).await;
         });
         let sender_client_end_koid = sender_server.basic_info().unwrap().related_koid;
         sender.serve_and_register(sender_server.into_stream().unwrap(), sender_client_end_koid);
-    }
-
-    fn create_open(
-        &self,
-        openable_client: ClientEnd<fio::OpenableMarker>,
-        openable_server: ServerEnd<fio::OpenableMarker>,
-    ) {
-        let open: Open = openable_client.into();
-        let client_end_koid = openable_server.basic_info().unwrap().related_koid;
-        open.serve_and_register(openable_server.into_stream().unwrap(), client_end_koid);
+        sender_client
     }
 
     fn create_directory(
@@ -135,10 +122,12 @@
         fsandbox::Capability::Directory(client_end)
     }
 
-    fn create_dictionary(&self, server_end: ServerEnd<fsandbox::DictionaryMarker>) {
+    fn create_dictionary(&self) -> ClientEnd<fsandbox::DictionaryMarker> {
+        let (client_end, server_end) = endpoints::create_endpoints();
         let dict = Dict::new();
         let client_end_koid = server_end.basic_info().unwrap().related_koid;
         dict.serve_and_register(server_end.into_stream().unwrap(), client_end_koid);
+        client_end
     }
 }
 
@@ -170,7 +159,6 @@
 mod tests {
     use super::*;
     use {
-        fidl::endpoints,
         fidl_fuchsia_io as fio, fuchsia_async as fasync,
         fuchsia_zircon::{self as zx},
     };
@@ -186,15 +174,14 @@
             host.serve(stream).await.unwrap();
         });
 
-        let (sender_proxy, sender_server_end) =
-            endpoints::create_proxy::<fsandbox::SenderMarker>().unwrap();
         let (receiver_client_end, mut receiver_stream) =
             endpoints::create_request_stream::<fsandbox::ReceiverMarker>().unwrap();
-        let () = factory_proxy.create_sender(receiver_client_end, sender_server_end).await.unwrap();
+        let sender = factory_proxy.create_sender(receiver_client_end).await.unwrap();
+        let sender = sender.into_proxy().unwrap();
 
         let (ch1, _ch2) = zx::Channel::create();
         let expected_koid = ch1.get_koid().unwrap();
-        sender_proxy.send_(ch1).unwrap();
+        sender.send_(ch1).unwrap();
 
         let request = receiver_stream.try_next().await.unwrap().unwrap();
         if let fsandbox::ReceiverRequest::Receive { channel, .. } = request {
@@ -225,7 +212,7 @@
     }
 
     #[fuchsia::test]
-    async fn create_dict() {
+    async fn create_dictionary() {
         let mut tasks = fasync::TaskGroup::new();
 
         let host = FactoryCapabilityHost::new();
@@ -235,12 +222,11 @@
             host.serve(stream).await.unwrap();
         });
 
-        let (dict_proxy, server_end) =
-            endpoints::create_proxy::<fsandbox::DictionaryMarker>().unwrap();
-        let () = factory_proxy.create_dictionary(server_end).await.unwrap();
+        let dict = factory_proxy.create_dictionary().await.unwrap();
+        let dict = dict.into_proxy().unwrap();
 
         // The dictionary is empty.
-        let items = dict_proxy.read().await.unwrap();
+        let items = dict.read().await.unwrap();
         assert_eq!(items.len(), 0);
     }
 }
diff --git a/src/sys/component_manager/src/framework/introspector.rs b/src/sys/component_manager/src/framework/introspector.rs
index 8fd9ddd..74e2be2 100644
--- a/src/sys/component_manager/src/framework/introspector.rs
+++ b/src/sys/component_manager/src/framework/introspector.rs
@@ -121,6 +121,9 @@
         lazy_static! {
             static ref MEMORY_MONITOR: Moniker =
                 Moniker::parse_str("/core/memory_monitor").unwrap();
+            /// Moniker for integration tests.
+            static ref RECEIVER: Moniker =
+                Moniker::parse_str("receiver").unwrap();
         };
         // TODO(https://fxbug.dev/318904493): Temporary workaround to prevent other components from
         // using `Introspector` while improvements to framework capability allowlists are under way.
@@ -131,7 +134,10 @@
         // realm, then exposed from `/`.
         //
         // All other cases are disallowed.
-        if target.moniker != *MEMORY_MONITOR && !target.moniker.is_root() {
+        if target.moniker != *MEMORY_MONITOR
+            && target.moniker != *RECEIVER
+            && !target.moniker.is_root()
+        {
             return Box::new(AccessDeniedCapabilityProvider {
                 target,
                 source_moniker: scope.moniker,
diff --git a/src/sys/component_manager/src/framework/lifecycle_controller.rs b/src/sys/component_manager/src/framework/lifecycle_controller.rs
index a862057..172ae64 100644
--- a/src/sys/component_manager/src/framework/lifecycle_controller.rs
+++ b/src/sys/component_manager/src/framework/lifecycle_controller.rs
@@ -293,7 +293,7 @@
     use {
         super::*,
         crate::model::{
-            actions::test_utils::{is_discovered, is_resolved},
+            actions::test_utils::{is_discovered, is_resolved, is_shutdown},
             testing::test_helpers::TestEnvironmentBuilder,
         },
         cm_rust_testing::ComponentDeclBuilder,
@@ -310,7 +310,7 @@
                 "root",
                 ComponentDeclBuilder::new()
                     .child(cm_rust::ChildDecl {
-                        name: "a".to_string(),
+                        name: "a".parse().unwrap(),
                         url: "test:///a".to_string(),
                         startup: fdecl::StartupMode::Eager,
                         environment: None,
@@ -318,7 +318,7 @@
                         config_overrides: None,
                     })
                     .child(cm_rust::ChildDecl {
-                        name: "cant-resolve".to_string(),
+                        name: "cant-resolve".parse().unwrap(),
                         url: "cant-resolve://cant-resolve".to_string(),
                         startup: fdecl::StartupMode::Eager,
                         environment: None,
@@ -331,7 +331,7 @@
                 "a",
                 ComponentDeclBuilder::new()
                     .child(cm_rust::ChildDecl {
-                        name: "b".to_string(),
+                        name: "b".parse().unwrap(),
                         url: "test:///b".to_string(),
                         startup: fdecl::StartupMode::Eager,
                         environment: None,
@@ -386,7 +386,7 @@
                 "root",
                 ComponentDeclBuilder::new()
                     .child(cm_rust::ChildDecl {
-                        name: "a".to_string(),
+                        name: "a".parse().unwrap(),
                         url: "test:///a".to_string(),
                         startup: fdecl::StartupMode::Eager,
                         environment: None,
@@ -399,7 +399,7 @@
                 "a",
                 ComponentDeclBuilder::new()
                     .child(cm_rust::ChildDecl {
-                        name: "b".to_string(),
+                        name: "b".parse().unwrap(),
                         url: "test:///b".to_string(),
                         startup: fdecl::StartupMode::Eager,
                         environment: None,
@@ -437,8 +437,9 @@
         assert!(is_resolved(&component_b).await);
 
         lifecycle_proxy.unresolve_instance(".").await.unwrap().unwrap();
-        assert!(is_discovered(&component_a).await);
-        assert!(is_discovered(&component_b).await);
+        assert!(is_discovered(&root).await);
+        assert!(is_shutdown(&component_a).await);
+        assert!(is_shutdown(&component_b).await);
 
         assert_eq!(
             lifecycle_proxy.unresolve_instance("./nonesuch").await.unwrap(),
@@ -447,8 +448,9 @@
 
         // Unresolve again, which is ok because UnresolveAction is idempotent.
         assert_eq!(lifecycle_proxy.unresolve_instance(".").await.unwrap(), Ok(()));
-        assert!(is_discovered(&component_a).await);
-        assert!(is_discovered(&component_b).await);
+        assert!(is_discovered(&root).await);
+        assert!(is_shutdown(&component_a).await);
+        assert!(is_shutdown(&component_b).await);
     }
 
     #[fuchsia::test]
@@ -506,7 +508,10 @@
             lifecycle_proxy
                 .destroy_instance(
                     "./",
-                    &ChildRef { name: "child".to_string(), collection: Some("coll".to_string()) }
+                    &ChildRef {
+                        name: "child".parse().unwrap(),
+                        collection: Some("coll".to_string())
+                    }
                 )
                 .await
                 .unwrap(),
diff --git a/src/sys/component_manager/src/framework/namespace.rs b/src/sys/component_manager/src/framework/namespace.rs
index 1ed6d0f..6fd4fab 100644
--- a/src/sys/component_manager/src/framework/namespace.rs
+++ b/src/sys/component_manager/src/framework/namespace.rs
@@ -219,7 +219,8 @@
             // Create a dictionary and add the Sender to it.
             let mut dict = Dict::new();
             dict.lock_entries()
-                .insert(fecho::EchoMarker::DEBUG_NAME.parse().unwrap(), Capability::Sender(sender));
+                .insert(fecho::EchoMarker::DEBUG_NAME.parse().unwrap(), Capability::Sender(sender))
+                .expect("dict entry already exists");
 
             let (dict_proxy, stream) =
                 endpoints::create_proxy_and_stream::<fsandbox::DictionaryMarker>().unwrap();
@@ -283,7 +284,8 @@
             // Create a dictionary and add the Sender to it.
             let mut dict = Dict::new();
             dict.lock_entries()
-                .insert(fecho::EchoMarker::DEBUG_NAME.parse().unwrap(), Capability::Sender(sender));
+                .insert(fecho::EchoMarker::DEBUG_NAME.parse().unwrap(), Capability::Sender(sender))
+                .expect("dict entry already exists");
 
             let (dict_proxy, stream) =
                 endpoints::create_proxy_and_stream::<fsandbox::DictionaryMarker>().unwrap();
diff --git a/src/sys/component_manager/src/framework/realm.rs b/src/sys/component_manager/src/framework/realm.rs
index 85220d9..6d394e1 100644
--- a/src/sys/component_manager/src/framework/realm.rs
+++ b/src/sys/component_manager/src/framework/realm.rs
@@ -367,19 +367,17 @@
         ) -> Self {
             // Init model.
             let config = RuntimeConfig { list_children_batch_size: 2, ..Default::default() };
+            let hook = Arc::new(TestHook::new());
             let TestModelResult { model, builtin_environment, mock_runner, .. } =
                 TestEnvironmentBuilder::new()
                     .set_runtime_config(config)
                     .set_components(components)
+                    // Install TestHook at the front so that when we receive an event the hook has
+                    // already run so the result is reflected in its printout
+                    .set_front_hooks(hook.hooks())
                     .build()
                     .await;
 
-            let hook = Arc::new(TestHook::new());
-            let hooks = hook.hooks();
-            // Install TestHook at the front so that when we receive an event the hook has already
-            // run so the result is reflected in its printout
-            model.root().hooks.install_front(hooks).await;
-
             // Look up and start component.
             let component = model
                 .root()
@@ -1113,7 +1111,7 @@
         let child = {
             let state = test.component().lock_resolved_state().await.unwrap();
             let child = state.children().next().unwrap();
-            assert_eq!("a", child.0.name());
+            assert_eq!("a", child.0.name().as_str());
             child.1.clone()
         };
 
diff --git a/src/sys/component_manager/src/framework/route_validator.rs b/src/sys/component_manager/src/framework/route_validator.rs
index fb832e2..5febcf6 100644
--- a/src/sys/component_manager/src/framework/route_validator.rs
+++ b/src/sys/component_manager/src/framework/route_validator.rs
@@ -944,7 +944,7 @@
         let offer_from_collection_decl = OfferBuilder::service()
             .name("my_service")
             .source(OfferSource::Collection("coll".parse().unwrap()))
-            .target(OfferTarget::static_child("target".into()))
+            .target_static_child("target")
             .build();
         let expose_from_self_decl =
             ExposeBuilder::service().name("my_service").source(ExposeSource::Self_).build();
diff --git a/src/sys/component_manager/src/model/actions/destroy.rs b/src/sys/component_manager/src/model/actions/destroy.rs
index 5196512..ec0e49e 100644
--- a/src/sys/component_manager/src/model/actions/destroy.rs
+++ b/src/sys/component_manager/src/model/actions/destroy.rs
@@ -35,8 +35,8 @@
 
 #[async_trait]
 impl Action for DestroyAction {
-    async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
-        do_destroy(component).await.map_err(Into::into)
+    async fn handle(self, component: Arc<ComponentInstance>) -> Result<(), ActionError> {
+        do_destroy(&component).await.map_err(Into::into)
     }
     fn key(&self) -> ActionKey {
         ActionKey::Destroy
@@ -112,19 +112,22 @@
         let start_shutdown;
         {
             let actions = component.lock_actions().await;
-            resolve_shutdown = wait(actions.wait(ResolveAction::new()));
-            start_shutdown = wait(actions.wait(StartAction::new(
-                StartReason::Debug,
-                None,
-                IncomingCapabilities::default(),
-            )));
+            resolve_shutdown = wait(actions.wait(ResolveAction::new()).await);
+            start_shutdown = wait(
+                actions
+                    .wait(StartAction::new(
+                        StartReason::Debug,
+                        None,
+                        IncomingCapabilities::default(),
+                    ))
+                    .await,
+            );
         }
         let execution_scope = &component.execution_scope;
         execution_scope.shutdown();
         join_all([
             pin!(resolve_shutdown) as Pin<&mut (dyn Future<Output = ()> + Send)>,
             pin!(start_shutdown),
-            pin!(component.blocking_task_group().join()),
             pin!(execution_scope.wait()),
         ])
         .await;
@@ -346,7 +349,7 @@
 
     #[async_trait]
     impl Action for MockAction {
-        async fn handle(mut self, _: &Arc<ComponentInstance>) -> Result<(), ActionError> {
+        async fn handle(mut self, _: Arc<ComponentInstance>) -> Result<(), ActionError> {
             self.rx.next().await.unwrap();
             self.result
         }
@@ -383,7 +386,7 @@
         // Spawn a mock action on 'a' that stalls
         {
             let mut actions = component_a.lock_actions().await;
-            let _ = actions.register_no_wait(&component_a, mock_action);
+            let _ = actions.register_no_wait(&component_a, mock_action).await;
         }
 
         // Spawn a task to destroy the child `a` under root.
@@ -396,7 +399,7 @@
         // Check that the destroy action is waiting on the mock action.
         loop {
             let actions = component_a.lock_actions().await;
-            assert!(actions.contains(&mock_action_key));
+            assert!(actions.contains(mock_action_key).await);
 
             // Check the reference count on the notifier of the mock action
             let rx = &actions.rep[&mock_action_key];
@@ -406,7 +409,7 @@
             // - 1 for the ActionSet that owns the notifier
             // - 1 for destroy action to wait on the mock action
             if refcount == 2 {
-                assert!(actions.contains(&ActionKey::Destroy));
+                assert!(actions.contains(ActionKey::Destroy).await);
                 break;
             }
 
@@ -472,14 +475,16 @@
         let (mut task_start_tx, mut task_start_rx) = mpsc::channel::<()>(0);
         let (mut task_done_tx, mut task_done_rx) = mpsc::channel::<()>(0);
         let a = component_a.clone();
+        let guard = component_a.execution_scope.active_guard();
         let fut = async move {
+            let _guard = guard;
             task_start_rx.next().await;
             if matches!(*a.lock_state().await, InstanceState::Destroyed) {
                 panic!("component state was set to destroyed before blocking task finished");
             }
             task_done_tx.try_send(()).unwrap();
         };
-        component_a.blocking_task_group().spawn(fut);
+        component_a.execution_scope.spawn(fut);
 
         let mock_action_key = ActionKey::Start;
         let (mock_action, mut mock_action_unblocker) =
@@ -488,7 +493,7 @@
         // Spawn a mock action on 'a' that stalls
         {
             let mut actions = component_a.lock_actions().await;
-            let _ = actions.register_no_wait(&component_a, mock_action);
+            let _ = actions.register_no_wait(&component_a, mock_action).await;
         }
 
         // Spawn a task to destroy the child `a` under root.
@@ -501,7 +506,7 @@
         // Check that the destroy action is waiting on the mock action.
         loop {
             let actions = component_a.lock_actions().await;
-            assert!(actions.contains(&mock_action_key));
+            assert!(actions.contains(mock_action_key).await);
 
             // Check the reference count on the notifier of the mock action
             let rx = &actions.rep[&mock_action_key];
@@ -511,7 +516,7 @@
             // - 1 for the ActionSet that owns the notifier
             // - 1 for destroy action to wait on the mock action
             if refcount == 2 {
-                assert!(actions.contains(&ActionKey::Destroy));
+                assert!(actions.contains(ActionKey::Destroy).await);
                 break;
             }
 
diff --git a/src/sys/component_manager/src/model/actions/discover.rs b/src/sys/component_manager/src/model/actions/discover.rs
index 9d43fe3..a5d208d 100644
--- a/src/sys/component_manager/src/model/actions/discover.rs
+++ b/src/sys/component_manager/src/model/actions/discover.rs
@@ -30,8 +30,8 @@
 
 #[async_trait]
 impl Action for DiscoverAction {
-    async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
-        do_discover(component, self.component_input).await.map_err(Into::into)
+    async fn handle(self, component: Arc<ComponentInstance>) -> Result<(), ActionError> {
+        do_discover(&component, self.component_input).await.map_err(Into::into)
     }
     fn key(&self) -> ActionKey {
         ActionKey::Discover
diff --git a/src/sys/component_manager/src/model/actions/mod.rs b/src/sys/component_manager/src/model/actions/mod.rs
index 6bea4f1..b5e1ac3 100644
--- a/src/sys/component_manager/src/model/actions/mod.rs
+++ b/src/sys/component_manager/src/model/actions/mod.rs
@@ -91,7 +91,7 @@
 #[async_trait]
 pub trait Action: Send + Sync + 'static {
     /// Run the action.
-    async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError>;
+    async fn handle(self, component: Arc<ComponentInstance>) -> Result<(), ActionError>;
 
     /// `key` identifies the action.
     fn key(&self) -> ActionKey;
@@ -202,8 +202,8 @@
         ActionSet { rep: HashMap::new(), history: HashSet::new(), passive_waiters: HashMap::new() }
     }
 
-    pub fn contains(&self, key: &ActionKey) -> bool {
-        self.rep.contains_key(key)
+    pub async fn contains(&self, key: ActionKey) -> bool {
+        self.rep.contains_key(&key)
     }
 
     #[cfg(test)]
@@ -221,7 +221,7 @@
     /// performing an action with the given key. The oneshot will receive a message immediately if
     /// the component has ever finished such an action. Does not cause any new actions to be
     /// started.
-    pub fn wait_for_action(&mut self, action_key: ActionKey) -> oneshot::Receiver<()> {
+    pub async fn wait_for_action(&mut self, action_key: ActionKey) -> oneshot::Receiver<()> {
         let (sender, receiver) = oneshot::channel();
         if self.history.contains(&action_key) {
             sender.send(()).unwrap();
@@ -243,7 +243,7 @@
     {
         let rx = {
             let mut actions = component.lock_actions().await;
-            actions.register_no_wait(&component, action)
+            actions.register_no_wait(&component, action).await
         };
         rx.await
     }
@@ -253,7 +253,7 @@
     /// already registered.
     ///
     /// REQUIRES: `self` is the `ActionSet` contained in `component`.
-    pub fn register_no_wait<A>(
+    pub async fn register_no_wait<A>(
         &mut self,
         component: &Arc<ComponentInstance>,
         action: A,
@@ -269,7 +269,7 @@
     }
 
     /// Returns a future that waits for the given action to complete, if one exists.
-    pub fn wait<A>(&self, action: A) -> Option<impl Future<Output = Result<(), ActionError>>>
+    pub async fn wait<A>(&self, action: A) -> Option<impl Future<Output = Result<(), ActionError>>>
     where
         A: Action,
     {
@@ -321,7 +321,7 @@
             }
             _ = join_all(prereqs).await;
             let key = action.key();
-            let res = action.handle(&component).await;
+            let res = action.handle(component.clone()).await;
             Self::finish(&component, &key).await;
             res
         }
@@ -522,4 +522,9 @@
         let state = component.lock_state().await;
         matches!(*state, InstanceState::Unresolved(_))
     }
+
+    pub async fn is_shutdown(component: &ComponentInstance) -> bool {
+        let state = component.lock_state().await;
+        matches!(*state, InstanceState::Shutdown(_, _))
+    }
 }
diff --git a/src/sys/component_manager/src/model/actions/resolve/mod.rs b/src/sys/component_manager/src/model/actions/resolve/mod.rs
index a0c3924..380bcc7 100644
--- a/src/sys/component_manager/src/model/actions/resolve/mod.rs
+++ b/src/sys/component_manager/src/model/actions/resolve/mod.rs
@@ -17,29 +17,41 @@
     ::routing::{component_instance::ComponentInstanceInterface, resolving::ComponentAddress},
     async_trait::async_trait,
     cm_util::io::clone_dir,
+    cm_util::{AbortError, AbortHandle, AbortableScope},
     std::{ops::DerefMut, sync::Arc},
 };
 
 /// Resolves a component instance's declaration and initializes its state.
-pub struct ResolveAction {}
+pub struct ResolveAction {
+    abort_handle: AbortHandle,
+    abortable_scope: AbortableScope,
+}
 
 impl ResolveAction {
     pub fn new() -> Self {
-        Self {}
+        let (abortable_scope, abort_handle) = AbortableScope::new();
+        Self { abort_handle, abortable_scope }
     }
 }
 
 #[async_trait]
 impl Action for ResolveAction {
-    async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
-        do_resolve(component).await.map_err(Into::into)
+    async fn handle(self, component: Arc<ComponentInstance>) -> Result<(), ActionError> {
+        do_resolve(&component, self.abortable_scope).await.map_err(Into::into)
     }
     fn key(&self) -> ActionKey {
         ActionKey::Resolve
     }
+
+    fn abort_handle(&self) -> Option<AbortHandle> {
+        Some(self.abort_handle.clone())
+    }
 }
 
-async fn do_resolve(component: &Arc<ComponentInstance>) -> Result<(), ResolveActionError> {
+async fn do_resolve(
+    component: &Arc<ComponentInstance>,
+    abortable_scope: AbortableScope,
+) -> Result<(), ResolveActionError> {
     {
         let state = component.lock_state().await;
         if state.is_shut_down() {
@@ -51,7 +63,7 @@
     // Ensure `Resolved` is dispatched after `Discovered`.
     {
         let discover_completed =
-            component.lock_actions().await.wait_for_action(ActionKey::Discover);
+            component.lock_actions().await.wait_for_action(ActionKey::Discover).await;
         discover_completed.await.unwrap();
     }
     let result = async move {
@@ -84,12 +96,21 @@
                     err,
                 }
             })?;
-        let component_info =
-            component.environment.resolve(&component_address).await.map_err(|err| {
-                ResolveActionError::ResolverError { url: component.component_url.clone(), err }
-            })?;
-        let component_info =
-            Component::resolve_with_config(component_info, component.config_parent_overrides())?;
+        let component_info = abortable_scope
+            .run(async {
+                let component_info =
+                    component.environment.resolve(&component_address).await.map_err(|err| {
+                        ResolveActionError::ResolverError {
+                            url: component.component_url.clone(),
+                            err,
+                        }
+                    })?;
+                Component::resolve_with_config(component_info, component.config_parent_overrides())
+            })
+            .await
+            .map_err(|_: AbortError| ResolveActionError::Aborted {
+                moniker: component.moniker.clone(),
+            })??;
         let policy = component.context.abi_revision_policy();
         policy
             .check_compatibility(
@@ -168,7 +189,8 @@
         crate::model::{
             actions::test_utils::{is_resolved, is_stopped},
             actions::{
-                ActionSet, ResolveAction, ShutdownAction, ShutdownType, StartAction, StopAction,
+                Action, ActionSet, ResolveAction, ShutdownAction, ShutdownType, StartAction,
+                StopAction,
             },
             component::{IncomingCapabilities, StartReason},
             error::{ActionError, ResolveActionError},
@@ -176,16 +198,10 @@
         },
         assert_matches::assert_matches,
         cm_rust_testing::ComponentDeclBuilder,
+        futures::{channel::oneshot, FutureExt},
         moniker::{Moniker, MonikerBase},
     };
 
-    /// Check unresolve for _nonrecursive_ case. The system has a root with the child `a` and `a`
-    /// has descendants as shown in the diagram below.
-    ///  a
-    ///   \
-    ///    b
-    ///
-    /// Also tests UnresolveAction on InstanceState::Unresolved.
     #[fuchsia::test]
     async fn resolve_action_test() {
         let components = vec![
@@ -228,4 +244,43 @@
         assert!(!is_resolved(&component_a).await);
         assert!(is_stopped(&component_root, &"a".try_into().unwrap()).await);
     }
+
+    /// Tests that a resolve action can be cancelled while it's waiting on the resolver.
+    #[fuchsia::test]
+    async fn cancel_resolve_test() {
+        let components = vec![
+            ("root", ComponentDeclBuilder::new().child_default("a").build()),
+            ("a", component_decl_with_test_runner()),
+        ];
+
+        let test = ActionsTest::new("root", components, None).await;
+
+        let (resolved_tx, resolved_rx) = oneshot::channel::<()>();
+        let (_continue_tx, continue_rx) = oneshot::channel::<()>();
+        test.resolver.add_blocker("a", resolved_tx, continue_rx).await;
+
+        let component_root = test.look_up(Moniker::root()).await;
+        let component_a = component_root.find(&vec!["a"].try_into().unwrap()).await.unwrap();
+        let resolve_action = ResolveAction::new();
+        let resolve_abort_handle = resolve_action.abort_handle().unwrap();
+        let resolve_fut =
+            component_a.lock_actions().await.register_no_wait(&component_a, resolve_action).await;
+        let resolve_fut_2 =
+            component_a.lock_actions().await.wait(ResolveAction::new()).await.unwrap();
+
+        // Wait until routing reaches resolution.
+        let _ = resolved_rx.await.unwrap();
+
+        // Resolution should not be finished yet.
+        assert!(resolve_fut_2.now_or_never().is_none());
+
+        // Cancel the resolve action.
+        resolve_abort_handle.abort();
+
+        // We should now see the abort error from the action.
+        assert_matches!(
+            resolve_fut.await,
+            Err(ActionError::ResolveError { err: ResolveActionError::Aborted { .. } })
+        );
+    }
 }
diff --git a/src/sys/component_manager/src/model/actions/resolve/sandbox_construction.rs b/src/sys/component_manager/src/model/actions/resolve/sandbox_construction.rs
index f754eea..22d09ad 100644
--- a/src/sys/component_manager/src/model/actions/resolve/sandbox_construction.rs
+++ b/src/sys/component_manager/src/model/actions/resolve/sandbox_construction.rs
@@ -9,6 +9,7 @@
             component::instance::ResolvedInstanceState,
             component::{ComponentInstance, WeakComponentInstance},
             routing::router::{Request, Router},
+            routing::router_ext::RouterExt,
             structured_dict::{ComponentEnvironment, ComponentInput, StructuredDictMap},
         },
         sandbox_util::{DictExt, LaunchTaskOnReceive, RoutableExt},
@@ -48,10 +49,12 @@
     let declared_dictionaries = Dict::new();
 
     for environment_decl in &decl.environments {
-        environments.insert(
-            Name::new(&environment_decl.name).unwrap(),
-            build_environment(component, children, component_input, environment_decl),
-        );
+        environments
+            .insert(
+                Name::new(&environment_decl.name).unwrap(),
+                build_environment(component, children, component_input, environment_decl),
+            )
+            .ok();
     }
 
     for child in &decl.children {
@@ -65,7 +68,8 @@
             environment = component_input.environment();
         }
         let input = ComponentInput::new(environment);
-        child_inputs.insert(Name::new(&child.name).unwrap(), input);
+        let name = Name::new(child.name.as_str()).expect("child is static so name is not long");
+        child_inputs.insert(name, input).ok();
     }
 
     for collection in &decl.collections {
@@ -79,7 +83,7 @@
             environment = component_input.environment();
         }
         let input = ComponentInput::new(environment);
-        collection_inputs.insert(collection.name.clone(), input);
+        collection_inputs.insert(collection.name.clone(), input).ok();
     }
 
     for capability in &decl.capabilities {
@@ -106,9 +110,10 @@
         let mut target_dict = match offer.target() {
             cm_rust::OfferTarget::Child(child_ref) => {
                 assert!(child_ref.collection.is_none(), "unexpected dynamic offer target");
-                let child_name = Name::new(&child_ref.name).unwrap();
+                let child_name = Name::new(child_ref.name.as_str())
+                    .expect("child is static so name is not long");
                 if child_inputs.get(&child_name).is_none() {
-                    child_inputs.insert(child_name.clone(), Default::default());
+                    child_inputs.insert(child_name.clone(), Default::default()).ok();
                 }
                 child_inputs
                     .get(&child_name)
@@ -117,16 +122,20 @@
             }
             cm_rust::OfferTarget::Collection(name) => {
                 if collection_inputs.get(name).is_none() {
-                    collection_inputs.insert(name.clone(), Default::default());
+                    collection_inputs.insert(name.clone(), Default::default()).ok();
                 }
                 collection_inputs.get(name).expect("collection input was just added").capabilities()
             }
             cm_rust::OfferTarget::Capability(name) => {
                 let mut entries = declared_dictionaries.lock_entries();
-                let dict = entries
-                    .entry(name.clone())
-                    .or_insert_with(|| Capability::Dictionary(Dict::new()))
-                    .clone();
+                let dict = match entries.get(name) {
+                    Some(dict) => dict.clone(),
+                    None => {
+                        let dict = Capability::Dictionary(Dict::new());
+                        entries.insert(name.clone(), dict.clone()).ok();
+                        dict
+                    }
+                };
                 let Capability::Dictionary(dict) = dict else {
                     panic!("wrong type in dict");
                 };
@@ -169,7 +178,12 @@
                 },
                 component.policy_checker().clone(),
             );
-            program_output_dict.insert_capability(capability.name(), router.into());
+            match program_output_dict.insert_capability(capability.name(), router.into()) {
+                Ok(()) => (),
+                Err(e) => {
+                    warn!("failed to add {} to program output dict: {e:?}", capability.name())
+                }
+            }
         }
         cm_rust::CapabilityDecl::Dictionary(d) => {
             extend_dict_with_dictionary(
@@ -238,8 +252,14 @@
     } else {
         Router::new_ok(dict.clone())
     };
-    declared_dictionaries.insert_capability(&decl.name, dict.into());
-    program_output_dict.insert_capability(&decl.name, router.into());
+    match declared_dictionaries.insert_capability(&decl.name, dict.into()) {
+        Ok(()) => (),
+        Err(e) => warn!("failed to add {} to declared dicts: {e:?}", decl.name),
+    };
+    match program_output_dict.insert_capability(&decl.name, router.into()) {
+        Ok(()) => (),
+        Err(e) => warn!("failed to add {} to program output dict: {e:?}", decl.name),
+    }
 }
 
 fn build_environment(
@@ -282,7 +302,13 @@
                 )
             }
         };
-        environment.debug().insert_capability(&debug_protocol.target_name, router.into());
+        match environment.debug().insert_capability(&debug_protocol.target_name, router.into()) {
+            Ok(()) => (),
+            Err(e) => warn!(
+                "failed to add {} to debug capabilities dict: {e:?}",
+                debug_protocol.target_name
+            ),
+        }
     }
     environment
 }
@@ -319,13 +345,15 @@
             {
                 let mut entries = dict.lock_entries();
                 let source_entries = source_dict.lock_entries();
-                for source_key in source_entries.keys() {
-                    if entries.contains_key(source_key.as_str()) {
+                for source_key in source_entries.iter().map(|(k, _v)| k) {
+                    if let Some(_entry) = entries.get(source_key) {
                         return Err(RoutingError::BedrockSourceDictionaryCollision.into());
                     }
                 }
-                for (source_key, source_value) in &*source_entries {
-                    entries.insert(source_key.clone(), source_value.clone());
+                for (source_key, source_value) in source_entries.iter() {
+                    if let Err(_e) = entries.insert(source_key.clone(), source_value.clone()) {
+                        return Err(RoutingError::BedrockSourceDictionaryCollision.into());
+                    }
                 }
             }
             *did_combine.lock().unwrap() = true;
@@ -443,10 +471,15 @@
         // UseSource::Environment is not used for protocol capabilities
         cm_rust::UseSource::Environment => return,
     };
-    program_input_dict.insert_capability(
+    match program_input_dict.insert_capability(
         &use_protocol.target_path,
         router.with_availability(*use_.availability()).into(),
-    );
+    ) {
+        Ok(()) => (),
+        Err(e) => {
+            warn!("failed to insert {} in program input dict: {e:?}", use_protocol.target_path)
+        }
+    }
 }
 
 /// Builds a router that obtains a capability that the program uses from `parent`.
@@ -485,7 +518,7 @@
                     match additions.and_then(|a| a.get_capability(&source_path)) {
                         // There's an addition to the program input dictionary for this
                         // capability, let's use it.
-                        Some(Capability::Open(o)) => Router::new_ok(o),
+                        Some(Capability::Sender(s)) => Router::new_ok(s),
                         // There's no addition to the program input dictionary for this
                         // capability, let's use the component input dictionary.
                         _ => component_input_capability,
@@ -596,8 +629,12 @@
         // This is only relevant for services, so this arm is never reached.
         cm_rust::OfferSource::Collection(_name) => return,
     };
-    target_dict
-        .insert_capability(target_name, router.with_availability(*offer.availability()).into());
+    match target_dict
+        .insert_capability(target_name, router.with_availability(*offer.availability()).into())
+    {
+        Ok(()) => (),
+        Err(e) => warn!("failed to insert {target_name} into target dict: {e:?}"),
+    }
 }
 
 pub fn is_supported_expose(expose: &cm_rust::ExposeDecl) -> bool {
@@ -679,8 +716,12 @@
         // This is only relevant for services, so this arm is never reached.
         cm_rust::ExposeSource::Collection(_name) => return,
     };
-    target_dict
-        .insert_capability(target_name, router.with_availability(*expose.availability()).into());
+    match target_dict
+        .insert_capability(target_name, router.with_availability(*expose.availability()).into())
+    {
+        Ok(()) => (),
+        Err(e) => warn!("failed to insert {target_name} into target_dict: {e:?}"),
+    }
 }
 
 fn new_unit_router() -> Router {
diff --git a/src/sys/component_manager/src/model/actions/shutdown.rs b/src/sys/component_manager/src/model/actions/shutdown.rs
index 57065ce..5131220 100644
--- a/src/sys/component_manager/src/model/actions/shutdown.rs
+++ b/src/sys/component_manager/src/model/actions/shutdown.rs
@@ -55,8 +55,8 @@
 
 #[async_trait]
 impl Action for ShutdownAction {
-    async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
-        do_shutdown(component, self.shutdown_type).await
+    async fn handle(self, component: Arc<ComponentInstance>) -> Result<(), ActionError> {
+        do_shutdown(&component, self.shutdown_type).await
     }
     fn key(&self) -> ActionKey {
         ActionKey::Shutdown
@@ -260,14 +260,14 @@
     }
 }
 
-async fn do_shutdown(
+pub async fn do_shutdown(
     component: &Arc<ComponentInstance>,
     shutdown_type: ShutdownType,
 ) -> Result<(), ActionError> {
     // Ensure `Shutdown` is dispatched after `Discovered`.
     {
         let discover_completed =
-            component.lock_actions().await.wait_for_action(ActionKey::Discover);
+            component.lock_actions().await.wait_for_action(ActionKey::Discover).await;
         discover_completed.await.unwrap();
     }
     // Keep logs short to preserve as much as possible in the crash report
@@ -399,9 +399,9 @@
     /// possible for multiple children to match a given `name` and `collection`,
     /// but at most one of them can be live.
     fn find_child(&self, name: &str, collection: Option<&Name>) -> Option<Child> {
-        self.children()
-            .into_iter()
-            .find(|child| child.moniker.name() == name && child.moniker.collection() == collection)
+        self.children().into_iter().find(|child| {
+            child.moniker.name().as_str() == name && child.moniker.collection() == collection
+        })
     }
 }
 
@@ -718,7 +718,7 @@
 ) -> Vec<ComponentRef> {
     match source {
         OfferSource::Child(ChildRef { name, collection }) => {
-            match instance.find_child(name, collection.as_ref()) {
+            match instance.find_child(name.as_str(), collection.as_ref()) {
                 Some(child) => vec![child.moniker.clone().into()],
                 None => {
                     error!(
@@ -775,7 +775,7 @@
 fn find_offer_targets(instance: &impl Component, target: &OfferTarget) -> Vec<ComponentRef> {
     match target {
         OfferTarget::Child(ChildRef { name, collection }) => {
-            match instance.find_child(name, collection.as_ref()) {
+            match instance.find_child(name.as_str(), collection.as_ref()) {
                 Some(child) => vec![child.moniker.into()],
                 None => {
                     error!(
@@ -846,7 +846,7 @@
                 let source = match source {
                     DictionarySource::Parent => None,
                     DictionarySource::Child(ChildRef { name, collection }) => {
-                        match instance.find_child(name, collection.as_ref()) {
+                        match instance.find_child(name.as_str(), collection.as_ref()) {
                             Some(child) => Some(child.moniker.clone().into()),
                             None => {
                                 error!(
@@ -936,16 +936,13 @@
             error::StopActionError,
             testing::{
                 test_helpers::{
-                    component_decl_with_test_runner, default_component_decl,
-                    execution_is_shut_down, has_child, ActionsTest, ComponentInfo,
+                    component_decl_with_test_runner, execution_is_shut_down, has_child,
+                    ActionsTest, ComponentInfo,
                 },
                 test_hook::Lifecycle,
             },
         },
-        cm_rust::{
-            Availability, ChildDecl, ComponentDecl, DependencyType, ExposeProtocolDecl,
-            ExposeSource, ExposeTarget,
-        },
+        cm_rust::{ComponentDecl, DependencyType, ExposeSource, ExposeTarget},
         cm_rust_testing::*,
         cm_types::AllowedOffers,
         fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_decl as fdecl,
@@ -1000,7 +997,7 @@
                 .children
                 .iter()
                 .map(|c| Child {
-                    moniker: ChildName::try_new(&c.name, None)
+                    moniker: ChildName::try_new(c.name.as_str(), None)
                         .expect("children should have valid monikers"),
                     environment_name: c.environment.clone(),
                 })
@@ -1023,26 +1020,15 @@
 
     #[fuchsia::test]
     fn test_service_from_self() {
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "serviceSelf".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSelf".parse().unwrap(),
-                target: OfferTarget::static_child("childA".to_string()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
-            children: vec![ChildDecl {
-                name: "childA".to_string(),
-                url: "ignored:///child".to_string(),
-                startup: fdecl::StartupMode::Lazy,
-                environment: None,
-                on_terminate: None,
-                config_overrides: None,
-            }],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceSelf")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA"),
+            )
+            .child_default("childA")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1055,26 +1041,16 @@
 
     #[test_case(DependencyType::Weak)]
     fn test_weak_service_from_self(weak_dep: DependencyType) {
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "serviceSelf".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSelf".parse().unwrap(),
-                target: OfferTarget::static_child("childA".to_string()),
-                dependency_type: weak_dep,
-                availability: Availability::Required,
-            })],
-            children: vec![ChildDecl {
-                name: "childA".to_string(),
-                url: "ignored:///child".to_string(),
-                startup: fdecl::StartupMode::Lazy,
-                environment: None,
-                on_terminate: None,
-                config_overrides: None,
-            }],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceSelf")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA")
+                    .dependency(weak_dep),
+            )
+            .child_default("childA")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1087,25 +1063,15 @@
 
     #[fuchsia::test]
     fn test_service_from_child() {
-        let decl = ComponentDecl {
-            exposes: vec![ExposeDecl::Protocol(ExposeProtocolDecl {
-                target: ExposeTarget::Parent,
-                source_name: "serviceFromChild".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceFromChild".parse().unwrap(),
-                source: ExposeSource::Child("childA".to_string()),
-                availability: cm_rust::Availability::Required,
-            })],
-            children: vec![ChildDecl {
-                name: "childA".to_string(),
-                url: "ignored:///child".to_string(),
-                startup: fdecl::StartupMode::Lazy,
-                environment: None,
-                on_terminate: None,
-                config_overrides: None,
-            }],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .expose(
+                ExposeBuilder::protocol()
+                    .name("serviceFromChild")
+                    .source(ExposeSource::Child("childA".into()))
+                    .target(ExposeTarget::Parent),
+            )
+            .child_default("childA")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1118,46 +1084,23 @@
 
     #[fuchsia::test]
     fn test_single_dependency() {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_b = ChildDecl {
-            name: "childB".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let decl = ComponentDecl {
-            offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::Self_,
-                    source_name: "serviceParent".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceParent".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBOffer".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-            ],
-            children: vec![child_a.clone(), child_b.clone()],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceParent")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childA"),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1174,33 +1117,25 @@
         let decl = ComponentDeclBuilder::new()
             .dictionary_default("dict")
             .protocol_default("serviceA")
-            .offer(OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "serviceA".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceA".parse().unwrap(),
-                target: OfferTarget::Capability("dict".parse().unwrap()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            }))
-            .offer(OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::static_child("childA".to_string()),
-                source_name: "serviceB".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceB".parse().unwrap(),
-                target: OfferTarget::Capability("dict".parse().unwrap()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            }))
-            .offer(OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "serviceB".parse().unwrap(),
-                source_dictionary: "dict".parse().unwrap(),
-                target_name: "serviceB".parse().unwrap(),
-                target: OfferTarget::static_child("childB".to_string()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            }))
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceA")
+                    .source(OfferSource::Self_)
+                    .target(OfferTarget::Capability("dict".parse().unwrap())),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceB")
+                    .source_static_child("childA")
+                    .target(OfferTarget::Capability("dict".parse().unwrap())),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceB")
+                    .source(OfferSource::Self_)
+                    .from_dictionary("dict")
+                    .target_static_child("childB"),
+            )
             .child_default("childA")
             .child_default("childB")
             .build();
@@ -1226,27 +1161,24 @@
                     .source_dictionary(DictionarySource::Self_, "other_dict"),
             )
             .capability(CapabilityBuilder::dictionary().name("other_dict").source_dictionary(
-                DictionarySource::Child(ChildRef { name: "childA".into(), collection: None }),
+                DictionarySource::Child(ChildRef {
+                    name: "childA".parse().unwrap(),
+                    collection: None,
+                }),
                 "remote/dict",
             ))
-            .offer(OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::static_child("childB".into()),
-                source_name: "serviceA".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceA".parse().unwrap(),
-                target: OfferTarget::Capability("other_dict".parse().unwrap()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            }))
-            .offer(OfferDecl::Dictionary(OfferDictionaryDecl {
-                source: OfferSource::Self_,
-                source_name: "dict".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "dict".parse().unwrap(),
-                target: OfferTarget::static_child("childC".into()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            }))
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceA")
+                    .source_static_child("childB")
+                    .target(OfferTarget::Capability("other_dict".parse().unwrap())),
+            )
+            .offer(
+                OfferBuilder::dictionary()
+                    .name("dict")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childC"),
+            )
             .child_default("childA")
             .child_default("childB")
             .child_default("childC")
@@ -1267,21 +1199,17 @@
 
     #[fuchsia::test]
     fn test_environment_with_runner_from_parent() {
-        let decl = ComponentDecl {
-            environments: vec![EnvironmentBuilder::new()
-                .name("env")
-                .runner(cm_rust::RunnerRegistration {
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("env").runner(
+                cm_rust::RunnerRegistration {
                     source: RegistrationSource::Parent,
                     source_name: "foo".parse().unwrap(),
                     target_name: "foo".parse().unwrap(),
-                })
-                .build()],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").environment("env").build(),
-            ],
-            ..default_component_decl()
-        };
+                },
+            ))
+            .child_default("childA")
+            .child(ChildBuilder::new().name("childB").environment("env"))
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1295,21 +1223,17 @@
 
     #[fuchsia::test]
     fn test_environment_with_runner_from_self() {
-        let decl = ComponentDecl {
-            environments: vec![EnvironmentBuilder::new()
-                .name("env")
-                .runner(cm_rust::RunnerRegistration {
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("env").runner(
+                cm_rust::RunnerRegistration {
                     source: RegistrationSource::Self_,
                     source_name: "foo".parse().unwrap(),
                     target_name: "foo".parse().unwrap(),
-                })
-                .build()],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").environment("env").build(),
-            ],
-            ..default_component_decl()
-        };
+                },
+            ))
+            .child_default("childA")
+            .child(ChildBuilder::new().name("childB").environment("env"))
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1323,21 +1247,17 @@
 
     #[fuchsia::test]
     fn test_environment_with_runner_from_child() {
-        let decl = ComponentDecl {
-            environments: vec![EnvironmentBuilder::new()
-                .name("env")
-                .runner(cm_rust::RunnerRegistration {
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("env").runner(
+                cm_rust::RunnerRegistration {
                     source: RegistrationSource::Child("childA".to_string()),
                     source_name: "foo".parse().unwrap(),
                     target_name: "foo".parse().unwrap(),
-                })
-                .build()],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").environment("env").build(),
-            ],
-            ..default_component_decl()
-        };
+                },
+            ))
+            .child_default("childA")
+            .child(ChildBuilder::new().name("childB").environment("env"))
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1351,19 +1271,17 @@
 
     #[fuchsia::test]
     fn test_environment_with_runner_from_child_to_collection() {
-        let decl = ComponentDecl {
-            environments: vec![EnvironmentBuilder::new()
-                .name("env")
-                .runner(cm_rust::RunnerRegistration {
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("env").runner(
+                cm_rust::RunnerRegistration {
                     source: RegistrationSource::Child("childA".to_string()),
                     source_name: "foo".parse().unwrap(),
                     target_name: "foo".parse().unwrap(),
-                })
-                .build()],
-            collections: vec![CollectionBuilder::new().name("coll").environment("env").build()],
-            children: vec![ChildBuilder::new().name("childA").build()],
-            ..default_component_decl()
-        };
+                },
+            ))
+            .collection(CollectionBuilder::new().name("coll").environment("env"))
+            .child_default("childA")
+            .build();
 
         let instance = FakeComponent {
             decl,
@@ -1403,32 +1321,25 @@
 
     #[fuchsia::test]
     fn test_chained_environments() {
-        let decl = ComponentDecl {
-            environments: vec![
-                EnvironmentBuilder::new()
-                    .name("env")
-                    .runner(cm_rust::RunnerRegistration {
-                        source: RegistrationSource::Child("childA".to_string()),
-                        source_name: "foo".parse().unwrap(),
-                        target_name: "foo".parse().unwrap(),
-                    })
-                    .build(),
-                EnvironmentBuilder::new()
-                    .name("env2")
-                    .runner(cm_rust::RunnerRegistration {
-                        source: RegistrationSource::Child("childB".to_string()),
-                        source_name: "bar".parse().unwrap(),
-                        target_name: "bar".parse().unwrap(),
-                    })
-                    .build(),
-            ],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").environment("env").build(),
-                ChildBuilder::new().name("childC").environment("env2").build(),
-            ],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("env").runner(
+                cm_rust::RunnerRegistration {
+                    source: RegistrationSource::Child("childA".to_string()),
+                    source_name: "foo".parse().unwrap(),
+                    target_name: "foo".parse().unwrap(),
+                },
+            ))
+            .environment(EnvironmentBuilder::new().name("env2").runner(
+                cm_rust::RunnerRegistration {
+                    source: RegistrationSource::Child("childB".to_string()),
+                    source_name: "bar".parse().unwrap(),
+                    target_name: "bar".parse().unwrap(),
+                },
+            ))
+            .child_default("childA")
+            .child(ChildBuilder::new().name("childB").environment("env"))
+            .child(ChildBuilder::new().name("childC").environment("env2"))
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1447,31 +1358,25 @@
 
     #[fuchsia::test]
     fn test_environment_and_offer() {
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::static_child("childB".to_string()),
-                source_name: "childBOffer".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSibling".parse().unwrap(),
-                target: OfferTarget::static_child("childC".to_string()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
-            environments: vec![EnvironmentBuilder::new()
-                .name("env")
-                .runner(cm_rust::RunnerRegistration {
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childC"),
+            )
+            .environment(EnvironmentBuilder::new().name("env").runner(
+                cm_rust::RunnerRegistration {
                     source: RegistrationSource::Child("childA".into()),
                     source_name: "foo".parse().unwrap(),
                     target_name: "foo".parse().unwrap(),
-                })
-                .build()],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").environment("env").build(),
-                ChildBuilder::new().name("childC").build(),
-            ],
-            ..default_component_decl()
-        };
+                },
+            ))
+            .child_default("childA")
+            .child(ChildBuilder::new().name("childB").environment("env"))
+            .child_default("childC")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1490,21 +1395,17 @@
 
     #[fuchsia::test]
     fn test_environment_with_resolver_from_parent() {
-        let decl = ComponentDecl {
-            environments: vec![EnvironmentBuilder::new()
-                .name("resolver_env")
-                .resolver(cm_rust::ResolverRegistration {
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("resolver_env").resolver(
+                cm_rust::ResolverRegistration {
                     source: RegistrationSource::Parent,
                     resolver: "foo".parse().unwrap(),
                     scheme: "httweeeeees".into(),
-                })
-                .build()],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").environment("resolver_env").build(),
-            ],
-            ..default_component_decl()
-        };
+                },
+            ))
+            .child_default("childA")
+            .child(ChildBuilder::new().name("childB").environment("resolver_env"))
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1518,21 +1419,17 @@
 
     #[fuchsia::test]
     fn test_environment_with_resolver_from_child() {
-        let decl = ComponentDecl {
-            environments: vec![EnvironmentBuilder::new()
-                .name("resolver_env")
-                .resolver(cm_rust::ResolverRegistration {
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("resolver_env").resolver(
+                cm_rust::ResolverRegistration {
                     source: RegistrationSource::Child("childA".to_string()),
                     resolver: "foo".parse().unwrap(),
                     scheme: "httweeeeees".into(),
-                })
-                .build()],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").environment("resolver_env").build(),
-            ],
-            ..default_component_decl()
-        };
+                },
+            ))
+            .child_default("childA")
+            .child(ChildBuilder::new().name("childB").environment("resolver_env"))
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1548,32 +1445,25 @@
 
     #[fuchsia::test]
     fn test_environment_with_chain_of_resolvers() {
-        let decl = ComponentDecl {
-            environments: vec![
-                EnvironmentBuilder::new()
-                    .name("env1")
-                    .resolver(cm_rust::ResolverRegistration {
-                        source: RegistrationSource::Child("childA".to_string()),
-                        resolver: "foo".parse().unwrap(),
-                        scheme: "httweeeeees".into(),
-                    })
-                    .build(),
-                EnvironmentBuilder::new()
-                    .name("env2")
-                    .resolver(cm_rust::ResolverRegistration {
-                        source: RegistrationSource::Child("childB".to_string()),
-                        resolver: "bar".parse().unwrap(),
-                        scheme: "httweeeeee".into(),
-                    })
-                    .build(),
-            ],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").environment("env1").build(),
-                ChildBuilder::new().name("childC").environment("env2").build(),
-            ],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("env1").resolver(
+                cm_rust::ResolverRegistration {
+                    source: RegistrationSource::Child("childA".to_string()),
+                    resolver: "foo".parse().unwrap(),
+                    scheme: "httweeeeees".into(),
+                },
+            ))
+            .environment(EnvironmentBuilder::new().name("env2").resolver(
+                cm_rust::ResolverRegistration {
+                    source: RegistrationSource::Child("childB".to_string()),
+                    resolver: "bar".parse().unwrap(),
+                    scheme: "httweeeeee".into(),
+                },
+            ))
+            .child_default("childA")
+            .child(ChildBuilder::new().name("childB").environment("env1"))
+            .child(ChildBuilder::new().name("childC").environment("env2"))
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1592,27 +1482,25 @@
 
     #[fuchsia::test]
     fn test_environment_with_resolver_and_runner_from_child() {
-        let decl = ComponentDecl {
-            environments: vec![EnvironmentBuilder::new()
-                .name("multi_env")
-                .resolver(cm_rust::ResolverRegistration {
-                    source: RegistrationSource::Child("childA".to_string()),
-                    resolver: "foo".parse().unwrap(),
-                    scheme: "httweeeeees".into(),
-                })
-                .runner(cm_rust::RunnerRegistration {
-                    source: RegistrationSource::Child("childB".to_string()),
-                    source_name: "bar".parse().unwrap(),
-                    target_name: "bar".parse().unwrap(),
-                })
-                .build()],
-            children: vec![
-                ChildBuilder::new().name("childA").build(),
-                ChildBuilder::new().name("childB").build(),
-                ChildBuilder::new().name("childC").environment("multi_env").build(),
-            ],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .environment(
+                EnvironmentBuilder::new()
+                    .name("multi_env")
+                    .resolver(cm_rust::ResolverRegistration {
+                        source: RegistrationSource::Child("childA".to_string()),
+                        resolver: "foo".parse().unwrap(),
+                        scheme: "httweeeeees".into(),
+                    })
+                    .runner(cm_rust::RunnerRegistration {
+                        source: RegistrationSource::Child("childB".to_string()),
+                        source_name: "bar".parse().unwrap(),
+                        target_name: "bar".parse().unwrap(),
+                    }),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .child(ChildBuilder::new().name("childC").environment("multi_env"))
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -1631,22 +1519,17 @@
 
     #[fuchsia::test]
     fn test_environment_with_collection_resolver_from_child() {
-        let decl = ComponentDecl {
-            environments: vec![EnvironmentBuilder::new()
-                .name("resolver_env")
-                .resolver(cm_rust::ResolverRegistration {
+        let decl = ComponentDeclBuilder::new()
+            .environment(EnvironmentBuilder::new().name("resolver_env").resolver(
+                cm_rust::ResolverRegistration {
                     source: RegistrationSource::Child("childA".to_string()),
                     resolver: "foo".parse().unwrap(),
                     scheme: "httweeeeees".into(),
-                })
-                .build()],
-            children: vec![ChildBuilder::new().name("childA").build()],
-            collections: vec![CollectionBuilder::new()
-                .name("coll")
-                .environment("resolver_env")
-                .build()],
-            ..default_component_decl()
-        };
+                },
+            ))
+            .child_default("childA")
+            .collection(CollectionBuilder::new().name("coll").environment("resolver_env"))
+            .build();
 
         let instance = FakeComponent {
             decl,
@@ -1689,7 +1572,7 @@
                 OfferBuilder::directory()
                     .name("some_dir")
                     .source(OfferSource::Child(ChildRef {
-                        name: "childA".into(),
+                        name: "childA".parse().unwrap(),
                         collection: None,
                     }))
                     .target(OfferTarget::Collection("coll".parse().unwrap())),
@@ -1705,36 +1588,30 @@
                 Child { moniker: "coll:dyn4".try_into().unwrap(), environment_name: None },
             ],
             dynamic_offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::Child(ChildRef {
-                        name: "dyn1".into(),
+                OfferBuilder::protocol()
+                    .name("test.protocol")
+                    .target_name("test.protocol")
+                    .source(OfferSource::Child(ChildRef {
+                        name: "dyn1".parse().unwrap(),
                         collection: Some("coll".parse().unwrap()),
-                    }),
-                    target: OfferTarget::Child(ChildRef {
-                        name: "dyn2".into(),
+                    }))
+                    .target(OfferTarget::Child(ChildRef {
+                        name: "dyn2".parse().unwrap(),
                         collection: Some("coll".parse().unwrap()),
-                    }),
-                    source_name: "test.protocol".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "test.protocol".parse().unwrap(),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::Child(ChildRef {
-                        name: "dyn1".into(),
+                    }))
+                    .build(),
+                OfferBuilder::protocol()
+                    .name("test.protocol")
+                    .target_name("test.protocol")
+                    .source(OfferSource::Child(ChildRef {
+                        name: "dyn1".parse().unwrap(),
                         collection: Some("coll".parse().unwrap()),
-                    }),
-                    target: OfferTarget::Child(ChildRef {
-                        name: "dyn3".into(),
+                    }))
+                    .target(OfferTarget::Child(ChildRef {
+                        name: "dyn3".parse().unwrap(),
                         collection: Some("coll".parse().unwrap()),
-                    }),
-                    source_name: "test.protocol".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "test.protocol".parse().unwrap(),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
+                    }))
+                    .build(),
             ],
         };
 
@@ -1778,36 +1655,28 @@
                 Child { moniker: "coll2:dyn2".try_into().unwrap(), environment_name: None },
             ],
             dynamic_offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::Child(ChildRef {
-                        name: "dyn1".into(),
+                OfferBuilder::protocol()
+                    .name("test.protocol")
+                    .source(OfferSource::Child(ChildRef {
+                        name: "dyn1".parse().unwrap(),
                         collection: Some("coll1".parse().unwrap()),
-                    }),
-                    target: OfferTarget::Child(ChildRef {
-                        name: "dyn1".into(),
+                    }))
+                    .target(OfferTarget::Child(ChildRef {
+                        name: "dyn1".parse().unwrap(),
                         collection: Some("coll2".parse().unwrap()),
-                    }),
-                    source_name: "test.protocol".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "test.protocol".parse().unwrap(),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::Child(ChildRef {
-                        name: "dyn2".into(),
+                    }))
+                    .build(),
+                OfferBuilder::protocol()
+                    .name("test.protocol")
+                    .source(OfferSource::Child(ChildRef {
+                        name: "dyn2".parse().unwrap(),
                         collection: Some("coll2".parse().unwrap()),
-                    }),
-                    target: OfferTarget::Child(ChildRef {
-                        name: "dyn1".into(),
+                    }))
+                    .target(OfferTarget::Child(ChildRef {
+                        name: "dyn1".parse().unwrap(),
                         collection: Some("coll1".parse().unwrap()),
-                    }),
-                    source_name: "test.protocol".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "test.protocol".parse().unwrap(),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
+                    }))
+                    .build(),
             ],
         };
 
@@ -1837,18 +1706,14 @@
                 Child { moniker: "coll:dyn1".try_into().unwrap(), environment_name: None },
                 Child { moniker: "coll:dyn2".try_into().unwrap(), environment_name: None },
             ],
-            dynamic_offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Parent,
-                target: OfferTarget::Child(ChildRef {
-                    name: "dyn1".into(),
+            dynamic_offers: vec![OfferBuilder::protocol()
+                .name("test.protocol")
+                .source(OfferSource::Parent)
+                .target(OfferTarget::Child(ChildRef {
+                    name: "dyn1".parse().unwrap(),
                     collection: Some("coll".parse().unwrap()),
-                }),
-                source_name: "test.protocol".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "test.protocol".parse().unwrap(),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
+                }))
+                .build()],
         };
 
         pretty_assertions::assert_eq!(
@@ -1873,18 +1738,14 @@
                 Child { moniker: "coll:dyn1".try_into().unwrap(), environment_name: None },
                 Child { moniker: "coll:dyn2".try_into().unwrap(), environment_name: None },
             ],
-            dynamic_offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                target: OfferTarget::Child(ChildRef {
-                    name: "dyn1".into(),
+            dynamic_offers: vec![OfferBuilder::protocol()
+                .name("test.protocol")
+                .source(OfferSource::Self_)
+                .target(OfferTarget::Child(ChildRef {
+                    name: "dyn1".parse().unwrap(),
                     collection: Some("coll".parse().unwrap()),
-                }),
-                source_name: "test.protocol".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "test.protocol".parse().unwrap(),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
+                }))
+                .build()],
         };
 
         pretty_assertions::assert_eq!(
@@ -1914,18 +1775,14 @@
                 Child { moniker: "coll:dyn1".try_into().unwrap(), environment_name: None },
                 Child { moniker: "coll:dyn2".try_into().unwrap(), environment_name: None },
             ],
-            dynamic_offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Child(ChildRef { name: "childA".into(), collection: None }),
-                target: OfferTarget::Child(ChildRef {
-                    name: "dyn1".into(),
+            dynamic_offers: vec![OfferBuilder::protocol()
+                .name("test.protocol")
+                .source_static_child("childA")
+                .target(OfferTarget::Child(ChildRef {
+                    name: "dyn1".parse().unwrap(),
                     collection: Some("coll".parse().unwrap()),
-                }),
-                source_name: "test.protocol".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "test.protocol".parse().unwrap(),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
+                }))
+                .build()],
         };
 
         pretty_assertions::assert_eq!(
@@ -1947,46 +1804,25 @@
 
     #[test_case(DependencyType::Weak)]
     fn test_single_weak_dependency(weak_dep: DependencyType) {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_b = ChildDecl {
-            name: "childB".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let decl = ComponentDecl {
-            offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::Self_,
-                    source_name: "serviceSelf".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSelf".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: weak_dep.clone(),
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBOffer".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: weak_dep.clone(),
-                    availability: Availability::Required,
-                }),
-            ],
-            children: vec![child_a.clone(), child_b.clone()],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceSelf")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA")
+                    .dependency(weak_dep.clone()),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childA")
+                    .dependency(weak_dep.clone()),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2000,55 +1836,30 @@
 
     #[fuchsia::test]
     fn test_multiple_dependencies_same_source() {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_b = ChildDecl {
-            name: "childB".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let decl = ComponentDecl {
-            offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::Self_,
-                    source_name: "serviceSelf".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSelf".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBOffer".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBOtherOffer".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceOtherSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-            ],
-            children: vec![child_a.clone(), child_b.clone()],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceSelf")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childA"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOtherOffer")
+                    .target_name("serviceOtherSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childA"),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2062,55 +1873,25 @@
 
     #[fuchsia::test]
     fn test_multiple_dependents_same_source() {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_b = ChildDecl {
-            name: "childB".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_c = ChildDecl {
-            name: "childC".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let decl = ComponentDecl {
-            offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBOffer".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBToC".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childC".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-            ],
-            children: vec![child_a.clone(), child_b.clone(), child_c.clone()],
-
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childA"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBToC")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childC"),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .child_default("childC")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2129,63 +1910,33 @@
 
     #[test_case(DependencyType::Weak)]
     fn test_multiple_dependencies(weak_dep: DependencyType) {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_b = ChildDecl {
-            name: "childB".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_c = ChildDecl {
-            name: "childC".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let decl = ComponentDecl {
-            offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childA".to_string()),
-                    source_name: "childBOffer".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childC".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBToC".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childC".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childC".to_string()),
-                    source_name: "childCToA".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    dependency_type: weak_dep,
-                    availability: Availability::Required,
-                }),
-            ],
-            children: vec![child_a.clone(), child_b.clone(), child_c.clone()],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childA")
+                    .target_static_child("childC"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBToC")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childC"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childCToA")
+                    .target_name("serviceSibling")
+                    .source_static_child("childC")
+                    .target_static_child("childA")
+                    .dependency(weak_dep),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .child_default("childC")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2204,54 +1955,25 @@
 
     #[fuchsia::test]
     fn test_component_is_source_and_target() {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_b = ChildDecl {
-            name: "childB".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_c = ChildDecl {
-            name: "childC".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let decl = ComponentDecl {
-            offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childA".to_string()),
-                    source_name: "childBOffer".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childB".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBToC".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "serviceSibling".parse().unwrap(),
-                    target: OfferTarget::static_child("childC".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-            ],
-            children: vec![child_a.clone(), child_b.clone(), child_c.clone()],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childA")
+                    .target_static_child("childB"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBToC")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childC"),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .child_default("childC")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2279,103 +2001,43 @@
     ///      *>~~>*
     #[fuchsia::test]
     fn test_complex_routing() {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_b = ChildDecl {
-            name: "childB".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_c = ChildDecl {
-            name: "childC".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_d = ChildDecl {
-            name: "childD".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_e = ChildDecl {
-            name: "childE".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let decl = ComponentDecl {
-            offers: vec![
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childA".to_string()),
-                    source_name: "childAService".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "childAService".parse().unwrap(),
-                    target: OfferTarget::static_child("childB".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childA".to_string()),
-                    source_name: "childAService".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "childAService".parse().unwrap(),
-                    target: OfferTarget::static_child("childC".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childB".to_string()),
-                    source_name: "childBService".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "childBService".parse().unwrap(),
-                    target: OfferTarget::static_child("childD".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childC".to_string()),
-                    source_name: "childAService".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "childAService".parse().unwrap(),
-                    target: OfferTarget::static_child("childD".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Protocol(OfferProtocolDecl {
-                    source: OfferSource::static_child("childC".to_string()),
-                    source_name: "childAService".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_name: "childAService".parse().unwrap(),
-                    target: OfferTarget::static_child("childE".to_string()),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-            ],
-            children: vec![
-                child_a.clone(),
-                child_b.clone(),
-                child_c.clone(),
-                child_d.clone(),
-                child_e.clone(),
-            ],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childAService")
+                    .source_static_child("childA")
+                    .target_static_child("childB"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childAService")
+                    .source_static_child("childA")
+                    .target_static_child("childC"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBService")
+                    .source_static_child("childB")
+                    .target_static_child("childD"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childAService")
+                    .source_static_child("childC")
+                    .target_static_child("childD"),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childAService")
+                    .source_static_child("childC")
+                    .target_static_child("childE"),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .child_default("childC")
+            .child_default("childD")
+            .child_default("childE")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2398,28 +2060,17 @@
 
     #[fuchsia::test]
     fn test_target_does_not_exist() {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
         // This declaration is invalid because the offer target doesn't exist
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::static_child("childA".to_string()),
-                source_name: "childBOffer".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSibling".parse().unwrap(),
-                target: OfferTarget::static_child("childB".to_string()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
-            children: vec![child_a.clone()],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childA")
+                    .target_static_child("childB"),
+            )
+            .child_default("childA")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2432,38 +2083,16 @@
 
     #[fuchsia::test]
     fn test_service_from_collection() {
-        let decl = ComponentDecl {
-            collections: vec![CollectionDecl {
-                name: "coll".parse().unwrap(),
-                durability: fdecl::Durability::Transient,
-                environment: None,
-                allowed_offers: cm_types::AllowedOffers::StaticOnly,
-                allow_long_names: false,
-                persistent_storage: Some(false),
-            }],
-            children: vec![ChildDecl {
-                name: "static_child".parse().unwrap(),
-                url: "fuchsia-pkg://imaginary".to_string(),
-                startup: fdecl::StartupMode::Lazy,
-                on_terminate: None,
-                environment: None,
-                config_overrides: None,
-            }],
-            offers: vec![OfferDecl::Service(OfferServiceDecl {
-                source: OfferSource::Collection("coll".parse().unwrap()),
-                source_name: "service_capability".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target: OfferTarget::Child(ChildRef {
-                    name: "static_child".into(),
-                    collection: None,
-                }),
-                target_name: "service_capbility".parse().unwrap(),
-                source_instance_filter: None,
-                renamed_instances: None,
-                availability: Availability::Required,
-            })],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .collection_default("coll")
+            .child_default("static_child")
+            .offer(
+                OfferBuilder::service()
+                    .name("service_capability")
+                    .source(OfferSource::Collection("coll".parse().unwrap()))
+                    .target_static_child("static_child"),
+            )
+            .build();
 
         let dynamic_child = ChildName::try_new("dynamic_child", Some("coll")).unwrap();
         let mut fake = FakeComponent::from_decl(decl);
@@ -2484,38 +2113,16 @@
 
     #[fuchsia::test]
     fn test_service_from_collection_with_multiple_instances() {
-        let decl = ComponentDecl {
-            collections: vec![CollectionDecl {
-                name: "coll".parse().unwrap(),
-                durability: fdecl::Durability::Transient,
-                environment: None,
-                allowed_offers: cm_types::AllowedOffers::StaticOnly,
-                allow_long_names: false,
-                persistent_storage: Some(false),
-            }],
-            children: vec![ChildDecl {
-                name: "static_child".parse().unwrap(),
-                url: "fuchsia-pkg://imaginary".to_string(),
-                startup: fdecl::StartupMode::Lazy,
-                on_terminate: None,
-                environment: None,
-                config_overrides: None,
-            }],
-            offers: vec![OfferDecl::Service(OfferServiceDecl {
-                source: OfferSource::Collection("coll".parse().unwrap()),
-                source_name: "service_capability".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target: OfferTarget::Child(ChildRef {
-                    name: "static_child".into(),
-                    collection: None,
-                }),
-                target_name: "service_capbility".parse().unwrap(),
-                source_instance_filter: None,
-                renamed_instances: None,
-                availability: Availability::Required,
-            })],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .collection_default("coll")
+            .child_default("static_child")
+            .offer(
+                OfferBuilder::service()
+                    .name("service_capability")
+                    .source(OfferSource::Collection("coll".parse().unwrap()))
+                    .target_static_child("static_child"),
+            )
+            .build();
 
         let dynamic_child1 = ChildName::try_new("dynamic_child1", Some("coll")).unwrap();
         let dynamic_child2 = ChildName::try_new("dynamic_child2", Some("coll")).unwrap();
@@ -2542,45 +2149,21 @@
 
     #[fuchsia::test]
     fn test_service_dependency_between_collections() {
-        let c1_name = "coll1".to_string();
-        let c2_name = "coll2".to_string();
-        let cap_name = "fuchsia.service.FakeService".to_string();
-        let decl = ComponentDecl {
-            collections: vec![
-                CollectionDecl {
-                    name: c1_name.parse().unwrap(),
-                    durability: fdecl::Durability::Transient,
-                    environment: None,
-                    allowed_offers: cm_types::AllowedOffers::StaticOnly,
-                    allow_long_names: false,
-                    persistent_storage: Some(false),
-                },
-                CollectionDecl {
-                    name: c2_name.parse().unwrap(),
-                    durability: fdecl::Durability::Transient,
-                    environment: None,
-                    allowed_offers: cm_types::AllowedOffers::StaticOnly,
-                    allow_long_names: false,
-                    persistent_storage: Some(false),
-                },
-            ],
-            offers: vec![OfferDecl::Service(OfferServiceDecl {
-                source: OfferSource::Collection(c1_name.parse().unwrap()),
-                source_name: cap_name.clone().parse().unwrap(),
-                source_dictionary: Default::default(),
-                target: OfferTarget::Collection(c2_name.parse().unwrap()),
-                target_name: cap_name.clone().parse().unwrap(),
-                source_instance_filter: None,
-                renamed_instances: None,
-                availability: Availability::Required,
-            })],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .collection_default("coll1")
+            .collection_default("coll2")
+            .offer(
+                OfferBuilder::service()
+                    .name("fuchsia.service.FakeService")
+                    .source(OfferSource::Collection("coll1".parse().unwrap()))
+                    .target(OfferTarget::Collection("coll2".parse().unwrap())),
+            )
+            .build();
 
-        let source_child1 = ChildName::try_new("source_child1", Some(&c1_name)).unwrap();
-        let source_child2 = ChildName::try_new("source_child2", Some(&c1_name)).unwrap();
-        let target_child1 = ChildName::try_new("target_child1", Some(&c2_name)).unwrap();
-        let target_child2 = ChildName::try_new("target_child2", Some(&c2_name)).unwrap();
+        let source_child1 = ChildName::try_new("source_child1", Some("coll1")).unwrap();
+        let source_child2 = ChildName::try_new("source_child2", Some("coll1")).unwrap();
+        let target_child1 = ChildName::try_new("target_child1", Some("coll2")).unwrap();
+        let target_child2 = ChildName::try_new("target_child2", Some("coll2")).unwrap();
 
         let mut fake = FakeComponent::from_decl(decl);
         fake.dynamic_children
@@ -2617,28 +2200,17 @@
 
     #[fuchsia::test]
     fn test_source_does_not_exist() {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
         // This declaration is invalid because the offer target doesn't exist
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::static_child("childB".to_string()),
-                source_name: "childBOffer".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSibling".parse().unwrap(),
-                target: OfferTarget::static_child("childA".to_string()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
-            children: vec![child_a.clone()],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("childBOffer")
+                    .target_name("serviceSibling")
+                    .source_static_child("childB")
+                    .target_static_child("childA"),
+            )
+            .child_default("childA")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2651,34 +2223,21 @@
 
     #[fuchsia::test]
     fn test_use_from_child() {
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "serviceSelf".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSelf".parse().unwrap(),
-                target: OfferTarget::static_child("childA".to_string()),
-                dependency_type: DependencyType::Weak,
-                availability: Availability::Required,
-            })],
-            children: vec![ChildDecl {
-                name: "childA".to_string(),
-                url: "ignored:///child".to_string(),
-                startup: fdecl::StartupMode::Lazy,
-                environment: None,
-                on_terminate: None,
-                config_overrides: None,
-            }],
-            uses: vec![UseDecl::Protocol(UseProtocolDecl {
-                source: UseSource::Child("childA".to_string()),
-                source_name: "test.protocol".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_path: "/svc/test.protocol".parse().unwrap(),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceSelf")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA")
+                    .dependency(DependencyType::Weak),
+            )
+            .child_default("childA")
+            .use_(
+                UseBuilder::protocol()
+                    .name("test.protocol")
+                    .source(UseSource::Child("childA".into())),
+            )
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2693,24 +2252,19 @@
     fn test_use_from_dictionary() {
         let decl = ComponentDeclBuilder::new()
             .dictionary_default("dict")
-            .offer(OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "weakService".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "weakService".parse().unwrap(),
-                target: OfferTarget::static_child("childA".into()),
-                dependency_type: DependencyType::Weak,
-                availability: Availability::Required,
-            }))
-            .offer(OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::static_child("childA".into()),
-                source_name: "serviceA".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceA".parse().unwrap(),
-                target: OfferTarget::Capability("dict".parse().unwrap()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            }))
+            .offer(
+                OfferBuilder::protocol()
+                    .name("weakService")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA")
+                    .dependency(DependencyType::Weak),
+            )
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceA")
+                    .source_static_child("childA")
+                    .target(OfferTarget::Capability("dict".parse().unwrap())),
+            )
             .child_default("childA")
             .use_(
                 UseBuilder::protocol()
@@ -2732,22 +2286,12 @@
 
     #[fuchsia::test]
     fn test_use_runner_from_child() {
-        let decl = ComponentDecl {
-            children: vec![ChildDecl {
-                name: "childA".to_string(),
-                url: "ignored:///child".to_string(),
-                startup: fdecl::StartupMode::Lazy,
-                environment: None,
-                on_terminate: None,
-                config_overrides: None,
-            }],
-            uses: vec![UseDecl::Runner(UseRunnerDecl {
-                source: UseSource::Child("childA".to_string()),
-                source_name: "test.runner".parse().unwrap(),
-                source_dictionary: Default::default(),
-            })],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .child_default("childA")
+            .use_(
+                UseBuilder::runner().name("test.runner").source(UseSource::Child("childA".into())),
+            )
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2760,44 +2304,22 @@
 
     #[fuchsia::test]
     fn test_use_from_some_children() {
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "serviceSelf".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSelf".parse().unwrap(),
-                target: OfferTarget::static_child("childA".to_string()),
-                dependency_type: DependencyType::Weak,
-                availability: Availability::Required,
-            })],
-            children: vec![
-                ChildDecl {
-                    name: "childA".to_string(),
-                    url: "ignored:///child".to_string(),
-                    startup: fdecl::StartupMode::Lazy,
-                    environment: None,
-                    on_terminate: None,
-                    config_overrides: None,
-                },
-                ChildDecl {
-                    name: "childB".to_string(),
-                    url: "ignored:///child".to_string(),
-                    startup: fdecl::StartupMode::Lazy,
-                    environment: None,
-                    on_terminate: None,
-                    config_overrides: None,
-                },
-            ],
-            uses: vec![UseDecl::Protocol(UseProtocolDecl {
-                source: UseSource::Child("childA".to_string()),
-                source_name: "test.protocol".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_path: "/svc/test.protocol".parse().unwrap(),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceSelf")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA")
+                    .dependency(DependencyType::Weak),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .use_(
+                UseBuilder::protocol()
+                    .name("test.protocol")
+                    .source(UseSource::Child("childA".into())),
+            )
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2814,67 +2336,39 @@
 
     #[fuchsia::test]
     fn test_use_from_child_offer_storage() {
-        let decl = ComponentDecl {
-            capabilities: vec![
-                CapabilityDecl::Storage(StorageDecl {
-                    name: "cdata".parse().unwrap(),
-                    source: StorageDirectorySource::Child("childB".to_string()),
-                    backing_dir: "directory".parse().unwrap(),
-                    subdir: Default::default(),
-                    storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
-                }),
-                CapabilityDecl::Storage(StorageDecl {
-                    name: "pdata".parse().unwrap(),
-                    source: StorageDirectorySource::Parent,
-                    backing_dir: "directory".parse().unwrap(),
-                    subdir: Default::default(),
-                    storage_id: fdecl::StorageId::StaticInstanceIdOrMoniker,
-                }),
-            ],
-            offers: vec![
-                OfferDecl::Storage(OfferStorageDecl {
-                    source: OfferSource::Self_,
-                    source_name: "cdata".parse().unwrap(),
-                    target_name: "cdata".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    availability: Availability::Required,
-                }),
-                OfferDecl::Storage(OfferStorageDecl {
-                    source: OfferSource::Self_,
-                    source_name: "pdata".parse().unwrap(),
-                    target_name: "pdata".parse().unwrap(),
-                    target: OfferTarget::static_child("childA".to_string()),
-                    availability: Availability::Required,
-                }),
-            ],
-            children: vec![
-                ChildDecl {
-                    name: "childA".to_string(),
-                    url: "ignored:///child".to_string(),
-                    startup: fdecl::StartupMode::Lazy,
-                    environment: None,
-                    on_terminate: None,
-                    config_overrides: None,
-                },
-                ChildDecl {
-                    name: "childB".to_string(),
-                    url: "ignored:///child".to_string(),
-                    startup: fdecl::StartupMode::Lazy,
-                    environment: None,
-                    on_terminate: None,
-                    config_overrides: None,
-                },
-            ],
-            uses: vec![UseDecl::Protocol(UseProtocolDecl {
-                source: UseSource::Child("childA".to_string()),
-                source_name: "test.protocol".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_path: "/svc/test.protocol".parse().unwrap(),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .capability(
+                CapabilityBuilder::storage()
+                    .name("cdata")
+                    .source(StorageDirectorySource::Child("childB".into()))
+                    .backing_dir("directory"),
+            )
+            .capability(
+                CapabilityBuilder::storage()
+                    .name("pdata")
+                    .source(StorageDirectorySource::Parent)
+                    .backing_dir("directory"),
+            )
+            .offer(
+                OfferBuilder::storage()
+                    .name("cdata")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA"),
+            )
+            .offer(
+                OfferBuilder::storage()
+                    .name("pdata")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA"),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .use_(
+                UseBuilder::protocol()
+                    .name("test.protocol")
+                    .source(UseSource::Child("childA".into())),
+            )
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2890,34 +2384,21 @@
 
     #[fuchsia::test]
     fn test_use_from_child_weak() {
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "serviceSelf".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSelf".parse().unwrap(),
-                target: OfferTarget::static_child("childA".to_string()),
-                dependency_type: DependencyType::Strong,
-                availability: Availability::Required,
-            })],
-            children: vec![ChildDecl {
-                name: "childA".to_string(),
-                url: "ignored:///child".to_string(),
-                startup: fdecl::StartupMode::Lazy,
-                environment: None,
-                on_terminate: None,
-                config_overrides: None,
-            }],
-            uses: vec![UseDecl::Protocol(UseProtocolDecl {
-                source: UseSource::Child("childA".to_string()),
-                source_name: "test.protocol".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_path: "/svc/test.protocol".parse().unwrap(),
-                dependency_type: DependencyType::Weak,
-                availability: Availability::Required,
-            })],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceSelf")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA"),
+            )
+            .child_default("childA")
+            .use_(
+                UseBuilder::protocol()
+                    .name("test.protocol")
+                    .source(UseSource::Child("childA".into()))
+                    .dependency(DependencyType::Weak),
+            )
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2930,54 +2411,28 @@
 
     #[fuchsia::test]
     fn test_use_from_some_children_weak() {
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Protocol(OfferProtocolDecl {
-                source: OfferSource::Self_,
-                source_name: "serviceSelf".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "serviceSelf".parse().unwrap(),
-                target: OfferTarget::static_child("childA".to_string()),
-                dependency_type: DependencyType::Weak,
-                availability: Availability::Required,
-            })],
-            children: vec![
-                ChildDecl {
-                    name: "childA".to_string(),
-                    url: "ignored:///child".to_string(),
-                    startup: fdecl::StartupMode::Lazy,
-                    environment: None,
-                    on_terminate: None,
-                    config_overrides: None,
-                },
-                ChildDecl {
-                    name: "childB".to_string(),
-                    url: "ignored:///child".to_string(),
-                    startup: fdecl::StartupMode::Lazy,
-                    environment: None,
-                    on_terminate: None,
-                    config_overrides: None,
-                },
-            ],
-            uses: vec![
-                UseDecl::Protocol(UseProtocolDecl {
-                    source: UseSource::Child("childA".to_string()),
-                    source_name: "test.protocol".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_path: "/svc/test.protocol".parse().unwrap(),
-                    dependency_type: DependencyType::Strong,
-                    availability: Availability::Required,
-                }),
-                UseDecl::Protocol(UseProtocolDecl {
-                    source: UseSource::Child("childB".to_string()),
-                    source_name: "test.protocol2".parse().unwrap(),
-                    source_dictionary: Default::default(),
-                    target_path: "/svc/test.protocol2".parse().unwrap(),
-                    dependency_type: DependencyType::Weak,
-                    availability: Availability::Required,
-                }),
-            ],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::protocol()
+                    .name("serviceSelf")
+                    .source(OfferSource::Self_)
+                    .target_static_child("childA")
+                    .dependency(DependencyType::Weak),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .use_(
+                UseBuilder::protocol()
+                    .name("test.protocol")
+                    .source(UseSource::Child("childA".into())),
+            )
+            .use_(
+                UseBuilder::protocol()
+                    .name("test.protocol2")
+                    .source(UseSource::Child("childB".into()))
+                    .dependency(DependencyType::Weak),
+            )
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -2992,33 +2447,16 @@
 
     #[fuchsia::test]
     fn test_resolver_capability_creates_dependency() {
-        let child_a = ChildDecl {
-            name: "childA".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let child_b = ChildDecl {
-            name: "childB".to_string(),
-            url: "ignored:///child".to_string(),
-            startup: fdecl::StartupMode::Lazy,
-            environment: None,
-            on_terminate: None,
-            config_overrides: None,
-        };
-        let decl = ComponentDecl {
-            offers: vec![OfferDecl::Resolver(OfferResolverDecl {
-                source: OfferSource::static_child("childA".to_string()),
-                source_name: "resolver".parse().unwrap(),
-                source_dictionary: Default::default(),
-                target_name: "resolver".parse().unwrap(),
-                target: OfferTarget::static_child("childB".to_string()),
-            })],
-            children: vec![child_a.clone(), child_b.clone()],
-            ..default_component_decl()
-        };
+        let decl = ComponentDeclBuilder::new()
+            .offer(
+                OfferBuilder::resolver()
+                    .name("resolver")
+                    .source_static_child("childA")
+                    .target_static_child("childB"),
+            )
+            .child_default("childA")
+            .child_default("childB")
+            .build();
 
         pretty_assertions::assert_eq!(
             hashmap! {
@@ -3235,7 +2673,7 @@
                             .name("static_offer_source")
                             .target_name("static_offer_target")
                             .source(OfferSource::Child(ChildRef {
-                                name: "c".into(),
+                                name: "c".parse().unwrap(),
                                 collection: None,
                             }))
                             .target(OfferTarget::Collection("coll".parse().unwrap())),
@@ -3452,17 +2890,12 @@
     async fn shutdown_hierarchy() {
         let components = vec![
             ("root", ComponentDeclBuilder::new().child_default("a").build()),
-            (
-                "a",
-                ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .build(),
-            ),
+            ("a", ComponentDeclBuilder::new().child(ChildBuilder::new().name("b").eager()).build()),
             (
                 "b",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("c").eager().build())
-                    .child(ChildBuilder::new().name("d").eager().build())
+                    .child(ChildBuilder::new().name("c").eager())
+                    .child(ChildBuilder::new().name("d").eager())
                     .build(),
             ),
             ("c", component_decl_with_test_runner()),
@@ -3539,29 +2972,24 @@
     async fn shutdown_with_multiple_deps() {
         let components = vec![
             ("root", ComponentDeclBuilder::new().child_default("a").build()),
-            (
-                "a",
-                ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .build(),
-            ),
+            ("a", ComponentDeclBuilder::new().child(ChildBuilder::new().name("b").eager()).build()),
             (
                 "b",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("c").eager().build())
-                    .child(ChildBuilder::new().name("d").eager().build())
-                    .child(ChildBuilder::new().name("e").eager().build())
+                    .child(ChildBuilder::new().name("c").eager())
+                    .child(ChildBuilder::new().name("d").eager())
+                    .child(ChildBuilder::new().name("e").eager())
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceD")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .source_static_child("d")
+                            .target_static_child("c"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceD")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("e".to_string())),
+                            .source_static_child("d")
+                            .target_static_child("e"),
                     )
                     .build(),
             ),
@@ -3666,36 +3094,31 @@
     async fn shutdown_with_multiple_out_and_longer_chain() {
         let components = vec![
             ("root", ComponentDeclBuilder::new().child_default("a").build()),
-            (
-                "a",
-                ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .build(),
-            ),
+            ("a", ComponentDeclBuilder::new().child(ChildBuilder::new().name("b").eager()).build()),
             (
                 "b",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("c").eager().build())
-                    .child(ChildBuilder::new().name("d").eager().build())
-                    .child(ChildBuilder::new().name("e").eager().build())
-                    .child(ChildBuilder::new().name("f").eager().build())
+                    .child(ChildBuilder::new().name("c").eager())
+                    .child(ChildBuilder::new().name("d").eager())
+                    .child(ChildBuilder::new().name("e").eager())
+                    .child(ChildBuilder::new().name("f").eager())
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceD")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .source_static_child("d")
+                            .target_static_child("c"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceD")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("e".to_string())),
+                            .source_static_child("d")
+                            .target_static_child("e"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceE")
-                            .source(OfferSource::static_child("e".to_string()))
-                            .target(OfferTarget::static_child("f".to_string())),
+                            .source_static_child("e")
+                            .target_static_child("f"),
                     )
                     .build(),
             ),
@@ -3837,42 +3260,37 @@
     async fn shutdown_with_multiple_out_multiple_in() {
         let components = vec![
             ("root", ComponentDeclBuilder::new().child_default("a").build()),
-            (
-                "a",
-                ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .build(),
-            ),
+            ("a", ComponentDeclBuilder::new().child(ChildBuilder::new().name("b").eager()).build()),
             (
                 "b",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("c").eager().build())
-                    .child(ChildBuilder::new().name("d").eager().build())
-                    .child(ChildBuilder::new().name("e").eager().build())
-                    .child(ChildBuilder::new().name("f").eager().build())
+                    .child(ChildBuilder::new().name("c").eager())
+                    .child(ChildBuilder::new().name("d").eager())
+                    .child(ChildBuilder::new().name("e").eager())
+                    .child(ChildBuilder::new().name("f").eager())
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceD")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .source_static_child("d")
+                            .target_static_child("c"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceD")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("e".to_string())),
+                            .source_static_child("d")
+                            .target_static_child("e"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceD")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("f".to_string())),
+                            .source_static_child("d")
+                            .target_static_child("f"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceE")
-                            .source(OfferSource::static_child("e".to_string()))
-                            .target(OfferTarget::static_child("f".to_string())),
+                            .source_static_child("e")
+                            .target_static_child("f"),
                     )
                     .build(),
             ),
@@ -4009,22 +3427,17 @@
     async fn shutdown_with_dependency() {
         let components = vec![
             ("root", ComponentDeclBuilder::new().child_default("a").build()),
-            (
-                "a",
-                ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .build(),
-            ),
+            ("a", ComponentDeclBuilder::new().child(ChildBuilder::new().name("b").eager()).build()),
             (
                 "b",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("c").eager().build())
-                    .child(ChildBuilder::new().name("d").eager().build())
+                    .child(ChildBuilder::new().name("c").eager())
+                    .child(ChildBuilder::new().name("d").eager())
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceC")
-                            .source(OfferSource::static_child("c".to_string()))
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .source_static_child("c")
+                            .target_static_child("d"),
                     )
                     .build(),
             ),
@@ -4101,22 +3514,17 @@
     async fn shutdown_with_dictionary_dependency() {
         let components = vec![
             ("root", ComponentDeclBuilder::new().child_default("a").build()),
-            (
-                "a",
-                ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .build(),
-            ),
+            ("a", ComponentDeclBuilder::new().child(ChildBuilder::new().name("b").eager()).build()),
             (
                 "b",
                 ComponentDeclBuilder::new()
                     .dictionary_default("dict")
-                    .child(ChildBuilder::new().name("c").eager().build())
-                    .child(ChildBuilder::new().name("d").eager().build())
+                    .child(ChildBuilder::new().name("c").eager())
+                    .child(ChildBuilder::new().name("d").eager())
                     .offer(
                         OfferBuilder::protocol()
                             .name("serviceC")
-                            .source(OfferSource::static_child("c".to_string()))
+                            .source_static_child("c")
                             .target(OfferTarget::Capability("dict".parse().unwrap())),
                     )
                     .offer(
@@ -4124,7 +3532,7 @@
                             .name("serviceC")
                             .source(OfferSource::Self_)
                             .from_dictionary("dict")
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .build(),
             ),
@@ -4202,8 +3610,8 @@
             (
                 "a",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .child(ChildBuilder::new().name("c").eager().build())
+                    .child(ChildBuilder::new().name("b").eager())
+                    .child(ChildBuilder::new().name("c").eager())
                     .use_(
                         UseBuilder::protocol()
                             .source(UseSource::Child("b".to_string()))
@@ -4278,8 +3686,8 @@
             (
                 "a",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .child(ChildBuilder::new().name("c").eager().build())
+                    .child(ChildBuilder::new().name("b").eager())
+                    .child(ChildBuilder::new().name("c").eager())
                     .use_(
                         UseBuilder::runner()
                             .source(UseSource::Child("b".to_string()))
@@ -4353,8 +3761,8 @@
             (
                 "a",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .child(ChildBuilder::new().name("c").eager().build())
+                    .child(ChildBuilder::new().name("b").eager())
+                    .child(ChildBuilder::new().name("c").eager())
                     .use_(
                         UseBuilder::protocol()
                             .source(UseSource::Child("b".to_string()))
@@ -4364,8 +3772,8 @@
                         OfferBuilder::protocol()
                             .name("serviceC")
                             .target_name("serviceB")
-                            .source(OfferSource::static_child("c".to_string()))
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .source_static_child("c")
+                            .target_static_child("b"),
                     )
                     .build(),
             ),
@@ -4443,8 +3851,8 @@
             (
                 "a",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .child(ChildBuilder::new().name("c").eager().build())
+                    .child(ChildBuilder::new().name("b").eager())
+                    .child(ChildBuilder::new().name("c").eager())
                     .use_(
                         UseBuilder::protocol()
                             .source(UseSource::Child("b".to_string()))
@@ -4598,17 +4006,12 @@
     async fn shutdown_error() {
         let components = vec![
             ("root", ComponentDeclBuilder::new().child_default("a").build()),
-            (
-                "a",
-                ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("b").eager().build())
-                    .build(),
-            ),
+            ("a", ComponentDeclBuilder::new().child(ChildBuilder::new().name("b").eager()).build()),
             (
                 "b",
                 ComponentDeclBuilder::new()
-                    .child(ChildBuilder::new().name("c").eager().build())
-                    .child(ChildBuilder::new().name("d").eager().build())
+                    .child(ChildBuilder::new().name("c").eager())
+                    .child(ChildBuilder::new().name("d").eager())
                     .build(),
             ),
             ("c", component_decl_with_test_runner()),
diff --git a/src/sys/component_manager/src/model/actions/start.rs b/src/sys/component_manager/src/model/actions/start.rs
index 0b2cdd3..d2c8ef5 100644
--- a/src/sys/component_manager/src/model/actions/start.rs
+++ b/src/sys/component_manager/src/model/actions/start.rs
@@ -16,7 +16,7 @@
     },
     crate::runner::RemoteRunner,
     ::namespace::Entry as NamespaceEntry,
-    ::routing::{component_instance::ComponentInstanceInterface, policy::GlobalPolicyChecker},
+    ::routing::component_instance::ComponentInstanceInterface,
     async_trait::async_trait,
     cm_logger::scoped::ScopedLogger,
     cm_rust::ComponentDecl,
@@ -84,9 +84,9 @@
 
 #[async_trait]
 impl Action for StartAction {
-    async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
+    async fn handle(self, component: Arc<ComponentInstance>) -> Result<(), ActionError> {
         do_start(
-            component,
+            &component,
             &self.start_reason,
             self.execution_controller_task,
             self.incoming,
@@ -114,6 +114,9 @@
     numbered_handles: Vec<fprocess::HandleInfo>,
     encoded_config: Option<fmem::Data>,
     program_input_dict_additions: Option<Dict>,
+    start_reason: StartReason,
+    execution_controller_task: Option<controller::ExecutionControllerTask>,
+    logger: Option<ScopedLogger>,
 }
 
 async fn do_start(
@@ -188,16 +191,33 @@
         })?;
     }
 
-    // Generate the Runtime which will be set in the Execution.
+    // Check policy.
+    // TODO(https://fxbug.dev/42071809): Consider moving this check to ComponentInstance::add_child
+    match component.on_terminate {
+        fdecl::OnTerminate::Reboot => {
+            component.policy_checker().reboot_on_terminate_allowed(&component.moniker).map_err(
+                |err| StartActionError::RebootOnTerminateForbidden {
+                    moniker: component.moniker.clone(),
+                    err,
+                },
+            )?;
+        }
+        fdecl::OnTerminate::None => {}
+    }
+
+    // Create a component-scoped logger if the component uses LogSink.
     let decl = &resolved_component.decl;
-    let pending_runtime = make_execution_runtime(
-        &component,
-        component.policy_checker(),
-        decl,
-        start_reason.clone(),
-        execution_controller_task,
-    )
-    .await?;
+    let logger = if let Some(logsink_decl) = get_logsink_decl(&decl) {
+        match create_scoped_logger(component, logsink_decl.clone()).await {
+            Ok(logger) => Some(logger),
+            Err(err) => {
+                warn!(moniker = %component.moniker, %err, "Could not create logger for component. Logs will be attributed to component_manager");
+                None
+            }
+        }
+    } else {
+        None
+    };
 
     let encoded_config = match decl.config {
         None => None,
@@ -241,9 +261,12 @@
         numbered_handles,
         encoded_config,
         program_input_dict_additions,
+        start_reason: start_reason.clone(),
+        execution_controller_task,
+        logger,
     };
 
-    start_component(&component, resolved_component.decl, pending_runtime, start_context).await
+    start_component(&component, resolved_component.decl, start_context).await
 }
 
 /// Set the Runtime in the Execution and start the exit watcher. From component manager's
@@ -254,7 +277,6 @@
 async fn start_component(
     component: &Arc<ComponentInstance>,
     decl: ComponentDecl,
-    mut pending_runtime: StartedInstanceState,
     start_context: StartContext,
 ) -> Result<(), StartActionError> {
     let runtime_info;
@@ -281,9 +303,12 @@
             namespace_scope,
             encoded_config,
             program_input_dict_additions,
+            start_reason,
+            execution_controller_task,
+            logger,
         } = start_context;
 
-        if let Some(runner) = runner {
+        let program = if let Some(runner) = runner {
             let moniker = &component.moniker;
             let component_instance = state
                 .instance_token(moniker, &component.context)
@@ -307,7 +332,7 @@
                 component_instance,
             };
 
-            pending_runtime.set_program(
+            Some(
                 Program::start(
                     &runner,
                     start_info,
@@ -319,16 +344,23 @@
                     moniker: moniker.clone(),
                     err,
                 })?,
-                component.as_weak(),
-            );
-        }
+            )
+        } else {
+            None
+        };
 
-        timestamp = pending_runtime.timestamp;
+        let started = StartedInstanceState::new(
+            program,
+            component.as_weak(),
+            start_reason,
+            execution_controller_task,
+            logger,
+        );
+        timestamp = started.timestamp;
         runtime_info = RuntimeInfo::new(timestamp, diagnostics_receiver);
-        runtime_dir = pending_runtime.runtime_dir().cloned();
-
+        runtime_dir = started.runtime_dir().cloned();
         state.replace(|instance_state| match instance_state {
-            InstanceState::Resolved(resolved) => InstanceState::Started(resolved, pending_runtime),
+            InstanceState::Resolved(resolved) => InstanceState::Started(resolved, started),
             other_state => panic!("starting an unresolved component: {:?}", other_state),
         });
 
@@ -516,43 +548,6 @@
     Ok(fmem::Data::Buffer(fmem::Buffer { vmo, size }))
 }
 
-/// Returns a configured Runtime for a component and the start info (without actually starting
-/// the component).
-async fn make_execution_runtime(
-    component: &Arc<ComponentInstance>,
-    checker: &GlobalPolicyChecker,
-    decl: &cm_rust::ComponentDecl,
-    start_reason: StartReason,
-    execution_controller_task: Option<controller::ExecutionControllerTask>,
-) -> Result<StartedInstanceState, StartActionError> {
-    // TODO(https://fxbug.dev/42071809): Consider moving this check to ComponentInstance::add_child
-    match component.on_terminate {
-        fdecl::OnTerminate::Reboot => {
-            checker.reboot_on_terminate_allowed(&component.moniker).map_err(|err| {
-                StartActionError::RebootOnTerminateForbidden {
-                    moniker: component.moniker.clone(),
-                    err,
-                }
-            })?;
-        }
-        fdecl::OnTerminate::None => {}
-    }
-
-    let logger = if let Some(logsink_decl) = get_logsink_decl(&decl) {
-        match create_scoped_logger(component, logsink_decl.clone()).await {
-            Ok(logger) => Some(logger),
-            Err(err) => {
-                warn!(moniker = %component.moniker, %err, "Could not create logger for component. Logs will be attributed to component_manager");
-                None
-            }
-        }
-    } else {
-        None
-    };
-
-    Ok(StartedInstanceState::new(start_reason, execution_controller_task, logger))
-}
-
 /// Returns the UseProtocolDecl for the LogSink protocol, if any.
 fn get_logsink_decl<'a>(decl: &'a cm_rust::ComponentDecl) -> Option<&'a cm_rust::UseProtocolDecl> {
     decl.uses.iter().find_map(|use_| match use_ {
@@ -580,7 +575,7 @@
         crate::model::{
             actions::{ActionSet, ShutdownAction, ShutdownType, StopAction},
             component::instance::{ResolvedInstanceState, UnresolvedInstanceState},
-            component::Component,
+            component::{Component, WeakComponentInstance},
             error::ModelError,
             hooks::{EventType, Hook, HooksRegistration},
             structured_dict::ComponentInput,
@@ -789,16 +784,21 @@
         let child =
             test_topology.model.root().find(&TEST_CHILD_NAME.try_into().unwrap()).await.unwrap();
 
-        let start_fut = child.lock_actions().await.register_no_wait(
-            &child,
-            StartAction::new(StartReason::Debug, None, IncomingCapabilities::default()),
-        );
+        let start_fut = child
+            .lock_actions()
+            .await
+            .register_no_wait(
+                &child,
+                StartAction::new(StartReason::Debug, None, IncomingCapabilities::default()),
+            )
+            .await;
 
         // Wait until start is blocked.
         resolved_rx.await.unwrap();
 
         // Stop should cancel start.
-        let stop_fut = child.lock_actions().await.register_no_wait(&child, StopAction::new(false));
+        let stop_fut =
+            child.lock_actions().await.register_no_wait(&child, StopAction::new(false)).await;
         assert_matches!(
             start_fut.await.unwrap_err(),
             ActionError::StartError { err: StartActionError::Aborted { .. } }
@@ -958,7 +958,13 @@
             )
             .await
             .unwrap();
-            let started_state = StartedInstanceState::new(StartReason::Debug, None, None);
+            let started_state = StartedInstanceState::new(
+                None,
+                WeakComponentInstance::invalid(),
+                StartReason::Debug,
+                None,
+                None,
+            );
             assert_matches!(
                 should_return_early(&InstanceState::Started(ris, started_state), &m),
                 Some(Ok(()))
diff --git a/src/sys/component_manager/src/model/actions/stop.rs b/src/sys/component_manager/src/model/actions/stop.rs
index ada50830..9681d9a 100644
--- a/src/sys/component_manager/src/model/actions/stop.rs
+++ b/src/sys/component_manager/src/model/actions/stop.rs
@@ -25,11 +25,11 @@
 
 #[async_trait]
 impl Action for StopAction {
-    async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
+    async fn handle(self, component: Arc<ComponentInstance>) -> Result<(), ActionError> {
         // Ensure `Stop` is dispatched after `Discovered`.
         {
             let discover_completed =
-                component.lock_actions().await.wait_for_action(ActionKey::Discover);
+                component.lock_actions().await.wait_for_action(ActionKey::Discover).await;
             discover_completed.await.unwrap();
         }
         component.stop_instance_internal(self.shut_down).await.map_err(Into::into)
@@ -182,7 +182,7 @@
         let component_root = test.look_up(Moniker::root()).await;
         let component_a = test.look_up(vec!["a"].try_into().unwrap()).await;
         let mut actions = component_a.lock_actions().await;
-        let nf = actions.register_no_wait(&component_a, StopAction::new(false));
+        let nf = actions.register_no_wait(&component_a, StopAction::new(false)).await;
         drop(actions);
         stopped_rx.await.unwrap();
 
diff --git a/src/sys/component_manager/src/model/actions/unresolve.rs b/src/sys/component_manager/src/model/actions/unresolve.rs
index 3a9ce38..49b2077 100644
--- a/src/sys/component_manager/src/model/actions/unresolve.rs
+++ b/src/sys/component_manager/src/model/actions/unresolve.rs
@@ -4,14 +4,13 @@
 
 use {
     crate::model::{
-        actions::{Action, ActionKey, ActionSet, ShutdownAction, ShutdownType},
+        actions::{shutdown::do_shutdown, Action, ActionKey, ShutdownType},
         component::instance::InstanceState,
         component::ComponentInstance,
         error::{ActionError, UnresolveActionError},
         hooks::{Event, EventPayload},
     },
     async_trait::async_trait,
-    futures::future::join_all,
     std::sync::Arc,
 };
 
@@ -29,8 +28,8 @@
 
 #[async_trait]
 impl Action for UnresolveAction {
-    async fn handle(self, component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
-        do_unresolve(component).await
+    async fn handle(self, component: Arc<ComponentInstance>) -> Result<(), ActionError> {
+        do_unresolve(&component).await
     }
     fn key(&self) -> ActionKey {
         ActionKey::Unresolve
@@ -38,43 +37,19 @@
 }
 
 // Implement the UnresolveAction by resetting the state from unresolved to unresolved and emitting
-// an Unresolved event. Unresolve the component's resolved children if any.
+// an Unresolved event.
 async fn do_unresolve(component: &Arc<ComponentInstance>) -> Result<(), ActionError> {
-    // Shut down the component, preventing new starts or resolves during the UnresolveAction.
-    ActionSet::register(component.clone(), ShutdownAction::new(ShutdownType::Instance)).await?;
-
-    if !component.lock_state().await.is_shut_down() {
-        return Err(
-            UnresolveActionError::InstanceRunning { moniker: component.moniker.clone() }.into()
-        );
-    }
-
-    // Unresolve all children
-    let children = {
-        let state = component.lock_state().await;
-        match *state {
-            InstanceState::Shutdown(ref state, _) => state.children.clone(),
-            InstanceState::Destroyed => {
-                return Err(UnresolveActionError::InstanceDestroyed {
-                    moniker: component.moniker.clone(),
-                }
-                .into())
-            }
-            _ => {
-                panic!("component {} was moved to unexpected state {:?}", component.moniker, state)
-            }
-        }
-    };
-    let mut futures = vec![];
-    for (_name, child) in children {
-        futures
-            .push(async move { ActionSet::register(child.clone(), UnresolveAction::new()).await });
-    }
-    // Run all the futures, and then return the first error if there were any.
-    join_all(futures).await.into_iter().fold(Ok(()), |acc, r| acc.and_then(|_| r))?;
+    // We want to shut down the component without invoking a full shutdown action, as the
+    // unresolved state of a component is viewed as unreachable from the shutdown state by the
+    // actions system.
+    //
+    // TODO(fxbug.dev/TODO): refactor shutdown such that the component is not put in an
+    // InstanceState::Shutdown when invoked from here. This will allow us to remove
+    // UnresolvedInstanceState from InstanceState::Shutdown.
+    do_shutdown(component, ShutdownType::Instance).await?;
 
     // Move this component back to the Unresolved state. The state may have changed during the time
-    // taken for the children to unresolve, so recheck here.
+    // between the do_shutdown call and now, so recheck here.
     {
         let mut state = component.lock_state().await;
         if let InstanceState::Destroyed = &*state {
@@ -83,6 +58,12 @@
             }
             .into());
         }
+        if !state.is_shut_down() {
+            return Err(UnresolveActionError::InstanceRunning {
+                moniker: component.moniker.clone(),
+            }
+            .into());
+        }
         state.replace(|instance_state| match instance_state {
             InstanceState::Shutdown(_, unresolved_state) => {
                 InstanceState::Unresolved(unresolved_state)
@@ -111,7 +92,7 @@
 pub mod tests {
     use {
         crate::model::{
-            actions::test_utils::{is_destroyed, is_discovered, is_resolved},
+            actions::test_utils::{is_destroyed, is_discovered, is_resolved, is_shutdown},
             actions::{ActionSet, ShutdownAction, ShutdownType, UnresolveAction},
             component::{ComponentInstance, StartReason},
             error::{ActionError, UnresolveActionError},
@@ -161,10 +142,13 @@
             .await
             .expect("unresolve failed");
         assert!(is_resolved(&component_root).await);
-        // Unresolved recursively, so children in Discovered state.
+        // Component a is back in the discovered state
         assert!(is_discovered(&component_a).await);
-        assert!(is_discovered(&component_b).await);
-        assert!(is_discovered(&component_c).await);
+        // The original descendents of component a have been placed in a Shutdown state.
+        assert!(is_shutdown(&component_b).await);
+        assert!(is_shutdown(&component_c).await);
+        // Component a itself is now unresolved, and thus does not have children anymore.
+        assert_matches!(component_a.find(&vec!["b"].try_into().unwrap()).await, None);
 
         // Unresolve again, which is ok because UnresolveAction is idempotent.
         assert_matches!(
@@ -216,11 +200,14 @@
             .await
             .expect("unresolve failed");
 
-        // Unresolved recursively, so children in Discovered state.
+        // Component a is back in the discovered state
         assert!(is_discovered(&component_a).await);
-        assert!(is_discovered(&component_b).await);
-        assert!(is_discovered(&component_c).await);
-        assert!(is_discovered(&component_d).await);
+        // The original descendents of component a have been placed in a Shutdown state.
+        assert!(is_shutdown(&component_b).await);
+        assert!(is_shutdown(&component_c).await);
+        assert!(is_shutdown(&component_d).await);
+        // Component a itself is now unresolved, and thus does not have children anymore.
+        assert_matches!(component_a.find(&vec!["b"].try_into().unwrap()).await, None);
     }
 
     async fn setup_unresolve_test_event_stream(
@@ -272,14 +259,10 @@
         // Register the UnresolveAction.
         let nf = {
             let mut actions = component_a.lock_actions().await;
-            actions.register_no_wait(&component_a, UnresolveAction::new())
+            actions.register_no_wait(&component_a, UnresolveAction::new()).await
         };
 
-        // Confirm that the Unresolved events are emitted in the expected recursive order.
-        event_stream
-            .wait_until(EventType::Unresolved, vec!["a", "b"].try_into().unwrap())
-            .await
-            .unwrap();
+        // Component a is then unresolved.
         event_stream
             .wait_until(EventType::Unresolved, vec!["a"].try_into().unwrap())
             .await
@@ -289,7 +272,7 @@
         // Now attempt to unresolve again with another UnresolveAction.
         let nf2 = {
             let mut actions = component_a.lock_actions().await;
-            actions.register_no_wait(&component_a, UnresolveAction::new())
+            actions.register_no_wait(&component_a, UnresolveAction::new()).await
         };
         // The component is not resolved anymore, so the unresolve will have no effect.
         nf2.await.unwrap();
diff --git a/src/sys/component_manager/src/model/component/instance.rs b/src/sys/component_manager/src/model/component/instance.rs
index 1dc2a1c..dcfe317 100644
--- a/src/sys/component_manager/src/model/component/instance.rs
+++ b/src/sys/component_manager/src/model/component/instance.rs
@@ -11,7 +11,7 @@
                 resolve::sandbox_construction::{
                     self, build_component_sandbox, extend_dict_with_offers,
                 },
-                shutdown, ActionKey, DiscoverAction, StopAction,
+                shutdown, ActionKey, ActionSet, DiscoverAction, StopAction,
             },
             component::{
                 Component, ComponentInstance, Package, StartReason, WeakComponentInstance,
@@ -619,13 +619,7 @@
     /// [`Router`]s. This [`Dict`] is used to generate the `exposed_dir`. This function creates a new [`Dict`],
     /// so allocation cost is paid only when called.
     pub async fn make_exposed_dict(&self) -> Dict {
-        // Unwrap is safe because `ResolvedInstanceState` is held within `ComponentInstance`.
-        let routing_task_group = self.weak_component.upgrade().unwrap().blocking_task_group();
-        let dict = Router::dict_routers_to_open(
-            &self.weak_component,
-            &self.component_output_dict,
-            routing_task_group,
-        );
+        let dict = Router::dict_routers_to_open(&self.weak_component, &self.component_output_dict);
         Self::extend_exposed_dict_with_legacy(&self.weak_component, self.decl(), &dict);
         dict
     }
@@ -655,7 +649,10 @@
                 None => continue,
             };
             let open = Open::new(RouteEntry::new(component.clone(), request, type_name.into()));
-            target_dict.insert_capability(target_name, open.into());
+            match target_dict.insert_capability(target_name, open.into()) {
+                Ok(()) => (),
+                Err(e) => warn!("failed to insert {} in target dict: {e:?}", target_name),
+            };
         }
     }
 
@@ -694,12 +691,12 @@
         self.dynamic_offers.retain(|offer| {
             let source_matches = offer.source()
                 == &cm_rust::OfferSource::Child(cm_rust::ChildRef {
-                    name: moniker.name().to_string().into(),
+                    name: moniker.name().clone(),
                     collection: moniker.collection().map(|c| c.clone()),
                 });
             let target_matches = offer.target()
                 == &cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                    name: moniker.name().to_string().into(),
+                    name: moniker.name().clone(),
                     collection: moniker.collection().map(|c| c.clone()),
                 });
             if target_matches && offer.source() == &cm_rust::OfferSource::Self_ {
@@ -804,6 +801,7 @@
             .lock_actions()
             .await
             .register_no_wait(&child, DiscoverAction::new(input))
+            .await
             .boxed();
         Ok((child, discover_fut))
     }
@@ -892,7 +890,8 @@
             WeakExtendedInstance::Component(WeakComponentInstance::from(component)),
             component.hooks.clone(),
             component.persistent_storage_for_child(collection),
-        );
+        )
+        .await;
         if let Some(controller) = controller {
             if let Ok(stream) = controller.into_stream() {
                 child
@@ -1019,13 +1018,15 @@
 
     async fn discover_static_children(&self, mut child_inputs: StructuredDictMap<ComponentInput>) {
         for (child_name, child_instance) in &self.children {
-            let child_name = Name::new(child_name.name()).unwrap();
+            if let Some(_) = child_name.collection {
+                continue;
+            }
+            let child_name =
+                Name::new(child_name.name.as_str()).expect("child is static so name is not long");
             let child_input = child_inputs.remove(&child_name).expect("missing child dict");
-            let _discover_fut = child_instance
-                .clone()
-                .lock_actions()
+            ActionSet::register(child_instance.clone(), DiscoverAction::new(child_input))
                 .await
-                .register_no_wait(&child_instance, DiscoverAction::new(child_input));
+                .expect("failed to discover child");
         }
     }
 }
@@ -1107,7 +1108,7 @@
             terminated_fut.await;
             if let Ok(component) = component.upgrade() {
                 let mut actions = component.lock_actions().await;
-                let stop_nf = actions.register_no_wait(&component, StopAction::new(false));
+                let stop_nf = actions.register_no_wait(&component, StopAction::new(false)).await;
                 drop(actions);
                 component.nonblocking_task_group().spawn(fasync::Task::spawn(async move {
                     let _ = stop_nf.await.map_err(
@@ -1160,7 +1161,7 @@
 
     /// This stores the hook for notifying an ExecutionController about stop events for this
     /// component.
-    pub execution_controller_task: Option<controller::ExecutionControllerTask>,
+    execution_controller_task: Option<controller::ExecutionControllerTask>,
 
     /// Logger attributed to this component.
     ///
@@ -1169,14 +1170,20 @@
 }
 
 impl StartedInstanceState {
+    /// Creates the state corresponding to a started component.
+    ///
+    /// If `program` is present, also creates a background task waiting for the program to
+    /// terminate. When that happens, uses the [`WeakComponentInstance`] to stop the component.
     pub fn new(
+        program: Option<Program>,
+        component: WeakComponentInstance,
         start_reason: StartReason,
         execution_controller_task: Option<controller::ExecutionControllerTask>,
         logger: Option<ScopedLogger>,
     ) -> Self {
         let timestamp = zx::Time::get_monotonic();
         StartedInstanceState {
-            program: None,
+            program: program.map(|p| ProgramRuntime::new(p, component)),
             timestamp,
             binder_server_ends: vec![],
             start_reason,
@@ -1185,34 +1192,22 @@
         }
     }
 
-    /// If this component is associated with a running [Program], obtain a capability
-    /// representing its runtime directory.
+    /// If this component has a program, obtain a capability representing its runtime directory.
     pub fn runtime_dir(&self) -> Option<&fio::DirectoryProxy> {
         self.program.as_ref().map(|program_runtime| program_runtime.program.runtime())
     }
 
-    /// Associates the [StartedInstanceState] with a running [Program].
-    ///
-    /// Creates a background task waiting for the program to terminate. When that happens, use the
-    /// [WeakComponentInstance] to stop the component.
-    pub fn set_program(&mut self, program: Program, component: WeakComponentInstance) {
-        self.program = Some(ProgramRuntime::new(program, component));
-    }
-
-    /// Stop the program, if any. The timer defines how long the runner is given to stop the
-    /// program gracefully before we request the controller to terminate the program.
-    ///
-    /// Regardless if the runner honored our request, after this method, the [`StartedInstanceState`] is
-    /// no longer associated with a [Program].
-    pub async fn stop_program<'a, 'b>(
-        &'a mut self,
+    /// Stops the component. If the component has a program, the timer defines how long
+    /// the runner is given to stop the program gracefully before we request the controller
+    /// to terminate the program.
+    pub async fn stop<'a, 'b>(
+        mut self,
         stop_timer: BoxFuture<'a, ()>,
         kill_timer: BoxFuture<'b, ()>,
     ) -> Result<StopOutcomeWithEscrow, program::StopError> {
         let program = self.program.take();
-        // Potentially there is no program, perhaps because the component
-        // has no running code. In this case this is a no-op.
-        if let Some(program) = program {
+        // If the component has a program, also stop the program.
+        let ret = if let Some(program) = program {
             program.stop(stop_timer, kill_timer).await
         } else {
             Ok(StopOutcomeWithEscrow {
@@ -1222,7 +1217,11 @@
                 },
                 escrow_request: None,
             })
+        }?;
+        if let Some(execution_controller_task) = self.execution_controller_task.as_mut() {
+            execution_controller_task.set_stop_status(ret.outcome.component_exit_status);
         }
+        Ok(ret)
     }
 
     /// Add a channel scoped to the lifetime of this object.
@@ -1269,7 +1268,8 @@
         // TODO(https://fxbug.dev/320698181): Before dispatching events we need to wait for any
         // in-progress resolve actions to end. See https://fxbug.dev/320698181#comment21 for why.
         {
-            let resolve_completed = source.lock_actions().await.wait_for_action(ActionKey::Resolve);
+            let resolve_completed =
+                source.lock_actions().await.wait_for_action(ActionKey::Resolve).await;
             resolve_completed.await.unwrap();
         }
         source.hooks.dispatch(&event).await;
diff --git a/src/sys/component_manager/src/model/component/mod.rs b/src/sys/component_manager/src/model/component/mod.rs
index 3be9278..57b15bc 100644
--- a/src/sys/component_manager/src/model/component/mod.rs
+++ b/src/sys/component_manager/src/model/component/mod.rs
@@ -61,7 +61,7 @@
     },
     manager::ComponentManagerInstance,
     moniker::{ChildName, ChildNameBase, Moniker, MonikerBase},
-    sandbox::{Capability, Dict, Open},
+    sandbox::{Capability, Dict, DictEntries, Open},
     std::{
         clone::Clone,
         collections::{HashMap, HashSet},
@@ -260,18 +260,15 @@
     /// Tasks owned by this component instance that will be cancelled if the component is
     /// destroyed.
     nonblocking_task_group: TaskGroup,
-    /// Tasks owned by this component instance that will block destruction if the component is
-    /// destroyed.
-    blocking_task_group: TaskGroup,
     /// The ExecutionScope for this component. Pseudo directories should be hosted with this scope
     /// to tie their life-time to that of the component. Tasks can block component destruction by
-    /// using `active_guard()` (as an alternative to `blocking_task_group`).
+    /// using `active_guard()`.
     pub execution_scope: ExecutionScope,
 }
 
 impl ComponentInstance {
     /// Instantiates a new root component instance.
-    pub fn new_root(
+    pub async fn new_root(
         environment: Environment,
         context: Arc<ModelContext>,
         component_manager_instance: Weak<ComponentManagerInstance>,
@@ -289,11 +286,12 @@
             Arc::new(Hooks::new()),
             false,
         )
+        .await
     }
 
     /// Instantiates a new component instance with the given contents.
     // TODO(https://fxbug.dev/42077692) convert this to a builder API
-    pub fn new(
+    pub async fn new(
         environment: Arc<Environment>,
         instanced_moniker: InstancedMoniker,
         component_url: String,
@@ -320,7 +318,6 @@
             actions: Mutex::new(ActionSet::new()),
             hooks,
             nonblocking_task_group: TaskGroup::new(),
-            blocking_task_group: TaskGroup::new(),
             persistent_storage,
             execution_scope: ExecutionScope::new(),
         })
@@ -344,12 +341,6 @@
         self.nonblocking_task_group.clone()
     }
 
-    /// Returns a group for this instance where tasks can be run scoped to this instance. Tasks run
-    /// in this group will block destruction if the component is destroyed.
-    pub fn blocking_task_group(&self) -> TaskGroup {
-        self.blocking_task_group.clone()
-    }
-
     /// Returns true if the component is started, i.e. when it has a runtime.
     pub async fn is_started(&self) -> bool {
         self.lock_state().await.is_started()
@@ -508,7 +499,7 @@
             };
             let dict_entries = {
                 let mut entries = dict.lock_entries();
-                std::mem::replace(&mut *entries, std::collections::BTreeMap::new())
+                std::mem::replace(&mut *entries, DictEntries::new())
             };
             let capabilities = child_input.capabilities();
             let mut child_dict_entries = capabilities.lock_entries();
@@ -517,18 +508,17 @@
                 // ChildArgs.dict may contain capabilities created by an external client.
                 //
                 // Currently there is no way to create a Rotuer externally, so assume these
-                // are Open capabilities and convert them to Router here.
+                // are Sender capabilities and convert them to Router here.
                 //
                 // TODO(https://fxbug.dev/319542502): Consider using the external Router type, once
                 // it exists
                 let router = match value {
-                    Capability::Open(o) => Router::new_ok(o),
+                    Capability::Sender(s) => Router::new_ok(s),
                     _ => return Err(AddDynamicChildError::InvalidDictionary),
                 };
 
-                if child_dict_entries
-                    .insert(key.clone(), Capability::Router(Box::new(router)))
-                    .is_some()
+                if let Err(_) =
+                    child_dict_entries.insert(key.clone(), Capability::Router(Box::new(router)))
                 {
                     return Err(AddDynamicChildError::StaticRouteConflict { capability_name: key });
                 }
@@ -625,17 +615,17 @@
     ) -> Result<(), StopActionError> {
         // If the component is started, we first move it back to the resolved state. We will move
         // it to the shutdown state after the stopping is complete.
-        let mut runtime = None;
+        let mut started = None;
         self.lock_state().await.replace(|instance_state| match instance_state {
             InstanceState::Started(resolved_state, started_state) => {
-                runtime = Some(started_state);
+                started = Some(started_state);
                 InstanceState::Resolved(resolved_state)
             }
             other_state => other_state,
         });
 
         let stop_result = {
-            if let Some(runtime) = &mut runtime {
+            if let Some(started) = started {
                 let stop_timer = Box::pin(async move {
                     let timer = fasync::Timer::new(fasync::Time::after(zx::Duration::from(
                         self.environment.stop_timeout(),
@@ -648,8 +638,8 @@
                     )));
                     timer.await;
                 });
-                let ret = runtime
-                    .stop_program(stop_timer, kill_timer)
+                let ret = started
+                    .stop(stop_timer, kill_timer)
                     .await
                     .map_err(StopActionError::ProgramStopError)?;
                 if ret.outcome.request == StopRequestSuccess::KilledAfterTimeout
@@ -673,11 +663,6 @@
                         .map_err(|_| StopActionError::GetTopInstanceFailed)?;
                     top_instance.trigger_reboot().await;
                 }
-
-                if let Some(execution_controller_task) = runtime.execution_controller_task.as_mut()
-                {
-                    execution_controller_task.set_stop_status(ret.outcome.component_exit_status);
-                }
                 Some(ret)
             } else {
                 None
@@ -708,8 +693,13 @@
                 };
             }
 
-            let event =
-                Event::new(self, EventPayload::Stopped { status: outcome.component_exit_status });
+            let event = Event::new(
+                self,
+                EventPayload::Stopped {
+                    status: outcome.component_exit_status,
+                    stop_time: zx::Time::get_monotonic(),
+                },
+            );
             self.hooks.dispatch(&event).await;
         }
 
@@ -1399,7 +1389,6 @@
         let mut event_stream = event_source
             .subscribe(
                 vec![
-                    EventType::Discovered.into(),
                     EventType::Resolved.into(),
                     EventType::Started.into(),
                     EventType::DebugStarted.into(),
@@ -1426,8 +1415,6 @@
         }
         .remote_handle();
         fasync::Task::spawn(f).detach();
-        let discovered_timestamp =
-            wait_until_event_get_timestamp(&mut event_stream, EventType::Discovered).await;
         let resolved_timestamp =
             wait_until_event_get_timestamp(&mut event_stream, EventType::Resolved).await;
         let started_timestamp =
@@ -1435,7 +1422,6 @@
         let debug_started_timestamp =
             wait_until_event_get_timestamp(&mut event_stream, EventType::DebugStarted).await;
 
-        assert!(discovered_timestamp < resolved_timestamp);
         assert!(resolved_timestamp < started_timestamp);
         assert!(started_timestamp == debug_started_timestamp);
 
@@ -1556,16 +1542,18 @@
         // Resolve each component.
         test.look_up(Moniker::root()).await;
         let component_a = test.look_up(vec!["a"].try_into().unwrap()).await;
-        let component_b = test.look_up(vec!["a", "b"].try_into().unwrap()).await;
-        let component_c = test.look_up(vec!["a", "b", "c"].try_into().unwrap()).await;
-        let component_d = test.look_up(vec!["a", "b", "d"].try_into().unwrap()).await;
+        let _component_b = test.look_up(vec!["a", "b"].try_into().unwrap()).await;
+        let _component_c = test.look_up(vec!["a", "b", "c"].try_into().unwrap()).await;
+        let _component_d = test.look_up(vec!["a", "b", "d"].try_into().unwrap()).await;
 
         // Just unresolve component a and children
         assert_matches!(component_a.unresolve().await, Ok(()));
+        // component a is now resolved
         assert!(is_discovered(&component_a).await);
-        assert!(is_discovered(&component_b).await);
-        assert!(is_discovered(&component_c).await);
-        assert!(is_discovered(&component_d).await);
+        // Component a no longer has children, due to not being resolved
+        assert_matches!(component_a.find(&vec!["b"].try_into().unwrap()).await, None);
+        assert_matches!(component_a.find(&vec!["b", "c"].try_into().unwrap()).await, None);
+        assert_matches!(component_a.find(&vec!["b", "d"].try_into().unwrap()).await, None);
 
         // Unresolve again, which is ok because UnresolveAction is idempotent.
         assert_matches!(component_a.unresolve().await, Ok(()));
@@ -1626,8 +1614,8 @@
     async fn shutdown_component_interface_no_dynamic() {
         let example_offer = OfferBuilder::directory()
             .name("foo")
-            .source(OfferSource::static_child("a".to_string()))
-            .target(OfferTarget::static_child("b".to_string()))
+            .source_static_child("a")
+            .target_static_child("b")
             .build();
         let example_capability = CapabilityBuilder::protocol().name("bar").build();
         let example_expose =
@@ -1694,8 +1682,8 @@
     async fn shutdown_component_interface_dynamic_children_and_offers() {
         let example_offer = OfferBuilder::directory()
             .name("foo")
-            .source(OfferSource::static_child("a".to_string()))
-            .target(OfferTarget::static_child("b".to_string()))
+            .source_static_child("a")
+            .target_static_child("b")
             .build();
 
         let components = vec![
@@ -1750,11 +1738,11 @@
 
         let example_dynamic_offer = OfferDecl::Protocol(OfferProtocolDecl {
             source: OfferSource::Child(ChildRef {
-                name: "a".into(),
+                name: "a".parse().unwrap(),
                 collection: Some("coll_1".parse().unwrap()),
             }),
             target: OfferTarget::Child(ChildRef {
-                name: "b".into(),
+                name: "b".parse().unwrap(),
                 collection: Some("coll_1".parse().unwrap()),
             }),
             source_dictionary: Default::default(),
@@ -1843,7 +1831,7 @@
             fcomponent::CreateChildArgs {
                 dynamic_offers: Some(vec![fdecl::Offer::Protocol(fdecl::OfferProtocol {
                     source: Some(fdecl::Ref::Child(fdecl::ChildRef {
-                        name: "a".into(),
+                        name: "a".parse().unwrap(),
                         collection: Some("coll_2".parse().unwrap()),
                     })),
                     source_name: Some("dyn_offer2_source_name".to_string()),
@@ -1859,11 +1847,11 @@
 
         let example_dynamic_offer2 = OfferDecl::Protocol(OfferProtocolDecl {
             source: OfferSource::Child(ChildRef {
-                name: "a".into(),
+                name: "a".parse().unwrap(),
                 collection: Some("coll_2".parse().unwrap()),
             }),
             target: OfferTarget::Child(ChildRef {
-                name: "b".into(),
+                name: "b".parse().unwrap(),
                 collection: Some("coll_1".parse().unwrap()),
             }),
             source_name: "dyn_offer2_source_name".parse().unwrap(),
@@ -1915,7 +1903,7 @@
         let example_offer = OfferBuilder::service()
             .name("foo")
             .source(OfferSource::Collection("coll".parse().unwrap()))
-            .target(OfferTarget::static_child("static_child".to_string()))
+            .target_static_child("static_child")
             .build();
 
         let components = vec![
@@ -2096,6 +2084,7 @@
             Arc::new(Hooks::new()),
             false,
         )
+        .await
     }
 
     async fn new_resolved() -> InstanceState {
@@ -2243,7 +2232,7 @@
                     Some(offers),
                     None,
                     &ChildDecl {
-                        name: "foo".to_string(),
+                        name: "foo".parse().unwrap(),
                         url: "http://foo".to_string(),
                         startup: fdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -2280,7 +2269,7 @@
                 source_name: "fuchsia.example.Echo".parse().unwrap(),
                 source_dictionary: Default::default(),
                 target: OfferTarget::Child(ChildRef {
-                    name: "foo".into(),
+                    name: "foo".parse().unwrap(),
                     collection: Some("col".parse().unwrap()),
                 }),
                 target_name: "fuchsia.example.Echo".parse().unwrap(),
@@ -2307,7 +2296,7 @@
                 source_name: "fuchsia.example.Echo".parse().unwrap(),
                 source_dictionary: Default::default(),
                 target: OfferTarget::Child(ChildRef {
-                    name: "foo".into(),
+                    name: "foo".parse().unwrap(),
                     collection: Some("col".parse().unwrap()),
                 }),
                 target_name: "fuchsia.example.Echo".parse().unwrap(),
@@ -2338,13 +2327,13 @@
             if err == DynamicOfferError::SourceNotFound {
                 offer: OfferDecl::Protocol(OfferProtocolDecl {
                     source: OfferSource::Child(ChildRef {
-                        name: "doesnt-exist".into(),
+                        name: "doesnt-exist".parse().unwrap(),
                         collection: Some("col".parse().unwrap()),
                     }),
                     source_name: "fuchsia.example.Echo".parse().unwrap(),
                     source_dictionary: Default::default(),
                     target: OfferTarget::Child(ChildRef {
-                        name: "foo".into(),
+                        name: "foo".parse().unwrap(),
                         collection: Some("col".parse().unwrap()),
                     }),
                     target_name: "fuchsia.example.Echo".parse().unwrap(),
@@ -2384,7 +2373,7 @@
                     None,
                     Some(capabilities),
                     &ChildDecl {
-                        name: "foo".to_string(),
+                        name: "foo".parse().unwrap(),
                         url: "http://foo".to_string(),
                         startup: fdecl::StartupMode::Lazy,
                         on_terminate: None,
@@ -2449,7 +2438,7 @@
                         OfferBuilder::protocol()
                             .name(flogger::LogSinkMarker::PROTOCOL_NAME)
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child(TEST_CHILD_NAME.to_string())),
+                            .target_static_child(TEST_CHILD_NAME),
                     )
                     .child_default(TEST_CHILD_NAME)
                     .build(),
@@ -2540,9 +2529,9 @@
         // Resolve each component.
         test.look_up(Moniker::root()).await;
         let component_a = test.look_up(vec!["a"].try_into().unwrap()).await;
-        let component_b = test.look_up(vec!["a", "b"].try_into().unwrap()).await;
-        let component_c = test.look_up(vec!["a", "b", "c"].try_into().unwrap()).await;
-        let component_d = test.look_up(vec!["a", "b", "d"].try_into().unwrap()).await;
+        let _component_b = test.look_up(vec!["a", "b"].try_into().unwrap()).await;
+        let _component_c = test.look_up(vec!["a", "b", "c"].try_into().unwrap()).await;
+        let _component_d = test.look_up(vec!["a", "b", "d"].try_into().unwrap()).await;
 
         // Now they can all be found.
         assert_matches!(root.find_resolved(&vec!["a"].try_into().unwrap()).await, Some(_));
@@ -2564,21 +2553,16 @@
             None
         );
 
-        // Unresolve, recursively.
+        // Unresolve component a, this causes it to stop having children and drop component b after
+        // shutting it down.
         ActionSet::register(component_a.clone(), UnresolveAction::new())
             .await
             .expect("unresolve failed");
 
-        // Unresolved recursively, so children in Discovered state.
-        assert!(is_discovered(&component_a).await);
-        assert!(is_discovered(&component_b).await);
-        assert!(is_discovered(&component_c).await);
-        assert!(is_discovered(&component_d).await);
-
-        assert_matches!(root.find_resolved(&vec!["a"].try_into().unwrap()).await, None);
-        assert_matches!(root.find_resolved(&vec!["a", "b"].try_into().unwrap()).await, None);
-        assert_matches!(root.find_resolved(&vec!["a", "b", "c"].try_into().unwrap()).await, None);
-        assert_matches!(root.find_resolved(&vec!["a", "b", "d"].try_into().unwrap()).await, None);
+        // Because component a is not resolved, it does not have children
+        assert_matches!(component_a.find(&vec!["b"].try_into().unwrap()).await, None);
+        assert_matches!(component_a.find(&vec!["b", "c"].try_into().unwrap()).await, None);
+        assert_matches!(component_a.find(&vec!["b", "d"].try_into().unwrap()).await, None);
     }
 
     /// If a component is not started, a call to `open_outgoing` should start the component
diff --git a/src/sys/component_manager/src/model/environment.rs b/src/sys/component_manager/src/model/environment.rs
index a6f3412..a714fbf 100644
--- a/src/sys/component_manager/src/model/environment.rs
+++ b/src/sys/component_manager/src/model/environment.rs
@@ -186,7 +186,8 @@
             Arc::new(ModelContext::new_for_test()),
             Weak::new(),
             "test:///root".to_string(),
-        );
+        )
+        .await;
         let environment = Environment::from_decl(
             &component,
             &EnvironmentBuilder::new()
diff --git a/src/sys/component_manager/src/model/error.rs b/src/sys/component_manager/src/model/error.rs
index 4851e28..9f6a673 100644
--- a/src/sys/component_manager/src/model/error.rs
+++ b/src/sys/component_manager/src/model/error.rs
@@ -559,6 +559,8 @@
     },
     #[error(transparent)]
     Policy(#[from] PolicyError),
+    #[error("Couldn't resolve `{moniker}` because the action was interrupted")]
+    Aborted { moniker: Moniker },
 }
 
 impl ResolveActionError {
@@ -572,6 +574,7 @@
             ResolveActionError::ExposeDirError { .. }
             | ResolveActionError::AddStaticChildError { .. }
             | ResolveActionError::StructuredConfigError { .. }
+            | ResolveActionError::Aborted { .. }
             | ResolveActionError::PackageDirProxyCreateError { .. } => zx::Status::INTERNAL,
             ResolveActionError::ResolverError { err, .. } => err.as_zx_status(),
             ResolveActionError::Policy(err) => err.as_zx_status(),
@@ -598,6 +601,7 @@
             | ResolveActionError::AddStaticChildError { .. }
             | ResolveActionError::DiscoverActionError { .. }
             | ResolveActionError::AbiCompatibilityError { .. }
+            | ResolveActionError::Aborted { .. }
             | ResolveActionError::PackageDirProxyCreateError { .. } => fsys::ResolveError::Internal,
             ResolveActionError::Policy(_) => fsys::ResolveError::PolicyError,
         }
@@ -624,6 +628,7 @@
             | ResolveActionError::AddStaticChildError { .. }
             | ResolveActionError::DiscoverActionError { .. }
             | ResolveActionError::AbiCompatibilityError { .. }
+            | ResolveActionError::Aborted { .. }
             | ResolveActionError::PackageDirProxyCreateError { .. } => fsys::StartError::Internal,
             ResolveActionError::Policy(_) => fsys::StartError::PolicyError,
         }
diff --git a/src/sys/component_manager/src/model/events/registry.rs b/src/sys/component_manager/src/model/events/registry.rs
index d44e98d..cf4ef9f6 100644
--- a/src/sys/component_manager/src/model/events/registry.rs
+++ b/src/sys/component_manager/src/model/events/registry.rs
@@ -30,7 +30,6 @@
     async_trait::async_trait,
     cm_rust::{ChildRef, EventScope, OfferDecl, UseDecl, UseEventStreamDecl},
     cm_types::Name,
-    flyweights::FlyStr,
     futures::lock::Mutex,
     moniker::{ChildNameBase, ExtendedMoniker, Moniker, MonikerBase},
     std::{
@@ -120,20 +119,18 @@
     /// filtering is performed.
     /// * The name of a component relative to its parent
     /// * The name of a collection relative to its parent
-    pub component: ChildRef,
+    ///
+    /// If None, refers to the root component.
+    pub component: Option<ChildRef>,
     /// A list of scopes that this route applies to
     pub scope: Option<Vec<EventScope>>,
 }
 
 impl ComponentEventRoute {
     fn from_moniker(moniker: &Moniker, scope: Option<Vec<EventScope>>) -> ComponentEventRoute {
-        let component = match moniker.leaf() {
-            Some(leaf) => ChildRef {
-                name: FlyStr::new(leaf.name.to_string()),
-                collection: leaf.collection.clone(),
-            },
-            None => ChildRef { name: FlyStr::new("<root>"), collection: None },
-        };
+        let component = moniker
+            .leaf()
+            .map(|leaf| ChildRef { name: leaf.name.clone(), collection: leaf.collection.clone() });
         ComponentEventRoute { component, scope }
     }
 }
@@ -353,10 +350,10 @@
         let _search_name: Name = event_decl.source_name;
         if let Some(moniker) = component.child_moniker() {
             route.push(ComponentEventRoute {
-                component: ChildRef {
-                    name: FlyStr::new(moniker.name()),
+                component: Some(ChildRef {
+                    name: moniker.name().clone(),
                     collection: moniker.collection().cloned(),
-                },
+                }),
                 scope: event_decl.scope,
             });
         }
diff --git a/src/sys/component_manager/src/model/events/serve.rs b/src/sys/component_manager/src/model/events/serve.rs
index 4c2fa8b..10a61eb 100644
--- a/src/sys/component_manager/src/model/events/serve.rs
+++ b/src/sys/component_manager/src/model/events/serve.rs
@@ -9,11 +9,10 @@
     },
     async_utils::stream::FlattenUnorderedExt,
     cm_rust::{ChildRef, EventScope},
-    cm_types::Name,
+    cm_types::{LongName, Name},
     cm_util::io::clone_dir,
     fidl::endpoints::Proxy,
     fidl_fuchsia_component as fcomponent, fidl_fuchsia_io as fio,
-    flyweights::FlyStr,
     fuchsia_zircon::{
         self as zx, sys::ZX_CHANNEL_MAX_MSG_BYTES, sys::ZX_CHANNEL_MAX_MSG_HANDLES, HandleBased,
     },
@@ -68,7 +67,7 @@
 // Returns true if the filter contains a specific Ref
 fn event_filter_contains_ref(
     filter: &Option<Vec<EventScope>>,
-    name: &str,
+    name: &LongName,
     collection: Option<&Name>,
 ) -> bool {
     filter.as_ref().map_or(true, |value| {
@@ -108,10 +107,10 @@
                 return false;
             }
             let child_ref = ChildRef {
-                name: FlyStr::new(event_part.name()),
+                name: event_part.name().clone(),
                 collection: event_part.collection().cloned(),
             };
-            if child_ref != component.component {
+            if Some(child_ref) != component.component {
                 // Reject due to path mismatch
                 return false;
             }
@@ -359,7 +358,7 @@
         EventPayload::CapabilityRequested { name, receiver, .. } => {
             create_capability_requested_payload(name.to_string(), receiver.clone())
         }
-        EventPayload::Stopped { status } => {
+        EventPayload::Stopped { status, .. } => {
             stream_once(Ok(fcomponent::EventPayload::Stopped(fcomponent::StoppedPayload {
                 status: Some(status.into_raw()),
                 ..Default::default()
@@ -501,12 +500,9 @@
             )
             .unwrap()]));
         let route = vec![
+            ComponentEventRoute { component: None, scope: None },
             ComponentEventRoute {
-                component: ChildRef { name: "<root>".into(), collection: None },
-                scope: None,
-            },
-            ComponentEventRoute {
-                component: ChildRef { name: "root".into(), collection: None },
+                component: Some(ChildRef { name: "root".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Collection("coll".parse().unwrap())]),
             },
         ];
@@ -520,16 +516,16 @@
     fn test_validate_and_filter_event_empty_moniker() {
         let mut event = ExtendedMoniker::ComponentInstance(Moniker::root());
         let route = vec![
+            ComponentEventRoute { component: None, scope: None },
             ComponentEventRoute {
-                component: ChildRef { name: "<root>".into(), collection: None },
-                scope: None,
-            },
-            ComponentEventRoute {
-                component: ChildRef { name: "core".into(), collection: None },
+                component: Some(ChildRef { name: "core".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Collection("test_manager".parse().unwrap())]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "test_manager".into(), collection: None },
+                component: Some(ChildRef {
+                    name: "test_manager".parse().unwrap(),
+                    collection: None,
+                }),
                 scope: None,
             },
         ];
@@ -547,26 +543,23 @@
             ChildName::try_new("c", None).unwrap(),
         ]));
         let route = vec![
+            ComponentEventRoute { component: None, scope: None },
             ComponentEventRoute {
-                component: ChildRef { name: "<root>".into(), collection: None },
-                scope: None,
-            },
-            ComponentEventRoute {
-                component: ChildRef { name: "a".into(), collection: None },
+                component: Some(ChildRef { name: "a".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Child(ChildRef {
-                    name: "b".into(),
+                    name: "b".parse().unwrap(),
                     collection: None,
                 })]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "b".into(), collection: None },
+                component: Some(ChildRef { name: "b".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Child(ChildRef {
-                    name: "c".into(),
+                    name: "c".parse().unwrap(),
                     collection: None,
                 })]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "c".into(), collection: None },
+                component: Some(ChildRef { name: "c".parse().unwrap(), collection: None }),
                 scope: None,
             },
         ];
@@ -586,26 +579,23 @@
             ChildName::try_new("d", None).unwrap(),
         ]));
         let route = vec![
+            ComponentEventRoute { component: None, scope: None },
             ComponentEventRoute {
-                component: ChildRef { name: "<root>".into(), collection: None },
-                scope: None,
-            },
-            ComponentEventRoute {
-                component: ChildRef { name: "a".into(), collection: None },
+                component: Some(ChildRef { name: "a".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Child(ChildRef {
-                    name: "b".into(),
+                    name: "b".parse().unwrap(),
                     collection: None,
                 })]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "b".into(), collection: None },
+                component: Some(ChildRef { name: "b".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Child(ChildRef {
-                    name: "c".into(),
+                    name: "c".parse().unwrap(),
                     collection: None,
                 })]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "c".into(), collection: None },
+                component: Some(ChildRef { name: "c".parse().unwrap(), collection: None }),
                 scope: None,
             },
         ];
@@ -628,20 +618,17 @@
                 ChildName::try_new("a", None).unwrap()
             ]));
         let route = vec![
+            ComponentEventRoute { component: None, scope: None },
             ComponentEventRoute {
-                component: ChildRef { name: "<root>".into(), collection: None },
-                scope: None,
-            },
-            ComponentEventRoute {
-                component: ChildRef { name: "a".into(), collection: None },
+                component: Some(ChildRef { name: "a".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Collection("b".parse().unwrap())]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "b".into(), collection: None },
+                component: Some(ChildRef { name: "b".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Collection("c".parse().unwrap())]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "c".into(), collection: None },
+                component: Some(ChildRef { name: "c".parse().unwrap(), collection: None }),
                 scope: None,
             },
         ];
@@ -664,20 +651,17 @@
             ChildName::try_new("i", None).unwrap(),
         ]));
         let route = vec![
+            ComponentEventRoute { component: None, scope: None },
             ComponentEventRoute {
-                component: ChildRef { name: "<root>".into(), collection: None },
+                component: Some(ChildRef { name: "a".parse().unwrap(), collection: None }),
                 scope: None,
             },
             ComponentEventRoute {
-                component: ChildRef { name: "a".into(), collection: None },
-                scope: None,
-            },
-            ComponentEventRoute {
-                component: ChildRef { name: "b".into(), collection: None },
+                component: Some(ChildRef { name: "b".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Collection("c".parse().unwrap())]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "c".into(), collection: None },
+                component: Some(ChildRef { name: "c".parse().unwrap(), collection: None }),
                 scope: None,
             },
         ];
@@ -694,20 +678,23 @@
             ChildName::try_new("feedback", None).unwrap(),
         ]));
         let route = vec![
+            ComponentEventRoute { component: None, scope: None },
             ComponentEventRoute {
-                component: ChildRef { name: "<root>".into(), collection: None },
-                scope: None,
-            },
-            ComponentEventRoute {
-                component: ChildRef { name: "core".into(), collection: None },
+                component: Some(ChildRef { name: "core".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Collection("test_manager".parse().unwrap())]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "test_manager".into(), collection: None },
+                component: Some(ChildRef {
+                    name: "test_manager".parse().unwrap(),
+                    collection: None,
+                }),
                 scope: Some(vec![EventScope::Collection("test_wrapper".parse().unwrap())]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "test_wrapper".into(), collection: None },
+                component: Some(ChildRef {
+                    name: "test_wrapper".parse().unwrap(),
+                    collection: None,
+                }),
                 scope: Some(vec![EventScope::Collection("test_root".parse().unwrap())]),
             },
         ];
@@ -727,47 +714,53 @@
             ChildName::try_new("archivist", None).unwrap(),
         ]));
         let route = vec![
+            ComponentEventRoute { component: None, scope: None },
             ComponentEventRoute {
-                component: ChildRef { name: "<root>".into(), collection: None },
-                scope: None,
-            },
-            ComponentEventRoute {
-                component: ChildRef { name: "core".into(), collection: None },
+                component: Some(ChildRef { name: "core".parse().unwrap(), collection: None }),
                 scope: Some(vec![EventScope::Child(ChildRef {
-                    name: "test_manager".into(),
+                    name: "test_manager".parse().unwrap(),
                     collection: None,
                 })]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "test_manager".into(), collection: None },
+                component: Some(ChildRef {
+                    name: "test_manager".parse().unwrap(),
+                    collection: None,
+                }),
                 scope: Some(vec![EventScope::Collection("tests".parse().unwrap())]),
             },
             ComponentEventRoute {
-                component: ChildRef {
-                    name: "auto-3fc01a79864c741".into(),
+                component: Some(ChildRef {
+                    name: "auto-3fc01a79864c741".parse().unwrap(),
                     collection: Some("tests".parse().unwrap()),
-                },
+                }),
                 scope: Some(vec![EventScope::Child(ChildRef {
-                    name: "test_wrapper".into(),
+                    name: "test_wrapper".parse().unwrap(),
                     collection: None,
                 })]),
             },
             ComponentEventRoute {
-                component: ChildRef { name: "test_wrapper".into(), collection: None },
+                component: Some(ChildRef {
+                    name: "test_wrapper".parse().unwrap(),
+                    collection: None,
+                }),
                 scope: Some(vec![
                     EventScope::Collection("test".parse().unwrap()),
-                    EventScope::Child(ChildRef { name: "enclosing_env".into(), collection: None }),
                     EventScope::Child(ChildRef {
-                        name: "hermetic_resolver".into(),
+                        name: "enclosing_env".parse().unwrap(),
+                        collection: None,
+                    }),
+                    EventScope::Child(ChildRef {
+                        name: "hermetic_resolver".parse().unwrap(),
                         collection: None,
                     }),
                 ]),
             },
             ComponentEventRoute {
-                component: ChildRef {
-                    name: "test_root".into(),
+                component: Some(ChildRef {
+                    name: "test_root".parse().unwrap(),
                     collection: Some("test".parse().unwrap()),
-                },
+                }),
                 scope: None,
             },
         ];
diff --git a/src/sys/component_manager/src/model/hooks.rs b/src/sys/component_manager/src/model/hooks.rs
index b18658c..27a58b0 100644
--- a/src/sys/component_manager/src/model/hooks.rs
+++ b/src/sys/component_manager/src/model/hooks.rs
@@ -256,6 +256,7 @@
     },
     Stopped {
         status: zx::Status,
+        stop_time: zx::Time,
     },
     DebugStarted {
         runtime_dir: Option<fio::DirectoryProxy>,
@@ -295,7 +296,7 @@
             EventPayload::Resolved { component: _, decl, .. } => {
                 formatter.field("decl", decl).finish()
             }
-            EventPayload::Stopped { status } => formatter.field("status", status).finish(),
+            EventPayload::Stopped { status, .. } => formatter.field("status", status).finish(),
             EventPayload::Unresolved
             | EventPayload::Discovered
             | EventPayload::Destroyed
@@ -418,7 +419,7 @@
             EventPayload::CapabilityRequested { source_moniker, name, .. } => {
                 format!("requested '{}' from '{}'", name.to_string(), source_moniker)
             }
-            EventPayload::Stopped { status } => {
+            EventPayload::Stopped { status, .. } => {
                 format!("with status: {}", status.to_string())
             }
             EventPayload::Discovered { .. }
diff --git a/src/sys/component_manager/src/model/model.rs b/src/sys/component_manager/src/model/model.rs
index e3341fd..a8a3066 100644
--- a/src/sys/component_manager/src/model/model.rs
+++ b/src/sys/component_manager/src/model/model.rs
@@ -4,7 +4,7 @@
 
 use {
     crate::model::{
-        actions::{ActionKey, DiscoverAction},
+        actions::{ActionKey, ActionSet, DiscoverAction},
         component::{manager::ComponentManagerInstance, ComponentInstance, StartReason},
         context::ModelContext,
         environment::Environment,
@@ -59,7 +59,8 @@
             context.clone(),
             Arc::downgrade(&params.top_instance),
             params.root_component_url,
-        );
+        )
+        .await;
         let model =
             Arc::new(Model { root: root.clone(), context, top_instance: params.top_instance });
         model.top_instance.init(root).await;
@@ -87,9 +88,9 @@
 
     /// Discovers the root component, providing it with `dict_for_root`.
     pub async fn discover_root_component(self: &Arc<Model>, input_for_root: ComponentInput) {
-        let mut actions = self.root.lock_actions().await;
-        // This returns a Future that does not need to be polled.
-        let _ = actions.register_no_wait(&self.root, DiscoverAction::new(input_for_root));
+        ActionSet::register(self.root.clone(), DiscoverAction::new(input_for_root))
+            .await
+            .expect("failed to discover root component");
     }
 
     /// Starts root, starting the component tree.
@@ -117,7 +118,7 @@
                 // shutdown, that's ok. The system is tearing down, so it doesn't matter any more
                 // if we never got everything started that we wanted to.
                 let action_set = self.root.lock_actions().await;
-                if !action_set.contains(&ActionKey::Shutdown) {
+                if !action_set.contains(ActionKey::Shutdown).await {
                     if !self.root.lock_state().await.is_shut_down() {
                         panic!(
                             "failed to start root component {}: {:?}",
diff --git a/src/sys/component_manager/src/model/namespace.rs b/src/sys/component_manager/src/model/namespace.rs
index 2959b2e..02939fd 100644
--- a/src/sys/component_manager/src/model/namespace.rs
+++ b/src/sys/component_manager/src/model/namespace.rs
@@ -10,7 +10,7 @@
             error::CreateNamespaceError,
             routing::{
                 self, route_and_open_capability,
-                router::{ErrorCapsule, Request, Router},
+                router::{Request, Router},
             },
         },
         sandbox_util::DictExt,
@@ -21,12 +21,11 @@
     },
     bedrock_error::{BedrockError, Explain},
     cm_rust::{ComponentDecl, UseDecl, UseEventStreamDecl, UseStorageDecl},
-    cm_util::TaskGroup,
     fidl::{endpoints::ClientEnd, prelude::*},
     fidl_fuchsia_io as fio, fuchsia_zircon as zx,
     futures::{
         channel::mpsc::{unbounded, UnboundedSender},
-        StreamExt,
+        FutureExt, StreamExt,
     },
     sandbox::{Capability, Dict, Directory, Open},
     serve_processargs::NamespaceBuilder,
@@ -37,7 +36,6 @@
             serve_directory, DirectoryEntry, DirectoryEntryAsync, EntryInfo, OpenRequest,
         },
         execution_scope::ExecutionScope,
-        ToObjectRequest,
     },
 };
 
@@ -124,25 +122,18 @@
             cm_rust::UseDecl::Storage(storage) => {
                 storage_use(storage, use_, component).await?.into()
             }
-            cm_rust::UseDecl::Protocol(s) => service_or_protocol_use(
-                UseDecl::Protocol(s.clone()),
-                component,
-                program_input_dict,
-                component.blocking_task_group(),
-            )
-            .into(),
-            cm_rust::UseDecl::Service(s) => service_or_protocol_use(
-                UseDecl::Service(s.clone()),
-                component,
-                program_input_dict,
-                component.blocking_task_group(),
-            )
-            .into(),
+            cm_rust::UseDecl::Protocol(s) => {
+                service_or_protocol_use(UseDecl::Protocol(s.clone()), component, program_input_dict)
+                    .into()
+            }
+            cm_rust::UseDecl::Service(s) => {
+                service_or_protocol_use(UseDecl::Service(s.clone()), component, program_input_dict)
+                    .into()
+            }
             cm_rust::UseDecl::EventStream(s) => service_or_protocol_use(
                 UseDecl::EventStream(s.clone()),
                 component,
                 program_input_dict,
-                component.blocking_task_group(),
             )
             .into(),
             cm_rust::UseDecl::Runner(_) => {
@@ -308,7 +299,6 @@
     use_: UseDecl,
     component: &Arc<ComponentInstance>,
     program_input_dict: &Dict,
-    blocking_task_group: TaskGroup,
 ) -> Open {
     match use_ {
         // Bedrock routing.
@@ -320,36 +310,41 @@
             let Some(capability) =
                 program_input_dict.get_capability(&use_protocol_decl.target_path)
             else {
-                panic!("router for capability {:?} is missing from program input dictionary for component {}", use_protocol_decl.target_path, component.moniker);
+                panic!(
+                    "router for capability {:?} is missing from program input dictionary for \
+                     component {}",
+                    use_protocol_decl.target_path, component.moniker
+                );
             };
             let Capability::Router(router) = &capability else {
-                panic!("program input dictionary for component {} had an entry with an unexpected type: {:?}", component.moniker, capability);
+                panic!(
+                    "program input dictionary for component {} had an entry with an unexpected \
+                     type: {:?}",
+                    component.moniker, capability
+                );
             };
             let router = Router::from_any(router.clone());
             let legacy_request = RouteRequest::UseProtocol(use_protocol_decl.clone());
 
             // When there are router errors, they are sent to the error handler, which reports
-            // errors and may attempt routing again via legacy.
+            // errors.
             let weak_component = component.as_weak();
-            let errors_fn = move |err: ErrorCapsule| {
-                let legacy_request = legacy_request.clone();
-                let Ok(target) = weak_component.upgrade() else {
-                    return;
-                };
-                target.blocking_task_group().spawn(async move {
-                    let (error, open_request) = err.manually_handle();
-                    let object_request =
-                        open_request.flags.to_object_request(open_request.server_end);
-                    object_request.shutdown(error.as_zx_status());
-                    routing::report_routing_failure(&legacy_request, &target, &error).await
-                });
-            };
 
             Open::new(router.into_directory_entry(
                 request,
                 fio::DirentType::Service,
-                blocking_task_group,
-                errors_fn,
+                move |error: &BedrockError| {
+                    let Ok(target) = weak_component.upgrade() else {
+                        return None;
+                    };
+                    let legacy_request = legacy_request.clone();
+                    Some(
+                        async move {
+                            routing::report_routing_failure(&legacy_request, &target, error).await
+                        }
+                        .boxed(),
+                    )
+                },
             ))
         }
 
diff --git a/src/sys/component_manager/src/model/resolver.rs b/src/sys/component_manager/src/model/resolver.rs
index a95575e..f31e6d0 100644
--- a/src/sys/component_manager/src/model/resolver.rs
+++ b/src/sys/component_manager/src/model/resolver.rs
@@ -347,12 +347,14 @@
             context,
             component_manager_instance,
             component_url,
-        );
+        )
+        .await;
         // We don't care about waiting for the discover action to complete, just that it's started.
         let _ = component
             .lock_actions()
             .await
-            .register_no_wait(&component, DiscoverAction::new(ComponentInput::default()));
+            .register_no_wait(&component, DiscoverAction::new(ComponentInput::default()))
+            .await;
         component
     }
 
@@ -379,12 +381,14 @@
             parent,
             hooks,
             persistent_storage,
-        );
+        )
+        .await;
         // We don't care about waiting for the discover action to complete, just that it's started.
         let _ = component
             .lock_actions()
             .await
-            .register_no_wait(&component, DiscoverAction::new(ComponentInput::default()));
+            .register_no_wait(&component, DiscoverAction::new(ComponentInput::default()))
+            .await;
         component
     }
 
diff --git a/src/sys/component_manager/src/model/routing/mod.rs b/src/sys/component_manager/src/model/routing/mod.rs
index 68297dd..dfabacb 100644
--- a/src/sys/component_manager/src/model/routing/mod.rs
+++ b/src/sys/component_manager/src/model/routing/mod.rs
@@ -5,6 +5,7 @@
 pub mod open;
 pub mod providers;
 pub mod router;
+pub mod router_ext;
 pub mod service;
 pub use ::routing::error::RoutingError;
 pub use open::*;
@@ -204,9 +205,9 @@
                 Availability::Required => {
                     // TODO(https://fxbug.dev/42060474): consider changing this to `error!()`
                     warn!(
-                        "{availability} {request} was not available for target component `{}`: {}\n{}",
-                        &target.moniker, &err, ROUTE_ERROR_HELP
-                    );
+                    "{availability} {request} was not available for target component `{}`: {}\n{}",
+                    &target.moniker, &err, ROUTE_ERROR_HELP
+                );
                 }
                 Availability::Optional
                 | Availability::SameAsTarget
@@ -223,9 +224,9 @@
                     // `Required` capabilities to `error!()`, consider also
                     // changing this log for `Optional` to `warn!()`.
                     info!(
-                        "{availability} {request} was not available for target component `{}`: {}\n{}",
-                        &target.moniker, &err, ROUTE_ERROR_HELP
-                    );
+                    "{availability} {request} was not available for target component `{}`: {}\n{}",
+                    &target.moniker, &err, ROUTE_ERROR_HELP
+                );
                 }
             }
         })
diff --git a/src/sys/component_manager/src/model/routing/router.rs b/src/sys/component_manager/src/model/routing/router.rs
index 58a9bfb..0d9bc0b 100644
--- a/src/sys/component_manager/src/model/routing/router.rs
+++ b/src/sys/component_manager/src/model/routing/router.rs
@@ -2,14 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use crate::capability::CapabilitySource;
 use crate::model::component::WeakComponentInstance;
-use ::routing::{error::RoutingError, policy::GlobalPolicyChecker};
+use ::routing::error::RoutingError;
 use async_trait::async_trait;
 use bedrock_error::{BedrockError, Explain};
 use cm_types::Availability;
-use cm_util::TaskGroup;
-use fidl::{endpoints::ServerEnd, epitaph::ChannelEpitaphExt};
 use fidl_fuchsia_component_sandbox as fsandbox;
 use fidl_fuchsia_io as fio;
 use fuchsia_zircon as zx;
@@ -17,13 +14,7 @@
 use futures::FutureExt;
 use sandbox::{AnyCapability, Capability, CapabilityTrait, Dict, Open};
 use std::{fmt, sync::Arc};
-use vfs::{
-    directory::entry::{self, DirectoryEntry, EntryInfo},
-    execution_scope::ExecutionScope,
-    path,
-    remote::RemoteLike,
-};
-use zx::HandleBased;
+use vfs::directory::entry::{self, DirectoryEntry, DirectoryEntryAsync, EntryInfo};
 
 /// Types that implement [`Routable`] let the holder asynchronously request
 /// capabilities from them.
@@ -144,35 +135,19 @@
         Router::new(route_fn)
     }
 
-    /// Returns a router that ensures the capability request is allowed by the
-    /// policy in [`GlobalPolicyChecker`].
-    pub fn with_policy_check(
-        self,
-        capability_source: CapabilitySource,
-        policy_checker: GlobalPolicyChecker,
-    ) -> Self {
-        Router::new(PolicyCheckRouter::new(capability_source, policy_checker, self))
-    }
-
     /// Returns a [Dict] equivalent to `dict`, but with all [Router]s replaced with [Open].
     ///
     /// This is an alternative to [Dict::try_into_open] when the [Dict] contains [Router]s, since
     /// [Router] is not currently a type defined by the sandbox library.
-    pub fn dict_routers_to_open(
-        weak_component: &WeakComponentInstance,
-        dict: &Dict,
-        routing_task_group: TaskGroup,
-    ) -> Dict {
+    pub fn dict_routers_to_open(weak_component: &WeakComponentInstance, dict: &Dict) -> Dict {
         let entries = dict.lock_entries();
         let out = Dict::new();
         let mut out_entries = out.lock_entries();
-        for (key, value) in &*entries {
+        for (key, value) in entries.iter() {
             let value = match value {
-                Capability::Dictionary(dict) => Capability::Dictionary(Self::dict_routers_to_open(
-                    weak_component,
-                    dict,
-                    routing_task_group.clone(),
-                )),
+                Capability::Dictionary(dict) => {
+                    Capability::Dictionary(Self::dict_routers_to_open(weak_component, dict))
+                }
                 Capability::Router(r) => {
                     let router = Router::from_any(r.clone());
                     let request = Request {
@@ -186,13 +161,12 @@
                     Capability::Open(Open::new(router.into_directory_entry(
                         request,
                         fio::DirentType::Service,
-                        routing_task_group.clone(),
-                        |_| {},
+                        |_| None,
                     )))
                 }
                 other => other.clone(),
             };
-            out_entries.insert(key.clone(), value);
+            out_entries.insert(key.clone(), value.clone()).ok();
         }
         drop(out_entries);
         out
@@ -204,157 +178,89 @@
     /// `entry_type` is the type of the entry when the DirectoryEntry is accessed through a `fuchsia.io`
     /// connection.
     ///
-    /// Routing tasks are run on the `routing_task_group`.
+    /// Tasks are spawned on the component's execution scope.
     ///
     /// When routing failed while exercising the returned DirectoryEntry, errors will be
     /// sent to `errors_fn`.
-    pub fn into_directory_entry(
+    pub fn into_directory_entry<F>(
         self,
         request: Request,
         entry_type: fio::DirentType,
-        routing_task_group: TaskGroup,
-        errors_fn: impl Fn(ErrorCapsule) + Send + Sync + 'static,
-    ) -> Arc<dyn DirectoryEntry> {
+        errors_fn: F,
+    ) -> Arc<dyn DirectoryEntry>
+    where
+        for<'a> F: Fn(&'a BedrockError) -> Option<BoxFuture<'a, ()>> + Send + Sync + 'static,
+    {
         struct RouterEntry<F> {
             router: Router,
             request: Request,
             entry_type: fio::DirentType,
-            routing_task_group: TaskGroup,
             errors_fn: F,
         }
 
-        impl<F: Fn(ErrorCapsule) + Send + Sync + 'static> DirectoryEntry for RouterEntry<F> {
+        impl<F> DirectoryEntry for RouterEntry<F>
+        where
+            for<'a> F: Fn(&'a BedrockError) -> Option<BoxFuture<'a, ()>> + Send + Sync + 'static,
+        {
             fn entry_info(&self) -> EntryInfo {
                 EntryInfo::new(fio::INO_UNKNOWN, self.entry_type)
             }
 
             fn open_entry(
                 self: Arc<Self>,
-                request: entry::OpenRequest<'_>,
+                mut request: entry::OpenRequest<'_>,
             ) -> Result<(), zx::Status> {
-                request.open_remote(self)
+                if let Ok(target) = self.request.target.upgrade() {
+                    // Spawn this request on the component's execution scope so that it doesn't
+                    // block the namespace.
+                    request.set_scope(target.execution_scope.clone());
+                    request.spawn(self);
+                    Ok(())
+                } else {
+                    Err(zx::Status::NOT_FOUND)
+                }
             }
         }
 
-        impl<F: Fn(ErrorCapsule) + Send + Sync + 'static> RemoteLike for RouterEntry<F> {
-            fn open(
+        impl<F> DirectoryEntryAsync for RouterEntry<F>
+        where
+            for<'a> F: Fn(&'a BedrockError) -> Option<BoxFuture<'a, ()>> + Send + Sync + 'static,
+        {
+            async fn open_entry_async(
                 self: Arc<Self>,
-                scope: ExecutionScope,
-                flags: fio::OpenFlags,
-                relative_path: path::Path,
-                server_end: ServerEnd<fio::NodeMarker>,
-            ) {
-                let this = self.clone();
-                self.routing_task_group.spawn(async move {
-                    // Request a capability from the `router`.
-                    let result = this.router.route(this.request.clone()).await;
-                    match result {
-                        Ok(capability) => {
-                            // HACK: Dict needs special casing because [Dict::try_into_open]
-                            // is unaware of [Router].
-                            let capability = match capability {
-                                Capability::Dictionary(d) => Router::dict_routers_to_open(
-                                    &this.request.target,
-                                    &d,
-                                    this.routing_task_group.clone(),
-                                )
-                                .into(),
-                                cap => cap,
-                            };
-                            match super::capability_into_open(capability.clone()) {
-                                Ok(open) => open.open(
-                                    scope,
-                                    flags,
-                                    relative_path,
-                                    server_end.into_channel(),
-                                ),
-                                Err(error) => (this.errors_fn)(ErrorCapsule {
-                                    error: error.into(),
-                                    open_request: OpenRequest {
-                                        flags,
-                                        relative_path,
-                                        server_end: server_end.into_channel(),
-                                    },
-                                }),
+                open_request: entry::OpenRequest<'_>,
+            ) -> Result<(), zx::Status> {
+                // Hold a guard to prevent this task from being dropped during component
+                // destruction.  This task is tied to the target component.
+                let _guard = open_request.scope().active_guard();
+
+                // Request a capability from the `router`.
+                let result = self.router.route(self.request.clone()).await;
+                let error = match result {
+                    Ok(capability) => {
+                        // HACK: Dict needs special casing because [Dict::try_into_open]
+                        // is unaware of [Router].
+                        let capability = match capability {
+                            Capability::Dictionary(d) => {
+                                Router::dict_routers_to_open(&self.request.target, &d).into()
                             }
-                        }
-                        Err(error) => {
-                            // Routing failed (e.g. broken route).
-                            (this.errors_fn)(ErrorCapsule {
-                                error,
-                                open_request: OpenRequest {
-                                    flags,
-                                    relative_path,
-                                    server_end: server_end.into_channel(),
-                                },
-                            });
+                            cap => cap,
+                        };
+                        match super::capability_into_open(capability.clone()) {
+                            Ok(open) => return open.open_entry(open_request),
+                            Err(error) => error,
                         }
                     }
-                });
+                    Err(error) => error, // Routing failed (e.g. broken route).
+                };
+                if let Some(fut) = (self.errors_fn)(&error) {
+                    fut.await;
+                }
+                Err(error.as_zx_status())
             }
         }
 
-        Arc::new(RouterEntry {
-            router: self.clone(),
-            request,
-            entry_type,
-            routing_task_group,
-            errors_fn,
-        })
-    }
-}
-
-/// [`ErrorCapsule `] holds an error from capability routing, and closes the
-/// server endpoint in the open request with an appropriate epitaph on drop.
-#[derive(Debug)]
-pub struct ErrorCapsule {
-    error: BedrockError,
-    open_request: OpenRequest,
-}
-
-impl ErrorCapsule {
-    /// Destructures the [`ErrorCapsule`] into the error and the open request
-    /// sent by the client when they connect to the requested capability. It is
-    /// provided here such that the endpoint may be closed with an appropriate
-    /// epitaph, which is now the responsibility of the caller.
-    pub fn manually_handle(mut self) -> (BedrockError, OpenRequest) {
-        (self.error.clone(), self.open_request.take())
-    }
-}
-
-impl fmt::Display for ErrorCapsule {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.error)
-    }
-}
-
-impl Drop for ErrorCapsule {
-    fn drop(&mut self) {
-        self.open_request.close(self.error.as_zx_status());
-    }
-}
-
-#[derive(Debug)]
-pub struct OpenRequest {
-    pub flags: fio::OpenFlags,
-    pub relative_path: vfs::path::Path,
-    pub server_end: zx::Channel,
-}
-
-impl OpenRequest {
-    fn take(&mut self) -> Self {
-        OpenRequest {
-            flags: self.flags.clone(),
-            relative_path: self.relative_path.clone(),
-            server_end: cm_util::channel::take_channel(&mut self.server_end),
-        }
-    }
-
-    fn close(&mut self, status: zx::Status) {
-        let server_end = cm_util::channel::take_channel(&mut self.server_end);
-        if !server_end.is_invalid_handle() {
-            let _ = server_end.close_with_epitaph(status);
-        }
+        Arc::new(RouterEntry { router: self.clone(), request, entry_type, errors_fn })
     }
 }
 
@@ -388,35 +294,6 @@
     }
 }
 
-pub struct PolicyCheckRouter {
-    capability_source: CapabilitySource,
-    policy_checker: GlobalPolicyChecker,
-    router: Router,
-}
-
-impl PolicyCheckRouter {
-    pub fn new(
-        capability_source: CapabilitySource,
-        policy_checker: GlobalPolicyChecker,
-        router: Router,
-    ) -> Self {
-        PolicyCheckRouter { capability_source, policy_checker, router }
-    }
-}
-
-#[async_trait]
-impl Routable for PolicyCheckRouter {
-    async fn route(&self, request: Request) -> Result<Capability, BedrockError> {
-        match self
-            .policy_checker
-            .can_route_capability(&self.capability_source, &request.target.moniker)
-        {
-            Ok(()) => self.router.route(request).await,
-            Err(policy_error) => Err(RoutingError::PolicyError(policy_error).into()),
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/sys/component_manager/src/model/routing/router_ext.rs b/src/sys/component_manager/src/model/routing/router_ext.rs
new file mode 100644
index 0000000..28178b9
--- /dev/null
+++ b/src/sys/component_manager/src/model/routing/router_ext.rs
@@ -0,0 +1,64 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::model::routing::router::Request;
+use crate::model::routing::router::Routable;
+use crate::model::routing::router::Router;
+
+use crate::capability::CapabilitySource;
+use ::routing::{error::RoutingError, policy::GlobalPolicyChecker};
+use async_trait::async_trait;
+use bedrock_error::BedrockError;
+use sandbox::Capability;
+
+/// A trait to add functions to Router that know about the component manager
+/// types.
+pub trait RouterExt {
+    /// Returns a router that ensures the capability request is allowed by the
+    /// policy in [`GlobalPolicyChecker`].
+    fn with_policy_check(
+        self,
+        capability_source: CapabilitySource,
+        policy_checker: GlobalPolicyChecker,
+    ) -> Self;
+}
+
+impl RouterExt for Router {
+    fn with_policy_check(
+        self,
+        capability_source: CapabilitySource,
+        policy_checker: GlobalPolicyChecker,
+    ) -> Self {
+        Router::new(PolicyCheckRouter::new(capability_source, policy_checker, self))
+    }
+}
+
+pub struct PolicyCheckRouter {
+    capability_source: CapabilitySource,
+    policy_checker: GlobalPolicyChecker,
+    router: Router,
+}
+
+impl PolicyCheckRouter {
+    pub fn new(
+        capability_source: CapabilitySource,
+        policy_checker: GlobalPolicyChecker,
+        router: Router,
+    ) -> Self {
+        PolicyCheckRouter { capability_source, policy_checker, router }
+    }
+}
+
+#[async_trait]
+impl Routable for PolicyCheckRouter {
+    async fn route(&self, request: Request) -> Result<Capability, BedrockError> {
+        match self
+            .policy_checker
+            .can_route_capability(&self.capability_source, &request.target.moniker)
+        {
+            Ok(()) => self.router.route(request).await,
+            Err(policy_error) => Err(RoutingError::PolicyError(policy_error).into()),
+        }
+    }
+}
diff --git a/src/sys/component_manager/src/model/routing/service.rs b/src/sys/component_manager/src/model/routing/service.rs
index 0b3efde..680d16b 100644
--- a/src/sys/component_manager/src/model/routing/service.rs
+++ b/src/sys/component_manager/src/model/routing/service.rs
@@ -372,7 +372,7 @@
                             "Failed to route service capability from component, skipping",
                         );
                     })
-                    .await;
+                    .await
             }
         }
         Ok(())
@@ -1732,7 +1732,7 @@
                         OfferBuilder::service()
                             .name("my.service.Service")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("container".into()))
+                            .target_static_child("container")
                             .availability(cm_rust::Availability::Required),
                     )
                     .child_default("container")
@@ -1751,21 +1751,21 @@
                         OfferBuilder::service()
                             .name("my.service.Service")
                             .source(OfferSource::Collection("coll".parse().unwrap()))
-                            .target(OfferTarget::static_child("target".into()))
+                            .target_static_child("target")
                             .availability(cm_rust::Availability::Required),
                     )
                     .offer(
                         OfferBuilder::service()
                             .name("my.service.Service")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("target".into()))
+                            .target_static_child("target")
                             .availability(cm_rust::Availability::Required),
                     )
                     .offer(
                         OfferBuilder::service()
                             .name("my.service.Service")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("target".into()))
+                            .target_static_child("target")
                             .availability(cm_rust::Availability::Required),
                     )
                     .collection_default("coll")
diff --git a/src/sys/component_manager/src/model/structured_dict.rs b/src/sys/component_manager/src/model/structured_dict.rs
index 4cbad9c..a9bc9e0 100644
--- a/src/sys/component_manager/src/model/structured_dict.rs
+++ b/src/sys/component_manager/src/model/structured_dict.rs
@@ -5,6 +5,7 @@
 use {
     crate::sandbox_util::DictExt,
     cm_types::{IterablePath, Name},
+    fidl_fuchsia_component_sandbox as fsandbox,
     lazy_static::lazy_static,
     sandbox::{Capability, Dict},
     std::{fmt, marker::PhantomData},
@@ -49,10 +50,10 @@
 
 #[allow(private_bounds)]
 impl<T: StructuredDict> StructuredDictMap<T> {
-    pub fn insert(&mut self, key: Name, value: T) {
+    pub fn insert(&mut self, key: Name, value: T) -> Result<(), fsandbox::DictionaryError> {
         let mut entries = self.inner.lock_entries();
         let dict: Dict = value.into();
-        entries.insert(key, dict.into());
+        entries.insert(key, dict.into())
     }
 
     pub fn get(&self, key: &Name) -> Option<T> {
@@ -115,8 +116,8 @@
     pub fn new(environment: ComponentEnvironment) -> Self {
         let dict = Dict::new();
         let mut entries = dict.lock_entries();
-        entries.insert(PARENT.clone(), Dict::new().into());
-        entries.insert(ENVIRONMENT.clone(), Dict::from(environment).into());
+        entries.insert(PARENT.clone(), Dict::new().into()).ok();
+        entries.insert(ENVIRONMENT.clone(), Dict::from(environment).into()).ok();
         drop(entries);
         Self(dict)
     }
@@ -131,8 +132,10 @@
         // inner sandboxes.
         let dict = Dict::new();
         let mut entries = dict.lock_entries();
-        entries.insert(PARENT.clone(), self.capabilities().shallow_copy().into());
-        entries.insert(ENVIRONMENT.clone(), Dict::from(self.environment()).shallow_copy().into());
+        entries.insert(PARENT.clone(), self.capabilities().shallow_copy().into()).ok();
+        entries
+            .insert(ENVIRONMENT.clone(), Dict::from(self.environment()).shallow_copy().into())
+            .ok();
         drop(entries);
         Self(dict)
     }
@@ -157,7 +160,11 @@
         ComponentEnvironment(dict.clone())
     }
 
-    pub fn insert_capability(&self, path: &impl IterablePath, capability: Capability) {
+    pub fn insert_capability(
+        &self,
+        path: &impl IterablePath,
+        capability: Capability,
+    ) -> Result<(), fsandbox::DictionaryError> {
         self.capabilities().insert_capability(path, capability.into())
     }
 }
@@ -177,7 +184,7 @@
     fn default() -> Self {
         let dict = Dict::new();
         let mut entries = dict.lock_entries();
-        entries.insert(DEBUG.clone(), Dict::new().into());
+        entries.insert(DEBUG.clone(), Dict::new().into()).ok();
         drop(entries);
         Self(dict)
     }
@@ -210,7 +217,7 @@
         // inner sandboxes.
         let dict = Dict::new();
         let mut entries = dict.lock_entries();
-        entries.insert(DEBUG.clone(), self.debug().shallow_copy().into());
+        entries.insert(DEBUG.clone(), self.debug().shallow_copy().into()).ok();
         drop(entries);
         Self(dict)
     }
@@ -226,6 +233,7 @@
 mod tests {
     use super::*;
     use assert_matches::assert_matches;
+    use sandbox::DictKey;
 
     impl StructuredDict for Dict {
         fn from_dict(dict: Dict) -> Self {
@@ -238,43 +246,52 @@
         let dict1 = Dict::new();
         {
             let mut entries = dict1.lock_entries();
-            entries.insert("a".parse().unwrap(), Dict::new().into());
+            entries
+                .insert("a".parse().unwrap(), Dict::new().into())
+                .expect("dict entry already exists");
         }
         let dict2 = Dict::new();
         {
             let mut entries = dict2.lock_entries();
-            entries.insert("b".parse().unwrap(), Dict::new().into());
+            entries
+                .insert("b".parse().unwrap(), Dict::new().into())
+                .expect("dict entry already exists");
         }
         let dict2_alt = Dict::new();
         {
             let mut entries = dict2_alt.lock_entries();
-            entries.insert("c".parse().unwrap(), Dict::new().into());
+            entries
+                .insert("c".parse().unwrap(), Dict::new().into())
+                .expect("dict entry already exists");
         }
         let name1 = Name::new("1").unwrap();
         let name2 = Name::new("2").unwrap();
 
         let mut map: StructuredDictMap<Dict> = Default::default();
         assert_matches!(map.get(&name1), None);
-        map.insert(name1.clone(), dict1);
+        assert!(map.insert(name1.clone(), dict1).is_ok());
         let d = map.get(&name1).unwrap();
         {
             let entries = d.lock_entries();
-            assert!(entries.contains_key("a"));
+            let key = DictKey::new("a").unwrap();
+            assert!(entries.get(&key).is_some());
         }
 
-        map.insert(name2.clone(), dict2);
+        assert!(map.insert(name2.clone(), dict2).is_ok());
         let d = map.remove(&name2).unwrap();
         assert_matches!(map.remove(&name2), None);
         {
             let entries = d.lock_entries();
-            assert!(entries.contains_key("b"));
+            let key = DictKey::new("b").unwrap();
+            assert!(entries.get(&key).is_some());
         }
 
-        map.insert(name2.clone(), dict2_alt);
+        assert!(map.insert(name2.clone(), dict2_alt).is_ok());
         let d = map.get(&name2).unwrap();
         {
             let entries = d.lock_entries();
-            assert!(entries.contains_key("c"));
+            let key = DictKey::new("c").unwrap();
+            assert!(entries.get(&key).is_some());
         }
     }
 }
diff --git a/src/sys/component_manager/src/model/testing/mocks.rs b/src/sys/component_manager/src/model/testing/mocks.rs
index 0a4e474..5efcc9d 100644
--- a/src/sys/component_manager/src/model/testing/mocks.rs
+++ b/src/sys/component_manager/src/model/testing/mocks.rs
@@ -50,7 +50,9 @@
 pub struct MockResolver {
     components: HashMap<String, ComponentDecl>,
     configs: HashMap<String, ConfigValuesData>,
-    blockers: HashMap<String, Arc<Mutex<Option<(oneshot::Sender<()>, oneshot::Receiver<()>)>>>>,
+    blockers: Arc<
+        Mutex<HashMap<String, Arc<Mutex<Option<(oneshot::Sender<()>, oneshot::Receiver<()>)>>>>>,
+    >,
 }
 
 impl MockResolver {
@@ -58,7 +60,7 @@
         MockResolver {
             components: HashMap::new(),
             configs: HashMap::new(),
-            blockers: HashMap::new(),
+            blockers: Arc::new(Mutex::new(HashMap::new())),
         }
     }
 
@@ -104,7 +106,7 @@
             ServerEnd::new(server.into_channel()),
         );
 
-        if let Some(blocker) = self.blockers.get(name) {
+        if let Some(blocker) = self.blockers.lock().await.get(name).cloned() {
             let mut blocker = blocker.lock().await;
             if let Some(blocker) = blocker.take() {
                 let (send, recv) = blocker;
@@ -133,13 +135,16 @@
         self.configs.insert(path.to_string(), values);
     }
 
-    pub fn add_blocker(
-        &mut self,
+    pub async fn add_blocker(
+        &self,
         path: &str,
         send: oneshot::Sender<()>,
         recv: oneshot::Receiver<()>,
     ) {
-        self.blockers.insert(path.to_string(), Arc::new(Mutex::new(Some((send, recv)))));
+        self.blockers
+            .lock()
+            .await
+            .insert(path.to_string(), Arc::new(Mutex::new(Some((send, recv)))));
     }
 
     pub fn get_component_decl(&self, name: &str) -> Option<ComponentDecl> {
diff --git a/src/sys/component_manager/src/model/testing/routing_test_helpers.rs b/src/sys/component_manager/src/model/testing/routing_test_helpers.rs
index 78bd770..fb99f08 100644
--- a/src/sys/component_manager/src/model/testing/routing_test_helpers.rs
+++ b/src/sys/component_manager/src/model/testing/routing_test_helpers.rs
@@ -284,7 +284,7 @@
         }
         for (name, blocker) in builder.blockers {
             let (send, recv) = blocker;
-            mock_resolver.add_blocker(name, send, recv);
+            mock_resolver.add_blocker(name, send, recv).await;
         }
         for (path, values) in builder.configs {
             mock_resolver.add_config_values(&path, values);
@@ -486,7 +486,8 @@
                 UseDecl::Storage(s) => Some(s.target_path.to_string()),
                 UseDecl::EventStream(s) => Some(s.target_path.parent().to_string()),
                 UseDecl::Runner(s) => Some(s.source_name.to_string().into()),
-                UseDecl::Config(s) => Some(s.source_name.to_string().into()),
+                // Using config doesn't add a namespace path.
+                UseDecl::Config(_) => None,
             })
             .collect();
         let mut expected_paths = vec![];
diff --git a/src/sys/component_manager/src/model/testing/test_helpers.rs b/src/sys/component_manager/src/model/testing/test_helpers.rs
index 90c3f64..29c2873 100644
--- a/src/sys/component_manager/src/model/testing/test_helpers.rs
+++ b/src/sys/component_manager/src/model/testing/test_helpers.rs
@@ -243,6 +243,7 @@
     component_id_index_path: Option<Utf8PathBuf>,
     realm_moniker: Option<Moniker>,
     hooks: Vec<HooksRegistration>,
+    front_hooks: Vec<HooksRegistration>,
 }
 
 impl TestEnvironmentBuilder {
@@ -255,6 +256,7 @@
             component_id_index_path: None,
             realm_moniker: None,
             hooks: vec![],
+            front_hooks: vec![],
         }
     }
 
@@ -296,6 +298,11 @@
         self
     }
 
+    pub fn set_front_hooks(mut self, hooks: Vec<HooksRegistration>) -> Self {
+        self.front_hooks = hooks;
+        self
+    }
+
     /// Returns a `Model` and `BuiltinEnvironment` suitable for most tests.
     pub async fn build(mut self) -> TestModelResult {
         let mock_runner = Arc::new(MockRunner::new());
@@ -331,10 +338,11 @@
                 .await
                 .expect("builtin environment setup failed"),
         ));
-        builtin_environment.lock().await.discover_root_component().await;
         let model = builtin_environment.lock().await.model.clone();
 
         model.root().hooks.install(self.hooks).await;
+        model.root().hooks.install_front(self.front_hooks).await;
+        builtin_environment.lock().await.discover_root_component().await;
 
         // Host framework service for `moniker`, if requested.
         let realm_proxy = if let Some(moniker) = self.realm_moniker {
@@ -449,7 +457,7 @@
     ) -> Result<(), fcomponent::Error> {
         let collection_ref = fdecl::CollectionRef { name: coll.to_string() };
         let child_decl = ChildDecl {
-            name: name.to_string(),
+            name: name.parse().unwrap(),
             url: format!("test:///{}", name),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
diff --git a/src/sys/component_manager/src/model/tests/dictionary.rs b/src/sys/component_manager/src/model/tests/dictionary.rs
index d001ce7..5cb1091 100644
--- a/src/sys/component_manager/src/model/tests/dictionary.rs
+++ b/src/sys/component_manager/src/model/tests/dictionary.rs
@@ -28,7 +28,7 @@
                     OfferBuilder::dictionary()
                         .name("parent_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into())),
+                        .target_static_child("mid"),
                 )
                 .child_default("mid")
                 .build(),
@@ -109,7 +109,7 @@
                     OfferBuilder::dictionary()
                         .name("dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into())),
+                        .target_static_child("leaf"),
                 )
                 .child_default("leaf")
                 .build(),
@@ -153,7 +153,7 @@
                         .name("dict")
                         .target_name("other_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into())),
+                        .target_static_child("leaf"),
                 )
                 .child_default("leaf")
                 .build(),
@@ -191,7 +191,7 @@
                     OfferBuilder::dictionary()
                         .name("parent_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into())),
+                        .target_static_child("leaf"),
                 )
                 .offer(
                     OfferBuilder::directory()
@@ -367,7 +367,7 @@
                     OfferBuilder::dictionary()
                         .name("parent_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into())),
+                        .target_static_child("mid"),
                 )
                 .child_default("mid")
                 .build(),
@@ -461,7 +461,7 @@
                     OfferBuilder::dictionary()
                         .name("parent_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into())),
+                        .target_static_child("mid"),
                 )
                 .child_default("mid")
                 .build(),
@@ -476,7 +476,7 @@
                         .name("A")
                         .target_name("A_svc")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("self_dict"),
                 )
                 .offer(
@@ -491,15 +491,15 @@
                         .name("B")
                         .target_name("B_svc")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("parent_dict"),
                 )
                 .offer(
                     OfferBuilder::protocol()
                         .name("C")
                         .target_name("C_svc")
-                        .source(OfferSource::static_child("provider".into()))
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .source_static_child("provider")
+                        .target_static_child("leaf")
                         .from_dictionary("child_dict"),
                 )
                 .child_default("provider")
@@ -562,7 +562,7 @@
                     OfferBuilder::dictionary()
                         .name("dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into())),
+                        .target_static_child("mid"),
                 )
                 .child_default("mid")
                 .build(),
@@ -575,7 +575,7 @@
                         .name("A")
                         .target_name("A_svc")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("dict"),
                 )
                 .child_default("leaf")
@@ -628,7 +628,7 @@
                     OfferBuilder::dictionary()
                         .name("parent_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into())),
+                        .target_static_child("mid"),
                 )
                 .child_default("mid")
                 .build(),
@@ -644,7 +644,7 @@
                         .name("A")
                         .target_name("A_svc")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("self_dict/nested"),
                 )
                 .offer(
@@ -665,15 +665,15 @@
                         .name("B")
                         .target_name("B_svc")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("parent_dict/nested"),
                 )
                 .offer(
                     OfferBuilder::protocol()
                         .name("C")
                         .target_name("C_svc")
-                        .source(OfferSource::static_child("provider".into()))
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .source_static_child("provider")
+                        .target_static_child("leaf")
                         .from_dictionary("child_dict/nested"),
                 )
                 .child_default("provider")
@@ -1031,7 +1031,7 @@
                     OfferBuilder::dictionary()
                         .name("parent_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into())),
+                        .target_static_child("mid"),
                 )
                 .child_default("mid")
                 .build(),
@@ -1064,7 +1064,7 @@
                 .offer(
                     OfferBuilder::dictionary()
                         .name("child_dict")
-                        .source(OfferSource::static_child("leaf".into()))
+                        .source_static_child("leaf")
                         .target(OfferTarget::Capability("root_dict".parse().unwrap())),
                 )
                 .use_(
@@ -1127,7 +1127,7 @@
                     OfferBuilder::protocol()
                         .name("bar")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into())),
+                        .target_static_child("leaf"),
                 )
                 .child_default("leaf")
                 .build(),
@@ -1209,7 +1209,7 @@
                     OfferBuilder::dictionary()
                         .name("origin_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into())),
+                        .target_static_child("leaf"),
                 )
                 .child_default("leaf")
                 .build(),
@@ -1276,7 +1276,7 @@
                         .name("self_dict")
                         .source_dictionary(
                             DictionarySource::Child(ChildRef {
-                                name: "leaf".into(),
+                                name: "leaf".parse().unwrap(),
                                 collection: None,
                             }),
                             "origin_dict",
@@ -1375,7 +1375,7 @@
                     OfferBuilder::dictionary()
                         .name("dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into())),
+                        .target_static_child("leaf"),
                 )
                 .child_default("leaf")
                 .build(),
@@ -1464,20 +1464,20 @@
                     OfferBuilder::dictionary()
                         .name("required_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into())),
+                        .target_static_child("leaf"),
                 )
                 .offer(
                     OfferBuilder::dictionary()
                         .name("optional_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .availability(Availability::Optional),
                 )
                 .offer(
                     OfferBuilder::dictionary()
                         .name("dict_with_optional_nested")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into())),
+                        .target_static_child("leaf"),
                 )
                 .child_default("leaf")
                 .build(),
@@ -1560,14 +1560,14 @@
                     OfferBuilder::protocol()
                         .name("A")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("dict"),
                 )
                 .offer(
                     OfferBuilder::protocol()
                         .name("B")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("dict/nested"),
                 )
                 .child_default("leaf")
@@ -1647,20 +1647,20 @@
                     OfferBuilder::dictionary()
                         .name("required_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into())),
+                        .target_static_child("mid"),
                 )
                 .offer(
                     OfferBuilder::dictionary()
                         .name("optional_dict")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into()))
+                        .target_static_child("mid")
                         .availability(Availability::Optional),
                 )
                 .offer(
                     OfferBuilder::dictionary()
                         .name("dict_with_optional_nested")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("mid".into())),
+                        .target_static_child("mid"),
                 )
                 .child_default("mid")
                 .build(),
@@ -1672,21 +1672,21 @@
                     OfferBuilder::protocol()
                         .name("A")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("required_dict"),
                 )
                 .offer(
                     OfferBuilder::protocol()
                         .name("B")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("optional_dict"),
                 )
                 .offer(
                     OfferBuilder::protocol()
                         .name("C")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("leaf".into()))
+                        .target_static_child("leaf")
                         .from_dictionary("dict_with_optional_nested/nested"),
                 )
                 .child_default("leaf")
@@ -1955,7 +1955,10 @@
                 CapabilityBuilder::dictionary()
                     .name("source")
                     .source_dictionary(
-                        DictionarySource::Child(ChildRef { name: "leaf".into(), collection: None }),
+                        DictionarySource::Child(ChildRef {
+                            name: "leaf".parse().unwrap(),
+                            collection: None,
+                        }),
                         "child_dict",
                     )
                     .build(),
diff --git a/src/sys/component_manager/src/model/tests/directory.rs b/src/sys/component_manager/src/model/tests/directory.rs
index 82ce44b..1714b8a 100644
--- a/src/sys/component_manager/src/model/tests/directory.rs
+++ b/src/sys/component_manager/src/model/tests/directory.rs
@@ -43,8 +43,8 @@
                 .offer(
                     OfferBuilder::directory()
                         .name("data")
-                        .source(OfferSource::static_child("c".to_string()))
-                        .target(OfferTarget::static_child("b".to_string()))
+                        .source_static_child("c")
+                        .target_static_child("b")
                         .rights(fio::R_STAR_DIR),
                 )
                 .child_default("b")
diff --git a/src/sys/component_manager/src/model/tests/lifecycle.rs b/src/sys/component_manager/src/model/tests/lifecycle.rs
index 169dcf6..1d38d91 100644
--- a/src/sys/component_manager/src/model/tests/lifecycle.rs
+++ b/src/sys/component_manager/src/model/tests/lifecycle.rs
@@ -59,8 +59,11 @@
     additional_hooks: Vec<HooksRegistration>,
 ) -> (Arc<Model>, Arc<Mutex<BuiltinEnvironment>>, Arc<MockRunner>) {
     let TestModelResult { model, builtin_environment, mock_runner, .. } =
-        TestEnvironmentBuilder::new().set_components(components).build().await;
-    model.root().hooks.install(additional_hooks).await;
+        TestEnvironmentBuilder::new()
+            .set_components(components)
+            .set_hooks(additional_hooks)
+            .build()
+            .await;
     (model, builtin_environment, mock_runner)
 }
 
@@ -140,20 +143,24 @@
     let system_component = model.root().find(&vec!["system"].try_into().unwrap()).await.unwrap();
     let first_start = {
         let mut actions = system_component.lock_actions().await;
-        actions.register_no_wait(
-            &system_component,
-            StartAction::new(StartReason::Debug, None, IncomingCapabilities::default()),
-        )
+        actions
+            .register_no_wait(
+                &system_component,
+                StartAction::new(StartReason::Debug, None, IncomingCapabilities::default()),
+            )
+            .await
     };
 
     // While the first start is paused, simulate a second start by explicitly scheduling a second
     // Start action. This should just be deduplicated to the first start by the action system.
     let second_start = {
         let mut actions = system_component.lock_actions().await;
-        actions.register_no_wait(
-            &system_component,
-            StartAction::new(StartReason::Debug, None, IncomingCapabilities::default()),
-        )
+        actions
+            .register_no_wait(
+                &system_component,
+                StartAction::new(StartReason::Debug, None, IncomingCapabilities::default()),
+            )
+            .await
     };
 
     // Unblock the start hook, then check the result of both starts.
@@ -460,8 +467,8 @@
     // Child of root should start out discovered but not resolved yet.
     let m = Moniker::parse_str("/system").unwrap();
     model.start(ComponentInput::default()).await;
-    event_stream.wait_until(EventType::Resolved, vec![].try_into().unwrap()).await.unwrap();
     event_stream.wait_until(EventType::Discovered, m.clone()).await.unwrap();
+    event_stream.wait_until(EventType::Resolved, vec![].try_into().unwrap()).await.unwrap();
     event_stream.wait_until(EventType::Started, vec![].try_into().unwrap()).await.unwrap();
 
     // Start child and check that it gets resolved, with a Resolve event and action.
diff --git a/src/sys/component_manager/src/model/tests/policy.rs b/src/sys/component_manager/src/model/tests/policy.rs
index 30c3eb1..0258fd8 100644
--- a/src/sys/component_manager/src/model/tests/policy.rs
+++ b/src/sys/component_manager/src/model/tests/policy.rs
@@ -14,6 +14,7 @@
         resolver::ResolverRegistry,
     },
     anyhow::Error,
+    async_trait::async_trait,
     cm_moniker::InstancedMoniker,
     fidl_fuchsia_component_decl as fdecl,
     routing::environment::{DebugRegistry, RunnerRegistry},
@@ -27,8 +28,9 @@
 #[derive(Default)]
 struct GlobalPolicyCheckerTestForCm {}
 
+#[async_trait]
 impl GlobalPolicyCheckerTest<ComponentInstance> for GlobalPolicyCheckerTestForCm {
-    fn make_component(&self, instanced_moniker: InstancedMoniker) -> Arc<ComponentInstance> {
+    async fn make_component(&self, instanced_moniker: InstancedMoniker) -> Arc<ComponentInstance> {
         let top_instance = Arc::new(ComponentManagerInstance::new(vec![], vec![]));
         ComponentInstance::new(
             Arc::new(Environment::new_root(
@@ -47,6 +49,7 @@
             Arc::new(Hooks::new()),
             false,
         )
+        .await
     }
 }
 
diff --git a/src/sys/component_manager/src/model/tests/rights.rs b/src/sys/component_manager/src/model/tests/rights.rs
index 96292ed..e8aaf94 100644
--- a/src/sys/component_manager/src/model/tests/rights.rs
+++ b/src/sys/component_manager/src/model/tests/rights.rs
@@ -103,7 +103,7 @@
                     OfferBuilder::directory()
                         .name("foo_data")
                         .source(OfferSource::Framework)
-                        .target(OfferTarget::static_child("b".to_string()))
+                        .target_static_child("b")
                         .subdir("foo"),
                 )
                 .child_default("b")
@@ -135,7 +135,7 @@
                     OfferBuilder::directory()
                         .name("foo_data")
                         .source(OfferSource::Framework)
-                        .target(OfferTarget::static_child("b".to_string()))
+                        .target_static_child("b")
                         .subdir("foo"),
                 )
                 .child_default("b")
diff --git a/src/sys/component_manager/src/model/tests/routing.rs b/src/sys/component_manager/src/model/tests/routing.rs
index 972bd56..080d49c 100644
--- a/src/sys/component_manager/src/model/tests/routing.rs
+++ b/src/sys/component_manager/src/model/tests/routing.rs
@@ -63,7 +63,6 @@
     routing_test_helpers::{
         default_service_capability, instantiate_common_routing_tests, RoutingTestModel,
     },
-    sandbox::Open,
     std::{
         collections::HashSet,
         pin::pin,
@@ -213,7 +212,7 @@
                     .name("foo")
                     .target_name("bar")
                     .source(OfferSource::Self_)
-                    .target(OfferTarget::static_child("b".to_string()))
+                    .target_static_child("b")
                 )
                 .use_(UseBuilder::event_stream()
                     .name("capability_requested")
@@ -306,7 +305,7 @@
                         .name("foo_data")
                         .target_name("hippo_data")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string()))
+                        .target_static_child("b")
                         .rights(fio::R_STAR_DIR),
                 )
                 .offer(
@@ -314,7 +313,7 @@
                         .name("foo")
                         .target_name("hippo")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .build(),
@@ -361,7 +360,7 @@
         &vec!["b"].try_into().unwrap(),
         "coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -374,7 +373,7 @@
         &vec!["b"].try_into().unwrap(),
         "coll",
         ChildDecl {
-            name: "d".to_string(),
+            name: "d".parse().unwrap(),
             url: "test:///d".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -416,7 +415,7 @@
                         .name("foo_data")
                         .target_name("hippo_data")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string()))
+                        .target_static_child("b")
                         .rights(fio::R_STAR_DIR),
                 )
                 .offer(
@@ -424,7 +423,7 @@
                         .name("foo")
                         .target_name("hippo")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .build(),
@@ -453,7 +452,7 @@
         &vec!["b"].try_into().unwrap(),
         "coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -498,7 +497,7 @@
                         .name("foo")
                         .target_name("hippo")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .build(),
@@ -526,7 +525,7 @@
         &vec!["b"].try_into().unwrap(),
         "coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -549,7 +548,7 @@
         &vec!["b"].try_into().unwrap(),
         "coll",
         ChildDecl {
-            name: "d".to_string(),
+            name: "d".parse().unwrap(),
             url: "test:///d".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -612,7 +611,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "b".to_string(),
+            name: "b".parse().unwrap(),
             url: "test:///b".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -625,7 +624,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -636,7 +635,7 @@
             dynamic_offers: Some(vec![fdecl::Offer::Protocol(fdecl::OfferProtocol {
                 source_name: Some("hippo".to_string()),
                 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
-                    name: "b".to_string(),
+                    name: "b".parse().unwrap(),
                     collection: Some("coll".to_string()),
                 })),
                 target_name: Some("hippo".to_string()),
@@ -694,7 +693,7 @@
         &Moniker::root(),
         "source_coll",
         ChildDecl {
-            name: "b".to_string(),
+            name: "b".parse().unwrap(),
             url: "test:///b".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -707,7 +706,7 @@
         &Moniker::root(),
         "target_coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -717,7 +716,7 @@
         fcomponent::CreateChildArgs {
             dynamic_offers: Some(vec![fdecl::Offer::Protocol(fdecl::OfferProtocol {
                 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
-                    name: "b".to_string(),
+                    name: "b".parse().unwrap(),
                     collection: Some("source_coll".to_string()),
                 })),
                 source_name: Some("hippo".to_string()),
@@ -775,7 +774,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "b".to_string(),
+            name: "b".parse().unwrap(),
             url: "test:///b".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -788,7 +787,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -799,7 +798,7 @@
             dynamic_offers: Some(vec![fdecl::Offer::Protocol(fdecl::OfferProtocol {
                 source_name: Some("hippo".to_string()),
                 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
-                    name: "b".to_string(),
+                    name: "b".parse().unwrap(),
                     collection: Some("coll".to_string()),
                 })),
                 target_name: Some("hippo".to_string()),
@@ -821,7 +820,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "b".to_string(),
+            name: "b".parse().unwrap(),
             url: "test:///b".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -890,7 +889,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "b".to_string(),
+            name: "b".parse().unwrap(),
             url: "test:///b".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -903,7 +902,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -914,7 +913,7 @@
             dynamic_offers: Some(vec![fdecl::Offer::Directory(fdecl::OfferDirectory {
                 source_name: Some("hippo_data".to_string()),
                 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
-                    name: "b".to_string(),
+                    name: "b".parse().unwrap(),
                     collection: Some("coll".to_string()),
                 })),
                 target_name: Some("hippo_data".to_string()),
@@ -936,7 +935,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -995,7 +994,7 @@
                     OfferBuilder::protocol()
                         .name("hippo")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("d".to_string())),
+                        .target_static_child("d"),
                 )
                 .child_default("d")
                 .build(),
@@ -1014,7 +1013,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "c".to_string(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -1025,7 +1024,7 @@
             dynamic_offers: Some(vec![fdecl::Offer::Protocol(fdecl::OfferProtocol {
                 source_name: Some("hippo".to_string()),
                 source: Some(fdecl::Ref::Child(fdecl::ChildRef {
-                    name: "b".to_string(),
+                    name: "b".parse().unwrap(),
                     collection: None,
                 })),
                 target_name: Some("hippo".to_string()),
@@ -1090,8 +1089,9 @@
 
     // CreateChild dictionary entries must be Open capabilities.
     // TODO(https://fxbug.dev/319542502): Insert the external Router type, once it exists
-    let open: sandbox::Open = sender.into();
-    dict.lock_entries().insert("hippo".parse().unwrap(), sandbox::Capability::Open(open));
+    dict.lock_entries()
+        .insert("hippo".parse().unwrap(), sender.into())
+        .expect("dict entry already exists");
 
     let dictionary_client_end: ClientEnd<fsandbox::DictionaryMarker> = dict.into();
 
@@ -1100,7 +1100,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "b".to_string(),
+            name: "b".parse().unwrap(),
             url: "test:///b".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -1162,14 +1162,14 @@
                 .offer(
                     OfferBuilder::protocol()
                         .name("foo")
-                        .source(OfferSource::static_child("c".into()))
-                        .target(OfferTarget::static_child("b".into())),
+                        .source_static_child("c")
+                        .target_static_child("b"),
                 )
                 .offer(
                     OfferBuilder::directory()
                         .name("foo_data")
-                        .source(OfferSource::static_child("c".into()))
-                        .target(OfferTarget::static_child("b".into())),
+                        .source_static_child("c")
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .child_default("c")
@@ -1359,7 +1359,7 @@
             &Moniker::root(),
             "coll",
             ChildDecl {
-                name: "b".to_string(),
+                name: "b".parse().unwrap(),
                 url: "test:///b".to_string(),
                 startup: fdecl::StartupMode::Lazy,
                 environment: None,
@@ -1406,7 +1406,7 @@
                         .name("elf")
                         .target_name("dwarf")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .runner_default("elf")
                 .build(),
@@ -1770,7 +1770,7 @@
                     OfferBuilder::protocol()
                         .name("foo")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("c".to_string())),
+                        .target_static_child("c"),
                 )
                 .child_default("c")
                 .build(),
@@ -1782,7 +1782,7 @@
         &Moniker::root(),
         "coll",
         ChildDecl {
-            name: "b".to_string(),
+            name: "b".parse().unwrap(),
             url: "test:///b".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
@@ -1844,8 +1844,8 @@
                     OfferBuilder::protocol()
                         .name("bar")
                         .target_name("baz")
-                        .source(OfferSource::static_child("b".to_string()))
-                        .target(OfferTarget::static_child("c".to_string())),
+                        .source_static_child("b")
+                        .target_static_child("c"),
                 )
                 .child_default("b")
                 .child_default("c")
@@ -2355,8 +2355,12 @@
     for child_moniker in &child_monikers {
         let coll = child_moniker.collection().unwrap();
         let name = child_moniker.name();
-        test.create_dynamic_child(&agg_moniker, coll.as_str(), ChildBuilder::new().name(name))
-            .await;
+        test.create_dynamic_child(
+            &agg_moniker,
+            coll.as_str(),
+            ChildBuilder::new().name(name.as_str()),
+        )
+        .await;
         test.start_instance_and_wait_start(&agg_moniker.child(child_moniker.clone()))
             .await
             .unwrap();
@@ -2408,7 +2412,7 @@
                     OfferBuilder::service()
                         .name("foo")
                         .source(OfferSource::Collection("coll".parse().unwrap()))
-                        .target(OfferTarget::static_child("b".into())),
+                        .target_static_child("b"),
                 )
                 .collection_default("coll")
                 .child_default("b")
@@ -2453,7 +2457,7 @@
             OfferBuilder::service()
                 .name("foo")
                 .source(OfferSource::Collection(coll.parse().unwrap()))
-                .target(OfferTarget::static_child("b".into()))
+                .target_static_child("b")
                 .build()
         })
         .collect();
@@ -2512,7 +2516,7 @@
             OfferBuilder::service()
                 .name("foo")
                 .source(OfferSource::Collection(coll.parse().unwrap()))
-                .target(OfferTarget::static_child("m".into()))
+                .target_static_child("m")
                 .build()
         })
         .collect();
@@ -2537,7 +2541,7 @@
                     OfferBuilder::service()
                         .name("foo")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("b".into())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .build(),
@@ -2753,7 +2757,7 @@
             OfferBuilder::service()
                 .name("foo")
                 .source(OfferSource::Collection(coll.parse().unwrap()))
-                .target(OfferTarget::static_child("client".into()))
+                .target_static_child("client")
                 .build()
         })
         .collect();
@@ -2883,8 +2887,8 @@
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
-                        .source(OfferSource::static_child("c".to_string()))
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .source_static_child("c")
+                        .target_static_child("b"),
                 )
                 .child(ChildBuilder::new().name("b"))
                 .child(ChildBuilder::new().name("c"))
@@ -3013,15 +3017,15 @@
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
-                        .source(OfferSource::static_child("b".to_string()))
-                        .target(OfferTarget::static_child("c".to_string()))
+                        .source_static_child("b")
+                        .target_static_child("c")
                         .source_instance_filter(vec!["variantinstance".to_string()]),
                 )
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
-                        .source(OfferSource::static_child("b".to_string()))
-                        .target(OfferTarget::static_child("d".to_string()))
+                        .source_static_child("b")
+                        .target_static_child("d")
                         .renamed_instances(vec![NameMapping {
                             source_name: "default".to_string(),
                             target_name: "renamed_default".to_string(),
@@ -3151,15 +3155,15 @@
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
-                        .source(OfferSource::static_child("b".to_string()))
-                        .target(OfferTarget::static_child("c".to_string()))
+                        .source_static_child("b")
+                        .target_static_child("c")
                         .source_instance_filter(vec!["variantinstance".to_string()]),
                 )
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
-                        .source(OfferSource::static_child("b".to_string()))
-                        .target(OfferTarget::static_child("c".to_string()))
+                        .source_static_child("b")
+                        .target_static_child("c")
                         .source_instance_filter(vec!["renamed_default".to_string()])
                         .renamed_instances(vec![NameMapping {
                             source_name: "default".to_string(),
@@ -3268,7 +3272,7 @@
                     OfferBuilder::service()
                         .name("my.service.Service")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .service_default("my.service.Service")
                 .child(ChildBuilder::new().name("b"))
@@ -3280,26 +3284,26 @@
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
-                        .source(OfferSource::static_child("c".to_string()))
-                        .target(OfferTarget::static_child("e".to_string())),
+                        .source_static_child("c")
+                        .target_static_child("e"),
                 )
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
-                        .source(OfferSource::static_child("d".to_string()))
-                        .target(OfferTarget::static_child("e".to_string())),
+                        .source_static_child("d")
+                        .target_static_child("e"),
                 )
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("e".to_string())),
+                        .target_static_child("e"),
                 )
                 .offer(
                     OfferBuilder::service()
                         .name("my.service.Service")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("e".to_string())),
+                        .target_static_child("e"),
                 )
                 .service_default("my.service.Service")
                 .child(ChildBuilder::new().name("c"))
@@ -3428,12 +3432,15 @@
                 target: root.as_weak().into(),
             })
             .await
-            .unwrap()
-            .try_into_directory_entry()
             .unwrap();
 
         // Connect to the capability.
-        Open::new(entry).open(ExecutionScope::new(), fio::OpenFlags::empty(), ".", server_end);
+        match entry {
+            sandbox::Capability::Sender(s) => {
+                s.send(sandbox::Message { channel: server_end }).unwrap()
+            }
+            e => panic!("{:#?}", e),
+        };
     };
 
     // Both should complete after the response delay has passed.
@@ -3481,19 +3488,19 @@
 
     // Request a capability from the component.
     let output = root.lock_resolved_state().await.unwrap().component_output_dict.clone();
-    let open: Open = Open::new(
-        output
-            .get_capability(&RelativePath::new("foo").unwrap())
-            .unwrap()
-            .route(crate::model::routing::router::Request {
-                availability: Availability::Required,
-                target: root.as_weak().into(),
-            })
-            .await
-            .unwrap()
-            .try_into_directory_entry()
-            .unwrap(),
-    );
+    let cap = output
+        .get_capability(&RelativePath::new("foo").unwrap())
+        .unwrap()
+        .route(crate::model::routing::router::Request {
+            availability: Availability::Required,
+            target: root.as_weak().into(),
+        })
+        .await
+        .unwrap();
+    let sender = match cap {
+        sandbox::Capability::Sender(s) => s,
+        c => panic!("{:#?}", c),
+    };
 
     // It should be started with the capability access start reason.
     assert!(root.is_started().await);
@@ -3508,7 +3515,7 @@
 
     // Connect to the capability. The component should be started again.
     let (client_end, server_end) = zx::Channel::create();
-    open.open(ExecutionScope::new(), fio::OpenFlags::empty(), ".", server_end);
+    sender.send(sandbox::Message { channel: server_end }).unwrap();
 
     let server_end = open_request_rx.next().await.unwrap();
     assert_eq!(
@@ -3550,19 +3557,19 @@
 
     // Request a capability from the component.
     let output = root.lock_resolved_state().await.unwrap().component_output_dict.clone();
-    let open: Open = Open::new(
-        output
-            .get_capability(&RelativePath::new("foo").unwrap())
-            .unwrap()
-            .route(crate::model::routing::router::Request {
-                availability: Availability::Required,
-                target: root.as_weak().into(),
-            })
-            .await
-            .unwrap()
-            .try_into_directory_entry()
-            .unwrap(),
-    );
+    let cap = output
+        .get_capability(&RelativePath::new("foo").unwrap())
+        .unwrap()
+        .route(crate::model::routing::router::Request {
+            availability: Availability::Required,
+            target: root.as_weak().into(),
+        })
+        .await
+        .unwrap();
+    let sender = match cap {
+        sandbox::Capability::Sender(s) => s,
+        c => panic!("{:#?}", c),
+    };
 
     // It should be started with the capability access start reason.
     assert!(root.is_started().await);
@@ -3577,7 +3584,7 @@
 
     // Connect to the capability. The request will fail and the component is not started.
     let (client_end, server_end) = zx::Channel::create();
-    open.open(ExecutionScope::new(), fio::OpenFlags::empty(), ".", server_end);
+    sender.send(sandbox::Message { channel: server_end }).unwrap();
     fasync::OnSignals::new(&client_end, zx::Signals::CHANNEL_PEER_CLOSED).await.unwrap();
     assert!(!root.is_started().await);
 }
@@ -3636,8 +3643,8 @@
                     OfferBuilder::protocol()
                         .name("foo_svc")
                         .target_name("foo_svc")
-                        .source(OfferSource::static_child("provider".into()))
-                        .target(OfferTarget::static_child("consumer".to_string()))
+                        .source_static_child("provider")
+                        .target_static_child("consumer")
                         .build(),
                 )
                 .offer(
@@ -3645,11 +3652,11 @@
                         .name("capability_requested")
                         .target_name("capability_requested")
                         .scope(vec![EventScope::Child(ChildRef {
-                            name: "consumer".into(),
+                            name: "consumer".parse().unwrap(),
                             collection: None,
                         })])
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("provider".to_string())),
+                        .target_static_child("provider"),
                 )
                 .child(ChildBuilder::new().name("provider"))
                 .child(ChildBuilder::new().name("consumer"))
diff --git a/src/sys/component_manager/src/model/tests/storage.rs b/src/sys/component_manager/src/model/tests/storage.rs
index f26c070..e91b1ef 100644
--- a/src/sys/component_manager/src/model/tests/storage.rs
+++ b/src/sys/component_manager/src/model/tests/storage.rs
@@ -119,7 +119,7 @@
                         .name("data")
                         .target_name("minfs")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string()))
+                        .target_static_child("b")
                         .rights(fio::RW_STAR_DIR),
                 )
                 .child_default("b")
@@ -259,13 +259,13 @@
                     OfferBuilder::storage()
                         .name("data")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .offer(
                     OfferBuilder::storage()
                         .name("cache")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .capability(
@@ -480,7 +480,7 @@
                     OfferBuilder::storage()
                         .name("cache")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("parent_consumer".to_string())),
+                        .target_static_child("parent_consumer"),
                 )
                 .child_default("parent_consumer")
                 .build(),
@@ -493,7 +493,7 @@
                     OfferBuilder::storage()
                         .name("cache")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("child_consumer".to_string())),
+                        .target_static_child("child_consumer"),
                 )
                 .child_default("child_consumer")
                 .build(),
@@ -573,7 +573,7 @@
                     OfferBuilder::storage()
                         .name("cache")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("parent_consumer".to_string())),
+                        .target_static_child("parent_consumer"),
                 )
                 .child_default("parent_consumer")
                 .build(),
@@ -698,7 +698,7 @@
                     OfferBuilder::storage()
                         .name("cache")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("consumer".to_string())),
+                        .target_static_child("consumer"),
                 )
                 .child_default("consumer")
                 .build(),
@@ -808,13 +808,13 @@
                     OfferBuilder::storage()
                         .name("data")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .offer(
                     OfferBuilder::protocol()
                         .name("fuchsia.sys2.StorageAdmin")
                         .source(OfferSource::Capability("data".parse().unwrap()))
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .build(),
@@ -971,13 +971,13 @@
                     OfferBuilder::storage()
                         .name("data")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .offer(
                     OfferBuilder::protocol()
                         .name("fuchsia.sys2.StorageAdmin")
                         .source(OfferSource::Capability("data".parse().unwrap()))
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .build(),
@@ -1138,7 +1138,7 @@
                     OfferBuilder::storage()
                         .name("data")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .build(),
@@ -1176,7 +1176,7 @@
                     OfferBuilder::storage()
                         .name("data")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("d".to_string())),
+                        .target_static_child("d"),
                 )
                 .offer(
                     OfferBuilder::storage()
@@ -1365,7 +1365,7 @@
                     OfferBuilder::storage()
                         .name("data")
                         .source(OfferSource::Self_)
-                        .target(OfferTarget::static_child("b".to_string())),
+                        .target_static_child("b"),
                 )
                 .child_default("b")
                 .build(),
@@ -1403,7 +1403,7 @@
                     OfferBuilder::storage()
                         .name("data")
                         .source(OfferSource::Parent)
-                        .target(OfferTarget::static_child("d".to_string())),
+                        .target_static_child("d"),
                 )
                 .offer(
                     OfferBuilder::storage()
@@ -1457,7 +1457,7 @@
         &vec!["b"].try_into().unwrap(),
         "persistent_coll",
         ChildDecl {
-            name: "c".into(),
+            name: "c".parse().unwrap(),
             url: "test:///c".to_string(),
             startup: fdecl::StartupMode::Lazy,
             environment: None,
diff --git a/src/sys/component_manager/src/sandbox_util.rs b/src/sys/component_manager/src/sandbox_util.rs
index f57fdb6..e22c70b 100644
--- a/src/sys/component_manager/src/sandbox_util.rs
+++ b/src/sys/component_manager/src/sandbox_util.rs
@@ -20,7 +20,7 @@
         epitaph::ChannelEpitaphExt,
         AsyncChannel,
     },
-    fidl_fuchsia_io as fio, fuchsia_zircon as zx,
+    fidl_fuchsia_component_sandbox as fsandbox, fidl_fuchsia_io as fio, fuchsia_zircon as zx,
     futures::{future::BoxFuture, FutureExt},
     sandbox::{Capability, Dict, Message, Open, Sendable, Sender},
     std::{fmt::Debug, sync::Arc},
@@ -43,7 +43,11 @@
     fn get_capability(&self, path: &impl IterablePath) -> Option<Capability>;
 
     /// Inserts the capability at the path. Intermediary dictionaries are created as needed.
-    fn insert_capability(&self, path: &impl IterablePath, capability: Capability);
+    fn insert_capability(
+        &self,
+        path: &impl IterablePath,
+        capability: Capability,
+    ) -> Result<(), fsandbox::DictionaryError>;
 
     /// Removes the capability at the path, if it exists.
     fn remove_capability(&self, path: &impl IterablePath);
@@ -69,18 +73,22 @@
                     // Lifetimes are weird here with the MutexGuard, so we do this in two steps
                     let sub_dict = current_dict
                         .lock_entries()
-                        .get(current_name.as_str())
+                        .get(current_name)
                         .and_then(|value| value.clone().to_dictionary())?;
                     current_dict = sub_dict;
 
                     current_name = next_name;
                 }
-                None => return current_dict.lock_entries().get(current_name.as_str()).cloned(),
+                None => return current_dict.lock_entries().get(current_name).cloned(),
             }
         }
     }
 
-    fn insert_capability(&self, path: &impl IterablePath, capability: Capability) {
+    fn insert_capability(
+        &self,
+        path: &impl IterablePath,
+        capability: Capability,
+    ) -> Result<(), fsandbox::DictionaryError> {
         let mut segments = path.iter_segments();
         let mut current_name = segments.next().expect("path must be non-empty");
         let mut current_dict = self.clone();
@@ -88,20 +96,23 @@
             match segments.next() {
                 Some(next_name) => {
                     // Lifetimes are weird here with the MutexGuard, so we do this in two steps
-                    let sub_dict = current_dict
-                        .lock_entries()
-                        .entry(current_name.clone())
-                        .or_insert(Capability::Dictionary(Dict::new()))
-                        .clone()
-                        .to_dictionary()
-                        .unwrap();
+                    let sub_dict = {
+                        let mut entries = current_dict.lock_entries();
+                        match entries.get(current_name) {
+                            Some(cap) => cap.clone().to_dictionary().unwrap(),
+                            None => {
+                                let cap = Capability::Dictionary(Dict::new());
+                                entries.insert(current_name.clone(), cap.clone())?;
+                                cap.to_dictionary().unwrap()
+                            }
+                        }
+                    };
                     current_dict = sub_dict;
 
                     current_name = next_name;
                 }
                 None => {
-                    current_dict.lock_entries().insert(current_name.clone(), capability);
-                    return;
+                    return current_dict.lock_entries().insert(current_name.clone(), capability);
                 }
             }
         }
@@ -116,7 +127,7 @@
                 Some(next_name) => {
                     let sub_dict = current_dict
                         .lock_entries()
-                        .get(current_name.as_str())
+                        .get(current_name)
                         .and_then(|value| value.clone().to_dictionary());
                     if sub_dict.is_none() {
                         // The capability doesn't exist, there's nothing to remove.
@@ -126,7 +137,7 @@
                     current_name = next_name;
                 }
                 None => {
-                    current_dict.lock_entries().remove(current_name.as_str());
+                    current_dict.lock_entries().remove(current_name);
                     return;
                 }
             }
@@ -144,7 +155,7 @@
             let Capability::Dictionary(current_dict) = &current_capability else { return Ok(None) };
 
             // Get the capability.
-            let capability = current_dict.lock_entries().get(next_name.as_str()).cloned();
+            let capability = current_dict.lock_entries().get(next_name).cloned();
 
             // The capability doesn't exist.
             let Some(capability) = capability else { return Ok(None) };
@@ -327,15 +338,13 @@
                 let entry = self.router.clone().into_directory_entry(
                     request,
                     self.entry_type,
-                    target.blocking_task_group(),
                     move |err| {
                         // TODO(https://fxbug.dev/319754472): Improve the fidelity of error logging.
                         // This should log into the component's log sink using the proper
                         // `report_routing_failure`, but that function requires a legacy
                         // `RouteRequest` at the moment.
-                        let group = target.nonblocking_task_group();
                         let target = target.clone();
-                        group.spawn(async move {
+                        Some(Box::pin(async move {
                             target
                                 .with_logger_as_default(|| {
                                     warn!(
@@ -343,8 +352,8 @@
                                         target.moniker, err
                                     );
                                 })
-                                .await;
-                        });
+                                .await
+                        }))
                     },
                 );
 
@@ -443,12 +452,21 @@
     #[fuchsia::test]
     async fn get_capability() {
         let sub_dict = Dict::new();
-        sub_dict.lock_entries().insert("bar".parse().unwrap(), Capability::Dictionary(Dict::new()));
+        sub_dict
+            .lock_entries()
+            .insert("bar".parse().unwrap(), Capability::Dictionary(Dict::new()))
+            .expect("dict entry already exists");
         let (_, sender) = Receiver::new();
-        sub_dict.lock_entries().insert("baz".parse().unwrap(), sender.into());
+        sub_dict
+            .lock_entries()
+            .insert("baz".parse().unwrap(), sender.into())
+            .expect("dict entry already exists");
 
         let test_dict = Dict::new();
-        test_dict.lock_entries().insert("foo".parse().unwrap(), Capability::Dictionary(sub_dict));
+        test_dict
+            .lock_entries()
+            .insert("foo".parse().unwrap(), Capability::Dictionary(sub_dict))
+            .expect("dict entry already exists");
 
         assert!(test_dict.get_capability(&RelativePath::dot()).is_some());
         assert!(test_dict.get_capability(&RelativePath::new("nonexistent").unwrap()).is_none());
@@ -461,18 +479,24 @@
     #[fuchsia::test]
     async fn insert_capability() {
         let test_dict = Dict::new();
-        test_dict.insert_capability(&RelativePath::new("foo/bar").unwrap(), Dict::new().into());
+        assert!(test_dict
+            .insert_capability(&RelativePath::new("foo/bar").unwrap(), Dict::new().into())
+            .is_ok());
         assert!(test_dict.get_capability(&RelativePath::new("foo/bar").unwrap()).is_some());
 
         let (_, sender) = Receiver::new();
-        test_dict.insert_capability(&RelativePath::new("foo/baz").unwrap(), sender.into());
+        assert!(test_dict
+            .insert_capability(&RelativePath::new("foo/baz").unwrap(), sender.into())
+            .is_ok());
         assert!(test_dict.get_capability(&RelativePath::new("foo/baz").unwrap()).is_some());
     }
 
     #[fuchsia::test]
     async fn remove_capability() {
         let test_dict = Dict::new();
-        test_dict.insert_capability(&RelativePath::new("foo/bar").unwrap(), Dict::new().into());
+        assert!(test_dict
+            .insert_capability(&RelativePath::new("foo/bar").unwrap(), Dict::new().into())
+            .is_ok());
         assert!(test_dict.get_capability(&RelativePath::new("foo/bar").unwrap()).is_some());
 
         test_dict.remove_capability(&RelativePath::new("foo/bar").unwrap());
@@ -487,18 +511,22 @@
     async fn get_with_request_ok() {
         let bar = Dict::new();
         let data = Data::String("hello".to_owned());
-        bar.insert_capability(&RelativePath::new("data").unwrap(), data.into());
+        assert!(bar.insert_capability(&RelativePath::new("data").unwrap(), data.into()).is_ok());
         // Put bar behind a few layers of Router for good measure.
         let bar_router = Router::new_ok(bar);
         let bar_router = Router::new_ok(bar_router);
         let bar_router = Router::new_ok(bar_router);
 
         let foo = Dict::new();
-        foo.insert_capability(&RelativePath::new("bar").unwrap(), bar_router.into());
+        assert!(foo
+            .insert_capability(&RelativePath::new("bar").unwrap(), bar_router.into())
+            .is_ok());
         let foo_router = Router::new_ok(foo);
 
         let dict = Dict::new();
-        dict.insert_capability(&RelativePath::new("foo").unwrap(), foo_router.into());
+        assert!(dict
+            .insert_capability(&RelativePath::new("foo").unwrap(), foo_router.into())
+            .is_ok());
 
         let cap = dict
             .get_with_request(
@@ -516,7 +544,7 @@
     async fn get_with_request_error() {
         let dict = Dict::new();
         let foo = Router::new_error(RoutingError::SourceCapabilityIsVoid);
-        dict.insert_capability(&RelativePath::new("foo").unwrap(), foo.into());
+        assert!(dict.insert_capability(&RelativePath::new("foo").unwrap(), foo.into()).is_ok());
         let cap = dict
             .get_with_request(
                 &RelativePath::new("foo/bar").unwrap(),
@@ -557,7 +585,7 @@
 
         let foo = Dict::new();
         let foo = Router::new_ok(foo);
-        dict.insert_capability(&RelativePath::new("foo").unwrap(), foo.into());
+        assert!(dict.insert_capability(&RelativePath::new("foo").unwrap(), foo.into()).is_ok());
 
         let cap = dict
             .get_with_request(
@@ -623,7 +651,8 @@
             Arc::new(ModelContext::new_for_test()),
             Weak::new(),
             "test:///root".to_string(),
-        );
+        )
+        .await;
         let capability = router
             .route(Request { availability: Availability::Required, target: component.as_weak() })
             .await
@@ -670,7 +699,8 @@
             Arc::new(ModelContext::new_for_test()),
             Weak::new(),
             "test:///root".to_string(),
-        );
+        )
+        .await;
         let capability = router
             .route(Request { availability: Availability::Required, target: component.as_weak() })
             .await
@@ -705,7 +735,10 @@
     async fn lazy_get() {
         let source = Capability::Data(Data::String("hello".to_string()));
         let dict1 = Dict::new();
-        dict1.lock_entries().insert("source".parse().unwrap(), source);
+        dict1
+            .lock_entries()
+            .insert("source".parse().unwrap(), source)
+            .expect("dict entry already exists");
 
         let base_router = Router::new_ok(dict1);
         let downscoped_router = base_router.lazy_get(
@@ -731,13 +764,25 @@
     async fn lazy_get_deep() {
         let source = Capability::Data(Data::String("hello".to_string()));
         let dict1 = Dict::new();
-        dict1.lock_entries().insert("source".parse().unwrap(), source);
+        dict1
+            .lock_entries()
+            .insert("source".parse().unwrap(), source)
+            .expect("dict entry already exists");
         let dict2 = Dict::new();
-        dict2.lock_entries().insert("dict1".parse().unwrap(), Capability::Dictionary(dict1));
+        dict2
+            .lock_entries()
+            .insert("dict1".parse().unwrap(), Capability::Dictionary(dict1))
+            .expect("dict entry already exists");
         let dict3 = Dict::new();
-        dict3.lock_entries().insert("dict2".parse().unwrap(), Capability::Dictionary(dict2));
+        dict3
+            .lock_entries()
+            .insert("dict2".parse().unwrap(), Capability::Dictionary(dict2))
+            .expect("dict entry already exists");
         let dict4 = Dict::new();
-        dict4.lock_entries().insert("dict3".parse().unwrap(), Capability::Dictionary(dict3));
+        dict4
+            .lock_entries()
+            .insert("dict3".parse().unwrap(), Capability::Dictionary(dict3))
+            .expect("dict entry already exists");
 
         let base_router = Router::new_ok(dict4);
         let downscoped_router = base_router.lazy_get(
diff --git a/src/sys/component_manager/tests/capability_provider_vfs_compliance/meta/integration_test.cml b/src/sys/component_manager/tests/capability_provider_vfs_compliance/meta/integration_test.cml
index a0342b1..e411130 100644
--- a/src/sys/component_manager/tests/capability_provider_vfs_compliance/meta/integration_test.cml
+++ b/src/sys/component_manager/tests/capability_provider_vfs_compliance/meta/integration_test.cml
@@ -36,6 +36,7 @@
                 "fuchsia.boot.WriteOnlyLog",
                 "fuchsia.inspect.InspectSink",
                 "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.DebugResource",
                 "fuchsia.kernel.EnergyInfoResource",
                 "fuchsia.kernel.FramebufferResource",
diff --git a/src/sys/component_manager/tests/capability_provider_vfs_compliance/src/integration_test.rs b/src/sys/component_manager/tests/capability_provider_vfs_compliance/src/integration_test.rs
index ffc86ee..6382c8d 100644
--- a/src/sys/component_manager/tests/capability_provider_vfs_compliance/src/integration_test.rs
+++ b/src/sys/component_manager/tests/capability_provider_vfs_compliance/src/integration_test.rs
@@ -28,8 +28,10 @@
         "/svc/fuchsia.inspect.InspectSink",
         "/svc/fuchsia.kernel.CpuResource",
         "/svc/fuchsia.kernel.DebugResource",
+        "/svc/fuchsia.kernel.DebuglogResource",
         "/svc/fuchsia.kernel.EnergyInfoResource",
         "/svc/fuchsia.kernel.FramebufferResource",
+        "/svc/fuchsia.kernel.DebuglogResource",
         "/svc/fuchsia.kernel.HypervisorResource",
         "/svc/fuchsia.kernel.InfoResource",
         "/svc/fuchsia.kernel.IommuResource",
diff --git a/src/sys/component_manager/tests/capability_provider_vfs_compliance/vfs_compliance_test_realm.shard.cml b/src/sys/component_manager/tests/capability_provider_vfs_compliance/vfs_compliance_test_realm.shard.cml
index 30ea655..6d22ba3 100644
--- a/src/sys/component_manager/tests/capability_provider_vfs_compliance/vfs_compliance_test_realm.shard.cml
+++ b/src/sys/component_manager/tests/capability_provider_vfs_compliance/vfs_compliance_test_realm.shard.cml
@@ -17,6 +17,7 @@
                 "fuchsia.boot.WriteOnlyLog",
                 "fuchsia.inspect.InspectSink",
                 "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.DebugResource",
                 "fuchsia.kernel.EnergyInfoResource",
                 "fuchsia.kernel.FramebufferResource",
diff --git a/src/sys/component_manager/tests/controller/src/lib.rs b/src/sys/component_manager/tests/controller/src/lib.rs
index a63c5cb3..54bf1420 100644
--- a/src/sys/component_manager/tests/controller/src/lib.rs
+++ b/src/sys/component_manager/tests/controller/src/lib.rs
@@ -22,7 +22,7 @@
     std::sync::{Arc, Mutex},
     vfs::{
         directory::entry_container::Directory as _, execution_scope::ExecutionScope,
-        file::vmo::read_only, pseudo_directory, ToObjectRequest,
+        file::vmo::read_only, pseudo_directory,
     },
 };
 
@@ -340,61 +340,40 @@
         .connect_to_protocol_at_exposed_dir::<fsandbox::FactoryMarker>()
         .expect("failed to connect to fuchsia.component.sandbox.Factory");
 
-    // Create a Dictionary that will be passed to StartChild, containing an Open capability for the Echo protocol.
-    let (dictionary_client, dictionary_server) =
-        create_proxy::<fsandbox::DictionaryMarker>().unwrap();
+    // StartChild dictionary entries must be Sender capabilities.
+    let (receiver_client, mut receiver_stream) =
+        create_request_stream::<fsandbox::ReceiverMarker>().unwrap();
 
-    // StartChild dictionary entries must be Open capabilities.
-    // TODO(https://fxbug.dev/319542502): Consider using the external Router type, once it exists
-    let (echo_openable_client, mut echo_openable_stream) =
-        create_request_stream::<fio::OpenableMarker>().unwrap();
-
-    // Serve the `fidl.examples.routing.echo.Echo` protocol on the Openable.
+    // Serve the `fidl.examples.routing.echo.Echo` protocol on the Sender.
     let task_group = Mutex::new(fasync::TaskGroup::new());
-    let echo_service =
-        vfs::service::endpoint(move |_scope: ExecutionScope, channel: fuchsia_async::Channel| {
-            let mut task_group = task_group.lock().unwrap();
-            task_group.spawn(async move {
-                let server_end = ServerEnd::<fecho::EchoMarker>::new(channel.into());
-                let mut stream = server_end.into_stream().unwrap();
-                while let Some(fecho::EchoRequest::EchoString { value, responder }) =
-                    stream.try_next().await.unwrap()
-                {
-                    responder.send(value.as_ref().map(|s| &**s)).unwrap();
-                }
-            });
-        });
-
     let _task = fasync::Task::spawn(async move {
-        while let Some(fio::OpenableRequest::Open {
-            flags,
-            mode: _,
-            path: _,
-            object,
-            control_handle: _,
-        }) = echo_openable_stream.try_next().await.unwrap()
-        {
-            flags.to_object_request(object).handle(|object_request| {
-                vfs::service::serve(
-                    echo_service.clone(),
-                    ExecutionScope::new(),
-                    &flags,
-                    object_request,
-                )
-            });
+        loop {
+            match receiver_stream.try_next().await.unwrap() {
+                Some(fsandbox::ReceiverRequest::Receive { channel, control_handle: _ }) => {
+                    let mut task_group = task_group.lock().unwrap();
+                    task_group.spawn(async move {
+                        let server_end = ServerEnd::<fecho::EchoMarker>::new(channel);
+                        let mut stream = server_end.into_stream().unwrap();
+                        while let Some(fecho::EchoRequest::EchoString { value, responder }) =
+                            stream.try_next().await.unwrap()
+                        {
+                            responder.send(value.as_ref().map(|s| &**s)).unwrap();
+                        }
+                    });
+                }
+                _ => panic!(),
+            }
         }
     });
 
-    // Convert the Openable to an Open capability, also represented as an Openable.
-    let (echo_open_cap_client, echo_open_cap_server) = create_endpoints::<fio::OpenableMarker>();
-    let () = factory
-        .create_open(echo_openable_client, echo_open_cap_server)
-        .await
-        .expect("failed to call CreateOpen");
+    // Create a sender from our receiver.
+    let sender_client =
+        factory.create_sender(receiver_client).await.expect("failed to call CreateOpen");
 
-    let () = factory.create_dictionary(dictionary_server).await.unwrap();
+    let dictionary_client = factory.create_dictionary().await.unwrap();
+    let dictionary_client = dictionary_client.into_proxy().unwrap();
     dictionary_client
-        .insert("fidl.examples.routing.echo.Echo", fsandbox::Capability::Open(echo_open_cap_client))
+        .insert("fidl.examples.routing.echo.Echo", fsandbox::Capability::Sender(sender_client))
         .await
         .unwrap()
         .unwrap();
@@ -548,17 +527,10 @@
 
     controller_proxy.get_exposed_dictionary(server_end).await.unwrap().unwrap();
     let echo_cap = exposed_dict.get(fecho::EchoMarker::DEBUG_NAME).await.unwrap().unwrap();
-    let fsandbox::Capability::Open(echo_open) = echo_cap else { panic!("wrong type") };
-    let echo_open = echo_open.into_proxy().unwrap();
+    let fsandbox::Capability::Sender(echo_sender) = echo_cap else { panic!("wrong type") };
+    let echo_sender = echo_sender.into_proxy().unwrap();
     let (echo_proxy, server_end) = create_proxy::<fecho::EchoMarker>().unwrap();
-    echo_open
-        .open(
-            fio::OpenFlags::empty(),
-            fio::ModeType::empty(),
-            ".",
-            server_end.into_channel().into(),
-        )
-        .unwrap();
+    echo_sender.send_(server_end.into_channel().into()).unwrap();
     let response = echo_proxy.echo_string(Some("hello")).await.unwrap().unwrap();
     assert_eq!(response, "hello");
 }
diff --git a/src/sys/component_manager/tests/diagnostics/reporter.rs b/src/sys/component_manager/tests/diagnostics/reporter.rs
index 2d36084..7f753ef 100644
--- a/src/sys/component_manager/tests/diagnostics/reporter.rs
+++ b/src/sys/component_manager/tests/diagnostics/reporter.rs
@@ -87,27 +87,36 @@
             start_timestamp_nanos: AnyProperty,
             status: "OK"
         },
-        early_start_times: {
-            "0": {
-                moniker: ".",
-                time: AnyProperty,
+        lifecycle: {
+            early: {
+                "0": {
+                    moniker: ".",
+                    type: "started",
+                    time: AnyProperty,
+                },
+                "1": {
+                    moniker: "root",
+                    type: "started",
+                    time: AnyProperty,
+                },
+                "2": {
+                    moniker: "root/elf_runner",
+                    type: "started",
+                    time: AnyProperty,
+                },
+                "3": {
+                    moniker: "root/reporter",
+                    type: "started",
+                    time: AnyProperty,
+                },
+                "4": {
+                    moniker: "root/archivist",
+                    type: "started",
+                    time: AnyProperty,
+                },
             },
-            "1": {
-                moniker: "root",
-                time: AnyProperty,
-            },
-            "2": {
-                moniker: "root/elf_runner",
-                time: AnyProperty,
-            },
-            "3": {
-                moniker: "root/reporter",
-                time: AnyProperty,
-            },
-            "4": {
-                moniker: "root/archivist",
-                time: AnyProperty,
-            },
+            late: {
+            }
         },
         stats: contains {
             measurements: {
diff --git a/src/sys/component_manager/tests/fuchsia_boot_resolver/BUILD.gn b/src/sys/component_manager/tests/fuchsia_boot_resolver/BUILD.gn
index 0e8ee24..63d7f37 100644
--- a/src/sys/component_manager/tests/fuchsia_boot_resolver/BUILD.gn
+++ b/src/sys/component_manager/tests/fuchsia_boot_resolver/BUILD.gn
@@ -42,7 +42,6 @@
       build_type = "eng"
       feature_set_level = "bootstrap"
       storage = {
-        configure_fshost = true
         filesystems = {
           image_name = "test_zbi"
           image_mode = "no_image"
diff --git a/src/sys/component_manager/tests/rights/expose_dir_rights.cc b/src/sys/component_manager/tests/rights/expose_dir_rights.cc
index a466dd6..1b038ae 100644
--- a/src/sys/component_manager/tests/rights/expose_dir_rights.cc
+++ b/src/sys/component_manager/tests/rights/expose_dir_rights.cc
@@ -22,12 +22,7 @@
   }
   auto& [memfs, root] = result.value();
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  if (endpoints.is_error()) {
-    fprintf(stderr, "Failed to create memfs endpoints: %s\n", endpoints.status_string());
-    return -1;
-  }
-  auto& [memfs_dir, server] = endpoints.value();
+  auto [memfs_dir, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   if (zx_status_t status = memfs->ServeDirectory(std::move(root), std::move(server));
       status != ZX_OK) {
@@ -47,12 +42,7 @@
   };
 
   for (const auto& [name, rights] : dirs) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    if (endpoints.is_error()) {
-      fprintf(stderr, "Failed to create endpoints: %s\n", endpoints.status_string());
-      return -1;
-    }
-    auto& [client, node_server] = endpoints.value();
+    auto [client, node_server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
     fidl::ServerEnd<fuchsia_io::Node> server(node_server.TakeChannel());
     if (fidl::Status result = fidl::WireCall(memfs_dir)->Clone(rights, std::move(server));
         !result.ok()) {
diff --git a/src/sys/component_manager/tests/security_policy/capability_allowlist/dir_service.cc b/src/sys/component_manager/tests/security_policy/capability_allowlist/dir_service.cc
index 4b5660b..4e35170 100644
--- a/src/sys/component_manager/tests/security_policy/capability_allowlist/dir_service.cc
+++ b/src/sys/component_manager/tests/security_policy/capability_allowlist/dir_service.cc
@@ -22,12 +22,7 @@
   }
   auto& [memfs, root] = result.value();
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  if (endpoints.is_error()) {
-    fprintf(stderr, "Failed to create memfs endpoints: %s\n", endpoints.status_string());
-    return -1;
-  }
-  auto& [memfs_dir, server] = endpoints.value();
+  auto [memfs_dir, server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
   if (zx_status_t status = memfs->ServeDirectory(std::move(root), std::move(server));
       status != ZX_OK) {
@@ -38,12 +33,7 @@
   svc::Outgoing outgoing(loop.dispatcher());
 
   for (fbl::String name : {"restricted", "unrestricted"}) {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    if (endpoints.is_error()) {
-      fprintf(stderr, "Failed to create endpoints: %s\n", endpoints.status_string());
-      return -1;
-    }
-    auto& [client, node_server] = endpoints.value();
+    auto [client, node_server] = fidl::Endpoints<fuchsia_io::Directory>::Create();
     fidl::ServerEnd<fuchsia_io::Node> server(node_server.TakeChannel());
     if (fidl::Status result =
             fidl::WireCall(memfs_dir)->Clone(fuchsia_io::wire::OpenFlags::kRightReadable |
diff --git a/src/sys/component_manager/tests/services/src/service_routing_test.rs b/src/sys/component_manager/tests/services/src/service_routing_test.rs
index 512baa5..9dcb44e 100644
--- a/src/sys/component_manager/tests/services/src/service_routing_test.rs
+++ b/src/sys/component_manager/tests/services/src/service_routing_test.rs
@@ -435,7 +435,7 @@
         .destroy_instance(
             &parent_moniker,
             &fdecl::ChildRef {
-                name: child_moniker.name().into(),
+                name: child_moniker.name().to_string(),
                 collection: child_moniker.collection().map(|c| c.to_string()),
             },
         )
diff --git a/src/sys/component_manager/tests/structured_config/capabilities/dynamic/test.cc b/src/sys/component_manager/tests/structured_config/capabilities/dynamic/test.cc
index af2620a..79d4114 100644
--- a/src/sys/component_manager/tests/structured_config/capabilities/dynamic/test.cc
+++ b/src/sys/component_manager/tests/structured_config/capabilities/dynamic/test.cc
@@ -32,19 +32,17 @@
 
 void ConnectAndCheckValues(fidl::SyncClient<fuchsia_component::Realm>& realm,
                            fuchsia_component_decl::ChildRef child_ref, ExpectedValues values) {
-  zx::result exposed_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(exposed_endpoints);
+  auto exposed_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   {
     fidl::Result result =
-        realm->OpenExposedDir({{std::move(child_ref), std::move(exposed_endpoints->server)}});
+        realm->OpenExposedDir({{std::move(child_ref), std::move(exposed_endpoints.server)}});
     ASSERT_TRUE(result.is_ok());
   }
 
-  zx::result config_endpoints = fidl::CreateEndpoints<test_config::Config>();
-  ASSERT_OK(config_endpoints);
-  ASSERT_OK(component::ConnectAt(exposed_endpoints->client, std::move(config_endpoints->server)));
+  auto config_endpoints = fidl::Endpoints<test_config::Config>::Create();
+  ASSERT_OK(component::ConnectAt(exposed_endpoints.client, std::move(config_endpoints.server)));
 
-  fidl::SyncClient config_client(std::move(config_endpoints->client));
+  fidl::SyncClient config_client(std::move(config_endpoints.client));
   ASSERT_NO_FATAL_FAILURE(CheckValues(config_client, values));
 }
 
@@ -275,22 +273,20 @@
   }});
   ASSERT_TRUE(result.is_ok(), "%s", result.error_value().FormatDescription().c_str());
 
-  zx::result exposed_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(exposed_endpoints);
+  auto exposed_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   fuchsia_component_decl::ChildRef child_ref;
   child_ref.collection("collection");
   child_ref.name("test");
   {
     fidl::Result result =
-        client->OpenExposedDir({{child_ref, std::move(exposed_endpoints->server)}});
+        client->OpenExposedDir({{child_ref, std::move(exposed_endpoints.server)}});
     ASSERT_TRUE(result.is_ok());
   }
 
-  zx::result config_endpoints = fidl::CreateEndpoints<test_config::Config>();
-  ASSERT_OK(config_endpoints);
-  ASSERT_OK(component::ConnectAt(exposed_endpoints->client, std::move(config_endpoints->server)));
+  auto config_endpoints = fidl::Endpoints<test_config::Config>::Create();
+  ASSERT_OK(component::ConnectAt(exposed_endpoints.client, std::move(config_endpoints.server)));
 
-  fidl::SyncClient config_client(std::move(config_endpoints->client));
+  fidl::SyncClient config_client(std::move(config_endpoints.client));
   {
     fidl::Result result = config_client->Get();
     ASSERT_TRUE(result.is_ok(), "%s", result.error_value().FormatDescription().c_str());
diff --git a/src/sys/core/meta/core.cml b/src/sys/core/meta/core.cml
index 58322c4..7d36514 100644
--- a/src/sys/core/meta/core.cml
+++ b/src/sys/core/meta/core.cml
@@ -142,6 +142,12 @@
             dependency: "weak",
         },
         {
+            from: "parent",
+            to: "#network",
+            config: "fuchsia.http-client.StopOnIdleTimeoutMillis",
+            availability: "same_as_target",
+        },
+        {
             protocol: [ "fuchsia.ui.activity.Provider" ],
             from: "#activity",
             to: [ "#cobalt_system_metrics" ],
diff --git a/src/sys/early_boot_instrumentation/coverage_source_test.cc b/src/sys/early_boot_instrumentation/coverage_source_test.cc
index 073d11a..b1dba78 100644
--- a/src/sys/early_boot_instrumentation/coverage_source_test.cc
+++ b/src/sys/early_boot_instrumentation/coverage_source_test.cc
@@ -250,9 +250,7 @@
                                  cpp20::span<zx::eventpair> out_tokens) {
     ASSERT_EQ(publish_info.size(), out_tokens.size());
 
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_TRUE(endpoints.is_ok()) << endpoints.status_string();
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
     const fidl::OneWayStatus status = svc_stash_->Store(std::move(server_end));
     ASSERT_TRUE(status.ok()) << status.FormatDescription();
diff --git a/src/sys/lib/cm_config/src/lib.rs b/src/sys/lib/cm_config/src/lib.rs
index 343f404..d8bad2b 100644
--- a/src/sys/lib/cm_config/src/lib.rs
+++ b/src/sys/lib/cm_config/src/lib.rs
@@ -932,7 +932,7 @@
                         allowlist: Some(vec![
                         component_internal::CapabilityAllowlistEntry {
                             source_moniker: Some("<component_manager>".to_string()),
-                            source_name: Some("fuchsia.boot.RootResource".to_string()),
+                            source_name: Some("fuchsia.kernel.MmioResource".to_string()),
                             source: Some(fdecl::Ref::Self_(fdecl::SelfRef {})),
                             capability: Some(component_internal::AllowlistedCapability::Protocol(component_internal::AllowlistedProtocol::default())),
                             target_monikers: Some(vec![
@@ -1034,7 +1034,7 @@
                     capability_policy: HashMap::from_iter(vec![
                         (CapabilityAllowlistKey {
                             source_moniker: ExtendedMoniker::ComponentManager,
-                            source_name: "fuchsia.boot.RootResource".parse().unwrap(),
+                            source_name: "fuchsia.kernel.MmioResource".parse().unwrap(),
                             source: CapabilityAllowlistSource::Self_,
                             capability: CapabilityTypeName::Protocol,
                         },
@@ -1179,7 +1179,7 @@
                         allowlist: Some(vec![
                         component_internal::CapabilityAllowlistEntry {
                             source_moniker: Some("<component_manager>".to_string()),
-                            source_name: Some("fuchsia.boot.RootResource".to_string()),
+                            source_name: Some("fuchsia.kernel.MmioResource".to_string()),
                             source: Some(fdecl::Ref::Self_(fdecl::SelfRef{})),
                             capability: None,
                             target_monikers: Some(vec!["/core".to_string()]),
diff --git a/src/sys/lib/cm_fidl_validator/src/lib.rs b/src/sys/lib/cm_fidl_validator/src/lib.rs
index e793c95..5783738 100644
--- a/src/sys/lib/cm_fidl_validator/src/lib.rs
+++ b/src/sys/lib/cm_fidl_validator/src/lib.rs
@@ -2236,7 +2236,7 @@
                     source_dictionary,
                     o.target.as_ref(),
                     o.target_name.as_ref(),
-                    Some(&fdecl::Availability::Required),
+                    o.availability.as_ref(),
                     offer_type,
                 );
 
diff --git a/src/sys/lib/cm_fidl_validator/src/util.rs b/src/sys/lib/cm_fidl_validator/src/util.rs
index fd3f205..5932398 100644
--- a/src/sys/lib/cm_fidl_validator/src/util.rs
+++ b/src/sys/lib/cm_fidl_validator/src/util.rs
@@ -327,6 +327,11 @@
             input = "/foo/bar/",
             result = Err(ErrorList::new(vec![Error::invalid_field(DeclType::Child, "foo")])),
         },
+        test_identifier_path_segment_invalid => {
+            check_fn = check_path,
+            input = "/.",
+            result = Err(ErrorList::new(vec![Error::field_invalid_segment(DeclType::Child, "foo")])),
+        },
         test_identifier_path_segment_too_long => {
             check_fn = check_path,
             input = &format!("/{}", "a".repeat(256)),
diff --git a/src/sys/lib/cm_moniker/src/instanced_child_name.rs b/src/sys/lib/cm_moniker/src/instanced_child_name.rs
index 9ba81a0..90b0926 100644
--- a/src/sys/lib/cm_moniker/src/instanced_child_name.rs
+++ b/src/sys/lib/cm_moniker/src/instanced_child_name.rs
@@ -54,8 +54,8 @@
         Self::try_new(name, coll, instance)
     }
 
-    fn name(&self) -> &str {
-        self.name.as_str()
+    fn name(&self) -> &LongName {
+        &self.name
     }
 
     fn collection(&self) -> Option<&Name> {
@@ -92,14 +92,14 @@
 
     /// Converts this child moniker into an instanced moniker.
     pub fn from_child_moniker(m: &ChildName, instance: IncarnationId) -> Self {
-        Self::try_new(m.name(), m.collection().map(|c| c.as_str()), instance)
+        Self::try_new(m.name().as_str(), m.collection().map(|c| c.as_str()), instance)
             .expect("child moniker is guaranteed to be valid")
     }
 
     /// Convert an InstancedChildName to an allocated ChildName
     /// without an InstanceId
     pub fn without_instance_id(&self) -> ChildName {
-        ChildName::try_new(self.name(), self.collection().map(|c| c.as_str()))
+        ChildName::try_new(self.name().as_str(), self.collection().map(|c| c.as_str()))
             .expect("moniker is guaranteed to be valid")
     }
 
@@ -162,7 +162,7 @@
     #[test]
     fn instanced_child_monikers() {
         let m = InstancedChildName::try_new("test", None, 42).unwrap();
-        assert_eq!("test", m.name());
+        assert_eq!("test", m.name().as_str());
         assert_eq!(None, m.collection());
         assert_eq!(42, m.instance());
         assert_eq!("test:42", format!("{}", m));
@@ -171,7 +171,7 @@
         assert_eq!(m, InstancedChildName::from_child_moniker(&"test".try_into().unwrap(), 42));
 
         let m = InstancedChildName::try_new("test", Some("coll"), 42).unwrap();
-        assert_eq!("test", m.name());
+        assert_eq!("test", m.name().as_str());
         assert_eq!(Some(&Name::new("coll").unwrap()), m.collection());
         assert_eq!(42, m.instance());
         assert_eq!("coll:test:42", format!("{}", m));
@@ -186,7 +186,7 @@
             max_coll_length_part, max_name_length_part
         ))
         .expect("valid moniker");
-        assert_eq!(max_name_length_part, m.name());
+        assert_eq!(max_name_length_part, m.name().as_str());
         assert_eq!(Some(&Name::new(max_coll_length_part).unwrap()), m.collection());
         assert_eq!(42, m.instance());
 
diff --git a/src/sys/lib/cm_moniker/src/instanced_moniker.rs b/src/sys/lib/cm_moniker/src/instanced_moniker.rs
index dbddbe5..f8117a2 100644
--- a/src/sys/lib/cm_moniker/src/instanced_moniker.rs
+++ b/src/sys/lib/cm_moniker/src/instanced_moniker.rs
@@ -50,8 +50,12 @@
             .path()
             .iter()
             .map(|c| {
-                InstancedChildName::try_new(c.name(), c.collection().map(|c| c.as_str()), 0)
-                    .expect("down path moniker is guaranteed to be valid")
+                InstancedChildName::try_new(
+                    c.name().as_str(),
+                    c.collection().map(|c| c.as_str()),
+                    0,
+                )
+                .expect("down path moniker is guaranteed to be valid")
             })
             .collect();
         InstancedMoniker::new(path)
@@ -141,7 +145,7 @@
         assert_eq!("a:1/coll:b:2", format!("{}", m));
         assert_eq!(m, InstancedMoniker::try_from(vec!["a:1", "coll:b:2"]).unwrap());
         assert_eq!(m.leaf().map(|m| m.collection()).flatten(), Some(&Name::new("coll").unwrap()));
-        assert_eq!(m.leaf().map(|m| m.name()), Some("b"));
+        assert_eq!(m.leaf().map(|m| m.name().as_str()), Some("b"));
         assert_eq!(m.leaf().map(|m| m.instance()), Some(2));
         assert_eq!(m.leaf(), Some(&InstancedChildName::try_from("coll:b:2").unwrap()));
     }
diff --git a/src/sys/lib/cm_rust/BUILD.gn b/src/sys/lib/cm_rust/BUILD.gn
index 40f28fc..9850f07 100644
--- a/src/sys/lib/cm_rust/BUILD.gn
+++ b/src/sys/lib/cm_rust/BUILD.gn
@@ -16,7 +16,6 @@
     "//sdk/fidl/fuchsia.data:fuchsia.data_rust",
     "//sdk/fidl/fuchsia.io:fuchsia.io_rust",
     "//sdk/fidl/fuchsia.process:fuchsia.process_rust",
-    "//src/lib/flyweights",
     "//src/lib/from-enum",
     "//src/sys/lib/cm_fidl_validator",
     "//src/sys/lib/cm_types",
diff --git a/src/sys/lib/cm_rust/src/lib.rs b/src/sys/lib/cm_rust/src/lib.rs
index cd6deb4..29e88b5 100644
--- a/src/sys/lib/cm_rust/src/lib.rs
+++ b/src/sys/lib/cm_rust/src/lib.rs
@@ -7,10 +7,9 @@
         ExposeDeclCommon, ExposeDeclCommonAlwaysRequired, FidlDecl, OfferDeclCommon,
         OfferDeclCommonNoAvailability, UseDeclCommon,
     },
-    cm_types::{AllowedOffers, BorrowedSeparatedPath, Name, Path, RelativePath},
+    cm_types::{AllowedOffers, BorrowedSeparatedPath, LongName, Name, Path, RelativePath},
     fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_data as fdata, fidl_fuchsia_io as fio,
     fidl_fuchsia_process as fprocess,
-    flyweights::FlyStr,
     from_enum::FromEnum,
     std::collections::{BTreeMap, HashMap},
     std::fmt,
@@ -64,6 +63,19 @@
     }
 }
 
+impl FidlIntoNative<LongName> for String {
+    fn fidl_into_native(self) -> LongName {
+        // cm_fidl_validator should have already validated this
+        self.parse().unwrap()
+    }
+}
+
+impl NativeIntoFidl<String> for LongName {
+    fn native_into_fidl(self) -> String {
+        self.to_string()
+    }
+}
+
 impl FidlIntoNative<Path> for String {
     fn fidl_into_native(self) -> Path {
         // cm_fidl_validator should have already validated this
@@ -1179,7 +1191,7 @@
 #[derive(FidlDecl, Debug, Clone, PartialEq, Eq)]
 #[fidl_decl(fidl_table = "fdecl::Child")]
 pub struct ChildDecl {
-    pub name: String,
+    pub name: LongName,
     pub url: String,
     pub startup: fdecl::StartupMode,
     pub on_terminate: Option<fdecl::OnTerminate>,
@@ -1190,7 +1202,7 @@
 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct ChildRef {
-    pub name: FlyStr,
+    pub name: LongName,
     pub collection: Option<Name>,
 }
 
@@ -1207,14 +1219,17 @@
 impl FidlIntoNative<ChildRef> for fdecl::ChildRef {
     fn fidl_into_native(self) -> ChildRef {
         // cm_fidl_validator should have already validated this
-        ChildRef { name: self.name.into(), collection: self.collection.map(|c| c.parse().unwrap()) }
+        ChildRef {
+            name: self.name.parse().unwrap(),
+            collection: self.collection.map(|c| c.parse().unwrap()),
+        }
     }
 }
 
 impl NativeIntoFidl<fdecl::ChildRef> for ChildRef {
     fn native_into_fidl(self) -> fdecl::ChildRef {
         fdecl::ChildRef {
-            name: self.name.into(),
+            name: self.name.to_string(),
             collection: self.collection.map(|c| c.to_string()),
         }
     }
@@ -2312,7 +2327,7 @@
                 if let Some(_) = c.collection {
                     panic!("Dynamic children scopes are not supported for EventStreams");
                 } else {
-                    EventScope::Child(ChildRef { name: c.name.into(), collection: None })
+                    EventScope::Child(ChildRef { name: c.name.parse().unwrap(), collection: None })
                 }
             }
             fdecl::Ref::Collection(collection) => {
@@ -2361,12 +2376,6 @@
     }
 }
 
-impl OfferSource {
-    pub fn static_child(name: String) -> Self {
-        Self::Child(ChildRef { name: name.into(), collection: None })
-    }
-}
-
 impl FidlIntoNative<OfferSource> for fdecl::Ref {
     fn fidl_into_native(self) -> OfferSource {
         match self {
@@ -2603,11 +2612,6 @@
     Collection(Name),
     Capability(Name),
 }
-impl OfferTarget {
-    pub fn static_child(name: String) -> Self {
-        Self::Child(ChildRef { name: name.into(), collection: None })
-    }
-}
 
 impl std::fmt::Display for OfferTarget {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -2686,6 +2690,14 @@
 mod tests {
     use {super::*, difference::Changeset, fidl_fuchsia_component_decl as fdecl};
 
+    fn offer_source_static_child(name: &str) -> OfferSource {
+        OfferSource::Child(ChildRef { name: name.parse().unwrap(), collection: None })
+    }
+
+    fn offer_target_static_child(name: &str) -> OfferTarget {
+        OfferTarget::Child(ChildRef { name: name.parse().unwrap(), collection: None })
+    }
+
     macro_rules! test_try_from_decl {
         (
             $(
@@ -3352,7 +3364,7 @@
                         }),
                         UseDecl::EventStream(UseEventStreamDecl {
                             source: UseSource::Child("netstack".to_string()),
-                            scope: Some(vec![EventScope::Child(ChildRef{ name: "a".into(), collection: None}), EventScope::Collection("b".parse().unwrap())]),
+                            scope: Some(vec![EventScope::Child(ChildRef{ name: "a".parse().unwrap(), collection: None}), EventScope::Collection("b".parse().unwrap())]),
                             source_name: "stopped".parse().unwrap(),
                             target_path: "/svc/test".parse().unwrap(),
                             filter: None,
@@ -3434,7 +3446,7 @@
                             source: OfferSource::Parent,
                             source_name: "legacy_netstack".parse().unwrap(),
                             source_dictionary: "in/dict".parse().unwrap(),
-                            target: OfferTarget::static_child("echo".to_string()),
+                            target: offer_target_static_child("echo"),
                             target_name: "legacy_mynetstack".parse().unwrap(),
                             dependency_type: DependencyType::Weak,
                             availability: Availability::Required,
@@ -3461,14 +3473,14 @@
                             source: OfferSource::Parent,
                             source_name: "elf".parse().unwrap(),
                             source_dictionary: "in/dict".parse().unwrap(),
-                            target: OfferTarget::static_child("echo".to_string()),
+                            target: offer_target_static_child("echo"),
                             target_name: "elf2".parse().unwrap(),
                         }),
                         OfferDecl::Resolver(OfferResolverDecl {
                             source: OfferSource::Parent,
                             source_name: "pkg".parse().unwrap(),
                             source_dictionary: "in/dict".parse().unwrap(),
-                            target: OfferTarget::static_child("echo".to_string()),
+                            target: offer_target_static_child("echo"),
                             target_name: "pkg".parse().unwrap(),
                         }),
                         OfferDecl::Service(OfferServiceDecl {
@@ -3477,7 +3489,7 @@
                             source_dictionary: "in/dict".parse().unwrap(),
                             source_instance_filter: None,
                             renamed_instances: None,
-                            target: OfferTarget::static_child("echo".to_string()),
+                            target: offer_target_static_child("echo"),
                             target_name: "mynetstack1".parse().unwrap(),
                             availability: Availability::Required,
                         }),
@@ -3487,7 +3499,7 @@
                             source_dictionary: ".".parse().unwrap(),
                             source_instance_filter: None,
                             renamed_instances: None,
-                            target: OfferTarget::static_child("echo".to_string()),
+                            target: offer_target_static_child("echo"),
                             target_name: "mynetstack2".parse().unwrap(),
                             availability: Availability::Optional,
                         }),
@@ -3497,7 +3509,7 @@
                             source_dictionary: ".".parse().unwrap(),
                             source_instance_filter: Some(vec!["allowedinstance".to_string()]),
                             renamed_instances: Some(vec![NameMapping{source_name: "default".to_string(), target_name: "allowedinstance".to_string()}]),
-                            target: OfferTarget::static_child("echo".to_string()),
+                            target: offer_target_static_child("echo"),
                             target_name: "mynetstack3".parse().unwrap(),
                             availability: Availability::Required,
                         }),
@@ -3505,7 +3517,7 @@
                             source: OfferSource::Parent,
                             source_name: "bundle".parse().unwrap(),
                             source_dictionary: "in/dict".parse().unwrap(),
-                            target: OfferTarget::static_child("echo".to_string()),
+                            target: offer_target_static_child("echo"),
                             target_name: "mybundle".parse().unwrap(),
                             dependency_type: DependencyType::Weak,
                             availability: Availability::Required,
@@ -3554,7 +3566,7 @@
                     ],
                     children: vec![
                         ChildDecl {
-                            name: "netstack".to_string(),
+                            name: "netstack".parse().unwrap(),
                             url: "fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cm".to_string(),
                             startup: fdecl::StartupMode::Lazy,
                             on_terminate: None,
@@ -3562,7 +3574,7 @@
                             config_overrides: None,
                         },
                         ChildDecl {
-                            name: "gtest".to_string(),
+                            name: "gtest".parse().unwrap(),
                             url: "fuchsia-pkg://fuchsia.com/gtest#meta/gtest.cm".to_string(),
                             startup: fdecl::StartupMode::Lazy,
                             on_terminate: Some(fdecl::OnTerminate::None),
@@ -3570,7 +3582,7 @@
                             config_overrides: None,
                         },
                         ChildDecl {
-                            name: "echo".to_string(),
+                            name: "echo".parse().unwrap(),
                             url: "fuchsia-pkg://fuchsia.com/echo#meta/echo.cm".to_string(),
                             startup: fdecl::StartupMode::Eager,
                             on_terminate: Some(fdecl::OnTerminate::Reboot),
@@ -3712,7 +3724,7 @@
             input_type = fdecl::Ref,
             result = vec![
                 OfferSource::Self_,
-                OfferSource::static_child("foo".to_string()),
+                offer_source_static_child("foo"),
                 OfferSource::Framework,
                 OfferSource::Capability("foo".parse().unwrap()),
                 OfferSource::Parent,
@@ -3734,7 +3746,7 @@
             result = vec![
                 DictionarySource::Self_,
                 DictionarySource::Child(ChildRef {
-                    name: "foo".into(),
+                    name: "foo".parse().unwrap(),
                     collection: None,
                 }),
                 DictionarySource::Parent,
diff --git a/src/sys/lib/cm_rust/testing/BUILD.gn b/src/sys/lib/cm_rust/testing/BUILD.gn
index f82338b..6cc4515 100644
--- a/src/sys/lib/cm_rust/testing/BUILD.gn
+++ b/src/sys/lib/cm_rust/testing/BUILD.gn
@@ -27,11 +27,12 @@
 
   visibility = [
     "//src/connectivity/network/testing/netemul/runner:*",
+    "//src/lib/fuchsia-component-test/realm_builder_server/*",
     "//src/security/lib/scrutiny/plugins:*",
     "//src/security/lib/scrutiny/x:*",
     "//src/sys/component_manager/*",
     "//src/sys/lib/cm_rust/testing:*",
-    "//src/sys/lib/routing/testing/*",
+    "//src/sys/lib/routing/*",
     "//tools/lib/cm_fidl_analyzer/*",
   ]
 
diff --git a/src/sys/lib/cm_rust/testing/src/lib.rs b/src/sys/lib/cm_rust/testing/src/lib.rs
index d8aeb93..cc5d6b5 100644
--- a/src/sys/lib/cm_rust/testing/src/lib.rs
+++ b/src/sys/lib/cm_rust/testing/src/lib.rs
@@ -6,7 +6,7 @@
     anyhow::{Context, Error},
     assert_matches::assert_matches,
     cm_rust::{CapabilityTypeName, ComponentDecl, FidlIntoNative},
-    cm_types::{Name, Path, RelativePath},
+    cm_types::{LongName, Name, Path, RelativePath},
     derivative::Derivative,
     fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_data as fdata, fidl_fuchsia_io as fio,
     std::collections::BTreeMap,
@@ -161,7 +161,7 @@
 #[derive(Debug, Derivative)]
 #[derivative(Default)]
 pub struct ChildBuilder {
-    name: Option<String>,
+    name: Option<LongName>,
     url: Option<String>,
     #[derivative(Default(value = "fdecl::StartupMode::Lazy"))]
     startup: fdecl::StartupMode,
@@ -176,7 +176,7 @@
 
     /// Defaults url to `"test:///{name}"`.
     pub fn name(mut self, name: &str) -> Self {
-        self.name = Some(name.into());
+        self.name = Some(name.parse().unwrap());
         if self.url.is_none() {
             self.url = Some(format!("test:///{name}"));
         }
@@ -1036,6 +1036,14 @@
     }
 }
 
+pub fn offer_source_static_child(name: &str) -> cm_rust::OfferSource {
+    cm_rust::OfferSource::Child(cm_rust::ChildRef { name: name.parse().unwrap(), collection: None })
+}
+
+pub fn offer_target_static_child(name: &str) -> cm_rust::OfferTarget {
+    cm_rust::OfferTarget::Child(cm_rust::ChildRef { name: name.parse().unwrap(), collection: None })
+}
+
 /// A convenience builder for constructing [OfferDecl]s.
 ///
 /// To use, call the constructor matching their capability type ([OfferBuilder::protocol],
@@ -1146,11 +1154,19 @@
         self
     }
 
+    pub fn source_static_child(self, source: &str) -> Self {
+        self.source(offer_source_static_child(source))
+    }
+
     pub fn target(mut self, target: cm_rust::OfferTarget) -> Self {
         self.target = Some(target);
         self
     }
 
+    pub fn target_static_child(self, target: &str) -> Self {
+        self.target(offer_target_static_child(target))
+    }
+
     pub fn availability(mut self, availability: cm_rust::Availability) -> Self {
         assert_matches!(
             self.type_,
diff --git a/src/sys/lib/cm_types/src/lib.rs b/src/sys/lib/cm_types/src/lib.rs
index fcaf1aa9..5753b16 100644
--- a/src/sys/lib/cm_types/src/lib.rs
+++ b/src/sys/lib/cm_types/src/lib.rs
@@ -165,6 +165,10 @@
     pub fn is_empty(&self) -> bool {
         self.0.is_empty()
     }
+
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
 }
 
 impl<const N: usize> AsRef<str> for BoundedName<N> {
@@ -173,9 +177,9 @@
     }
 }
 
-impl<const N: usize> Borrow<str> for BoundedName<N> {
-    fn borrow(&self) -> &str {
-        self.as_str()
+impl<const N: usize> Borrow<FlyStr> for BoundedName<N> {
+    fn borrow(&self) -> &FlyStr {
+        &self.0
     }
 }
 
@@ -291,7 +295,12 @@
         if path == "/" {
             Ok(Self(RelativePath::dot()))
         } else {
-            Ok(Self(path[1..].parse()?))
+            let path: RelativePath = path[1..].parse()?;
+            if path.is_dot() {
+                // "/." is not a valid NamespacePath
+                return Err(ParseError::InvalidSegment);
+            }
+            Ok(Self(path))
         }
     }
 
@@ -453,7 +462,12 @@
         if path.len() > MAX_PATH_LENGTH {
             return Err(ParseError::TooLong);
         }
-        Ok(Self(path[1..].parse()?))
+        let path: RelativePath = path[1..].parse()?;
+        if path.is_dot() {
+            // "/." is not a valid Path
+            return Err(ParseError::InvalidSegment);
+        }
+        Ok(Self(path))
     }
 
     /// Splits the path according to "/".
@@ -680,7 +694,7 @@
         if self.is_dot() {
             write!(f, ".")
         } else {
-            write!(f, "{}", self.segments.join("/"))
+            write!(f, "{}", self.segments.iter().map(|s| s.as_str()).collect::<Vec<_>>().join("/"))
         }
     }
 }
@@ -1318,6 +1332,7 @@
         expect_err!(Path, ParseError::InvalidValue, "/foo/");
         expect_err!(Path, ParseError::InvalidValue, "/foo//bar");
         expect_err!(Path, ParseError::InvalidSegment, "/fo\0b/bar");
+        expect_err!(Path, ParseError::InvalidSegment, "/.");
         expect_err!(Path, ParseError::InvalidSegment, "/foo/.");
         expect_err!(
             Path,
@@ -1357,6 +1372,7 @@
         expect_err_no_serialize!(NamespacePath, ParseError::InvalidValue, "/foo/");
         expect_err_no_serialize!(NamespacePath, ParseError::InvalidValue, "/foo//bar");
         expect_err_no_serialize!(NamespacePath, ParseError::InvalidSegment, "/fo\0b/bar");
+        expect_err_no_serialize!(NamespacePath, ParseError::InvalidSegment, "/.");
         expect_err_no_serialize!(NamespacePath, ParseError::InvalidSegment, "/foo/.");
         expect_err_no_serialize!(
             NamespacePath,
diff --git a/src/sys/lib/component_debug/src/capability.rs b/src/sys/lib/component_debug/src/capability.rs
index 47cde6e..2e040bd 100644
--- a/src/sys/lib/component_debug/src/capability.rs
+++ b/src/sys/lib/component_debug/src/capability.rs
@@ -171,7 +171,7 @@
                 "./my_foo".to_string(),
                 ComponentDecl {
                     children: vec![ChildDecl {
-                        name: "my_bar".to_string(),
+                        name: "my_bar".parse().unwrap(),
                         url: "fuchsia-pkg://fuchsia.com/bar#meta/bar.cm".to_string(),
                         startup: fdecl::StartupMode::Lazy,
                         environment: None,
@@ -199,7 +199,7 @@
                         source_name: "fuchsia.foo.bar".parse().unwrap(),
                         source_dictionary: Default::default(),
                         target: OfferTarget::Child(ChildRef {
-                            name: "my_bar".into(),
+                            name: "my_bar".parse().unwrap(),
                             collection: None,
                         }),
                         target_name: "fuchsia.foo.bar".parse().unwrap(),
@@ -261,7 +261,7 @@
                             source_name: "fuchsia.foo.bar".parse().unwrap(),
                             source_dictionary: Default::default(),
                             target: OfferTarget::Child(ChildRef {
-                                name: "my_bar".into(),
+                                name: "my_bar".parse().unwrap(),
                                 collection: None,
                             }),
                             target_name: "fuchsia.foo.bar".parse().unwrap(),
diff --git a/src/sys/lib/component_debug/src/lifecycle.rs b/src/sys/lib/component_debug/src/lifecycle.rs
index 08581bb..36e508f 100644
--- a/src/sys/lib/component_debug/src/lifecycle.rs
+++ b/src/sys/lib/component_debug/src/lifecycle.rs
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 use {
-    cm_types::Name,
+    cm_types::{LongName, Name},
     fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_decl as fdecl,
     fidl_fuchsia_sys2 as fsys,
     fuchsia_url::AbsoluteComponentUrl,
@@ -75,7 +75,7 @@
     lifecycle_controller: &fsys::LifecycleControllerProxy,
     parent: &Moniker,
     collection: &Name,
-    child_name: &str,
+    child_name: &LongName,
     url: &AbsoluteComponentUrl,
     config_overrides: Vec<fdecl::ConfigOverride>,
     child_args: Option<fcomponent::CreateChildArgs>,
@@ -118,7 +118,7 @@
     lifecycle_controller: &fsys::LifecycleControllerProxy,
     parent: &Moniker,
     collection: &Name,
-    child_name: &str,
+    child_name: &LongName,
 ) -> Result<(), DestroyError> {
     let child =
         fdecl::ChildRef { name: child_name.to_string(), collection: Some(collection.to_string()) };
@@ -433,7 +433,7 @@
             &lc,
             &parent,
             &"foo".parse().unwrap(),
-            "bar",
+            &"bar".parse().unwrap(),
             &url,
             vec![],
             None,
@@ -466,7 +466,7 @@
             &lc,
             &parent,
             &"foo".parse().unwrap(),
-            "bar",
+            &"bar".parse().unwrap(),
             &url,
             vec![],
             Some(child_args),
@@ -485,7 +485,7 @@
             &lc,
             &parent,
             &"foo".parse().unwrap(),
-            "bar",
+            &"bar".parse().unwrap(),
             &url,
             vec![],
             None,
@@ -499,7 +499,14 @@
     async fn test_destroy_child() {
         let parent = Moniker::parse_str("core").unwrap();
         let lc = lifecycle_destroy_instance("core", "foo", "bar");
-        destroy_instance_in_collection(&lc, &parent, &"foo".parse().unwrap(), "bar").await.unwrap();
+        destroy_instance_in_collection(
+            &lc,
+            &parent,
+            &"foo".parse().unwrap(),
+            &"bar".parse().unwrap(),
+        )
+        .await
+        .unwrap();
     }
 
     #[fuchsia_async::run_singlethreaded(test)]
diff --git a/src/sys/lib/elf_runner/meta/elf_runner_tests.cml b/src/sys/lib/elf_runner/meta/elf_runner_tests.cml
index b85f9ec..b696c31 100644
--- a/src/sys/lib/elf_runner/meta/elf_runner_tests.cml
+++ b/src/sys/lib/elf_runner/meta/elf_runner_tests.cml
@@ -15,6 +15,7 @@
         {
             protocol: [
                 "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.DebugResource",
                 "fuchsia.kernel.EnergyInfoResource",
                 "fuchsia.kernel.FramebufferResource",
diff --git a/src/sys/lib/elf_runner/src/memory/reporter.rs b/src/sys/lib/elf_runner/src/memory/reporter.rs
index dfcaba8..4c5ea85 100644
--- a/src/sys/lib/elf_runner/src/memory/reporter.rs
+++ b/src/sys/lib/elf_runner/src/memory/reporter.rs
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use attribution::AttributionServer;
+use attribution::{AttributionServer, AttributionServerHandle};
 use fidl::endpoints::RequestStream;
 use fidl::endpoints::{ControlHandle, DiscoverableProtocolMarker};
 use fidl_fuchsia_io as fio;
@@ -16,7 +16,7 @@
 use crate::{component::ElfComponentInfo, ComponentSet};
 
 pub struct MemoryReporter {
-    server: AttributionServer,
+    server: AttributionServerHandle,
     components: Arc<ComponentSet>,
 }
 
diff --git a/src/sys/lib/fidl-fuchsia-pkg-ext/src/cache/storage.rs b/src/sys/lib/fidl-fuchsia-pkg-ext/src/cache/storage.rs
index c5078b2..9744a5d 100644
--- a/src/sys/lib/fidl-fuchsia-pkg-ext/src/cache/storage.rs
+++ b/src/sys/lib/fidl-fuchsia-pkg-ext/src/cache/storage.rs
@@ -240,7 +240,7 @@
         let blobfs = blobfs_ramdisk::BlobfsRamdisk::builder().fxblob().start().await.unwrap();
         assert_eq!(blobfs.list_blobs().unwrap(), std::collections::BTreeSet::new());
         let contents = [0u8; 7];
-        let hash = fuchsia_merkle::MerkleTree::from_reader(&contents[..]).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(&contents).root();
         let compressed = delivery_blob::Type1Blob::generate(
             &contents[..],
             delivery_blob::CompressionMode::Attempt,
diff --git a/src/sys/lib/moniker/src/child_name.rs b/src/sys/lib/moniker/src/child_name.rs
index 4b95d9e..7ff1c2a 100644
--- a/src/sys/lib/moniker/src/child_name.rs
+++ b/src/sys/lib/moniker/src/child_name.rs
@@ -14,7 +14,7 @@
     where
         Self: Sized;
 
-    fn name(&self) -> &str;
+    fn name(&self) -> &LongName;
 
     fn collection(&self) -> Option<&Name>;
 }
@@ -46,8 +46,8 @@
         ChildName::try_new(name, coll)
     }
 
-    fn name(&self) -> &str {
-        self.name.as_str()
+    fn name(&self) -> &LongName {
+        &self.name
     }
 
     fn collection(&self) -> Option<&Name> {
@@ -88,11 +88,15 @@
     }
 }
 
-impl TryFrom<cm_rust::ChildRef> for ChildName {
-    type Error = cm_types::ParseError;
+impl From<cm_rust::ChildRef> for ChildName {
+    fn from(child_ref: cm_rust::ChildRef) -> Self {
+        Self { name: child_ref.name, collection: child_ref.collection }
+    }
+}
 
-    fn try_from(child_ref: cm_rust::ChildRef) -> Result<Self, Self::Error> {
-        Ok(Self { name: child_ref.name.parse()?, collection: child_ref.collection })
+impl From<(LongName, Option<Name>)> for ChildName {
+    fn from(t: (LongName, Option<Name>)) -> Self {
+        Self { name: t.0, collection: t.1 }
     }
 }
 
@@ -130,13 +134,13 @@
     #[test]
     fn child_monikers() {
         let m = ChildName::try_new("test", None).unwrap();
-        assert_eq!("test", m.name());
+        assert_eq!("test", m.name().as_str());
         assert_eq!(None, m.collection());
         assert_eq!("test", format!("{}", m));
         assert_eq!(m, ChildName::try_from("test").unwrap());
 
         let m = ChildName::try_new("test", Some("coll")).unwrap();
-        assert_eq!("test", m.name());
+        assert_eq!("test", m.name().as_str());
         assert_eq!(Some(&Name::new("coll").unwrap()), m.collection());
         assert_eq!("coll:test", format!("{}", m));
         assert_eq!(m, ChildName::try_from("coll:test").unwrap());
@@ -145,7 +149,7 @@
         let max_name_length_part = "f".repeat(MAX_LONG_NAME_LENGTH);
         let max_moniker_length = format!("{}:{}", max_coll_length_part, max_name_length_part);
         let m = ChildName::parse(max_moniker_length).expect("valid moniker");
-        assert_eq!(&max_name_length_part, m.name());
+        assert_eq!(&max_name_length_part, m.name().as_str());
         assert_eq!(Some(&Name::new(max_coll_length_part).unwrap()), m.collection());
 
         assert!(ChildName::parse("").is_err(), "cannot be empty");
diff --git a/src/sys/lib/moniker/src/moniker.rs b/src/sys/lib/moniker/src/moniker.rs
index 2538ddc..74d42a0 100644
--- a/src/sys/lib/moniker/src/moniker.rs
+++ b/src/sys/lib/moniker/src/moniker.rs
@@ -240,7 +240,7 @@
         assert_eq!("a/coll:b", format!("{}", m));
         assert_eq!(m, Moniker::try_from(vec!["a", "coll:b"]).unwrap());
         assert_eq!(m.leaf().map(|m| m.collection()).flatten(), Some(&Name::new("coll").unwrap()));
-        assert_eq!(m.leaf().map(|m| m.name()), Some("b"));
+        assert_eq!(m.leaf().map(|m| m.name().as_str()), Some("b"));
         assert_eq!(m.leaf(), Some(&ChildName::try_from("coll:b").unwrap()));
     }
 
diff --git a/src/sys/lib/namespace/src/tree.rs b/src/sys/lib/namespace/src/tree.rs
index 21f6635..640e13f 100644
--- a/src/sys/lib/namespace/src/tree.rs
+++ b/src/sys/lib/namespace/src/tree.rs
@@ -107,15 +107,14 @@
         }
     }
 
-    fn get_mut<I, V>(&mut self, mut path: I) -> Option<&mut T>
+    fn get_mut<'a, 'b, I>(&'a mut self, mut path: I) -> Option<&'a mut T>
     where
-        I: Iterator<Item = V>,
-        V: AsRef<str> + std::hash::Hash + std::cmp::Eq,
+        I: Iterator<Item = &'b Name>,
     {
         match path.next() {
             Some(name) => match self {
                 Node::Leaf(_) => None,
-                Node::Internal(children) => match children.get_mut(name.as_ref()) {
+                Node::Internal(children) => match children.get_mut(name) {
                     Some(node) => node.get_mut(path),
                     None => None,
                 },
@@ -127,15 +126,14 @@
         }
     }
 
-    fn get<I, V>(&self, mut path: I) -> Option<&T>
+    fn get<'a, 'b, I>(&'a self, mut path: I) -> Option<&'a T>
     where
-        I: Iterator<Item = V>,
-        V: AsRef<str> + std::hash::Hash + std::cmp::Eq,
+        I: Iterator<Item = &'b Name>,
     {
         match path.next() {
             Some(name) => match self {
                 Node::Leaf(_) => None,
-                Node::Internal(children) => match children.get(name.as_ref()) {
+                Node::Internal(children) => match children.get(name) {
                     Some(node) => node.get(path),
                     None => None,
                 },
@@ -165,7 +163,7 @@
                             None => None,
                         }
                     } else {
-                        match children.get_mut(name.as_str()) {
+                        match children.get_mut(name) {
                             Some(node) => node.remove(path),
                             None => None,
                         }
diff --git a/src/sys/lib/routing/BUILD.gn b/src/sys/lib/routing/BUILD.gn
index 0f4c35c..4ddd9b2 100644
--- a/src/sys/lib/routing/BUILD.gn
+++ b/src/sys/lib/routing/BUILD.gn
@@ -74,6 +74,7 @@
   ]
 
   test_deps = [
+    "//src/sys/lib/cm_rust/testing",
     "//third_party/rust_crates:assert_matches",
     "//third_party/rust_crates:test-case",
   ]
diff --git a/src/sys/lib/routing/src/availability.rs b/src/sys/lib/routing/src/availability.rs
index 3c6fb59..dfb9942 100644
--- a/src/sys/lib/routing/src/availability.rs
+++ b/src/sys/lib/routing/src/availability.rs
@@ -67,8 +67,9 @@
         super::*,
         cm_rust::{
             DependencyType, ExposeDecl, ExposeProtocolDecl, ExposeTarget, OfferDecl,
-            OfferProtocolDecl, OfferTarget,
+            OfferProtocolDecl,
         },
+        cm_rust_testing::*,
         test_case::test_case,
     };
 
@@ -77,7 +78,7 @@
             source: OfferSource::Parent,
             source_name: "fuchsia.examples.Echo".parse().unwrap(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child("echo".to_string()),
+            target: offer_target_static_child("echo"),
             target_name: "fuchsia.examples.Echo".parse().unwrap(),
             dependency_type: DependencyType::Weak,
             availability,
@@ -89,7 +90,7 @@
             source: OfferSource::Void,
             source_name: "fuchsia.examples.Echo".parse().unwrap(),
             source_dictionary: Default::default(),
-            target: OfferTarget::static_child("echo".to_string()),
+            target: offer_target_static_child("echo"),
             target_name: "fuchsia.examples.Echo".parse().unwrap(),
             dependency_type: DependencyType::Weak,
             availability: Availability::Optional,
diff --git a/src/sys/lib/routing/src/collection.rs b/src/sys/lib/routing/src/collection.rs
index 880ceb6..72d3989 100644
--- a/src/sys/lib/routing/src/collection.rs
+++ b/src/sys/lib/routing/src/collection.rs
@@ -432,7 +432,8 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    use cm_rust::{Availability, ChildRef, OfferSource, OfferTarget};
+    use cm_rust::{Availability, OfferSource};
+    use cm_rust_testing::*;
 
     #[test]
     fn test_get_instance_filter() {
@@ -444,7 +445,7 @@
                 source: OfferSource::Parent,
                 source_name: "foo".parse().unwrap(),
                 source_dictionary: Default::default(),
-                target: OfferTarget::Child(ChildRef { name: "a".into(), collection: None }),
+                target: offer_target_static_child("a"),
                 target_name: "bar".parse().unwrap(),
                 source_instance_filter,
                 renamed_instances,
diff --git a/src/sys/lib/routing/src/legacy_router.rs b/src/sys/lib/routing/src/legacy_router.rs
index 01123af..36fefcd 100644
--- a/src/sys/lib/routing/src/legacy_router.rs
+++ b/src/sys/lib/routing/src/legacy_router.rs
@@ -1477,7 +1477,7 @@
 fn target_matches_moniker(target: &OfferTarget, child_moniker: &ChildName) -> bool {
     match target {
         OfferTarget::Child(target_ref) => {
-            target_ref.name == child_moniker.name()
+            &target_ref.name == child_moniker.name()
                 && target_ref.collection.as_ref() == child_moniker.collection()
         }
         OfferTarget::Collection(target_collection) => {
@@ -1597,9 +1597,7 @@
 #[cfg(test)]
 mod tests {
     use {
-        super::*,
-        assert_matches::assert_matches,
-        cm_rust::{ChildRef, ExposeServiceDecl},
+        super::*, assert_matches::assert_matches, cm_rust::ExposeServiceDecl, cm_rust_testing::*,
     };
 
     #[test]
@@ -1639,7 +1637,7 @@
             source: OfferSource::Collection("coll".parse().unwrap()),
             source_name: "foo_source".parse().unwrap(),
             source_dictionary: Default::default(),
-            target: OfferTarget::Child(ChildRef { name: "target".into(), collection: None }),
+            target: offer_target_static_child("target"),
             target_name: "foo_target".parse().unwrap(),
             source_instance_filter: None,
             renamed_instances: None,
diff --git a/src/sys/lib/routing/testing/src/availability.rs b/src/sys/lib/routing/testing/src/availability.rs
index 9e1421e..5b64717 100644
--- a/src/sys/lib/routing/testing/src/availability.rs
+++ b/src/sys/lib/routing/testing/src/availability.rs
@@ -82,22 +82,22 @@
                         .offer(
                             OfferBuilder::service()
                                 .name("fuchsia.examples.EchoService")
-                                .source(OfferSource::static_child("b".to_string()))
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .source_static_child("b")
+                                .target_static_child("c")
                                 .availability(test_case.provider_availability),
                         )
                         .offer(
                             OfferBuilder::protocol()
                                 .name("fuchsia.examples.Echo")
-                                .source(OfferSource::static_child("b".to_string()))
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .source_static_child("b")
+                                .target_static_child("c")
                                 .availability(test_case.provider_availability),
                         )
                         .offer(
                             OfferBuilder::directory()
                                 .name("dir")
-                                .source(OfferSource::static_child("b".to_string()))
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .source_static_child("b")
+                                .target_static_child("c")
                                 .rights(fio::R_STAR_DIR)
                                 .availability(test_case.provider_availability),
                         )
@@ -118,14 +118,14 @@
                             OfferBuilder::storage()
                                 .name("cache")
                                 .source(OfferSource::Self_)
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .target_static_child("c")
                                 .availability(test_case.provider_availability),
                         )
                         .offer(
                             OfferBuilder::event_stream()
                                 .name("started")
                                 .source(OfferSource::Parent)
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .target_static_child("c")
                                 .availability(test_case.provider_availability),
                         )
                         .child_default("b")
@@ -246,7 +246,7 @@
         }
         for test_case in &[
             TestCase {
-                source: OfferSource::static_child("b".to_string()),
+                source: offer_source_static_child("b"),
                 storage_source: Some(OfferSource::Self_),
                 offer_availability: Availability::Optional,
                 use_availability: Availability::Required,
@@ -284,21 +284,21 @@
                             OfferBuilder::service()
                                 .name("fuchsia.examples.EchoService")
                                 .source(test_case.source.clone())
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .target_static_child("c")
                                 .availability(test_case.offer_availability),
                         )
                         .offer(
                             OfferBuilder::protocol()
                                 .name("fuchsia.examples.Echo")
                                 .source(test_case.source.clone())
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .target_static_child("c")
                                 .availability(test_case.offer_availability),
                         )
                         .offer(
                             OfferBuilder::directory()
                                 .name("dir")
                                 .source(test_case.source.clone())
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .target_static_child("c")
                                 .rights(fio::Operations::CONNECT)
                                 .availability(test_case.offer_availability),
                         )
@@ -312,7 +312,7 @@
                                         .map(Clone::clone)
                                         .unwrap_or(test_case.source.clone()),
                                 )
-                                .target(OfferTarget::static_child("c".to_string()))
+                                .target_static_child("c")
                                 .availability(test_case.offer_availability),
                         )
                         .capability(
diff --git a/src/sys/lib/routing/testing/src/lib.rs b/src/sys/lib/routing/testing/src/lib.rs
index ae31e25..80973c5 100644
--- a/src/sys/lib/routing/testing/src/lib.rs
+++ b/src/sys/lib/routing/testing/src/lib.rs
@@ -400,7 +400,7 @@
                             .name("foo_data")
                             .target_name("bar_data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
@@ -408,14 +408,14 @@
                             .name("foo")
                             .target_name("bar")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("file")
                             .target_name("device")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -640,7 +640,7 @@
                             .name("foo_data")
                             .target_name("bar_data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
@@ -648,7 +648,7 @@
                             .name("foo")
                             .target_name("bar")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -661,7 +661,7 @@
                             .name("bar_data")
                             .target_name("baz_data")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
@@ -669,7 +669,7 @@
                             .name("bar")
                             .target_name("baz")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .build(),
@@ -718,7 +718,7 @@
                         OfferBuilder::protocol()
                             .name("builtin.Echo")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -730,7 +730,7 @@
                         OfferBuilder::protocol()
                             .name("builtin.Echo")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .build(),
@@ -781,16 +781,16 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("foobar_data")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("d")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("bar")
                             .target_name("foobar")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .source_static_child("d")
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .child_default("d")
@@ -858,16 +858,16 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("baz_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("bar")
                             .target_name("baz")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .source_static_child("b")
+                            .target_static_child("c"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -938,16 +938,16 @@
                         OfferBuilder::directory()
                             .name("baz_data")
                             .target_name("foobar_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("baz")
                             .target_name("foobar")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .source_static_child("b")
+                            .target_static_child("c"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -1041,13 +1041,13 @@
                             .name("foo")
                             .target_name("foo_from_a_svc")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .offer(
                         OfferBuilder::directory()
                             .name("foo_from_d_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .child_default("b")
@@ -1060,15 +1060,15 @@
                     .offer(
                         OfferBuilder::directory()
                             .name("foo_from_d_data")
-                            .source(OfferSource::static_child("d".to_string()))
-                            .target(OfferTarget::static_child("e".to_string()))
+                            .source_static_child("d")
+                            .target_static_child("e")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("foo_from_a_svc")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("e".to_string())),
+                            .target_static_child("e"),
                     )
                     .expose(
                         ExposeBuilder::directory()
@@ -1087,14 +1087,14 @@
                         OfferBuilder::directory()
                             .name("foo_from_d_data")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("f".to_string()))
+                            .target_static_child("f")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("foo_from_h_svc")
-                            .source(OfferSource::static_child("g".to_string()))
-                            .target(OfferTarget::static_child("f".to_string())),
+                            .source_static_child("g")
+                            .target_static_child("f"),
                     )
                     .child_default("f")
                     .child_default("g")
@@ -1245,7 +1245,7 @@
                             .name("foo_data")
                             .target_name("bar_data")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
@@ -1253,7 +1253,7 @@
                             .name("foo")
                             .target_name("bar")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -1349,15 +1349,15 @@
                     .offer(
                         OfferBuilder::directory()
                             .name("hippo_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("hippo")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .source_static_child("b")
+                            .target_static_child("c"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -1410,14 +1410,14 @@
                         OfferBuilder::directory()
                             .name("hippo_data")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("hippo")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .build(),
@@ -1566,16 +1566,16 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("baz_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("bar")
                             .target_name("baz")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .source_static_child("b")
+                            .target_static_child("c"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -1648,14 +1648,14 @@
                         OfferBuilder::directory()
                             .name("hippo_data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::R_STAR_DIR),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("hippo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -1704,8 +1704,8 @@
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
-                            .source(OfferSource::static_child("b".parse().unwrap()))
-                            .target(OfferTarget::static_child("d".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("d")
                             .source_instance_filter(vec![
                                 "instance_0".to_string(),
                                 "instance_1".to_string(),
@@ -1714,8 +1714,8 @@
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
-                            .source(OfferSource::static_child("c".parse().unwrap()))
-                            .target(OfferTarget::static_child("d".to_string()))
+                            .source_static_child("c")
+                            .target_static_child("d")
                             .source_instance_filter(vec![
                                 "instance_2".to_string(),
                                 "instance_3".to_string(),
@@ -1799,7 +1799,7 @@
                         OfferBuilder::service()
                             .name("foo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .capability(expected_service_decl.clone())
                     .child_default("b")
@@ -1811,20 +1811,20 @@
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
-                            .source(OfferSource::static_child("c".parse().unwrap()))
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .source_static_child("c")
+                            .target_static_child("d"),
                     )
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .capability(expected_service_decl.clone())
                     .child_default("c")
@@ -1898,8 +1898,8 @@
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
-                            .source(OfferSource::static_child("b".parse().unwrap()))
-                            .target(OfferTarget::static_child("d".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("d")
                             .source_instance_filter(vec![
                                 "default".to_string(),
                                 "other_a".to_string(),
@@ -1908,8 +1908,8 @@
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
-                            .source(OfferSource::static_child("c".parse().unwrap()))
-                            .target(OfferTarget::static_child("d".to_string()))
+                            .source_static_child("c")
+                            .target_static_child("d")
                             .source_instance_filter(vec![
                                 "default".to_string(),
                                 "other_b".to_string(),
@@ -1978,7 +1978,7 @@
                         OfferBuilder::directory()
                             .name("foo_data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::R_STAR_DIR)
                             .subdir("s1/s2"),
                     )
@@ -1992,7 +1992,7 @@
                         OfferBuilder::directory()
                             .name("foo_data")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR)
                             .subdir("s3"),
                     )
@@ -2039,8 +2039,8 @@
                     .offer(
                         OfferBuilder::directory()
                             .name("foo_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR)
                             .subdir("s3"),
                     )
@@ -2350,7 +2350,7 @@
                             .name("invalid")
                             .target_name("valid")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -2484,11 +2484,11 @@
                             .name("started")
                             .source(OfferSource::Parent)
                             .target(OfferTarget::Child(ChildRef {
-                                name: "b".into(),
+                                name: "b".parse().unwrap(),
                                 collection: None,
                             }))
                             .scope(vec![EventScope::Child(ChildRef {
-                                name: "b".into(),
+                                name: "b".parse().unwrap(),
                                 collection: None,
                             })]),
                     )
@@ -2497,11 +2497,11 @@
                             .name("started")
                             .source(OfferSource::Parent)
                             .target(OfferTarget::Child(ChildRef {
-                                name: "d".into(),
+                                name: "d".parse().unwrap(),
                                 collection: None,
                             }))
                             .scope(vec![EventScope::Child(ChildRef {
-                                name: "c".into(),
+                                name: "c".parse().unwrap(),
                                 collection: None,
                             })]),
                     )
@@ -2510,11 +2510,11 @@
                             .name("started")
                             .source(OfferSource::Parent)
                             .target(OfferTarget::Child(ChildRef {
-                                name: "c".into(),
+                                name: "c".parse().unwrap(),
                                 collection: None,
                             }))
                             .scope(vec![EventScope::Child(ChildRef {
-                                name: "d".into(),
+                                name: "d".parse().unwrap(),
                                 collection: None,
                             })]),
                     )
@@ -2644,12 +2644,18 @@
                             .name("started")
                             .source(OfferSource::Parent)
                             .target(OfferTarget::Child(ChildRef {
-                                name: "b".into(),
+                                name: "b".parse().unwrap(),
                                 collection: None,
                             }))
                             .scope(vec![
-                                EventScope::Child(ChildRef { name: "b".into(), collection: None }),
-                                EventScope::Child(ChildRef { name: "c".into(), collection: None }),
+                                EventScope::Child(ChildRef {
+                                    name: "b".parse().unwrap(),
+                                    collection: None,
+                                }),
+                                EventScope::Child(ChildRef {
+                                    name: "c".parse().unwrap(),
+                                    collection: None,
+                                }),
                             ]),
                     )
                     .offer(
@@ -2657,12 +2663,18 @@
                             .name("started")
                             .source(OfferSource::Parent)
                             .target(OfferTarget::Child(ChildRef {
-                                name: "c".into(),
+                                name: "c".parse().unwrap(),
                                 collection: None,
                             }))
                             .scope(vec![
-                                EventScope::Child(ChildRef { name: "b".into(), collection: None }),
-                                EventScope::Child(ChildRef { name: "c".into(), collection: None }),
+                                EventScope::Child(ChildRef {
+                                    name: "b".parse().unwrap(),
+                                    collection: None,
+                                }),
+                                EventScope::Child(ChildRef {
+                                    name: "c".parse().unwrap(),
+                                    collection: None,
+                                }),
                             ]),
                     )
                     .child_default("b")
@@ -2684,11 +2696,11 @@
                             .name("started")
                             .source(OfferSource::Parent)
                             .target(OfferTarget::Child(ChildRef {
-                                name: "d".into(),
+                                name: "d".parse().unwrap(),
                                 collection: None,
                             }))
                             .scope(vec![EventScope::Child(ChildRef {
-                                name: "e".into(),
+                                name: "e".parse().unwrap(),
                                 collection: None,
                             })]),
                     )
@@ -2776,7 +2788,7 @@
                             .name("capability_requested")
                             .target_name("capability_requested_on_a")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -2824,7 +2836,7 @@
                         OfferBuilder::protocol()
                             .name("hippo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -2871,7 +2883,7 @@
                             .name("foo_data")
                             .target_name("bar_data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::R_STAR_DIR),
                     )
                     .child_default("b")
@@ -2922,7 +2934,7 @@
                         OfferBuilder::protocol()
                             .name("hippo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -2934,7 +2946,7 @@
                         OfferBuilder::protocol()
                             .name("hippo")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .use_(UseBuilder::protocol().name("hippo"))
                     .child_default("c")
@@ -2998,7 +3010,7 @@
                         OfferBuilder::protocol()
                             .name("hippo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -3010,13 +3022,13 @@
                         OfferBuilder::protocol()
                             .name("hippo")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("hippo")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .child_default("c")
                     .child_default("d")
@@ -3120,7 +3132,7 @@
                         OfferBuilder::service()
                             .name("foo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .service_default("foo")
                     .child_default("b")
@@ -3231,8 +3243,8 @@
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
-                            .source(OfferSource::static_child("c".parse().unwrap()))
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .source_static_child("c")
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -3302,8 +3314,8 @@
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
-                            .source(OfferSource::static_child("c".parse().unwrap()))
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .source_static_child("c")
+                            .target_static_child("b")
                             .source_instance_filter(source_instance_filter)
                             .renamed_instances(renamed_instances),
                     )
@@ -3398,8 +3410,8 @@
                     .offer(
                         OfferBuilder::service()
                             .name("foo")
-                            .source(OfferSource::static_child("c".parse().unwrap()))
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .source_static_child("c")
+                            .target_static_child("b")
                             .source_instance_filter(source_instance_filter)
                             .renamed_instances(renamed_instances),
                     )
@@ -3556,7 +3568,7 @@
                             .name("elf")
                             .target_name("dwarf")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .runner_default("elf")
                     .build(),
@@ -4101,7 +4113,7 @@
                             .name("elf")
                             .target_name("dwarf")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .runner_default("elf")
                     .child_default("b")
@@ -4292,7 +4304,7 @@
                             .name("fuchsia.MyConfig")
                             .source(cm_rust::OfferSource::Self_)
                             .target(cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                                name: "b".into(),
+                                name: "b".parse().unwrap(),
                                 collection: None,
                             })),
                     )
@@ -4349,7 +4361,7 @@
                             .source(cm_rust::OfferSource::Void)
                             .availability(cm_rust::Availability::Optional)
                             .target(cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                                name: "b".into(),
+                                name: "b".parse().unwrap(),
                                 collection: None,
                             })),
                     )
diff --git a/src/sys/lib/routing/testing/src/policy.rs b/src/sys/lib/routing/testing/src/policy.rs
index 35f7e7d..663244f 100644
--- a/src/sys/lib/routing/testing/src/policy.rs
+++ b/src/sys/lib/routing/testing/src/policy.rs
@@ -5,6 +5,7 @@
 use {
     anyhow::Error,
     assert_matches::assert_matches,
+    async_trait::async_trait,
     cm_config::{
         AllowlistEntry, AllowlistEntryBuilder, CapabilityAllowlistKey, CapabilityAllowlistSource,
         ChildPolicyAllowlists, DebugCapabilityAllowlistEntry, DebugCapabilityKey,
@@ -52,24 +53,24 @@
         instantiate_global_policy_checker_tests! { $fixture_impl, $($remaining),+ }
     };
     ($fixture_impl:path, $test:ident) => {
-        #[test]
         fn $test() -> Result<(), Error> {
-            let _executor = fuchsia_async::LocalExecutor::new();
-            <$fixture_impl as Default>::default().$test()
+            let mut executor = fuchsia_async::LocalExecutor::new();
+            executor.run_singlethreaded(<$fixture_impl as Default>::default().$test())
         }
     };
 }
 
 // Tests `GlobalPolicyChecker` for implementations of `ComponentInstanceInterface`.
+#[async_trait]
 pub trait GlobalPolicyCheckerTest<C>
 where
     C: ComponentInstanceInterface,
 {
     // Creates a `ComponentInstanceInterface` with the given `InstancedMoniker`.
-    fn make_component(&self, instanced_moniker: InstancedMoniker) -> Arc<C>;
+    async fn make_component(&self, instanced_moniker: InstancedMoniker) -> Arc<C>;
 
     // Tests `GlobalPolicyChecker::can_route_capability()` for framework capability sources.
-    fn global_policy_checker_can_route_capability_framework_cap(&self) -> Result<(), Error> {
+    async fn global_policy_checker_can_route_capability_framework_cap(&self) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
         policy_builder.add_capability_policy(
             CapabilityAllowlistKey {
@@ -86,7 +87,7 @@
             ],
         );
         let global_policy_checker = GlobalPolicyChecker::new(Arc::new(policy_builder.build()));
-        let component = self.make_component(vec!["foo:0", "bar:0"].try_into().unwrap());
+        let component = self.make_component(vec!["foo:0", "bar:0"].try_into().unwrap()).await;
 
         let protocol_capability = CapabilitySource::<C>::Framework {
             capability: InternalCapability::Protocol("fuchsia.component.Realm".parse().unwrap()),
@@ -117,7 +118,7 @@
     }
 
     // Tests `GlobalPolicyChecker::can_route_capability()` for namespace capability sources.
-    fn global_policy_checker_can_route_capability_namespace_cap(&self) -> Result<(), Error> {
+    async fn global_policy_checker_can_route_capability_namespace_cap(&self) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
         policy_builder.add_capability_policy(
             CapabilityAllowlistKey {
@@ -172,7 +173,7 @@
     }
 
     // Tests `GlobalPolicyChecker::can_route_capability()` for component capability sources.
-    fn global_policy_checker_can_route_capability_component_cap(&self) -> Result<(), Error> {
+    async fn global_policy_checker_can_route_capability_component_cap(&self) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
         policy_builder.add_capability_policy(
             CapabilityAllowlistKey {
@@ -190,7 +191,7 @@
             ],
         );
         let global_policy_checker = GlobalPolicyChecker::new(Arc::new(policy_builder.build()));
-        let component = self.make_component(vec!["foo:0"].try_into().unwrap());
+        let component = self.make_component(vec!["foo:0"].try_into().unwrap()).await;
 
         let protocol_capability = CapabilitySource::<C>::Component {
             capability: ComponentCapability::Protocol(ProtocolDecl {
@@ -225,7 +226,7 @@
     }
 
     // Tests `GlobalPolicyChecker::can_route_capability()` for capability sources of type `Capability`.
-    fn global_policy_checker_can_route_capability_capability_cap(&self) -> Result<(), Error> {
+    async fn global_policy_checker_can_route_capability_capability_cap(&self) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
         policy_builder.add_capability_policy(
             CapabilityAllowlistKey {
@@ -243,7 +244,7 @@
             ],
         );
         let global_policy_checker = GlobalPolicyChecker::new(Arc::new(policy_builder.build()));
-        let component = self.make_component(vec!["foo:0"].try_into().unwrap());
+        let component = self.make_component(vec!["foo:0"].try_into().unwrap()).await;
 
         let protocol_capability = CapabilitySource::<C>::Capability {
             source_capability: ComponentCapability::Storage(StorageDecl {
@@ -280,7 +281,9 @@
     }
 
     // Tests `GlobalPolicyChecker::can_route_debug_capability()` for capability sources of type `Capability`.
-    fn global_policy_checker_can_route_debug_capability_capability_cap(&self) -> Result<(), Error> {
+    async fn global_policy_checker_can_route_debug_capability_capability_cap(
+        &self,
+    ) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
         policy_builder.add_debug_capability_policy(
             DebugCapabilityKey {
@@ -348,7 +351,7 @@
 
     // Tests `GlobalPolicyChecker::can_route_debug_capability()` for capability sources of type
     // `Capability` with realm allowlist entries.
-    fn global_policy_checker_can_route_debug_capability_with_realm_allowlist_entry(
+    async fn global_policy_checker_can_route_debug_capability_with_realm_allowlist_entry(
         &self,
     ) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
@@ -431,7 +434,7 @@
 
     // Tests `GlobalPolicyChecker::can_route_debug_capability()` for capability sources of type
     // `Capability` with collection allowlist entries.
-    fn global_policy_checker_can_route_debug_capability_with_collection_allowlist_entry(
+    async fn global_policy_checker_can_route_debug_capability_with_collection_allowlist_entry(
         &self,
     ) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
@@ -521,7 +524,7 @@
     }
 
     // Tests `GlobalPolicyChecker::can_route_capability()` for builtin capabilities.
-    fn global_policy_checker_can_route_capability_builtin_cap(&self) -> Result<(), Error> {
+    async fn global_policy_checker_can_route_capability_builtin_cap(&self) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
         policy_builder.add_capability_policy(
             CapabilityAllowlistKey {
@@ -567,7 +570,7 @@
 
     // Tests `GlobalPolicyChecker::can_route_capability()` for policy that includes non-exact
     // `AllowlistEntry::Realm` entries.
-    fn global_policy_checker_can_route_capability_with_realm_allowlist_entry(
+    async fn global_policy_checker_can_route_capability_with_realm_allowlist_entry(
         &self,
     ) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
@@ -616,7 +619,7 @@
 
     // Tests `GlobalPolicyChecker::can_route_capability()` for policy that includes non-exact
     // `AllowlistEntry::Collection` entries.
-    fn global_policy_checker_can_route_capability_with_collection_allowlist_entry(
+    async fn global_policy_checker_can_route_capability_with_collection_allowlist_entry(
         &self,
     ) -> Result<(), Error> {
         let mut policy_builder = CapabilityAllowlistPolicyBuilder::new();
diff --git a/src/sys/lib/routing/testing/src/rights.rs b/src/sys/lib/routing/testing/src/rights.rs
index cb00c40..e1d6c48 100644
--- a/src/sys/lib/routing/testing/src/rights.rs
+++ b/src/sys/lib/routing/testing/src/rights.rs
@@ -28,8 +28,8 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("baz_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::RW_STAR_DIR),
                     )
                     .child_default("b")
@@ -79,8 +79,8 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("baz_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::W_STAR_DIR),
                     )
                     .child_default("b")
@@ -130,8 +130,8 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("baz_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .child_default("b")
@@ -181,8 +181,8 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("baz_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::RW_STAR_DIR),
                     )
                     .child_default("b")
@@ -232,8 +232,8 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("baz_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::R_STAR_DIR),
                     )
                     .child_default("b")
@@ -283,8 +283,8 @@
                         OfferBuilder::directory()
                             .name("bar_data")
                             .target_name("baz_data")
-                            .source(OfferSource::static_child("b".to_string()))
-                            .target(OfferTarget::static_child("c".to_string()))
+                            .source_static_child("b")
+                            .target_static_child("c")
                             .rights(fio::RW_STAR_DIR),
                     )
                     .child_default("b")
@@ -343,7 +343,7 @@
                             .name("foo_data")
                             .target_name("bar_data")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
diff --git a/src/sys/lib/routing/testing/src/storage.rs b/src/sys/lib/routing/testing/src/storage.rs
index e4cf5fc..1f91ff3b 100644
--- a/src/sys/lib/routing/testing/src/storage.rs
+++ b/src/sys/lib/routing/testing/src/storage.rs
@@ -44,7 +44,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .capability(
@@ -110,7 +110,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .capability(
@@ -167,7 +167,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .capability(
@@ -220,7 +220,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .capability(
@@ -279,7 +279,7 @@
                             .name("data")
                             .target_name("minfs")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::RW_STAR_DIR),
                     )
                     .child_default("b")
@@ -292,7 +292,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .capability(
@@ -352,7 +352,7 @@
                             .name("data")
                             .target_name("minfs")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::RW_STAR_DIR)
                             .subdir("subdir_1"),
                     )
@@ -366,7 +366,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .capability(
@@ -434,7 +434,7 @@
                             .name("data")
                             .target_name("minfs")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::RW_STAR_DIR),
                     )
                     .child_default("b")
@@ -447,7 +447,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .capability(
@@ -507,7 +507,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .capability(
@@ -525,7 +525,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .build(),
@@ -575,7 +575,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -646,7 +646,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -734,13 +734,13 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .offer(
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -771,13 +771,13 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .offer(
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .use_(UseBuilder::storage().name("data").path("/storage"))
                     .use_(UseBuilder::storage().name("cache").path("/cache"))
@@ -866,7 +866,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .capability(
@@ -920,7 +920,7 @@
                         OfferBuilder::directory()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::RW_STAR_DIR),
                     )
                     .child_default("b")
@@ -1023,7 +1023,7 @@
                             .name("data")
                             .target_name("minfs")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::RW_STAR_DIR),
                     )
                     .child_default("b")
@@ -1036,7 +1036,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .capability(
@@ -1088,7 +1088,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .capability(
@@ -1171,7 +1171,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .capability(
@@ -1190,7 +1190,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .build(),
diff --git a/src/sys/lib/routing/testing/src/storage_admin.rs b/src/sys/lib/routing/testing/src/storage_admin.rs
index 8450719..9d9808b 100644
--- a/src/sys/lib/routing/testing/src/storage_admin.rs
+++ b/src/sys/lib/routing/testing/src/storage_admin.rs
@@ -51,13 +51,13 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .offer(
                         OfferBuilder::protocol()
                             .name("fuchsia.sys2.StorageAdmin")
                             .source(OfferSource::Capability("data".parse().unwrap()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -116,7 +116,7 @@
                         OfferBuilder::directory()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string()))
+                            .target_static_child("b")
                             .rights(fio::RW_STAR_DIR)
                             .subdir("foo"),
                     )
@@ -137,7 +137,7 @@
                         OfferBuilder::protocol()
                             .name("fuchsia.sys2.StorageAdmin")
                             .source(OfferSource::Capability("storage".parse().unwrap()))
-                            .target(OfferTarget::static_child("c".to_string())),
+                            .target_static_child("c"),
                     )
                     .child_default("c")
                     .build(),
@@ -183,8 +183,8 @@
                     .offer(
                         OfferBuilder::protocol()
                             .name("fuchsia.sys2.StorageAdmin")
-                            .source(OfferSource::static_child("c".to_string()))
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .source_static_child("c")
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -215,7 +215,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .expose(
                         ExposeBuilder::protocol()
@@ -274,7 +274,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .use_(
                         UseBuilder::protocol()
@@ -338,7 +338,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .use_(
                         UseBuilder::protocol()
@@ -401,7 +401,7 @@
                         OfferBuilder::protocol()
                             .name("fuchsia.sys2.StorageAdmin")
                             .source(OfferSource::Capability("unrelated.protocol".parse().unwrap()))
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -448,8 +448,8 @@
                     .offer(
                         OfferBuilder::protocol()
                             .name("fuchsia.sys2.StorageAdmin")
-                            .source(OfferSource::static_child("c".to_string()))
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .source_static_child("c")
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -483,7 +483,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .expose(
                         ExposeBuilder::protocol().name("fuchsia.sys2.StorageAdmin").source(
@@ -546,7 +546,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .use_(
                         UseBuilder::protocol()
@@ -607,7 +607,7 @@
                             .name("unrelated.protocol")
                             .target_name("fuchsia.sys2.StorageAdmin")
                             .source(OfferSource::Capability("data".parse().unwrap()))
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .build(),
@@ -653,8 +653,8 @@
                     .offer(
                         OfferBuilder::protocol()
                             .name("fuchsia.sys2.StorageAdmin")
-                            .source(OfferSource::static_child("c".to_string()))
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .source_static_child("c")
+                            .target_static_child("b"),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -685,7 +685,7 @@
                         OfferBuilder::storage()
                             .name("data")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("d".to_string())),
+                            .target_static_child("d"),
                     )
                     .expose(
                         ExposeBuilder::protocol()
diff --git a/src/sys/pkg/bin/package-tool/package-tool.gni b/src/sys/pkg/bin/package-tool/package-tool.gni
index 2db9a97..b92ccb8 100644
--- a/src/sys/pkg/bin/package-tool/package-tool.gni
+++ b/src/sys/pkg/bin/package-tool/package-tool.gni
@@ -450,7 +450,12 @@
   } else {
     archive_name = package_name
   }
+
+  # LINT.IfChange
   archive_out = "${target_out_dir}/${archive_name}.far"
+
+  # LINT.ThenChange(//build/packages/exported_fuchsia_package_archive.gni)
+
   archive_depfile = "${archive_out}.d"
 
   compiled_action(target_name) {
diff --git a/src/sys/pkg/bin/pkg-cache/src/compat/pkgfs/validation.rs b/src/sys/pkg/bin/pkg-cache/src/compat/pkgfs/validation.rs
index 5ceb0aa..5803142 100644
--- a/src/sys/pkg/bin/pkg-cache/src/compat/pkgfs/validation.rs
+++ b/src/sys/pkg/bin/pkg-cache/src/compat/pkgfs/validation.rs
@@ -493,7 +493,7 @@
     #[fuchsia_async::run_singlethreaded(test)]
     async fn make_missing_contents_irrelevant_blobfs_blob() {
         let blob = vec![0u8, 1u8];
-        let hash = fuchsia_merkle::MerkleTree::from_reader(blob.as_slice()).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(&blob).root();
         let (_env, validation) =
             TestEnv::with_base_blobs_and_blobfs_contents(HashSet::new(), [(hash, blob)]).await;
 
@@ -503,7 +503,7 @@
     #[fuchsia_async::run_singlethreaded(test)]
     async fn make_missing_contents_present_blob() {
         let blob = vec![0u8, 1u8];
-        let hash = fuchsia_merkle::MerkleTree::from_reader(blob.as_slice()).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(&blob).root();
         let (_env, validation) =
             TestEnv::with_base_blobs_and_blobfs_contents(HashSet::from([hash]), [(hash, blob)])
                 .await;
@@ -514,7 +514,7 @@
     #[fuchsia_async::run_singlethreaded(test)]
     async fn make_missing_contents_present_blob_missing_blob() {
         let blob = vec![0u8, 1u8];
-        let hash = fuchsia_merkle::MerkleTree::from_reader(blob.as_slice()).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(&blob).root();
         let mut missing_hash = <[u8; 32]>::from(hash);
         missing_hash[0] = !missing_hash[0];
         let missing_hash = missing_hash.into();
diff --git a/src/sys/pkg/lib/blobfs/src/lib.rs b/src/sys/pkg/lib/blobfs/src/lib.rs
index ee981e6..3794360 100644
--- a/src/sys/pkg/lib/blobfs/src/lib.rs
+++ b/src/sys/pkg/lib/blobfs/src/lib.rs
@@ -561,8 +561,8 @@
 mod tests {
     use {
         super::*, assert_matches::assert_matches, blobfs_ramdisk::BlobfsRamdisk,
-        fuchsia_async as fasync, fuchsia_merkle::MerkleTree, futures::stream::TryStreamExt,
-        maplit::hashset, std::io::Write as _, std::sync::Arc,
+        fuchsia_async as fasync, futures::stream::TryStreamExt, maplit::hashset,
+        std::io::Write as _, std::sync::Arc,
     };
 
     #[fasync::run_singlethreaded(test)]
@@ -599,10 +599,10 @@
             .unwrap();
         let client = Client::for_ramdisk(&blobfs);
 
-        let merkle = MerkleTree::from_reader(&b"blob 1"[..]).unwrap().root();
+        let merkle = fuchsia_merkle::from_slice(&b"blob 1"[..]).root();
         assert_matches!(client.delete_blob(&merkle).await, Ok(()));
 
-        let expected = hashset! {MerkleTree::from_reader(&b"blob 2"[..]).unwrap().root()};
+        let expected = hashset! {fuchsia_merkle::from_slice(&b"blob 2"[..]).root()};
         assert_eq!(client.list_known_blobs().await.unwrap(), expected);
         blobfs.stop().await.unwrap();
     }
@@ -643,10 +643,7 @@
         let blobfs = BlobfsRamdisk::builder().with_blob(&b"blob 1"[..]).start().await.unwrap();
         let client = Client::for_ramdisk(&blobfs);
 
-        assert_eq!(
-            client.has_blob(&MerkleTree::from_reader(&b"blob 1"[..]).unwrap().root()).await,
-            true
-        );
+        assert_eq!(client.has_blob(&fuchsia_merkle::from_slice(&b"blob 1"[..]).root()).await, true);
         assert_eq!(client.has_blob(&Hash::from([1; 32])).await, false);
 
         blobfs.stop().await.unwrap();
@@ -658,7 +655,7 @@
             BlobfsRamdisk::builder().fxblob().with_blob(&b"blob 1"[..]).start().await.unwrap();
         let client = Client::for_ramdisk(&blobfs);
 
-        assert!(client.has_blob(&MerkleTree::from_reader(&b"blob 1"[..]).unwrap().root()).await);
+        assert!(client.has_blob(&fuchsia_merkle::from_slice(&b"blob 1"[..]).root()).await);
         assert!(!client.has_blob(&Hash::from([1; 32])).await);
 
         blobfs.stop().await.unwrap();
@@ -670,7 +667,7 @@
         let client = Client::for_ramdisk(&blobfs);
 
         let blob = [3; 1024];
-        let hash = MerkleTree::from_reader(&blob[..]).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(&blob).root();
 
         let mut file = blobfs.root_dir().unwrap().write_file(hash.to_string(), 0o777).unwrap();
         assert_eq!(client.has_blob(&hash).await, false);
@@ -701,7 +698,7 @@
         let client = Client::for_ramdisk(&blobfs);
 
         let content = [3; 1024];
-        let hash = MerkleTree::from_reader(&content[..]).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(&content).root();
         let delivery_content =
             delivery_blob::Type1Blob::generate(&content, delivery_blob::CompressionMode::Always);
 
@@ -724,20 +721,20 @@
     }
 
     async fn open_blob_only(client: &Client, content: &[u8]) -> TestBlob {
-        let hash = MerkleTree::from_reader(content).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(content).root();
         let _blob = client.open_blob_proxy_from_dir_for_write(&hash).await.unwrap();
         TestBlob { _blob, hash }
     }
 
     async fn open_and_truncate_blob(client: &Client, content: &[u8]) -> TestBlob {
-        let hash = MerkleTree::from_reader(content).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(content).root();
         let _blob = client.open_blob_proxy_from_dir_for_write(&hash).await.unwrap();
         let () = resize(&_blob, content.len()).await;
         TestBlob { _blob, hash }
     }
 
     async fn partially_write_blob(client: &Client, content: &[u8]) -> TestBlob {
-        let hash = MerkleTree::from_reader(content).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(content).root();
         let _blob = client.open_blob_proxy_from_dir_for_write(&hash).await.unwrap();
         let content = delivery_blob::generate(delivery_blob::DeliveryBlobType::Type1, content);
         let () = resize(&_blob, content.len()).await;
@@ -746,7 +743,7 @@
     }
 
     async fn fully_write_blob(client: &Client, content: &[u8]) -> TestBlob {
-        let hash = MerkleTree::from_reader(content).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(content).root();
         let _blob = client.open_blob_proxy_from_dir_for_write(&hash).await.unwrap();
         let content = delivery_blob::generate(delivery_blob::DeliveryBlobType::Type1, content);
         let () = resize(&_blob, content.len()).await;
diff --git a/src/sys/pkg/lib/fuchsia-merkle/src/lib.rs b/src/sys/pkg/lib/fuchsia-merkle/src/lib.rs
index abbc5c3..7a6e16f5 100644
--- a/src/sys/pkg/lib/fuchsia-merkle/src/lib.rs
+++ b/src/sys/pkg/lib/fuchsia-merkle/src/lib.rs
@@ -40,18 +40,7 @@
 where
     R: Read,
 {
-    let mut buf = [0; BLOCK_SIZE];
-    let mut builder = MerkleTreeBuilder::new();
-
-    loop {
-        let len = reader.read(&mut buf)?;
-        if len == 0 {
-            break;
-        }
-        builder.write(&buf[0..len]);
-    }
-
-    Ok(builder.finish())
+    MerkleTree::from_reader(reader)
 }
 
 /// Compute a merkle tree from a `futures::io::AsyncRead`.
diff --git a/src/sys/pkg/lib/fuchsia-pkg-testing/src/repo.rs b/src/sys/pkg/lib/fuchsia-pkg-testing/src/repo.rs
index 32f8286..2a71685 100644
--- a/src/sys/pkg/lib/fuchsia-pkg-testing/src/repo.rs
+++ b/src/sys/pkg/lib/fuchsia-pkg-testing/src/repo.rs
@@ -344,7 +344,7 @@
 #[cfg(test)]
 mod tests {
 
-    use {super::*, crate::package::PackageBuilder, fuchsia_merkle::MerkleTree};
+    use {super::*, crate::package::PackageBuilder};
 
     #[fuchsia_async::run_singlethreaded(test)]
     async fn test_repo_builder() {
@@ -388,7 +388,7 @@
         assert_eq!(blobs.len(), 5);
 
         // Spot check the contents of a blob in the repo.
-        let same_contents_merkle = MerkleTree::from_reader(&same_contents[..]).unwrap().root();
+        let same_contents_merkle = fuchsia_merkle::from_slice(&same_contents[..]).root();
         assert_eq!(repo.read_blob(&same_contents_merkle).unwrap(), same_contents);
         assert_eq!(
             repo.read_delivery_blob(1, &same_contents_merkle).unwrap(),
diff --git a/src/sys/pkg/lib/fuchsia-pkg/src/package_builder.rs b/src/sys/pkg/lib/fuchsia-pkg/src/package_builder.rs
index 47b3e59..c4b3942 100644
--- a/src/sys/pkg/lib/fuchsia-pkg/src/package_builder.rs
+++ b/src/sys/pkg/lib/fuchsia-pkg/src/package_builder.rs
@@ -635,7 +635,7 @@
 
 #[cfg(test)]
 mod tests {
-    use {super::*, camino::Utf8Path, fuchsia_merkle::MerkleTreeBuilder, tempfile::TempDir};
+    use {super::*, camino::Utf8Path, tempfile::TempDir};
 
     const FAKE_ABI_REVISION: AbiRevision = AbiRevision::from_u64(0x5836508c2defac54);
 
@@ -668,9 +668,7 @@
         std::fs::write(&blob_source_file_path, blob_contents).unwrap();
 
         // Pre-calculate the blob's hash
-        let mut merkle_builder = MerkleTreeBuilder::new();
-        merkle_builder.write(blob_contents.as_bytes());
-        let blob_hash = merkle_builder.finish().root();
+        let blob_hash = fuchsia_merkle::from_slice(blob_contents.as_bytes()).root();
 
         let subpackage_url = "subpackage0".parse::<RelativePackageUrl>().unwrap();
         let subpackage_hash = Hash::from([0; fuchsia_hash::HASH_SIZE]);
diff --git a/src/sys/pkg/lib/fuchsia-pkg/src/package_directory.rs b/src/sys/pkg/lib/fuchsia-pkg/src/package_directory.rs
index 8c5ab1e..8edd0a7 100644
--- a/src/sys/pkg/lib/fuchsia-pkg/src/package_directory.rs
+++ b/src/sys/pkg/lib/fuchsia-pkg/src/package_directory.rs
@@ -250,8 +250,7 @@
         assert!(!blobs.is_empty());
 
         // the test duplicate blob appears twice
-        let duplicate_blob_merkle =
-            fuchsia_merkle::MerkleTree::from_reader("Hello World!".as_bytes()).unwrap().root();
+        let duplicate_blob_merkle = fuchsia_merkle::from_slice("Hello World!".as_bytes()).root();
         assert_eq!(blobs.iter().filter(|hash| *hash == &duplicate_blob_merkle).count(), 2);
     }
 
diff --git a/src/sys/pkg/lib/fuchsia-repo/src/repo_client.rs b/src/sys/pkg/lib/fuchsia-repo/src/repo_client.rs
index 55d6ff6..29c2347 100644
--- a/src/sys/pkg/lib/fuchsia-repo/src/repo_client.rs
+++ b/src/sys/pkg/lib/fuchsia-repo/src/repo_client.rs
@@ -165,6 +165,45 @@
         self.tuf_client.remote_repo().fetch_blob_range(path, range).await
     }
 
+    pub fn delivery_blob_path(&self, hash: &Hash) -> String {
+        format!("{}/{hash}", u32::from(self.blob_type()))
+    }
+
+    /// Return a Vec of the blob decompressed.
+    pub async fn read_blob_decompressed(&self, hash: &Hash) -> Result<Vec<u8>> {
+        let path = self.delivery_blob_path(hash);
+        let mut delivery_blob = vec![];
+        self.fetch_blob(&path)
+            .await
+            .with_context(|| format!("fetching blob {path}"))?
+            .read_to_end(&mut delivery_blob)
+            .await
+            .with_context(|| format!("reading blob {path}"))?;
+        delivery_blob::decompress(&delivery_blob)
+            .with_context(|| format!("decompressing blob {path}"))
+    }
+
+    async fn blob_decompressed_size(&self, hash: &Hash) -> Result<u64> {
+        let path = self.delivery_blob_path(hash);
+        let mut delivery_blob = vec![];
+        let mut blob_resource =
+            self.fetch_blob(&path).await.with_context(|| format!("fetching blob {path}"))?;
+
+        while let Some(chunk) = blob_resource.stream.try_next().await? {
+            delivery_blob.extend_from_slice(&chunk);
+            match delivery_blob::decompressed_size(&delivery_blob) {
+                Ok(len) => {
+                    return Ok(len);
+                }
+                Err(delivery_blob::DecompressError::NeedMoreData) => {}
+                Err(e) => {
+                    return Err(e).with_context(|| format!("parsing delivery blob {path}"));
+                }
+            }
+        }
+        Err(anyhow!("blob {path} too small"))
+    }
+
     /// Return the target description for a TUF target path.
     pub async fn get_target_description(
         &self,
@@ -300,14 +339,8 @@
     ) -> BoxFuture<'a, Result<Vec<PackageEntry>>> {
         async move {
             // Read the meta.far.
-            let hash_str = hash.to_string();
-            let mut meta_far_bytes = vec![];
-            self.fetch_blob(&hash_str)
-                .await
-                .with_context(|| format!("fetching blob {hash}"))?
-                .read_to_end(&mut meta_far_bytes)
-                .await
-                .with_context(|| format!("reading blob {hash}"))?;
+            let meta_far_bytes =
+                self.read_blob_decompressed(hash).await.context("reading meta.far")?;
             let size: u64 = meta_far_bytes.len().try_into()?;
 
             let mut archive =
@@ -317,7 +350,7 @@
             let modified = self
                 .tuf_client
                 .remote_repo()
-                .blob_modification_time(&hash_str)
+                .blob_modification_time(&self.delivery_blob_path(hash))
                 .await?
                 .map(|x| -> anyhow::Result<u64> {
                     Ok(x.duration_since(SystemTime::UNIX_EPOCH)?.as_secs())
@@ -351,17 +384,12 @@
                         .contents()
                         .iter()
                         .map(|(name, hash)| async move {
-                            let hash_str = hash.to_string();
-                            let blob_size = self
-                                .tuf_client
-                                .remote_repo()
-                                .blob_len(&hash_str)
-                                .await
-                                .with_context(|| format!("fetching length of blob {hash}"))?;
+                            let blob_size =
+                                self.blob_decompressed_size(hash).await.with_context(|| {
+                                    format!("getting decompressed size of blob {hash}")
+                                })?;
                             let modified = self
-                                .tuf_client
-                                .remote_repo()
-                                .blob_modification_time(&hash_str)
+                                .blob_modification_time(&self.delivery_blob_path(hash))
                                 .await?
                                 .map(|x| -> anyhow::Result<u64> {
                                     Ok(x.duration_since(SystemTime::UNIX_EPOCH)?.as_secs())
@@ -510,10 +538,6 @@
         self.tuf_client.remote_repo().watch()
     }
 
-    fn blob_len<'a>(&'a self, path: &str) -> BoxFuture<'a, Result<u64>> {
-        self.tuf_client.remote_repo().blob_len(path)
-    }
-
     fn blob_modification_time<'a>(
         &'a self,
         path: &str,
@@ -692,8 +716,8 @@
         repo.update().await.unwrap();
 
         // Look up the timestamp for the meta.far for the modified setting.
-        let pkg1_modified = get_modtime(dir.join("repository").join("blobs").join(PKG1_HASH));
-        let pkg2_modified = get_modtime(dir.join("repository").join("blobs").join(PKG2_HASH));
+        let pkg1_modified = get_modtime(dir.join("repository/blobs/1").join(PKG1_HASH));
+        let pkg2_modified = get_modtime(dir.join("repository/blobs/1").join(PKG2_HASH));
 
         let mut packages = repo.list_packages().await.unwrap();
 
@@ -772,7 +796,7 @@
         repo.update().await.unwrap();
 
         // Look up the timestamps for the blobs.
-        let blob_dir = dir.join("repository").join("blobs");
+        let blob_dir = dir.join("repository/blobs/1");
         let meta_far_modified = get_modtime(blob_dir.join(PKG1_HASH));
 
         let bin_modified = get_modtime(blob_dir.join(PKG1_BIN_HASH));
diff --git a/src/sys/pkg/lib/fuchsia-repo/src/repository.rs b/src/sys/pkg/lib/fuchsia-repo/src/repository.rs
index b301235..41cfd34 100644
--- a/src/sys/pkg/lib/fuchsia-repo/src/repository.rs
+++ b/src/sys/pkg/lib/fuchsia-repo/src/repository.rs
@@ -6,6 +6,7 @@
     crate::{range::Range, resource::Resource},
     anyhow::Result,
     camino::{Utf8Path, Utf8PathBuf},
+    delivery_blob::DeliveryBlobType,
     fuchsia_merkle::Hash,
     futures::{future::BoxFuture, stream::BoxStream},
     serde::{Deserialize, Serialize},
@@ -17,7 +18,7 @@
     url::ParseError,
 };
 
-mod file_system;
+pub(crate) mod file_system;
 mod pm;
 
 #[cfg(test)]
@@ -110,14 +111,16 @@
         Err(anyhow::anyhow!("Watching not supported for this repo type"))
     }
 
-    /// Get the length of a blob in this repository.
-    fn blob_len<'a>(&'a self, path: &str) -> BoxFuture<'a, anyhow::Result<u64>>;
-
     /// Get the modification time of a blob in this repository if available.
     fn blob_modification_time<'a>(
         &'a self,
         path: &str,
     ) -> BoxFuture<'a, anyhow::Result<Option<SystemTime>>>;
+
+    /// Get the type of delivery blobs in this repository.
+    fn blob_type(&self) -> DeliveryBlobType {
+        DeliveryBlobType::Type1
+    }
 }
 
 pub trait RepoStorage: TufRepositoryStorage<Pouf1> + Send + Sync {
@@ -173,11 +176,6 @@
                 (**self).watch()
             }
 
-            /// Get the length of a blob in this repository.
-            fn blob_len<'a>(&'a self, path: &str) -> BoxFuture<'a, anyhow::Result<u64>> {
-                (**self).blob_len(path)
-            }
-
             /// Get the modification time of a blob in this repository if available.
             fn blob_modification_time<'a>(
                 &'a self,
@@ -185,6 +183,11 @@
             ) -> BoxFuture<'a, anyhow::Result<Option<SystemTime>>> {
                 (**self).blob_modification_time(path)
             }
+
+            /// Get the type of delivery blobs in this repository.
+            fn blob_type(&self) -> DeliveryBlobType {
+                (**self).blob_type()
+            }
         }
     };
 }
diff --git a/src/sys/pkg/lib/fuchsia-repo/src/repository/file_system.rs b/src/sys/pkg/lib/fuchsia-repo/src/repository/file_system.rs
index 896cdec..be2f628 100644
--- a/src/sys/pkg/lib/fuchsia-repo/src/repository/file_system.rs
+++ b/src/sys/pkg/lib/fuchsia-repo/src/repository/file_system.rs
@@ -312,15 +312,6 @@
         Ok(WatchStream { _watcher: watcher, receiver }.boxed())
     }
 
-    fn blob_len<'a>(&'a self, path: &str) -> BoxFuture<'a, Result<u64>> {
-        let file_path = sanitize_path(&self.blob_repo_path, path);
-        async move {
-            let file_path = file_path?;
-            Ok(fs::metadata(&file_path)?.len())
-        }
-        .boxed()
-    }
-
     fn blob_modification_time<'a>(
         &'a self,
         path: &str,
@@ -332,6 +323,10 @@
         }
         .boxed()
     }
+
+    fn blob_type(&self) -> DeliveryBlobType {
+        self.delivery_blob_type
+    }
 }
 
 impl TufRepositoryProvider<Pouf1> for FileSystemRepository {
@@ -551,7 +546,7 @@
     set_blob_read_only(dst).await
 }
 
-async fn generate_delivery_blob(
+pub(crate) async fn generate_delivery_blob(
     src: &Utf8Path,
     dst: &Utf8Path,
     blob_type: DeliveryBlobType,
diff --git a/src/sys/pkg/lib/fuchsia-repo/src/repository/gcs_repository.rs b/src/sys/pkg/lib/fuchsia-repo/src/repository/gcs_repository.rs
index f569547..4d58f27 100644
--- a/src/sys/pkg/lib/fuchsia-repo/src/repository/gcs_repository.rs
+++ b/src/sys/pkg/lib/fuchsia-repo/src/repository/gcs_repository.rs
@@ -250,13 +250,6 @@
         self.get(&self.blob_repo_url, resource_path, range)
     }
 
-    fn blob_len<'a>(&'a self, path: &str) -> BoxFuture<'a, Result<u64, anyhow::Error>> {
-        // FIXME(https://fxbug.dev/42181387): The gcs library does not expose a more efficient API for
-        // determining the blob size.
-        let fut = self.fetch_blob_range(path, Range::Full);
-        async move { Ok(fut.await?.total_len()) }.boxed()
-    }
-
     fn blob_modification_time<'a>(
         &'a self,
         _path: &str,
diff --git a/src/sys/pkg/lib/fuchsia-repo/src/repository/http_repository.rs b/src/sys/pkg/lib/fuchsia-repo/src/repository/http_repository.rs
index b289fde..ff1bc965 100644
--- a/src/sys/pkg/lib/fuchsia-repo/src/repository/http_repository.rs
+++ b/src/sys/pkg/lib/fuchsia-repo/src/repository/http_repository.rs
@@ -202,14 +202,6 @@
         self.fetch_from(&self.blob_repo_url, resource_path, range)
     }
 
-    fn blob_len<'a>(&'a self, path: &str) -> BoxFuture<'a, Result<u64>> {
-        // FIXME(https://fxbug.dev/42180702): It may be more efficient to try to make a HEAD request and
-        // see if that includes the content length before falling back to us requesting the blob and
-        // dropping the stream.
-        let fut = self.fetch_blob_range(path, Range::Full);
-        async move { Ok(fut.await?.total_len()) }.boxed()
-    }
-
     fn blob_modification_time<'a>(
         &'a self,
         _path: &str,
diff --git a/src/sys/pkg/lib/fuchsia-repo/src/repository/pm.rs b/src/sys/pkg/lib/fuchsia-repo/src/repository/pm.rs
index 2b4fb58..b09daef 100644
--- a/src/sys/pkg/lib/fuchsia-repo/src/repository/pm.rs
+++ b/src/sys/pkg/lib/fuchsia-repo/src/repository/pm.rs
@@ -144,16 +144,16 @@
         self.repo.watch()
     }
 
-    fn blob_len<'a>(&'a self, path: &str) -> BoxFuture<'a, Result<u64>> {
-        self.repo.blob_len(path)
-    }
-
     fn blob_modification_time<'a>(
         &'a self,
         path: &str,
     ) -> BoxFuture<'a, Result<Option<SystemTime>>> {
         self.repo.blob_modification_time(path)
     }
+
+    fn blob_type(&self) -> DeliveryBlobType {
+        self.repo.blob_type()
+    }
 }
 
 impl TufRepositoryProvider<Pouf1> for PmRepository {
diff --git a/src/sys/pkg/lib/fuchsia-repo/src/test_utils.rs b/src/sys/pkg/lib/fuchsia-repo/src/test_utils.rs
index 2387c9b6..9228a03 100644
--- a/src/sys/pkg/lib/fuchsia-repo/src/test_utils.rs
+++ b/src/sys/pkg/lib/fuchsia-repo/src/test_utils.rs
@@ -288,26 +288,6 @@
     let build_tmp = tempfile::tempdir().unwrap();
     let build_path = build_tmp.path();
 
-    let packages = ["package1", "package2"].map(|name| {
-        let (meta_far_path, manifest) = make_package_manifest(name, build_path, Vec::new());
-
-        // Copy the package blobs into the blobs directory.
-        let mut meta_far_merkle = None;
-        for blob in manifest.blobs() {
-            let merkle = blob.merkle.to_string();
-
-            if blob.path == "meta/" {
-                meta_far_merkle = Some(merkle.clone());
-            }
-
-            let mut src = std::fs::File::open(&blob.source_path).unwrap();
-            let mut dst = std::fs::File::create(blobs_dir.join(merkle)).unwrap();
-            std::io::copy(&mut src, &mut dst).unwrap();
-        }
-
-        (name, meta_far_path, meta_far_merkle.unwrap())
-    });
-
     // Write TUF metadata
     let repo =
         FileSystemRepositoryBuilder::<Pouf1>::new(metadata_dir).targets_prefix("targets").build();
@@ -327,12 +307,39 @@
         .unwrap();
 
     // Add all the packages to the metadata.
-    for (name, meta_far_path, meta_far_merkle) in packages {
+    for name in ["package1", "package2"] {
+        let (meta_far_path, manifest) = make_package_manifest(name, build_path, Vec::new());
+
+        // Copy the package blobs into the blobs directory.
+        let mut meta_far_merkle = None;
+        for blob in manifest.blobs() {
+            let merkle = blob.merkle.to_string();
+
+            if blob.path == "meta/" {
+                meta_far_merkle = Some(merkle.clone());
+            }
+
+            let mut src = std::fs::File::open(&blob.source_path).unwrap();
+            let mut dst = std::fs::File::create(blobs_dir.join(&merkle)).unwrap();
+            std::io::copy(&mut src, &mut dst).unwrap();
+
+            let blob_type = delivery_blob::DeliveryBlobType::Type1;
+            crate::repository::file_system::generate_delivery_blob(
+                blob.source_path.as_str().into(),
+                &Utf8PathBuf::from_path_buf(
+                    blobs_dir.join(format!("{}/{merkle}", u32::from(blob_type))),
+                )
+                .unwrap(),
+                blob_type,
+            )
+            .await
+            .unwrap();
+        }
         builder = builder
             .add_target_with_custom(
                 TargetPath::new(format!("{name}/0")).unwrap(),
                 AllowStdIo::new(File::open(meta_far_path).unwrap()),
-                hashmap! { "merkle".into() => meta_far_merkle.into() },
+                hashmap! { "merkle".into() => meta_far_merkle.unwrap().into() },
             )
             .await
             .unwrap();
diff --git a/src/sys/pkg/lib/package-directory/src/meta_as_dir.rs b/src/sys/pkg/lib/package-directory/src/meta_as_dir.rs
index 34b6844..55c1539 100644
--- a/src/sys/pkg/lib/package-directory/src/meta_as_dir.rs
+++ b/src/sys/pkg/lib/package-directory/src/meta_as_dir.rs
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 use {
-    crate::{meta_file::MetaFile, meta_subdir::MetaSubdir, root_dir::RootDir, usize_to_u64_safe},
+    crate::{root_dir::RootDir, usize_to_u64_safe},
     async_trait::async_trait,
     fidl::endpoints::ServerEnd,
     fidl_fuchsia_io as fio, fuchsia_zircon as zx,
@@ -123,29 +123,16 @@
         let file_path =
             format!("meta/{}", path.as_ref().strip_suffix('/').unwrap_or_else(|| path.as_ref()));
 
-        if let Some(location) = self.root_dir.meta_files.get(&file_path).copied() {
-            flags.to_object_request(server_end).handle(|object_request| {
-                vfs::file::serve(
-                    MetaFile::new(self.root_dir.clone(), location),
-                    scope,
-                    &flags,
-                    object_request,
-                )
-            });
+        if let Some(file) = self.root_dir.get_meta_file(&file_path) {
+            flags
+                .to_object_request(server_end)
+                .handle(|object_request| vfs::file::serve(file, scope, &flags, object_request));
             return;
         }
 
-        let directory_path = file_path + "/";
-        for k in self.root_dir.meta_files.keys() {
-            if k.starts_with(&directory_path) {
-                let () = MetaSubdir::new(self.root_dir.clone(), directory_path).open(
-                    scope,
-                    flags,
-                    VfsPath::dot(),
-                    server_end,
-                );
-                return;
-            }
+        if let Some(subdir) = self.root_dir.get_meta_subdir(file_path + "/") {
+            let () = subdir.open(scope, flags, VfsPath::dot(), server_end);
+            return;
         }
 
         let () = send_on_open_with_error(describe, server_end, zx::Status::NOT_FOUND);
@@ -199,28 +186,12 @@
         let file_path =
             format!("meta/{}", path.as_ref().strip_suffix('/').unwrap_or_else(|| path.as_ref()));
 
-        if let Some(location) = self.root_dir.meta_files.get(&file_path).copied() {
-            return vfs::file::serve(
-                MetaFile::new(self.root_dir.clone(), location),
-                scope,
-                &protocols,
-                object_request,
-            );
+        if let Some(file) = self.root_dir.get_meta_file(&file_path) {
+            return vfs::file::serve(file, scope, &protocols, object_request);
         }
 
-        let directory_path = file_path + "/";
-        for k in self.root_dir.meta_files.keys() {
-            if k.starts_with(&directory_path) {
-                object_request.take().handle(|object_request| {
-                    MetaSubdir::new(self.root_dir.clone(), directory_path).open2(
-                        scope,
-                        VfsPath::dot(),
-                        protocols,
-                        object_request,
-                    )
-                });
-                return Ok(());
-            }
+        if let Some(subdir) = self.root_dir.get_meta_subdir(file_path + "/") {
+            return subdir.open2(scope, VfsPath::dot(), protocols, object_request);
         }
 
         Err(zx::Status::NOT_FOUND)
diff --git a/src/sys/pkg/lib/package-directory/src/meta_subdir.rs b/src/sys/pkg/lib/package-directory/src/meta_subdir.rs
index 4e704e4..248a560 100644
--- a/src/sys/pkg/lib/package-directory/src/meta_subdir.rs
+++ b/src/sys/pkg/lib/package-directory/src/meta_subdir.rs
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 use {
-    crate::{meta_file::MetaFile, root_dir::RootDir},
+    crate::root_dir::RootDir,
     async_trait::async_trait,
     fidl::endpoints::ServerEnd,
     fidl_fuchsia_io as fio, fuchsia_zircon as zx,
@@ -126,29 +126,16 @@
             path.as_ref().strip_suffix('/').unwrap_or_else(|| path.as_ref())
         );
 
-        if let Some(location) = self.root_dir.meta_files.get(&file_path).copied() {
-            flags.to_object_request(server_end).handle(|object_request| {
-                vfs::file::serve(
-                    MetaFile::new(self.root_dir.clone(), location),
-                    scope,
-                    &flags,
-                    object_request,
-                )
-            });
+        if let Some(file) = self.root_dir.get_meta_file(&file_path) {
+            flags
+                .to_object_request(server_end)
+                .handle(|object_request| vfs::file::serve(file, scope, &flags, object_request));
             return;
         }
 
-        let directory_path = file_path + "/";
-        for k in self.root_dir.meta_files.keys() {
-            if k.starts_with(&directory_path) {
-                let () = MetaSubdir::new(self.root_dir.clone(), directory_path).open(
-                    scope,
-                    flags,
-                    VfsPath::dot(),
-                    server_end,
-                );
-                return;
-            }
+        if let Some(subdir) = self.root_dir.get_meta_subdir(file_path + "/") {
+            let () = subdir.open(scope, flags, VfsPath::dot(), server_end);
+            return;
         }
 
         let () = send_on_open_with_error(describe, server_end, zx::Status::NOT_FOUND);
@@ -198,24 +185,12 @@
             path.as_ref().strip_suffix('/').unwrap_or_else(|| path.as_ref())
         );
 
-        if let Some(location) = self.root_dir.meta_files.get(&file_path).copied() {
-            return vfs::file::serve(
-                MetaFile::new(self.root_dir.clone(), location),
-                scope,
-                &protocols,
-                object_request,
-            );
+        if let Some(file) = self.root_dir.get_meta_file(&file_path) {
+            return vfs::file::serve(file, scope, &protocols, object_request);
         }
-        let directory_path = file_path + "/";
-        for k in self.root_dir.meta_files.keys() {
-            if k.starts_with(&directory_path) {
-                return MetaSubdir::new(self.root_dir.clone(), directory_path).open2(
-                    scope,
-                    VfsPath::dot(),
-                    protocols,
-                    object_request,
-                );
-            }
+
+        if let Some(subdir) = self.root_dir.get_meta_subdir(file_path + "/") {
+            return subdir.open2(scope, VfsPath::dot(), protocols, object_request);
         }
 
         Err(zx::Status::NOT_FOUND)
diff --git a/src/sys/pkg/lib/package-directory/src/non_meta_subdir.rs b/src/sys/pkg/lib/package-directory/src/non_meta_subdir.rs
index 73efaea..df1304c 100644
--- a/src/sys/pkg/lib/package-directory/src/non_meta_subdir.rs
+++ b/src/sys/pkg/lib/package-directory/src/non_meta_subdir.rs
@@ -132,17 +132,9 @@
             return;
         }
 
-        let directory_path = file_path + "/";
-        for k in self.root_dir.non_meta_files.keys() {
-            if k.starts_with(&directory_path) {
-                let () = NonMetaSubdir::new(self.root_dir.clone(), directory_path).open(
-                    scope,
-                    flags,
-                    VfsPath::dot(),
-                    server_end,
-                );
-                return;
-            }
+        if let Some(subdir) = self.root_dir.get_non_meta_subdir(file_path + "/") {
+            let () = subdir.open(scope, flags, VfsPath::dot(), server_end);
+            return;
         }
 
         let () = send_on_open_with_error(describe, server_end, zx::Status::NOT_FOUND);
@@ -186,16 +178,8 @@
             return self.root_dir.non_meta_storage.open2(blob, protocols, scope, object_request);
         }
 
-        let directory_path = file_path + "/";
-        for k in self.root_dir.non_meta_files.keys() {
-            if k.starts_with(&directory_path) {
-                return NonMetaSubdir::new(self.root_dir.clone(), directory_path).open2(
-                    scope,
-                    VfsPath::dot(),
-                    protocols,
-                    object_request,
-                );
-            }
+        if let Some(subdir) = self.root_dir.get_non_meta_subdir(file_path + "/") {
+            return subdir.open2(scope, VfsPath::dot(), protocols, object_request);
         }
 
         Err(zx::Status::NOT_FOUND)
diff --git a/src/sys/pkg/lib/package-directory/src/root_dir.rs b/src/sys/pkg/lib/package-directory/src/root_dir.rs
index 8cf6ff9..8fdb972 100644
--- a/src/sys/pkg/lib/package-directory/src/root_dir.rs
+++ b/src/sys/pkg/lib/package-directory/src/root_dir.rs
@@ -232,6 +232,37 @@
             })
             .await
     }
+
+    /// Creates and returns a `MetaFile` if one exists at `path`.
+    pub(crate) fn get_meta_file(self: &Arc<Self>, path: &str) -> Option<Arc<MetaFile<S>>> {
+        let location = self.meta_files.get(path)?;
+        Some(MetaFile::new(self.clone(), *location))
+    }
+
+    /// Creates and returns a `MetaSubdir` if one exists at `path`. `path` must end in '/'.
+    pub(crate) fn get_meta_subdir(self: &Arc<Self>, path: String) -> Option<Arc<MetaSubdir<S>>> {
+        debug_assert!(path.ends_with("/"));
+        for k in self.meta_files.keys() {
+            if k.starts_with(&path) {
+                return Some(MetaSubdir::new(self.clone(), path));
+            }
+        }
+        None
+    }
+
+    /// Creates and returns a `NonMetaSubdir` if one exists at `path`. `path` must end in '/'.
+    pub(crate) fn get_non_meta_subdir(
+        self: &Arc<Self>,
+        path: String,
+    ) -> Option<Arc<NonMetaSubdir<S>>> {
+        debug_assert!(path.ends_with("/"));
+        for k in self.non_meta_files.keys() {
+            if k.starts_with(&path) {
+                return Some(NonMetaSubdir::new(self.clone(), path));
+            }
+        }
+        None
+    }
 }
 
 #[derive(thiserror::Error, Debug)]
@@ -371,24 +402,16 @@
         }
 
         if canonical_path.starts_with("meta/") {
-            if let Some(meta_file) = self.meta_files.get(canonical_path).copied() {
+            if let Some(meta_file) = self.get_meta_file(canonical_path) {
                 flags.to_object_request(server_end).handle(|object_request| {
-                    vfs::file::serve(MetaFile::new(self, meta_file), scope, &flags, object_request)
+                    vfs::file::serve(meta_file, scope, &flags, object_request)
                 });
                 return;
             }
 
-            let subdir_prefix = canonical_path.to_string() + "/";
-            for k in self.meta_files.keys() {
-                if k.starts_with(&subdir_prefix) {
-                    let () = MetaSubdir::new(self, subdir_prefix).open(
-                        scope,
-                        flags,
-                        VfsPath::dot(),
-                        server_end,
-                    );
-                    return;
-                }
+            if let Some(subdir) = self.get_meta_subdir(canonical_path.to_string() + "/") {
+                let () = subdir.open(scope, flags, VfsPath::dot(), server_end);
+                return;
             }
 
             let () = send_on_open_with_error(describe, server_end, zx::Status::NOT_FOUND);
@@ -403,17 +426,9 @@
             return;
         }
 
-        let subdir_prefix = canonical_path.to_string() + "/";
-        for k in self.non_meta_files.keys() {
-            if k.starts_with(&subdir_prefix) {
-                let () = NonMetaSubdir::new(self, subdir_prefix).open(
-                    scope,
-                    flags,
-                    VfsPath::dot(),
-                    server_end,
-                );
-                return;
-            }
+        if let Some(subdir) = self.get_non_meta_subdir(canonical_path.to_string() + "/") {
+            let () = subdir.open(scope, flags, VfsPath::dot(), server_end);
+            return;
         }
 
         let () = send_on_open_with_error(describe, server_end, zx::Status::NOT_FOUND);
@@ -473,25 +488,12 @@
         }
 
         if canonical_path.starts_with("meta/") {
-            if let Some(meta_file) = self.meta_files.get(canonical_path).copied() {
-                return vfs::file::serve(
-                    MetaFile::new(self, meta_file),
-                    scope,
-                    &protocols,
-                    object_request,
-                );
+            if let Some(file) = self.get_meta_file(canonical_path) {
+                return vfs::file::serve(file, scope, &protocols, object_request);
             }
 
-            let subdir_prefix = canonical_path.to_string() + "/";
-            for k in self.meta_files.keys() {
-                if k.starts_with(&subdir_prefix) {
-                    return MetaSubdir::new(self, subdir_prefix).open2(
-                        scope,
-                        VfsPath::dot(),
-                        protocols,
-                        object_request,
-                    );
-                }
+            if let Some(subdir) = self.get_meta_subdir(canonical_path.to_string() + "/") {
+                return subdir.open2(scope, VfsPath::dot(), protocols, object_request);
             }
             return Err(zx::Status::NOT_FOUND);
         }
@@ -500,16 +502,8 @@
             return self.non_meta_storage.open2(blob, protocols, scope, object_request);
         }
 
-        let subdir_prefix = canonical_path.to_string() + "/";
-        for k in self.non_meta_files.keys() {
-            if k.starts_with(&subdir_prefix) {
-                return NonMetaSubdir::new(self, subdir_prefix).open2(
-                    scope,
-                    VfsPath::dot(),
-                    protocols,
-                    object_request,
-                );
-            }
+        if let Some(subdir) = self.get_non_meta_subdir(canonical_path.to_string() + "/") {
+            return subdir.open2(scope, VfsPath::dot(), protocols, object_request);
         }
 
         Err(zx::Status::NOT_FOUND)
@@ -666,7 +660,7 @@
             )]),
         )
         .unwrap();
-        let hash = fuchsia_merkle::MerkleTree::from_reader(&*meta_far).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(&meta_far).root();
         let () = blobfs_fake.add_blob(hash, meta_far);
 
         assert_matches!(
diff --git a/src/sys/pkg/lib/package-tool/src/repo_publish.rs b/src/sys/pkg/lib/package-tool/src/repo_publish.rs
index ed37fd61..14a57d9 100644
--- a/src/sys/pkg/lib/package-tool/src/repo_publish.rs
+++ b/src/sys/pkg/lib/package-tool/src/repo_publish.rs
@@ -186,7 +186,8 @@
                 blobs_dir.as_std_path(),
                 package.hash,
                 manifests_dir.as_std_path(),
-            )?;
+            )
+            .context("creating package manifest")?;
 
             package_manifest
                 .write_with_relative_paths(&package_manifest_path)
@@ -1282,7 +1283,7 @@
                     name: "fuchsia.com".into(),
                     metadata_path: src_repo_path.join("repository"),
                     blobs_path: src_repo_path.join("repository").join("blobs"),
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
@@ -1292,7 +1293,7 @@
                     name: "fuchsia.com".into(),
                     metadata_path: second_repo_path.join("repository"),
                     blobs_path: second_repo_path.join("repository").join("blobs"),
-                    delivery_blob_type: None,
+                    delivery_blob_type: 1,
                     root_private_key_path: None,
                     targets_private_key_path: None,
                     snapshot_private_key_path: None,
@@ -1363,7 +1364,7 @@
                 name: "fuchsia.com".into(),
                 metadata_path: pb_metadata_dir,
                 blobs_path: pb_blobs_dir.clone(),
-                delivery_blob_type: None,
+                delivery_blob_type: 1,
                 root_private_key_path: None,
                 targets_private_key_path: None,
                 snapshot_private_key_path: None,
@@ -1396,10 +1397,10 @@
             pb_client.list_packages().await.unwrap().sort(),
         );
 
-        for entry in std::fs::read_dir(&pb_blobs_dir).unwrap() {
+        for entry in std::fs::read_dir(&pb_blobs_dir.join("1")).unwrap() {
             let entry = entry.unwrap();
             let blob = entry.file_name().into_string().unwrap();
-            let repo_blob_path = repo_dir.join("repository").join("blobs").join(blob);
+            let repo_blob_path = repo_dir.join("repository/blobs/1").join(blob);
 
             assert_eq!(
                 std::fs::read(entry.path()).unwrap(),
diff --git a/src/sys/pkg/testing/blobfs-ramdisk/src/lib.rs b/src/sys/pkg/testing/blobfs-ramdisk/src/lib.rs
index 514d97f..89ac8e8 100644
--- a/src/sys/pkg/testing/blobfs-ramdisk/src/lib.rs
+++ b/src/sys/pkg/testing/blobfs-ramdisk/src/lib.rs
@@ -14,7 +14,7 @@
     fidl::endpoints::ClientEnd,
     fidl_fuchsia_fxfs as ffxfs, fidl_fuchsia_io as fio,
     fuchsia_component::server::ServiceFs,
-    fuchsia_merkle::{Hash, MerkleTreeBuilder},
+    fuchsia_merkle::Hash,
     fuchsia_zircon::{self as zx, prelude::*},
     futures::prelude::*,
     std::{borrow::Cow, collections::BTreeSet, ffi::CString},
@@ -39,9 +39,7 @@
 {
     fn from(bytes: B) -> Self {
         let bytes = bytes.into();
-        let mut tree = MerkleTreeBuilder::new();
-        tree.write(&bytes);
-        Self { merkle: tree.finish().root(), contents: bytes }
+        Self { merkle: fuchsia_merkle::from_slice(&bytes).root(), contents: bytes }
     }
 }
 
@@ -617,10 +615,7 @@
         let c = BlobInfo::from(Cow::from(&b"cow"[..]));
         assert_ne!(a.merkle, b.merkle);
         assert_ne!(b.merkle, c.merkle);
-        assert_eq!(
-            a.merkle,
-            fuchsia_merkle::MerkleTree::from_reader(&b"static slice"[..]).unwrap().root()
-        );
+        assert_eq!(a.merkle, fuchsia_merkle::from_slice(&b"static slice"[..]).root());
 
         // Verify the following calling patterns build, but don't bother building the ramdisk.
         let _ = BlobfsRamdisk::builder()
@@ -656,8 +651,8 @@
             .unwrap();
 
         let expected = BTreeSet::from([
-            fuchsia_merkle::MerkleTree::from_reader(&b"blob 1"[..]).unwrap().root(),
-            fuchsia_merkle::MerkleTree::from_reader(&b"blob 2"[..]).unwrap().root(),
+            fuchsia_merkle::from_slice(&b"blob 1"[..]).root(),
+            fuchsia_merkle::from_slice(&b"blob 2"[..]).root(),
         ]);
         assert_eq!(expected.len(), 2);
         assert_eq!(blobfs.list_blobs().unwrap(), expected);
@@ -706,7 +701,7 @@
     /// Writes a blob to blobfs, returning the computed merkle root of the blob.
     #[allow(clippy::zero_prefixed_literal)]
     fn write_blob(dir: &openat::Dir, payload: &[u8]) -> String {
-        let merkle = fuchsia_merkle::MerkleTree::from_reader(payload).unwrap().root().to_string();
+        let merkle = fuchsia_merkle::from_slice(payload).root().to_string();
         let compressed_data = Type1Blob::generate(payload, CompressionMode::Always);
         let mut f = dir.new_file(delivery_blob_path(&merkle), 0600).unwrap();
         f.set_len(compressed_data.len() as u64).unwrap();
@@ -765,7 +760,7 @@
 
         assert_eq!(list_blobs(&root), Vec::<String>::new());
         let data = "Hello blobfs!".as_bytes();
-        let merkle = fuchsia_merkle::MerkleTree::from_reader(data).unwrap().root();
+        let merkle = fuchsia_merkle::from_slice(data).root();
         blobfs.write_blob(merkle, data).await.unwrap();
 
         assert_eq!(list_blobs(&root), vec![merkle.to_string()]);
@@ -781,7 +776,7 @@
         assert_eq!(list_blobs(&root), Vec::<String>::new());
 
         let bytes = [1u8; 40];
-        let hash = fuchsia_merkle::MerkleTree::from_reader(&bytes[..]).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(&bytes).root();
         let compressed_data = Type1Blob::generate(&bytes, CompressionMode::Always);
 
         let blob_creator = blobfs.blob_creator_proxy().unwrap().unwrap();
@@ -803,7 +798,7 @@
     #[fuchsia_async::run_singlethreaded(test)]
     async fn fxblob_blob_reader_api() {
         let data = "Hello blobfs!".as_bytes();
-        let hash = fuchsia_merkle::MerkleTree::from_reader(data).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(data).root();
         let blobfs = BlobfsRamdisk::builder().fxblob().with_blob(data).start().await.unwrap();
 
         let root = blobfs.root_dir().unwrap();
diff --git a/src/sys/pkg/testing/blobfs-ramdisk/src/test.rs b/src/sys/pkg/testing/blobfs-ramdisk/src/test.rs
index 19c5d61..88174d9 100644
--- a/src/sys/pkg/testing/blobfs-ramdisk/src/test.rs
+++ b/src/sys/pkg/testing/blobfs-ramdisk/src/test.rs
@@ -7,7 +7,6 @@
     assert_matches::assert_matches,
     fidl::endpoints::ServerEnd,
     fidl_fuchsia_io as fio,
-    fuchsia_merkle::MerkleTree,
     fuchsia_zircon::Status,
     std::{io::Write as _, time::Duration},
 };
@@ -387,7 +386,7 @@
 
 #[fuchsia_async::run_singlethreaded(test)]
 async fn empty_blob_readable_after_resize() {
-    let empty_hash = MerkleTree::from_reader(&[][..]).unwrap().root().to_string();
+    let empty_hash = fuchsia_merkle::from_slice(&[][..]).root().to_string();
 
     let blobfs_server = BlobfsRamdisk::start().await.unwrap();
     let root_dir = blobfs_server.root_dir_proxy().unwrap();
@@ -428,7 +427,7 @@
 
 impl TestBlob {
     fn new(contents: &'static [u8]) -> Self {
-        Self { merkle: MerkleTree::from_reader(contents).unwrap().root(), contents }
+        Self { merkle: fuchsia_merkle::from_slice(contents).root(), contents }
     }
 }
 
@@ -549,7 +548,7 @@
 
     // 8,194 bytes so that the partial write exceeds 8,192 bytes.
     let bytes = vec![0u8; 8194];
-    let hash = fuchsia_merkle::MerkleTree::from_reader(&bytes[..]).unwrap().root();
+    let hash = fuchsia_merkle::from_slice(&bytes).root();
     let compressed = Type1Blob::generate(&bytes, CompressionMode::Never);
     let compressed_len: u64 = compressed.len().try_into().unwrap();
 
@@ -574,7 +573,7 @@
     let creator = blobfs.blob_creator_proxy().unwrap().unwrap();
 
     let bytes = vec![0u8; 1];
-    let hash = fuchsia_merkle::MerkleTree::from_reader(&bytes[..]).unwrap().root();
+    let hash = fuchsia_merkle::from_slice(&bytes).root();
     let compressed = Type1Blob::generate(&bytes, CompressionMode::Never);
     let compressed_len: u64 = compressed.len().try_into().unwrap();
 
diff --git a/src/sys/pkg/tests/pkg-cache/src/get.rs b/src/sys/pkg/tests/pkg-cache/src/get.rs
index a4b6f8a..65b296b 100644
--- a/src/sys/pkg/tests/pkg-cache/src/get.rs
+++ b/src/sys/pkg/tests/pkg-cache/src/get.rs
@@ -11,7 +11,6 @@
     fidl_fuchsia_io as fio,
     fidl_fuchsia_pkg::{self as fpkg, BlobInfo, NeededBlobsMarker},
     fidl_fuchsia_pkg_ext::{self as fpkg_ext, BlobId},
-    fuchsia_merkle::MerkleTree,
     fuchsia_pkg_testing::{Package, PackageBuilder, SystemImageBuilder},
     fuchsia_zircon::Status,
     futures::prelude::*,
@@ -227,14 +226,14 @@
     let () = env.write_to_blobfs(&meta_far_hash, &meta_far_data).await;
     {
         let data = &b"some contents"[..];
-        let hash = MerkleTree::from_reader(data).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(data).root();
         let () = env.write_to_blobfs(&hash, data).await;
     }
 
     // Perform a Get(), expecting to only write the 1 remaining content blob.
     let dir = {
         let data = &b"different contents"[..];
-        let hash = MerkleTree::from_reader(data).unwrap().root();
+        let hash = fuchsia_merkle::from_slice(data).root();
         let compressed =
             delivery_blob::Type1Blob::generate(data, delivery_blob::CompressionMode::Always);
 
@@ -654,7 +653,7 @@
     let () = env.block_until_started().await;
 
     // Delete the content blob.
-    let blob_hash = MerkleTree::from_reader(blob_content).unwrap().root();
+    let blob_hash = fuchsia_merkle::from_slice(blob_content).root();
     let blobfs = env.blobfs.client();
     let () = blobfs.delete_blob(&blob_hash).await.unwrap();
     assert!(!blobfs.has_blob(&blob_hash).await);
@@ -749,7 +748,7 @@
     let dir = crate::get_and_verify_package(&env.proxies.package_cache, &pkg).await;
 
     // Delete its content blob.
-    let content_hash = MerkleTree::from_reader(blob_content).unwrap().root();
+    let content_hash = fuchsia_merkle::from_slice(blob_content).root();
     let () = env.blobfs.client().delete_blob(&content_hash).await.unwrap();
 
     {
diff --git a/src/sys/pkg/tests/pkg-cache/src/space.rs b/src/sys/pkg/tests/pkg-cache/src/space.rs
index f250257..10e6394 100644
--- a/src/sys/pkg/tests/pkg-cache/src/space.rs
+++ b/src/sys/pkg/tests/pkg-cache/src/space.rs
@@ -119,7 +119,7 @@
 async fn gc_unowned_blob() {
     let env = TestEnv::builder().build().await;
     let unowned_content = &b"blob not referenced by any protected packages"[..];
-    let unowned_hash = fuchsia_merkle::MerkleTree::from_reader(unowned_content).unwrap().root();
+    let unowned_hash = fuchsia_merkle::from_slice(unowned_content).root();
     let () = env.write_to_blobfs(&unowned_hash, unowned_content).await;
     assert!(env.blobfs.list_blobs().unwrap().contains(&unowned_hash));
 
@@ -143,7 +143,7 @@
     // Write an orphaned incompressible 4 MB blob.
     let mut orphan_data = vec![0; 4 * 1024 * 1024];
     StdRng::from_seed([0u8; 32]).fill(&mut orphan_data[..]);
-    let orphan_hash = fuchsia_merkle::MerkleTree::from_reader(&orphan_data[..]).unwrap().root();
+    let orphan_hash = fuchsia_merkle::from_slice(&orphan_data).root();
     let () = small_blobfs.add_blob_from(orphan_hash, &orphan_data[..]).await.unwrap();
     assert!(small_blobfs.list_blobs().unwrap().contains(&orphan_hash));
 
diff --git a/src/sys/pkg/tests/pkg-resolver/src/lib.rs b/src/sys/pkg/tests/pkg-resolver/src/lib.rs
index 6b33bd7..ba4fa86 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/lib.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/lib.rs
@@ -30,7 +30,7 @@
     fuchsia_component_test::{
         Capability, ChildOptions, RealmBuilder, RealmInstance, Ref, Route, ScopedInstance,
     },
-    fuchsia_merkle::{Hash, MerkleTree},
+    fuchsia_merkle::Hash,
     fuchsia_pkg_testing::{serve::ServedRepository, Package, PackageBuilder},
     fuchsia_sync::Mutex,
     fuchsia_url::{PinnedAbsolutePackageUrl, RepositoryUrl},
@@ -874,7 +874,7 @@
 
 impl TestEnv<BlobfsRamdisk> {
     pub fn add_slice_to_blobfs(&self, slice: &[u8]) {
-        let merkle = MerkleTree::from_reader(slice).expect("merkle slice").root().to_string();
+        let merkle = fuchsia_merkle::from_slice(slice).root().to_string();
         let mut blob = self
             .blobfs
             .root_dir()
diff --git a/src/sys/pkg/tests/pkg-resolver/src/resolve_propagates_blobfs_failure.rs b/src/sys/pkg/tests/pkg-resolver/src/resolve_propagates_blobfs_failure.rs
index 312fce7..e3b4b0a 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/resolve_propagates_blobfs_failure.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/resolve_propagates_blobfs_failure.rs
@@ -13,7 +13,7 @@
     fidl::endpoints::{ClientEnd, RequestStream, ServerEnd},
     fidl_fuchsia_io as fio,
     fuchsia_async::Task,
-    fuchsia_merkle::{Hash, MerkleTree},
+    fuchsia_merkle::Hash,
     fuchsia_pkg_testing::{Package, RepositoryBuilder, SystemImageBuilder},
     fuchsia_zircon::Status,
     futures::{future::BoxFuture, prelude::*},
@@ -218,10 +218,8 @@
 async fn make_pkg_for_mock_blobfs_tests(package_name: &str) -> (Package, String, String) {
     let pkg = make_pkg_with_extra_blobs(package_name, 1).await;
     let pkg_merkle = pkg.hash().to_string();
-    let blob_merkle = MerkleTree::from_reader(extra_blob_contents(package_name, 0).as_slice())
-        .expect("merkle slice")
-        .root()
-        .to_string();
+    let blob_merkle =
+        fuchsia_merkle::from_slice(&extra_blob_contents(package_name, 0)).root().to_string();
     (pkg, pkg_merkle, blob_merkle)
 }
 
diff --git a/src/sys/pkg/tests/pkg-resolver/src/resolve_recovers_from_http_errors.rs b/src/sys/pkg/tests/pkg-resolver/src/resolve_recovers_from_http_errors.rs
index ae66aac..eaae3ff 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/resolve_recovers_from_http_errors.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/resolve_recovers_from_http_errors.rs
@@ -7,7 +7,6 @@
 /// servicing fuchsia.pkg.PackageResolver.Resolve FIDL requests.
 use {
     assert_matches::assert_matches,
-    fuchsia_merkle::MerkleTree,
     fuchsia_pkg_testing::{
         serve::{responder, HttpResponder},
         Package, PackageBuilder, RepositoryBuilder,
@@ -81,10 +80,10 @@
     let pkg = make_pkg_with_extra_blobs("second_resolve_succeeds_when_blob_404", 1).await;
     let path_to_override = format!(
         "/blobs/1/{}",
-        MerkleTree::from_reader(
-            extra_blob_contents("second_resolve_succeeds_when_blob_404", 0).as_slice()
-        )
-        .expect("merkle slice")
+        fuchsia_merkle::from_slice(&extra_blob_contents(
+            "second_resolve_succeeds_when_blob_404",
+            0
+        ))
         .root()
     );
 
@@ -124,10 +123,7 @@
         .build()
         .await
         .unwrap();
-    let path_to_override = format!(
-        "/blobs/1/{}",
-        MerkleTree::from_reader(blob.as_slice()).expect("merkle slice").root()
-    );
+    let path_to_override = format!("/blobs/1/{}", fuchsia_merkle::from_slice(&blob).root());
 
     verify_resolve_fails_then_succeeds(
         pkg,
@@ -165,10 +161,7 @@
         .build()
         .await
         .unwrap();
-    let path_to_override = format!(
-        "/blobs/1/{}",
-        MerkleTree::from_reader(blob.as_slice()).expect("merkle slice").root()
-    );
+    let path_to_override = format!("/blobs/1/{}", fuchsia_merkle::from_slice(&blob).root());
 
     verify_resolve_fails_then_succeeds(
         pkg,
@@ -195,10 +188,7 @@
 async fn second_resolve_succeeds_when_blob_corrupted() {
     let pkg = make_pkg_with_extra_blobs("second_resolve_succeeds_when_blob_corrupted", 1).await;
     let blob = extra_blob_contents("second_resolve_succeeds_when_blob_corrupted", 0);
-    let path_to_override = format!(
-        "/blobs/1/{}",
-        MerkleTree::from_reader(blob.as_slice()).expect("merkle slice").root()
-    );
+    let path_to_override = format!("/blobs/1/{}", fuchsia_merkle::from_slice(&blob).root());
 
     verify_resolve_fails_then_succeeds(
         pkg,
diff --git a/src/sys/pkg/tests/pkgdir/test_realm_proxy/src/main.rs b/src/sys/pkg/tests/pkgdir/test_realm_proxy/src/main.rs
index 3be2133b..aef5349 100644
--- a/src/sys/pkg/tests/pkgdir/test_realm_proxy/src/main.rs
+++ b/src/sys/pkg/tests/pkgdir/test_realm_proxy/src/main.rs
@@ -96,8 +96,8 @@
                 }
                 // TODO(https://fxbug.dev/329496030): We have to use this factory method instead
                 // of creating a Capability::Directory directly - see the bug for details.
-                let (my_dictionary_proxy, server) = endpoints::create_proxy().unwrap();
-                let () = factory.create_dictionary(server).await?;
+                let my_dictionary_proxy = factory.create_dictionary().await?;
+                let my_dictionary_proxy = my_dictionary_proxy.into_proxy().unwrap();
                 let value =
                     factory.create_directory(client_end.into_channel().into()).await.unwrap();
                 my_dictionary_proxy.insert("pkg", value).await?.unwrap();
diff --git a/src/sys/root/root.cml b/src/sys/root/root.cml
index 86eca93..6f9bbe1 100644
--- a/src/sys/root/root.cml
+++ b/src/sys/root/root.cml
@@ -63,6 +63,7 @@
             from: "#config",
             to: "#core",
             config: [
+                "fuchsia.http-client.StopOnIdleTimeoutMillis",
                 "fuchsia.memory.CaptureOnPressureChange",
                 "fuchsia.memory.CriticalCaptureDelay",
                 "fuchsia.memory.ImminentOomCaptureDelay",
@@ -141,6 +142,7 @@
                 "fuchsia.boot.SvcStashProvider",
                 "fuchsia.boot.WriteOnlyLog",
                 "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.DebugResource",
                 "fuchsia.kernel.EnergyInfoResource",
                 "fuchsia.kernel.FramebufferResource",
diff --git a/src/sys/test_manager/meta/common.shard.cml b/src/sys/test_manager/meta/common.shard.cml
index 5ba1ede..bf50ec9 100644
--- a/src/sys/test_manager/meta/common.shard.cml
+++ b/src/sys/test_manager/meta/common.shard.cml
@@ -161,6 +161,8 @@
         },
         { protocol: "fuchsia.test.manager.Query" },
         { protocol: "fuchsia.test.manager.RunBuilder" },
+        { protocol: "fuchsia.test.manager.TestCaseEnumerator" },
+        { protocol: "fuchsia.test.manager.SuiteRunner" },
         { protocol: "fuchsia.test.manager.EarlyBootProfile" },
     ],
     use: [
@@ -264,6 +266,7 @@
                 "fuchsia.boot.ReadOnlyLog",
                 "fuchsia.exception.Handler",
                 "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.DebugResource",
                 "fuchsia.kernel.EnergyInfoResource",
                 "fuchsia.kernel.FramebufferResource",
@@ -654,6 +657,14 @@
             from: "self",
         },
         {
+            protocol: "fuchsia.test.manager.TestCaseEnumerator",
+            from: "self",
+        },
+        {
+            protocol: "fuchsia.test.manager.SuiteRunner",
+            from: "self",
+        },
+        {
             protocol: "fuchsia.test.manager.EarlyBootProfile",
             from: "self",
         },
diff --git a/src/sys/test_manager/meta/test_manager.core_shard.cml b/src/sys/test_manager/meta/test_manager.core_shard.cml
index 86c4d3c..a8cfa8d 100644
--- a/src/sys/test_manager/meta/test_manager.core_shard.cml
+++ b/src/sys/test_manager/meta/test_manager.core_shard.cml
@@ -217,6 +217,7 @@
                 "fuchsia.boot.RootResource",
                 "fuchsia.device.NameProvider",
                 "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.DebugResource",
                 "fuchsia.kernel.EnergyInfoResource",
                 "fuchsia.kernel.FramebufferResource",
diff --git a/src/sys/test_manager/src/debug_data_processor.rs b/src/sys/test_manager/src/debug_data_processor.rs
index 1b4a21f..8a94f80 100644
--- a/src/sys/test_manager/src/debug_data_processor.rs
+++ b/src/sys/test_manager/src/debug_data_processor.rs
@@ -3,11 +3,16 @@
 // found in the LICENSE file.
 
 use {
-    crate::{debug_data_server, run_events::RunEvent},
+    crate::{
+        debug_data_server,
+        run_events::{RunEvent, SuiteEvents},
+    },
     anyhow::Error,
     fidl::endpoints::create_endpoints,
     fidl_fuchsia_debugdata as fdebug, fidl_fuchsia_io as fio,
-    fidl_fuchsia_test_debug as ftest_debug, fuchsia_async as fasync,
+    fidl_fuchsia_test_debug as ftest_debug,
+    fidl_fuchsia_test_manager::LaunchError,
+    fuchsia_async as fasync,
     fuchsia_component::{client::connect_to_protocol, server::ServiceFs},
     fuchsia_component_test::LocalComponentHandles,
     fuchsia_fs::{directory::open_channel_in_namespace, OpenFlags},
@@ -95,7 +100,7 @@
     ) -> Result<(), Error> {
         let Self { directory, receiver, proxy_init_fn } = self;
 
-        // Avoid setting up resrources in the common case where no debug data is produced.
+        // Avoid setting up resources in the common case where no debug data is produced.
         let peekable_reciever = receiver.ready_chunks(Self::MAX_SENT_VMOS).peekable();
         pin_mut!(peekable_reciever);
         if peekable_reciever.as_mut().peek().await.is_none() {
@@ -138,6 +143,59 @@
         }
         Ok(())
     }
+
+    /// Collect debug data produced by the corresponding |DebugDataSender|, and serve the resulting
+    /// data. In case debug data is produced, sends the event over |suite_event_sender|.
+    pub async fn collect_and_serve_for_suite(
+        self,
+        suite_event_sender: mpsc::Sender<Result<SuiteEvents, LaunchError>>,
+    ) -> Result<(), Error> {
+        let Self { directory, receiver, proxy_init_fn } = self;
+
+        // Avoid setting up resources in the common case where no debug data is produced.
+        let peekable_reciever = receiver.ready_chunks(Self::MAX_SENT_VMOS).peekable();
+        pin_mut!(peekable_reciever);
+        if peekable_reciever.as_mut().peek().await.is_none() {
+            return Ok(());
+        }
+
+        enum MaybeOwnedDirectory {
+            Owned(tempfile::TempDir),
+            Unowned(&'static str),
+        }
+        let debug_directory = match directory {
+            DebugDataDirectory::Isolated { parent } => {
+                MaybeOwnedDirectory::Owned(tempfile::TempDir::new_in(parent)?)
+            }
+            DebugDataDirectory::Accumulating { dir } => MaybeOwnedDirectory::Unowned(dir),
+        };
+        let debug_directory_path = match &debug_directory {
+            MaybeOwnedDirectory::Owned(tmp) => tmp.path().to_string_lossy(),
+            MaybeOwnedDirectory::Unowned(dir) => std::borrow::Cow::Borrowed(*dir),
+        };
+
+        let (directory_proxy, server_end) = create_endpoints::<fio::DirectoryMarker>();
+        open_channel_in_namespace(
+            &debug_directory_path,
+            OpenFlags::RIGHT_READABLE | OpenFlags::RIGHT_WRITABLE,
+            server_end,
+        )?;
+
+        let proxy = proxy_init_fn()?;
+        proxy.set_directory(directory_proxy)?;
+        while let Some(chunk) = peekable_reciever.next().await {
+            proxy.add_debug_vmos(chunk).await?;
+        }
+        proxy.finish().await?;
+
+        debug_data_server::serve_directory_for_suite(&debug_directory_path, suite_event_sender)
+            .await?;
+
+        if let MaybeOwnedDirectory::Owned(tmp) = debug_directory {
+            tmp.close()?;
+        }
+        Ok(())
+    }
 }
 
 #[cfg(test)]
@@ -243,7 +301,7 @@
 mod test {
     use {
         super::*,
-        crate::{run_events::RunEventPayload, utilities::stream_fn},
+        crate::{run_events::RunEventPayload, run_events::SuiteEventPayload, utilities::stream_fn},
         fidl::endpoints::create_proxy_and_stream,
         fuchsia_component_test::{
             Capability, ChildOptions, RealmBuilder, RealmInstance, Ref, Route,
@@ -365,6 +423,21 @@
     }
 
     #[fuchsia::test]
+    async fn serve_for_suite_no_requests() {
+        const TEST_URL: &str = "test-url";
+        let DebugDataForTestResult { processor, sender, stream } =
+            DebugDataProcessor::new_for_test(isolated_dir());
+        let test_realm = construct_test_realm(sender, TEST_URL).await.expect("build test realm");
+        test_realm.destroy().await.expect("destroy test realm");
+
+        let (event_sender, event_recv) = mpsc::channel(1);
+        processor.collect_and_serve_for_suite(event_sender).await.unwrap();
+
+        assert!(stream.collect::<Vec<_>>().await.is_empty());
+        assert!(event_recv.collect::<Vec<_>>().await.is_empty());
+    }
+
+    #[fuchsia::test]
     async fn serve_single_client() {
         const TEST_URL: &str = "test-url";
         let DebugDataForTestResult { processor, sender, stream } =
@@ -429,6 +502,75 @@
     }
 
     #[fuchsia::test]
+    async fn serve_for_suite_single_client() {
+        const TEST_URL: &str = "test-url";
+        let DebugDataForTestResult { processor, sender, stream } =
+            DebugDataProcessor::new_for_test(isolated_dir());
+        let test_realm = construct_test_realm(sender, TEST_URL).await.expect("build test realm");
+
+        let (vmo_request_received_send, vmo_request_received_recv) = mpsc::channel(2);
+        // Future running fuchsia.test.debug.DebugDataProcessor.
+        let processor_server_fut = run_test_processor(stream, vmo_request_received_send);
+        // Future running the 'test' (client of fuchsia.debugdata.Publisher)
+        let test_fut = async move {
+            let proxy = test_realm
+                .root
+                .connect_to_protocol_at_exposed_dir::<fdebug::PublisherMarker>()
+                .expect("connect to publisher");
+            let vmo_1 = zx::Vmo::create(VMO_SIZE).unwrap();
+            let (vmo_token_1, vmo_token_server_1) = zx::EventPair::create();
+            proxy.publish("data-sink-1", vmo_1, vmo_token_server_1).expect("publish vmo");
+            drop(vmo_token_1);
+            let vmo_2 = zx::Vmo::create(VMO_SIZE).unwrap();
+            let (vmo_token_2, vmo_token_server_2) = zx::EventPair::create();
+            proxy.publish("data-sink-2", vmo_2, vmo_token_server_2).expect("publish vmo");
+            drop(vmo_token_2);
+            drop(proxy);
+
+            vmo_request_received_recv.take(1).collect::<()>().await;
+            test_realm.destroy().await.expect("destroy test realm");
+        };
+
+        let (event_sender, event_recv) = mpsc::channel(10);
+        // Future that collects VMOs from the test realm and forwards
+        // them to fuchsia.debugdata.Publisher
+        let processor_fut = processor
+            .collect_and_serve_for_suite(event_sender)
+            .unwrap_or_else(|e| panic!("processor failed: {:?}", e));
+        // Future that collects produced debug artifact and asserts on contents.
+        let assertion_fut = async move {
+            let mut events: Vec<_> = event_recv.collect().await;
+            assert_eq!(events.len(), 1);
+            if let SuiteEventPayload::DebugData(iterator) =
+                events.pop().unwrap().unwrap().into_payload()
+            {
+                let iterator_proxy = iterator.into_proxy().unwrap();
+                let files: HashSet<_> = stream_fn(move || iterator_proxy.get_next())
+                    .and_then(|debug_data| async move {
+                        Ok((
+                            debug_data.name.unwrap(),
+                            collect_string_from_socket(debug_data.socket.unwrap())
+                                .await
+                                .expect("Cannot read socket"),
+                        ))
+                    })
+                    .try_collect()
+                    .await
+                    .expect("file collection");
+                let expected = hashset! {
+                    ("data-sink-1".to_string(), TEST_URL.to_string()),
+                    ("data-sink-2".to_string(), TEST_URL.to_string()),
+                };
+                assert_eq!(files, expected);
+            } else {
+                assert!(false); // Event payload was not DebugData
+            }
+        };
+
+        futures::future::join4(processor_server_fut, test_fut, processor_fut, assertion_fut).await;
+    }
+
+    #[fuchsia::test]
     async fn serve_multiple_client() {
         const TEST_URL: &str = "test-url";
         let DebugDataForTestResult { processor, sender, stream } =
@@ -498,6 +640,80 @@
     }
 
     #[fuchsia::test]
+    async fn serve_for_suite_multiple_client() {
+        const TEST_URL: &str = "test-url";
+        let DebugDataForTestResult { processor, sender, stream } =
+            DebugDataProcessor::new_for_test(isolated_dir());
+        let test_realm = construct_test_realm(sender, TEST_URL).await.expect("build test realm");
+
+        let (vmo_request_received_send, vmo_request_received_recv) = mpsc::channel(2);
+        // Future running fuchsia.test.debug.DebugDataProcessor.
+        let processor_server_fut = run_test_processor(stream, vmo_request_received_send);
+        // Future running the 'test' (client of fuchsia.debugdata.Publisher)
+        let test_fut = async move {
+            let proxy_1 = test_realm
+                .root
+                .connect_to_protocol_at_exposed_dir::<fdebug::PublisherMarker>()
+                .expect("connect to publisher");
+            let vmo_1 = zx::Vmo::create(VMO_SIZE).unwrap();
+            let (vmo_token_1, vmo_token_server_1) = zx::EventPair::create();
+            proxy_1.publish("data-sink-1", vmo_1, vmo_token_server_1).expect("publish vmo");
+            drop(vmo_token_1);
+            let proxy_2 = test_realm
+                .root
+                .connect_to_protocol_at_exposed_dir::<fdebug::PublisherMarker>()
+                .expect("connect to publisher");
+            let vmo_2 = zx::Vmo::create(VMO_SIZE).unwrap();
+            let (vmo_token_2, vmo_token_server_2) = zx::EventPair::create();
+            proxy_2.publish("data-sink-2", vmo_2, vmo_token_server_2).expect("publish vmo");
+            drop(vmo_token_2);
+            drop(proxy_1);
+            drop(proxy_2);
+
+            vmo_request_received_recv.take(2).collect::<()>().await;
+            test_realm.destroy().await.expect("destroy test realm");
+        };
+
+        let (event_sender, event_recv) = mpsc::channel(10);
+        // Future that collects VMOs from the test realm and forwards
+        // them to fuchsia.debugdata.Publisher
+        let processor_fut = processor
+            .collect_and_serve_for_suite(event_sender)
+            .unwrap_or_else(|e| panic!("processor failed: {:?}", e));
+        // Future that collects produced debug artifact and asserts on contents.
+        let assertion_fut = async move {
+            let mut events: Vec<_> = event_recv.collect().await;
+            assert_eq!(events.len(), 1);
+            if let SuiteEventPayload::DebugData(iterator) =
+                events.pop().unwrap().unwrap().into_payload()
+            {
+                let iterator_proxy = iterator.into_proxy().unwrap();
+                let files: HashSet<_> = stream_fn(move || iterator_proxy.get_next())
+                    .and_then(|debug_data| async move {
+                        Ok((
+                            debug_data.name.unwrap(),
+                            collect_string_from_socket(debug_data.socket.unwrap())
+                                .await
+                                .expect("read socket"),
+                        ))
+                    })
+                    .try_collect()
+                    .await
+                    .expect("file collection");
+                let expected = hashset! {
+                    ("data-sink-1".to_string(), TEST_URL.to_string()),
+                    ("data-sink-2".to_string(), TEST_URL.to_string()),
+                };
+                assert_eq!(files, expected);
+            } else {
+                assert!(false); // Event payload was not DebugData
+            }
+        };
+
+        futures::future::join4(processor_server_fut, test_fut, processor_fut, assertion_fut).await;
+    }
+
+    #[fuchsia::test]
     fn single_publisher_connection_send_vmo_when_ready() {
         const TEST_URL: &str = "test-url";
         let mut executor = fasync::TestExecutor::new();
diff --git a/src/sys/test_manager/src/debug_data_server.rs b/src/sys/test_manager/src/debug_data_server.rs
index dca328d..8dbb43b 100644
--- a/src/sys/test_manager/src/debug_data_server.rs
+++ b/src/sys/test_manager/src/debug_data_server.rs
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 use {
-    crate::run_events::RunEvent,
+    crate::run_events::{RunEvent, SuiteEvents},
     anyhow::Error,
     fidl::endpoints::{create_proxy, create_request_stream, Proxy},
     fidl_fuchsia_io as fio, fidl_fuchsia_test_manager as ftest_manager, fuchsia_async as fasync,
@@ -104,6 +104,34 @@
     serve_iterator(dir_path, directory, iterator).await
 }
 
+pub(crate) async fn serve_directory_for_suite(
+    dir_path: &str,
+    mut event_sender: mpsc::Sender<Result<SuiteEvents, ftest_manager::LaunchError>>,
+) -> Result<(), Error> {
+    let directory =
+        fuchsia_fs::directory::open_in_namespace(dir_path, fuchsia_fs::OpenFlags::RIGHT_READABLE)?;
+    {
+        let file_stream = fuchsia_fs::directory::readdir_recursive(
+            &directory,
+            Some(fasync::Duration::from_seconds(DEBUG_DATA_TIMEOUT_SECONDS)),
+        )
+        .filter_map(|entry| filter_map_filename(entry, dir_path));
+        pin_mut!(file_stream);
+        if file_stream.next().await.is_none() {
+            // No files to serve.
+            return Ok(());
+        }
+
+        drop(file_stream);
+    }
+
+    let (client, iterator) = create_request_stream::<ftest_manager::DebugDataIteratorMarker>()?;
+    let _ = event_sender.send(Ok(SuiteEvents::debug_data(client).into())).await;
+    event_sender.disconnect(); // No need to hold this open while we serve the iterator.
+
+    serve_iterator(dir_path, directory, iterator).await
+}
+
 /// Serves the |DebugDataIterator| protocol by serving all the files contained under
 /// |dir_path|.
 ///
@@ -162,8 +190,12 @@
 #[cfg(test)]
 mod test {
     use {
-        super::*, crate::run_events::RunEventPayload, fuchsia_async as fasync,
-        std::collections::HashSet, tempfile::tempdir, test_diagnostics::collect_string_from_socket,
+        super::*,
+        crate::run_events::{RunEventPayload, SuiteEventPayload},
+        fuchsia_async as fasync,
+        std::collections::HashSet,
+        tempfile::tempdir,
+        test_diagnostics::collect_string_from_socket,
     };
 
     async fn serve_iterator_from_tmp(
@@ -260,4 +292,104 @@
         drop(proxy);
         task.await.expect("iterator server should not fail");
     }
+
+    async fn serve_iterator_for_suite_from_tmp(
+        dir: &tempfile::TempDir,
+    ) -> (Option<ftest_manager::DebugDataIteratorProxy>, fasync::Task<Result<(), Error>>) {
+        let (send, mut recv) = mpsc::channel(0);
+        let dir_path = dir.path().to_str().unwrap().to_string();
+        let task =
+            fasync::Task::local(async move { serve_directory_for_suite(&dir_path, send).await });
+        let proxy = recv.next().await.map(|event| {
+            if let SuiteEventPayload::DebugData(client) = event.unwrap().into_payload() {
+                Some(client.into_proxy().expect("into proxy"))
+            } else {
+                None // Event is not a DebugData
+            }
+            .unwrap()
+        });
+        (proxy, task)
+    }
+
+    #[fuchsia::test]
+    async fn serve_iterator_for_suite_empty_dir_returns_no_client() {
+        let dir = tempdir().unwrap();
+        let (client, task) = serve_iterator_for_suite_from_tmp(&dir).await;
+        assert!(client.is_none());
+        task.await.expect("iterator server should not fail");
+    }
+
+    #[fuchsia::test]
+    async fn serve_iterator_for_suite_single_response() {
+        let dir = tempdir().unwrap();
+        fuchsia_fs::file::write_in_namespace(&dir.path().join("file").to_string_lossy(), "test")
+            .await
+            .expect("write to file");
+
+        let (client, task) = serve_iterator_for_suite_from_tmp(&dir).await;
+
+        let proxy = client.expect("client to be returned");
+
+        let mut values = proxy.get_next().await.expect("get next");
+        assert_eq!(1usize, values.len());
+        let ftest_manager::DebugData { name, socket, .. } = values.pop().unwrap();
+        assert_eq!(Some("file".to_string()), name);
+        let contents = collect_string_from_socket(socket.unwrap()).await.expect("read socket");
+        assert_eq!("test", contents);
+
+        let values = proxy.get_next().await.expect("get next");
+        assert_eq!(values, vec![]);
+
+        // Calling again is okay and should also return empty vector.
+        let values = proxy.get_next().await.expect("get next");
+        assert_eq!(values, vec![]);
+
+        drop(proxy);
+        task.await.expect("iterator server should not fail");
+    }
+
+    #[fuchsia::test]
+    async fn serve_iterator_for_suite_multiple_responses() {
+        let num_files_served = ITERATOR_BATCH_SIZE * 2;
+
+        let dir = tempdir().unwrap();
+        for idx in 0..num_files_served {
+            fuchsia_fs::file::write_in_namespace(
+                &dir.path().join(format!("file-{:?}", idx)).to_string_lossy(),
+                &format!("test-{:?}", idx),
+            )
+            .await
+            .expect("write to file");
+        }
+
+        let (client, task) = serve_iterator_from_tmp(&dir).await;
+
+        let proxy = client.expect("client to be returned");
+
+        let mut all_files = vec![];
+        loop {
+            let mut next = proxy.get_next().await.expect("get next");
+            if next.is_empty() {
+                break;
+            }
+            all_files.append(&mut next);
+        }
+
+        let file_contents: HashSet<_> = futures::stream::iter(all_files)
+            .then(|ftest_manager::DebugData { name, socket, .. }| async move {
+                let contents =
+                    collect_string_from_socket(socket.unwrap()).await.expect("read socket");
+                (name.unwrap(), contents)
+            })
+            .collect()
+            .await;
+
+        let expected_files: HashSet<_> = (0..num_files_served)
+            .map(|idx| (format!("file-{:?}", idx), format!("test-{:?}", idx)))
+            .collect();
+
+        assert_eq!(file_contents, expected_files);
+        drop(proxy);
+        task.await.expect("iterator server should not fail");
+    }
 }
diff --git a/src/sys/test_manager/src/lib.rs b/src/sys/test_manager/src/lib.rs
index 43dbb32..d7d2de7 100644
--- a/src/sys/test_manager/src/lib.rs
+++ b/src/sys/test_manager/src/lib.rs
@@ -23,6 +23,8 @@
     above_root_capabilities::AboveRootCapabilitiesForTest,
     self_diagnostics::RootDiagnosticNode,
     test_manager_server::{
-        run_test_manager, run_test_manager_query_server, serve_early_boot_profiles,
+        run_test_manager_query_server, run_test_manager_run_builder_server,
+        run_test_manager_suite_runner_server, run_test_manager_test_case_enumerator_server,
+        serve_early_boot_profiles,
     },
 };
diff --git a/src/sys/test_manager/src/main.rs b/src/sys/test_manager/src/main.rs
index 1b830e5..679d5a8 100644
--- a/src/sys/test_manager/src/main.rs
+++ b/src/sys/test_manager/src/main.rs
@@ -55,29 +55,39 @@
     );
 
     info!("Reading capabilities from {}", args.manifest_name());
-    let routing_info = Arc::new(AboveRootCapabilitiesForTest::new(args.manifest_name()).await?);
-    let routing_info_clone = routing_info.clone();
-    let resolver = Arc::new(
+    let routing_info_for_run_builder =
+        Arc::new(AboveRootCapabilitiesForTest::new(args.manifest_name()).await?);
+    let routing_info_for_query = routing_info_for_run_builder.clone();
+    let routing_info_for_task_test_case_enumerator = routing_info_for_run_builder.clone();
+    let routing_info_for_suite_runner = routing_info_for_run_builder.clone();
+
+    let resolver_for_run_builder = Arc::new(
         connect_to_protocol::<fresolution::ResolverMarker>()
             .expect("Cannot connect to component resolver"),
     );
-    let resolver_clone = resolver.clone();
-    let root_inspect = Arc::new(RootDiagnosticNode::new(
+    let resolver_for_query = resolver_for_run_builder.clone();
+    let resolver_for_test_case_enumerator = resolver_for_run_builder.clone();
+    let resolver_for_suite_runner = resolver_for_run_builder.clone();
+
+    let root_inspect_for_run_builder = Arc::new(RootDiagnosticNode::new(
         fuchsia_inspect::component::inspector().root().clone_weak(),
     ));
-    let root_inspect_query = root_inspect.clone();
+    let root_inspect_for_query = root_inspect_for_run_builder.clone();
+    let root_inspect_for_test_case_enumerator = root_inspect_for_run_builder.clone();
+    let root_inspect_for_suite_runner = root_inspect_for_run_builder.clone();
 
     fs.dir("svc")
         .add_fidl_service(move |stream| {
-            let routing_info_for_task = routing_info_clone.clone();
-            let resolver = resolver.clone();
-            let root_inspect_clone = root_inspect.clone();
-            fasync::Task::local(async move {
-                test_manager_lib::run_test_manager(
+            let resolver = resolver_for_run_builder.clone();
+            let routing_info = routing_info_for_run_builder.clone();
+            let root_inspect = root_inspect_for_run_builder.clone();
+
+            fasync::Task::spawn(async move {
+                test_manager_lib::run_test_manager_run_builder_server(
                     stream,
                     resolver,
-                    routing_info_for_task,
-                    &*root_inspect_clone,
+                    routing_info,
+                    &*root_inspect,
                 )
                 .await
                 .unwrap_or_else(|error| warn!(?error, "test manager returned error"))
@@ -85,16 +95,16 @@
             .detach();
         })
         .add_fidl_service(move |stream| {
-            let routing_info_for_task = routing_info.clone();
-            let resolver = resolver_clone.clone();
-            let root_inspect_clone = root_inspect_query.clone();
+            let resolver = resolver_for_query.clone();
+            let routing_info = routing_info_for_query.clone();
+            let root_inspect = root_inspect_for_query.clone();
 
             fasync::Task::local(async move {
                 test_manager_lib::run_test_manager_query_server(
                     stream,
                     resolver,
-                    routing_info_for_task,
-                    &*root_inspect_clone,
+                    routing_info,
+                    &*root_inspect,
                 )
                 .await
                 .unwrap_or_else(|error| warn!(?error, "test manager returned error"))
@@ -102,12 +112,46 @@
             .detach();
         })
         .add_fidl_service(move |stream| {
-            fasync::Task::local(async move {
+            fasync::Task::spawn(async move {
                 test_manager_lib::serve_early_boot_profiles(stream)
                     .await
                     .unwrap_or_else(|error| warn!(?error, "test manager returned error"))
             })
             .detach();
+        })
+        .add_fidl_service(move |stream| {
+            let resolver = resolver_for_test_case_enumerator.clone();
+            let routing_info = routing_info_for_task_test_case_enumerator.clone();
+            let root_inspect = root_inspect_for_test_case_enumerator.clone();
+
+            fasync::Task::local(async move {
+                test_manager_lib::run_test_manager_test_case_enumerator_server(
+                    stream,
+                    resolver,
+                    routing_info,
+                    &*root_inspect,
+                )
+                .await
+                .unwrap_or_else(|error| warn!(?error, "test manager returned error"))
+            })
+            .detach();
+        })
+        .add_fidl_service(move |stream| {
+            let resolver = resolver_for_suite_runner.clone();
+            let routing_info = routing_info_for_suite_runner.clone();
+            let root_inspect = root_inspect_for_suite_runner.clone();
+
+            fasync::Task::spawn(async move {
+                test_manager_lib::run_test_manager_suite_runner_server(
+                    stream,
+                    resolver,
+                    routing_info,
+                    &*root_inspect,
+                )
+                .await
+                .unwrap_or_else(|error| warn!(?error, "test manager returned error"))
+            })
+            .detach();
         });
     fs.take_and_serve_directory_handle()?;
     fs.collect::<()>().await;
diff --git a/src/sys/test_manager/src/run_events.rs b/src/sys/test_manager/src/run_events.rs
index 967f6ff..95916d6 100644
--- a/src/sys/test_manager/src/run_events.rs
+++ b/src/sys/test_manager/src/run_events.rs
@@ -6,9 +6,10 @@
     fidl::endpoints::ClientEnd,
     fidl_fuchsia_test_manager as ftest_manager,
     ftest_manager::{
-        CaseStatus, DebugDataIteratorMarker, RunEvent as FidlRunEvent,
-        RunEventPayload as FidlRunEventPayload, SuiteEvent as FidlSuiteEvent,
-        SuiteEventPayload as FidlSuiteEventPayload, SuiteStatus,
+        CaseStatus, DebugDataIteratorMarker, Event as FidlEvent, EventDetails as FidlEventDetails,
+        RunEvent as FidlRunEvent, RunEventPayload as FidlRunEventPayload,
+        SuiteEvent as FidlSuiteEvent, SuiteEventPayload as FidlSuiteEventPayload, SuiteResult,
+        SuiteStatus, TestCaseResult,
     },
     fuchsia_zircon as zx,
 };
@@ -50,7 +51,7 @@
     }
 }
 
-enum SuiteEventPayload {
+pub(crate) enum SuiteEventPayload {
     CaseFound(String, u32),
     CaseStarted(u32),
     CaseStopped(u32, CaseStatus),
@@ -61,6 +62,7 @@
     SuiteSyslog(ftest_manager::Syslog),
     SuiteStarted,
     SuiteStopped(SuiteStatus),
+    DebugData(ClientEnd<DebugDataIteratorMarker>),
 }
 
 pub struct SuiteEvents {
@@ -143,6 +145,154 @@
                 })),
                 ..Default::default()
             },
+            SuiteEventPayload::DebugData(client) => FidlSuiteEvent {
+                timestamp: Some(self.timestamp),
+                payload: Some(FidlSuiteEventPayload::SuiteArtifact(ftest_manager::SuiteArtifact {
+                    artifact: ftest_manager::Artifact::DebugData(client),
+                })),
+                ..Default::default()
+            },
+        }
+    }
+}
+
+fn to_case_result(status: CaseStatus) -> TestCaseResult {
+    match status {
+        CaseStatus::Passed => TestCaseResult::Passed,
+        CaseStatus::Failed => TestCaseResult::Failed,
+        CaseStatus::TimedOut => TestCaseResult::TimedOut,
+        CaseStatus::Skipped => TestCaseResult::Skipped,
+        CaseStatus::Error => TestCaseResult::Error,
+        _ => TestCaseResult::Error,
+    }
+}
+
+fn to_suite_result(status: SuiteStatus) -> SuiteResult {
+    match status {
+        SuiteStatus::Passed => SuiteResult::Finished,
+        SuiteStatus::Failed => SuiteResult::Failed,
+        SuiteStatus::DidNotFinish => SuiteResult::DidNotFinish,
+        SuiteStatus::TimedOut => SuiteResult::TimedOut,
+        SuiteStatus::Stopped => SuiteResult::Stopped,
+        SuiteStatus::InternalError => SuiteResult::InternalError,
+        _ => SuiteResult::InternalError,
+    }
+}
+
+impl Into<FidlEvent> for SuiteEvents {
+    fn into(self) -> FidlEvent {
+        match self.payload {
+            SuiteEventPayload::SuiteStarted => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::SuiteStarted(
+                    ftest_manager::SuiteStartedEventDetails { ..Default::default() },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::CaseFound(name, identifier) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::TestCaseFound(
+                    ftest_manager::TestCaseFoundEventDetails {
+                        test_case_name: Some(name),
+                        test_case_id: Some(identifier),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::CaseStarted(identifier) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::TestCaseStarted(
+                    ftest_manager::TestCaseStartedEventDetails {
+                        test_case_id: Some(identifier),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::CaseStopped(identifier, status) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::TestCaseStopped(
+                    ftest_manager::TestCaseStoppedEventDetails {
+                        test_case_id: Some(identifier),
+                        result: Some(to_case_result(status)),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::CaseFinished(identifier) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::TestCaseFinished(
+                    ftest_manager::TestCaseFinishedEventDetails {
+                        test_case_id: Some(identifier),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::CaseStdout(identifier, socket) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::TestCaseArtifactGenerated(
+                    ftest_manager::TestCaseArtifactGeneratedEventDetails {
+                        test_case_id: Some(identifier),
+                        artifact: Some(ftest_manager::Artifact::Stdout(socket)),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::CaseStderr(identifier, socket) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::TestCaseArtifactGenerated(
+                    ftest_manager::TestCaseArtifactGeneratedEventDetails {
+                        test_case_id: Some(identifier),
+                        artifact: Some(ftest_manager::Artifact::Stderr(socket)),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::CustomArtifact(custom) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::SuiteArtifactGenerated(
+                    ftest_manager::SuiteArtifactGeneratedEventDetails {
+                        artifact: Some(ftest_manager::Artifact::Custom(custom)),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::SuiteSyslog(syslog) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::SuiteArtifactGenerated(
+                    ftest_manager::SuiteArtifactGeneratedEventDetails {
+                        artifact: Some(ftest_manager::Artifact::Log(syslog)),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::SuiteStopped(status) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::SuiteStopped(
+                    ftest_manager::SuiteStoppedEventDetails {
+                        result: Some(to_suite_result(status)),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
+            SuiteEventPayload::DebugData(client) => FidlEvent {
+                timestamp: Some(self.timestamp),
+                details: Some(FidlEventDetails::SuiteArtifactGenerated(
+                    ftest_manager::SuiteArtifactGeneratedEventDetails {
+                        artifact: Some(ftest_manager::Artifact::DebugData(client)),
+                        ..Default::default()
+                    },
+                )),
+                ..Default::default()
+            },
         }
     }
 }
@@ -218,10 +368,27 @@
         }
     }
 
+    pub fn debug_data(client: ClientEnd<DebugDataIteratorMarker>) -> Self {
+        Self {
+            timestamp: zx::Time::get_monotonic().into_nanos(),
+            payload: SuiteEventPayload::DebugData(client),
+        }
+    }
+
     #[cfg(test)]
     pub fn into_suite_run_event(self) -> FidlSuiteEvent {
         self.into()
     }
+
+    #[cfg(test)]
+    pub fn into_event(self) -> FidlEvent {
+        self.into()
+    }
+
+    #[cfg(test)]
+    pub fn into_payload(self) -> SuiteEventPayload {
+        self.payload
+    }
 }
 
 #[cfg(test)]
@@ -318,5 +485,134 @@
                 artifact: ftest_manager::Artifact::Log(ftest_manager::Syslog::Batch(_)),
             }))
         );
+
+        // New Event FIDL type.
+
+        let event = SuiteEvents::suite_started().into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_eq!(
+            event.details,
+            Some(FidlEventDetails::SuiteStarted(ftest_manager::SuiteStartedEventDetails {
+                ..Default::default()
+            }))
+        );
+
+        let event = SuiteEvents::suite_stopped(SuiteStatus::Failed).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_eq!(
+            event.details,
+            Some(FidlEventDetails::SuiteStopped(ftest_manager::SuiteStoppedEventDetails {
+                result: Some(SuiteResult::Failed),
+                ..Default::default()
+            }))
+        );
+
+        let event = SuiteEvents::case_found(1, "case1".to_string()).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_eq!(
+            event.details,
+            Some(FidlEventDetails::TestCaseFound(ftest_manager::TestCaseFoundEventDetails {
+                test_case_name: Some("case1".into()),
+                test_case_id: Some(1),
+                ..Default::default()
+            }))
+        );
+
+        let event = SuiteEvents::case_started(2).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_eq!(
+            event.details,
+            Some(FidlEventDetails::TestCaseStarted(ftest_manager::TestCaseStartedEventDetails {
+                test_case_id: Some(2),
+                ..Default::default()
+            }))
+        );
+
+        let (sock1, _sock2) = zx::Socket::create_stream();
+        let event = SuiteEvents::case_stdout(2, sock1).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_matches!(
+            event.details,
+            Some(FidlEventDetails::TestCaseArtifactGenerated(
+                ftest_manager::TestCaseArtifactGeneratedEventDetails {
+                    test_case_id: Some(2),
+                    artifact: Some(ftest_manager::Artifact::Stdout(_)),
+                    ..
+                }
+            ))
+        );
+
+        let (sock1, _sock2) = zx::Socket::create_stream();
+        let event = SuiteEvents::case_stderr(2, sock1).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_matches!(
+            event.details,
+            Some(FidlEventDetails::TestCaseArtifactGenerated(
+                ftest_manager::TestCaseArtifactGeneratedEventDetails {
+                    test_case_id: Some(2),
+                    artifact: Some(ftest_manager::Artifact::Stderr(_)),
+                    ..
+                }
+            ))
+        );
+
+        let event = SuiteEvents::case_stopped(2, CaseStatus::Failed).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_eq!(
+            event.details,
+            Some(FidlEventDetails::TestCaseStopped(ftest_manager::TestCaseStoppedEventDetails {
+                test_case_id: Some(2),
+                result: Some(TestCaseResult::Failed),
+                ..Default::default()
+            }))
+        );
+
+        let event = SuiteEvents::case_finished(2).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_eq!(
+            event.details,
+            Some(FidlEventDetails::TestCaseFinished(ftest_manager::TestCaseFinishedEventDetails {
+                test_case_id: Some(2),
+                ..Default::default()
+            }))
+        );
+
+        let (client_end, _server_end) = fuchsia_zircon::Socket::create_stream();
+        let event =
+            SuiteEvents::suite_syslog(ftest_manager::Syslog::Stream(client_end)).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_matches!(
+            event.details,
+            Some(FidlEventDetails::SuiteArtifactGenerated(
+                ftest_manager::SuiteArtifactGeneratedEventDetails {
+                    artifact: Some(ftest_manager::Artifact::Log(ftest_manager::Syslog::Stream(_))),
+                    ..
+                }
+            ))
+        );
+
+        let (client_end, _server_end) = fidl::endpoints::create_endpoints();
+        let event =
+            SuiteEvents::suite_syslog(ftest_manager::Syslog::Batch(client_end)).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_matches!(
+            event.details,
+            Some(FidlEventDetails::SuiteArtifactGenerated(
+                ftest_manager::SuiteArtifactGeneratedEventDetails {
+                    artifact: Some(ftest_manager::Artifact::Log(ftest_manager::Syslog::Batch(_))),
+                    ..
+                }
+            ))
+        );
+
+        let event = SuiteEvents::suite_stopped(SuiteStatus::Failed).into_event();
+        assert_matches!(event.timestamp, Some(_));
+        assert_eq!(
+            event.details,
+            Some(FidlEventDetails::SuiteStopped(ftest_manager::SuiteStoppedEventDetails {
+                result: Some(SuiteResult::Failed),
+                ..Default::default()
+            }))
+        );
     }
 }
diff --git a/src/sys/test_manager/src/running_suite.rs b/src/sys/test_manager/src/running_suite.rs
index 2523301..5bc2d3a 100644
--- a/src/sys/test_manager/src/running_suite.rs
+++ b/src/sys/test_manager/src/running_suite.rs
@@ -28,7 +28,7 @@
     fidl_fuchsia_io as fio, fidl_fuchsia_sys2 as fsys, fidl_fuchsia_test as ftest,
     fidl_fuchsia_test_manager as ftest_manager,
     ftest::Invocation,
-    ftest_manager::{CaseStatus, LaunchError, SuiteEvent as FidlSuiteEvent, SuiteStatus},
+    ftest_manager::{CaseStatus, LaunchError, SuiteStatus},
     fuchsia_async::{self as fasync, TimeoutExt},
     fuchsia_component::client::connect_to_protocol_at_dir_root,
     fuchsia_component_test::{
@@ -169,7 +169,7 @@
         &mut self,
         test_url: &str,
         mut options: ftest_manager::RunOptions,
-        mut sender: mpsc::Sender<Result<FidlSuiteEvent, LaunchError>>,
+        mut sender: mpsc::Sender<Result<SuiteEvents, LaunchError>>,
         mut stop_recv: oneshot::Receiver<()>,
     ) {
         debug!("running test suite {}", test_url);
@@ -349,7 +349,7 @@
     /// Find any custom artifact users under the test realm and report them via sender.
     async fn report_custom_artifacts(
         &mut self,
-        sender: &mut mpsc::Sender<Result<FidlSuiteEvent, LaunchError>>,
+        sender: &mut mpsc::Sender<Result<SuiteEvents, LaunchError>>,
     ) -> Result<(), Error> {
         // TODO(https://fxbug.dev/42074399): Support custom artifacts when test is running in outside
         // realm.
@@ -921,7 +921,7 @@
     invocations: Vec<Invocation>,
     run_options: fidl_fuchsia_test::RunOptions,
     counter: &AtomicU32,
-    sender: &mut mpsc::Sender<Result<FidlSuiteEvent, LaunchError>>,
+    sender: &mut mpsc::Sender<Result<SuiteEvents, LaunchError>>,
     timeout_fut: futures::future::Shared<fasync::Timer>,
 ) -> Result<SuiteStatus, anyhow::Error> {
     let (run_listener_client, mut run_listener) =
@@ -1047,13 +1047,11 @@
 
     futures::select! {
         () = timeout_fut => {
-                let mut all_tasks = vec![];
-                let mut tasks = tasks.lock().await;
-                all_tasks.append(&mut tasks);
-                drop(tasks);
-                for t in all_tasks {
-                    t.cancel().await;
-                }
+            let mut all_tasks = vec![];
+            let mut tasks = tasks.lock().await;
+            all_tasks.append(&mut tasks);
+            drop(tasks);
+            drop(all_tasks);
                 let running_test_cases = running_test_cases.lock().await;
                 for i in &*running_test_cases {
                     sender
diff --git a/src/sys/test_manager/src/test_lib.rs b/src/sys/test_manager/src/test_lib.rs
index 85ad848..a09fda6 100644
--- a/src/sys/test_manager/src/test_lib.rs
+++ b/src/sys/test_manager/src/test_lib.rs
@@ -31,6 +31,10 @@
     }
 }
 
+pub fn default_run_suite_options() -> ftest_manager::RunSuiteOptions {
+    ftest_manager::RunSuiteOptions { run_disabled_tests: Some(false), ..Default::default() }
+}
+
 #[derive(Debug, Eq, PartialEq)]
 pub struct AttributedLog {
     pub log: String,
@@ -78,6 +82,9 @@
             SuiteEventPayload::TestCaseLog { .. } => {
                 panic!("not supported yet!")
             }
+            SuiteEventPayload::DebugData { .. } => {
+                panic!("not supported yet!")
+            }
         }
     }
     execution_task.await.context("test execution failed")?;
@@ -97,6 +104,100 @@
     Ok((events, collected_logs))
 }
 
+pub async fn collect_suite_events_with_watch(
+    suite_instance: SuiteRunInstance,
+    filter_debug_data: bool,
+) -> Result<(Vec<RunEvent>, Vec<AttributedLog>), Error> {
+    let (sender, mut recv) = mpsc::channel(1);
+    let execution_task = fasync::Task::spawn(async move {
+        suite_instance.collect_events_with_watch(sender, filter_debug_data).await
+    });
+    let mut events = vec![];
+    let mut log_tasks = vec![];
+    while let Some(event) = recv.next().await {
+        match event.payload {
+            SuiteEventPayload::RunEvent(RunEvent::CaseStdout { name, mut stdout_message }) => {
+                if stdout_message.ends_with("\n") {
+                    stdout_message.truncate(stdout_message.len() - 1)
+                }
+                let logs = stdout_message.split("\n");
+                for log in logs {
+                    // gtest produces this line when tests are randomized. As of
+                    // this writing, our gtest_main binary *always* randomizes.
+                    if log.contains("Note: Randomizing tests' orders with a seed of") {
+                        continue;
+                    }
+                    events.push(RunEvent::case_stdout(name.clone(), log.to_string()));
+                }
+            }
+            SuiteEventPayload::RunEvent(RunEvent::CaseStderr { name, mut stderr_message }) => {
+                if stderr_message.ends_with("\n") {
+                    stderr_message.truncate(stderr_message.len() - 1)
+                }
+                let logs = stderr_message.split("\n");
+                for log in logs {
+                    events.push(RunEvent::case_stderr(name.clone(), log.to_string()));
+                }
+            }
+            SuiteEventPayload::RunEvent(e) => events.push(e),
+            SuiteEventPayload::SuiteLog { log_stream } => {
+                let t = fasync::Task::spawn(log_stream.collect::<Vec<_>>());
+                log_tasks.push(t);
+            }
+            SuiteEventPayload::TestCaseLog { .. } => {
+                panic!("not supported yet!")
+            }
+            SuiteEventPayload::DebugData { filename, socket } => {
+                events.push(RunEvent::DebugData { filename, socket })
+            }
+        }
+    }
+    execution_task.await.context("test execution failed")?;
+
+    let mut collected_logs = vec![];
+    for t in log_tasks {
+        let logs = t.await;
+        for log_result in logs {
+            let log = log_result?;
+            collected_logs.push(AttributedLog {
+                log: log.msg().unwrap().to_string(),
+                moniker: log.moniker.clone(),
+            });
+        }
+    }
+
+    Ok((events, collected_logs))
+}
+
+/// Runs a test suite.
+pub struct SuiteRunner {
+    proxy: ftest_manager::SuiteRunnerProxy,
+}
+
+impl SuiteRunner {
+    /// Create new instance
+    pub fn new(proxy: ftest_manager::SuiteRunnerProxy) -> Self {
+        Self { proxy }
+    }
+
+    pub fn take_proxy(self) -> ftest_manager::SuiteRunnerProxy {
+        self.proxy
+    }
+
+    /// Starts the suite run, returning the suite run controller wrapped in a SuiteRunInstance.
+    pub fn start_suite_run(
+        &self,
+        test_url: &str,
+        options: ftest_manager::RunSuiteOptions,
+    ) -> Result<SuiteRunInstance, Error> {
+        let (controller_proxy, controller) =
+            fidl::endpoints::create_proxy().context("Cannot create proxy")?;
+        self.proxy.run(test_url, options, controller).context("Error starting tests")?;
+
+        return Ok(SuiteRunInstance { controller_proxy: controller_proxy.into() });
+    }
+}
+
 /// Builds and runs test suite(s).
 pub struct TestBuilder {
     proxy: ftest_manager::RunBuilderProxy,
@@ -178,7 +279,7 @@
                 break;
             }
             for fidl_event in fidl_events {
-                match fidl_event.payload.expect("Payload cannot be empty") {
+                match fidl_event.payload.expect("Details cannot be empty") {
                     ftest_manager::RunEventPayload::Artifact(
                         ftest_manager::Artifact::DebugData(iterator),
                     ) => {
@@ -239,6 +340,18 @@
 }
 
 impl SuiteEvent {
+    // Note: This is only used with SuiteRunner, not RunBuilder.
+    pub fn debug_data<S: Into<String>>(
+        timestamp: Option<i64>,
+        filename: S,
+        socket: fidl::Socket,
+    ) -> Self {
+        Self {
+            timestamp,
+            payload: SuiteEventPayload::DebugData { filename: filename.into(), socket },
+        }
+    }
+
     pub fn case_found(timestamp: Option<i64>, name: String) -> Self {
         SuiteEvent { timestamp, payload: SuiteEventPayload::RunEvent(RunEvent::case_found(name)) }
     }
@@ -325,16 +438,27 @@
 
 pub enum SuiteEventPayload {
     /// Logger for test suite
-    SuiteLog { log_stream: LogStream },
+    SuiteLog {
+        log_stream: LogStream,
+    },
 
     /// Logger for a test case in suite.
-    TestCaseLog { name: String, log_stream: LogStream },
+    TestCaseLog {
+        name: String,
+        log_stream: LogStream,
+    },
 
     /// Test events.
     RunEvent(RunEvent),
+
+    // Debug data. Note: This is only used with SuiteRunner, not RunBuilder.
+    DebugData {
+        filename: String,
+        socket: fidl::Socket,
+    },
 }
 
-#[derive(PartialEq, Debug, Eq, Hash, Ord, PartialOrd, Clone)]
+#[derive(PartialEq, Debug, Eq, Hash, Ord, PartialOrd)]
 pub enum RunEvent {
     CaseFound { name: String },
     CaseStarted { name: String },
@@ -345,6 +469,7 @@
     SuiteStarted,
     SuiteCustom { component: String, filename: String, contents: String },
     SuiteStopped { status: ftest_manager::SuiteStatus },
+    DebugData { filename: String, socket: fidl::Socket },
 }
 
 impl RunEvent {
@@ -412,6 +537,14 @@
     pub fn suite_stopped(status: ftest_manager::SuiteStatus) -> Self {
         Self::SuiteStopped { status }
     }
+
+    pub fn debug_data<S>(filename: S, socket: fidl::Socket) -> Self
+    where
+        S: Into<String>,
+    {
+        Self::DebugData { filename: filename.into(), socket }
+    }
+
     /// Returns the name of the test case to which the event belongs, if applicable.
     pub fn test_case_name(&self) -> Option<&String> {
         match self {
@@ -423,7 +556,8 @@
             | RunEvent::CaseFinished { name } => Some(name),
             RunEvent::SuiteStarted
             | RunEvent::SuiteStopped { .. }
-            | RunEvent::SuiteCustom { .. } => None,
+            | RunEvent::SuiteCustom { .. }
+            | RunEvent::DebugData { .. } => None,
         }
     }
 
@@ -435,7 +569,7 @@
 
 /// Groups events by stdout, stderr and non stdout/stderr events to make it easy to compare them
 /// in tests.
-#[derive(Default, Debug, Eq, PartialEq, Clone)]
+#[derive(Default, Debug, Eq, PartialEq)]
 pub struct GroupedRunEvents {
     // order of events is maintained.
     pub non_artifact_events: Vec<RunEvent>,
@@ -557,7 +691,7 @@
         mut sender: mpsc::Sender<SuiteEvent>,
     ) -> Result<(), Error> {
         let timestamp = event.timestamp;
-        let e = match event.payload.expect("Payload cannot be null, please file bug.") {
+        let e = match event.payload.expect("Details cannot be null, please file bug.") {
             FidlSuiteEventPayload::CaseFound(cf) => {
                 self.case_map.insert(cf.identifier, cf.test_case_name.clone());
                 SuiteEvent::case_found(timestamp, cf.test_case_name).into()
@@ -725,6 +859,247 @@
         }
         Ok(())
     }
+
+    async fn process_event(
+        &mut self,
+        event: ftest_manager::Event,
+        mut sender: mpsc::Sender<SuiteEvent>,
+        filter_debug_data: bool,
+    ) -> Result<(), Error> {
+        let timestamp = event.timestamp;
+        let e = match event.details.expect("Details cannot be null, please file bug.") {
+            ftest_manager::EventDetails::TestCaseFound(cf) => {
+                let test_case_name =
+                    cf.test_case_name.expect("test_case_name must be specified, please file bug.");
+                self.case_map.insert(
+                    cf.test_case_id.expect("test_case_id must be specified, please file bug."),
+                    test_case_name.clone(),
+                );
+                SuiteEvent::case_found(timestamp, test_case_name).into()
+            }
+            ftest_manager::EventDetails::TestCaseStarted(cs) => {
+                let test_case_name = self.get_test_case_name(
+                    cs.test_case_id.expect("test_case_id must be specified, please file bug."),
+                );
+                SuiteEvent::case_started(timestamp, test_case_name).into()
+            }
+            ftest_manager::EventDetails::TestCaseStopped(cs) => {
+                let test_case_name = self.get_test_case_name(
+                    cs.test_case_id.expect("test_case_id must be specified, please file bug."),
+                );
+                if let Some(outputs) = self.std_output_map.remove(
+                    &cs.test_case_id.expect("test_case_id must be specified, please file bug."),
+                ) {
+                    for s in outputs {
+                        s.await.context(format!(
+                            "error collecting stdout/stderr of {}",
+                            test_case_name
+                        ))?;
+                    }
+                }
+                SuiteEvent::case_stopped(
+                    timestamp,
+                    test_case_name,
+                    to_case_status(cs.result.expect("result must be specified, please file bug.")),
+                )
+                .into()
+            }
+            ftest_manager::EventDetails::TestCaseFinished(cf) => {
+                let test_case_name = self.get_test_case_name(
+                    cf.test_case_id.expect("test_case_id must be specified, please file bug."),
+                );
+                SuiteEvent::case_finished(timestamp, test_case_name).into()
+            }
+            ftest_manager::EventDetails::TestCaseArtifactGenerated(ca) => {
+                let name = self.get_test_case_name(
+                    ca.test_case_id.expect("test_case_id must be specified, please file bug."),
+                );
+                match ca.artifact.expect("artifact must be specified, please file bug.") {
+                    ftest_manager::Artifact::Stdout(stdout) => {
+                        let (s, mut r) = mpsc::channel(1024);
+                        let stdout_task =
+                            fasync::Task::spawn(collect_and_send_string_output(stdout, s));
+                        let mut sender_clone = sender.clone();
+                        let send_stdout_task = fasync::Task::spawn(async move {
+                            while let Some(msg) = r.next().await {
+                                sender_clone
+                                    .send(SuiteEvent::case_stdout(None, &name, msg))
+                                    .await
+                                    .context(format!("cannot send logs for {}", name))?;
+                            }
+                            Ok(())
+                        });
+                        match self.std_output_map.get_mut(
+                            &ca.test_case_id
+                                .expect("test_case_id must be specified, please file bug."),
+                        ) {
+                            Some(v) => {
+                                v.push(stdout_task);
+                                v.push(send_stdout_task);
+                            }
+                            None => {
+                                self.std_output_map.insert(
+                                    ca.test_case_id
+                                        .expect("test_case_id must be specified, please file bug."),
+                                    vec![stdout_task, send_stdout_task],
+                                );
+                            }
+                        }
+                        None
+                    }
+                    ftest_manager::Artifact::Stderr(stderr) => {
+                        let (s, mut r) = mpsc::channel(1024);
+                        let stderr_task =
+                            fasync::Task::spawn(collect_and_send_string_output(stderr, s));
+                        let mut sender_clone = sender.clone();
+                        let send_stderr_task = fasync::Task::spawn(async move {
+                            while let Some(msg) = r.next().await {
+                                sender_clone
+                                    .send(SuiteEvent::case_stderr(None, &name, msg))
+                                    .await
+                                    .context(format!("cannot send logs for {}", name))?;
+                            }
+                            Ok(())
+                        });
+                        match self.std_output_map.get_mut(
+                            &ca.test_case_id
+                                .expect("test_case_id must be specified, please file bug."),
+                        ) {
+                            Some(v) => {
+                                v.push(stderr_task);
+                                v.push(send_stderr_task);
+                            }
+                            None => {
+                                self.std_output_map.insert(
+                                    ca.test_case_id
+                                        .expect("test_case_id must be specified, please file bug."),
+                                    vec![stderr_task, send_stderr_task],
+                                );
+                            }
+                        }
+                        None
+                    }
+                    ftest_manager::Artifact::Log(log) => match LogStream::from_syslog(log) {
+                        Ok(log_stream) => {
+                            SuiteEvent::test_case_log(timestamp, name, log_stream).into()
+                        }
+                        Err(e) => {
+                            warn!("Cannot collect logs for test suite: {:?}", e);
+                            None
+                        }
+                    },
+                    _ => {
+                        panic!("not supported")
+                    }
+                }
+            }
+            ftest_manager::EventDetails::SuiteArtifactGenerated(sa) => {
+                match sa.artifact.expect("artifact must be specified, please file bug.") {
+                    ftest_manager::Artifact::Stdout(_) => {
+                        panic!("not supported")
+                    }
+                    ftest_manager::Artifact::Stderr(_) => {
+                        panic!("not supported")
+                    }
+                    ftest_manager::Artifact::Log(log) => match LogStream::from_syslog(log) {
+                        Ok(log_stream) => SuiteEvent::suite_log(timestamp, log_stream).into(),
+                        Err(e) => {
+                            warn!("Cannot collect logs for test suite: {:?}", e);
+                            None
+                        }
+                    },
+                    ftest_manager::Artifact::Custom(custom_artifact) => {
+                        let ftest_manager::DirectoryAndToken { directory, token } =
+                            custom_artifact.directory_and_token.unwrap();
+                        let component_moniker = custom_artifact.component_moniker.unwrap();
+                        let mut sender_clone = sender.clone();
+                        fasync::Task::spawn(async move {
+                            let directory = directory.into_proxy().unwrap();
+                            let entries: Vec<_> =
+                                fuchsia_fs::directory::readdir_recursive(&directory, None)
+                                    .try_collect()
+                                    .await
+                                    .expect("read custom artifact directory");
+                            for entry in entries.into_iter() {
+                                let file = fuchsia_fs::directory::open_file_no_describe(
+                                    &directory,
+                                    &entry.name,
+                                    fio::OpenFlags::RIGHT_READABLE,
+                                )
+                                .unwrap();
+                                let contents =
+                                    fuchsia_fs::file::read_to_string(&file).await.unwrap();
+                                sender_clone
+                                    .send(SuiteEvent::suite_custom(
+                                        timestamp,
+                                        component_moniker.clone(),
+                                        entry.name,
+                                        contents,
+                                    ))
+                                    .await
+                                    .unwrap();
+                            }
+                            // Drop the token here - we must keep the token open for the duration that
+                            // the directory is in use.
+                            drop(token);
+                        })
+                        .detach();
+                        None
+                    }
+                    ftest_manager::Artifact::DebugData(iterator) => {
+                        if !filter_debug_data {
+                            let mut sender_clone = sender.clone();
+                            let proxy = iterator.into_proxy().context("Create proxy")?;
+                            fasync::Task::spawn(async move {
+                                loop {
+                                    let data = proxy.get_next().await.unwrap();
+                                    if data.is_empty() {
+                                        break;
+                                    }
+                                    for data_file in data {
+                                        let socket =
+                                            data_file.socket.expect("File cannot be empty");
+                                        sender_clone
+                                            .send(SuiteEvent::debug_data(
+                                                timestamp,
+                                                data_file.name.expect("Name cannot be empty"),
+                                                socket,
+                                            ))
+                                            .await
+                                            .unwrap();
+                                    }
+                                }
+                            })
+                            .detach();
+                        }
+                        None
+                    }
+                    _ => {
+                        panic!("not supported")
+                    }
+                }
+            }
+            ftest_manager::EventDetails::SuiteStarted(_started) => SuiteEvent {
+                timestamp,
+                payload: SuiteEventPayload::RunEvent(RunEvent::SuiteStarted),
+            }
+            .into(),
+            ftest_manager::EventDetails::SuiteStopped(stopped) => SuiteEvent {
+                timestamp,
+                payload: SuiteEventPayload::RunEvent(RunEvent::SuiteStopped {
+                    status: to_suite_status(
+                        stopped.result.expect("result must be specified, please file bug."),
+                    ),
+                }),
+            }
+            .into(),
+            SuiteEventPayloadUnknown!() => panic!("Unrecognized SuiteEvent"),
+        };
+        if let Some(item) = e {
+            sender.send(item).await.context("Cannot send event")?;
+        }
+        Ok(())
+    }
 }
 
 #[derive(Debug, thiserror::Error, Eq, PartialEq, Copy, Clone)]
@@ -804,4 +1179,56 @@
         }
         Ok(())
     }
+
+    pub async fn collect_events_with_watch(
+        &self,
+        sender: mpsc::Sender<SuiteEvent>,
+        filter_debug_data: bool,
+    ) -> Result<(), Error> {
+        let controller_proxy = self.controller_proxy.clone();
+        let mut processor = FidlSuiteEventProcessor::new();
+        loop {
+            match controller_proxy.watch_events().await? {
+                Err(e) => return Err(SuiteLaunchError::from(e).into()),
+                Ok(events) => {
+                    if events.len() == 0 {
+                        break;
+                    }
+                    for event in events {
+                        if let Err(e) =
+                            processor.process_event(event, sender.clone(), filter_debug_data).await
+                        {
+                            warn!("error running test suite: {:?}", e);
+                            let _ = controller_proxy.kill();
+                            return Ok(());
+                        }
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+fn to_case_status(outcome: ftest_manager::TestCaseResult) -> ftest_manager::CaseStatus {
+    match outcome {
+        ftest_manager::TestCaseResult::Passed => ftest_manager::CaseStatus::Passed,
+        ftest_manager::TestCaseResult::Failed => ftest_manager::CaseStatus::Failed,
+        ftest_manager::TestCaseResult::TimedOut => ftest_manager::CaseStatus::TimedOut,
+        ftest_manager::TestCaseResult::Skipped => ftest_manager::CaseStatus::Skipped,
+        ftest_manager::TestCaseResult::Error => ftest_manager::CaseStatus::Error,
+        _ => ftest_manager::CaseStatus::Error,
+    }
+}
+
+fn to_suite_status(outcome: ftest_manager::SuiteResult) -> ftest_manager::SuiteStatus {
+    match outcome {
+        ftest_manager::SuiteResult::Finished => ftest_manager::SuiteStatus::Passed,
+        ftest_manager::SuiteResult::Failed => ftest_manager::SuiteStatus::Failed,
+        ftest_manager::SuiteResult::DidNotFinish => ftest_manager::SuiteStatus::DidNotFinish,
+        ftest_manager::SuiteResult::TimedOut => ftest_manager::SuiteStatus::TimedOut,
+        ftest_manager::SuiteResult::Stopped => ftest_manager::SuiteStatus::Stopped,
+        ftest_manager::SuiteResult::InternalError => ftest_manager::SuiteStatus::InternalError,
+        _ => ftest_manager::SuiteStatus::InternalError,
+    }
 }
diff --git a/src/sys/test_manager/src/test_manager_server.rs b/src/sys/test_manager/src/test_manager_server.rs
index 878d99b..55355c8 100644
--- a/src/sys/test_manager/src/test_manager_server.rs
+++ b/src/sys/test_manager/src/test_manager_server.rs
@@ -16,6 +16,7 @@
         test_suite::{Suite, SuiteRealm, TestRunBuilder},
     },
     fidl::endpoints::ControlHandle,
+    fidl::Error,
     fidl_fuchsia_component_resolution::ResolverProxy,
     fidl_fuchsia_test_manager as ftest_manager,
     fidl_fuchsia_test_manager::{QueryEnumerateInRealmResponder, QueryEnumerateResponder},
@@ -27,8 +28,8 @@
     tracing::warn,
 };
 
-/// Start test manager and serve it over `stream`.
-pub async fn run_test_manager(
+/// Start `RunBuilder` server and serve it over `stream`.
+pub async fn run_test_manager_run_builder_server(
     mut stream: ftest_manager::RunBuilderRequestStream,
     resolver: Arc<ResolverProxy>,
     above_root_capabilities_for_test: Arc<AboveRootCapabilitiesForTest>,
@@ -169,7 +170,7 @@
     }
 }
 
-/// Start test manager and serve it over `stream`.
+/// Start `Query` server and serve it over `stream`.
 pub async fn run_test_manager_query_server(
     mut stream: ftest_manager::QueryRequestStream,
     resolver: Arc<ResolverProxy>,
@@ -196,7 +197,7 @@
                             "Cannot add suite {}, invalid realm. Closing connection. error: {}",
                             test_url, e
                         );
-                        let _ = responder.send(Err(LaunchError::InvalidArgs));
+                        responder.send(Err(LaunchError::InvalidArgs)).ok();
                         break;
                     }
                 };
@@ -204,7 +205,7 @@
                     Ok(offers) => offers,
                     Err(e) => {
                         warn!("Cannot add suite {}, invalid offers. error: {}", test_url, e);
-                        let _ = responder.send(Err(LaunchError::InvalidArgs));
+                        responder.send(Err(LaunchError::InvalidArgs)).ok();
                         break;
                     }
                 };
@@ -226,7 +227,7 @@
             Ok(c) => c,
             Err(e) => {
                 warn!("Cannot query test, invalid iterator {}: {}", test_url, e);
-                let _ = responder.send(Err(LaunchError::InvalidArgs));
+                responder.send(Err(LaunchError::InvalidArgs)).ok();
                 break;
             }
         };
@@ -251,7 +252,7 @@
                 let suite = match suite_instance.connect_to_suite() {
                     Ok(proxy) => proxy,
                     Err(e) => {
-                        let _ = responder.send(Err(e.into()));
+                        responder.send(Err(e.into())).ok();
                         continue;
                     }
                 };
@@ -271,37 +272,39 @@
                                 Err(())
                             }
                         }) {
-                            let _ = responder.send(Ok(()));
+                            responder.send(Ok(())).ok();
                             let mut names = names.chunks(NAMES_CHUNK);
                             while let Ok(Some(request)) = iterator.try_next().await {
                                 match request {
                                     ftest_manager::CaseIteratorRequest::GetNext { responder } => {
                                         match names.next() {
                                             Some(names) => {
-                                                let _ = responder.send(
-                                                    &names
-                                                        .into_iter()
-                                                        .map(|s| ftest_manager::Case {
-                                                            name: Some(s.into()),
-                                                            ..Default::default()
-                                                        })
-                                                        .collect::<Vec<_>>(),
-                                                );
+                                                responder
+                                                    .send(
+                                                        &names
+                                                            .into_iter()
+                                                            .map(|s| ftest_manager::Case {
+                                                                name: Some(s.into()),
+                                                                ..Default::default()
+                                                            })
+                                                            .collect::<Vec<_>>(),
+                                                    )
+                                                    .ok();
                                             }
                                             None => {
-                                                let _ = responder.send(&[]);
+                                                responder.send(&[]).ok();
                                             }
                                         }
                                     }
                                 }
                             }
                         } else {
-                            let _ = responder.send(Err(LaunchError::CaseEnumeration));
+                            responder.send(Err(LaunchError::CaseEnumeration)).ok();
                         }
                     }
                     Err(err) => {
                         warn!(?err, "cannot enumerate tests for {}", test_url);
-                        let _ = responder.send(Err(LaunchError::CaseEnumeration));
+                        responder.send(Err(LaunchError::CaseEnumeration)).ok();
                     }
                 }
                 if let Err(err) = t.await {
@@ -309,7 +312,7 @@
                 }
             }
             Err(e) => {
-                let _ = responder.send(Err(e.into()));
+                responder.send(Err(e.into())).ok();
             }
         }
     }
@@ -352,3 +355,286 @@
     }
     Ok(())
 }
+
+/// Start `TestCaseEnumerator` server and serve it over `stream`.
+pub async fn run_test_manager_test_case_enumerator_server(
+    mut stream: ftest_manager::TestCaseEnumeratorRequestStream,
+    resolver: Arc<ResolverProxy>,
+    above_root_capabilities_for_test: Arc<AboveRootCapabilitiesForTest>,
+    root_diagnostics: &RootDiagnosticNode,
+) -> Result<(), TestManagerError> {
+    while let Some(req) = stream.try_next().await.map_err(TestManagerError::Stream)? {
+        match req {
+            ftest_manager::TestCaseEnumeratorRequest::Enumerate {
+                test_suite_url,
+                options,
+                iterator,
+                responder,
+            } => {
+                let realm = if let Some(realm_options) = options.realm_options {
+                    let realm_proxy = match realm_options
+                        .realm
+                        .map(|r| r.into_proxy())
+                        .unwrap_or(Err(Error::NotNullable))
+                    {
+                        Ok(r) => r,
+                        Err(e) => {
+                            warn!(
+                                "Cannot enumerate test cases {}, invalid realm. Closing connection. error: {}",
+                                test_suite_url, e
+                            );
+                            responder.send(Err(LaunchError::InvalidArgs)).ok();
+                            break;
+                        }
+                    };
+                    let offers = match realm_options
+                        .offers
+                        .map(map_offers)
+                        .unwrap_or(Err(Error::NotNullable.into()))
+                    {
+                        Ok(offers) => offers,
+                        Err(e) => {
+                            warn!(
+                                "Cannot enumerate test cases {}, invalid offers. error: {}",
+                                test_suite_url, e
+                            );
+                            responder.send(Err(LaunchError::InvalidArgs)).ok();
+                            break;
+                        }
+                    };
+                    let test_collection = match realm_options.test_collection {
+                        Some(test_collection) => test_collection,
+                        None => {
+                            warn!(
+                                "Cannot enumerate test cases {}, missing test collection.",
+                                test_suite_url
+                            );
+                            responder.send(Err(LaunchError::InvalidArgs)).ok();
+                            break;
+                        }
+                    };
+                    Some(SuiteRealm { realm_proxy, offers, test_collection })
+                } else {
+                    None
+                };
+
+                let iterator = match iterator.into_stream() {
+                    Ok(c) => c,
+                    Err(e) => {
+                        warn!("Cannot query test, invalid iterator {}: {}", test_suite_url, e);
+                        responder.send(Err(LaunchError::InvalidArgs)).ok();
+                        break;
+                    }
+                };
+                let (_processor, sender) = DebugDataProcessor::new(DebugDataDirectory::Isolated {
+                    parent: constants::ISOLATED_TMP,
+                });
+                let diagnostics = root_diagnostics.child();
+                let launch_fut = facet::get_suite_facets(test_suite_url.clone(), resolver.clone())
+                    .and_then(|facets| {
+                        RunningSuite::launch(
+                            &test_suite_url,
+                            facets,
+                            resolver.clone(),
+                            above_root_capabilities_for_test.clone(),
+                            sender,
+                            &diagnostics,
+                            &realm,
+                        )
+                    });
+                match launch_fut.await {
+                    Ok(suite_instance) => {
+                        let suite = match suite_instance.connect_to_suite() {
+                            Ok(proxy) => proxy,
+                            Err(e) => {
+                                responder.send(Err(e.into())).ok();
+                                continue;
+                            }
+                        };
+                        let enumeration_result = enumerate_test_cases(&suite, None).await;
+                        let t = fasync::Task::spawn(suite_instance.destroy(diagnostics));
+                        match enumeration_result {
+                            Ok(invocations) => {
+                                if let Ok(names) = invocations
+                                    .into_iter()
+                                    .map(|i| i.name.ok_or(()))
+                                    .collect::<Result<Vec<String>, ()>>()
+                                {
+                                    responder.send(Ok(())).ok();
+                                    drain_test_case_names(iterator, names).await;
+                                } else {
+                                    responder.send(Err(LaunchError::CaseEnumeration)).ok();
+                                }
+                            }
+                            Err(err) => {
+                                warn!(?err, "cannot enumerate tests for {}", test_suite_url);
+                                responder.send(Err(LaunchError::CaseEnumeration)).ok();
+                            }
+                        }
+                        if let Err(err) = t.await {
+                            warn!(?err, "Error destroying test realm for {}", test_suite_url);
+                        }
+                    }
+                    Err(e) => {
+                        responder.send(Err(e.into())).ok();
+                    }
+                }
+            }
+
+            ftest_manager::TestCaseEnumeratorRequest::_UnknownMethod {
+                ordinal,
+                control_handle,
+                ..
+            } => {
+                warn!("Unknown query request received: {}, closing connection", ordinal);
+                control_handle.shutdown_with_epitaph(zx::Status::NOT_SUPPORTED);
+                break;
+            }
+        };
+    }
+    Ok(())
+}
+
+async fn drain_test_case_names(
+    mut iterator: ftest_manager::TestCaseIteratorRequestStream,
+    names: Vec<String>,
+) {
+    const NAMES_CHUNK: usize = 50;
+    let mut names = names.chunks(NAMES_CHUNK);
+    while let Ok(Some(request)) = iterator.try_next().await {
+        match request {
+            ftest_manager::TestCaseIteratorRequest::GetNext { responder } => match names.next() {
+                Some(names) => {
+                    responder
+                        .send(
+                            &names
+                                .into_iter()
+                                .map(|s| ftest_manager::TestCase {
+                                    name: Some(s.into()),
+                                    ..Default::default()
+                                })
+                                .collect::<Vec<_>>(),
+                        )
+                        .ok();
+                }
+                None => {
+                    responder.send(&[]).ok();
+                }
+            },
+        }
+    }
+}
+
+/// Start `SuiteRunner` server and serve it over `stream`.
+pub async fn run_test_manager_suite_runner_server(
+    mut stream: ftest_manager::SuiteRunnerRequestStream,
+    resolver: Arc<ResolverProxy>,
+    above_root_capabilities_for_test: Arc<AboveRootCapabilitiesForTest>,
+    root_diagnostics: &RootDiagnosticNode,
+) -> Result<(), TestManagerError> {
+    while let Some(req) = stream.try_next().await.map_err(TestManagerError::Stream)? {
+        match req {
+            ftest_manager::SuiteRunnerRequest::Run {
+                test_suite_url,
+                options,
+                controller,
+                control_handle,
+            } => {
+                let realm = if let Some(realm_options) = options.realm_options {
+                    let realm_proxy = match realm_options
+                        .realm
+                        .map(|r| r.into_proxy())
+                        .unwrap_or(Err(Error::NotNullable))
+                    {
+                        Ok(r) => r,
+                        Err(e) => {
+                            warn!(
+                                "Cannot add suite {}, invalid realm. Closing connection. error: {}",
+                                test_suite_url, e
+                            );
+                            control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
+                            break;
+                        }
+                    };
+                    let offers = match realm_options
+                        .offers
+                        .map(map_offers)
+                        .unwrap_or(Err(Error::NotNullable.into()))
+                    {
+                        Ok(offers) => offers,
+                        Err(e) => {
+                            warn!(
+                                "Cannot add suite {}, invalid offers. error: {}",
+                                test_suite_url, e
+                            );
+                            control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
+                            break;
+                        }
+                    };
+                    let test_collection = match realm_options.test_collection {
+                        Some(test_collection) => test_collection,
+                        None => {
+                            warn!("Cannot add suite {}, missing test collection.", test_suite_url);
+                            control_handle.shutdown_with_epitaph(zx::Status::INVALID_ARGS);
+                            break;
+                        }
+                    };
+                    Some(SuiteRealm { realm_proxy, offers, test_collection })
+                } else {
+                    None
+                };
+
+                let controller = match controller.into_stream() {
+                    Ok(c) => c,
+                    Err(e) => {
+                        warn!("Invalid builder controller. Closing connection. error: {}", e);
+                        control_handle.shutdown_with_epitaph(zx::Status::BAD_HANDLE);
+                        break;
+                    }
+                };
+
+                let suite = Suite {
+                    realm: realm.into(),
+                    test_url: test_suite_url,
+                    options: ftest_manager::RunOptions {
+                        run_disabled_tests: options.run_disabled_tests,
+                        parallel: options.max_concurrent_test_case_runs,
+                        arguments: options.arguments,
+                        timeout: options.timeout,
+                        case_filters_to_run: options.test_case_filters,
+                        log_iterator: options.logs_iterator_type.map(convert),
+                        log_interest: options.log_interest,
+                        ..Default::default()
+                    },
+                    controller,
+                    resolver: resolver.clone(),
+                    above_root_capabilities_for_test: above_root_capabilities_for_test.clone(),
+                    facets: facet::ResolveStatus::Unresolved,
+                };
+
+                let diagnostics = root_diagnostics.child();
+
+                suite.run(diagnostics, options.accumulate_debug_data.unwrap_or(false)).await;
+            }
+
+            ftest_manager::SuiteRunnerRequest::_UnknownMethod {
+                ordinal, control_handle, ..
+            } => {
+                warn!("Unknown run builder request received: {}, closing connection", ordinal);
+                control_handle.shutdown_with_epitaph(zx::Status::NOT_SUPPORTED);
+                break;
+            }
+        }
+    }
+    Ok(())
+}
+
+fn convert(item: ftest_manager::LogsIteratorType) -> ftest_manager::LogsIteratorOption {
+    match item {
+        ftest_manager::LogsIteratorType::Batch => ftest_manager::LogsIteratorOption::BatchIterator,
+        ftest_manager::LogsIteratorType::Socket => {
+            ftest_manager::LogsIteratorOption::SocketBatchIterator
+        }
+        _ => todo!(),
+    }
+}
diff --git a/src/sys/test_manager/src/test_suite.rs b/src/sys/test_manager/src/test_suite.rs
index c869d24..680c7f3 100644
--- a/src/sys/test_manager/src/test_suite.rs
+++ b/src/sys/test_manager/src/test_suite.rs
@@ -10,7 +10,7 @@
         error::*,
         facet,
         facet::SuiteFacets,
-        run_events::RunEvent,
+        run_events::{RunEvent, SuiteEvents},
         running_suite, scheduler,
         scheduler::Scheduler,
         self_diagnostics::DiagnosticNode,
@@ -22,7 +22,7 @@
     fidl_fuchsia_component_test as ftest, fidl_fuchsia_test_manager as ftest_manager,
     ftest_manager::{
         LaunchError, RunControllerRequest, RunControllerRequestStream, SchedulingOptions,
-        SuiteControllerRequest, SuiteControllerRequestStream, SuiteEvent as FidlSuiteEvent,
+        SuiteControllerRequest, SuiteControllerRequestStream,
     },
     fuchsia_async as fasync, fuchsia_zircon as zx,
     futures::{
@@ -35,6 +35,8 @@
     tracing::{error, info, warn},
 };
 
+const EXECUTION_PROPERTY: &'static str = "execution";
+
 pub(crate) struct SuiteRealm {
     pub realm_proxy: RealmProxy,
     pub offers: Vec<ftest::Capability>,
@@ -194,7 +196,7 @@
 
         // This future returns the task which needs to be completed before completion.
         let suite_scheduler_fut = async move {
-            diagnostics_ref.set_property("execution", "executing");
+            diagnostics_ref.set_property(EXECUTION_PROPERTY, "executing");
 
             let serial_executor = scheduler::SerialScheduler {};
 
@@ -241,7 +243,7 @@
 
             drop(debug_data_sender); // needed for debug_data_processor to complete.
 
-            diagnostics_ref.set_property("execution", "complete");
+            diagnostics_ref.set_property(EXECUTION_PROPERTY, "complete");
         };
 
         let (remote, remote_handle) = suite_scheduler_fut.remote_handle();
@@ -267,11 +269,54 @@
 const EVENTS_THRESHOLD: usize = 50;
 
 impl Suite {
+    pub(crate) async fn run(self, diagnostics: DiagnosticNode, accumulate_debug_data: bool) {
+        let diagnostics_ref = &diagnostics;
+
+        let debug_data_directory = match accumulate_debug_data {
+            true => DebugDataDirectory::Accumulating { dir: constants::DEBUG_DATA_FOR_SCP },
+            false => DebugDataDirectory::Isolated { parent: constants::ISOLATED_TMP },
+        };
+        let (debug_data_processor, debug_data_sender) =
+            DebugDataProcessor::new(debug_data_directory);
+
+        let (event_sender, event_receiver) = mpsc::channel(1024);
+
+        let debug_task = fasync::Task::local(
+            debug_data_processor
+                .collect_and_serve_for_suite(event_sender.clone())
+                .unwrap_or_else(|err| warn!(?err, "Error serving debug data")),
+        );
+
+        // This future returns the task which needs to be completed before completion.
+        let suite_run_fut = async move {
+            diagnostics_ref.set_property(EXECUTION_PROPERTY, "executing");
+
+            let suite_node = diagnostics_ref.child("serial_executor").child("suite-0");
+            suite_node.set_property("url", self.test_url.clone());
+            run_single_suite_for_suite_runner(
+                self,
+                debug_data_sender,
+                suite_node,
+                event_sender,
+                event_receiver,
+            )
+            .await;
+
+            diagnostics_ref.set_property(EXECUTION_PROPERTY, "complete");
+        };
+
+        suite_run_fut
+            .then(|_| async move {
+                debug_task.await;
+            })
+            .await;
+    }
+
     async fn run_controller(
         mut controller: SuiteControllerRequestStream,
         stop_sender: oneshot::Sender<()>,
         run_suite_remote_handle: futures::future::RemoteHandle<()>,
-        event_recv: mpsc::Receiver<Result<FidlSuiteEvent, LaunchError>>,
+        event_recv: mpsc::Receiver<Result<SuiteEvents, LaunchError>>,
     ) -> Result<(), Error> {
         let mut task = Some(run_suite_remote_handle);
         let mut stop_sender = Some(stop_sender);
@@ -297,18 +342,22 @@
                         // connection after that.
                     }
                     SuiteControllerRequest::WatchEvents { responder } => {
-                        warn!("Unimplemented WatchEvents suite controller request received: closing connection");
-                        // Dropping the remote handle for the suite execution task cancels it.
-                        drop(task.take());
-                        responder.control_handle().shutdown_with_epitaph(zx::Status::NOT_SUPPORTED);
-                        break;
+                        events_responder_sender
+                            .unbounded_send(EventResponder::New(responder))
+                            .unwrap_or_else(|e| {
+                                // If the handler is already done, drop responder without closing the
+                                // channel.
+                                e.into_inner().drop_without_shutdown();
+                            })
                     }
                     SuiteControllerRequest::GetEvents { responder } => {
-                        events_responder_sender.unbounded_send(responder).unwrap_or_else(|e| {
-                            // If the handler is already done, drop responder without closing the
-                            // channel.
-                            e.into_inner().drop_without_shutdown();
-                        })
+                        events_responder_sender
+                            .unbounded_send(EventResponder::Deprecated(responder))
+                            .unwrap_or_else(|e| {
+                                // If the handler is already done, drop responder without closing the
+                                // channel.
+                                e.into_inner().drop_without_shutdown();
+                            })
                     }
                     SuiteControllerRequest::_UnknownMethod { ordinal, control_handle, .. } => {
                         warn!(
@@ -330,13 +379,7 @@
             while let Some(responder) = events_responder_recv.next().await {
                 let next_chunk_results: Vec<Result<_, _>> =
                     event_chunks.next().await.unwrap_or_default();
-                let next_chunk_result: Result<Vec<_>, _> = next_chunk_results.into_iter().collect();
-                let done = match &next_chunk_result {
-                    Ok(events) => events.is_empty(),
-                    Err(_) => true,
-                };
-                responder.send(next_chunk_result)?;
-                if done {
+                if responder.send(next_chunk_results)? {
                     break;
                 }
             }
@@ -364,6 +407,138 @@
     }
 }
 
+enum EventResponder {
+    Deprecated(ftest_manager::SuiteControllerGetEventsResponder),
+    New(ftest_manager::SuiteControllerWatchEventsResponder),
+}
+
+impl EventResponder {
+    fn drop_without_shutdown(self) {
+        match self {
+            EventResponder::Deprecated(inner) => inner.drop_without_shutdown(),
+            EventResponder::New(inner) => inner.drop_without_shutdown(),
+        }
+    }
+
+    pub fn send(self, results: Vec<Result<SuiteEvents, LaunchError>>) -> Result<bool, fidl::Error> {
+        match self {
+            EventResponder::Deprecated(inner) => {
+                let result: Result<Vec<_>, _> =
+                    results.into_iter().map(|r| r.map(SuiteEvents::into)).collect();
+                let done = match &result {
+                    Ok(events) => events.is_empty(),
+                    Err(_) => true,
+                };
+                inner.send(result).map(|_| done)
+            }
+            EventResponder::New(inner) => {
+                let result: Result<Vec<_>, _> =
+                    results.into_iter().map(|r| r.map(SuiteEvents::into)).collect();
+                let done = match &result {
+                    Ok(events) => events.is_empty(),
+                    Err(_) => true,
+                };
+                inner.send(result).map(|_| done)
+            }
+        }
+    }
+}
+
+async fn run_single_suite_for_suite_runner(
+    suite: Suite,
+    debug_data_sender: DebugDataSender,
+    diagnostics: DiagnosticNode,
+    mut event_sender: mpsc::Sender<Result<SuiteEvents, LaunchError>>,
+    event_recv: mpsc::Receiver<Result<SuiteEvents, LaunchError>>,
+) {
+    let (stop_sender, stop_recv) = oneshot::channel::<()>();
+
+    let Suite {
+        test_url,
+        options,
+        controller,
+        resolver,
+        above_root_capabilities_for_test,
+        facets,
+        realm: suite_realm,
+    } = suite;
+
+    let run_test_fut = async {
+        diagnostics.set_property(EXECUTION_PROPERTY, "get_facets");
+
+        let facets = match facets {
+            // Currently, all suites are passed in with unresolved facets by the
+            // SerialScheduler. ParallelScheduler will pass in Resolved facets
+            // once it is implemented.
+            facet::ResolveStatus::Resolved(result) => {
+                match result {
+                    Ok(facets) => facets,
+
+                    // This error is reported here instead of when the error was
+                    // first encountered because here is where it has access to
+                    // the SuiteController protocol server (Suite::run_controller)
+                    // which can report the error back to the test_manager client
+                    Err(error) => {
+                        event_sender.send(Err(error.into())).await.unwrap();
+                        return;
+                    }
+                }
+            }
+            facet::ResolveStatus::Unresolved => {
+                match facet::get_suite_facets(test_url.clone(), resolver.clone()).await {
+                    Ok(facets) => facets,
+                    Err(error) => {
+                        event_sender.send(Err(error.into())).await.unwrap();
+                        return;
+                    }
+                }
+            }
+        };
+        diagnostics.set_property(EXECUTION_PROPERTY, "launch");
+        match running_suite::RunningSuite::launch(
+            &test_url,
+            facets,
+            resolver,
+            above_root_capabilities_for_test,
+            debug_data_sender,
+            &diagnostics,
+            &suite_realm,
+        )
+        .await
+        {
+            Ok(mut instance) => {
+                diagnostics.set_property(EXECUTION_PROPERTY, "run_tests");
+                instance.run_tests(&test_url, options, event_sender, stop_recv).await;
+                diagnostics.set_property(EXECUTION_PROPERTY, "tests_done");
+                diagnostics.set_property(EXECUTION_PROPERTY, "tear_down");
+                if let Err(err) = instance.destroy(diagnostics.child("destroy")).await {
+                    // Failure to destroy an instance could mean that some component events fail to send.
+                    error!(
+                        ?diagnostics,
+                        ?err,
+                        "Failed to destroy instance. Debug data may be lost."
+                    );
+                }
+            }
+            Err(e) => {
+                event_sender.send(Err(e.into())).await.unwrap();
+            }
+        }
+    };
+    let (run_test_remote, run_test_handle) = run_test_fut.remote_handle();
+
+    let controller_fut =
+        Suite::run_controller(controller, stop_sender, run_test_handle, event_recv);
+    let ((), controller_ret) = futures::future::join(run_test_remote, controller_fut).await;
+
+    if let Err(e) = controller_ret {
+        warn!(?diagnostics, "Ended test {}: {:?}", test_url, e);
+    }
+
+    diagnostics.set_property(EXECUTION_PROPERTY, "complete");
+    info!(?diagnostics, "Test destruction complete");
+}
+
 pub(crate) async fn run_single_suite(
     suite: Suite,
     debug_data_sender: DebugDataSender,
@@ -384,7 +559,7 @@
     } = suite;
 
     let run_test_fut = async {
-        diagnostics.set_property("execution", "get_facets");
+        diagnostics.set_property(EXECUTION_PROPERTY, "get_facets");
 
         let facets = match facets {
             // Currently, all suites are passed in with unresolved facets by the
@@ -414,7 +589,7 @@
                 }
             }
         };
-        diagnostics.set_property("execution", "launch");
+        diagnostics.set_property(EXECUTION_PROPERTY, "launch");
         match running_suite::RunningSuite::launch(
             &test_url,
             facets,
@@ -427,10 +602,10 @@
         .await
         {
             Ok(instance) => {
-                diagnostics.set_property("execution", "run_tests");
+                diagnostics.set_property(EXECUTION_PROPERTY, "run_tests");
                 let instance_ref = maybe_instance.insert(instance);
                 instance_ref.run_tests(&test_url, options, sender, stop_recv).await;
-                diagnostics.set_property("execution", "tests_done");
+                diagnostics.set_property(EXECUTION_PROPERTY, "tests_done");
             }
             Err(e) => {
                 sender.send(Err(e.into())).await.unwrap();
@@ -447,14 +622,14 @@
     }
 
     if let Some(instance) = maybe_instance.take() {
-        diagnostics.set_property("execution", "tear_down");
+        diagnostics.set_property(EXECUTION_PROPERTY, "tear_down");
         info!(?diagnostics, "Try destroying the test");
         if let Err(err) = instance.destroy(diagnostics.child("destroy")).await {
             // Failure to destroy an instance could mean that some component events fail to send.
             error!(?diagnostics, ?err, "Failed to destroy instance. Debug data may be lost.");
         }
     }
-    diagnostics.set_property("execution", "complete");
+    diagnostics.set_property(EXECUTION_PROPERTY, "complete");
     info!(?diagnostics, "Test destruction complete");
 }
 
@@ -497,7 +672,7 @@
 #[cfg(test)]
 mod tests {
     use {
-        super::*, crate::run_events::SuiteEvents, fidl::endpoints::create_proxy_and_stream,
+        super::*, fidl::endpoints::create_proxy_and_stream,
         fidl_fuchsia_component_resolution as fresolution, fuchsia_async as fasync,
     };
 
@@ -559,7 +734,7 @@
         // sending a get event first should not prevent killing the controller.
         let get_events_task = fasync::Task::spawn(proxy.get_events());
         drop(proxy);
-        drop(get_events_task.cancel().await);
+        drop(get_events_task);
         // After controller is dropped, both the controller future and the task it was
         // controlling should terminate.
         pending_task.await;
@@ -607,7 +782,7 @@
         // sending a get event first should not prevent killing the controller.
         let get_events_task = fasync::Task::spawn(proxy.get_events());
         drop(proxy);
-        drop(get_events_task.cancel().await);
+        drop(get_events_task);
         // After controller is dropped, both the controller future and the task it was
         // controlling should terminate.
         pending_task.await;
diff --git a/src/sys/test_manager/tests/meta/test_manager_test.cml b/src/sys/test_manager/tests/meta/test_manager_test.cml
index dd8d965..7505ccf 100644
--- a/src/sys/test_manager/tests/meta/test_manager_test.cml
+++ b/src/sys/test_manager/tests/meta/test_manager_test.cml
@@ -20,6 +20,14 @@
             from: "#test_manager",
         },
         {
+            protocol: "fuchsia.test.manager.TestCaseEnumerator",
+            from: "#test_manager",
+        },
+        {
+            protocol: "fuchsia.test.manager.SuiteRunner",
+            from: "#test_manager",
+        },
+        {
             protocol: "fuchsia.test.manager.EarlyBootProfile",
             from: "#test_manager",
         },
diff --git a/src/sys/test_manager/tests/src/tests.rs b/src/sys/test_manager/tests/src/tests.rs
index 5a4a47d..5780b80 100644
--- a/src/sys/test_manager/tests/src/tests.rs
+++ b/src/sys/test_manager/tests/src/tests.rs
@@ -3,17 +3,19 @@
 // found in the LICENSE file.
 
 use {
-    anyhow::{Context as _, Error},
+    anyhow::{Context, Error},
     fidl::endpoints,
     fidl_fuchsia_test_manager as ftest_manager,
-    ftest_manager::{CaseStatus, RunOptions, SuiteStatus},
+    ftest_manager::{CaseStatus, RunOptions, RunSuiteOptions, SuiteStatus},
     fuchsia_async as fasync,
     fuchsia_component::client,
-    futures::{channel::mpsc, prelude::*},
+    futures::{channel::mpsc, stream, StreamExt},
     pretty_assertions::assert_eq,
+    //std::collections::HashMap,
     test_diagnostics::collect_string_from_socket,
     test_manager_test_lib::{
-        collect_suite_events, default_run_option, AttributedLog, GroupRunEventByTestCase, RunEvent,
+        collect_suite_events, collect_suite_events_with_watch, default_run_option,
+        default_run_suite_options, AttributedLog, GroupRunEventByTestCase, RunEvent, SuiteRunner,
         TestBuilder, TestRunEventPayload,
     },
 };
@@ -32,6 +34,21 @@
     };
 }
 
+macro_rules! connect_suite_runner {
+    () => {
+        client::connect_to_protocol::<ftest_manager::SuiteRunnerMarker>()
+            .context("cannot connect to suite runner proxy")
+    };
+}
+
+macro_rules! connect_test_case_enumerator_server {
+    () => {
+        client::connect_to_protocol::<ftest_manager::TestCaseEnumeratorMarker>()
+            .context("cannot connect to test case numerator proxy")
+    };
+}
+
+#[allow(dead_code)]
 async fn run_single_test(
     test_url: &str,
     run_options: RunOptions,
@@ -45,6 +62,19 @@
     ret
 }
 
+#[allow(dead_code)]
+async fn run_single_test_for_suite(
+    test_url: &str,
+    options: RunSuiteOptions,
+) -> Result<(Vec<RunEvent>, Vec<AttributedLog>), Error> {
+    let runner = SuiteRunner::new(connect_suite_runner!()?);
+    let suite_instance = runner.start_suite_run(test_url, options).context("Cannot run suite")?;
+    let ret = collect_suite_events_with_watch(suite_instance, false).await;
+    // Drop the runner here so it stays alive through `collect_suite_events_with_watch`.
+    drop(runner);
+    ret
+}
+
 #[fuchsia::test]
 async fn calling_kill_should_kill_test() {
     let proxy = connect_run_builder!().unwrap();
@@ -709,31 +739,76 @@
 
 #[fuchsia::test]
 async fn debug_data_accumulate_test() {
+    // Two tests are combined here, because one would otherwise break the other due to the
+    // accumulated files left behind.
+
     let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/debug_data_write_test.cm";
 
-    for iteration in 1usize..3 {
-        let builder = TestBuilder::new(connect_run_builder!().unwrap());
-        builder.set_scheduling_options(true).expect("set scheduling options");
-        let suite_instance = builder
-            .add_suite(test_url, default_run_option())
-            .await
-            .expect("Cannot create suite instance");
-        let (run_events_result, _) =
-            futures::future::join(builder.run(), collect_suite_events(suite_instance)).await;
+    // This is the old `TestBuilder` test.
+    {
+        for iteration in 1usize..3 {
+            let builder = TestBuilder::new(connect_run_builder!().unwrap());
+            builder.set_scheduling_options(true).expect("set scheduling options");
+            let suite_instance = builder
+                .add_suite(test_url, default_run_option())
+                .await
+                .expect("Cannot create suite instance");
+            let (run_events_result, _) =
+                futures::future::join(builder.run(), collect_suite_events(suite_instance)).await;
 
-        let num_debug_data_events = stream::iter(run_events_result.unwrap())
-            .then(|run_event| async move {
-                let TestRunEventPayload::DebugData { socket, .. } = run_event.payload;
-                let content = collect_string_from_socket(socket).await.unwrap();
-                content == "Debug data from test\n"
-            })
-            .filter(|matches_vmo| futures::future::ready(*matches_vmo))
-            .count()
-            .await;
-        assert_eq!(num_debug_data_events, iteration);
+            let num_debug_data_events = stream::iter(run_events_result.unwrap())
+                .then(|run_event| async move {
+                    let TestRunEventPayload::DebugData { socket, .. } = run_event.payload;
+                    let content = collect_string_from_socket(socket).await.unwrap();
+                    content == "Debug data from test\n"
+                })
+                .filter(|matches_vmo| futures::future::ready(*matches_vmo))
+                .count()
+                .await;
+            assert_eq!(num_debug_data_events, iteration);
+        }
     }
 
-    // If I run the same test again, also accumulating debug_data, I should see two files
+    // This is the new `SuiteRunner` test.
+    {
+        for iteration in 1usize..3 {
+            let runner = SuiteRunner::new(connect_suite_runner!().unwrap());
+            let suite_run_instance = runner
+                .start_suite_run(
+                    test_url,
+                    ftest_manager::RunSuiteOptions {
+                        run_disabled_tests: Some(false),
+                        accumulate_debug_data: Some(true),
+                        ..Default::default()
+                    },
+                )
+                .context("Cannot run suite")
+                .unwrap();
+            let suite_events_result =
+                collect_suite_events_with_watch(suite_run_instance, false).await;
+            let suite_events = suite_events_result.unwrap().0;
+
+            let debug_event_count = stream::iter(suite_events)
+                .then(|suite_event| async move {
+                    if let RunEvent::DebugData { filename, socket } = suite_event {
+                        if filename.starts_with("data_sink/data_sink.") {
+                            let content = collect_string_from_socket(socket).await.unwrap();
+                            assert_eq!(content, "Debug data from test\n");
+                            true
+                        } else {
+                            false
+                        }
+                    } else {
+                        false
+                    }
+                })
+                .filter(|matches_vmo| futures::future::ready(*matches_vmo))
+                .count()
+                .await;
+            // Add 2 here to account for the files left behind by the `TestBuilder` test above.
+            assert_eq!(debug_event_count, iteration + 2);
+        }
+    }
 }
 
 #[fuchsia::test]
@@ -882,3 +957,738 @@
     assert_eq!(logs, Vec::new());
     assert_eq!(&expected_events, &events);
 }
+
+#[fuchsia::test]
+async fn calling_kill_should_kill_test_for_suite() {
+    let runner = SuiteRunner::new(connect_suite_runner!().unwrap());
+    let suite_run_instance = runner
+        .start_suite_run(
+            "fuchsia-pkg://fuchsia.com/test_manager_test#meta/hanging_test.cm",
+            default_run_suite_options(),
+        )
+        .context("Cannot run suite")
+        .unwrap();
+    let (sender, mut recv) = mpsc::channel(1024);
+
+    let controller = suite_run_instance.controller();
+    let task = fasync::Task::spawn(async move {
+        suite_run_instance.collect_events_with_watch(sender, false).await
+    });
+    // let the test start
+    let _initial_event = recv.next().await.unwrap();
+    controller.kill().unwrap();
+    // collect rest of the events
+    let events = recv.collect::<Vec<_>>().await;
+    task.await.unwrap();
+    let events = events
+        .into_iter()
+        .filter_map(|e| match e.payload {
+            test_manager_test_lib::SuiteEventPayload::RunEvent(e) => Some(e),
+            _ => None,
+        })
+        .collect::<Vec<_>>();
+    // make sure that test never finished
+    for event in events {
+        match event {
+            RunEvent::SuiteStopped { .. } => {
+                panic!("should not receive SuiteStopped event as the test was killed. ")
+            }
+            _ => {}
+        }
+    }
+
+    drop(runner);
+}
+
+#[fuchsia::test]
+async fn calling_stop_should_stop_test_for_suite() {
+    let runner = SuiteRunner::new(connect_suite_runner!().unwrap());
+    let suite_run_instance = runner
+        .start_suite_run(
+            "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/huge_gtest.cm",
+            default_run_suite_options(),
+        )
+        .context("Cannot run suite")
+        .unwrap();
+    let (sender, mut recv) = mpsc::channel(1024);
+
+    let controller = suite_run_instance.controller();
+    let task = fasync::Task::spawn(async move {
+        suite_run_instance.collect_events_with_watch(sender, false).await
+    });
+    // let the test start
+    let _initial_event = recv.next().await.unwrap();
+    controller.stop().unwrap();
+    // collect rest of the events
+    let events = recv.collect::<Vec<_>>().await;
+    task.await.unwrap();
+    // get suite finished event
+    let events = events
+        .into_iter()
+        .filter_map(|e| match e.payload {
+            test_manager_test_lib::SuiteEventPayload::RunEvent(e) => match e {
+                RunEvent::SuiteStopped { .. } => Some(e),
+                _ => None,
+            },
+            _ => None,
+        })
+        .collect::<Vec<_>>();
+
+    assert_eq!(events, vec![RunEvent::suite_stopped(SuiteStatus::Stopped)]);
+}
+
+#[fuchsia::test]
+async fn launch_and_test_subpackaged_test_for_suite() {
+    let test_url =
+        "fuchsia-pkg://fuchsia.com/subpackaged_echo_integration_test_cpp#meta/default.cm";
+    let (events, logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("EchoIntegrationTest.TestEcho"),
+        RunEvent::case_started("EchoIntegrationTest.TestEcho"),
+        RunEvent::case_stopped("EchoIntegrationTest.TestEcho", CaseStatus::Passed),
+        RunEvent::case_finished("EchoIntegrationTest.TestEcho"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ];
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events.into_iter().filter(not_debug_data).collect::<Vec<_>>());
+
+    let test_url =
+        "fuchsia-pkg://fuchsia.com/subpackaged_echo_integration_test_rust#meta/default.cm";
+    let (events, logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("echo_integration_test"),
+        RunEvent::case_started("echo_integration_test"),
+        RunEvent::case_stopped("echo_integration_test", CaseStatus::Passed),
+        RunEvent::case_finished("echo_integration_test"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ];
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events.into_iter().filter(not_debug_data).collect::<Vec<_>>());
+}
+
+#[fuchsia::test]
+async fn launch_and_test_echo_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/echo_test_realm.cm";
+    let (events, logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("EchoTest"),
+        RunEvent::case_started("EchoTest"),
+        RunEvent::case_stopped("EchoTest", CaseStatus::Passed),
+        RunEvent::case_finished("EchoTest"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ];
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events.into_iter().filter(not_debug_data).collect::<Vec<_>>());
+}
+
+#[fuchsia::test]
+async fn launch_and_test_no_on_finished_for_suite() {
+    let test_url =
+        "fuchsia-pkg://fuchsia.com/test_manager_test#meta/no-onfinished-after-test-example.cm";
+
+    let (events, logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    let events = events.into_iter().filter(not_debug_data).group_by_test_case_unordered();
+
+    let test_cases = ["Example.Test1", "Example.Test2", "Example.Test3"];
+    let mut expected_events = vec![RunEvent::suite_started()];
+    for case in test_cases {
+        expected_events.push(RunEvent::case_found(case));
+        expected_events.push(RunEvent::case_started(case));
+
+        for i in 1..=3 {
+            expected_events.push(RunEvent::case_stdout(case, format!("log{} for {}", i, case)));
+        }
+        expected_events.push(RunEvent::case_stopped(case, CaseStatus::Passed));
+        expected_events.push(RunEvent::case_finished(case));
+    }
+    expected_events.push(RunEvent::suite_stopped(SuiteStatus::DidNotFinish));
+    let expected_events = expected_events.into_iter().group_by_test_case_unordered();
+
+    assert_eq!(&expected_events, &events);
+    assert_eq!(logs, Vec::new());
+}
+
+#[fuchsia::test]
+async fn launch_and_test_gtest_runner_sample_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
+
+    let (events, logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+    let events = events.into_iter().filter(not_debug_data).group_by_test_case_unordered();
+
+    let expected_events =
+        include!("../../../test_runners/gtest/test_data/sample_tests_golden_events.rsf")
+            .into_iter()
+            .group_by_test_case_unordered();
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events);
+}
+
+#[fuchsia::test]
+async fn launch_and_test_isolated_data_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/data_storage_test.cm";
+
+    let (events, _logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("test_data_storage"),
+        RunEvent::case_started("test_data_storage"),
+        RunEvent::case_stopped("test_data_storage", CaseStatus::Passed),
+        RunEvent::case_finished("test_data_storage"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ];
+
+    assert_eq!(&expected_events, &events.into_iter().filter(not_debug_data).collect::<Vec<_>>());
+}
+
+#[fuchsia::test]
+async fn positive_filter_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
+    let mut options = default_run_suite_options();
+    options.test_case_filters =
+        Some(vec!["SampleTest2.SimplePass".into(), "SampleFixture*".into()]);
+    let (events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+    let events = events.into_iter().filter(not_debug_data).group_by_test_case_unordered();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("SampleTest2.SimplePass"),
+        RunEvent::case_started("SampleTest2.SimplePass"),
+        RunEvent::case_stopped("SampleTest2.SimplePass", CaseStatus::Passed),
+        RunEvent::case_finished("SampleTest2.SimplePass"),
+        RunEvent::case_found("SampleFixture.Test1"),
+        RunEvent::case_started("SampleFixture.Test1"),
+        RunEvent::case_stopped("SampleFixture.Test1", CaseStatus::Passed),
+        RunEvent::case_finished("SampleFixture.Test1"),
+        RunEvent::case_found("SampleFixture.Test2"),
+        RunEvent::case_started("SampleFixture.Test2"),
+        RunEvent::case_stopped("SampleFixture.Test2", CaseStatus::Passed),
+        RunEvent::case_finished("SampleFixture.Test2"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ]
+    .into_iter()
+    .group_by_test_case_unordered();
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events);
+}
+
+#[fuchsia::test]
+async fn negative_filter_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
+    let mut options = default_run_suite_options();
+    options.test_case_filters = Some(vec![
+        "-SampleTest1.*".into(),
+        "-Tests/SampleParameterizedTestFixture.*".into(),
+        "-SampleDisabled.*".into(),
+        "-WriteToStd.*".into(),
+    ]);
+    let (events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+    let events = events.into_iter().filter(not_debug_data).group_by_test_case_unordered();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("SampleTest2.SimplePass"),
+        RunEvent::case_started("SampleTest2.SimplePass"),
+        RunEvent::case_stopped("SampleTest2.SimplePass", CaseStatus::Passed),
+        RunEvent::case_finished("SampleTest2.SimplePass"),
+        RunEvent::case_found("SampleFixture.Test1"),
+        RunEvent::case_started("SampleFixture.Test1"),
+        RunEvent::case_stopped("SampleFixture.Test1", CaseStatus::Passed),
+        RunEvent::case_finished("SampleFixture.Test1"),
+        RunEvent::case_found("SampleFixture.Test2"),
+        RunEvent::case_started("SampleFixture.Test2"),
+        RunEvent::case_stopped("SampleFixture.Test2", CaseStatus::Passed),
+        RunEvent::case_finished("SampleFixture.Test2"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ]
+    .into_iter()
+    .group_by_test_case_unordered();
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events);
+}
+
+#[fuchsia::test]
+async fn positive_and_negative_filter_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
+    let mut options = default_run_suite_options();
+    options.test_case_filters =
+        Some(vec!["SampleFixture.*".into(), "SampleTest2.*".into(), "-*Test1".into()]);
+    let (events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+    let events = events.into_iter().filter(not_debug_data).group_by_test_case_unordered();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("SampleTest2.SimplePass"),
+        RunEvent::case_started("SampleTest2.SimplePass"),
+        RunEvent::case_stopped("SampleTest2.SimplePass", CaseStatus::Passed),
+        RunEvent::case_finished("SampleTest2.SimplePass"),
+        RunEvent::case_found("SampleFixture.Test2"),
+        RunEvent::case_started("SampleFixture.Test2"),
+        RunEvent::case_stopped("SampleFixture.Test2", CaseStatus::Passed),
+        RunEvent::case_finished("SampleFixture.Test2"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ]
+    .into_iter()
+    .group_by_test_case_unordered();
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events);
+}
+
+#[fuchsia::test]
+async fn parallel_tests_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
+    let mut options = default_run_suite_options();
+    options.max_concurrent_test_case_runs = Some(10);
+    let (events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+    let events = events.into_iter().filter(not_debug_data).group_by_test_case_unordered();
+
+    let expected_events =
+        include!("../../../test_runners/gtest/test_data/sample_tests_golden_events.rsf")
+            .into_iter()
+            .group_by_test_case_unordered();
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events);
+}
+
+#[fuchsia::test]
+async fn no_suite_service_test_for_suite() {
+    let runner = SuiteRunner::new(connect_suite_runner!().unwrap());
+    let suite_run_instance = runner
+        .start_suite_run(
+            "fuchsia-pkg://fuchsia.com/test_manager_test#meta/no_suite_service.cm",
+            default_run_suite_options(),
+        )
+        .context("Cannot run suite")
+        .unwrap();
+    let (sender, _recv) = mpsc::channel(1024);
+    let err = suite_run_instance
+        .collect_events(sender)
+        .await
+        .expect_err("this should return instance not found error");
+    let err = err.downcast::<test_manager_test_lib::SuiteLaunchError>().unwrap();
+    // as test doesn't expose suite service, enumeration of test cases will fail.
+    assert_eq!(err, test_manager_test_lib::SuiteLaunchError::CaseEnumeration);
+}
+
+#[fuchsia::test]
+async fn test_not_resolved_for_suite() {
+    let runner = SuiteRunner::new(connect_suite_runner!().unwrap());
+    let suite_run_instance = runner
+        .start_suite_run(
+            "fuchsia-pkg://fuchsia.com/test_manager_test#meta/invalid_cml.cm",
+            default_run_suite_options(),
+        )
+        .context("Cannot run suite")
+        .unwrap();
+    let (sender, _recv) = mpsc::channel(1024);
+    let err = suite_run_instance
+        .collect_events(sender)
+        .await
+        .expect_err("this should return instance not found error");
+    let err = err.downcast::<test_manager_test_lib::SuiteLaunchError>().unwrap();
+    assert_eq!(err, test_manager_test_lib::SuiteLaunchError::InstanceCannotResolve);
+}
+
+#[fuchsia::test]
+async fn collect_isolated_logs_using_default_log_iterator_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
+    let (_events, logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    assert_eq!(
+        logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
+        vec!["Started diagnostics publisher", "Finishing through Stop"],
+        "{logs:#?}",
+    );
+}
+
+#[fuchsia::test]
+async fn collect_isolated_logs_from_generated_component_manifest_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/logger-test-generated-manifest.cm";
+    let (_events, logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    assert_eq!(
+        logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
+        vec!["I'm a info log from a test"],
+        "{logs:#?}",
+    );
+}
+
+#[fuchsia::test]
+async fn collect_isolated_logs_using_batch_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
+    let mut options = default_run_suite_options();
+    options.logs_iterator_type = Some(ftest_manager::LogsIteratorType::Batch);
+    let (_events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+
+    assert_eq!(
+        logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
+        vec!["Started diagnostics publisher", "Finishing through Stop"],
+        "{logs:#?}",
+    );
+}
+
+#[fuchsia::test]
+async fn collect_isolated_logs_using_archive_iterator_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
+    let options = RunSuiteOptions {
+        logs_iterator_type: Some(ftest_manager::LogsIteratorType::Socket),
+        ..default_run_suite_options()
+    };
+    let (_events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+
+    assert_eq!(
+        logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
+        vec!["Started diagnostics publisher", "Finishing through Stop"],
+        "{logs:#?}",
+    );
+}
+
+#[fuchsia::test]
+async fn collect_isolated_logs_using_host_socket_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
+    let options = RunSuiteOptions {
+        logs_iterator_type: Some(ftest_manager::LogsIteratorType::Socket),
+        ..default_run_suite_options()
+    };
+    let (_events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+
+    assert_eq!(
+        logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
+        vec!["Started diagnostics publisher", "Finishing through Stop"],
+        "{logs:#?}",
+    );
+}
+
+#[fuchsia::test]
+async fn update_log_severity_for_all_components_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
+    let options = RunSuiteOptions {
+        logs_iterator_type: Some(ftest_manager::LogsIteratorType::Socket),
+        log_interest: Some(vec![
+            selectors::parse_log_interest_selector_or_severity("DEBUG").unwrap()
+        ]),
+        ..default_run_suite_options()
+    };
+    let (_events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+    assert_eq!(
+        logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
+        vec![
+            "I'm a debug log from a test",
+            "Started diagnostics publisher",
+            "I'm a debug log from the publisher!",
+            "Finishing through Stop",
+        ]
+    );
+}
+
+#[fuchsia::test]
+async fn update_log_severity_for_the_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
+    let options = RunSuiteOptions {
+        logs_iterator_type: Some(ftest_manager::LogsIteratorType::Socket),
+        log_interest: Some(vec![selectors::parse_log_interest_selector_or_severity(
+            "<root>#DEBUG",
+        )
+        .unwrap()]),
+        ..default_run_suite_options()
+    };
+    let (_events, logs) = run_single_test_for_suite(test_url, options).await.unwrap();
+    assert_eq!(
+        logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
+        vec![
+            "I'm a debug log from a test",
+            "Started diagnostics publisher",
+            "Finishing through Stop",
+        ]
+    );
+}
+
+#[fuchsia::test]
+async fn custom_artifact_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/custom_artifact_user.cm";
+
+    let (events, _) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+    let events = events.into_iter().filter(not_debug_data).group_by_test_case_unordered();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("use_artifact"),
+        RunEvent::case_started("use_artifact"),
+        RunEvent::case_stopped("use_artifact", CaseStatus::Passed),
+        RunEvent::case_finished("use_artifact"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+        RunEvent::suite_custom(".", "artifact.txt", "Hello, world!"),
+    ]
+    .into_iter()
+    .group_by_test_case_unordered();
+
+    assert_eq!(&expected_events, &events);
+}
+
+#[fuchsia::test]
+async fn debug_data_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/debug_data_write_test.cm";
+
+    let runner = SuiteRunner::new(connect_suite_runner!().unwrap());
+    let suite_run_instance = runner
+        .start_suite_run(test_url, default_run_suite_options())
+        .context("Cannot run suite")
+        .unwrap();
+    let suite_events_result = collect_suite_events_with_watch(suite_run_instance, false).await;
+    let suite_events = suite_events_result.unwrap().0;
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("publish_debug_data"),
+        RunEvent::case_started("publish_debug_data"),
+        RunEvent::case_stopped("publish_debug_data", CaseStatus::Passed),
+        RunEvent::case_finished("publish_debug_data"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ];
+
+    // Split `suite_events` into `DebugData` events and others.
+    let mut debug_data_events = vec![];
+    let suite_events: Vec<RunEvent> = suite_events
+        .into_iter()
+        .filter_map(|e| {
+            if let RunEvent::DebugData { .. } = e {
+                debug_data_events.push(e);
+                None
+            } else {
+                Some(e)
+            }
+        })
+        .collect();
+
+    // Verify the `DebugData` events.
+    let got_summary = false;
+    let got_data_sink = false;
+    stream::iter(debug_data_events).for_each(|debug_data_event| async move {
+        if let RunEvent::DebugData { filename, socket } = debug_data_event {
+            if filename == "summary.json" {
+                assert!(!got_summary, "received summary.json DebugData more than once");
+                let content = collect_string_from_socket(socket).await.unwrap();
+                assert_eq!(content[..150], r#"{"tests":[{"name":"fuchsia-pkg://fuchsia.com/test_manager_test#meta/debug_data_write_test.cm","data_sinks":{"data_sink":[{"file":"data_sink/data_sink."#[..150]);
+            } else if filename.starts_with("data_sink/data_sink.") {
+                assert!(!got_data_sink, "received data sink DebugData more than once");
+                let content = collect_string_from_socket(socket).await.unwrap();
+                assert_eq!(content, "Debug data from test\n");
+            }
+        }
+    }).await;
+
+    // Verify the other events.
+    assert_eq!(
+        suite_events.into_iter().group_by_test_case_unordered(),
+        expected_events.into_iter().group_by_test_case_unordered(),
+    );
+}
+
+// Test that we can hook up DebugDataIterator connection for EarlyBootPrfile.
+#[fuchsia::test]
+async fn early_boot_profile_test_for_suite() {
+    let proxy = client::connect_to_protocol::<ftest_manager::EarlyBootProfileMarker>()
+        .expect("cannot connect to run builder proxy");
+    let (debug_data_proxy, iterator) = endpoints::create_proxy().unwrap();
+    proxy.register_watcher(iterator).unwrap();
+
+    // We cannot check the returned value as it can be empty vector or bunch of socket connections.
+    // But we can check that our call to DebugDataIterator goes through.
+    let _ = debug_data_proxy.get_next().await.unwrap();
+}
+
+#[fuchsia::test]
+async fn debug_data_isolated_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/debug_data_write_test.cm";
+
+    // By default, when I run the same test twice, debug data is not accumulated.
+    for _ in 0..2 {
+        let runner = SuiteRunner::new(connect_suite_runner!().unwrap());
+        let suite_run_instance = runner
+            .start_suite_run(test_url, default_run_suite_options())
+            .context("Cannot run suite")
+            .unwrap();
+        let suite_events_result = collect_suite_events_with_watch(suite_run_instance, false).await;
+        let suite_events = suite_events_result.unwrap().0;
+
+        let debug_event_count = stream::iter(suite_events)
+            .then(|suite_event| async move {
+                if let RunEvent::DebugData { filename, socket } = suite_event {
+                    if filename.starts_with("data_sink/data_sink.") {
+                        let content = collect_string_from_socket(socket).await.unwrap();
+                        assert_eq!(content, "Debug data from test\n");
+                        true
+                    } else {
+                        false
+                    }
+                } else {
+                    false
+                }
+            })
+            .filter(|matches_vmo| futures::future::ready(*matches_vmo))
+            .count()
+            .await;
+        assert_eq!(debug_event_count, 1);
+    }
+}
+
+#[fuchsia::test]
+async fn custom_artifact_realm_test_for_suite() {
+    let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/custom_artifact_realm_test.cm";
+
+    let (events, _) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+    let events = events.into_iter().filter(not_debug_data).group_by_test_case_unordered();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("use_artifact"),
+        RunEvent::case_started("use_artifact"),
+        RunEvent::case_stopped("use_artifact", CaseStatus::Passed),
+        RunEvent::case_finished("use_artifact"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+        RunEvent::suite_custom("test_driver", "artifact.txt", "Hello, world!"),
+    ]
+    .into_iter()
+    .group_by_test_case_unordered();
+
+    assert_eq!(&expected_events, &events);
+}
+
+#[fuchsia::test]
+async fn enumerate_invalid_test_for_suite() {
+    let proxy = connect_test_case_enumerator_server!().unwrap();
+    let (_iterator, server_end) = endpoints::create_proxy().unwrap();
+    let err = proxy
+        .enumerate(
+            "fuchsia-pkg://fuchsia.com/test_manager_test#meta/invalid_cml.cm",
+            ftest_manager::EnumerateTestCasesOptions { ..Default::default() },
+            server_end,
+        )
+        .await
+        .unwrap()
+        .expect_err("This should error out as we have invalid test");
+    assert_eq!(err, ftest_manager::LaunchError::InstanceCannotResolve);
+}
+
+#[fuchsia::test]
+async fn enumerate_echo_test_for_suite() {
+    let proxy = connect_test_case_enumerator_server!().unwrap();
+    let (iterator, server_end) = endpoints::create_proxy().unwrap();
+    proxy
+        .enumerate(
+            "fuchsia-pkg://fuchsia.com/test_manager_test#meta/echo_test_realm.cm",
+            ftest_manager::EnumerateTestCasesOptions { ..Default::default() },
+            server_end,
+        )
+        .await
+        .unwrap()
+        .expect("This should not fail");
+
+    let mut cases = vec![];
+    loop {
+        let mut c = iterator.get_next().await.unwrap();
+        if c.is_empty() {
+            break;
+        }
+        cases.append(&mut c);
+    }
+    assert_eq!(
+        cases.into_iter().map(|c| c.name.unwrap()).collect::<Vec<_>>(),
+        vec!["EchoTest".to_string()]
+    );
+}
+
+#[fuchsia::test]
+async fn enumerate_huge_test_for_suite() {
+    let proxy = connect_test_case_enumerator_server!().unwrap();
+    let (iterator, server_end) = endpoints::create_proxy().unwrap();
+    proxy
+        .enumerate(
+            "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/huge_gtest.cm",
+            ftest_manager::EnumerateTestCasesOptions { ..Default::default() },
+            server_end,
+        )
+        .await
+        .unwrap()
+        .expect("This should not fail");
+
+    let mut cases = vec![];
+    loop {
+        let mut c = iterator.get_next().await.unwrap();
+        if c.is_empty() {
+            break;
+        }
+        cases.append(&mut c);
+    }
+    let expected_cases = (0..=999)
+        .into_iter()
+        .map(|n| format!("HugeStress/HugeTest.Test/{}", n))
+        .collect::<Vec<_>>();
+
+    assert_eq!(cases.into_iter().map(|c| c.name.unwrap()).collect::<Vec<_>>(), expected_cases);
+}
+
+#[fuchsia::test]
+async fn capability_access_test_for_suite() {
+    let test_url =
+        "fuchsia-pkg://fuchsia.com/test_manager_test#meta/nonhermetic_capability_test.cm";
+    let (events, _) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    let failed_suite = RunEvent::suite_stopped(SuiteStatus::Failed);
+
+    assert!(events.contains(&failed_suite));
+}
+
+#[fuchsia::test]
+async fn launch_chromium_test_for_suite() {
+    // TODO(91934): This test is launched in the chromium realm. Once we support out of tree realm
+    // definitions we should move the definition and test to chromium.
+    let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/simple_chromium_realm_test.cm";
+    let (events, logs) =
+        run_single_test_for_suite(test_url, default_run_suite_options()).await.unwrap();
+
+    let expected_events = vec![
+        RunEvent::suite_started(),
+        RunEvent::case_found("noop_test"),
+        RunEvent::case_started("noop_test"),
+        RunEvent::case_stopped("noop_test", CaseStatus::Passed),
+        RunEvent::case_finished("noop_test"),
+        RunEvent::suite_stopped(SuiteStatus::Passed),
+    ];
+
+    assert_eq!(logs, Vec::new());
+    assert_eq!(&expected_events, &events.into_iter().filter(not_debug_data).collect::<Vec<_>>());
+}
+
+fn not_debug_data(event: &RunEvent) -> bool {
+    match event {
+        RunEvent::DebugData { .. } => false,
+        _ => true,
+    }
+}
diff --git a/src/sys/test_runners/gtest/tests/tests.rs b/src/sys/test_runners/gtest/tests/tests.rs
index cbd6c4c..aedb64b 100644
--- a/src/sys/test_runners/gtest/tests/tests.rs
+++ b/src/sys/test_runners/gtest/tests/tests.rs
@@ -10,7 +10,6 @@
     ftest_manager::{CaseStatus, SuiteStatus},
     maplit::hashset,
     pretty_assertions::assert_eq,
-    std::collections::HashSet,
     test_manager_test_lib::{GroupRunEventByTestCase, RunEvent},
 };
 
@@ -107,7 +106,7 @@
     ]
     .into_iter()
     .group();
-    let expected_fail_events = hashset![
+    let mut expected_fail_events = hashset![
         RunEvent::case_found("SampleDisabled.DISABLED_TestFail"),
         RunEvent::case_started("SampleDisabled.DISABLED_TestFail"),
         RunEvent::case_stopped("SampleDisabled.DISABLED_TestFail", CaseStatus::Failed),
@@ -135,18 +134,14 @@
     assert_eq!(actual_pass_events, &expected_pass_events);
 
     // Not going to check all of the exact log events.
-    let actual_fail_events = HashSet::from_iter(
-        events
-            .get(&Some("SampleDisabled.DISABLED_TestFail".to_string()))
-            .unwrap()
-            .non_artifact_events
-            .clone(),
-    );
-    assert!(
-        actual_fail_events.is_superset(&expected_fail_events),
-        "actual_fail_events: {:?}",
-        &actual_fail_events
-    );
+    for e in &events
+        .get(&Some("SampleDisabled.DISABLED_TestFail".to_string()))
+        .unwrap()
+        .non_artifact_events
+    {
+        assert!(expected_fail_events.remove(&e), "unexpected fail event {:?}", e);
+    }
+    assert!(expected_fail_events.len() == 0, "missing fail events {:?}", expected_fail_events);
 
     let actual_skip_events = events.get(&Some("SampleDisabled.DynamicSkip".to_string())).unwrap();
     assert_eq!(actual_skip_events, &expected_skip_events);
diff --git a/src/sys/test_runners/gunit/tests/tests.rs b/src/sys/test_runners/gunit/tests/tests.rs
index 5137f19..fbbc360 100644
--- a/src/sys/test_runners/gunit/tests/tests.rs
+++ b/src/sys/test_runners/gunit/tests/tests.rs
@@ -137,7 +137,7 @@
     ]
     .into_iter()
     .group();
-    let expected_fail_events = hashset![
+    let mut expected_fail_events = hashset![
         RunEvent::case_found("SampleDisabled.DISABLED_TestFail"),
         RunEvent::case_started("SampleDisabled.DISABLED_TestFail"),
         RunEvent::case_stopped("SampleDisabled.DISABLED_TestFail", CaseStatus::Failed),
@@ -165,18 +165,14 @@
     assert_eq!(actual_pass_events, &expected_pass_events);
 
     // Not going to check all of the exact log events.
-    let actual_fail_events = HashSet::from_iter(
-        events
-            .get(&Some("SampleDisabled.DISABLED_TestFail".to_string()))
-            .unwrap()
-            .non_artifact_events
-            .clone(),
-    );
-    assert!(
-        actual_fail_events.is_superset(&expected_fail_events),
-        "actual_fail_events: {:?}",
-        &actual_fail_events
-    );
+    for e in &events
+        .get(&Some("SampleDisabled.DISABLED_TestFail".to_string()))
+        .unwrap()
+        .non_artifact_events
+    {
+        assert!(expected_fail_events.remove(&e), "unexpected fail event {:?}", e);
+    }
+    assert!(expected_fail_events.len() == 0, "missing fail events {:?}", expected_fail_events);
 
     let actual_skip_events = events.get(&Some("SampleDisabled.DynamicSkip".to_string())).unwrap();
     assert_eq!(actual_skip_events, &expected_skip_events);
diff --git a/src/sys/test_runners/src/test_lib.rs b/src/sys/test_runners/src/test_lib.rs
index e3bb940..8c4e30f 100644
--- a/src/sys/test_runners/src/test_lib.rs
+++ b/src/sys/test_runners/src/test_lib.rs
@@ -220,6 +220,9 @@
             test_manager_test_lib::SuiteEventPayload::TestCaseLog { .. } => {
                 panic!("not supported yet!")
             }
+            test_manager_test_lib::SuiteEventPayload::DebugData { .. } => {
+                panic!("not supported yet!")
+            }
         }
     }
     execution_task.await.context("test execution failed")?;
diff --git a/src/sys/testing/meta/system-tests.shard.cml b/src/sys/testing/meta/system-tests.shard.cml
index 83e6330..aab45b8 100644
--- a/src/sys/testing/meta/system-tests.shard.cml
+++ b/src/sys/testing/meta/system-tests.shard.cml
@@ -52,6 +52,7 @@
                 "fuchsia.boot.RootResource",
                 "fuchsia.exception.Handler",
                 "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.DebugResource",
                 "fuchsia.kernel.EnergyInfoResource",
                 "fuchsia.kernel.FramebufferResource",
diff --git a/src/sys/testing/meta/test_realm.core_shard.cml b/src/sys/testing/meta/test_realm.core_shard.cml
index 31c4db3..a173878 100644
--- a/src/sys/testing/meta/test_realm.core_shard.cml
+++ b/src/sys/testing/meta/test_realm.core_shard.cml
@@ -196,6 +196,7 @@
             protocol: [
                 "fuchsia.boot.RootResource",
                 "fuchsia.kernel.CpuResource",
+                "fuchsia.kernel.DebuglogResource",
                 "fuchsia.kernel.DebugResource",
                 "fuchsia.kernel.EnergyInfoResource",
                 "fuchsia.kernel.FramebufferResource",
diff --git a/src/sys/time/timekeeper/src/clock_manager.rs b/src/sys/time/timekeeper/src/clock_manager.rs
index ab0608a..57f400c 100644
--- a/src/sys/time/timekeeper/src/clock_manager.rs
+++ b/src/sys/time/timekeeper/src/clock_manager.rs
@@ -446,9 +446,7 @@
     /// and applying the most appropriate strategy and recording diagnostic events.
     async fn apply_clock_correction(&mut self, estimate_transform: &Transform) {
         // Any pending clock updates will be superseded by the handling of this one.
-        if let Some(task) = self.delayed_updates.take() {
-            task.cancel().await;
-        };
+        self.delayed_updates = None;
 
         let current_transform = Transform::from(self.clock.as_ref());
         let mono = zx::Time::get_monotonic();
diff --git a/src/sys/tools/component/BUILD.gn b/src/sys/tools/component/BUILD.gn
index 401416c..10c9311 100644
--- a/src/sys/tools/component/BUILD.gn
+++ b/src/sys/tools/component/BUILD.gn
@@ -3,16 +3,21 @@
 # found in the LICENSE file.
 
 import("//build/assembly/bootfs_files_for_assembly.gni")
-import("//build/rust/rustc_binary.gni")
+import("//build/dist/renamed_binary.gni")
+import("//build/rust/rustc_library.gni")
 
-rustc_binary("component") {
-  visibility = [ ":*" ]
+# `component` is conceptually a binary, but it is built as a lib here so it can be
+# aggregated into //src/sys/tools/shared-multi-call-tool-binary to save disk space.
+rustc_library("component") {
+  visibility = [
+    ":*",
+    "../shared-multi-call-tool-binary:*",
+  ]
   edition = "2021"
 
   deps = [
     "//sdk/fidl/fuchsia.dash:fuchsia.dash_rust",
     "//sdk/fidl/fuchsia.sys2:fuchsia.sys2_rust",
-    "//src/lib/fuchsia",
     "//src/lib/fuchsia-component",
     "//src/lib/fuchsia-url",
     "//src/sys/lib/component_debug",
@@ -22,19 +27,24 @@
     "//third_party/rust_crates:argh",
   ]
 
-  # The component tool is only used in eng products, not production.
+  # The component tool is only used for debugging.
   deps += [ "//build/validate:non_production_tag" ]
 
-  # This binary is a part of the bootfs image, so attempt to minimize
-  # its size impact.
+  # This is a part of the bootfs image, so attempt to minimize its size impact.
   configs += [ "//build/config/rust:bootfs" ]
 
   sources = [
     "src/args.rs",
-    "src/main.rs",
+    "src/lib.rs",
   ]
 }
 
+renamed_binary("component-binary") {
+  source = "$root_out_dir/shared-multi-call-tool-binary"
+  source_deps = [ "//src/sys/tools/shared-multi-call-tool-binary" ]
+  dest = "bin/component"
+}
+
 bootfs_files_for_assembly("bootfs") {
-  deps = [ ":component" ]
+  deps = [ ":component-binary" ]
 }
diff --git a/src/sys/tools/component/src/main.rs b/src/sys/tools/component/src/lib.rs
similarity index 96%
rename from src/sys/tools/component/src/main.rs
rename to src/sys/tools/component/src/lib.rs
index 0acb541..8857944 100644
--- a/src/sys/tools/component/src/main.rs
+++ b/src/sys/tools/component/src/lib.rs
@@ -150,12 +150,3 @@
         },
     }
 }
-
-#[fuchsia::main(logging = false)]
-async fn main() {
-    #[allow(clippy::large_futures)]
-    if let Err(e) = exec().await {
-        eprintln!("{}", e);
-        std::process::exit(1);
-    }
-}
diff --git a/src/sys/tools/debug-dash-launcher/BUILD.gn b/src/sys/tools/debug-dash-launcher/BUILD.gn
index db9c95c..01952a1 100644
--- a/src/sys/tools/debug-dash-launcher/BUILD.gn
+++ b/src/sys/tools/debug-dash-launcher/BUILD.gn
@@ -36,6 +36,7 @@
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:futures",
     "//third_party/rust_crates:indexmap",
+    "//third_party/rust_crates:thiserror",
     "//third_party/rust_crates:tracing",
   ]
 
diff --git a/src/sys/tools/debug-dash-launcher/src/launch/package.rs b/src/sys/tools/debug-dash-launcher/src/launch/package.rs
index 631c1c6..3833a53 100644
--- a/src/sys/tools/debug-dash-launcher/src/launch/package.rs
+++ b/src/sys/tools/debug-dash-launcher/src/launch/package.rs
@@ -54,7 +54,10 @@
     command: Option<String>,
 ) -> Result<zx::Process, fdash::LauncherError> {
     let package_resolver = crate::package_resolver::PackageResolver::new(fuchsia_pkg_resolver)?;
-    let dir = package_resolver.resolve_subpackage(url, subpackages).await?;
+    let dir = package_resolver
+        .resolve_subpackage(url, subpackages)
+        .await
+        .map_err(|e| e.while_resolving_package_to_explore())?;
 
     // Add all the necessary entries, except for the tools, into the dash namespace.
     let name_infos =
diff --git a/src/sys/tools/debug-dash-launcher/src/package_resolver.rs b/src/sys/tools/debug-dash-launcher/src/package_resolver.rs
index 71c064e..7e05d6f 100644
--- a/src/sys/tools/debug-dash-launcher/src/package_resolver.rs
+++ b/src/sys/tools/debug-dash-launcher/src/package_resolver.rs
@@ -32,10 +32,7 @@
     }
 
     /// Resolves `url` and returns a proxy to the package directory.
-    pub(crate) async fn resolve(
-        &self,
-        url: &str,
-    ) -> Result<fio::DirectoryProxy, fdash::LauncherError> {
+    pub(crate) async fn resolve(&self, url: &str) -> Result<fio::DirectoryProxy, Error> {
         self.resolve_subpackage(url, &[]).await
     }
 
@@ -45,24 +42,16 @@
         &self,
         url: &str,
         subpackages: &[String],
-    ) -> Result<fio::DirectoryProxy, fdash::LauncherError> {
-        let (mut dir, server) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>()
-            .map_err(|_| fdash::LauncherError::Internal)?;
-        let mut context = self
-            .resolver
-            .resolve(url, server)
-            .await
-            .map_err(|_| fdash::LauncherError::Internal)?
-            .map_err(|_| fdash::LauncherError::PackageResolver)?;
+    ) -> Result<fio::DirectoryProxy, Error> {
+        let (mut dir, server) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>()?;
+        let mut context = self.resolver.resolve(url, server).await?.map_err(Error::Application)?;
         for subpackage in subpackages {
-            let (sub_dir, server) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>()
-                .map_err(|_| fdash::LauncherError::Internal)?;
+            let (sub_dir, server) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>()?;
             context = self
                 .resolver
                 .resolve_with_context(subpackage, &context, server)
-                .await
-                .map_err(|_| fdash::LauncherError::Internal)?
-                .map_err(|_| fdash::LauncherError::PackageResolver)?;
+                .await?
+                .map_err(Error::Application)?;
             dir = sub_dir;
         }
         Ok(dir)
@@ -74,6 +63,30 @@
     }
 }
 
+#[derive(thiserror::Error, Debug)]
+pub(crate) enum Error {
+    #[error("fuchsia.pkg/PackageResolver fidl error")]
+    Fidl(#[from] fidl::Error),
+
+    #[error("fuchsia.pkg/PackageResolver application error: {0:?}")]
+    Application(fpkg::ResolveError),
+}
+
+impl Error {
+    pub(crate) fn while_resolving_tool_package(self) -> fdash::LauncherError {
+        fdash::LauncherError::PackageResolver
+    }
+
+    pub(crate) fn while_resolving_package_to_explore(self) -> fdash::LauncherError {
+        match self {
+            Self::Application(fpkg::ResolveError::PackageNotFound) => {
+                fdash::LauncherError::ResolveTargetPackage
+            }
+            _ => fdash::LauncherError::PackageResolver,
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/sys/tools/debug-dash-launcher/src/trampoline.rs b/src/sys/tools/debug-dash-launcher/src/trampoline.rs
index eae89c9..f91304f 100644
--- a/src/sys/tools/debug-dash-launcher/src/trampoline.rs
+++ b/src/sys/tools/debug-dash-launcher/src/trampoline.rs
@@ -47,7 +47,10 @@
     let mut dirs: Vec<PkgDir> = vec![];
     for url in tool_urls {
         let (pkg_url, resource) = parse_url(&url)?;
-        let dir = package_resolver.resolve(&pkg_url.to_string()).await?;
+        let dir = package_resolver
+            .resolve(&pkg_url.to_string())
+            .await
+            .map_err(|e| e.while_resolving_tool_package())?;
         dirs.push(PkgDir { pkg_url, dir, resource });
     }
     Ok(dirs)
diff --git a/src/sys/tools/package/BUILD.gn b/src/sys/tools/package/BUILD.gn
new file mode 100644
index 0000000..837211d
--- /dev/null
+++ b/src/sys/tools/package/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/assembly/bootfs_files_for_assembly.gni")
+import("//build/dist/renamed_binary.gni")
+import("//build/rust/rustc_library.gni")
+
+# `package` is conceptually a binary, but it is built as a lib here so it can be
+# aggregated into //src/sys/tools/shared-multi-call-tool-binary to save disk space.
+rustc_library("package") {
+  visibility = [
+    ":*",
+    "../shared-multi-call-tool-binary:*",
+  ]
+  edition = "2021"
+
+  deps = [
+    "//sdk/fidl/fuchsia.dash:fuchsia.dash_rust",
+    "//src/lib/fidl/rust/fidl",
+    "//src/lib/fuchsia-component",
+    "//src/sys/lib/socket-to-stdio",
+    "//third_party/rust_crates:anyhow",
+    "//third_party/rust_crates:argh",
+    "//third_party/rust_crates:futures",
+  ]
+
+  # The package tool is only used for debugging.
+  deps += [ "//build/validate:non_production_tag" ]
+
+  # This is a part of the bootfs image, so attempt to minimize its size impact.
+  configs += [ "//build/config/rust:bootfs" ]
+
+  sources = [
+    "src/args.rs",
+    "src/lib.rs",
+  ]
+}
+
+renamed_binary("package-binary") {
+  source = "$root_out_dir/shared-multi-call-tool-binary"
+  source_deps = [ "//src/sys/tools/shared-multi-call-tool-binary" ]
+  dest = "bin/package"
+}
+
+bootfs_files_for_assembly("bootfs") {
+  deps = [ ":package-binary" ]
+}
diff --git a/src/sys/tools/package/METADATA.textproto b/src/sys/tools/package/METADATA.textproto
new file mode 100644
index 0000000..625c988
--- /dev/null
+++ b/src/sys/tools/package/METADATA.textproto
@@ -0,0 +1,15 @@
+# proto-file: tools/metadata/proto/metadata.proto
+# proto-message: Metadata
+# https://fuchsia.dev/fuchsia-src/development/source_code/metadata
+
+last_reviewed_date: {
+  year: 2024
+  month: 04
+  day: 12
+}
+
+trackers: {
+  issue_tracker: {
+    component_id: 1404422
+  }
+}
\ No newline at end of file
diff --git a/src/sys/tools/package/OWNERS b/src/sys/tools/package/OWNERS
new file mode 100644
index 0000000..b8e4aa9
--- /dev/null
+++ b/src/sys/tools/package/OWNERS
@@ -0,0 +1 @@
+include /src/sys/pkg/OWNERS
diff --git a/src/sys/tools/package/src/args.rs b/src/sys/tools/package/src/args.rs
new file mode 100644
index 0000000..d6f7446
--- /dev/null
+++ b/src/sys/tools/package/src/args.rs
@@ -0,0 +1,59 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use argh::FromArgs;
+use fidl_fuchsia_dash as fdash;
+
+#[derive(FromArgs, PartialEq, Debug)]
+#[argh(name = "package", description = "Interact with the packaging system.")]
+pub struct PackageArgs {
+    #[argh(subcommand)]
+    pub subcommand: PackageSubcommand,
+}
+
+#[derive(FromArgs, PartialEq, Debug)]
+#[argh(subcommand)]
+pub enum PackageSubcommand {
+    Explore(ExploreArgs),
+}
+
+#[derive(FromArgs, Debug, PartialEq)]
+#[argh(subcommand, name = "explore", description = "Same as `ffx target-package explore`")]
+pub struct ExploreArgs {
+    #[argh(positional)]
+    /// the package URL to resolve. If `subpackages` is empty the resolved package directory will
+    /// be loaded into the shell's namespace at `/pkg`.
+    pub url: String,
+
+    #[argh(option, long = "subpackage")]
+    /// the chain of subpackages, if any, of `url` to resolve, in resolution order.
+    /// If `subpackages` is not empty, the package directory of the final subpackage will be
+    /// loaded into the shell's namespace at `/pkg`.
+    pub subpackages: Vec<String>,
+
+    #[argh(option)]
+    /// list of URLs of tools packages to include in the shell environment.
+    /// the PATH variable will be updated to include binaries from these tools packages.
+    /// repeat `--tools url` for each package to be included.
+    /// The path preference is given by command line order.
+    pub tools: Vec<String>,
+
+    #[argh(option, short = 'c', long = "command")]
+    /// execute a command instead of reading from stdin.
+    /// the exit code of the command will be forwarded to the host.
+    pub command: Option<String>,
+
+    #[argh(option, default = "fdash::FuchsiaPkgResolver::Full", from_str_fn(parse_resolver))]
+    /// the resolver to use when resolving package URLs with scheme "fuchsia-pkg".
+    /// Possible values are "base" and "full". Defaults to "full".
+    pub fuchsia_pkg_resolver: fdash::FuchsiaPkgResolver,
+}
+
+fn parse_resolver(flag: &str) -> Result<fdash::FuchsiaPkgResolver, String> {
+    Ok(match flag {
+        "base" => fdash::FuchsiaPkgResolver::Base,
+        "full" => fdash::FuchsiaPkgResolver::Full,
+        _ => return Err("supported fuchsia-pkg resolvers are: 'base' and 'full'".into()),
+    })
+}
diff --git a/src/sys/tools/package/src/lib.rs b/src/sys/tools/package/src/lib.rs
new file mode 100644
index 0000000..6e3ee98
--- /dev/null
+++ b/src/sys/tools/package/src/lib.rs
@@ -0,0 +1,67 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use anyhow::{anyhow, Context as _};
+use fidl_fuchsia_dash as fdash;
+use fuchsia_component::client::connect_to_protocol;
+use futures::stream::StreamExt as _;
+
+mod args;
+
+pub async fn exec() -> anyhow::Result<()> {
+    let args: args::PackageArgs = argh::from_env();
+
+    match args.subcommand {
+        crate::args::PackageSubcommand::Explore(args) => {
+            // TODO(https://fxbug.dev/42177573): Verify that the optional Launcher protocol is
+            // available before connecting.
+            let dash_launcher = connect_to_protocol::<fdash::LauncherMarker>()?;
+            // TODO(https://fxbug.dev/42077838): Use Stdout::raw when a command is not provided.
+            let stdout = socket_to_stdio::Stdout::buffered();
+
+            #[allow(clippy::large_futures)]
+            explore_cmd(args, dash_launcher, stdout).await
+        }
+    }
+}
+
+async fn explore_cmd(
+    args: crate::args::ExploreArgs,
+    dash_launcher: fdash::LauncherProxy,
+    stdout: socket_to_stdio::Stdout<'_>,
+) -> anyhow::Result<()> {
+    let crate::args::ExploreArgs { url, subpackages, tools, command, fuchsia_pkg_resolver } = args;
+    let (client, server) = fidl::Socket::create_stream();
+    let () = dash_launcher
+        .explore_package_over_socket2(
+            fuchsia_pkg_resolver,
+            &url,
+            &subpackages,
+            server,
+            &tools,
+            command.as_deref(),
+        )
+        .await
+        .context("fuchsia.dash/Launcher.ExplorePackageOverSocket2 fidl error")?
+        .map_err(|e| match e {
+            fdash::LauncherError::ResolveTargetPackage => {
+                anyhow!("No package found matching '{url}' {}.", subpackages.join(" "))
+            }
+            e => anyhow!("Error exploring package: {e:?}"),
+        })?;
+
+    #[allow(clippy::large_futures)]
+    let () = socket_to_stdio::connect_socket_to_stdio(client, stdout).await?;
+
+    let exit_code = wait_for_shell_exit(&dash_launcher).await?;
+    std::process::exit(exit_code);
+}
+
+async fn wait_for_shell_exit(launcher_proxy: &fdash::LauncherProxy) -> anyhow::Result<i32> {
+    match launcher_proxy.take_event_stream().next().await {
+        Some(Ok(fdash::LauncherEvent::OnTerminated { return_code })) => Ok(return_code),
+        Some(Err(e)) => Err(anyhow!("OnTerminated event error: {e:?}")),
+        None => Err(anyhow!("didn't receive an expected OnTerminated event")),
+    }
+}
diff --git a/src/sys/tools/shared-multi-call-tool-binary/BUILD.gn b/src/sys/tools/shared-multi-call-tool-binary/BUILD.gn
new file mode 100644
index 0000000..0595216
--- /dev/null
+++ b/src/sys/tools/shared-multi-call-tool-binary/BUILD.gn
@@ -0,0 +1,34 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/components.gni")
+import("//build/rust/rustc_binary.gni")
+
+rustc_binary("shared-multi-call-tool-binary") {
+  visibility = [
+    ":*",
+    "../component:*",
+    "../package:*",
+  ]
+  edition = "2021"
+
+  deps = [
+    "//src/lib/fuchsia",
+    "//src/sys/tools/component",
+    "//src/sys/tools/package",
+    "//third_party/rust_crates:anyhow",
+    "//third_party/rust_crates:futures",
+  ]
+
+  # This is only used in eng products, not production.
+  deps += [ "//build/validate:non_production_tag" ]
+
+  sources = [ "src/main.rs" ]
+  configs += [
+    "//build/config/rust/lints:clippy_warn_all",
+
+    # This binary is a part of the bootfs image, so attempt to minimize its size impact.
+    "//build/config/rust:bootfs",
+  ]
+}
diff --git a/src/sys/tools/shared-multi-call-tool-binary/src/main.rs b/src/sys/tools/shared-multi-call-tool-binary/src/main.rs
new file mode 100644
index 0000000..525da66
--- /dev/null
+++ b/src/sys/tools/shared-multi-call-tool-binary/src/main.rs
@@ -0,0 +1,32 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use anyhow::anyhow;
+use futures::future::FutureExt as _;
+
+#[fuchsia::main(logging = false)]
+async fn main() {
+    match main_impl().await {
+        Ok(()) => (),
+        Err(e) => {
+            eprintln!("{e:#}");
+            std::process::exit(1);
+        }
+    }
+}
+
+async fn main_impl() -> anyhow::Result<()> {
+    let first_arg =
+        &std::env::args_os().next().ok_or_else(|| anyhow!("binary called without any args"))?;
+    match AsRef::<std::path::Path>::as_ref(first_arg)
+        .file_name()
+        .ok_or_else(|| anyhow!("first argument has no filename: {first_arg:?}"))?
+        .to_str()
+        .ok_or_else(|| anyhow!("first argument is not unicode: {first_arg:?}"))?
+    {
+        "component" => component::exec().boxed_local().await,
+        "package" => package::exec().boxed_local().await,
+        other => Err(anyhow!("no program registered for: {other}")),
+    }
+}
diff --git a/src/tee/runtime/BUILD.gn b/src/tee/runtime/BUILD.gn
index 3421c6d..b7af053 100644
--- a/src/tee/runtime/BUILD.gn
+++ b/src/tee/runtime/BUILD.gn
@@ -52,8 +52,21 @@
   component_name = "tee-runtime-test"
 }
 
+shared_library("ta_loader_test_missing_entry_points") {
+  sources = [ "ta_loader_tests/ta_create_entry_point.cc" ]
+}
+
+shared_library("ta_loader_test_complete") {
+  sources = [ "ta_loader_tests/ta_all_entry_points.cc" ]
+}
+
 fuchsia_test_package("tee-runtime-tests-package") {
   test_components = [ ":runtime-test-component" ]
+  package_name = "tee-runtime-tests"
+  deps = [
+    ":ta_loader_test_complete",
+    ":ta_loader_test_missing_entry_points",
+  ]
 }
 
 group("tests") {
diff --git a/src/tee/runtime/src/params.rs b/src/tee/runtime/src/params.rs
index 24f85bb..261ab4a 100644
--- a/src/tee/runtime/src/params.rs
+++ b/src/tee/runtime/src/params.rs
@@ -11,19 +11,29 @@
     TEE_PARAM_TYPE_VALUE_INOUT, TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_VALUE_OUTPUT,
 };
 
-struct BufferMapping {
-    vmo: zx::Vmo,
+struct Memref {
+    direction: ftee::Direction,
+    vmo: Option<zx::Vmo>,
+    offset: Option<u64>,
+    original_size: usize,
     mapped_address: usize,
     mapped_length: usize,
 }
 
-// TEEParams has logic for translating parameters for a trusted application from the
+enum ParamInfo {
+    None,
+    Memref(Memref),
+    Value(ftee::Direction),
+}
+
+// ParamAdapter has logic for translating parameters for a trusted application from the
 // FIDL format to the in-memory format used by the TA and back.
 // Translating between the FIDL and in-memory representations of buffer requires
 // memory mapping operations and is stateful. This type stores this state and cleans
 // it up when dropped.
-pub struct TEEParams {
-    mapped_buffers: Vec<BufferMapping>,
+pub struct ParamAdapter {
+    tee_params: [TEE_Param; 4],
+    infos: [ParamInfo; 4],
 }
 
 fn param_type(parameter: &ftee::Parameter) -> u32 {
@@ -49,60 +59,28 @@
     TEE_Param { value: TEE_Param__bindgen_ty_2 { a: 0, b: 0 } }
 }
 
-fn import_value_from_fidl(value: Value) -> Result<TEE_Param, Error> {
-    Ok(match value.direction {
-        Some(direction) => match direction {
-            Direction::Input | Direction::Inout => TEE_Param {
-                value: TEE_Param__bindgen_ty_2 {
-                    a: value.a.unwrap_or_default() as u32,
-                    b: value.b.unwrap_or_default() as u32,
+fn import_value_from_fidl(value: Value) -> Result<(TEE_Param, ParamInfo), Error> {
+    match value.direction {
+        Some(direction) => {
+            let tee_param = match direction {
+                Direction::Input | Direction::Inout => TEE_Param {
+                    value: TEE_Param__bindgen_ty_2 {
+                        a: value.a.unwrap_or_default() as u32,
+                        b: value.b.unwrap_or_default() as u32,
+                    },
                 },
-            },
-            Direction::Output => empty_tee_param(),
-        },
+                Direction::Output => empty_tee_param(),
+            };
+            Ok((tee_param, ParamInfo::Value(direction)))
+        }
         None => anyhow::bail!("Invalid direction"),
-    })
+    }
 }
 
-impl TEEParams {
-    pub fn new() -> Self {
-        Self { mapped_buffers: vec![] }
-    }
-
-    pub fn import_from_fidl(
-        &mut self,
-        parameters: Vec<ftee::Parameter>,
-    ) -> Result<(u32, Vec<TEE_Param>), Error> {
-        if parameters.len() > 4 {
-            anyhow::bail!("Expected 4 parameters in set but got {}", parameters.len());
-        }
-
-        let mut param_types = 0;
-        let mut param_shift = 0;
-        let mut params = vec![];
-        for param in parameters {
-            param_types |= param_type(&param) << param_shift;
-            param_shift += 4;
-            use fidl_fuchsia_tee::Parameter;
-            let param = match param {
-                Parameter::None(_) => empty_tee_param(),
-                Parameter::Buffer(buffer) => self.import_buffer_from_fidl(buffer)?,
-                Parameter::Value(value) => import_value_from_fidl(value)?,
-                ParameterUnknown!() => anyhow::bail!("Unexpected parameter type"),
-            };
-            params.push(param);
-        }
-        // 4.3.6.2 Initial Content of params Argument specifies that unset values must be filled with zeros.
-        // These entries do not affect the param_types value.
-        while params.len() < 4 {
-            params.push(empty_tee_param());
-        }
-        Ok((param_types, params))
-    }
-
-    fn import_buffer_from_fidl(&mut self, buffer: Buffer) -> Result<TEE_Param, Error> {
-        Ok(match buffer.direction {
-            Some(direction) => match direction {
+fn import_buffer_from_fidl(buffer: Buffer) -> Result<(TEE_Param, ParamInfo), Error> {
+    match buffer.direction {
+        Some(direction) => {
+            match direction {
                 Direction::Input | Direction::Inout => {
                     let vmo = buffer.vmo;
                     let mapped_length = match buffer.size {
@@ -113,7 +91,7 @@
                         None => anyhow::bail!("Missing offset"),
                         Some(offset) => offset,
                     };
-                    let addr = if let Some(vmo) = vmo {
+                    let (vmo, mapped_address, mapped_length) = if let Some(vmo) = vmo {
                         let flags = match direction {
                             Direction::Input => zx::VmarFlags::PERM_READ,
                             Direction::Inout => {
@@ -125,49 +103,161 @@
                             .map(0, &vmo, mapping_offset, mapped_length, flags)
                             .map_err(|e| anyhow::anyhow!("Unable to map VMO: {e:?}"))?;
 
-                        self.mapped_buffers.push(BufferMapping {
-                            vmo,
-                            mapped_address: addr,
-                            mapped_length,
-                        });
-                        addr
+                        (Some(vmo), addr, mapped_length)
                     } else {
                         // The VMO can be omitted meaning that no memory is
                         // mapped. This is useful for asking the TA to compute
                         // the size of a buffer needed for an operation. In this
                         // case, the null address is provided as the buffer
                         // address.
-                        0
+                        (None, 0, 0)
                     };
-                    TEE_Param {
-                        memref: TEE_Param__bindgen_ty_1 {
-                            buffer: addr as *mut std::os::raw::c_void,
-                            size: mapped_length,
+                    return Ok((
+                        TEE_Param {
+                            memref: TEE_Param__bindgen_ty_1 {
+                                buffer: mapped_address as *mut std::os::raw::c_void,
+                                size: mapped_length,
+                            },
                         },
-                    }
+                        ParamInfo::Memref(Memref {
+                            direction,
+                            vmo,
+                            offset: Some(mapping_offset),
+                            original_size: mapped_length,
+                            mapped_address,
+                            mapped_length,
+                        }),
+                    ));
                 }
-                Direction::Output => empty_tee_param(),
-            },
-            None => anyhow::bail!("Invalid direction"),
-        })
-    }
-
-    fn unmap_buffers(&mut self) {
-        for mapped_buffer in &self.mapped_buffers {
-            unsafe {
-                fuchsia_runtime::vmar_root_self()
-                    .unmap(mapped_buffer.mapped_address, mapped_buffer.mapped_length)
-                    .unwrap()
-            };
-            let _ = mapped_buffer.vmo;
+                Direction::Output => {
+                    return Ok((
+                        empty_tee_param(),
+                        ParamInfo::Memref(Memref {
+                            direction,
+                            vmo: None,
+                            offset: None,
+                            original_size: 0,
+                            mapped_address: 0,
+                            mapped_length: 0,
+                        }),
+                    ))
+                }
+            }
         }
-        self.mapped_buffers.clear();
+        None => anyhow::bail!("Invalid direction"),
     }
 }
 
-impl Drop for TEEParams {
-    fn drop(&mut self) {
-        self.unmap_buffers()
+impl ParamAdapter {
+    pub fn from_fidl(parameters: Vec<ftee::Parameter>) -> Result<(Self, u32), Error> {
+        if parameters.len() > 4 {
+            anyhow::bail!("Expected <= 4 parameters in set but got {}", parameters.len());
+        }
+
+        let mut param_types = 0;
+        // 4.3.6.2 Initial Content of params Argument specifies that unset values must be filled with zeros.
+        // These entries do not affect the param_types value.
+        let mut tee_params = [empty_tee_param(); 4];
+        let mut infos = [ParamInfo::None, ParamInfo::None, ParamInfo::None, ParamInfo::None];
+        let mut i = 0;
+        for param in parameters {
+            param_types |= param_type(&param) << (i * 4);
+            use fidl_fuchsia_tee::Parameter;
+            let (param, info) = match param {
+                Parameter::None(_) => (empty_tee_param(), ParamInfo::None),
+                Parameter::Buffer(buffer) => import_buffer_from_fidl(buffer)?,
+                Parameter::Value(value) => import_value_from_fidl(value)?,
+                ParameterUnknown!() => anyhow::bail!("Unexpected parameter type"),
+            };
+            tee_params[i] = param;
+            infos[i] = info;
+            i += 1;
+        }
+        Ok((Self { tee_params, infos }, param_types))
+    }
+
+    pub fn tee_params_mut<'a>(&'a mut self) -> &'a mut [TEE_Param; 4] {
+        &mut self.tee_params
+    }
+
+    // 4.3.6.3 Behavior of the Framework when the Trusted Application Returns
+    pub fn export_to_fidl(mut self) -> Result<Vec<ftee::Parameter>, Error> {
+        let mut ret = vec![];
+        for i in 0..4 {
+            ret.push(match &mut self.infos[i] {
+                ParamInfo::None => ftee::Parameter::None(ftee::None_),
+                ParamInfo::Value(direction) => match direction {
+                    Direction::Input => ftee::Parameter::None(ftee::None_),
+                    Direction::Inout | Direction::Output => {
+                        let tee_value = unsafe { self.tee_params[i].value };
+                        let a = Some(tee_value.a as u64);
+                        let b = Some(tee_value.b as u64);
+                        ftee::Parameter::Value(Value {
+                            direction: Some(*direction),
+                            a,
+                            b,
+                            c: None,
+                            ..Default::default()
+                        })
+                    }
+                },
+                ParamInfo::Memref(memref) => {
+                    unsafe {
+                        if memref.mapped_address != 0 {
+                            // If we mapped the buffer into our address space we need to unmap it.
+                            fuchsia_runtime::vmar_root_self()
+                                .unmap(memref.mapped_address, memref.mapped_length)
+                                .unwrap();
+                        }
+                    }
+                    match memref.direction {
+                        Direction::Input => ftee::Parameter::None(ftee::None_),
+                        Direction::Inout | Direction::Output => {
+                            // Table 4-9: Interpretation of params[i] when Trusted Application Entry Point Returns
+                            // The Framework reads params[i].memref.size:
+                            let tee_memref = unsafe { self.tee_params[i].memref };
+                            let size = tee_memref.size;
+                            if size > memref.original_size {
+                                // * If it is greater than the original value of size, it is considered
+                                // as a request for a larger buffer. In this case, the Framework
+                                // assumes that the Trusted Application has not written
+                                // anything in the buffer and no data will be synchronized.
+                                ftee::Parameter::Buffer(Buffer {
+                                    direction: Some(memref.direction),
+                                    vmo: None,
+                                    offset: memref.offset,
+                                    size: Some(size as u64),
+                                    ..Default::default()
+                                })
+                            } else {
+                                // * If it is equal or less than the original value of size, it is
+                                // considered as the actual size of the memory buffer. In this
+                                // case, the Framework assumes that the Trusted Application
+                                // has not written beyond this actual size and only this actual
+                                // size will be synchronized with the client.
+                                ftee::Parameter::Buffer(Buffer {
+                                    direction: Some(memref.direction),
+                                    vmo: memref.vmo.take(),
+                                    offset: memref.offset,
+                                    size: Some(size as u64),
+                                    ..Default::default()
+                                })
+                            }
+                        }
+                    }
+                }
+            })
+        }
+        // Remove trailing 'None' entries.
+        while !ret.is_empty() {
+            match ret.last() {
+                Some(ftee::Parameter::None(_)) => {
+                    let _ = ret.pop().unwrap();
+                }
+                _ => break,
+            }
+        }
+        Ok(ret)
     }
 }
 
@@ -176,25 +266,25 @@
     use super::*;
 
     #[fuchsia::test]
-    fn empty_fidl_parameters_to_tee_params() {
+    fn empty_fidl_parameters_to_tee_params() -> Result<(), Error> {
         let fidl_parameters = vec![];
 
-        let mut tee_params = TEEParams::new();
-
-        let (param_types, params) = tee_params.import_from_fidl(fidl_parameters).unwrap();
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(fidl_parameters)?;
 
         assert_eq!(param_types, 0);
-        assert_eq!(params.len(), 4);
+
+        let tee_params = adapter.tee_params_mut();
         for i in 0..4 {
             // Accessing the 'value' field of the parameter's union is unsafe as it
             // is a repr(C) union and carries no type information.
-            let value = unsafe { params[i].value };
+            let value = unsafe { tee_params[i].value };
             assert_eq!(value, TEE_Param__bindgen_ty_2 { a: 0, b: 0 });
         }
+        Ok(())
     }
 
     #[fuchsia::test]
-    fn too_many_fidl_parameters() {
+    fn too_many_fidl_parameters() -> Result<(), Error> {
         let fidl_parameters = vec![
             ftee::Parameter::Value(Value { ..Default::default() }),
             ftee::Parameter::Value(Value { ..Default::default() }),
@@ -203,13 +293,14 @@
             ftee::Parameter::Value(Value { ..Default::default() }),
         ];
 
-        let mut tee_params = TEEParams::new();
-        let result = tee_params.import_from_fidl(fidl_parameters);
+        let result = ParamAdapter::from_fidl(fidl_parameters);
+
         assert!(result.is_err());
+        Ok(())
     }
 
     #[fuchsia::test]
-    fn fidl_parameter_value_to_tee_params() {
+    fn fidl_parameter_value_to_tee_params() -> Result<(), Error> {
         let fidl_parameters = vec![ftee::Parameter::Value(Value {
             direction: Some(Direction::Input),
             a: Some(1),
@@ -217,24 +308,23 @@
             ..Default::default()
         })];
 
-        let mut tee_params = TEEParams::new();
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(fidl_parameters)?;
 
-        let (param_types, params) = tee_params.import_from_fidl(fidl_parameters).unwrap();
-
-        assert_eq!(params.len(), 4);
         assert_eq!(param_types, TEE_PARAM_TYPE_VALUE_INPUT);
+        let tee_params = adapter.tee_params_mut();
         // Accessing the 'value' field of the parameter's union is unsafe as it
         // is a repr(C) union and carries no type information.
-        let value = unsafe { params[0].value };
+        let value = unsafe { tee_params[0].value };
         assert_eq!(value, TEE_Param__bindgen_ty_2 { a: 1, b: 2 });
         for i in 1..4 {
-            let value = unsafe { params[i].value };
+            let value = unsafe { tee_params[i].value };
             assert_eq!(value, TEE_Param__bindgen_ty_2 { a: 0, b: 0 });
         }
+        Ok(())
     }
 
     #[fuchsia::test]
-    fn fidl_parameter_multiple_value_to_tee_params() {
+    fn fidl_parameter_multiple_value_to_tee_params() -> Result<(), Error> {
         let fidl_parameters = vec![
             ftee::Parameter::Value(Value {
                 direction: Some(Direction::Input),
@@ -250,25 +340,25 @@
             }),
         ];
 
-        let mut tee_params = TEEParams::new();
-
-        let (param_types, params) = tee_params.import_from_fidl(fidl_parameters).unwrap();
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(fidl_parameters)?;
 
         assert_eq!(param_types, TEE_PARAM_TYPE_VALUE_INPUT | (TEE_PARAM_TYPE_VALUE_INOUT << 4));
+        let tee_params = adapter.tee_params_mut();
         // Accessing the 'value' field of the parameter's union is unsafe as it
         // is a repr(C) union and carries no type information.
-        let value = unsafe { params[0].value };
+        let value = unsafe { tee_params[0].value };
         assert_eq!(value, TEE_Param__bindgen_ty_2 { a: 1, b: 2 });
-        let value = unsafe { params[1].value };
+        let value = unsafe { tee_params[1].value };
         assert_eq!(value, TEE_Param__bindgen_ty_2 { a: 3, b: 4 });
         for i in 2..4 {
-            let value = unsafe { params[i].value };
+            let value = unsafe { tee_params[i].value };
             assert_eq!(value, TEE_Param__bindgen_ty_2 { a: 0, b: 0 });
         }
+        Ok(())
     }
 
     #[fuchsia::test]
-    fn fidl_parameter_with_buffers() {
+    fn fidl_parameter_with_buffers() -> Result<(), Error> {
         let page_size = zx::system_get_page_size() as u64;
         let vmo1 = zx::Vmo::create(page_size).unwrap();
         vmo1.write(&[1, 2, 3, 4], 0).unwrap();
@@ -299,9 +389,7 @@
             }),
         ];
 
-        let mut tee_params = TEEParams::new();
-
-        let (param_types, params) = tee_params.import_from_fidl(fidl_parameters).unwrap();
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(fidl_parameters)?;
 
         assert_eq!(
             param_types,
@@ -309,28 +397,285 @@
                 | (TEE_PARAM_TYPE_MEMREF_INPUT << 4)
                 | (TEE_PARAM_TYPE_MEMREF_INOUT << 8)
         );
-        assert_eq!(params.len(), 4);
+        let tee_params = adapter.tee_params_mut();
         // Accessing the 'value' field of the parameter's union is unsafe as it
         // is a repr(C) union and carries no type information.
-        let value = unsafe { params[0].memref };
+        let value = unsafe { tee_params[0].memref };
         assert_eq!(value.size, page_size as usize);
         assert!(value.buffer != std::ptr::null_mut() as *mut std::os::raw::c_void);
         let memref_contents = unsafe { std::slice::from_raw_parts(value.buffer as *const u8, 4) };
         assert_eq!(memref_contents, &[1, 2, 3, 4]);
 
-        let value = unsafe { params[1].memref };
+        let value = unsafe { tee_params[1].memref };
         assert_eq!(value.size, 2 * page_size as usize);
         assert!(value.buffer != std::ptr::null_mut() as *mut std::os::raw::c_void);
         let memref_contents = unsafe { std::slice::from_raw_parts(value.buffer as *const u8, 4) };
         assert_eq!(memref_contents, &[5, 6, 7, 8]);
 
-        let value = unsafe { params[2].memref };
+        let value = unsafe { tee_params[2].memref };
         assert_eq!(value.size, 0);
         assert_eq!(value.buffer, std::ptr::null_mut() as *mut std::os::raw::c_void);
 
         for i in 3..4 {
-            let value = unsafe { params[i].value };
+            let value = unsafe { tee_params[i].value };
             assert_eq!(value, TEE_Param__bindgen_ty_2 { a: 0, b: 0 });
         }
+        Ok(())
+    }
+
+    #[fuchsia::test]
+    fn test_export_empty_to_fidl() -> Result<(), Error> {
+        let (adapter, param_types) = ParamAdapter::from_fidl(vec![])?;
+
+        assert_eq!(param_types, TEE_PARAM_TYPE_NONE);
+
+        let fidl_parameters = adapter.export_to_fidl()?;
+
+        assert!(fidl_parameters.is_empty());
+        Ok(())
+    }
+
+    #[fuchsia::test]
+    fn test_unchanged_value_directions() -> Result<(), Error> {
+        let fidl_parameters = vec![
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Input),
+                a: Some(1),
+                b: Some(2),
+                c: None,
+                ..Default::default()
+            }),
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Inout),
+                a: Some(3),
+                b: Some(4),
+                c: None,
+                ..Default::default()
+            }),
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Output),
+                a: None,
+                b: None,
+                c: None,
+                ..Default::default()
+            }),
+        ];
+        let (adapter, param_types) = ParamAdapter::from_fidl(fidl_parameters)?;
+
+        assert_eq!(
+            param_types,
+            TEE_PARAM_TYPE_VALUE_INPUT
+                | TEE_PARAM_TYPE_VALUE_INOUT << 4
+                | TEE_PARAM_TYPE_VALUE_OUTPUT << 8
+        );
+
+        let fidl_parameters = adapter.export_to_fidl()?;
+        assert_eq!(fidl_parameters.len(), 3);
+        assert_eq!(fidl_parameters[0], ftee::Parameter::None(ftee::None_));
+        assert_eq!(
+            fidl_parameters[1],
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Inout),
+                a: Some(3),
+                b: Some(4),
+                c: None,
+                ..Default::default()
+            })
+        );
+        assert_eq!(
+            fidl_parameters[2],
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Output),
+                a: Some(0),
+                b: Some(0),
+                c: None,
+                ..Default::default()
+            })
+        );
+
+        Ok(())
+    }
+
+    #[fuchsia::test]
+    fn test_export_changed_value_to_fidl() -> Result<(), Error> {
+        let fidl_parameters = vec![
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Inout),
+                a: Some(1),
+                b: Some(2),
+                c: None,
+                ..Default::default()
+            }),
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Output),
+                a: None,
+                b: None,
+                c: None,
+                ..Default::default()
+            }),
+        ];
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(fidl_parameters)?;
+
+        assert_eq!(param_types, TEE_PARAM_TYPE_VALUE_INOUT | TEE_PARAM_TYPE_VALUE_OUTPUT << 4);
+
+        let tee_params = adapter.tee_params_mut();
+        let value = unsafe { &mut tee_params[0].value };
+        value.a = 3;
+        value.b = 4;
+        let value = unsafe { &mut tee_params[1].value };
+        value.a = 5;
+        value.b = 6;
+
+        let fidl_parameters = adapter.export_to_fidl()?;
+
+        assert_eq!(fidl_parameters.len(), 2);
+        assert_eq!(
+            fidl_parameters[0],
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Inout),
+                a: Some(3),
+                b: Some(4),
+                c: None,
+                ..Default::default()
+            })
+        );
+        assert_eq!(
+            fidl_parameters[1],
+            ftee::Parameter::Value(Value {
+                direction: Some(Direction::Output),
+                a: Some(5),
+                b: Some(6),
+                c: None,
+                ..Default::default()
+            })
+        );
+
+        Ok(())
+    }
+
+    #[fuchsia::test]
+    fn test_export_changed_memref_to_fidl() -> Result<(), Error> {
+        // This test checks that we can provide a buffer with direction "INOUT" and modify the buffer's
+        // contents and size then translate that back to a FIDL response.
+        let page_size = zx::system_get_page_size() as u64;
+        let vmo = zx::Vmo::create(page_size).unwrap();
+        vmo.write(&[1, 2, 3], 0).unwrap();
+        let fidl_parameters = vec![ftee::Parameter::Buffer(Buffer {
+            direction: Some(Direction::Inout),
+            vmo: Some(vmo),
+            offset: Some(0),
+            size: Some(page_size),
+            ..Default::default()
+        })];
+
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(fidl_parameters)?;
+
+        assert_eq!(param_types, TEE_PARAM_TYPE_MEMREF_INOUT);
+
+        {
+            // This logic makes two modifications to the TEE_Param[4] representation of the buffer:
+            // 1. Writes the byte sequence [3, 4, 5] to the start of the buffer.
+            // 2. Sets the memref's "size" to 3 down from its initial value of page_size.
+            let tee_params = adapter.tee_params_mut();
+            let memref = unsafe { &mut tee_params[0].memref };
+            assert_eq!(memref.size, page_size as usize);
+            assert_ne!(memref.buffer, std::ptr::null_mut() as *mut std::ffi::c_void);
+
+            {
+                let mapped_buffer =
+                    unsafe { std::slice::from_raw_parts_mut(memref.buffer as *mut u8, 3) };
+                mapped_buffer.copy_from_slice(&[3, 4, 5]);
+            }
+            memref.size = 3;
+        }
+
+        let fidl_parameters = adapter.export_to_fidl()?;
+
+        assert_eq!(fidl_parameters.len(), 1);
+
+        if let ftee::Parameter::Buffer(buffer) = &fidl_parameters[0] {
+            // We expect to get back a buffer that has the byte sequence [3, 4, 5] at the start and
+            // a reported size of 3.
+            let mut read = [0u8; 3];
+            let _ = buffer.vmo.as_ref().unwrap().read(&mut read, 0).unwrap();
+            assert_eq!(read, [3, 4, 5]);
+            assert_eq!(buffer.direction, Some(Direction::Inout));
+            assert_eq!(buffer.offset, Some(0));
+            assert_eq!(buffer.size, Some(3));
+        } else {
+            assert!(
+                false,
+                "Expected a Buffer parameter but observed another type: {:?}",
+                &fidl_parameters[0]
+            );
+        }
+
+        Ok(())
+    }
+
+    #[fuchsia::test]
+    fn test_memref_size_increased() -> Result<(), Error> {
+        // This tests the behavior when a buffer's size is changed in the TEE_Param[4]
+        // representation to a larger value than was initially specified. According to the
+        // specification this pattern is used to let a TA indicate that an operation requires a
+        // larger buffer than was initially provided.  In this case no data is returned to the
+        // client but the larger size is returned with the expectation that the client will allocate
+        // a larger buffer and try again.
+        let page_size = zx::system_get_page_size() as u64;
+        let vmo = zx::Vmo::create(page_size).unwrap();
+        let fidl_parameters = vec![
+            ftee::Parameter::Buffer(Buffer {
+                direction: Some(Direction::Inout),
+                vmo: None,
+                offset: Some(0),
+                size: Some(0),
+                ..Default::default()
+            }),
+            ftee::Parameter::Buffer(Buffer {
+                direction: Some(Direction::Inout),
+                vmo: Some(vmo),
+                offset: Some(0),
+                size: Some(page_size),
+                ..Default::default()
+            }),
+        ];
+
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(fidl_parameters)?;
+
+        assert_eq!(param_types, TEE_PARAM_TYPE_MEMREF_INOUT | TEE_PARAM_TYPE_MEMREF_INOUT << 4);
+
+        {
+            let tee_params = adapter.tee_params_mut();
+            let memref = unsafe { &mut tee_params[0].memref };
+            // The first parameter is grown from 0 bytes to 12 bytes.
+            memref.size = 12;
+            let memref = unsafe { &mut tee_params[1].memref };
+            // The second parameter is grown from 1 page to 2 pages.
+            memref.size = 2 * page_size as usize;
+        }
+
+        let fidl_parameters = adapter.export_to_fidl()?;
+
+        assert_eq!(
+            fidl_parameters,
+            vec![
+                ftee::Parameter::Buffer(Buffer {
+                    direction: Some(Direction::Inout),
+                    vmo: None,
+                    offset: Some(0),
+                    size: Some(12),
+                    ..Default::default()
+                }),
+                ftee::Parameter::Buffer(Buffer {
+                    direction: Some(Direction::Inout),
+                    vmo: None,
+                    offset: Some(0),
+                    size: Some(2 * page_size),
+                    ..Default::default()
+                }),
+            ]
+        );
+
+        Ok(())
     }
 }
diff --git a/src/tee/runtime/src/ta_loader.rs b/src/tee/runtime/src/ta_loader.rs
index 5e2c411..a9478b2 100644
--- a/src/tee/runtime/src/ta_loader.rs
+++ b/src/tee/runtime/src/ta_loader.rs
@@ -106,3 +106,34 @@
         },
     })
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    // The C string literal syntax c"foo" isn't supported by #[fuchsia::test] so
+    // we use a helper function instead to construct &CStrs from literals.
+    // TODO(https://fxbug.dev/332964901): Remove this and use C-string literals
+    // once supported.
+    fn c_str<'a>(s: &'a [u8]) -> &'a std::ffi::CStr {
+        std::ffi::CStr::from_bytes_with_nul(s).unwrap()
+    }
+
+    #[fuchsia::test]
+    fn load_missing_so() {
+        let result = load_ta(c_str(b"libta_loader_test_missing.so\0"));
+        assert!(result.is_err());
+    }
+
+    #[fuchsia::test]
+    fn load_ta_missing_entry_points() {
+        let result = load_ta(c_str(b"libta_loader_test_missing_entry_points.so\0"));
+        assert!(result.is_err());
+    }
+
+    #[fuchsia::test]
+    fn load_ta_complete() {
+        let result = load_ta(c_str(b"libta_loader_test_complete.so\0"));
+        assert!(!result.is_err());
+    }
+}
diff --git a/src/tee/runtime/src/trusted_app.rs b/src/tee/runtime/src/trusted_app.rs
index a21d361..ca8db40 100644
--- a/src/tee/runtime/src/trusted_app.rs
+++ b/src/tee/runtime/src/trusted_app.rs
@@ -4,7 +4,7 @@
 
 use std::{collections::BTreeMap, ops::AddAssign};
 
-use crate::params::TEEParams;
+use crate::params::ParamAdapter;
 use crate::ta_loader::{SessionContext, TAInterface};
 use anyhow::Error;
 use fidl_fuchsia_tee::{OpResult, Parameter, ReturnOrigin};
@@ -42,11 +42,13 @@
         parameter_set: Vec<Parameter>,
     ) -> Result<(u32, OpResult), Error> {
         let mut session_context = std::ptr::null_mut();
-        let mut tee_params = TEEParams::new();
-        let (param_types, mut params) = tee_params.import_from_fidl(parameter_set)?;
-        let ta_result =
-            self.interface.open_session(param_types, params.as_mut_ptr(), &mut session_context);
-        let return_params = vec![]; // TODO: export 'params' to FIDL types to return to the caller.
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(parameter_set)?;
+        let ta_result = self.interface.open_session(
+            param_types,
+            adapter.tee_params_mut().as_mut_ptr(),
+            &mut session_context,
+        );
+        let return_params = adapter.export_to_fidl()?;
         let session_id = self.allocate_session_id();
         let _ = self.sessions.insert(session_id, session_context);
         let op_result = OpResult {
@@ -78,15 +80,14 @@
             Some(session_context) => session_context,
             None => anyhow::bail!("Invalid session id"),
         };
-        let mut tee_params = TEEParams::new();
-        let (param_types, mut params) = tee_params.import_from_fidl(parameter_set)?;
+        let (mut adapter, param_types) = ParamAdapter::from_fidl(parameter_set)?;
         let ta_result = self.interface.invoke_command(
             *session_context,
             command,
             param_types,
-            params.as_mut_ptr(),
+            adapter.tee_params_mut().as_mut_ptr(),
         );
-        let return_params = vec![]; // TODO: export 'params' to FIDL type to return to caller.
+        let return_params = adapter.export_to_fidl()?;
         let op_result = OpResult {
             return_code: Some(ta_result as u64),
             return_origin: Some(ReturnOrigin::TrustedApplication),
diff --git a/src/tee/runtime/ta_loader_tests/ta_all_entry_points.cc b/src/tee/runtime/ta_loader_tests/ta_all_entry_points.cc
new file mode 100644
index 0000000..43618f6
--- /dev/null
+++ b/src/tee/runtime/ta_loader_tests/ta_all_entry_points.cc
@@ -0,0 +1,23 @@
+// Copyright 2024 The Fuchsia Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <zircon/compiler.h>
+
+// This file exports all of the entry points that a TA is expected to export.
+// The signatures for these are not correct but the exported symbol contains
+// only a name so this doesn't matter for loading purposes.
+
+extern "C" {
+
+void __EXPORT TA_CreateEntryPoint() {}
+
+void __EXPORT TA_DestroyEntryPoint() {}
+
+void __EXPORT TA_OpenSessionEntryPoint() {}
+
+void __EXPORT TA_CloseSessionEntryPoint() {}
+
+void __EXPORT TA_InvokeCommandEntryPoint() {}
+
+}  // extern "C"
diff --git a/src/tee/runtime/ta_loader_tests/ta_create_entry_point.cc b/src/tee/runtime/ta_loader_tests/ta_create_entry_point.cc
new file mode 100644
index 0000000..cf4f06c
--- /dev/null
+++ b/src/tee/runtime/ta_loader_tests/ta_create_entry_point.cc
@@ -0,0 +1,15 @@
+// Copyright 2024 The Fuchsia Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <zircon/compiler.h>
+
+// This file exports the creation entry point that TAs are expected to export.
+// The signatures for this is not correct but the exported symbol contains only
+// a name so this doesn't matter for loading purposes.
+
+extern "C" {
+
+void __EXPORT TA_CreateEntryPoint() {}
+
+}  // extern "C"
diff --git a/src/testing/end_to_end/honeydew/BUILD.gn b/src/testing/end_to_end/honeydew/BUILD.gn
index 5642f51..80d78bd 100644
--- a/src/testing/end_to_end/honeydew/BUILD.gn
+++ b/src/testing/end_to_end/honeydew/BUILD.gn
@@ -107,11 +107,9 @@
     "utils/properties.py",
   ]
   library_deps = [
+    ":honeydew_ffx_tool_deps",
     ":honeydew_fidl_ir_and_deps",
     "//src/developer/ffx/lib/fuchsia-controller:fidl_bindings",
-
-    # For "ffx starnix adb" command
-    "//src/developer/ffx/tools/starnix:ffx_starnix_test_data",
     "//third_party/pypng",
   ]
 
@@ -125,9 +123,7 @@
   ]
 }
 
-# This data is specific to ONLY Fuchsia Controller based tests. Other Fuchsia
-# Controller based tests will need to add their respective host test data
-# definitions to include the proper FIDL IR json.
+# FIDL dependencies that will be used in Honeydew using Fuchsia-Controller.
 group("honeydew_fidl_ir_and_deps") {
   # Needed for SDK inclusion.
   testonly = false
@@ -149,6 +145,18 @@
   ]
 }
 
+# FFX tools that will be used in Honeydew.
+group("honeydew_ffx_tool_deps") {
+  # Needed for SDK inclusion.
+  testonly = false
+
+  deps = [
+    "//src/developer/ffx/plugins/log:ffx_log_tool_test_data",
+    "//src/developer/ffx/plugins/test:ffx_test_tool_test_data",
+    "//src/developer/ffx/tools/starnix:ffx_starnix_test_data",
+  ]
+}
+
 # SL4F packages
 group("sl4f_packages") {
   testonly = true
diff --git a/src/testing/end_to_end/honeydew/honeydew/affordances/sl4f/wlan/wlan.py b/src/testing/end_to_end/honeydew/honeydew/affordances/sl4f/wlan/wlan.py
index f0d3537..f2f3554 100644
--- a/src/testing/end_to_end/honeydew/honeydew/affordances/sl4f/wlan/wlan.py
+++ b/src/testing/end_to_end/honeydew/honeydew/affordances/sl4f/wlan/wlan.py
@@ -5,7 +5,6 @@
 """Wlan affordance implementation using SL4F."""
 
 import enum
-import logging
 from collections.abc import Mapping
 
 from honeydew.interfaces.affordances.wlan import wlan
@@ -14,20 +13,40 @@
     BssDescription,
     BssType,
     ChannelBandwidth,
+    ClientStatusConnected,
+    ClientStatusConnecting,
+    ClientStatusIdle,
     ClientStatusResponse,
     CountryCodeList,
     Protection,
     QueryIfaceResponse,
-    ServingApInfo,
     WlanChannel,
     WlanMacRole,
 )
 
-_LOGGER: logging.Logger = logging.getLogger(__name__)
+STATUS_IDLE_KEY = "Idle"
+STATUS_CONNECTING_KEY = "Connecting"
+
+# We need to convert the string we receive from the wlan facade to an intEnum
+# because serde gives us a string.
+string_to_int_enum_map: dict[str, int] = {
+    "Unknown": 0,
+    "Open": 1,
+    "Wep": 2,
+    "Wpa1": 3,
+    "Wpa1Wpa2PersonalTkipOnly": 4,
+    "Wpa2PersonalTkipOnly": 5,
+    "Wpa1Wpa2Personal": 6,
+    "Wpa2Personal": 7,
+    "Wpa2Wpa3Personal": 8,
+    "Wpa3Personal": 9,
+    "Wpa2Enterprise": 10,
+    "Wpa3Enterprise": 11,
+}
 
 
 def _get_int(m: Mapping[str, object], key: str) -> int:
-    val = m[key]
+    val = m.get(key)
     if not isinstance(val, int):
         raise TypeError(f'Expected "{val}" to be int, got {type(val)}')
     return val
@@ -90,7 +109,7 @@
         resp: dict[str, object] = self._sl4f.run(
             method=_Sl4fMethods.CONNECT, params=method_params
         )
-        result = resp.get("result", False)
+        result = resp.get("result")
 
         if not isinstance(result, bool):
             raise TypeError(f'Expected "result" to be bool, got {type(result)}')
@@ -163,7 +182,7 @@
         resp = self._sl4f.run(
             method=_Sl4fMethods.GET_COUNTRY, params=method_params
         )
-        result = resp.get("result", "")
+        result = resp.get("result")
 
         if not isinstance(result, str):
             raise TypeError(f'Expected "result" to be str, got {type(result)}')
@@ -183,7 +202,7 @@
         resp: dict[str, object] = self._sl4f.run(
             method=_Sl4fMethods.GET_IFACE_ID_LIST
         )
-        result: object = resp.get("result", [])
+        result: object = resp.get("result")
 
         if not isinstance(result, list):
             raise TypeError(f'Expected "result" to be list, got {type(result)}')
@@ -203,7 +222,7 @@
         resp: dict[str, object] = self._sl4f.run(
             method=_Sl4fMethods.GET_PHY_ID_LIST
         )
-        result: object = resp.get("result", [])
+        result: object = resp.get("result")
 
         if not isinstance(result, list):
             raise TypeError(f'Expected "result" to be list, got {type(result)}')
@@ -228,23 +247,23 @@
         resp: dict[str, object] = self._sl4f.run(
             method=_Sl4fMethods.QUERY_IFACE, params=method_params
         )
-        result: object = resp.get("result", {})
+        result: object = resp.get("result")
 
         if not isinstance(result, dict):
             raise TypeError(f'Expected "result" to be dict, got {type(result)}')
 
-        if not isinstance(result["sta_addr"], list):
+        sta_addr = result.get("sta_addr")
+        if not isinstance(sta_addr, list):
             raise TypeError(
-                'Expected "sta_addr" to be list, '
-                f'got {type(result["sta_addr"])}'
+                'Expected "sta_addr" to be list, ' f"got {type(sta_addr)}"
             )
 
         return QueryIfaceResponse(
-            role=WlanMacRole(result["role"]),
+            role=WlanMacRole(result.get("role", None)),
             id=_get_int(result, "id"),
             phy_id=_get_int(result, "phy_id"),
             phy_assigned_id=_get_int(result, "phy_assigned_id"),
-            sta_addr=result["sta_addr"],
+            sta_addr=sta_addr,
         )
 
     def scan_for_bss_info(self) -> dict[str, BssDescription]:
@@ -273,29 +292,35 @@
                     f'Expected "bss_block" to be dict, got {type(bss)}'
                 )
 
-            if not isinstance(bss["bssid"], list):
+            bssid = bss.get("bssid")
+            if not isinstance(bssid, list):
                 raise TypeError(
-                    f'Expected "bssid" to be list, got {type(bss["bssid"])}'
+                    f'Expected "bssid" to be list, got {type(bssid)}'
                 )
 
-            if not isinstance(bss["ies"], list):
+            ies = bss.get("ies")
+            if not isinstance(ies, list):
+                raise TypeError(f'Expected "ies" to be list, got {type(ies)}')
+
+            channel = bss.get("channel")
+            if not isinstance(channel, dict):
                 raise TypeError(
-                    f'Expected "ies" to be list, got {type(bss["ies"])}'
+                    f'Expected "channel" to be dict, got {type(channel)}'
                 )
 
-            channel = WlanChannel(
-                primary=_get_int(bss["channel"], "primary"),
-                cbw=ChannelBandwidth(bss["channel"]["cbw"]),
-                secondary80=_get_int(bss["channel"], "secondary80"),
+            wlan_channel = WlanChannel(
+                primary=_get_int(channel, "primary"),
+                cbw=ChannelBandwidth(channel.get("cbw", None)),
+                secondary80=_get_int(channel, "secondary80"),
             )
 
             bss_block = BssDescription(
-                bssid=bss["bssid"],
-                bss_type=BssType(bss["bss_type"]),
+                bssid=bssid,
+                bss_type=BssType(bss.get("bss_type", None)),
                 beacon_period=_get_int(bss, "beacon_period"),
                 capability_info=_get_int(bss, "capability_info"),
-                ies=bss["ies"],
-                channel=channel,
+                ies=ies,
+                channel=wlan_channel,
                 rssi_dbm=_get_int(bss, "rssi_dbm"),
                 snr_db=_get_int(bss, "snr_db"),
             )
@@ -320,60 +345,72 @@
         """Request connection status
 
         Returns:
-            ClientStatusResponse state summary and
-            status of various networks connections.
+            ClientStatusResponse which can be any one of three  things:
+            ClientStatusConnected, ClientStatusConnecting, ClientStatusIdle.
 
         Raises:
             errors.Sl4fError: On failure.
             TypeError: If any of the return values are not of the expected type.
+            ValueError: If none of the possible results are present.
         """
         resp: dict[str, object] = self._sl4f.run(method=_Sl4fMethods.STATUS)
-        result: object = resp.get("result", None)
+        result: object = resp.get("result")
 
         if not isinstance(result, dict):
             raise TypeError(f'Expected "result" to be dict, got {type(result)}')
 
-        if not isinstance(result["Connected"], dict):
-            raise TypeError(
-                'Expected "Connected" to be dict,'
-                f'got {type(result["Connected"])}'
+        # Only one of these keys in result should be present.
+        if STATUS_IDLE_KEY in result:
+            return ClientStatusIdle()
+        elif STATUS_CONNECTING_KEY in result:
+            ssid = result.get("Connecting")
+            if not isinstance(ssid, list):
+                raise TypeError(
+                    f'Expected "connecting" to be list, got "{type(ssid)}"'
+                )
+            return ClientStatusConnecting(ssid=ssid)
+        else:
+            connected = result.get("Connected")
+            if not isinstance(connected, dict):
+                raise TypeError(
+                    f'Expected "connected" to be dict, got {type(connected)}'
+                )
+
+            channel = connected.get("channel")
+            if not isinstance(channel, dict):
+                raise TypeError(
+                    f'Expected "channel" to be dict, got {type(channel)}'
+                )
+
+            wlan_channel = WlanChannel(
+                primary=_get_int(channel, "primary"),
+                cbw=ChannelBandwidth(channel.get("cbw", None)),
+                secondary80=_get_int(channel, "secondary80"),
             )
 
-        if not isinstance(result["Connecting"], list):
-            raise TypeError(
-                'Expected "Connecting" to be list, '
-                f'got {type(result["Connecting"])}'
+            bssid = connected.get("bssid")
+            if not isinstance(bssid, list):
+                raise TypeError(
+                    f'Expected "bssid" to be list, got {type(bssid)}'
+                )
+
+            ssid = connected.get("ssid")
+            if not isinstance(ssid, list):
+                raise TypeError(f'Expected "ssid" to be list, got {type(ssid)}')
+
+            protection = connected.get("protection")
+            if not isinstance(protection, str):
+                raise TypeError(
+                    f'Expected "protection" to be str, got {type(protection)}'
+                )
+
+            return ClientStatusConnected(
+                bssid=bssid,
+                ssid=ssid,
+                rssi_dbm=_get_int(connected, "rssi_dbm"),
+                snr_db=_get_int(connected, "snr_db"),
+                channel=wlan_channel,
+                protection=Protection(
+                    string_to_int_enum_map.get(protection, 0)
+                ),
             )
-
-        channel = WlanChannel(
-            primary=result["Connected"]["channel"]["primary"],
-            cbw=ChannelBandwidth(result["Connected"]["channel"]["cbw"]),
-            secondary80=result["Connected"]["channel"]["secondary80"],
-        )
-
-        if not isinstance(result["Connected"]["bssid"], list):
-            raise TypeError(
-                'Expected "bssid" to be list, '
-                f'got {type(result["Connected"]["bssid"])}'
-            )
-
-        if not isinstance(result["Connected"]["ssid"], list):
-            raise TypeError(
-                'Expected "ssid" to be list, '
-                f'got {type(result["Connected"]["ssid"])}'
-            )
-
-        serving_ap_info = ServingApInfo(
-            bssid=result["Connected"]["bssid"],
-            ssid=result["Connected"]["ssid"],
-            rssi_dbm=_get_int(result["Connected"], "rssi_dbm"),
-            snr_db=_get_int(result["Connected"], "snr_db"),
-            channel=channel,
-            protection=Protection(result["Connected"]["protection"]),
-        )
-
-        return ClientStatusResponse(
-            connected=serving_ap_info,
-            connecting=result["Connecting"],
-            idle=result["Idle"],
-        )
diff --git a/src/testing/end_to_end/honeydew/honeydew/affordances/sl4f/wlan/wlan_policy.py b/src/testing/end_to_end/honeydew/honeydew/affordances/sl4f/wlan/wlan_policy.py
index 5fbbd45..3f1d6b7 100644
--- a/src/testing/end_to_end/honeydew/honeydew/affordances/sl4f/wlan/wlan_policy.py
+++ b/src/testing/end_to_end/honeydew/honeydew/affordances/sl4f/wlan/wlan_policy.py
@@ -4,7 +4,6 @@
 # found in the LICENSE file.
 """Wlan policy affordance implementation using SL4F."""
 
-import logging
 from collections.abc import Mapping
 from enum import StrEnum
 
@@ -22,11 +21,9 @@
     WlanClientState,
 )
 
-_LOGGER: logging.Logger = logging.getLogger(__name__)
-
 
 def _get_str(m: Mapping[str, object], key: str) -> str:
-    val = m[key]
+    val = m.get(key)
     if not isinstance(val, str):
         raise TypeError(f'Expected "{val}" to be str, got {type(val)}')
     return val
@@ -85,7 +82,7 @@
         resp: dict[str, object] = self._sl4f.run(
             method=_Sl4fMethods.CONNECT, params=method_params
         )
-        result: object = resp.get("result", "")
+        result: object = resp.get("result")
 
         if not isinstance(result, str):
             raise TypeError(f'Expected "result" to be str, got {type(result)}')
@@ -114,7 +111,7 @@
         resp: dict[str, object] = self._sl4f.run(
             method=_Sl4fMethods.GET_SAVED_NETWORKS
         )
-        result: object = resp.get("result", [])
+        result: object = resp.get("result")
 
         if not isinstance(result, list):
             raise TypeError(f'Expected "result" to be list, got {type(result)}')
@@ -163,28 +160,30 @@
         resp: dict[str, object] = self._sl4f.run(
             method=_Sl4fMethods.GET_UPDATE, timeout=timeout
         )
-        result: object = resp.get("result", {})
+        result: object = resp.get("result")
 
         if not isinstance(result, dict):
             raise TypeError(f'Expected "result" to be dict, got {type(result)}')
 
-        if not isinstance(result["networks"], list):
+        networks = result.get("networks")
+        if not isinstance(networks, list):
             raise TypeError(
                 'Expected "networks" to be list, '
-                f'got {type(result["networks"])}'
+                f'got {type(result.get("networks"))}'
             )
 
         network_states: list[NetworkState] = []
-        for n in result["networks"]:
-            state: str | None = n["state"]
-            status: str | None = n["status"]
+        for network in networks:
+            state: str | None = network.get("state")
+            status: str | None = network.get("status")
             if state is None:
                 state = ConnectionState.DISCONNECTED
             if status is None:
                 status = DisconnectStatus.CONNECTION_STOPPED
 
-            ssid: str = n["id"]["ssid"]
-            security_type: str = n["id"]["type_"]
+            net_id = network.get("id")
+            ssid: str = net_id.get("ssid")
+            security_type: str = net_id.get("type_")
 
             network_states.append(
                 NetworkState(
@@ -198,7 +197,8 @@
             )
 
         return ClientStateSummary(
-            state=WlanClientState(result["state"]), networks=network_states
+            state=WlanClientState(result.get("state", None)),
+            networks=network_states,
         )
 
     def remove_all_networks(self) -> None:
@@ -276,7 +276,7 @@
         resp: dict[str, object] = self._sl4f.run(
             method=_Sl4fMethods.GET_SAVED_NETWORKS
         )
-        result: object = resp.get("result", [])
+        result: object = resp.get("result")
 
         if not isinstance(result, list):
             raise TypeError(f'Expected "result" to be list, got {type(result)}')
diff --git a/src/testing/end_to_end/honeydew/honeydew/affordances/starnix/system_power_state_controller.py b/src/testing/end_to_end/honeydew/honeydew/affordances/starnix/system_power_state_controller.py
index 8b7e4ab..646833e 100644
--- a/src/testing/end_to_end/honeydew/honeydew/affordances/starnix/system_power_state_controller.py
+++ b/src/testing/end_to_end/honeydew/honeydew/affordances/starnix/system_power_state_controller.py
@@ -17,7 +17,9 @@
 from honeydew.interfaces.affordances import (
     system_power_state_controller as system_power_state_controller_interface,
 )
+from honeydew.interfaces.device_classes import affordances_capable
 from honeydew.transports import ffx as ffx_transport
+from honeydew.typing import custom_types
 
 
 class _StarnixCmds:
@@ -43,14 +45,41 @@
     """Class to hold the timeouts."""
 
     STARNIX_CMD = 15
+    FFX_LOGS_CMD = 60
 
 
 class _RegExPatterns:
+    """Class to hold Regular Expression patterns."""
+
     STARNIX_CMD_SUCCESS: re.Pattern[str] = re.compile(r"(exit code: 0)")
+
     STARNIX_NOT_SUPPORTED: re.Pattern[str] = re.compile(
         r"Unable to find Starnix container in the session"
     )
 
+    SUSPEND_OPERATION: re.Pattern[str] = re.compile(
+        r"\[(\d+).\d+\].*?\[system-activity-governor\].+?Suspending"
+    )
+
+    RESUME_OPERATION: re.Pattern[str] = re.compile(
+        r"\[(\d+?).\d+?\].*?\[system-activity-governor\].+?Resuming.+?Ok"
+    )
+
+    HONEYDEW_SUSPEND_RESUME_START: re.Pattern[str] = re.compile(
+        r"\[lacewing\].*?\[Host Time: (.*?)\].*?Performing.*?Suspend.*?followed by.*?Resume.*?operations"
+    )
+
+    HONEYDEW_SUSPEND_RESUME_END: re.Pattern[str] = re.compile(
+        r"\[lacewing\].*?\[Host Time: (.*?)\].*?Completed.*?Suspend.*?followed by.*?Resume.*?operations.*?in (\d+?.\d+?) seconds"
+    )
+
+    SUSPEND_RESUME_PATTERNS: list[re.Pattern[str]] = [
+        HONEYDEW_SUSPEND_RESUME_START,
+        SUSPEND_OPERATION,
+        RESUME_OPERATION,
+        HONEYDEW_SUSPEND_RESUME_END,
+    ]
+
 
 _MAX_READ_SIZE: int = 1024
 
@@ -71,9 +100,17 @@
         errors.NotSupportedError: If Fuchsia device does not support Starnix.
     """
 
-    def __init__(self, device_name: str, ffx: ffx_transport.FFX) -> None:
+    def __init__(
+        self,
+        device_name: str,
+        ffx: ffx_transport.FFX,
+        device_logger: affordances_capable.FuchsiaDeviceLogger,
+    ) -> None:
         self._device_name: str = device_name
         self._ffx: ffx_transport.FFX = ffx
+        self._device_logger: affordances_capable.FuchsiaDeviceLogger = (
+            device_logger
+        )
 
         _LOGGER.debug(
             "Checking if %s supports %s affordance...",
@@ -94,6 +131,7 @@
         self,
         suspend_state: system_power_state_controller_interface.SuspendState,
         resume_mode: system_power_state_controller_interface.ResumeMode,
+        verify: bool = True,
     ) -> None:
         """Perform suspend-resume operation on the device.
 
@@ -103,21 +141,28 @@
         Args:
             suspend_state: Which state to suspend the Fuchsia device into.
             resume_mode: Information about how to resume the device.
+            verify: Whether or not to verify if suspend-resume operation
+                performed successfully. Optional and default is True. Note that
+                this raises SystemPowerStateControllerError if verification
+                fails.
 
         Raises:
             errors.SystemPowerStateControllerError: In case of failure
             errors.NotSupportedError: If any of the suspend_state or resume_type
                 is not yet supported
         """
-        _LOGGER.info(
-            "Putting the '%s' into '%s' followed by '%s'...",
-            self._device_name,
-            suspend_state,
-            resume_mode,
+        logs_start_time: float = time.time()
+        log_message: str = (
+            f"Performing '{suspend_state}' followed by '{resume_mode}' "
+            f"operations on '{self._device_name}'..."
+        )
+        _LOGGER.info(log_message)
+        self._device_logger.log_message_to_device(
+            message=log_message,
+            level=custom_types.LEVEL.INFO,
         )
 
-        start_time: float = time.time()
-
+        suspend_resume_start_time: float = time.time()
         if isinstance(
             resume_mode, system_power_state_controller_interface.AutomaticResume
         ):
@@ -127,7 +172,6 @@
             raise errors.NotSupportedError(
                 f"Resuming the device using '{resume_mode}' is not yet supported."
             )
-
         if isinstance(
             suspend_state, system_power_state_controller_interface.IdleSuspend
         ):
@@ -137,29 +181,46 @@
                 f"Suspending the device to '{suspend_state}' state is not yet "
                 f"supported."
             )
-
-        end_time: float = time.time()
-        duration: float = end_time - start_time
-
-        self._verify_suspend_resume(suspend_state, resume_mode, duration)
-
-        _LOGGER.info(
-            "Successfully completed '%s' and '%s' operations on '%s' in '%s' seconds",
-            suspend_state,
-            resume_mode,
-            self._device_name,
-            duration,
+        suspend_resume_end_time: float = time.time()
+        suspend_resume_duration: float = (
+            suspend_resume_end_time - suspend_resume_start_time
         )
 
-    def idle_suspend_auto_resume(self) -> None:
+        log_message = (
+            f"Completed '{suspend_state}' followed by '{resume_mode}' "
+            f"operations on '{self._device_name}' in {suspend_resume_duration} "
+            f"seconds."
+        )
+        self._device_logger.log_message_to_device(
+            message=log_message,
+            level=custom_types.LEVEL.INFO,
+        )
+        _LOGGER.info(log_message)
+        logs_end_time: float = time.time()
+        logs_duration: float = logs_end_time - logs_start_time
+
+        if verify:
+            self._verify_suspend_resume(
+                suspend_state,
+                resume_mode,
+                suspend_resume_duration,
+                logs_duration,
+            )
+
+    def idle_suspend_auto_resume(self, verify: bool = True) -> None:
         """Perform idle-suspend and auto-resume operation on the device.
 
+        Args:
+            verify: Whether or not to verify if suspend-resume operation
+                performed successfully. Optional and default is True.
+
         Raises:
             errors.SystemPowerStateControllerError: In case of failure
         """
         self.suspend_resume(
             suspend_state=system_power_state_controller_interface.IdleSuspend(),
             resume_mode=system_power_state_controller_interface.AutomaticResume(),
+            verify=verify,
         )
 
     # List all the private methods
@@ -253,7 +314,8 @@
         self,
         suspend_state: system_power_state_controller_interface.SuspendState,
         resume_mode: system_power_state_controller_interface.ResumeMode,
-        duration: float,
+        suspend_resume_duration: float,
+        logs_duration: float,
     ) -> None:
         """Verifies suspend resume operation has been indeed performed
         correctly.
@@ -261,7 +323,55 @@
         Args:
             suspend_state: Which state to suspend the Fuchsia device into.
             resume_mode: Information about how to resume the device.
-            duration: how long suspend-resume operation took.
+            suspend_resume_duration: How long suspend-resume operation took.
+            logs_duration: How many seconds of logs need to be captured for
+                the log analysis.
+        Raises:
+            errors.SystemPowerStateControllerError: In case of verification
+                failure.
+        """
+        _LOGGER.info(
+            "Verifying the '%s' followed by '%s' operations that were "
+            "performed on '%s'...",
+            suspend_state,
+            resume_mode,
+            self._device_name,
+        )
+
+        self._verify_suspend_resume_using_duration(
+            suspend_state=suspend_state,
+            resume_mode=resume_mode,
+            suspend_resume_duration=suspend_resume_duration,
+        )
+
+        # TODO (https://fxbug.dev/335494603): Use inspect based verification
+        self._verify_suspend_resume_using_log_analysis(
+            suspend_state=suspend_state,
+            resume_mode=resume_mode,
+            logs_duration=logs_duration,
+        )
+
+        _LOGGER.info(
+            "Successfully verified the '%s' followed by '%s' operations that "
+            "were performed on '%s'",
+            suspend_state,
+            resume_mode,
+            self._device_name,
+        )
+
+    def _verify_suspend_resume_using_duration(
+        self,
+        suspend_state: system_power_state_controller_interface.SuspendState,
+        resume_mode: system_power_state_controller_interface.ResumeMode,
+        suspend_resume_duration: float,
+    ) -> None:
+        """Verify that suspend-resume operation was indeed triggered by checking
+        the duration it took to perform suspend-resume operation.
+
+        Args:
+            suspend_state: Which state to suspend the Fuchsia device into.
+            resume_mode: Information about how to resume the device.
+            suspend_resume_duration: How long suspend-resume operation took.
 
         Raises:
             errors.SystemPowerStateControllerError: In case of verification
@@ -270,20 +380,86 @@
         if isinstance(
             resume_mode, system_power_state_controller_interface.AutomaticResume
         ):
-            buffer_duration: float = 5
+            buffer_duration: float = 3
             max_expected_duration: float = (
                 resume_mode.duration + buffer_duration
             )
-            actual_duration: float = duration
 
             if (
-                actual_duration < resume_mode.duration
-                or actual_duration > max_expected_duration
+                suspend_resume_duration < resume_mode.duration
+                or suspend_resume_duration > max_expected_duration
             ):
                 raise errors.SystemPowerStateControllerError(
-                    f"Putting the '{self._device_name}' into '{suspend_state}' "
-                    f"followed by '{resume_mode}' operation took {duration} "
-                    f"seconds instead of {resume_mode.duration} seconds. "
-                    f"Expected duration range: [{resume_mode.duration}, "
-                    f"{max_expected_duration}] seconds.",
+                    f"'{suspend_state}' followed by '{resume_mode}' operation "
+                    f"took  {suspend_resume_duration} seconds on "
+                    f"'{self._device_name}'. Expected duration "
+                    f"range: [{resume_mode.duration}, {max_expected_duration}] "
+                    f"seconds.",
                 )
+
+    def _verify_suspend_resume_using_log_analysis(
+        self,
+        suspend_state: system_power_state_controller_interface.SuspendState,
+        resume_mode: system_power_state_controller_interface.ResumeMode,
+        logs_duration: float,
+    ) -> None:
+        """Verify that suspend resume operation was indeed triggered using log
+        analysis.
+
+        Args:
+            suspend_state: Which state to suspend the Fuchsia device into.
+            resume_mode: Information about how to resume the device.
+            logs_duration: How many seconds of logs need to be captured for
+                the log analysis.
+        """
+        duration: int = round(logs_duration) + 1
+        suspend_resume_logs_cmd: list[str] = [
+            "log",
+            "--symbolize",
+            "off",  # Turn off symbolize to run this cmd in infra
+            "--filter",
+            "remote-control",  # Lacewing logs
+            "--filter",
+            "system-activity-governor",  # suspend-resume logs
+            "--since",
+            f"{duration}s ago",
+            "dump",
+        ]
+
+        suspend_resume_logs: list[str] = self._ffx.run(
+            suspend_resume_logs_cmd,
+            timeout=_Timeouts.FFX_LOGS_CMD,
+        ).split("\n")
+
+        suspend_time: int = 0
+        resume_time: int = 0
+
+        expected_patterns: list[
+            re.Pattern[str]
+        ] = _RegExPatterns.SUSPEND_RESUME_PATTERNS.copy()
+        for suspend_resume_log in suspend_resume_logs:
+            reg_ex: re.Pattern[str] = expected_patterns[0]
+            match: re.Match[str] | None = reg_ex.search(suspend_resume_log)
+            if match:
+                if reg_ex == _RegExPatterns.SUSPEND_OPERATION:
+                    suspend_time = int(match.group(1))
+                elif reg_ex == _RegExPatterns.RESUME_OPERATION:
+                    resume_time = int(match.group(1))
+                expected_patterns.remove(reg_ex)
+                if not expected_patterns:
+                    break
+                reg_ex = expected_patterns[0]
+
+        if expected_patterns:
+            raise errors.SystemPowerStateControllerError(
+                f"Log analysis for '{suspend_state}' followed by "
+                f"'{resume_mode}' operation failed on '{self._device_name}'. "
+                f"Following patterns were not found: {expected_patterns}"
+            )
+
+        suspend_resume_duration: int = resume_time - suspend_time
+        self._verify_suspend_resume_using_duration(
+            suspend_state=suspend_state,
+            resume_mode=resume_mode,
+            suspend_resume_duration=suspend_resume_duration,
+        )
diff --git a/src/testing/end_to_end/honeydew/honeydew/fuchsia_device/base_fuchsia_device.py b/src/testing/end_to_end/honeydew/honeydew/fuchsia_device/base_fuchsia_device.py
index d4dc672..b3c3d76 100644
--- a/src/testing/end_to_end/honeydew/honeydew/fuchsia_device/base_fuchsia_device.py
+++ b/src/testing/end_to_end/honeydew/honeydew/fuchsia_device/base_fuchsia_device.py
@@ -51,6 +51,7 @@
 class BaseFuchsiaDevice(
     fuchsia_device_interface.FuchsiaDevice,
     affordances_capable.RebootCapableDevice,
+    affordances_capable.FuchsiaDeviceLogger,
 ):
     """Common implementation for Fuchsia devices using different transports.
     Every device running Fuchsia contains common functionality as well as the
@@ -294,7 +295,9 @@
             errors.NotSupportedError: If Fuchsia device does not support Starnix
         """
         return system_power_state_controller_starnix.SystemPowerStateController(
-            device_name=self.device_name, ffx=self.ffx
+            device_name=self.device_name,
+            ffx=self.ffx,
+            device_logger=self,
         )
 
     # List all the public methods
diff --git a/src/testing/end_to_end/honeydew/honeydew/interfaces/affordances/system_power_state_controller.py b/src/testing/end_to_end/honeydew/honeydew/interfaces/affordances/system_power_state_controller.py
index 978057b..a4b92ce 100644
--- a/src/testing/end_to_end/honeydew/honeydew/interfaces/affordances/system_power_state_controller.py
+++ b/src/testing/end_to_end/honeydew/honeydew/interfaces/affordances/system_power_state_controller.py
@@ -59,12 +59,15 @@
         self,
         suspend_state: SuspendState,
         resume_mode: ResumeMode,
+        verify: bool = True,
     ) -> None:
         """Perform suspend-resume operation on the device.
 
         Args:
             suspend_state: Which state to suspend the Fuchsia device into.
             resume_mode: Information about how to resume the device.
+            verify: Whether or not to verify if suspend-resume operation
+                performed successfully. Optional and default is True.
 
         Raises:
             errors.SystemPowerStateControllerError: In case of failure
@@ -73,9 +76,13 @@
         """
 
     @abc.abstractmethod
-    def idle_suspend_auto_resume(self) -> None:
+    def idle_suspend_auto_resume(self, verify: bool = True) -> None:
         """Perform idle-suspend and auto-resume operation on the device.
 
+        Args:
+            verify: Whether or not to verify if suspend-resume operation
+                performed successfully. Optional and default is True.
+
         Raises:
             errors.SystemPowerStateControllerError: In case of failure
         """
diff --git a/src/testing/end_to_end/honeydew/honeydew/interfaces/device_classes/affordances_capable.py b/src/testing/end_to_end/honeydew/honeydew/interfaces/device_classes/affordances_capable.py
index 1d5a0f0..3e933a8 100644
--- a/src/testing/end_to_end/honeydew/honeydew/interfaces/device_classes/affordances_capable.py
+++ b/src/testing/end_to_end/honeydew/honeydew/interfaces/device_classes/affordances_capable.py
@@ -8,6 +8,7 @@
 from collections.abc import Callable
 
 from honeydew.interfaces.device_classes import fuchsia_device
+from honeydew.typing import custom_types
 
 
 class RebootCapableDevice(abc.ABC):
@@ -45,3 +46,19 @@
         Args:
             timeout: How long in sec to wait for device to go offline.
         """
+
+
+class FuchsiaDeviceLogger(abc.ABC):
+    """Abstract base class which contains methods for logging message to fuchsia
+    device."""
+
+    @abc.abstractmethod
+    def log_message_to_device(
+        self, message: str, level: custom_types.LEVEL
+    ) -> None:
+        """Log message to fuchsia device at specified level.
+
+        Args:
+            message: Message that need to logged.
+            level: Log message level.
+        """
diff --git a/src/testing/end_to_end/honeydew/honeydew/interfaces/transports/ffx.py b/src/testing/end_to_end/honeydew/honeydew/interfaces/transports/ffx.py
index 6fa3ede..ccfbbec 100644
--- a/src/testing/end_to_end/honeydew/honeydew/interfaces/transports/ffx.py
+++ b/src/testing/end_to_end/honeydew/honeydew/interfaces/transports/ffx.py
@@ -9,7 +9,7 @@
 from collections.abc import Iterable
 from typing import Any
 
-from honeydew.typing import custom_types, ffx
+from honeydew.typing import custom_types
 from honeydew.typing import ffx as ffx_types
 from honeydew.utils import properties
 
diff --git a/src/testing/end_to_end/honeydew/honeydew/transports/ffx.py b/src/testing/end_to_end/honeydew/honeydew/transports/ffx.py
index e92df24..19c93d4 100644
--- a/src/testing/end_to_end/honeydew/honeydew/transports/ffx.py
+++ b/src/testing/end_to_end/honeydew/honeydew/transports/ffx.py
@@ -17,8 +17,8 @@
 from honeydew import errors
 from honeydew.interfaces.transports import ffx as ffx_interface
 from honeydew.typing import custom_types
-from honeydew.utils import properties
 from honeydew.typing.ffx import TargetInfoData
+from honeydew.utils import properties
 
 _FFX_BINARY: str = "ffx"
 
diff --git a/src/testing/end_to_end/honeydew/honeydew/typing/custom_types.py b/src/testing/end_to_end/honeydew/honeydew/typing/custom_types.py
index 31ac92f..769a125 100644
--- a/src/testing/end_to_end/honeydew/honeydew/typing/custom_types.py
+++ b/src/testing/end_to_end/honeydew/honeydew/typing/custom_types.py
@@ -9,6 +9,7 @@
 import enum
 import ipaddress
 from dataclasses import dataclass
+
 import fuchsia_controller_py as fuchsia_controller
 
 
diff --git a/src/testing/end_to_end/honeydew/honeydew/typing/ffx.py b/src/testing/end_to_end/honeydew/honeydew/typing/ffx.py
index 0272fa2..39be339 100644
--- a/src/testing/end_to_end/honeydew/honeydew/typing/ffx.py
+++ b/src/testing/end_to_end/honeydew/honeydew/typing/ffx.py
@@ -4,8 +4,8 @@
 """Data types that match the machine output of ffx."""
 from dataclasses import dataclass
 from typing import Any
-from honeydew.typing.custom_types import IpPort
 
+from honeydew.typing.custom_types import IpPort
 
 # LINT.IfChange
 
diff --git a/src/testing/end_to_end/honeydew/honeydew/typing/wlan.py b/src/testing/end_to_end/honeydew/honeydew/typing/wlan.py
index 23889c2..ea2faa8 100644
--- a/src/testing/end_to_end/honeydew/honeydew/typing/wlan.py
+++ b/src/testing/end_to_end/honeydew/honeydew/typing/wlan.py
@@ -8,6 +8,7 @@
 
 import enum
 from dataclasses import dataclass
+from typing import Protocol
 
 
 # pylint: disable=line-too-long
@@ -123,14 +124,14 @@
     OPEN = 1
     WEP = 2
     WPA1 = 3
-    WPA1WPA2PERSONALTKIPONLY = 4
-    WPA2PERSONALTKIPONLY = 5
-    WPA1WPA2PERSONAL = 6
-    WPA2PERSONAL = 7
-    WPA2WPA3PERSONAL = 8
-    WPA3PERSONAL = 9
-    WPA2ENTERPRISE = 0
-    WPA3ENTERPRISE = 1
+    WPA1_WPA2_PERSONAL_TKIP_ONLY = 4
+    WPA2_PERSONAL_TKIP_ONLY = 5
+    WPA1_WPA2_PERSONAL = 6
+    WPA2_PERSONAL = 7
+    WPA2_WPA3_PERSONAL = 8
+    WPA3_PERSONAL = 9
+    WPA2_ENTERPRISE = 10
+    WPA3_ENTERPRISE = 11
 
 
 @dataclass(frozen=True)
@@ -201,21 +202,6 @@
 
 
 @dataclass(frozen=True)
-class ServingApInfo:
-    """ServingApInfo, returned as a part of ClientStatusResponse.
-
-    Defined by https://cs.opensource.google/fuchsia/fuchsia/+/main:src/testing/sl4f/src/wlan/types.rs
-    """
-
-    bssid: list[int]
-    ssid: list[int]
-    rssi_dbm: int
-    snr_db: int
-    channel: WlanChannel
-    protection: Protection
-
-
-@dataclass(frozen=True)
 class WlanChannel:
     """Wlan channel information.
 
@@ -259,15 +245,41 @@
 
 
 @dataclass(frozen=True)
-class ClientStatusResponse:
-    """ClientStatusResponse returned from a status request.
+class ClientStatusResponse(Protocol):
+    def status(self) -> str:
+        ...
+
+
+@dataclass(frozen=True)
+class ClientStatusConnected(ClientStatusResponse):
+    """ServingApInfo, returned as a part of ClientStatusResponse.
 
     Defined by https://cs.opensource.google/fuchsia/fuchsia/+/main:src/testing/sl4f/src/wlan/types.rs
     """
 
-    connected: ServingApInfo
-    connecting: list[int]
-    idle: str
+    bssid: list[int]
+    ssid: list[int]
+    rssi_dbm: int
+    snr_db: int
+    channel: WlanChannel
+    protection: Protection
+
+    def status(self) -> str:
+        return "Connected"
+
+
+@dataclass(frozen=True)
+class ClientStatusConnecting(ClientStatusResponse):
+    ssid: list[int]
+
+    def status(self) -> str:
+        return "Connecting"
+
+
+@dataclass(frozen=True)
+class ClientStatusIdle(ClientStatusResponse):
+    def status(self) -> str:
+        return "Idle"
 
 
 class CountryCodeList(enum.StrEnum):
diff --git a/src/testing/end_to_end/honeydew/tests/functional_tests/affordance_tests/test_system_power_state_controller/test_system_power_state_controller.py b/src/testing/end_to_end/honeydew/tests/functional_tests/affordance_tests/test_system_power_state_controller/test_system_power_state_controller.py
index 855f9fd..455aa8c 100644
--- a/src/testing/end_to_end/honeydew/tests/functional_tests/affordance_tests/test_system_power_state_controller/test_system_power_state_controller.py
+++ b/src/testing/end_to_end/honeydew/tests/functional_tests/affordance_tests/test_system_power_state_controller/test_system_power_state_controller.py
@@ -15,7 +15,6 @@
 _LOGGER: logging.Logger = logging.getLogger(__name__)
 
 
-# TODO(b/328778702): Run this test in infra once test groups are updated per <PRODUCT>.<BOARD>
 class SystemPowerStateControllerAffordanceTests(
     fuchsia_base_test.FuchsiaBaseTest
 ):
@@ -34,10 +33,6 @@
             with asserts.assert_raises(errors.NotSupportedError):
                 self.device.system_power_state_controller.idle_suspend_auto_resume()
 
-        # TODO (b/330594505): Add checks either here or in affordance
-        # implementation to make sure device is indeed suspend-resumed by doing
-        # `ffx log` parsing
-
 
 if __name__ == "__main__":
     test_runner.main()
diff --git a/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/sl4f/wlan_test.py b/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/sl4f/wlan_test.py
index 9434eca..72da3a5 100644
--- a/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/sl4f/wlan_test.py
+++ b/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/sl4f/wlan_test.py
@@ -13,10 +13,11 @@
     BssDescription,
     BssType,
     ChannelBandwidth,
-    ClientStatusResponse,
+    ClientStatusConnected,
+    ClientStatusConnecting,
+    ClientStatusIdle,
     Protection,
     QueryIfaceResponse,
-    ServingApInfo,
     WlanChannel,
     WlanMacRole,
 )
@@ -254,7 +255,13 @@
     def test_scan_for_bss_info_failure_bssid_not_list(self) -> None:
         """Test for Wlan.scan_for_bss_info()."""
         self.sl4f_obj.run.return_value = {
-            "result": {"bss": {"bssid": "not_list", "ies": [1, 2]}}
+            "result": {
+                "test_bss": {
+                    "bssid": "not_list",
+                    "ies": [1, 2],
+                    "channel": {"primary": 1, "cbw": 0, "secondary80": 1},
+                }
+            }
         }
 
         with self.assertRaises(TypeError):
@@ -264,25 +271,60 @@
     def test_scan_for_bss_info_failure_ies_not_list(self) -> None:
         """Test for Wlan.scan_for_bss_info()."""
         self.sl4f_obj.run.return_value = {
-            "result": {"bss": {"bssid": [1, 2], "ies": "not_list"}}
+            "result": {
+                "test_bss": {
+                    "bssid": [1, 2],
+                    "ies": "not_list",
+                    "channel": {"primary": 1, "cbw": 0, "secondary80": 1},
+                }
+            }
         }
 
         with self.assertRaises(TypeError):
             self.wlan_obj.scan_for_bss_info()
         self.sl4f_obj.run.assert_called()
 
+    def test_scan_for_bss_info_failure_channel_not_dict(self) -> None:
+        """Test for Wlan.scan_for_bss_info()."""
+        self.sl4f_obj.run.return_value = {
+            "result": {
+                "test_bss": {
+                    "bssid": [1, 2],
+                    "ies": [1, 2],
+                    "channel": "not_dict",
+                }
+            }
+        }
+        with self.assertRaises(TypeError):
+            self.wlan_obj.scan_for_bss_info()
+        self.sl4f_obj.run.assert_called()
+
     def test_set_region_success(self) -> None:
         """Test for Wlan.set_region()."""
         self.wlan_obj.set_region("US")
         self.sl4f_obj.run.assert_called()
 
-    def test_status_success(self) -> None:
+    def test_status_idle_success(self) -> None:
+        """Test for Wlan.status()."""
+        self.sl4f_obj.run.return_value = {"result": {"Idle": None}}
+        expected_value = ClientStatusIdle()
+        self.assertEqual(self.wlan_obj.status(), expected_value)
+        self.sl4f_obj.run.assert_called()
+
+    def test_status_connecting_success(self) -> None:
+        """Test for Wlan.status()."""
+        self.sl4f_obj.run.return_value = {"result": {"Connecting": [1, 2, 3]}}
+        expected_value = ClientStatusConnecting(ssid=[1, 2, 3])
+        self.assertEqual(self.wlan_obj.status(), expected_value)
+        self.sl4f_obj.run.assert_called()
+
+    def test_status_connected_success(self) -> None:
         """Test for Wlan.status()."""
         self.sl4f_obj.run.return_value = {
             "result": {
                 "Connected": {
                     "bssid": [1, 2],
-                    "ssid": [2, 3],
+                    "ssid": [1, 2],
                     "rssi_dbm": 4,
                     "snr_db": 5,
                     "channel": {
@@ -290,28 +332,21 @@
                         "cbw": "Cbw20",
                         "secondary80": 3,
                     },
-                    "protection": 1,
+                    "protection": "Open",
                 },
-                "Connecting": [1, 2, 3],
-                "Idle": "test",
             }
         }
-
-        expected_value = ClientStatusResponse(
-            connected=ServingApInfo(
-                bssid=[1, 2],
-                ssid=[2, 3],
-                rssi_dbm=4,
-                snr_db=5,
-                channel=WlanChannel(
-                    primary=1,
-                    cbw=ChannelBandwidth.CBW20,
-                    secondary80=3,
-                ),
-                protection=Protection.OPEN,
+        expected_value = ClientStatusConnected(
+            bssid=[1, 2],
+            ssid=[1, 2],
+            rssi_dbm=4,
+            snr_db=5,
+            channel=WlanChannel(
+                primary=1,
+                cbw=ChannelBandwidth.CBW20,
+                secondary80=3,
             ),
-            connecting=[1, 2, 3],
-            idle="test",
+            protection=Protection.OPEN,
         )
 
         self.assertEqual(self.wlan_obj.status(), expected_value)
@@ -325,6 +360,14 @@
             self.wlan_obj.status()
         self.sl4f_obj.run.assert_called()
 
+    def test_status_failure_connecting_not_list(self) -> None:
+        """Test for Wlan.status()."""
+        self.sl4f_obj.run.return_value = {"result": {"Connecting": "not_list"}}
+
+        with self.assertRaises(TypeError):
+            self.wlan_obj.status()
+        self.sl4f_obj.run.assert_called()
+
     def test_status_failure_connected_not_dict(self) -> None:
         """Test for Wlan.status()."""
         self.sl4f_obj.run.return_value = {"result": {"Connected": "not_dict"}}
@@ -333,24 +376,15 @@
             self.wlan_obj.status()
         self.sl4f_obj.run.assert_called()
 
-    def test_status_failure_connecting_not_list(self) -> None:
+    def test_status_failure_connected_channel_not_dict(self) -> None:
         """Test for Wlan.status()."""
         self.sl4f_obj.run.return_value = {
             "result": {
                 "Connected": {
-                    "bssid": "not_list",
+                    "bssid": [1, 2],
                     "ssid": [2, 3],
-                    "rssi_dbm": 4,
-                    "snr_db": 5,
-                    "channel": {
-                        "primary": 1,
-                        "cbw": "Cbw20",
-                        "secondary80": 3,
-                    },
-                    "protection": 1,
-                },
-                "Connecting": "not_list",
-                "Idle": "test",
+                    "channel": "not_dict",
+                }
             }
         }
 
@@ -358,24 +392,19 @@
             self.wlan_obj.status()
         self.sl4f_obj.run.assert_called()
 
-    def test_status_failure_bssid_not_list(self) -> None:
+    def test_status_failure_connected_bssid_not_list(self) -> None:
         """Test for Wlan.status()."""
         self.sl4f_obj.run.return_value = {
             "result": {
                 "Connected": {
                     "bssid": "not_list",
                     "ssid": [2, 3],
-                    "rssi_dbm": 4,
-                    "snr_db": 5,
                     "channel": {
                         "primary": 1,
                         "cbw": "Cbw20",
                         "secondary80": 3,
                     },
-                    "protection": 1,
-                },
-                "Connecting": [1, 2, 3],
-                "Idle": "test",
+                }
             }
         }
 
@@ -383,24 +412,40 @@
             self.wlan_obj.status()
         self.sl4f_obj.run.assert_called()
 
-    def test_status_failure_ssid_not_list(self) -> None:
+    def test_status_failure_connected_ssid_not_list(self) -> None:
         """Test for Wlan.status()."""
         self.sl4f_obj.run.return_value = {
             "result": {
                 "Connected": {
                     "bssid": [1, 2],
                     "ssid": "not_list",
-                    "rssi_dbm": 4,
-                    "snr_db": 5,
+                    "channel": {
+                        "primary": 1,
+                        "cbw": "Cbw20",
+                        "secondary80": 3,
+                    },
+                }
+            }
+        }
+
+        with self.assertRaises(TypeError):
+            self.wlan_obj.status()
+        self.sl4f_obj.run.assert_called()
+
+    def test_status_failure_connected_protection_not_str(self) -> None:
+        """Test for Wlan.status()."""
+        self.sl4f_obj.run.return_value = {
+            "result": {
+                "Connected": {
+                    "bssid": [1, 2],
+                    "ssid": [1, 2],
                     "channel": {
                         "primary": 1,
                         "cbw": "Cbw20",
                         "secondary80": 3,
                     },
                     "protection": 1,
-                },
-                "Connecting": [1, 2, 3],
-                "Idle": "test",
+                }
             }
         }
 
diff --git a/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/starnix/BUILD.gn b/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/starnix/BUILD.gn
index a8be4f9..f01a8c9 100644
--- a/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/starnix/BUILD.gn
+++ b/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/starnix/BUILD.gn
@@ -8,7 +8,10 @@
   python_host_test("system_power_state_controller_starnix_test") {
     enable_mypy = true
     main_source = "system_power_state_controller_test.py"
-    libraries = [ "//src/testing/end_to_end/honeydew" ]
+    libraries = [
+      "//src/testing/end_to_end/honeydew",
+      "//third_party/parameterized",
+    ]
     main_callable = "unittest.main"
     extra_args = [ "-v" ]
   }
diff --git a/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/starnix/system_power_state_controller_test.py b/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/starnix/system_power_state_controller_test.py
index bdb7c45..92afd91 100644
--- a/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/starnix/system_power_state_controller_test.py
+++ b/src/testing/end_to_end/honeydew/tests/unit_tests/affordances_tests/starnix/system_power_state_controller_test.py
@@ -7,6 +7,8 @@
 import unittest
 from unittest import mock
 
+from parameterized import param, parameterized
+
 from honeydew import errors
 from honeydew.affordances.starnix import (
     system_power_state_controller as starnix_system_power_state_controller,
@@ -14,12 +16,51 @@
 from honeydew.interfaces.affordances import (
     system_power_state_controller as system_power_state_controller_interface,
 )
+from honeydew.interfaces.device_classes import affordances_capable
 from honeydew.transports import ffx as ffx_transport
 
 _INPUT_ARGS: dict[str, object] = {
     "device_name": "fuchsia-emulator",
 }
 
+_SUSPEND_RESUME_SUCCESS_LOGS: list[str] = [
+    "[00174.893370][remote-control][lacewing] INFO: [Host Time: 2024-04-16-08-38-16-PM] - Performing 'IdleSuspend' followed by 'AutomaticResume after 5sec' operations on 'fuchsia-c863-1470-a849'...",
+    "[00175.010150][system-activity-governor] INFO: Suspending",
+    "[00180.030013][system-activity-governor] INFO: Resuming response=Ok(Ok(SuspenderSuspendResponse { reason: None, suspend_duration: Some(0), suspend_overhead: Some(0), __source_breaking: SourceBreaking }))",
+    "[00180.088070][remote-control][lacewing] INFO: [Host Time: 2024-04-16-08-38-21-PM] - Completed 'IdleSuspend' followed by 'AutomaticResume after 5sec' operations on 'fuchsia-c863-1470-a849' in 5.165762186050415 seconds.",
+]
+
+_SUSPEND_RESUME_FAILURE_LOGS_NO_LACEWING_START: list[str] = [
+    "[00175.010150][system-activity-governor] INFO: Suspending",
+    "[00180.030013][system-activity-governor] INFO: Resuming response=Ok(Ok(SuspenderSuspendResponse { reason: None, suspend_duration: Some(0), suspend_overhead: Some(0), __source_breaking: SourceBreaking }))",
+    "[00180.088070][remote-control][lacewing] INFO: [Host Time: 2024-04-16-08-38-21-PM] - Completed 'IdleSuspend' followed by 'AutomaticResume after 5sec' operations on 'fuchsia-c863-1470-a849' in 5.165762186050415 seconds.",
+]
+
+_SUSPEND_RESUME_FAILURE_LOGS_NO_SUSPEND: list[str] = [
+    "[00174.893370][remote-control][lacewing] INFO: [Host Time: 2024-04-16-08-38-16-PM] - Performing 'IdleSuspend' followed by 'AutomaticResume after 5sec' operations on 'fuchsia-c863-1470-a849'...",
+    "[00180.030013][system-activity-governor] INFO: Resuming response=Ok(Ok(SuspenderSuspendResponse { reason: None, suspend_duration: Some(0), suspend_overhead: Some(0), __source_breaking: SourceBreaking }))",
+    "[00180.088070][remote-control][lacewing] INFO: [Host Time: 2024-04-16-08-38-21-PM] - Completed 'IdleSuspend' followed by 'AutomaticResume after 5sec' operations on 'fuchsia-c863-1470-a849' in 5.165762186050415 seconds.",
+]
+
+_SUSPEND_RESUME_FAILURE_LOGS_NO_RESUME: list[str] = [
+    "[00174.893370][remote-control][lacewing] INFO: [Host Time: 2024-04-16-08-38-16-PM] - Performing 'IdleSuspend' followed by 'AutomaticResume after 5sec' operations on 'fuchsia-c863-1470-a849'...",
+    "[00175.010150][system-activity-governor] INFO: Suspending",
+    "[00180.088070][remote-control][lacewing] INFO: [Host Time: 2024-04-16-08-38-21-PM] - Completed 'IdleSuspend' followed by 'AutomaticResume after 5sec' operations on 'fuchsia-c863-1470-a849' in 5.165762186050415 seconds.",
+]
+
+_SUSPEND_RESUME_FAILURE_LOGS_NO_LACEWING_END: list[str] = [
+    "[00174.893370][remote-control][lacewing] INFO: [Host Time: 2024-04-16-08-38-16-PM] - Performing 'IdleSuspend' followed by 'AutomaticResume after 5sec' operations on 'fuchsia-c863-1470-a849'...",
+    "[00175.010150][system-activity-governor] INFO: Suspending",
+    "[00180.030013][system-activity-governor] INFO: Resuming response=Ok(Ok(SuspenderSuspendResponse { reason: None, suspend_duration: Some(0), suspend_overhead: Some(0), __source_breaking: SourceBreaking }))",
+]
+
+
+def _custom_test_name_func(testcase_func, _, param_obj: param) -> str:
+    """Custom test name function method."""
+    test_func_name: str = testcase_func.__name__
+    test_label: str = parameterized.to_safe_name(param_obj.kwargs["label"])
+    return f"{test_func_name}_with_{test_label}"
+
 
 # pylint: disable=protected-access
 class SystemPowerStateControllerStarnixTests(unittest.TestCase):
@@ -29,6 +70,9 @@
         super().setUp()
 
         self.mock_ffx = mock.MagicMock(spec=ffx_transport.FFX)
+        self.mock_device_logger = mock.MagicMock(
+            spec=affordances_capable.FuchsiaDeviceLogger
+        )
 
         with mock.patch.object(
             starnix_system_power_state_controller.SystemPowerStateController,
@@ -37,6 +81,7 @@
         ) as mock_run_starnix_console_shell_cmd:
             self.system_power_state_controller_obj = starnix_system_power_state_controller.SystemPowerStateController(
                 ffx=self.mock_ffx,
+                device_logger=self.mock_device_logger,
                 device_name=str(_INPUT_ARGS["device_name"]),
             )
 
@@ -50,11 +95,14 @@
     def test_idle_suspend_auto_resume(self, mock_suspend_resume) -> None:
         """Test case for SystemPowerStateController.idle_suspend_auto_resume()"""
 
-        self.system_power_state_controller_obj.idle_suspend_auto_resume()
+        self.system_power_state_controller_obj.idle_suspend_auto_resume(
+            verify=False,
+        )
         mock_suspend_resume.assert_called_once_with(
             mock.ANY,
             suspend_state=system_power_state_controller_interface.IdleSuspend(),
             resume_mode=system_power_state_controller_interface.AutomaticResume(),
+            verify=False,
         )
 
     @mock.patch.object(
@@ -74,6 +122,7 @@
         self.system_power_state_controller_obj.suspend_resume(
             suspend_state=system_power_state_controller_interface.IdleSuspend(),
             resume_mode=system_power_state_controller_interface.AutomaticResume(),
+            verify=True,
         )
 
         mock_run_starnix_console_shell_cmd.assert_called_once_with(
@@ -85,34 +134,8 @@
             mock.ANY,
             suspend_state=system_power_state_controller_interface.IdleSuspend(),
             resume_mode=system_power_state_controller_interface.AutomaticResume(),
-            duration=mock.ANY,
-        )
-
-    @mock.patch.object(
-        starnix_system_power_state_controller.SystemPowerStateController,
-        "_run_starnix_console_shell_cmd",
-        autospec=True,
-    )
-    def test_verify_suspend_resume_for_idle_suspend_auto_resume(
-        self, mock_run_starnix_console_shell_cmd
-    ) -> None:
-        """Test case for SystemPowerStateController._verify_suspend_resume()
-        raising an exception."""
-        with self.assertRaisesRegex(
-            errors.SystemPowerStateControllerError,
-            "Putting the 'fuchsia-emulator' into 'IdleSuspend' followed by "
-            "'AutomaticResume after .+sec' operation took .+ seconds instead "
-            "of .+ seconds",
-        ):
-            self.system_power_state_controller_obj.suspend_resume(
-                suspend_state=system_power_state_controller_interface.IdleSuspend(),
-                resume_mode=system_power_state_controller_interface.AutomaticResume(),
-            )
-
-        mock_run_starnix_console_shell_cmd.assert_called_once_with(
-            mock.ANY,
-            cmd=starnix_system_power_state_controller._StarnixCmds.IDLE_SUSPEND,
-            timeout=None,
+            suspend_resume_duration=mock.ANY,
+            logs_duration=mock.ANY,
         )
 
     def test_suspend_resume_with_not_supported_suspend_mode(self) -> None:
@@ -197,3 +220,138 @@
             )
         mock_openpty.assert_called_once()
         mock_os_read.assert_called_once()
+
+    @mock.patch.object(
+        starnix_system_power_state_controller.SystemPowerStateController,
+        "_run_starnix_console_shell_cmd",
+        side_effect=errors.StarnixError("error"),
+        autospec=True,
+    )
+    def test_perform_idle_suspend_exception(
+        self,
+        mock_run_starnix_console_shell_cmd: mock.Mock,
+    ) -> None:
+        """Test case for SystemPowerStateController._perform_idle_suspend()
+        raising exception"""
+        with self.assertRaises(errors.SystemPowerStateControllerError):
+            self.system_power_state_controller_obj._perform_idle_suspend()
+
+        mock_run_starnix_console_shell_cmd.assert_called_once()
+
+    @mock.patch.object(
+        starnix_system_power_state_controller.SystemPowerStateController,
+        "_verify_suspend_resume_using_log_analysis",
+        autospec=True,
+    )
+    @mock.patch.object(
+        starnix_system_power_state_controller.SystemPowerStateController,
+        "_verify_suspend_resume_using_duration",
+        autospec=True,
+    )
+    def test_verify_suspend_resume(
+        self,
+        mock_verify_suspend_resume_using_duration: mock.Mock,
+        mock_verify_suspend_resume_using_log_analysis: mock.Mock,
+    ) -> None:
+        """Test case for SystemPowerStateController._verify_suspend_resume()"""
+        self.system_power_state_controller_obj._verify_suspend_resume(
+            suspend_state=system_power_state_controller_interface.IdleSuspend(),
+            resume_mode=system_power_state_controller_interface.AutomaticResume(),
+            suspend_resume_duration=5,
+            logs_duration=7,
+        )
+
+        mock_verify_suspend_resume_using_duration.assert_called_once_with(
+            mock.ANY,
+            suspend_state=system_power_state_controller_interface.IdleSuspend(),
+            resume_mode=system_power_state_controller_interface.AutomaticResume(),
+            suspend_resume_duration=5,
+        )
+
+        mock_verify_suspend_resume_using_log_analysis.assert_called_once_with(
+            mock.ANY,
+            suspend_state=system_power_state_controller_interface.IdleSuspend(),
+            resume_mode=system_power_state_controller_interface.AutomaticResume(),
+            logs_duration=7,
+        )
+
+    def test_verify_suspend_resume_using_duration_success(self) -> None:
+        """Test case for SystemPowerStateController._verify_suspend_resume_using_duration()
+        success case"""
+        self.system_power_state_controller_obj._verify_suspend_resume_using_duration(
+            suspend_state=system_power_state_controller_interface.IdleSuspend(),
+            resume_mode=system_power_state_controller_interface.AutomaticResume(),
+            suspend_resume_duration=system_power_state_controller_interface.AutomaticResume.duration
+            + 2,
+        )
+
+    def test_verify_suspend_resume_using_duration_fail(self) -> None:
+        """Test case for SystemPowerStateController._verify_suspend_resume_using_duration()
+        failure case"""
+        with self.assertRaisesRegex(
+            errors.SystemPowerStateControllerError,
+            "'IdleSuspend' followed by 'AutomaticResume after .+sec' "
+            "operation took .+ seconds on 'fuchsia-emulator'",
+        ):
+            self.system_power_state_controller_obj._verify_suspend_resume_using_duration(
+                suspend_state=system_power_state_controller_interface.IdleSuspend(),
+                resume_mode=system_power_state_controller_interface.AutomaticResume(),
+                suspend_resume_duration=system_power_state_controller_interface.AutomaticResume.duration
+                + 20,
+            )
+
+    def test_verify_suspend_resume_using_log_analysis_success(self) -> None:
+        """Test case for SystemPowerStateController._verify_suspend_resume_using_log_analysis()
+        success case"""
+        self.mock_ffx.run.return_value = "\n".join(_SUSPEND_RESUME_SUCCESS_LOGS)
+
+        self.system_power_state_controller_obj._verify_suspend_resume_using_log_analysis(
+            suspend_state=system_power_state_controller_interface.IdleSuspend(),
+            resume_mode=system_power_state_controller_interface.AutomaticResume(),
+            logs_duration=7,
+        )
+
+        self.mock_ffx.run.assert_called_once()
+
+    @parameterized.expand(
+        [
+            param(
+                label="no_suspend",
+                device_logs=_SUSPEND_RESUME_FAILURE_LOGS_NO_SUSPEND,
+            ),
+            param(
+                label="no_resume",
+                device_logs=_SUSPEND_RESUME_FAILURE_LOGS_NO_RESUME,
+            ),
+            param(
+                label="no_lacewing_start",
+                device_logs=_SUSPEND_RESUME_FAILURE_LOGS_NO_LACEWING_START,
+            ),
+            param(
+                label="no_lacewing_end",
+                device_logs=_SUSPEND_RESUME_FAILURE_LOGS_NO_LACEWING_END,
+            ),
+        ],
+        name_func=_custom_test_name_func,
+    )
+    def test_verify_suspend_resume_using_log_analysis_fail(
+        self,
+        label: str,  # pylint: disable=unused-argument
+        device_logs: list[str],
+    ) -> None:
+        """Test case for SystemPowerStateController._verify_suspend_resume_using_log_analysis()
+        failure case"""
+        self.mock_ffx.run.return_value = "\n".join(device_logs)
+
+        with self.assertRaisesRegex(
+            errors.SystemPowerStateControllerError,
+            "Log analysis for 'IdleSuspend' followed by 'AutomaticResume after .+sec' "
+            "operation failed on 'fuchsia-emulator'",
+        ):
+            self.system_power_state_controller_obj._verify_suspend_resume_using_log_analysis(
+                suspend_state=system_power_state_controller_interface.IdleSuspend(),
+                resume_mode=system_power_state_controller_interface.AutomaticResume(),
+                logs_duration=5,
+            )
+
+        self.mock_ffx.run.assert_called_once()
diff --git a/src/testing/realm_proxy/client/src/lib.rs b/src/testing/realm_proxy/client/src/lib.rs
index 00b39e9..105d316 100644
--- a/src/testing/realm_proxy/client/src/lib.rs
+++ b/src/testing/realm_proxy/client/src/lib.rs
@@ -6,7 +6,8 @@
     anyhow::{bail, format_err, Result},
     fdio::Namespace,
     fidl::endpoints::{
-        create_endpoints, ClientEnd, DiscoverableProtocolMarker, Proxy, ServiceMarker, ServiceProxy,
+        create_endpoints, ClientEnd, DiscoverableProtocolMarker, Proxy, ServerEnd, ServiceMarker,
+        ServiceProxy,
     },
     fidl_fuchsia_component as fcomponent, fidl_fuchsia_component_sandbox as fsandbox,
     fidl_fuchsia_io as fio,
@@ -150,6 +151,16 @@
         self.connect_to_named_protocol::<T>(T::PROTOCOL_NAME).await
     }
 
+    // Connects the `sever_end` to the protocol marked by [T] via the proxy.
+    //
+    // Returns an error if the connection fails.
+    pub async fn connect_server_end_to_protocol<T: DiscoverableProtocolMarker>(
+        &self,
+        server_end: ServerEnd<T>,
+    ) -> Result<(), anyhow::Error> {
+        self.connect_server_end_to_named_protocol::<T>(T::PROTOCOL_NAME, server_end).await
+    }
+
     // Connects to the protocol with the given name, via the proxy.
     //
     // Returns an error if the connection fails.
@@ -158,14 +169,26 @@
         protocol_name: &str,
     ) -> Result<T::Proxy, anyhow::Error> {
         let (client, server) = create_endpoints::<T>();
+        self.connect_server_end_to_named_protocol(protocol_name, server).await?;
+        Ok(client.into_proxy()?)
+    }
+
+    // Connects the `server_end` to the protocol with the given name, via the proxy.
+    //
+    // Returns an error if the connection fails.
+    pub async fn connect_server_end_to_named_protocol<T: DiscoverableProtocolMarker>(
+        &self,
+        protocol_name: &str,
+        server_end: ServerEnd<T>,
+    ) -> Result<(), anyhow::Error> {
         let res =
-            self.inner.connect_to_named_protocol(protocol_name, server.into_channel()).await?;
+            self.inner.connect_to_named_protocol(protocol_name, server_end.into_channel()).await?;
 
         if let Some(op_err) = res.err() {
             bail!("{:?}", op_err);
         }
 
-        Ok(client.into_proxy()?)
+        Ok(())
     }
 
     // Opens the given service capability, via the proxy.
diff --git a/src/testing/realm_proxy/src/service.rs b/src/testing/realm_proxy/src/service.rs
index 61ab199..f43e061 100644
--- a/src/testing/realm_proxy/src/service.rs
+++ b/src/testing/realm_proxy/src/service.rs
@@ -11,7 +11,7 @@
     fuchsia_component_test::RealmInstance,
     fuchsia_zircon::{self as zx},
     futures::{Future, StreamExt, TryStreamExt},
-    tracing::{error, info, warn},
+    tracing::{debug, error, warn},
 };
 
 // RealmProxy mediates a test suite's access to the services in a test realm.
@@ -168,7 +168,7 @@
     }
 
     // Tell the user we're disconnecting in case this is a premature shutdown.
-    info!("done serving the RealmProxy connection");
+    debug!("done serving the RealmProxy connection");
     Ok(())
 }
 
diff --git a/src/testing/runtests/runtests.cc b/src/testing/runtests/runtests.cc
index 9822b75..8e05774 100644
--- a/src/testing/runtests/runtests.cc
+++ b/src/testing/runtests/runtests.cc
@@ -20,26 +20,8 @@
 
 const char* kDefaultTestDirs[] = {
     // zircon builds place everything in ramdisks so tests are located in /boot
-    "/boot/test",
-    "/boot/test/c",
-    "/boot/test/core",
-    "/boot/test/libc",
-    "/boot/test/ddk",
-    "/boot/test/sys",
-    "/boot/test/fs",
-    "/boot/test/storage",
-    // /pkgfs is where test binaries should be found in garnet and above.
-    "/pkgfs/packages/*/*/test",
-    // Moreover, for the higher layers, there are still tests using the deprecated /system image.
-    // Soon they will all be moved under /pkgfs.
-    "/system/test",
-    "/system/test/c",
-    "/system/test/core",
-    "/system/test/libc",
-    "/system/test/ddk",
-    "/system/test/sys",
-    "/system/test/fs",
-    "/system/test/storage",
+    "/boot/test",     "/boot/test/c",   "/boot/test/core", "/boot/test/libc",
+    "/boot/test/ddk", "/boot/test/sys", "/boot/test/fs",   "/boot/test/storage",
 };
 
 class FuchsiaStopwatch final : public runtests::Stopwatch {
diff --git a/src/testing/sl4f/BUILD.gn b/src/testing/sl4f/BUILD.gn
index 1d013bb..f5fdebd 100644
--- a/src/testing/sl4f/BUILD.gn
+++ b/src/testing/sl4f/BUILD.gn
@@ -129,7 +129,6 @@
     "//src/testing/fidl:placeholders_rust",
     "//third_party/rust_crates:assert_matches",
     "//third_party/rust_crates:lazy_static",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:tempfile",
     "//third_party/rust_crates:test-case",
   ]
diff --git a/src/testing/sl4f/src/fidl/sl4f.rs b/src/testing/sl4f/src/fidl/sl4f.rs
index fc6cfb5..d04f5e2 100644
--- a/src/testing/sl4f/src/fidl/sl4f.rs
+++ b/src/testing/sl4f/src/fidl/sl4f.rs
@@ -201,10 +201,10 @@
     use fidl_fuchsia_testing_sl4f::FacadeProviderMarker;
     use fuchsia_async as fasync;
     use fuchsia_zircon as zx;
-    use pin_utils::pin_mut;
     use serde_json::json;
     use std::cell::RefCell;
     use std::collections::HashMap;
+    use std::pin::pin;
     use std::task::Poll;
 
     /// TestFacade provides a trivial Facade implementation which supports commands to interact
@@ -343,11 +343,10 @@
             drop(proxy);
             Ok::<(), Error>(())
         };
-        let combined_fut = async {
+        let mut combined_fut = pin!(async {
             let (_, res) = futures::join!(server_fut, client_fut);
             res.unwrap();
-        };
-        pin_mut!(combined_fut);
+        });
 
         assert_eq!(Poll::Ready(()), executor.run_until_stalled(&mut combined_fut));
 
diff --git a/src/tests/assembly/assemble_image/assemble_image/BUILD.gn b/src/tests/assembly/assemble_image/assemble_image/BUILD.gn
index 2ea05db..78d9036 100644
--- a/src/tests/assembly/assemble_image/assemble_image/BUILD.gn
+++ b/src/tests/assembly/assemble_image/assemble_image/BUILD.gn
@@ -10,7 +10,6 @@
     feature_set_level = "empty"
     build_type = "eng"
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "assemble_test"
         volume = {
diff --git a/src/tests/assembly/assemble_image/compiled_package/BUILD.gn b/src/tests/assembly/assemble_image/compiled_package/BUILD.gn
index 52603ae..fb249f4 100644
--- a/src/tests/assembly/assemble_image/compiled_package/BUILD.gn
+++ b/src/tests/assembly/assemble_image/compiled_package/BUILD.gn
@@ -27,7 +27,6 @@
       include_example_aib = true
     }
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "assemble_test"
         volume = {
diff --git a/src/tests/assembly/assemble_image/developer_packages/BUILD.gn b/src/tests/assembly/assemble_image/developer_packages/BUILD.gn
index add54ab..6225f05 100644
--- a/src/tests/assembly/assemble_image/developer_packages/BUILD.gn
+++ b/src/tests/assembly/assemble_image/developer_packages/BUILD.gn
@@ -26,7 +26,6 @@
     feature_set_level = "empty"
     build_type = "eng"
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "assemble_test"
         volume = {
diff --git a/src/tests/assembly/assemble_image/product_drivers/BUILD.gn b/src/tests/assembly/assemble_image/product_drivers/BUILD.gn
index e33c897..76f6044f 100644
--- a/src/tests/assembly/assemble_image/product_drivers/BUILD.gn
+++ b/src/tests/assembly/assemble_image/product_drivers/BUILD.gn
@@ -10,7 +10,6 @@
     feature_set_level = "empty"
     build_type = "eng"
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "assemble_test"
         volume = {
diff --git a/src/tests/assembly/assemble_image/structured_config/BUILD.gn b/src/tests/assembly/assemble_image/structured_config/BUILD.gn
index e86eb29..e0fdd4e 100644
--- a/src/tests/assembly/assemble_image/structured_config/BUILD.gn
+++ b/src/tests/assembly/assemble_image/structured_config/BUILD.gn
@@ -14,7 +14,6 @@
     feature_set_level = "bootstrap"
     build_type = "eng"
     storage = {
-      configure_fshost = true
       filesystems = {
         image_name = "assemble_test"
         volume = {
diff --git a/src/tests/benchmarks/fidl/fidlc/main.cc b/src/tests/benchmarks/fidl/fidlc/main.cc
index 8466063..5290301 100644
--- a/src/tests/benchmarks/fidl/fidlc/main.cc
+++ b/src/tests/benchmarks/fidl/fidlc/main.cc
@@ -9,7 +9,6 @@
 #include "src/tests/benchmarks/fidl/fidlc/benchmarks.h"
 #include "tools/fidl/fidlc/src/json_generator.h"
 #include "tools/fidl/fidlc/src/lexer.h"
-#include "tools/fidl/fidlc/src/ordinals.h"
 #include "tools/fidl/fidlc/src/parser.h"
 #include "tools/fidl/fidlc/src/source_file.h"
 #include "tools/fidl/fidlc/src/virtual_source_file.h"
@@ -32,7 +31,7 @@
     fidlc::VirtualSourceFile virtual_file("generated");
     fidlc::Libraries all_libraries(&reporter, &virtual_file);
     fidlc::VersionSelection version_selection;
-    fidlc::Compiler compiler(&all_libraries, &version_selection, fidlc::GetGeneratedOrdinal64,
+    fidlc::Compiler compiler(&all_libraries, &version_selection, fidlc::Sha256MethodHasher,
                              experimental_flags);
     auto ast = parser.Parse();
     bool enable_color = !std::getenv("NO_COLOR") && isatty(fileno(stderr));
diff --git a/src/tests/benchmarks/fidl/hlcpp/coding_table.h b/src/tests/benchmarks/fidl/hlcpp/coding_table.h
index 0ca64ea..fce959a 100644
--- a/src/tests/benchmarks/fidl/hlcpp/coding_table.h
+++ b/src/tests/benchmarks/fidl/hlcpp/coding_table.h
@@ -11,7 +11,7 @@
 namespace hlcpp_benchmarks {
 
 template <typename FidlType>
-constexpr size_t EncodedSize = fidl::CodingTraits<FidlType>::inline_size_v2;
+constexpr size_t EncodedSize = fidl::CodingTraits<FidlType>::kInlineSize;
 
 }  // namespace hlcpp_benchmarks
 
diff --git a/src/tests/diagnostics/meta/component_manager_status_tests.cml b/src/tests/diagnostics/meta/component_manager_status_tests.cml
index a22bae5..dd5a3fd 100644
--- a/src/tests/diagnostics/meta/component_manager_status_tests.cml
+++ b/src/tests/diagnostics/meta/component_manager_status_tests.cml
@@ -10,10 +10,13 @@
             // Component manager reports that it is healthy.
             "<component_manager>:root/fuchsia.inspect.Health:status WHERE [a] a == 'OK'",
 
-            // Ensure component manager has at least 256KiB of space
+            // LINT.IfChange
+            // Ensure component manager has at least 300KiB of space
             // for inspect, and that this limit is not reached.
-            "<component_manager>:root/fuchsia.inspect.Stats:current_size WHERE [a] a < 256*1024",
-            "<component_manager>:root/fuchsia.inspect.Stats:maximum_size WHERE [a] a >= 256*1024",
+            "<component_manager>:root/fuchsia.inspect.Stats:current_size WHERE [a] a < 350*1024",
+            "<component_manager>:root/fuchsia.inspect.Stats:maximum_size WHERE [a] a >= 350*1024",
+
+            // LINT.ThenChange(/src/sys/component_manager/src/builtin_environment.rs)
         ],
     },
 }
diff --git a/src/tests/early-boot-coverage/host-test/BUILD.gn b/src/tests/early-boot-coverage/host-test/BUILD.gn
index a776752..fb1a380 100644
--- a/src/tests/early-boot-coverage/host-test/BUILD.gn
+++ b/src/tests/early-boot-coverage/host-test/BUILD.gn
@@ -45,9 +45,7 @@
   deps = [ "//src/storage/bin/fvm" ]
 }
 
-host_test_data("ssh_key") {
-  sources = [
-    "//.ssh/pkey",
-    "//.ssh/pkey.pub",
-  ]
+host_test_data("zbi") {
+  sources = [ "$host_out_dir/zbi" ]
+  deps = [ "//zircon/tools/zbi" ]
 }
diff --git a/src/tests/early-boot-coverage/host-test/configration.schema.json b/src/tests/early-boot-coverage/host-test/configration.schema.json
index 14b814a..26b5cd6 100644
--- a/src/tests/early-boot-coverage/host-test/configration.schema.json
+++ b/src/tests/early-boot-coverage/host-test/configration.schema.json
@@ -15,13 +15,21 @@
                 "llvm_cxxfilt": {
                     "type": "string"
                 },
+                "ffx": {
+                    "type": "string"
+                },
                 "fvm": {
                     "type": "string"
+                },
+                "zbi_host_tool": {
+                    "type": "string"
                 }
             },
             "required": [
                 "llvm_cov",
-                "llvm_profdata"
+                "llvm_profdata",
+                "ffx",
+                "zbi_host_tool"
             ]
         },
         "test": {
@@ -41,10 +49,6 @@
                 "block_image": {
                     "type": "string",
                     "description": "Block image to back a drive.(E.g. FVM, FXFS, etc)"
-                },
-                "ssh_key": {
-                    "type": "string",
-                    "description": "Path to ssh key file to be used for ffx."
                 }
             },
             "required": [
@@ -97,4 +101,4 @@
         "test",
         "expectations"
     ]
-}
\ No newline at end of file
+}
diff --git a/src/tests/early-boot-coverage/host-test/coverage_verification_test.gni b/src/tests/early-boot-coverage/host-test/coverage_verification_test.gni
index 1244872..d56c715 100644
--- a/src/tests/early-boot-coverage/host-test/coverage_verification_test.gni
+++ b/src/tests/early-boot-coverage/host-test/coverage_verification_test.gni
@@ -113,6 +113,7 @@
       llvm_cxxfilt = rebase_path("${clang_prefix}/llvm-cxxfilt", root_build_dir)
       fvm = rebase_path(fvm_host_tool, root_build_dir)
       ffx = rebase_path("${host_tools_dir}/ffx", root_build_dir)
+      zbi_host_tool = rebase_path("${host_out_dir}/zbi", root_build_dir)
     }
 
     # Test specific artifacts.
@@ -121,7 +122,6 @@
       name = invoker.test_uri
       zbi_image = zbi_name
       block_image = block_image
-      ssh_key = rebase_path("//.ssh/pkey", rebase_path(root_build_dir))
     }
 
     # Represents the validation to be performed on the coverage data.
@@ -161,7 +161,7 @@
                     "//src/developer/ffx/plugins/test:ffx_test_tool_test_data",
                     "//src/tests/early-boot-coverage/host-test:coverage_tools",
                     "//src/tests/early-boot-coverage/host-test:fvm",
-                    "//src/tests/early-boot-coverage/host-test:ssh_key",
+                    "//src/tests/early-boot-coverage/host-test:zbi",
                   ] + extra_deps
     args = [
       "-config",
diff --git a/src/tests/early-boot-coverage/host-test/coverage_verifier_test.go b/src/tests/early-boot-coverage/host-test/coverage_verifier_test.go
index 08c95b1..24245b3 100644
--- a/src/tests/early-boot-coverage/host-test/coverage_verifier_test.go
+++ b/src/tests/early-boot-coverage/host-test/coverage_verifier_test.go
@@ -41,6 +41,7 @@
 	LlvmProfdata string `json:"llvm_profdata"`
 	LlvmCxxFilt  string `json:"llvm_cxxfilt"`
 	Fvm          string `json:"fvm"`
+	ZbiHostTool  string `json:"zbi_host_tool"`
 }
 
 type Function struct {
@@ -58,7 +59,6 @@
 	Name       string `json:"name"`
 	ZbiImage   string `json:"zbi_image"`
 	BlockImage string `json:"block_image"`
-	SshKeyFile string `json:"ssh_key,omitempty"`
 }
 
 type Config struct {
@@ -122,7 +122,22 @@
 
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
-	i := distro.CreateContext(ctx, device)
+
+	runnerCtx := context.Background()
+	ffxInstance, err := ffxutil.NewFFXInstance(runnerCtx, config.Bin.Ffx, "", os.Environ(), defaultNodename, "", outDir)
+	if err != nil {
+		t.Fatalf("Cannot create Ffx instance. Reason: %s", err)
+	}
+
+	hostPathAuthorizedKeys, err := ffxInstance.GetSshAuthorizedKeys(ctx)
+	if err != nil {
+		t.Fatalf("Cannot get authorized key path. Reason: %s", err)
+	}
+	hostPathSshKey, err := ffxInstance.GetSshPrivateKey(ctx)
+	if err != nil {
+		t.Fatalf("Cannot get private key path. Reason: %s", err)
+	}
+	i := distro.CreateContextWithAuthorizedKeys(ctx, device, config.Bin.ZbiHostTool, hostPathAuthorizedKeys)
 	i.Start()
 	i.WaitForLogMessage("initializing platform")
 	// Component manager starts up.
@@ -153,8 +168,8 @@
 	var address net.IPAddr = ipv6
 
 	t.Log("Establishing SSH Session.")
-	runnerCtx := context.Background()
-	sshRunner, err = testrunner.NewFuchsiaSSHTester(runnerCtx, address, config.Test.SshKeyFile, outDir, "")
+
+	sshRunner, err = testrunner.NewFuchsiaSSHTester(runnerCtx, address, hostPathSshKey, outDir, "")
 	if err != nil {
 		t.Fatalf("Error initializing Fuchsia SSH Test. Reason: %s", err)
 	}
@@ -168,11 +183,6 @@
 	// here as well.
 	ffxExperimentLevel := 1
 
-	ffxInstance, err := ffxutil.NewFFXInstance(runnerCtx, config.Bin.Ffx, "", os.Environ(), defaultNodename, config.Test.SshKeyFile, outDir)
-	if err != nil {
-		t.Fatalf("Cannot create Ffx instance. Reason: %s", err)
-	}
-
 	ffxRunner, err := testrunner.NewFFXTester(runnerCtx, ffxInstance, sshRunner, outDir, ffxExperimentLevel)
 	if err != nil {
 		t.Fatalf("Cannot create Ffx Tester. Reason: %s", err)
diff --git a/src/tests/end_to_end/perf/BUILD.gn b/src/tests/end_to_end/perf/BUILD.gn
index 4e5b2bf..0f1d121 100644
--- a/src/tests/end_to_end/perf/BUILD.gn
+++ b/src/tests/end_to_end/perf/BUILD.gn
@@ -145,9 +145,7 @@
 }
 
 _python_benchmarks += [
-  "//src/connectivity/network/drivers/network-device/device:benchmarks",
-  "//src/connectivity/network/netstack3:benchmarks",
-  "//src/connectivity/network/tests/benchmarks",
+  "//src/connectivity/network:benchmarks",
   "//src/devices/bin/driver_runtime/microbenchmarks",
   "//src/diagnostics:benchmarks",
   "//src/lib/diagnostics:benchmarks",
@@ -166,8 +164,6 @@
   deps = _python_benchmarks
 
   deps += [
-    "//third_party/sbase:sbase-pkgs",
-
     # Many tests use sl4f to communicate with the target.
     "//src/testing/sl4f",
 
diff --git a/src/ui/backlight/drivers/ti-lp8556/BUILD.gn b/src/ui/backlight/drivers/ti-lp8556/BUILD.gn
index 9f7c8fb..ef44dc3 100644
--- a/src/ui/backlight/drivers/ti-lp8556/BUILD.gn
+++ b/src/ui/backlight/drivers/ti-lp8556/BUILD.gn
@@ -88,7 +88,7 @@
     "//src/devices/i2c/testing/mock-i2c",
     "//src/devices/lib/mmio",
     "//src/devices/testing/mock-ddk",
-    "//src/devices/testing/mock-mmio-reg-zxtest",
+    "//src/devices/testing/mock-mmio-reg:mock-mmio-reg-zxtest",
     "//src/lib/ddk",
     "//src/lib/ddktl",
     "//zircon/system/ulib/async-loop",
diff --git a/src/ui/backlight/drivers/ti-lp8556/ti-lp8556-test.cc b/src/ui/backlight/drivers/ti-lp8556/ti-lp8556-test.cc
index 1baa9d5..1e9ba11 100644
--- a/src/ui/backlight/drivers/ti-lp8556/ti-lp8556-test.cc
+++ b/src/ui/backlight/drivers/ti-lp8556/ti-lp8556-test.cc
@@ -18,7 +18,7 @@
 
 #include <map>
 
-#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
 #include <zxtest/zxtest.h>
 
 #include "sdk/lib/inspect/testing/cpp/zxtest/inspect.h"
@@ -477,10 +477,9 @@
       .pid = PDEV_PID_NELSON,
   };
 
-  zx::result outgoing_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(outgoing_endpoints);
+  auto outgoing_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   ASSERT_OK(incoming_loop.StartThread("incoming-ns-thread"));
-  incoming.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints->server)](
+  incoming.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints.server)](
                         IncomingNamespace* infra) mutable {
     infra->pdev_server.SetConfig(std::move(config));
     ASSERT_OK(infra->outgoing.AddService<fuchsia_hardware_platform_device::Service>(
@@ -490,7 +489,7 @@
   });
   ASSERT_NO_FATAL_FAILURE();
   fake_parent_->AddFidlService(fuchsia_hardware_platform_device::Service::Name,
-                               std::move(outgoing_endpoints->client), "pdev");
+                               std::move(outgoing_endpoints.client), "pdev");
 
   fake_parent_->SetMetadata(DEVICE_METADATA_PRIVATE, &kDeviceMetadata, sizeof(kDeviceMetadata));
   fake_parent_->SetMetadata(DEVICE_METADATA_BOARD_PRIVATE, &kPanelId, sizeof(kPanelId));
@@ -536,10 +535,9 @@
       .pid = PDEV_PID_NELSON,
   };
 
-  zx::result outgoing_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-  ASSERT_OK(outgoing_endpoints);
+  auto outgoing_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
   ASSERT_OK(incoming_loop.StartThread("incoming-ns-thread"));
-  incoming.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints->server)](
+  incoming.SyncCall([config = std::move(config), server = std::move(outgoing_endpoints.server)](
                         IncomingNamespace* infra) mutable {
     infra->pdev_server.SetConfig(std::move(config));
     ASSERT_OK(infra->outgoing.AddService<fuchsia_hardware_platform_device::Service>(
@@ -549,7 +547,7 @@
   });
   ASSERT_NO_FATAL_FAILURE();
   fake_parent_->AddFidlService(fuchsia_hardware_platform_device::Service::Name,
-                               std::move(outgoing_endpoints->client), "pdev");
+                               std::move(outgoing_endpoints.client), "pdev");
 
   fake_parent_->SetMetadata(DEVICE_METADATA_PRIVATE, &kDeviceMetadata, sizeof(kDeviceMetadata));
   fake_parent_->SetMetadata(DEVICE_METADATA_BOARD_PRIVATE, &kPanelId, sizeof(kPanelId));
diff --git a/src/ui/bin/terminal/src/ui/terminal_scene.rs b/src/ui/bin/terminal/src/ui/terminal_scene.rs
index 1f06fed..ee030ba 100644
--- a/src/ui/bin/terminal/src/ui/terminal_scene.rs
+++ b/src/ui/bin/terminal/src/ui/terminal_scene.rs
@@ -61,14 +61,10 @@
         }
     }
 
-    // Cancel existing task. Returns true if task was scheduled.
+    // Cancel existing task. Returns true if a task was cancelled..
     fn cancel(&mut self) -> bool {
-        let task = self.task.take();
-        if let Some(task) = task {
-            fasync::Task::local(async move {
-                task.cancel().await;
-            })
-            .detach();
+        if let Some(task) = self.task.take() {
+            std::mem::drop(task);
             if let Some(app_sender) = &self.app_sender {
                 app_sender.queue_message(
                     MessageTarget::View(self.view_id),
diff --git a/src/ui/input/bin/hid/main.cc b/src/ui/input/bin/hid/main.cc
index 7a29902..2b7f6ce 100644
--- a/src/ui/input/bin/hid/main.cc
+++ b/src/ui/input/bin/hid/main.cc
@@ -311,11 +311,7 @@
   if (controller.is_error()) {
     return controller.error_value();
   }
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::Device>();
-  if (endpoints.is_error()) {
-    return endpoints.error_value();
-  }
-  auto& [device, server] = endpoints.value();
+  auto [device, server] = fidl::Endpoints<fuchsia_hardware_input::Device>::Create();
   const fidl::Status status = fidl::WireCall(controller.value())->OpenSession(std::move(server));
   if (!status.ok()) {
     return status.status();
@@ -442,12 +438,7 @@
     printf("could not open %s: %s\n", argv[1], controller.status_string());
     return controller.error_value();
   }
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::Device>();
-  if (endpoints.is_error()) {
-    printf("could not create endpoints: %s\n", endpoints.status_string());
-    return endpoints.error_value();
-  }
-  auto& [device, server] = endpoints.value();
+  auto [device, server] = fidl::Endpoints<fuchsia_hardware_input::Device>::Create();
   {
     const fidl::Status status = fidl::WireCall(controller.value())->OpenSession(std::move(server));
     if (!status.ok()) {
diff --git a/src/ui/input/drivers/adc-buttons/adc-buttons-test.cc b/src/ui/input/drivers/adc-buttons/adc-buttons-test.cc
index 4652912..c3cad66 100644
--- a/src/ui/input/drivers/adc-buttons/adc-buttons-test.cc
+++ b/src/ui/input/drivers/adc-buttons/adc-buttons-test.cc
@@ -177,14 +177,13 @@
 }
 
 TEST_F(AdcButtonsDeviceTest, ReadInputReportsTest) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_OK(endpoints);
-  auto result = client_->GetInputReportsReader(std::move(endpoints->server));
+  auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+  auto result = client_->GetInputReportsReader(std::move(endpoints.server));
   ASSERT_TRUE(result.ok());
   // Ensure that the reader has been registered with the client before moving on.
   ASSERT_TRUE(client_->GetDescriptor().ok());
   auto reader =
-      fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints->client));
+      fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
   EXPECT_TRUE(reader.is_valid());
   DrainInitialReport(reader);
 
diff --git a/src/ui/input/drivers/adc-buttons/adc-buttons.cc b/src/ui/input/drivers/adc-buttons/adc-buttons.cc
index d9b2b77..ff79711 100644
--- a/src/ui/input/drivers/adc-buttons/adc-buttons.cc
+++ b/src/ui/input/drivers/adc-buttons/adc-buttons.cc
@@ -170,22 +170,19 @@
                   .devfs_args(devfs.Build())
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
   ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create endpoints: %s",
                 node_endpoints.status_string());
 
   fidl::WireResult result = fidl::WireCall(node())->AddChild(
-      args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+      args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
   node_.Bind(std::move(node_endpoints->client));
   return zx::ok();
 }
diff --git a/src/ui/input/drivers/buttons/buttons-test.cc b/src/ui/input/drivers/buttons/buttons-test.cc
index 4a04107..07ed7beb 100644
--- a/src/ui/input/drivers/buttons/buttons-test.cc
+++ b/src/ui/input/drivers/buttons/buttons-test.cc
@@ -256,13 +256,12 @@
   }
 
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> GetReader() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ZX_ASSERT(endpoints.is_ok());
-    auto result = client_->GetInputReportsReader(std::move(endpoints->server));
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+    auto result = client_->GetInputReportsReader(std::move(endpoints.server));
     ZX_ASSERT(result.ok());
     ZX_ASSERT(client_->GetDescriptor().ok());
-    auto reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-        std::move(endpoints->client));
+    auto reader =
+        fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
     ZX_ASSERT(reader.is_valid());
 
     DrainInitialReport(reader);
diff --git a/src/ui/input/drivers/buttons/buttons.cc b/src/ui/input/drivers/buttons/buttons.cc
index fb7bc59..b7c2c1a 100644
--- a/src/ui/input/drivers/buttons/buttons.cc
+++ b/src/ui/input/drivers/buttons/buttons.cc
@@ -209,22 +209,19 @@
                   .devfs_args(devfs.Build())
                   .Build();
 
-  zx::result controller_endpoints =
-      fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-  ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create node controller endpoints: %s",
-                controller_endpoints.status_string());
+  auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
   zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
   ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create node endpoints: %s",
                 node_endpoints.status_string());
 
   fidl::WireResult result = fidl::WireCall(node())->AddChild(
-      args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+      args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
   if (!result.ok()) {
     FDF_LOG(ERROR, "Failed to add child %s", result.status_string());
     return zx::error(result.status());
   }
-  controller_.Bind(std::move(controller_endpoints->client));
+  controller_.Bind(std::move(controller_endpoints.client));
   node_.Bind(std::move(node_endpoints->client));
   return zx::ok();
 }
diff --git a/src/ui/input/drivers/ctaphid/test.cc b/src/ui/input/drivers/ctaphid/test.cc
index 6fd3ba9..b4a28c4 100644
--- a/src/ui/input/drivers/ctaphid/test.cc
+++ b/src/ui/input/drivers/ctaphid/test.cc
@@ -127,11 +127,10 @@
 
   void SetupSyncClient() {
     ASSERT_OK(loop_.StartThread("test-loop-thread"));
-    auto endpoints = fidl::CreateEndpoints<fuchsia_fido_report::SecurityKeyDevice>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_fido_report::SecurityKeyDevice>::Create();
     binding_ =
-        fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), ctap_driver_device_);
-    sync_client_.Bind(std::move(endpoints->client));
+        fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), ctap_driver_device_);
+    sync_client_.Bind(std::move(endpoints.client));
   }
 
   void SetupAsyncClient() {
diff --git a/src/ui/input/drivers/focaltech/ft_device_test.cc b/src/ui/input/drivers/focaltech/ft_device_test.cc
index 5b3310a..5622257 100644
--- a/src/ui/input/drivers/focaltech/ft_device_test.cc
+++ b/src/ui/input/drivers/focaltech/ft_device_test.cc
@@ -184,9 +184,8 @@
 
     // I2c fragment
     {
-      auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-      ZX_ASSERT(endpoints.is_ok());
-      incoming_.SyncCall([server = std::move(endpoints->server)](IncomingNamespace* infra) mutable {
+      auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+      incoming_.SyncCall([server = std::move(endpoints.server)](IncomingNamespace* infra) mutable {
         zx::result service_result =
             infra->i2c_fragment_outgoing_.AddService<fuchsia_hardware_i2c::Service>(
                 fuchsia_hardware_i2c::Service::InstanceHandler(
@@ -194,15 +193,14 @@
         ZX_ASSERT(service_result.is_ok());
         ZX_ASSERT(infra->i2c_fragment_outgoing_.Serve(std::move(server)).is_ok());
       });
-      fake_parent_->AddFidlService(fuchsia_hardware_i2c::Service::Name,
-                                   std::move(endpoints->client), "i2c");
+      fake_parent_->AddFidlService(fuchsia_hardware_i2c::Service::Name, std::move(endpoints.client),
+                                   "i2c");
     }
 
     // Reset gpio fragment
     {
-      auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-      ZX_ASSERT(endpoints.is_ok());
-      incoming_.SyncCall([server = std::move(endpoints->server)](IncomingNamespace* infra) mutable {
+      auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+      incoming_.SyncCall([server = std::move(endpoints.server)](IncomingNamespace* infra) mutable {
         auto service_result =
             infra->reset_gpio_fragment_outgoing_.AddService<fuchsia_hardware_gpio::Service>(
                 infra->reset_gpio_.CreateInstanceHandler());
@@ -210,14 +208,13 @@
         ZX_ASSERT(infra->reset_gpio_fragment_outgoing_.Serve(std::move(server)).is_ok());
       });
       fake_parent_->AddFidlService(fuchsia_hardware_gpio::Service::Name,
-                                   std::move(endpoints->client), "gpio-reset");
+                                   std::move(endpoints.client), "gpio-reset");
     }
 
     // Interrupt gpio fragment
     {
-      auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-      ZX_ASSERT(endpoints.is_ok());
-      incoming_.SyncCall([server = std::move(endpoints->server)](IncomingNamespace* infra) mutable {
+      auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+      incoming_.SyncCall([server = std::move(endpoints.server)](IncomingNamespace* infra) mutable {
         auto service_result =
             infra->interrupt_gpio_fragment_outgoing_.AddService<fuchsia_hardware_gpio::Service>(
                 infra->interrupt_gpio_.CreateInstanceHandler());
@@ -225,7 +222,7 @@
         ZX_ASSERT(infra->interrupt_gpio_fragment_outgoing_.Serve(std::move(server)).is_ok());
       });
       fake_parent_->AddFidlService(fuchsia_hardware_gpio::Service::Name,
-                                   std::move(endpoints->client), "gpio-int");
+                                   std::move(endpoints.client), "gpio-int");
     }
 
     zx::interrupt interrupt;
@@ -246,10 +243,9 @@
     dut_ = child_->GetDeviceContext<FtDevice>();
     VerifyGpioInit();
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputDevice>();
-    EXPECT_EQ(ZX_OK, endpoints.status_value());
-    fidl::BindServer(dispatcher_->async_dispatcher(), std::move(endpoints->server), dut_);
-    return std::move(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputDevice>::Create();
+    fidl::BindServer(dispatcher_->async_dispatcher(), std::move(endpoints.server), dut_);
+    return std::move(std::move(endpoints.client));
   }
 
   void TearDown() override {
@@ -420,12 +416,11 @@
 
   fidl::WireSyncClient<fuchsia_input_report::InputDevice> client(CreateDut());
 
-  auto reader_endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_EQ(ZX_OK, reader_endpoints.status_value());
-  auto result = client->GetInputReportsReader(std::move(reader_endpoints->server));
+  auto reader_endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+  auto result = client->GetInputReportsReader(std::move(reader_endpoints.server));
   ASSERT_EQ(ZX_OK, result.status());
   auto reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-      std::move(reader_endpoints->client));
+      std::move(reader_endpoints.client));
 
   ASSERT_EQ(ZX_OK, dut_->WaitForNextReader(zx::duration::infinite()));
 
diff --git a/src/ui/input/drivers/goldfish_sensor/BUILD.gn b/src/ui/input/drivers/goldfish_sensor/BUILD.gn
index 617d575..f404b94 100644
--- a/src/ui/input/drivers/goldfish_sensor/BUILD.gn
+++ b/src/ui/input/drivers/goldfish_sensor/BUILD.gn
@@ -27,6 +27,7 @@
   "//src/devices/lib/driver",
   "//src/devices/lib/driver:driver_runtime",
   "//src/devices/lib/goldfish/pipe_io",
+  "//src/graphics/display/lib/driver-framework-migration-utils/logging:logging-dfv1",
   "//src/lib/ddk",
   "//src/lib/ddktl",
   "//zircon/system/ulib/async-loop:async-loop-cpp",
diff --git a/src/ui/input/drivers/goldfish_sensor/tests/input_device_test.cc b/src/ui/input/drivers/goldfish_sensor/tests/input_device_test.cc
index 225f98a..8b3d468 100644
--- a/src/ui/input/drivers/goldfish_sensor/tests/input_device_test.cc
+++ b/src/ui/input/drivers/goldfish_sensor/tests/input_device_test.cc
@@ -39,13 +39,12 @@
 
     ASSERT_EQ(fake_parent_->child_count(), 1u);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputDevice>();
-    ASSERT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputDevice>::Create();
 
-    binding_ = fidl::BindServer(dispatcher_->async_dispatcher(), std::move(endpoints->server),
+    binding_ = fidl::BindServer(dispatcher_->async_dispatcher(), std::move(endpoints.server),
                                 fake_parent_->GetLatestChild()->GetDeviceContext<InputDevice>());
 
-    device_client_.Bind(std::move(endpoints->client));
+    device_client_.Bind(std::move(endpoints.client));
   }
 
   void TearDown() override {
@@ -85,9 +84,8 @@
 using AccelerationInputDeviceTest = InputDeviceTest<TestAccelerationInputDevice>;
 
 TEST_P(AccelerationInputDeviceTest, ReadInputReports) {
-  auto endpoint_result = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_TRUE(endpoint_result.is_ok());
-  auto [client_end, server_end] = std::move(endpoint_result.value());
+  auto [client_end, server_end] =
+      fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
   auto reader_result = device_client_->GetInputReportsReader(std::move(server_end));
   ASSERT_TRUE(reader_result.ok());
@@ -200,9 +198,8 @@
 using GyroscopeInputDeviceTest = InputDeviceTest<TestGyroscopeInputDevice>;
 
 TEST_P(GyroscopeInputDeviceTest, ReadInputReports) {
-  auto endpoint_result = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_TRUE(endpoint_result.is_ok());
-  auto [client_end, server_end] = std::move(endpoint_result.value());
+  auto [client_end, server_end] =
+      fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
   auto reader_result = device_client_->GetInputReportsReader(std::move(server_end));
   ASSERT_TRUE(reader_result.ok());
@@ -321,9 +318,8 @@
 using RgbcLightInputDeviceTest = InputDeviceTest<TestRgbcLightInputDevice>;
 
 TEST_P(RgbcLightInputDeviceTest, ReadInputReports) {
-  auto endpoint_result = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_TRUE(endpoint_result.is_ok());
-  auto [client_end, server_end] = std::move(endpoint_result.value());
+  auto [client_end, server_end] =
+      fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
   auto reader_result = device_client_->GetInputReportsReader(std::move(server_end));
   ASSERT_TRUE(reader_result.ok());
diff --git a/src/ui/input/drivers/goldfish_sensor/tests/root_device_test.cc b/src/ui/input/drivers/goldfish_sensor/tests/root_device_test.cc
index 536bea6..7687c7c 100644
--- a/src/ui/input/drivers/goldfish_sensor/tests/root_device_test.cc
+++ b/src/ui/input/drivers/goldfish_sensor/tests/root_device_test.cc
@@ -120,9 +120,8 @@
   void SetUp() override {
     ASSERT_EQ(incoming_loop_.StartThread("incoming-ns-thread"), ZX_OK);
 
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_EQ(endpoints.status_value(), ZX_OK);
-    incoming_.SyncCall([server = std::move(endpoints->server)](IncomingNamespace* infra) mutable {
+    auto endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
+    incoming_.SyncCall([server = std::move(endpoints.server)](IncomingNamespace* infra) mutable {
       zx::result service_result =
           infra->outgoing_.AddService<fuchsia_hardware_goldfish_pipe::Service>(
               fuchsia_hardware_goldfish_pipe::Service::InstanceHandler({
@@ -133,7 +132,7 @@
     });
 
     fake_parent_->AddFidlService(fuchsia_hardware_goldfish_pipe::Service::Name,
-                                 std::move(endpoints->client));
+                                 std::move(endpoints.client));
 
     auto result = fdf::RunOnDispatcherSync(dispatcher_->async_dispatcher(), [&]() {
       auto device = std::make_unique<TestRootDevice>(fake_parent_.get());
diff --git a/src/ui/input/drivers/goodix/gt92xx-firmware-test.cc b/src/ui/input/drivers/goodix/gt92xx-firmware-test.cc
index 0915216f..607af54 100644
--- a/src/ui/input/drivers/goodix/gt92xx-firmware-test.cc
+++ b/src/ui/input/drivers/goodix/gt92xx-firmware-test.cc
@@ -250,11 +250,10 @@
     enable_load_firmware = true;
     fidl::ClientEnd reset_gpio_client = reset_gpio_.SyncCall(&fake_gpio::FakeGpio::Connect);
     fidl::ClientEnd intr_gpio_client = intr_gpio_.SyncCall(&fake_gpio::FakeGpio::Connect);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
-    fidl::BindServer(fidl_servers_loop_.dispatcher(), std::move(endpoints->server), &i2c_);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    fidl::BindServer(fidl_servers_loop_.dispatcher(), std::move(endpoints.server), &i2c_);
     fake_parent_ = MockDevice::FakeRootParent();
-    device_.emplace(nullptr, std::move(endpoints->client), std::move(intr_gpio_client),
+    device_.emplace(nullptr, std::move(endpoints.client), std::move(intr_gpio_client),
                     std::move(reset_gpio_client), fake_parent_.get());
   }
 
diff --git a/src/ui/input/drivers/goodix/gt92xx-test.cc b/src/ui/input/drivers/goodix/gt92xx-test.cc
index e0409b1..dc251cd 100644
--- a/src/ui/input/drivers/goodix/gt92xx-test.cc
+++ b/src/ui/input/drivers/goodix/gt92xx-test.cc
@@ -58,11 +58,10 @@
     ASSERT_OK(fidl_servers_loop_.StartThread("fidl-servers"));
     fidl::ClientEnd reset_gpio_client = reset_gpio_.SyncCall(&fake_gpio::FakeGpio::Connect);
     fidl::ClientEnd intr_gpio_client = intr_gpio_.SyncCall(&fake_gpio::FakeGpio::Connect);
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    ASSERT_TRUE(endpoints.is_ok());
-    fidl::BindServer(fidl_servers_loop_.dispatcher(), std::move(endpoints->server), &mock_i2c_);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
+    fidl::BindServer(fidl_servers_loop_.dispatcher(), std::move(endpoints.server), &mock_i2c_);
     fake_parent_ = MockDevice::FakeRootParent();
-    device_.emplace(input_report_loop_.dispatcher(), std::move(endpoints->client),
+    device_.emplace(input_report_loop_.dispatcher(), std::move(endpoints.client),
                     std::move(intr_gpio_client), std::move(reset_gpio_client), fake_parent_.get());
     EXPECT_OK(input_report_loop_.RunUntilIdle());
   }
@@ -85,17 +84,15 @@
   }
 
   fidl::WireClient<fuchsia_input_report::InputReportsReader> GetReader() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputDevice>();
-    EXPECT_OK(endpoints);
-    fidl::BindServer(input_report_loop_.dispatcher(), std::move(endpoints->server), &*device_);
-    fidl::WireSyncClient<fuchsia_input_report::InputDevice> client(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputDevice>::Create();
+    fidl::BindServer(input_report_loop_.dispatcher(), std::move(endpoints.server), &*device_);
+    fidl::WireSyncClient<fuchsia_input_report::InputDevice> client(std::move(endpoints.client));
 
-    auto reader_endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    EXPECT_OK(reader_endpoints.status_value());
-    auto result = client->GetInputReportsReader(std::move(reader_endpoints->server));
+    auto reader_endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+    auto result = client->GetInputReportsReader(std::move(reader_endpoints.server));
     EXPECT_TRUE(result.ok());
     auto reader = fidl::WireClient<fuchsia_input_report::InputReportsReader>(
-        std::move(reader_endpoints->client), input_report_loop_.dispatcher());
+        std::move(reader_endpoints.client), input_report_loop_.dispatcher());
     EXPECT_OK(input_report_loop_.RunUntilIdle());
 
     return reader;
@@ -156,10 +153,9 @@
 TEST_F(Gt92xxTest, TestGetDescriptor) {
   ASSERT_OK(input_report_loop_.StartThread("input-report-loop"));
 
-  auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputDevice>();
-  ASSERT_OK(endpoints);
-  fidl::BindServer(input_report_loop_.dispatcher(), std::move(endpoints->server), &*device_);
-  fidl::WireSyncClient<fuchsia_input_report::InputDevice> client(std::move(endpoints->client));
+  auto endpoints = fidl::Endpoints<fuchsia_input_report::InputDevice>::Create();
+  fidl::BindServer(input_report_loop_.dispatcher(), std::move(endpoints.server), &*device_);
+  fidl::WireSyncClient<fuchsia_input_report::InputDevice> client(std::move(endpoints.client));
 
   auto result = client->GetDescriptor();
   EXPECT_TRUE(result.ok());
diff --git a/src/ui/input/drivers/gt6853/gt6853-test.cc b/src/ui/input/drivers/gt6853/gt6853-test.cc
index 8bc7358..b5ffc6c 100644
--- a/src/ui/input/drivers/gt6853/gt6853-test.cc
+++ b/src/ui/input/drivers/gt6853/gt6853-test.cc
@@ -525,9 +525,8 @@
 
   fidl::WireSyncClient client(GetInputDeviceClient());
 
-  auto reader_endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_TRUE(reader_endpoints.is_ok());
-  auto [reader_client, reader_server] = std::move(reader_endpoints.value());
+  auto [reader_client, reader_server] =
+      fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
   // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
   (void)client->GetInputReportsReader(std::move(reader_server));
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader(std::move(reader_client));
@@ -758,9 +757,8 @@
 
   fidl::WireSyncClient client(GetInputDeviceClient());
 
-  auto reader_endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_TRUE(reader_endpoints.is_ok());
-  auto [reader_client, reader_server] = std::move(reader_endpoints.value());
+  auto [reader_client, reader_server] =
+      fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
   // TODO(https://fxbug.dev/42180237) Consider handling the error instead of ignoring it.
   (void)client->GetInputReportsReader(std::move(reader_server));
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader(std::move(reader_client));
diff --git a/src/ui/input/drivers/hid-input-report/driver_v2.cc b/src/ui/input/drivers/hid-input-report/driver_v2.cc
index 915691a..1fd9031 100644
--- a/src/ui/input/drivers/hid-input-report/driver_v2.cc
+++ b/src/ui/input/drivers/hid-input-report/driver_v2.cc
@@ -86,22 +86,19 @@
                     .Build();
 
     // Create endpoints of the `NodeController` for the node.
-    zx::result controller_endpoints =
-        fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
-    ZX_ASSERT_MSG(controller_endpoints.is_ok(), "Failed to create endpoints: %s",
-                  controller_endpoints.status_string());
+    auto controller_endpoints = fidl::Endpoints<fuchsia_driver_framework::NodeController>::Create();
 
     zx::result node_endpoints = fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
     ZX_ASSERT_MSG(node_endpoints.is_ok(), "Failed to create endpoints: %s",
                   node_endpoints.status_string());
 
     fidl::WireResult result = fidl::WireCall(node())->AddChild(
-        args, std::move(controller_endpoints->server), std::move(node_endpoints->server));
+        args, std::move(controller_endpoints.server), std::move(node_endpoints->server));
     if (!result.ok()) {
       FDF_SLOG(ERROR, "Failed to add child", KV("status", result.status_string()));
       return zx::error(result.status());
     }
-    controller_.Bind(std::move(controller_endpoints->client));
+    controller_.Bind(std::move(controller_endpoints.client));
     node_.Bind(std::move(node_endpoints->client));
     return zx::ok();
   }
diff --git a/src/ui/input/drivers/hid-input-report/test.cc b/src/ui/input/drivers/hid-input-report/test.cc
index 6f19e17..8320f8a 100644
--- a/src/ui/input/drivers/hid-input-report/test.cc
+++ b/src/ui/input/drivers/hid-input-report/test.cc
@@ -140,10 +140,9 @@
 
  protected:
   fidl::WireSyncClient<fuchsia_input_report::InputDevice> GetSyncClient() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputDevice>();
-    ZX_ASSERT(endpoints.is_ok());
-    fidl::BindServer(fidl_loop_.dispatcher(), std::move(endpoints->server), device_);
-    return fidl::WireSyncClient(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputDevice>::Create();
+    fidl::BindServer(fidl_loop_.dispatcher(), std::move(endpoints.server), device_);
+    return fidl::WireSyncClient(std::move(endpoints.client));
   }
 
   async::Loop fidl_loop_ = async::Loop(&kAsyncLoopConfigNoAttachToCurrentThread);
@@ -253,13 +252,12 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-    auto result = sync_client->GetInputReportsReader(std::move(endpoints->server));
+    auto result = sync_client->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-        std::move(endpoints->client));
+    reader =
+        fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
     ASSERT_OK(device_->input_report().WaitForNextReader(zx::duration::infinite()));
   }
 
@@ -306,12 +304,11 @@
   async::Loop loop = async::Loop(&kAsyncLoopConfigNoAttachToCurrentThread);
   fidl::WireClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-    auto result = sync_client->GetInputReportsReader(std::move(endpoints->server));
+    auto result = sync_client->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader.Bind(std::move(endpoints->client), loop.dispatcher());
+    reader.Bind(std::move(endpoints.client), loop.dispatcher());
     ASSERT_OK(device_->input_report().WaitForNextReader(zx::duration::infinite()));
   }
 
@@ -358,12 +355,11 @@
   async::Loop loop = async::Loop(&kAsyncLoopConfigNoAttachToCurrentThread);
   fidl::WireClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-    auto result = sync_client->GetInputReportsReader(std::move(endpoints->server));
+    auto result = sync_client->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader.Bind(std::move(endpoints->client), loop.dispatcher());
+    reader.Bind(std::move(endpoints.client), loop.dispatcher());
     ASSERT_OK(device_->input_report().WaitForNextReader(zx::duration::infinite()));
   }
 
@@ -415,13 +411,12 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-    auto result = sync_client->GetInputReportsReader(std::move(endpoints->server));
+    auto result = sync_client->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-        std::move(endpoints->client));
+    reader =
+        fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
     ASSERT_OK(device_->input_report().WaitForNextReader(zx::duration::infinite()));
   }
 
@@ -477,13 +472,12 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-    auto result = sync_client->GetInputReportsReader(std::move(endpoints->server));
+    auto result = sync_client->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-        std::move(endpoints->client));
+    reader =
+        fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
     ASSERT_OK(device_->input_report().WaitForNextReader(zx::duration::infinite()));
   }
 
@@ -555,13 +549,12 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-    auto result = sync_client->GetInputReportsReader(std::move(endpoints->server));
+    auto result = sync_client->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-        std::move(endpoints->client));
+    reader =
+        fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
     ASSERT_OK(device_->input_report().WaitForNextReader(zx::duration::infinite()));
   }
 
@@ -672,13 +665,12 @@
   // Get an InputReportsReader.
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-    auto result = sync_client->GetInputReportsReader(std::move(endpoints->server));
+    auto result = sync_client->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-        std::move(endpoints->client));
+    reader =
+        fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
     ASSERT_OK(device_->input_report().WaitForNextReader(zx::duration::infinite()));
   }
 
@@ -755,13 +747,12 @@
     // Get an InputReportsReader.
     fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
     {
-      auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-      ASSERT_OK(endpoints.status_value());
+      auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-      auto result = client->GetInputReportsReader(std::move(endpoints->server));
+      auto result = client->GetInputReportsReader(std::move(endpoints.server));
       ASSERT_OK(result.status());
       reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-          std::move(endpoints->client));
+          std::move(endpoints.client));
     }
 
     auto report_result = reader->ReadInputReports();
@@ -780,13 +771,12 @@
     // Get an InputReportsReader.
     fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
     {
-      auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-      ASSERT_OK(endpoints.status_value());
+      auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
-      auto result = client->GetInputReportsReader(std::move(endpoints->server));
+      auto result = client->GetInputReportsReader(std::move(endpoints.server));
       ASSERT_OK(result.status());
       reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-          std::move(endpoints->client));
+          std::move(endpoints.client));
       ASSERT_OK(device_->input_report().WaitForNextReader(zx::duration::infinite()));
     }
 
diff --git a/src/ui/input/drivers/hid/hid-test.cc b/src/ui/input/drivers/hid/hid-test.cc
index 6e50525..8848790 100644
--- a/src/ui/input/drivers/hid/hid-test.cc
+++ b/src/ui/input/drivers/hid/hid-test.cc
@@ -161,13 +161,12 @@
   }
 
   void SetupInstanceDriver() {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::Device>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_input::Device>::Create();
 
     ASSERT_OK(device_->CreateInstance(fdf::Dispatcher::GetCurrent()->async_dispatcher(),
-                                      std::move(endpoints->server)));
+                                      std::move(endpoints.server)));
 
-    sync_client_ = fidl::WireSyncClient(std::move(endpoints->client));
+    sync_client_ = fidl::WireSyncClient(std::move(endpoints.client));
 
     RunSyncClientTask([&]() {
       auto result = sync_client_->GetReportsEvent();
@@ -726,14 +725,13 @@
 
   fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader> reader;
   {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::DeviceReportsReader>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_input::DeviceReportsReader>::Create();
 
     RunSyncClientTask([&]() {
-      auto result = sync_client_->GetDeviceReportsReader(std::move(endpoints->server));
+      auto result = sync_client_->GetDeviceReportsReader(std::move(endpoints.server));
       ASSERT_OK(result.status());
       reader = fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader>(
-          std::move(endpoints->client));
+          std::move(endpoints.client));
     });
   }
 
@@ -764,14 +762,13 @@
 
   fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader> reader;
   {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::DeviceReportsReader>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_input::DeviceReportsReader>::Create();
 
     RunSyncClientTask([&]() {
-      auto result = sync_client_->GetDeviceReportsReader(std::move(endpoints->server));
+      auto result = sync_client_->GetDeviceReportsReader(std::move(endpoints.server));
       ASSERT_OK(result.status());
       reader = fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader>(
-          std::move(endpoints->client));
+          std::move(endpoints.client));
     });
   }
 
@@ -807,24 +804,22 @@
   fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader> reader1;
   fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader> reader2;
   {
-    zx::result endpoints1 = fidl::CreateEndpoints<fuchsia_hardware_input::DeviceReportsReader>();
-    ASSERT_OK(endpoints1);
+    auto endpoints1 = fidl::Endpoints<fuchsia_hardware_input::DeviceReportsReader>::Create();
 
     RunSyncClientTask([&]() {
-      auto result1 = sync_client_->GetDeviceReportsReader(std::move(endpoints1->server));
+      auto result1 = sync_client_->GetDeviceReportsReader(std::move(endpoints1.server));
       ASSERT_OK(result1.status());
       reader1 = fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader>(
-          std::move(endpoints1->client));
+          std::move(endpoints1.client));
     });
 
-    zx::result endpoints2 = fidl::CreateEndpoints<fuchsia_hardware_input::DeviceReportsReader>();
-    ASSERT_OK(endpoints2);
+    auto endpoints2 = fidl::Endpoints<fuchsia_hardware_input::DeviceReportsReader>::Create();
 
     RunSyncClientTask([&]() {
-      auto result2 = sync_client_->GetDeviceReportsReader(std::move(endpoints2->server));
+      auto result2 = sync_client_->GetDeviceReportsReader(std::move(endpoints2.server));
       ASSERT_OK(result2.status());
       reader2 = fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader>(
-          std::move(endpoints2->client));
+          std::move(endpoints2.client));
     });
   }
 
@@ -865,14 +860,13 @@
 
   fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader> reader;
   {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::DeviceReportsReader>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_input::DeviceReportsReader>::Create();
 
     RunSyncClientTask([&]() {
-      auto result = sync_client_->GetDeviceReportsReader(std::move(endpoints->server));
+      auto result = sync_client_->GetDeviceReportsReader(std::move(endpoints.server));
       ASSERT_OK(result.status());
       reader = fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader>(
-          std::move(endpoints->client));
+          std::move(endpoints.client));
     });
   }
 
@@ -907,14 +901,13 @@
 
   fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader> reader;
   {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::DeviceReportsReader>();
-    ASSERT_OK(endpoints);
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_input::DeviceReportsReader>::Create();
 
     RunSyncClientTask([&]() {
-      auto result = sync_client_->GetDeviceReportsReader(std::move(endpoints->server));
+      auto result = sync_client_->GetDeviceReportsReader(std::move(endpoints.server));
       ASSERT_OK(result.status());
       reader = fidl::WireSyncClient<fuchsia_hardware_input::DeviceReportsReader>(
-          std::move(endpoints->client));
+          std::move(endpoints.client));
     });
   }
 
diff --git a/src/ui/input/drivers/i2c-hid/i2c-hid-test.cc b/src/ui/input/drivers/i2c-hid/i2c-hid-test.cc
index b3e06ea..8506313 100644
--- a/src/ui/input/drivers/i2c-hid/i2c-hid-test.cc
+++ b/src/ui/input/drivers/i2c-hid/i2c-hid-test.cc
@@ -287,24 +287,22 @@
     ASSERT_OK(irq.duplicate(ZX_RIGHT_SAME_RIGHTS, &interrupt));
     fake_i2c_hid_.SetInterrupt(std::move(interrupt));
 
-    auto io_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(io_endpoints.status_value());
+    auto io_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
 
-    mock_component_.emplace(std::move(irq), std::move(io_endpoints->server));
+    mock_component_.emplace(std::move(irq), std::move(io_endpoints.server));
 
     parent_->AddFidlService(fuchsia_hardware_interrupt::Service::Name,
-                            std::move(io_endpoints->client), "irq001");
+                            std::move(io_endpoints.client), "irq001");
 
     auto client = acpi_device_.CreateClient(loop_.dispatcher());
     ASSERT_OK(client.status_value());
     device_ = new I2cHidbus(parent_.get(), std::move(client.value()));
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-    EXPECT_TRUE(endpoints.is_ok());
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
 
-    fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &fake_i2c_hid_);
+    fidl::BindServer(loop_.dispatcher(), std::move(endpoints.server), &fake_i2c_hid_);
 
-    i2c_ = std::move(endpoints->client);
+    i2c_ = std::move(endpoints.client);
     // Each test is responsible for calling Bind().
   }
 
@@ -379,17 +377,15 @@
   async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
   EXPECT_OK(loop.StartThread());
 
-  auto i2c_endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-  EXPECT_TRUE(i2c_endpoints.is_ok());
+  auto i2c_endpoints = fidl::Endpoints<fuchsia_hardware_i2c::Device>::Create();
 
-  fidl::BindServer(loop.dispatcher(), std::move(i2c_endpoints->server), &fake_i2c_hid_);
+  fidl::BindServer(loop.dispatcher(), std::move(i2c_endpoints.server), &fake_i2c_hid_);
 
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_acpi::Device>();
-  ASSERT_OK(endpoints.status_value());
-  endpoints->server.reset();
+  auto endpoints = fidl::Endpoints<fuchsia_hardware_acpi::Device>::Create();
+  endpoints.server.reset();
   device_ = new I2cHidbus(parent.get(),
-                          acpi::Client::Create(fidl::WireSyncClient(std::move(endpoints->client))));
-  channel_ = ddk::I2cChannel(std::move(i2c_endpoints->client));
+                          acpi::Client::Create(fidl::WireSyncClient(std::move(endpoints.client))));
+  channel_ = ddk::I2cChannel(std::move(i2c_endpoints.client));
 
   fake_i2c_hid_.SetHidDescriptorFailure(ZX_ERR_TIMED_OUT);
   ASSERT_OK(device_->Bind(std::move(channel_)));
diff --git a/src/ui/input/drivers/pc-ps2/unit-tests.cc b/src/ui/input/drivers/pc-ps2/unit-tests.cc
index 0fbe050..9c4c019 100644
--- a/src/ui/input/drivers/pc-ps2/unit-tests.cc
+++ b/src/ui/input/drivers/pc-ps2/unit-tests.cc
@@ -205,13 +205,12 @@
     sync_completion_wait(&controller_dev_->GetDeviceContext<i8042::Controller>()->added_children(),
                          ZX_TIME_INFINITE);
 
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputDevice>();
-    ASSERT_OK(endpoints.status_value());
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputDevice>::Create();
 
     binding_ =
-        fidl::BindServer(dispatcher_->async_dispatcher(), std::move(endpoints->server),
+        fidl::BindServer(dispatcher_->async_dispatcher(), std::move(endpoints.server),
                          controller_dev_->GetLatestChild()->GetDeviceContext<i8042::I8042Device>());
-    client_.Bind(std::move(endpoints->client));
+    client_.Bind(std::move(endpoints.client));
   }
 
  protected:
@@ -263,12 +262,11 @@
 
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
-    auto result = client_->GetInputReportsReader(std::move(endpoints->server));
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+    auto result = client_->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-        std::move(endpoints->client));
+    reader =
+        fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
     ASSERT_OK(keyboard->WaitForNextReader(zx::duration::infinite()));
   }
   {
@@ -354,12 +352,11 @@
 
   fidl::WireSyncClient<fuchsia_input_report::InputReportsReader> reader;
   {
-    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    ASSERT_OK(endpoints.status_value());
-    auto result = client_->GetInputReportsReader(std::move(endpoints->server));
+    auto endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
+    auto result = client_->GetInputReportsReader(std::move(endpoints.server));
     ASSERT_OK(result.status());
-    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-        std::move(endpoints->client));
+    reader =
+        fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(std::move(endpoints.client));
     ASSERT_OK(mouse->WaitForNextReader(zx::duration::infinite()));
   }
 
diff --git a/src/ui/input/drivers/usb-hid/usb-hid-test.cc b/src/ui/input/drivers/usb-hid/usb-hid-test.cc
index 444cdde..19378d1 100644
--- a/src/ui/input/drivers/usb-hid/usb-hid-test.cc
+++ b/src/ui/input/drivers/usb-hid/usb-hid-test.cc
@@ -50,9 +50,7 @@
     zx::result controller =
         component::ConnectAt<fuchsia_hardware_input::Controller>(caller.directory(), devpath_);
     ASSERT_OK(controller);
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::Device>();
-    ASSERT_OK(endpoints);
-    auto& [device, server] = endpoints.value();
+    auto [device, server] = fidl::Endpoints<fuchsia_hardware_input::Device>::Create();
     ASSERT_OK(fidl::WireCall(controller.value())->OpenSession(std::move(server)));
 
     sync_client_ = fidl::WireSyncClient<fuchsia_hardware_input::Device>(std::move(device));
@@ -120,9 +118,7 @@
     const size_t last_slash = usb_hid_relpath.find_last_of('/');
     const std::string_view suffix = usb_hid_relpath.substr(last_slash + 1);
     std::string ifc_path{usb_hid_relpath.substr(0, last_slash)};
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
-    ASSERT_OK(endpoints);
-    auto& [client_end, server_end] = endpoints.value();
+    auto [client_end, server_end] = fidl::Endpoints<fuchsia_io::Directory>::Create();
     ASSERT_OK(fdio_open_at(caller.directory().channel()->get(), ifc_path.c_str(),
                            static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
                            server_end.TakeChannel().release()));
diff --git a/src/ui/input/drivers/virtio/input_test.cc b/src/ui/input/drivers/virtio/input_test.cc
index 3474e1e..45d1376 100644
--- a/src/ui/input/drivers/virtio/input_test.cc
+++ b/src/ui/input/drivers/virtio/input_test.cc
@@ -51,15 +51,14 @@
 
   template <typename HidDeviceType>
   fidl::WireClient<fuchsia_input_report::InputReportsReader> GetReader(HidDeviceType& device) {
-    auto reader_endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-    EXPECT_OK(reader_endpoints.status_value());
+    auto reader_endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
 
     device.SyncCall([&](HidDeviceBase* device) {
       device->GetInputReportsReader(async_get_default_dispatcher(),
-                                    std::move(reader_endpoints->server));
+                                    std::move(reader_endpoints.server));
     });
     auto reader = fidl::WireClient<fuchsia_input_report::InputReportsReader>(
-        std::move(reader_endpoints->client), input_report_loop_.dispatcher());
+        std::move(reader_endpoints.client), input_report_loop_.dispatcher());
     EXPECT_OK(input_report_loop_.RunUntilIdle());
 
     return reader;
diff --git a/src/ui/input/fhcp/touchpad-test.cc b/src/ui/input/fhcp/touchpad-test.cc
index a8216c9..865f2d2 100644
--- a/src/ui/input/fhcp/touchpad-test.cc
+++ b/src/ui/input/fhcp/touchpad-test.cc
@@ -49,12 +49,11 @@
   ConfigureTouchEvents(input_device_client);
 
   // Get the InputReportsReader client from the InputDevice protocol.
-  auto endpoints = fidl::CreateEndpoints<fir::InputReportsReader>();
-  ASSERT_TRUE(endpoints.is_ok());
+  auto endpoints = fidl::Endpoints<fir::InputReportsReader>::Create();
   ASSERT_EQ(ZX_OK,
-            input_device_client->GetInputReportsReader(std::move(endpoints->server)).status());
+            input_device_client->GetInputReportsReader(std::move(endpoints.server)).status());
 
-  auto reader_client = fidl::WireSyncClient<fir::InputReportsReader>(std::move(endpoints->client));
+  auto reader_client = fidl::WireSyncClient<fir::InputReportsReader>(std::move(endpoints.client));
 
   // The test itself - check for touches in each corner.
   //
diff --git a/src/ui/input/tests/hid/hid-driver.cc b/src/ui/input/tests/hid/hid-driver.cc
index efc7fea..c7d5034 100644
--- a/src/ui/input/tests/hid/hid-driver.cc
+++ b/src/ui/input/tests/hid/hid-driver.cc
@@ -137,9 +137,7 @@
   ASSERT_OK(input_client.status_value());
 
   // Open a FIDL channel to the HID device
-  zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_input::Device>();
-  ASSERT_OK(endpoints);
-  auto& [device, server] = endpoints.value();
+  auto [device, server] = fidl::Endpoints<fuchsia_hardware_input::Device>::Create();
 
   ASSERT_OK(fidl::WireCall(input_client.value())->OpenSession(std::move(server)));
 
@@ -211,11 +209,10 @@
   ASSERT_OK(input_client.status_value());
   fidl::WireSyncClient client(std::move(input_client.value()));
 
-  auto reader_endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputReportsReader>();
-  ASSERT_OK(reader_endpoints.status_value());
+  auto reader_endpoints = fidl::Endpoints<fuchsia_input_report::InputReportsReader>::Create();
   auto reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
-      std::move(reader_endpoints->client));
-  ASSERT_OK(client->GetInputReportsReader(std::move(reader_endpoints->server)).status());
+      std::move(reader_endpoints.client));
+  ASSERT_OK(client->GetInputReportsReader(std::move(reader_endpoints.server)).status());
 
   // Check the Descriptor.
   {
diff --git a/src/ui/lib/input_pipeline/BUILD.gn b/src/ui/lib/input_pipeline/BUILD.gn
index a55edaa..e4fe8bf 100644
--- a/src/ui/lib/input_pipeline/BUILD.gn
+++ b/src/ui/lib/input_pipeline/BUILD.gn
@@ -87,7 +87,6 @@
     "//third_party/rust_crates:assert_matches",
     "//third_party/rust_crates:nom",
     "//third_party/rust_crates:nom_locate",
-    "//third_party/rust_crates:pin-utils",
     "//third_party/rust_crates:pretty_assertions",
     "//third_party/rust_crates:rand",
     "//third_party/rust_crates:regex",
diff --git a/src/ui/lib/input_pipeline/src/autorepeater.rs b/src/ui/lib/input_pipeline/src/autorepeater.rs
index 48e1f76..9d536c5 100644
--- a/src/ui/lib/input_pipeline/src/autorepeater.rs
+++ b/src/ui/lib/input_pipeline/src/autorepeater.rs
@@ -477,9 +477,8 @@
     use fuchsia_async::TestExecutor;
     use fuchsia_zircon as zx;
     use futures::Future;
-    use pin_utils::pin_mut;
     use pretty_assertions::assert_eq;
-    use std::task::Poll;
+    use std::{pin::pin, task::Poll};
 
     // Default autorepeat settings used for test.  If these settings are changed,
     // any tests may fail, since the tests are tuned to the precise timing that
@@ -723,10 +722,9 @@
         // Drive both the test fixture task and the handler task in parallel,
         // and both in fake time.  `run_in_fake_time` advances the fake time from
         // zero in increments of about 10ms until all futures complete.
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -783,10 +781,9 @@
             )
             .await;
         };
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -847,10 +844,9 @@
             .await;
         };
 
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -929,10 +925,9 @@
             )
             .await;
         };
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -1013,10 +1008,9 @@
             )
             .await;
         };
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -1146,10 +1140,9 @@
             )
             .await;
         };
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -1277,10 +1270,9 @@
             )
             .await;
         };
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -1343,10 +1335,9 @@
             )
             .await;
         };
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -1455,10 +1446,9 @@
             )
             .await;
         };
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -1584,10 +1574,9 @@
             )
             .await;
         };
-        let joined_fut = async move {
+        let mut joined_fut = pin!(async move {
             let _r = futures::join!(main_fut, handler_task);
-        };
-        pin_mut!(joined_fut);
+        });
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 
@@ -1705,10 +1694,9 @@
                 }
             });
         };
-        let joined_fut = Task::local(async move {
+        let mut joined_fut = Task::local(async move {
             let _r = futures::join!(handler_task, main_fut);
         });
-        pin_mut!(joined_fut);
         run_in_fake_time(&mut executor, &mut joined_fut, zx::Duration::from_seconds(10));
     }
 }
diff --git a/src/ui/lib/input_pipeline/src/factory_reset_handler.rs b/src/ui/lib/input_pipeline/src/factory_reset_handler.rs
index 67177c6..ef906ee 100644
--- a/src/ui/lib/input_pipeline/src/factory_reset_handler.rs
+++ b/src/ui/lib/input_pipeline/src/factory_reset_handler.rs
@@ -470,9 +470,8 @@
         fidl_fuchsia_recovery_policy::{DeviceMarker, DeviceProxy},
         fidl_fuchsia_recovery_ui::{FactoryResetCountdownMarker, FactoryResetCountdownProxy},
         fuchsia_async::TestExecutor,
-        pin_utils::pin_mut,
         pretty_assertions::assert_eq,
-        std::task::Poll,
+        std::{pin::pin, task::Poll},
     };
 
     fn create_factory_reset_countdown_proxy(
@@ -622,9 +621,8 @@
 
         // Send a reset event
         let reset_event = create_reset_input_event();
-        let handle_input_event_fut =
-            reset_handler.clone().handle_unhandled_input_event(reset_event);
-        pin_mut!(handle_input_event_fut);
+        let mut handle_input_event_fut =
+            pin!(reset_handler.clone().handle_unhandled_input_event(reset_event));
         assert_matches!(executor.run_until_stalled(&mut handle_input_event_fut), Poll::Ready(events) => {
             assert_matches!(events.as_slice(), [input_device::InputEvent { .. }]);
         });
diff --git a/src/ui/light/drivers/aml-light/aml-light-test.cc b/src/ui/light/drivers/aml-light/aml-light-test.cc
index f4cd1fa..07f45726 100644
--- a/src/ui/light/drivers/aml-light/aml-light-test.cc
+++ b/src/ui/light/drivers/aml-light/aml-light-test.cc
@@ -63,10 +63,9 @@
   }
 
   fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> BindServer() {
-    zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pwm::Pwm>();
-    EXPECT_TRUE(endpoints.is_ok());
-    fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints->server), this);
-    return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints->client));
+    auto endpoints = fidl::Endpoints<fuchsia_hardware_pwm::Pwm>::Create();
+    fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints.server), this);
+    return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints.client));
   }
 
   void VerifyAndClear() {
diff --git a/src/virtualization/bin/vmm/controller/virtio_balloon.cc b/src/virtualization/bin/vmm/controller/virtio_balloon.cc
index 003b3be..675d55d 100644
--- a/src/virtualization/bin/vmm/controller/virtio_balloon.cc
+++ b/src/virtualization/bin/vmm/controller/virtio_balloon.cc
@@ -27,8 +27,8 @@
 
 zx_status_t VirtioBalloon::Start(const zx::guest& guest, ::sys::ComponentContext* context,
                                  async_dispatcher_t* dispatcher) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_virtualization_hardware::VirtioBalloon>();
-  auto [client_end, server_end] = std::move(endpoints.value());
+  auto [client_end, server_end] =
+      fidl::Endpoints<fuchsia_virtualization_hardware::VirtioBalloon>::Create();
   fidl::InterfaceRequest<fuchsia::virtualization::hardware::VirtioBalloon> balloon_request(
       server_end.TakeChannel());
   balloon_.Bind(std::move(client_end), dispatcher, this);
diff --git a/src/virtualization/bin/vmm/controller/virtio_gpu.cc b/src/virtualization/bin/vmm/controller/virtio_gpu.cc
index cf69938..0e896e4 100644
--- a/src/virtualization/bin/vmm/controller/virtio_gpu.cc
+++ b/src/virtualization/bin/vmm/controller/virtio_gpu.cc
@@ -24,8 +24,8 @@
     fidl::InterfaceHandle<fuchsia::ui::input3::KeyboardListener> keyboard_listener,
     fidl::InterfaceRequest<fuchsia::ui::pointer::MouseSource> mouse_source,
     ::sys::ComponentContext* context, async_dispatcher_t* dispatcher) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_virtualization_hardware::VirtioGpu>();
-  auto [client_end, server_end] = std::move(endpoints.value());
+  auto [client_end, server_end] =
+      fidl::Endpoints<fuchsia_virtualization_hardware::VirtioGpu>::Create();
   fidl::InterfaceRequest<fuchsia::virtualization::hardware::VirtioGpu> gpu_request(
       server_end.TakeChannel());
   gpu_.Bind(std::move(client_end), dispatcher, this);
diff --git a/src/virtualization/bin/vmm/controller/virtio_mem.cc b/src/virtualization/bin/vmm/controller/virtio_mem.cc
index 06d4a5d..6980203 100644
--- a/src/virtualization/bin/vmm/controller/virtio_mem.cc
+++ b/src/virtualization/bin/vmm/controller/virtio_mem.cc
@@ -31,8 +31,8 @@
 zx_status_t VirtioMem::Start(const zx::guest& guest, ::sys::ComponentContext* context,
                              async_dispatcher_t* dispatcher, uint64_t plugged_block_size,
                              uint64_t region_size) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_virtualization_hardware::VirtioMem>();
-  auto [client_end, server_end] = std::move(endpoints.value());
+  auto [client_end, server_end] =
+      fidl::Endpoints<fuchsia_virtualization_hardware::VirtioMem>::Create();
   fidl::InterfaceRequest<fuchsia::virtualization::hardware::VirtioMem> mem_request(
       server_end.TakeChannel());
   mem_.Bind(std::move(client_end), dispatcher, this);
diff --git a/src/zircon/bin/hwstress/BUILD.gn b/src/zircon/bin/hwstress/BUILD.gn
index 71a9b76..e0f35da 100644
--- a/src/zircon/bin/hwstress/BUILD.gn
+++ b/src/zircon/bin/hwstress/BUILD.gn
@@ -162,9 +162,5 @@
 
 group("hwstress") {
   testonly = true
-  public_deps = [
-    ":hwstress_cli",
-    ":hwstress_v2_pkg",
-    ":hwstress_v2_shard",
-  ]
+  public_deps = [ ":hwstress_v2_pkg" ]
 }
diff --git a/src/zircon/bin/vsock_service/BUILD.gn b/src/zircon/bin/vsock_service/BUILD.gn
index 5c982ef..16a53d8 100644
--- a/src/zircon/bin/vsock_service/BUILD.gn
+++ b/src/zircon/bin/vsock_service/BUILD.gn
@@ -13,12 +13,11 @@
   deps = [
     ":lib",
     "//sdk/fidl/fuchsia.hardware.vsock:fuchsia.hardware.vsock_rust",
-    "//src/lib/fdio/rust:fdio",
-    "//src/lib/fidl/rust/fidl",
+    "//sdk/lib/device-watcher/rust",
+    "//src/lib/fuchsia",
     "//src/lib/fuchsia-async",
     "//src/lib/fuchsia-component",
     "//src/lib/fuchsia-fs",
-    "//src/lib/zircon/rust:fuchsia-zircon",
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:futures",
     "//third_party/rust_crates:tracing",
diff --git a/src/zircon/bin/vsock_service/src/main.rs b/src/zircon/bin/vsock_service/src/main.rs
index c18ebe8..abe94b48 100644
--- a/src/zircon/bin/vsock_service/src/main.rs
+++ b/src/zircon/bin/vsock_service/src/main.rs
@@ -8,43 +8,35 @@
     anyhow::{Context as _, Error},
     fidl_fuchsia_hardware_vsock::DeviceMarker,
     fuchsia_async as fasync,
+    fuchsia_component::client::connect_to_named_protocol_at_dir_root,
     fuchsia_component::server::ServiceFs,
-    fuchsia_fs::{directory::Watcher, OpenFlags},
-    fuchsia_zircon as zx,
+    fuchsia_fs::OpenFlags,
+    futures::TryStreamExt,
     futures::{StreamExt, TryFutureExt},
 };
 
 use vsock_service_lib as service;
 
-#[fasync::run_singlethreaded]
+#[fuchsia::main]
 async fn main() -> Result<(), Error> {
     tracing::info!("Starting vsock service");
 
-    let vsock_device_path = std::path::Path::new("/dev/class/vsock");
-    let (client, device) = zx::Channel::create();
-    let vsock_dir = fuchsia_fs::directory::open_in_namespace(
-        vsock_device_path.to_str().unwrap(),
-        OpenFlags::RIGHT_READABLE,
-    )
-    .context("Open vsock dir")?;
-    let mut watcher = Watcher::new(&vsock_dir).await.context("Create watcher")?;
+    const DEV_CLASS_VSOCK: &str = "/dev/class/vsock";
+    let vsock_dir =
+        fuchsia_fs::directory::open_in_namespace(DEV_CLASS_VSOCK, OpenFlags::RIGHT_READABLE)
+            .context("Open vsock dir")?;
+    let path = device_watcher::watch_for_files(&vsock_dir)
+        .await
+        .with_context(|| format!("Watching for files in {}", DEV_CLASS_VSOCK))?
+        .try_next()
+        .await
+        .with_context(|| format!("Getting a file from {}", DEV_CLASS_VSOCK))?;
+    let path = path.ok_or(anyhow::anyhow!("Could not find device in {}", DEV_CLASS_VSOCK))?;
+    let path = path.to_str().ok_or(anyhow::anyhow!("Expected valid utf-8 device name"))?;
+    let path = format!("{path}/device_protocol");
 
-    let event = loop {
-        let event = watcher.next().await.unwrap().context("Get watch event")?;
-        if event.filename.as_path().to_str().unwrap() == "."
-            || event.filename.as_path().to_str().unwrap() == ".."
-        {
-            continue;
-        }
-        break event;
-    };
-
-    let device_path = vsock_device_path.join(&event.filename);
-    fdio::service_connect(device_path.as_path().to_str().unwrap(), device)
-        .context("open service")?;
-    let dev = fidl::endpoints::ClientEnd::<DeviceMarker>::new(client)
-        .into_proxy()
-        .context("Failed to make channel")?;
+    let dev = connect_to_named_protocol_at_dir_root::<DeviceMarker>(&vsock_dir, &path)
+        .context("Failed to connect vsock device")?;
 
     let (service, event_loop) =
         service::Vsock::new(dev).await.context("Failed to initialize vsock service")?;
diff --git a/src/zircon/testing/standalone-test/include/lib/standalone-test/standalone.h b/src/zircon/testing/standalone-test/include/lib/standalone-test/standalone.h
index 29c7c30..da1c868 100644
--- a/src/zircon/testing/standalone-test/include/lib/standalone-test/standalone.h
+++ b/src/zircon/testing/standalone-test/include/lib/standalone-test/standalone.h
@@ -7,7 +7,9 @@
 
 #include <lib/zx/channel.h>
 #include <lib/zx/resource.h>
+#include <lib/zx/result.h>
 #include <lib/zx/vmo.h>
+#include <zircon/syscalls/resource.h>
 
 #include <string>
 #include <string_view>
@@ -30,6 +32,9 @@
 zx::unowned_resource GetMmioResource();
 zx::unowned_resource GetSystemResource();
 
+// Creates and returns upon success a specific system resource given a |base|.
+zx::result<zx::resource> GetSystemResourceWithBase(zx::unowned_resource& system_resource,
+                                                   uint64_t base);
 zx::unowned_vmo GetVmo(std::string_view name);
 zx::unowned_channel GetNsDir(std::string_view name);
 
diff --git a/src/zircon/testing/standalone-test/standalone-init.cc b/src/zircon/testing/standalone-test/standalone-init.cc
index 52fceeb..328b5ad 100644
--- a/src/zircon/testing/standalone-test/standalone-init.cc
+++ b/src/zircon/testing/standalone-test/standalone-init.cc
@@ -76,6 +76,17 @@
   return system_resource.borrow();
 }
 
+zx::result<zx::resource> GetSystemResourceWithBase(zx::unowned_resource& system_resource,
+                                                   uint64_t base) {
+  zx::resource new_resource;
+  const zx_status_t status = zx::resource::create(*system_resource, ZX_RSRC_KIND_SYSTEM, base, 1,
+                                                  nullptr, 0, &new_resource);
+  if (status != ZX_OK) {
+    return zx::error(status);
+  }
+  return zx::ok(std::move(new_resource));
+}
+
 // This overrides a weak definition in libc, replacing the hook that's
 // ordinarily defined by fdio.  The retain attribute makes sure that linker
 // doesn't decide it can elide this definition and let libc use its weak one.
diff --git a/third_party/antlion b/third_party/antlion
index 6427076..05909d4 160000
--- a/third_party/antlion
+++ b/third_party/antlion
@@ -1 +1 @@
-Subproject commit 64270760cf7522f248548ad1b923db417dfc41e9
+Subproject commit 05909d49e4957027bc0332529a5cb7c3e64f036d
diff --git a/third_party/cobalt b/third_party/cobalt
index 69be2f1..77b22bf 160000
--- a/third_party/cobalt
+++ b/third_party/cobalt
@@ -1 +1 @@
-Subproject commit 69be2f1314d87c8240af3d9e866f98faf7d53134
+Subproject commit 77b22bf067e6f89d36d42b98da419352553b6435
diff --git a/third_party/cobalt_config b/third_party/cobalt_config
index d1371c7..da867f2 160000
--- a/third_party/cobalt_config
+++ b/third_party/cobalt_config
@@ -1 +1 @@
-Subproject commit d1371c778647e58a6665f8dc61256eaf7bcd0060
+Subproject commit da867f296b5ea9301b864ccf119180fb41643e6d
diff --git a/third_party/fuchsia-infra-bazel-rules/src b/third_party/fuchsia-infra-bazel-rules/src
index 7a761b3..b242b4a 160000
--- a/third_party/fuchsia-infra-bazel-rules/src
+++ b/third_party/fuchsia-infra-bazel-rules/src
@@ -1 +1 @@
-Subproject commit 7a761b301ff30c8f0a8bde0f058324f1832c0ef0
+Subproject commit b242b4add86e25c48ca9a33ede7ec9157a515a2f
diff --git a/third_party/github.com/google/emboss/src b/third_party/github.com/google/emboss/src
index e0f9b36..f94cbfb 160000
--- a/third_party/github.com/google/emboss/src
+++ b/third_party/github.com/google/emboss/src
@@ -1 +1 @@
-Subproject commit e0f9b368bba0309f0f8ebf80487e5125f56f1f3c
+Subproject commit f94cbfb1e79e7464cccf7a6e41a695bc4838167c
diff --git a/third_party/gvisor_syscall_tests/BUILD.gn b/third_party/gvisor_syscall_tests/BUILD.gn
index 3e1c0e3..9e215fa 100644
--- a/third_party/gvisor_syscall_tests/BUILD.gn
+++ b/third_party/gvisor_syscall_tests/BUILD.gn
@@ -507,11 +507,7 @@
 
 ns3_labels = []
 foreach(label, suite_labels) {
-  # TODO(https://fxbug.dev/331492167): Enable loopback syscall tests on riscv
-  # builders.
-  if (target_cpu != "riscv64" || label != loopback_test_label) {
-    ns3_labels += [ ":${label}_ns3" ]
-  }
+  ns3_labels += [ ":${label}_ns3" ]
 }
 
 all_packages = ns3_labels
diff --git a/third_party/gvisor_syscall_tests/LATEST_GIT_COMMIT.txt b/third_party/gvisor_syscall_tests/LATEST_GIT_COMMIT.txt
index 924bfcd..0ea9b9c 100644
--- a/third_party/gvisor_syscall_tests/LATEST_GIT_COMMIT.txt
+++ b/third_party/gvisor_syscall_tests/LATEST_GIT_COMMIT.txt
@@ -1 +1 @@
-5b9642a0f29bac2eabdb561ee8d7a96a98627f59
+43c2c00c5006e7d21ce9cd431692622031891231
diff --git a/third_party/gvisor_syscall_tests/expects/netstack3/raw_packet.json5 b/third_party/gvisor_syscall_tests/expects/netstack3/raw_packet.json5
index 2bb011a..df3c7a0 100644
--- a/third_party/gvisor_syscall_tests/expects/netstack3/raw_packet.json5
+++ b/third_party/gvisor_syscall_tests/expects/netstack3/raw_packet.json5
@@ -6,49 +6,88 @@
         {
             type: "expect_failure",
             matchers: [
-                // TODO(https://fxbug.dev/42058078): Support packet sockets.
-                "AllInetTests/RawPacketTest.SetSocketSendBuf*",
-                "AllInetTests/RawPacketTest.GetSocketError*",
-                "AllInetTests/RawPacketTest.SetSocketDetachFilterNoInstalledFilter/*",
-                "AllInetTests/RawPacketTest.SetAndGetSocketLinger/*",
+                // Not-yet-supported socket options on raw packet sockets.
                 "AllInetTests/RawPacketTest.GetSocketAcceptConn/*",
-                "AllRawPacketMsgSizeTest/*",
-                "RawHDRINCL.*",
-                "RawSocketICMPTest.*",
-                "RawSocketICMPv6Test.*",
-                "AllInetTests/RawSocketTest.*",
-                "AllRawSocketTests/*",
-                "RawSocketTest.*",
-            ],
-        },
-        {
-            type: "expect_pass",
-            matchers: [
-                "RawSocketTest.SetIPv6ChecksumError_ReadShort",
-                "RawHDRINCL.MultipleCreation",
-                "RawHDRINCL.FailListen",
-                "RawHDRINCL.FailAccept",
-                "RawHDRINCL.PollWritableImmediately",
-                "AllInetTests/RawSocketTest.MultipleCreation/0",
-                "AllInetTests/RawSocketTest.MultipleCreation/1",
-                "AllInetTests/RawSocketTest.MultipleCreation/2",
-                "AllInetTests/RawSocketTest.MultipleCreation/3",
-                "AllInetTests/RawSocketTest.FailListen/0",
-                "AllInetTests/RawSocketTest.FailListen/1",
-                "AllInetTests/RawSocketTest.FailListen/2",
-                "AllInetTests/RawSocketTest.FailListen/3",
-                "AllInetTests/RawSocketTest.FailAccept/0",
-                "AllInetTests/RawSocketTest.FailAccept/1",
-                "AllInetTests/RawSocketTest.FailAccept/2",
-                "AllInetTests/RawSocketTest.FailAccept/3",
-                "AllInetTests/RawSocketTest.PollWritableImmediately/0",
-                "AllInetTests/RawSocketTest.PollWritableImmediately/1",
-                "AllInetTests/RawSocketTest.PollWritableImmediately/2",
-                "AllInetTests/RawSocketTest.PollWritableImmediately/3",
-                "AllInetTests/RawSocketTest.GetSocketDetachFilter/0",
-                "AllInetTests/RawSocketTest.GetSocketDetachFilter/1",
-                "AllInetTests/RawSocketTest.GetSocketDetachFilter/2",
-                "AllInetTests/RawSocketTest.GetSocketDetachFilter/3",
+                "AllInetTests/RawPacketTest.GetSocketError/*",
+                "AllInetTests/RawPacketTest.GetSocketErrorBind/*",
+                "AllInetTests/RawPacketTest.SetAndGetSocketLinger/*",
+                "AllInetTests/RawPacketTest.SetSocketDetachFilterNoInstalledFilter/*",
+                "AllInetTests/RawPacketTest.SetSocketSendBuf/*",
+                "AllInetTests/RawPacketTest.SetSocketSendBufAboveMax/*",
+                "AllInetTests/RawPacketTest.SetSocketSendBufBelowMin/*",
+
+                // TODO(https://fxbug.dev/42175797): Support Raw IP Sockets.
+                "AllInetTests/RawSocketTest.BindConnectSendAndReceive/*",
+                "AllInetTests/RawSocketTest.BindSendAndReceive/*",
+                "AllInetTests/RawSocketTest.BindThenGetSockName/*",
+                "AllInetTests/RawSocketTest.BindToDevice/*",
+                "AllInetTests/RawSocketTest.BindToInvalid/*",
+                "AllInetTests/RawSocketTest.BindToLocalhost/*",
+                "AllInetTests/RawSocketTest.BindToWildcard/*",
+                "AllInetTests/RawSocketTest.ConnectOnIPv6Socket/*",
+                "AllInetTests/RawSocketTest.ConnectThenGetSockName/*",
+                "AllInetTests/RawSocketTest.ConnectToLoopback/*",
+                "AllInetTests/RawSocketTest.FailGetPeerNameBeforeConnect/*",
+                "AllInetTests/RawSocketTest.FailShutdownWithoutConnect/*",
+                "AllInetTests/RawSocketTest.GetPeerName/*",
+                "AllInetTests/RawSocketTest.MultipleSocketReceive/*",
+                "AllInetTests/RawSocketTest.PollNotReadableInitially/*",
+                "AllInetTests/RawSocketTest.PollTriggeredOnWrite/*",
+                "AllInetTests/RawSocketTest.RecvBufLimits/*",
+                "AllInetTests/RawSocketTest.RecvBufLimitsEmptyRecvBuffer/*",
+                "AllInetTests/RawSocketTest.SendAndReceive/*",
+                "AllInetTests/RawSocketTest.SendAndReceiveViaConnect/*",
+                "AllInetTests/RawSocketTest.SendWithoutConnectFails/*",
+                "AllInetTests/RawSocketTest.SetSocketDetachFilterNoInstalledFilter/*",
+                "AllInetTests/RawSocketTest.SetSocketRecvBuf/*",
+                "AllInetTests/RawSocketTest.SetSocketRecvBufAboveMax/*",
+                "AllInetTests/RawSocketTest.SetSocketRecvBufBelowMin/*",
+                "AllInetTests/RawSocketTest.SetSocketSendBuf/*",
+                "AllInetTests/RawSocketTest.SetSocketSendBufAboveMax/*",
+                "AllInetTests/RawSocketTest.SetSocketSendBufBelowMin/*",
+                "AllInetTests/RawSocketTest.ShutdownReadNoop/*",
+                "AllInetTests/RawSocketTest.ShutdownWriteNoop/*",
+                "AllRawPacketMsgSizeTest/RawPacketMsgSizeTest.SendTooLong/*",
+                "AllRawPacketMsgSizeTest/RawPacketMsgSizeTest.SpliceTooLong/*",
+                "AllRawSocketTests/RawSocketICMPv6TypeTest.FilterDeliveredPackets/*",
+                "RawHDRINCL.BindToInvalid",
+                "RawHDRINCL.BindToLocalhost",
+                "RawHDRINCL.ConnectToLoopback",
+                "RawHDRINCL.FailShutdownWithoutConnect",
+                "RawHDRINCL.NotReadable",
+                "RawHDRINCL.NotReadableAfterWrite",
+                "RawHDRINCL.SendAndReceive",
+                "RawHDRINCL.SendAndReceiveDifferentAddress",
+                "RawHDRINCL.SendAndReceiveIPHdrIncl",
+                "RawHDRINCL.SendWithoutConnectFails",
+                "RawHDRINCL.WriteTooSmall",
+                "RawSocketICMPTest.BindConnectSendAndReceive",
+                "RawSocketICMPTest.BindSendAndReceive",
+                "RawSocketICMPTest.GetSocketAcceptConn",
+                "RawSocketICMPTest.ICMPv6FilterNotSupported",
+                "RawSocketICMPTest.IPv6ChecksumNotSupported",
+                "RawSocketICMPTest.MultipleSocketReceive",
+                "RawSocketICMPTest.SendAndReceive",
+                "RawSocketICMPTest.SendAndReceiveBadChecksum",
+                "RawSocketICMPTest.SendAndReceiveViaConnect",
+                "RawSocketICMPTest.SetAndGetSocketLinger",
+                "RawSocketICMPv6Test.GetPartialFilterSucceeds",
+                "RawSocketICMPv6Test.InitialFilterPassesAll",
+                "RawSocketICMPv6Test.MsgTooSmallToFillChecksumFailsSend",
+                "RawSocketICMPv6Test.PingSuccessfully",
+                "RawSocketICMPv6Test.SetSockOptIPv6ChecksumFails",
+                "RawSocketTest.BindReceive",
+                "RawSocketTest.IPv6Checksum_ValidateAndCalculate",
+                "RawSocketTest.IPv6ProtoRaw",
+                "RawSocketTest.IPv6SendMsg",
+                "RawSocketTest.ReceiveHopLimit",
+                "RawSocketTest.ReceiveIPPacketInfo",
+                "RawSocketTest.ReceiveIPv6PacketInfo",
+                "RawSocketTest.ReceiveTClass",
+                "RawSocketTest.ReceiveTOS",
+                "RawSocketTest.ReceiveTTL",
+                "RawSocketTest.SetIPv6ChecksumError_MultipleOf2",
+                "RawSocketTest.UnboundReceive",
             ],
         },
     ],
diff --git a/third_party/gvisor_syscall_tests/gvisor/test/syscalls/linux/socket_inet_loopback.cc b/third_party/gvisor_syscall_tests/gvisor/test/syscalls/linux/socket_inet_loopback.cc
index 56e2974..25bb818 100644
--- a/third_party/gvisor_syscall_tests/gvisor/test/syscalls/linux/socket_inet_loopback.cc
+++ b/third_party/gvisor_syscall_tests/gvisor/test/syscalls/linux/socket_inet_loopback.cc
@@ -979,56 +979,6 @@
 // random save as established connections which can't be delivered to the accept
 // queue because the queue is full are not correctly delivered after restore
 // causing the last accept to timeout on the restore.
-TEST_P(SocketInetLoopbackTest, TCPAcceptBacklogSizes) {
-  SocketInetTestParam const& param = GetParam();
-
-  TestAddress const& listener = param.listener;
-  TestAddress const& connector = param.connector;
-
-  // Create the listening socket.
-  const FileDescriptor listen_fd = ASSERT_NO_ERRNO_AND_VALUE(
-      Socket(listener.family(), SOCK_STREAM, IPPROTO_TCP));
-  sockaddr_storage listen_addr = listener.addr;
-  ASSERT_THAT(
-      bind(listen_fd.get(), AsSockAddr(&listen_addr), listener.addr_len),
-      SyscallSucceeds());
-  // Get the port bound by the listening socket.
-  socklen_t addrlen = listener.addr_len;
-  ASSERT_THAT(getsockname(listen_fd.get(), AsSockAddr(&listen_addr), &addrlen),
-              SyscallSucceeds());
-  uint16_t const port =
-      ASSERT_NO_ERRNO_AND_VALUE(AddrPort(listener.family(), listen_addr));
-  std::array<int, 3> backlogs = {-1, 0, 1};
-  for (auto& backlog : backlogs) {
-    ASSERT_THAT(listen(listen_fd.get(), backlog), SyscallSucceeds());
-
-    int expected_accepts;
-    if (backlog < 0) {
-      expected_accepts = 1024;
-    } else {
-      // See the comment in TCPBacklog for why this isn't backlog + 1.
-      expected_accepts = backlog;
-    }
-    for (int i = 0; i < expected_accepts; i++) {
-      SCOPED_TRACE(absl::StrCat("i=", i));
-      // Connect to the listening socket.
-      const FileDescriptor conn_fd = ASSERT_NO_ERRNO_AND_VALUE(
-          Socket(connector.family(), SOCK_STREAM, IPPROTO_TCP));
-      sockaddr_storage conn_addr = connector.addr;
-      ASSERT_NO_ERRNO(SetAddrPort(connector.family(), &conn_addr, port));
-      ASSERT_THAT(RetryEINTR(connect)(conn_fd.get(), AsSockAddr(&conn_addr),
-                                      connector.addr_len),
-                  SyscallSucceeds());
-      const FileDescriptor accepted =
-          ASSERT_NO_ERRNO_AND_VALUE(Accept(listen_fd.get(), nullptr, nullptr));
-    }
-  }
-}
-
-// TODO(b/153489135): Remove  once bug is fixed. Test fails w/
-// random save as established connections which can't be delivered to the accept
-// queue because the queue is full are not correctly delivered after restore
-// causing the last accept to timeout on the restore.
 TEST_P(SocketInetLoopbackTest, TCPBacklog) {
   SocketInetTestParam const& param = GetParam();
 
diff --git a/third_party/llvm-libc/src b/third_party/llvm-libc/src
index 7c15455..bc1b7b5 160000
--- a/third_party/llvm-libc/src
+++ b/third_party/llvm-libc/src
@@ -1 +1 @@
-Subproject commit 7c154553332eb3989d25dd3f5dbfe2dc6c48d5cf
+Subproject commit bc1b7b5151b8e1751053288fafea6b153ec87ff3
diff --git a/third_party/mesa b/third_party/mesa
index d2b3a20..80c5429 160000
--- a/third_party/mesa
+++ b/third_party/mesa
@@ -1 +1 @@
-Subproject commit d2b3a2051179b265d0817d9e027101a85a91d4fe
+Subproject commit 80c5429c69c53b9bc3e62a08618c2d427ba61e53
diff --git a/third_party/openssh-portable b/third_party/openssh-portable
index 250f64e..9907b3e 160000
--- a/third_party/openssh-portable
+++ b/third_party/openssh-portable
@@ -1 +1 @@
-Subproject commit 250f64e746b0bcb58776099f3fe893089a51b221
+Subproject commit 9907b3ed5b59b21688ba5c17eb0d550d82e4be40
diff --git a/third_party/openthread b/third_party/openthread
index cafef38..bb1a525 160000
--- a/third_party/openthread
+++ b/third_party/openthread
@@ -1 +1 @@
-Subproject commit cafef38edc11573db8ac4a02797e7959ef22f96f
+Subproject commit bb1a52547cd6059040655d4ed84b02407ddb0f33
diff --git a/third_party/pigweed/backends/pw_log/BUILD.gn b/third_party/pigweed/backends/pw_log/BUILD.gn
index 9045345..17a94ff 100644
--- a/third_party/pigweed/backends/pw_log/BUILD.gn
+++ b/third_party/pigweed/backends/pw_log/BUILD.gn
@@ -57,3 +57,11 @@
     "//src/lib/ddk",
   ]
 }
+
+source_set("dfv2") {
+  sources = [ "log_dfv2.cc" ]
+  deps = [
+    ":pw_log",
+    "//sdk/lib/driver/logging/cpp",
+  ]
+}
diff --git a/third_party/pigweed/backends/pw_log/log_dfv2.cc b/third_party/pigweed/backends/pw_log/log_dfv2.cc
new file mode 100644
index 0000000..225ce03
--- /dev/null
+++ b/third_party/pigweed/backends/pw_log/log_dfv2.cc
@@ -0,0 +1,38 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/driver/logging/cpp/logger.h>
+
+#include "pw_log_fuchsia/log_fuchsia.h"
+
+namespace {
+inline FuchsiaLogSeverity LogLevelToLogSeverity(int level) {
+  switch (level) {
+    case PW_LOG_LEVEL_DEBUG:
+      return FUCHSIA_LOG_DEBUG;
+    case PW_LOG_LEVEL_INFO:
+      return FUCHSIA_LOG_INFO;
+    case PW_LOG_LEVEL_WARN:
+      return FUCHSIA_LOG_WARNING;
+    case PW_LOG_LEVEL_ERROR:
+    case PW_LOG_LEVEL_CRITICAL:
+      return FUCHSIA_LOG_ERROR;
+    case PW_LOG_LEVEL_FATAL:
+      return FUCHSIA_LOG_FATAL;
+    default:
+      return FUCHSIA_LOG_INFO;
+  }
+}
+}  // namespace
+
+extern "C" {
+void pw_log_fuchsia_impl(int level, const char* module_name, const char* file_name, int line_number,
+                         const char* message) {
+  FuchsiaLogSeverity severity = LogLevelToLogSeverity(level);
+  if (fdf::Logger::GlobalInstance()->GetSeverity() <= severity) {
+    fdf::Logger::GlobalInstance()->logf(severity, module_name, file_name, line_number, "%s",
+                                        message);
+  }
+}
+}
diff --git a/third_party/pigweed/src b/third_party/pigweed/src
index 2369171..84084ec 160000
--- a/third_party/pigweed/src
+++ b/third_party/pigweed/src
@@ -1 +1 @@
-Subproject commit 23691711b80943ada28bc9c805ee6ad3ded88387
+Subproject commit 84084ec60dd5d15e0732bc5ba32190a047550ae2
diff --git a/third_party/rust_crates/BUILD.gn b/third_party/rust_crates/BUILD.gn
index 0dee065..55aad80 100644
--- a/third_party/rust_crates/BUILD.gn
+++ b/third_party/rust_crates/BUILD.gn
@@ -630,8 +630,8 @@
   public_deps = [ ":pin-project-v1_0_11" ]
 }
 
-group("pin-utils") {
-  public_deps = [ ":pin-utils-v0_1_0" ]
+group("pin-project-lite") {
+  public_deps = [ ":pin-project-lite-v0_2_13" ]
 }
 
 group("pkcs8") {
diff --git a/third_party/rust_crates/Cargo.lock b/third_party/rust_crates/Cargo.lock
index bbd521a..4e636b31 100644
--- a/third_party/rust_crates/Cargo.lock
+++ b/third_party/rust_crates/Cargo.lock
@@ -1399,7 +1399,7 @@
  "pest_derive",
  "petgraph",
  "pin-project",
- "pin-utils",
+ "pin-project-lite",
  "pkcs8",
  "png",
  "pretty",
diff --git a/third_party/rust_crates/Cargo.toml b/third_party/rust_crates/Cargo.toml
index a7142ba..d158699 100644
--- a/third_party/rust_crates/Cargo.toml
+++ b/third_party/rust_crates/Cargo.toml
@@ -166,7 +166,7 @@
 pest = "2.7.8"
 pest_derive = "2.7.8"
 pin-project = "1.0.11"
-pin-utils = "0.1.0"
+pin-project-lite = "0.2.13"
 png = "0.14" # saved for future use
 pretty_assertions = "1.2.1"
 prettytable-rs = "0.8.0"
diff --git a/third_party/scudo/src b/third_party/scudo/src
index eb39902..784c4cf 160000
--- a/third_party/scudo/src
+++ b/third_party/scudo/src
@@ -1 +1 @@
-Subproject commit eb39902a7b3bd689e8fbb70a7535c736a5ef594b
+Subproject commit 784c4cf7cccaee34237bd0f3607acce7d3690247
diff --git a/tools/botanist/cmd/run.go b/tools/botanist/cmd/run.go
index 614708d..ffbcdc9 100644
--- a/tools/botanist/cmd/run.go
+++ b/tools/botanist/cmd/run.go
@@ -107,6 +107,9 @@
 
 	// When true, upload to resultdb from testrunner.
 	uploadToResultDB bool
+
+	// The timeout to wait for an SSH connection after booting the target.
+	bootupTimeout time.Duration
 }
 
 func (*RunCommand) Name() string {
@@ -146,6 +149,7 @@
 	f.BoolVar(&r.skipSetup, "skip-setup", false, "if set, botanist will not set up a target.")
 	// Temporary flag to enable a soft transition to uploading test results from botanist rather than from the recipe.
 	f.BoolVar(&r.uploadToResultDB, "upload-to-resultdb", false, "if set, test results will be uploaded to ResultDB from testrunner.")
+	f.DurationVar(&r.bootupTimeout, "bootup-timeout", 0, "duration allowed for the command to finish execution, a value of 0 (zero) will fall back to the default.")
 
 	// Parsing of testrunner options.
 	f.StringVar(&r.testrunnerOptions.OutDir, "out-dir", "", "Optional path where a directory containing test results should be created.")
@@ -351,6 +355,7 @@
 			ProductBundles:    r.productBundles,
 			ProductBundleName: r.productBundleName,
 			IsBootTest:        r.isBootTest,
+			BootupTimeout:     r.bootupTimeout,
 		}
 
 		if err := targets.StartTargets(ctx, startOpts, fuchsiaTargets); err != nil {
@@ -402,7 +407,7 @@
 						}
 						syslogPath := filepath.Join(r.syslogDir, syslogName)
 						if err := t.CaptureSyslog(client, syslogPath, r.repoURL, r.blobURL); err != nil && ctx.Err() == nil {
-							logger.Errorf(ctx, "failed to capture syslog at %s: %s", syslogPath, err)
+							logger.Errorf(ctx, "%s at %s: %s", constants.FailedToCaptureSyslogMsg, syslogPath, err)
 						}
 					}()
 				}
diff --git a/tools/botanist/constants/constants.go b/tools/botanist/constants/constants.go
index d94c31c..991eda0 100644
--- a/tools/botanist/constants/constants.go
+++ b/tools/botanist/constants/constants.go
@@ -16,6 +16,7 @@
 	FailedToExtendBlkMsg      = "failed to extend blk"
 	CommandExceededTimeoutMsg = "Command exceeded timeout"
 	FailedToServeMsg          = "[package server] failed to serve"
+	FailedToCaptureSyslogMsg  = "failed to capture syslog"
 
 	NodenameEnvKey     = "FUCHSIA_NODENAME"
 	SSHKeyEnvKey       = "FUCHSIA_SSH_KEY"
diff --git a/tools/botanist/targets/gce.go b/tools/botanist/targets/gce.go
index 35c4833..0212e4e 100644
--- a/tools/botanist/targets/gce.go
+++ b/tools/botanist/targets/gce.go
@@ -33,8 +33,7 @@
 )
 
 const (
-	gcemClientBinary  = "./gcem_client"
-	gceSerialEndpoint = "ssh-serialport.googleapis.com:9600"
+	gcemClientBinary = "./gcem_client"
 )
 
 // gceSerial is a ReadWriteCloser that talks to a GCE serial port via SSH.
@@ -283,7 +282,6 @@
 	pubkey = strings.TrimSuffix(pubkey, "\n")
 	pubkey = fmt.Sprintf("\"%s %s\"", pubkey, g.currentUser)
 	cmds := []serial.Command{
-		{Cmd: []string{"/pkgfs/packages/sshd-host/0/bin/hostkeygen"}},
 		{Cmd: []string{"echo", pubkey, ">", "/data/ssh/authorized_keys"}},
 	}
 	if err := serial.RunCommands(ctx, g.serial, cmds); err != nil {
@@ -306,6 +304,12 @@
 	return nil
 }
 
+func getSerialEndpoint(zone string) string {
+	zoneParts := strings.Split(zone, "-")
+	region := strings.ToLower(strings.Join(zoneParts[:len(zoneParts)-1], "-"))
+	return fmt.Sprintf("%s-ssh-serialport.googleapis.com:9600", region)
+}
+
 func (g *GCE) connectToSerial() error {
 	username := fmt.Sprintf(
 		"%s.%s.%s.%s.%s",
@@ -315,7 +319,7 @@
 		g.currentUser,
 		"replay-from=0",
 	)
-	serial, err := newGCESerial(g.opts.SSHKey, username, gceSerialEndpoint)
+	serial, err := newGCESerial(g.opts.SSHKey, username, getSerialEndpoint(g.config.Zone))
 	g.serial = serial
 	return err
 }
diff --git a/tools/botanist/targets/target.go b/tools/botanist/targets/target.go
index 6c64b10..18d48ea 100644
--- a/tools/botanist/targets/target.go
+++ b/tools/botanist/targets/target.go
@@ -424,8 +424,19 @@
 	defer f.Close()
 
 	syslogWriter := botanist.NewLineWriter(botanist.NewTimestampWriter(f), "")
-	errs := syslogger.Stream(t.targetCtx, syslogWriter)
+	syslogCtx, cancel := context.WithCancel(t.targetCtx)
+	defer cancel()
+	errs := syslogger.Stream(syslogCtx, syslogWriter)
+	maxAttempts := 5
+	startTime := time.Now()
+	attempt := 0
 	for range errs {
+		attempt += 1
+		if attempt == maxAttempts && time.Since(startTime) < time.Minute {
+			// If we failed maxAttempts times within a minute of starting to stream,
+			// then there's likely an issue with the syslogger so return an err.
+			return fmt.Errorf("failed to capture syslog %d times within 1 minute", maxAttempts)
+		}
 		if !syslogger.IsRunning() {
 			return nil
 		}
@@ -434,12 +445,18 @@
 		// build out a more resilient framework in which we register "restart handlers"
 		// that are triggered on reboot.
 		if repoURL != "" && blobURL != "" {
-			client, err := t.SSHClient()
-			if err != nil {
-				return fmt.Errorf("failed to get SSH client: %w", err)
+			select {
+			case <-client.DisconnectionListener():
+				if err := client.Reconnect(syslogCtx); err != nil {
+					return fmt.Errorf("failed to reconnect SSH client: %w", err)
+				}
+			default:
+				// The client is still connected, so continue.
 			}
 			t.AddPackageRepository(client, repoURL, blobURL)
-			client.Close()
+			if t.UseFFXExperimental(1) {
+				client.Close()
+			}
 		}
 	}
 	return nil
@@ -644,6 +661,9 @@
 
 	// IsBootTest tells whether the provided product bundle is for a boot test.
 	IsBootTest bool
+
+	// BootupTimeout is the timeout to wait for an SSH connection after booting the target.
+	BootupTimeout time.Duration
 }
 
 // StartTargets starts all the targets given the opts.
@@ -657,9 +677,8 @@
 	eg, startCtx := errgroup.WithContext(ctx)
 	for _, t := range targets {
 		t := t
-		// TODO(https://fxbug.dev/322239710): Find a way to set this per product bundle.
-		if opts.IsBootTest {
-			t.SetConnectionTimeout(10 * time.Minute)
+		if opts.BootupTimeout > 0 {
+			t.SetConnectionTimeout(opts.BootupTimeout)
 		}
 		eg.Go(func() error {
 			imgs, closeFunc, err := bootserver.GetImages(startCtx, opts.ImageManifest, bootMode)
diff --git a/tools/build/tests.go b/tools/build/tests.go
index a9a73a0..9d7706e 100644
--- a/tools/build/tests.go
+++ b/tools/build/tests.go
@@ -22,6 +22,10 @@
 	// ProductBundle is the name of the product bundle describing the system
 	// against which the test should be run.
 	ProductBundle string `json:"product_bundle,omitempty"`
+
+	// BootupTimeout is the timeout in seconds that the test expects the provided
+	// product bundle and environment it's run against to take to boot up.
+	BootupTimeoutSecs int `json:"bootup_timeout_secs,omitempty"`
 }
 
 // Test encapsulates details about a particular test.
diff --git a/tools/check-licenses/assets/readmes/prebuilt/third_party/llvm/fuchsia-arm64/README.fuchsia b/tools/check-licenses/assets/readmes/prebuilt/third_party/llvm/fuchsia-arm64/README.fuchsia
new file mode 100644
index 0000000..32198ae
--- /dev/null
+++ b/tools/check-licenses/assets/readmes/prebuilt/third_party/llvm/fuchsia-arm64/README.fuchsia
@@ -0,0 +1,13 @@
+Name: The LLVM Project
+
+License File: LICENSE.TXT
+ -> License File Format: Single License
+ -> License Classifications: Apache-2.0, Copyright, NCSA
+
+License File: include/llvm/Support/LICENSE.TXT
+ -> License File Format: Single License
+
+Description:
+
+
+Local Modifications:
diff --git a/tools/check-licenses/assets/readmes/prebuilt/third_party/llvm/fuchsia-x64/README.fuchsia b/tools/check-licenses/assets/readmes/prebuilt/third_party/llvm/fuchsia-x64/README.fuchsia
new file mode 100644
index 0000000..32198ae
--- /dev/null
+++ b/tools/check-licenses/assets/readmes/prebuilt/third_party/llvm/fuchsia-x64/README.fuchsia
@@ -0,0 +1,13 @@
+Name: The LLVM Project
+
+License File: LICENSE.TXT
+ -> License File Format: Single License
+ -> License Classifications: Apache-2.0, Copyright, NCSA
+
+License File: include/llvm/Support/LICENSE.TXT
+ -> License File Format: Single License
+
+Description:
+
+
+Local Modifications:
diff --git a/tools/check-licenses/directory/_config.json b/tools/check-licenses/directory/_config.json
index 92933ea..65100649 100644
--- a/tools/check-licenses/directory/_config.json
+++ b/tools/check-licenses/directory/_config.json
@@ -19,7 +19,9 @@
                     "Investigation in https://fxbug.dev/333576929"
                 ],
                 "paths": [
-                    "prebuilt/connectivity/bluetooth/bt-host"
+                    "prebuilt/connectivity/bluetooth/bt-host",
+                    "prebuilt/drivers/msd-arm-mali-debug",
+                    "prebuilt/drivers/msd-arm-mali-release"
                 ]
             },
             {
diff --git a/tools/check-licenses/result/_config.json b/tools/check-licenses/result/_config.json
index 31a6534..7b356af 100644
--- a/tools/check-licenses/result/_config.json
+++ b/tools/check-licenses/result/_config.json
@@ -218,6 +218,8 @@
           "third_party/rust_crates/ask2patch/same-file/COPYING": true,
           "third_party/rust_crates/ask2patch/termcolor/COPYING": true,
           "third_party/rust_crates/ask2patch/byteorder/COPYING": true,
+          "prebuilt/third_party/llvm/fuchsia-arm64/include/llvm/Support/LICENSE.TXT": true,
+          "prebuilt/third_party/llvm/fuchsia-x64/include/llvm/Support/LICENSE.TXT": true,
           "prebuilt/third_party/llvm/linux-arm64/include/llvm/Support/LICENSE.TXT": true,
           "third_party/openthread/NOTICE": true,
           "third_party/network-conformance/orchestrator/dutscripts/tclfmt/LICENSE": true,
diff --git a/tools/cmc/build/restricted_features/BUILD.gn b/tools/cmc/build/restricted_features/BUILD.gn
index e463c81..7ef9ba9 100644
--- a/tools/cmc/build/restricted_features/BUILD.gn
+++ b/tools/cmc/build/restricted_features/BUILD.gn
@@ -9,7 +9,11 @@
 
 # The allowlist of components that can use dictionaries in CML.
 group("dictionaries") {
-  visibility = [ "//src/sys/component_manager/tests/*" ]
+  visibility = [
+    "//src/session/bin/session_manager:*",
+    "//src/sys/component_manager/tests/*",
+    "//vendor/google/boards/*",
+  ]
 }
 
 # The allowlist of components that can use config capabilities in CML.
diff --git a/tools/devshell/contrib/OWNERS b/tools/devshell/contrib/OWNERS
index b5fcc52..485d3c5 100644
--- a/tools/devshell/contrib/OWNERS
+++ b/tools/devshell/contrib/OWNERS
@@ -56,3 +56,4 @@
 per-file roll-compiler = file: /scripts/rust/OWNERS
 per-file zedmon=claridge@google.com
 per-file size-check = aaronwood@google.com,awolter@google.com,diserovich@google.com,frousseau@google.com,jfsulliv@google.com,thomasalpinus@google.com,wittrock@google.com
+per-file add-test=yifeit@google.com
diff --git a/tools/devshell/contrib/add-test b/tools/devshell/contrib/add-test
new file mode 100755
index 0000000..3806b51
--- /dev/null
+++ b/tools/devshell/contrib/add-test
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+#### CATEGORY=Build
+### add a GN label to args.gn and regen
+
+## usage: fx add-test //foo/bar //foo/baz
+##
+## Adds the labels to `developer_test_labels` and regen.
+## This is useful when `fx test` tells you to add a target to the build,
+## but you have some custom args set in `args.gn`, so do not want to run
+## `fx set` to overwrite those args.
+
+readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
+source "$SCRIPT_DIR/../lib/vars.sh" || exit $?
+
+fx-config-read
+
+set -e
+
+# Cache args in case of typos, bad paths, etc.
+args_gn="${FUCHSIA_BUILD_DIR}/args.gn"
+backup_args_gn="$(mktemp --suffix=.args.gn)"
+cp "${args_gn}" "${backup_args_gn}"
+
+echo "Adding test labels to ${args_gn}"
+
+for arg in "$@"; do
+    if [ "$arg" == "--with" ]; then
+        # Skip the '--with' argument, which is included in some error messages
+        continue
+    fi
+    # Append the formatted string to args.gn
+    echo "developer_test_labels += [\"$arg\"]" >> "$args_gn"
+done
+
+echo "Generating Ninja outputs file"
+if ! fx-gen; then
+    echo "fx gen failed, restoring original args.gn and re-running 'fx gen'"
+    cp "${backup_args_gn}" "${args_gn}"
+    fx-gen
+fi
+
+rm -f "${backup_args_gn}"
diff --git a/tools/devshell/contrib/lib/rust/rustdoc.py b/tools/devshell/contrib/lib/rust/rustdoc.py
index 01c751f..e5df62e 100755
--- a/tools/devshell/contrib/lib/rust/rustdoc.py
+++ b/tools/devshell/contrib/lib/rust/rustdoc.py
@@ -83,9 +83,13 @@
     ):
         env[f"CARGO_TARGET_{target}_LINKER"] = clang
         if "FUCHSIA" in target:
-            env[
-                f"CARGO_TARGET_{target}_RUSTFLAGS"
-            ] = f"-Clink-arg=--sysroot={fuchsia_sysroot} -Lnative={shared_libs_root}"
+            env[f"CARGO_TARGET_{target}_RUSTFLAGS"] = " ".join(
+                [
+                    f"-Clink-arg=--sysroot={fuchsia_sysroot}",
+                    f"-Lnative={shared_libs_root}",
+                    f"@{ROOT_PATH / build_dir}/rust_api_level_cfg_flags.txt",
+                ]
+            )
         if "LINUX" in target:
             env[
                 f"CARGO_TARGET_{target}_RUSTFLAGS"
diff --git a/tools/devshell/contrib/remove-update-source b/tools/devshell/contrib/remove-update-source
index 7e2931c..e8d9bb1e 100755
--- a/tools/devshell/contrib/remove-update-source
+++ b/tools/devshell/contrib/remove-update-source
@@ -6,11 +6,11 @@
 #### CATEGORY=Software delivery
 ### deregisters dev host as target's update source
 
-## usage: fx remove-update-source [-r|--repository NAME]
+## usage: fx remove-update-source [-r|--repositoryname NAME]
 ##
-## Configure target device to use a new update source.
+## Configure target device to remove an update source.
 ##
-##   -r|--repo-name NAME  Name the generated repository config NAME.
+##   -r|--repositoryname NAME  Name the generated repository config NAME.
 ##
 ## NAME:
 ## If no name is supplied, the name defaults to "devhost", otherwise
@@ -77,7 +77,7 @@
       repo_name="$(ffx-default-repository-name)"
     fi
 
-    fx-command-run ffx --config ffx_repository=true repository target deregister \
+    fx-command-run ffx --config ffx_repository=true target repository deregister \
       --repository "$repo_name"
     err=$?
 
diff --git a/tools/devshell/serve b/tools/devshell/serve
index 8f6608d..8c40781 100755
--- a/tools/devshell/serve
+++ b/tools/devshell/serve
@@ -7,18 +7,12 @@
 ### start the update server and attach to a running fuchsia device
 ## usage: fx serve [-v] [-l host[:port]] [-c version] [--no-auto-config] [--name NAME]
 ##
-##   -l host:port       host and port that "pm serve" will listen on
-##   -c version         configuration format version for the served config.json
-##                      that "pm" will serve. Valid choices: 1 or 2.
-##                      Choosing `1` will serve a file which can be processed by
-##                      `pkgctl repo add ... -f 1`.
-##                      Choosing `2` will serve a file which can be processed by
-##                      `pkgctl repo ...` without the `-f 1` switch.
+##   -l host:port       host and port that "fx serve" will listen on
 ##   --no-auto-config   do not configure this host as a package server on the device
 ##   --name NAME        Name the generated update source config NAME.
 ##   --[no-]persist     enable or disable persistence of repository metadata. Disabled
 ##                      by default.
-##   -v                 verbose mode, shows info and debug messages from "pm" and "ffx repository serve"
+##   -v                 verbose mode, shows info and debug messages from "ffx repository serve"
 ##   -C|--clean         clean the package repository first. This flag is only
 ##                      valid if the incremental package publishing is enabled.
 ##
@@ -48,7 +42,6 @@
 verbose=false
 auto_config=true
 clean_first=false
-config_format="2"
 source_name=""
 persist="--no-persist"
 while (($#)); do
@@ -58,10 +51,6 @@
       port="${1##*:}"
       pm_serve_flags+=(-l "$1")
       ;;
-    -c)
-      config_format=("$2")
-      shift
-      ;;
     --name)
       source_name="$2"
       shift
@@ -88,7 +77,6 @@
   esac
   shift
 done
-pm_serve_flags+=("-c" "${config_format}")
 
 if fx-is-bringup; then
   fx-error "$0 is not supported in the bringup build configuration, as there are no package features in bringup."
@@ -183,6 +171,44 @@
   )
 }
 
+pm_bg_resolutions() {
+  fx-error "Please consider switching to foreground serving via ffx, and report"
+  fx-error "any blocking issues at your earliest convenience."
+  fx-error "To serve repositories, please pick between the following two options:"
+  fx-error ""
+  fx-error "1. Disable pm and switch to ffx foreground server (aka supported):"
+  fx-error ""
+  fx-error "   Ensure your shell does *not* export the environment variable"
+  fx-error "   FUCHSIA_DISABLED_foreground_repo_server"
+  fx-error ""
+  fx-error "   $ ffx config remove repository.server.mode"
+  fx-error "   $ ffx config remove repository.server.enabled"
+  fx-error "   $ ffx doctor --restart-daemon"
+  fx-error ""
+  fx-error "   Then restart \"fx serve\""
+  fx-error ""
+  fx-error "2. Strongly discouraged, this option is going away at the end"
+  fx-error "   of 2024Q2: Ensure your shell *does* export the following"
+  fx-error "   environment variable wherever you use fx and ffx."
+  fx-error ""
+  fx-error "   $ export FUCHSIA_DISABLED_foreground_repo_server=1"
+  fx-error ""
+  fx-error "   Enable the ffx background server:"
+  fx-error ""
+  fx-error "   $ ffx config remove repository.server.mode"
+  fx-error "   $ ffx config set repository.server.enabled true"
+  fx-error "   $ ffx doctor --restart-daemon"
+  fx-error ""
+  fx-error "In both cases, please note that an already running foreground server is"
+  fx-error "not always detected correctly. Consider running the following commands"
+  fx-error "in case of problems:"
+  fx-error ""
+  fx-error "$ ffx config remove repository.server.listen"
+  fx-error "$ ffx doctor --restart-daemon"
+  fx-error ""
+  exit 1
+}
+
 repo_dir="${FUCHSIA_BUILD_DIR}/amber-files"
 
 if is_feature_enabled "incremental" || is_feature_enabled "incremental_new" || is_feature_enabled "incremental_legacy"; then
@@ -238,30 +264,9 @@
 
 # Heads-up for the upcoming removal of pm
 if [[ "${server_mode}" = "pm" ]] ; then
-  fx-warn "Serving repositories with pm is going away, targeted for 2024 Q2."
-  fx-warn "Please consider switching to serving via ffx, and report any issues."
-  fx-warn "To help make the transition as smooth as possible, you can use the"
-  fx-warn "following command to delete your settings overrides and use the"
-  fx-warn "default server mode:"
-  fx-warn ""
-  fx-warn "$ ffx config remove repository.server.mode"
-  fx-warn ""
-fi
-
-# pm and foreground repo server are mutually incompatible
-if [[ "${server_mode}" = "pm" ]] && is_feature_enabled "foreground_repo_server"; then
-  fx-error "The ffx foreground repo server and pm are mutually incompatible."
-  fx-error "If you want to serve via pm (please note that is is going away soon,"
-  fx-error "see above), you can export the following shell variable to disable"
-  fx-error "foreground serving:"
-  fx-error ""
-  fx-error "$ export FUCHSIA_DISABLED_foreground_repo_server=1"
-  fx-error ""
-  fx-error "But please consider using the foreground server instead of pm as"
-  fx-error "described above, and report any issues to help make the transition"
-  fx-error "away from pm as smooth as possible. Thank you."
-  fx-error ""
-  exit 1
+  fx-error "Invoking pm via fx serve is no longer supported. Additionally,"
+  fx-error "the pm is slated for removal, targeted for 2024 Q2."
+  pm_bg_resolutions
 fi
 
 # Default the port to 8083 if it is unset.
@@ -272,7 +277,7 @@
 fi
 
 if [[ "${server_mode}" = "pm" ]]; then
-  pm_serve_args=( serve -vt -repo "${repo_dir}" "${pm_serve_flags[@]}" )
+  pm_serve_args=( serve -vt -c 2 -repo "${repo_dir}" "${pm_serve_flags[@]}" )
 
   # the manifest list file has relative paths and "pm serve" looks for them
   # from PWD, so pm command needs to be executed in "$FUCHSIA_BUILD_DIR"
@@ -284,49 +289,14 @@
   exit 1
 fi
 
-if is_feature_enabled "foreground_repo_server" && [[ "$(ffx-repository-server-enabled)" == "true" ]]; then
-  fx-error "Both the foreground and background server are enabled. This is mutually incompatible."
-  fx-error "To fix this, please pick between the following two options:"
-  fx-error ""
-  fx-error "1. Disable the background server and restart ffx:"
-  fx-error ""
-  fx-error "   $ ffx config remove repository.server.enabled"
-  fx-error "   $ ffx doctor --restart-daemon"
-  fx-error ""
-  fx-error "2. (discouraged, background serving is going away at the end of 2024Q2) Opt out of"
-  fx-error "   using the foreground server: Set the following variable in (sh-type) shells"
-  fx-error "   where you use fx/ffx:"
-  fx-error ""
-  fx-error "   $ export FUCHSIA_DISABLED_foreground_repo_server=1"
-  fx-error ""
-  fx-error "   Please note that an already dunning foreground server may not always"
-  fx-error "   be detected correctly. Consider running the following commands in case"
-  fx-error "   of problems:"
-  fx-error ""
-  fx-error "   $ ffx config remove repository.server.listen"
-  fx-error "   $ ffx doctor --restart-daemon"
-  fx-error ""
-  fx-error "   Then restart \"fx serve\""
-  fx-error ""
-  exit 1
-elif is_feature_enabled "foreground_repo_server"; then
-  fx-info "The 'foreground_repo_server' feature is now enabled by default."
-  fx-info "Background serving with both ffx and pm is going away soon."
-  fx-info "Until the end of 2024Q2, you can opt out of foreground serving by"
-  fx-info "setting the following environment variable in (sh-type) shells"
-  fx-info "where you use fx / ffx:"
-  fx-info ""
-  fx-info "$ export FUCHSIA_DISABLED_foreground_repo_server=1"
-  fx-info ""
-  fx-info "Please note that an already running foreground server"
-  fx-info "may not always be detected correctly. Please consider"
-  fx-info "running the following commands in case of problems:"
-  fx-info ""
-  fx-info "$ ffx config remove repository.server.listen"
-  fx-info "$ ffx doctor --restart-daemon"
-  fx-info ""
-  fx-info "Then restart \"fx serve\""
-  fx-info ""
+if [[ "$(ffx-repository-server-enabled)" == "true" ]]; then
+  if is_feature_enabled "foreground_repo_server"; then
+    fx-error "Both ffx foreground and background serving are enabled. This is mutually incompatible."
+  else
+    fx-error "Starting an ffx background server from \"fx serve\" is no longer supported,"
+    fx-error "preceding the upcoming removal of background serving at the end of 2024Q2."
+  fi
+  pm_bg_resolutions
 fi
 
 # Error out if we can't start a package server.
@@ -491,6 +461,7 @@
       fx-command-exec ffx ${ffx_flags[@]} repository serve \
         --address [::]:${port} \
         --repository "${source_name}" \
+        --repo-path "${repo_dir}" \
         --alias "fuchsia.com" \
         --alias "chromium.org"
       exit 0
diff --git a/tools/devshell/serve-remote b/tools/devshell/serve-remote
index 48ab8cc..3247c59 100755
--- a/tools/devshell/serve-remote
+++ b/tools/devshell/serve-remote
@@ -269,13 +269,21 @@
   fi
 
   if [[ "${remote_server_mode}" == \"pm\" ]]; then
-    # If the user requested serving, then we'll check to see if there's a
-    # remote server already running and kill it, this prevents most cases where
-    # signal propagation seems to sometimes not make it to "pm".
-    # TODO(drees) This can be combined with the `fx serve` call later to reduce ssh calls.
-    if ssh "${host}" "${ssh_base_args[@]}" "ss -ln | grep :${package_server_port}" > /dev/null; then
-      ssh "${ssh_base_args[@]}" "${host}" 'pkill -x -u $USER pm' || true
-    fi
+    fx-error "Invoking pm on a remote host via fx serve-remote is no longer supported."
+    fx-error "To resolve your issue, please migrate to the ffx foreground server:"
+    fx-error ""
+    fx-error "On both the local and remote host, ensure your shell does *not* export"
+    fx-error "the environment variable:"
+    fx-error "FUCHSIA_DISABLED_foreground_repo_server"
+    fx-error ""
+    fx-error "On both the local and remote host, migrate to ffx foreground serving:"
+    fx-error ""
+    fx-error "$ ffx config remove repository.server.mode"
+    fx-error "$ ffx config remove repository.server.enabled"
+    fx-error "$ ffx doctor --restart-daemon"
+    fx-error ""
+    fx-error "Then restart \"fx serve-remote\" <your parameters> on the local host."
+    exit 1
   else
     # Check if the remote repository server is running on a different port.
     # FIXME(https://fxbug.dev/42071440): Remove the `ffx_repository=true` once this command is stable.
diff --git a/tools/devshell/sync-to b/tools/devshell/sync-to
index 6227da7..4c8fa53 100755
--- a/tools/devshell/sync-to
+++ b/tools/devshell/sync-to
@@ -142,6 +142,8 @@
         self.state: str = args.state
         self.dry_run: bool = args.dry_run
         self.force: bool = args.force
+        self.verbose: bool = args.verbose
+        self.jiri_update_extra_args: list[str] = ["-v"] if self.verbose else []
 
     @property
     def integration_dir(self) -> pathlib.Path:
@@ -248,7 +250,7 @@
         # checkout prior to syncing and have `reset` restore the exact contents
         # of the old checkout instead of always going back to JIRI_HEAD.
         print("Resetting the tree to the latest...")
-        self.jiri("update", "-gc")
+        self.jiri("update", "-gc", *self.jiri_update_extra_args)
 
     def sync_to_release_branch(self) -> None:
         print(f"{self.state!r} looks like a branch name")
@@ -317,7 +319,13 @@
         self.set_baseline()
 
         print(f"Syncing to Jiri snapshot {str(snapshot_file)!r}")
-        self.jiri("update", "-local-manifest", "-gc", snapshot_file)
+        self.jiri(
+            "update",
+            "-local-manifest",
+            "-gc",
+            snapshot_file,
+            *self.jiri_update_extra_args,
+        )
 
     def sync_to_integration_ref(self, ref: str) -> None:
         """Sync to a branch, tag, or revision of the integration repo."""
@@ -341,7 +349,9 @@
             ref,
         )
         try:
-            self.jiri("update", "-local-manifest", "-gc")
+            self.jiri(
+                "update", "-local-manifest", "-gc", *self.jiri_update_extra_args
+            )
         except subprocess.CalledProcessError:
             print("Sync failed, restoring the integration repo to JIRI_HEAD")
             self.run_command(
@@ -504,7 +514,13 @@
         # If we patched in a change to the integration repo, we have to `jiri
         # update` again to make sure we respect any project/package pin updates.
         if has_integration_patch:
-            self.jiri("update", "-local-manifest", "-rebase-tracked", "-gc")
+            self.jiri(
+                "update",
+                "-local-manifest",
+                "-rebase-tracked",
+                "-gc",
+                *self.jiri_update_extra_args,
+            )
 
     def sync_to_legacy_build_id(self, build_id: str) -> None:
         """Sync to a build's Jiri snapshot from GCS.
@@ -760,6 +776,7 @@
     parser.add_argument("-h", "--help", action="store_true")
     parser.add_argument("-n", "--dry-run", dest="dry_run", action="store_true")
     parser.add_argument("-f", "--force", dest="force", action="store_true")
+    parser.add_argument("-v", "--verbose", dest="verbose", action="store_true")
     parser.add_argument("state", nargs="?", default="")
     return parser.parse_args()
 
diff --git a/tools/devshell/test b/tools/devshell/test
index 0cbf8c5..b2a464c 100755
--- a/tools/devshell/test
+++ b/tools/devshell/test
@@ -76,13 +76,6 @@
 
 args=()
 
-# TODO(https://fxbug.dev/42130661): Using tput colors is more reliable than letting Dart do its
-# own terminal detection. Remove once Dart can do its own detection more
-# robustly.
-if [[ ! -t 1 ]] || ! tput colors >/dev/null 2>&1; then
-  args+=("--simple")
-fi
-
 if is_feature_enabled "legacy_fxtest"; then
   run-dart-tool fxtest "${args[@]}" "$@"
 else
diff --git a/tools/devshell/tests/subcommands/data/fx_test_test/tests_multiple_in_package.json b/tools/devshell/tests/subcommands/data/fx_test_test/tests_multiple_in_package.json
index 0fe4457..393b9f7 100644
--- a/tools/devshell/tests/subcommands/data/fx_test_test/tests_multiple_in_package.json
+++ b/tools/devshell/tests/subcommands/data/fx_test_test/tests_multiple_in_package.json
@@ -8,8 +8,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "baz_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/baz_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/baz_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/baz_fuzzer_test.cm"
     }
   },
   {
@@ -21,8 +20,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "overflow_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/overflow_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/overflow_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/overflow_fuzzer_test.cm"
     }
   },
   {
@@ -34,8 +32,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "trap_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/trap_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/trap_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/trap_fuzzer_test.cm"
     }
   },
   {
@@ -47,8 +44,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "fuzzed_data_provider_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/fuzzed_data_provider_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/fuzzed_data_provider_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/fuzzed_data_provider_fuzzer_test.cm"
     }
   },
   {
@@ -60,8 +56,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "corpus_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/corpus_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/corpus_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/corpus_fuzzer_test.cm"
     }
   },
   {
@@ -73,8 +68,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "oom_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/oom_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/oom_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/oom_fuzzer_test.cm"
     }
   },
   {
@@ -86,8 +80,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "rust_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/rust_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/rust_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/rust_fuzzer_test.cm"
     }
   }
 ]
diff --git a/tools/devshell/tests/subcommands/data/fx_test_test/tests_package_server_integration.json b/tools/devshell/tests/subcommands/data/fx_test_test/tests_package_server_integration.json
index 0fe4457..393b9f7 100644
--- a/tools/devshell/tests/subcommands/data/fx_test_test/tests_package_server_integration.json
+++ b/tools/devshell/tests/subcommands/data/fx_test_test/tests_package_server_integration.json
@@ -8,8 +8,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "baz_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/baz_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/baz_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/baz_fuzzer_test.cm"
     }
   },
   {
@@ -21,8 +20,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "overflow_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/overflow_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/overflow_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/overflow_fuzzer_test.cm"
     }
   },
   {
@@ -34,8 +32,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "trap_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/trap_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/trap_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/trap_fuzzer_test.cm"
     }
   },
   {
@@ -47,8 +44,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "fuzzed_data_provider_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/fuzzed_data_provider_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/fuzzed_data_provider_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/fuzzed_data_provider_fuzzer_test.cm"
     }
   },
   {
@@ -60,8 +56,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "corpus_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/corpus_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/corpus_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/corpus_fuzzer_test.cm"
     }
   },
   {
@@ -73,8 +68,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "oom_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/oom_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/oom_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/oom_fuzzer_test.cm"
     }
   },
   {
@@ -86,8 +80,7 @@
       "label": "//examples/fuzzer:example_fuzzers_pkg(//build/toolchain/fuchsia:arm64)",
       "name": "rust_fuzzer_test",
       "os": "fuchsia",
-      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/rust_fuzzer_test.cm",
-      "path": "/pkgfs/packages/example_fuzzers/0/test/rust_fuzzer_test"
+      "package_url": "fuchsia-pkg://fuchsia.com/example_fuzzers#meta/rust_fuzzer_test.cm"
     }
   }
 ]
diff --git a/tools/emulator/emulatortest/emulatortest.go b/tools/emulator/emulatortest/emulatortest.go
index a1b9656..a43a76f 100644
--- a/tools/emulator/emulatortest/emulatortest.go
+++ b/tools/emulator/emulatortest/emulatortest.go
@@ -37,6 +37,20 @@
 }
 
 // Creates reimplements emulator.Distribution.
+func (d *Distribution) CreateContextWithAuthorizedKeys(ctx context.Context, fvd *fvdpb.VirtualDevice, hostPathZbiBinary, hostPathAuthorizedKeys string) *Instance {
+	i, err := d.d.CreateContextWithAuthorizedKeys(ctx, fvd, hostPathZbiBinary, hostPathAuthorizedKeys)
+	if err != nil {
+		d.t.Fatal(err)
+	}
+	d.t.Cleanup(func() {
+		if err := d.d.Delete(); err != nil {
+			d.t.Error(err)
+		}
+	})
+	return &Instance{i, d.t}
+}
+
+// Creates reimplements emulator.Distribution.
 func (d *Distribution) CreateContext(ctx context.Context, fvd *fvdpb.VirtualDevice) *Instance {
 	i, err := d.d.CreateContext(ctx, fvd)
 	if err != nil {
diff --git a/tools/fidl/fidlc/BUILD.gn b/tools/fidl/fidlc/BUILD.gn
index 8cb6336..bff72ab 100644
--- a/tools/fidl/fidlc/BUILD.gn
+++ b/tools/fidl/fidlc/BUILD.gn
@@ -28,7 +28,6 @@
     "src/linting_tree_callbacks.cc",
     "src/name.cc",
     "src/names.cc",
-    "src/ordinals.cc",
     "src/parser.cc",
     "src/raw_ast.cc",
     "src/reference.cc",
diff --git a/tools/fidl/fidlc/cmd/fidl-format/main.cc b/tools/fidl/fidlc/cmd/fidl-format/main.cc
index a7eba7a..72fd62c 100644
--- a/tools/fidl/fidlc/cmd/fidl-format/main.cc
+++ b/tools/fidl/fidlc/cmd/fidl-format/main.cc
@@ -65,7 +65,7 @@
   output = result.value();
 
   std::string source_file_str(source_file.data());
-  if (!fidlc::OnlyWhitespaceChanged(source_file_str, output)) {
+  if (fidlc::RemoveWhitespace(source_file_str) != fidlc::RemoveWhitespace(output)) {
     // Note that this is only useful as long as we do not have the formatter do
     // things that affect non-whitespace characters, like sort using statements
     // or coalesce consts into const blocks.  If / when this happens, this check
diff --git a/tools/fidl/fidlc/cmd/fidlc/main.cc b/tools/fidl/fidlc/cmd/fidlc/main.cc
index 3a334cd..02cb4fc 100644
--- a/tools/fidl/fidlc/cmd/fidlc/main.cc
+++ b/tools/fidl/fidlc/cmd/fidlc/main.cc
@@ -27,8 +27,6 @@
 #include "tools/fidl/fidlc/src/json_generator.h"
 #include "tools/fidl/fidlc/src/json_schema.h"
 #include "tools/fidl/fidlc/src/lexer.h"
-#include "tools/fidl/fidlc/src/names.h"
-#include "tools/fidl/fidlc/src/ordinals.h"
 #include "tools/fidl/fidlc/src/parser.h"
 #include "tools/fidl/fidlc/src/source_manager.h"
 #include "tools/fidl/fidlc/src/versioning_types.h"
@@ -41,7 +39,7 @@
 
 Usage: fidlc [--json JSON_PATH]
              [--available PLATFORM:VERSION]
-             [--platform PLATFORM]
+             [--versioned PLATFORM[:VERSION]]
              [--name LIBRARY_NAME]
              [--experimental FLAG_NAME]
              [--werror]
@@ -70,8 +68,9 @@
     PLATFORM corresponds to a library's `@available(platform="PLATFORM")` attribute,
     or to the library name's first component if the `platform` argument is omitted.
 
- * `--platform PLATFORM`. If present, this flag instructs `fidlc` to validate
-   that the main library being compiled is versioned under PLATFORM.
+ * `--versioned PLATFORM[:VERSION]`. If present, this flag instructs `fidlc` to
+   validate that the main library being compiled is versioned under PLATFORM.
+   If VERSION is provided, also validates that the library is added at VERSION.
    The library's platform is determined as follows:
     * If there are no `@available` attributes, the platform is "unversioned".
     * The platform can be explicit with `@available(platform="PLATFORM")`.
@@ -253,6 +252,25 @@
   std::unique_ptr<ResponseFileArguments> response_file_;
 };
 
+std::pair<fidlc::Platform, std::optional<fidlc::Version>> ParsePlatformAndVersion(
+    const std::string& arg) {
+  auto colon_idx = arg.find(':');
+  auto platform_str = arg.substr(0, colon_idx);
+  auto platform = fidlc::Platform::Parse(platform_str);
+  if (!platform.has_value())
+    FailWithUsage("Invalid platform name `%s`\n", platform_str.c_str());
+  std::optional<fidlc::Version> version;
+  if (colon_idx != std::string::npos) {
+    auto version_str = arg.substr(colon_idx + 1);
+    version = fidlc::Version::Parse(version_str);
+    if (!version.has_value())
+      FailWithUsage("Invalid version `%s`\n", version_str.c_str());
+    if (platform->is_unversioned())
+      FailWithUsage("Selecting a version for '%s' is not allowed\n", platform_str.c_str());
+  }
+  return {std::move(platform).value(), version};
+}
+
 enum struct Behavior {
   kJSON,
   kIndex,
@@ -300,6 +318,7 @@
 }  // namespace
 
 int compile(fidlc::Reporter* reporter, const std::optional<fidlc::Platform>& expected_platform,
+            std::optional<fidlc::Version> expected_version_added,
             const std::optional<std::string>& expected_library_name,
             const std::string& dep_file_path, const std::vector<std::string>& source_list,
             const std::vector<std::pair<Behavior, std::string>>& outputs,
@@ -312,7 +331,7 @@
     if (source_manager.sources().empty()) {
       continue;
     }
-    fidlc::Compiler compiler(&all_libraries, version_selection, fidlc::GetGeneratedOrdinal64,
+    fidlc::Compiler compiler(&all_libraries, version_selection, fidlc::Sha256MethodHasher,
                              experimental_flags);
     for (const auto& source_file : source_manager.sources()) {
       if (!Parse(*source_file, reporter, &compiler, experimental_flags)) {
@@ -348,14 +367,14 @@
       } else {
         library_names.append(", ");
       }
-      library_names.append(fidlc::NameLibrary(library->name));
+      library_names.append(library->name);
     }
     library_names.append("\n");
     Fail("Unused libraries provided via --files: %s", library_names.c_str());
   }
 
   auto compilation = all_libraries.Filter(version_selection);
-  auto library_name = fidlc::NameLibrary(compilation->library_name);
+  auto library_name = std::string(compilation->library_name);
 
   if (expected_library_name.has_value() && library_name != *expected_library_name) {
     Fail("Found `library %s;`, but expected `library %s;` based on the --name flag\n",
@@ -367,25 +386,37 @@
     auto& expected = expected_platform.value();
     if (actual != expected) {
       std::stringstream hint;
+      auto version = expected_version_added.value_or(fidlc::Version::Head()).ToString();
       if (expected.is_unversioned()) {
         hint << "try removing @available attributes";
       } else if (actual.is_unversioned()) {
-        if (compilation->library_name[0] == expected.name()) {
-          hint << "try adding `@available(added=HEAD)` on the `library` declaration";
+        if (fidlc::FirstComponent(compilation->library_name) == expected.name()) {
+          hint << "try adding `@available(added=" << version << ")` on the `library` declaration";
         } else {
-          hint << "try adding `@available(platform=\"" << expected.name()
-               << "\", added=HEAD)` on the `library` declaration";
+          hint << "try adding `@available(platform=\"" << expected.name() << "\", added=" << version
+               << ")` on the `library` declaration";
         }
       } else {
         hint << "try changing the library name to start with '" << expected.name()
-             << ".', or use `@available(platform=\"" << expected.name() << "\")`";
+             << ".', or use `@available(platform=\"" << expected.name() << "\", added=" << version
+             << ")`";
       }
       Fail(
           "Library '%s' is versioned under platform '%s', but expected platform '%s' based on the "
-          "--platform flag; %s\n",
+          "--versioned flag; %s\n",
           library_name.c_str(), actual.name().c_str(), expected.name().c_str(), hint.str().c_str());
     }
   }
+  if (expected_version_added.has_value()) {
+    auto& actual = compilation->version_added;
+    auto& expected = expected_version_added.value();
+    if (actual != expected) {
+      Fail(
+          "Library '%s' is marked @available(added=%s), but expected @available(added=%s) based on "
+          "the --versioned flag\n",
+          library_name.c_str(), actual.ToString().c_str(), expected.ToString().c_str());
+    }
+  }
 
   // Write depfile, with format:
   // output1 : inputA inputB inputC
@@ -436,6 +467,7 @@
   }
 
   std::optional<fidlc::Platform> expected_platform;
+  std::optional<fidlc::Version> expected_version_added;
   std::optional<std::string> expected_library_name;
 
   std::string dep_file_path;
@@ -448,74 +480,52 @@
   fidlc::ExperimentalFlagSet experimental_flags;
   while (args->Remaining()) {
     // Try to parse an output type.
-    std::string behavior_argument = args->Claim();
-    if (behavior_argument == "--help") {
+    std::string flag = args->Claim();
+    if (flag == "--help") {
       Usage();
       exit(0);
-    } else if (behavior_argument == "--json-schema") {
+    } else if (flag == "--json-schema") {
       PrintJsonSchema();
       exit(0);
-    } else if (behavior_argument == "--werror") {
+    } else if (flag == "--werror") {
       warnings_as_errors = true;
-    } else if (behavior_argument.rfind("--format") == 0) {
-      const auto equals = behavior_argument.rfind('=');
+    } else if (flag.rfind("--format") == 0) {
+      const auto equals = flag.rfind('=');
       if (equals == std::string::npos) {
         FailWithUsage("Unknown value for flag `format`\n");
       }
-      const auto format_value = behavior_argument.substr(equals + 1, behavior_argument.length());
+      const auto format_value = flag.substr(equals + 1, flag.length());
       if (format_value != "text" && format_value != "json") {
         FailWithUsage("Unknown value `%s` for flag `format`\n", format_value.c_str());
       }
       format = format_value;
-    } else if (behavior_argument == "--json") {
+    } else if (flag == "--json") {
       std::string path = args->Claim();
       json_path = path;
       outputs.emplace_back(Behavior::kJSON, path);
-    } else if (behavior_argument == "--available") {
-      std::string selection = args->Claim();
-      const auto colon_idx = selection.find(':');
-      if (colon_idx == std::string::npos) {
-        FailWithUsage("Invalid value `%s` for flag `available`\n", selection.c_str());
-      }
-      const auto platform_str = selection.substr(0, colon_idx);
-      const auto version_str = selection.substr(colon_idx + 1);
-      const auto platform = fidlc::Platform::Parse(platform_str);
-      const auto version = fidlc::Version::Parse(version_str);
-      if (!platform.has_value()) {
-        FailWithUsage("Invalid platform name `%s`\n", platform_str.c_str());
-      }
-      if (!version.has_value()) {
-        FailWithUsage("Invalid version `%s`\n", version_str.c_str());
-      }
-      if (platform->is_unversioned()) {
-        FailWithUsage(
-            "Invalid flag `--available %s:%s`; selecting a version for '%s' is not allowed\n",
-            platform_str.c_str(), version_str.c_str(), platform_str.c_str());
-      }
-      version_selection.Insert(platform.value(), version.value());
-    } else if (behavior_argument == "--platform") {
-      const auto platform_str = args->Claim();
-      const auto platform = fidlc::Platform::Parse(platform_str);
-      if (!platform.has_value()) {
-        FailWithUsage("Invalid platform name `%s`\n", platform_str.c_str());
-      }
-      expected_platform = platform.value();
-    } else if (behavior_argument == "--name") {
+    } else if (flag == "--available") {
+      auto [platform, version] = ParsePlatformAndVersion(args->Claim());
+      if (!version.has_value())
+        FailWithUsage("Missing version for flag `available`\n");
+      version_selection.Insert(platform, version.value());
+    } else if (flag == "--versioned") {
+      std::tie(expected_platform, expected_version_added) = ParsePlatformAndVersion(args->Claim());
+    } else if (flag == "--name") {
       expected_library_name = args->Claim();
-    } else if (behavior_argument == "--experimental") {
+    } else if (flag == "--experimental") {
       std::string string = args->Claim();
       auto it = fidlc::kAllExperimentalFlags.find(string);
       if (it == fidlc::kAllExperimentalFlags.end()) {
         FailWithUsage("Unknown experimental flag %s\n", string.c_str());
       }
       experimental_flags.Enable(it->second);
-    } else if (behavior_argument == "--depfile") {
+    } else if (flag == "--depfile") {
       dep_file_path = args->Claim();
-    } else if (behavior_argument == "--files") {
+    } else if (flag == "--files") {
       // Start parsing filenames.
       break;
     } else {
-      FailWithUsage("Unknown argument: %s\n", behavior_argument.c_str());
+      FailWithUsage("Unknown argument: %s\n", flag.c_str());
     }
   }
 
@@ -544,9 +554,9 @@
   fidlc::Reporter reporter;
   fidlc::VirtualSourceFile virtual_file("generated");
   reporter.set_warnings_as_errors(warnings_as_errors);
-  auto status =
-      compile(&reporter, expected_platform, expected_library_name, dep_file_path, source_list,
-              outputs, source_managers, &virtual_file, &version_selection, experimental_flags);
+  auto status = compile(&reporter, expected_platform, expected_version_added, expected_library_name,
+                        dep_file_path, source_list, outputs, source_managers, &virtual_file,
+                        &version_selection, experimental_flags);
   if (format == "json") {
     reporter.PrintReportsJson();
   } else {
diff --git a/tools/fidl/fidlc/goldens/aliases.index.json.golden b/tools/fidl/fidlc/goldens/aliases.index.json.golden
index fa5cca8..67b8e66 100644
--- a/tools/fidl/fidlc/goldens/aliases.index.json.golden
+++ b/tools/fidl/fidlc/goldens/aliases.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/aliases/someotherlibrary.test.fidl",
-        "data": "library test.someotherlibrary",
-        "start_offset": 0,
+        "data": "test.someotherlibrary",
+        "start_offset": 8,
         "end_offset": 29
       }
     }
diff --git a/tools/fidl/fidlc/goldens/bindings_denylist.index.json.golden b/tools/fidl/fidlc/goldens/bindings_denylist.index.json.golden
index dd3f124..12a8f55 100644
--- a/tools/fidl/fidlc/goldens/bindings_denylist.index.json.golden
+++ b/tools/fidl/fidlc/goldens/bindings_denylist.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/bindings_denylist/dependent.test.fidl",
-        "data": "library test.dependent",
-        "start_offset": 0,
+        "data": "test.dependent",
+        "start_offset": 8,
         "end_offset": 22
       }
     }
diff --git a/tools/fidl/fidlc/goldens/consts.index.json.golden b/tools/fidl/fidlc/goldens/consts.index.json.golden
index 6f755c3..2994e3c 100644
--- a/tools/fidl/fidlc/goldens/consts.index.json.golden
+++ b/tools/fidl/fidlc/goldens/consts.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../zircon/vdso/overview.fidl",
-        "data": "@available(platform=\"fuchsia\", added=7)\nlibrary zx",
-        "start_offset": 164,
+        "data": "zx",
+        "start_offset": 212,
         "end_offset": 214
       }
     }
diff --git a/tools/fidl/fidlc/goldens/driver_handle.index.json.golden b/tools/fidl/fidlc/goldens/driver_handle.index.json.golden
index 957b9fa..cace5db 100644
--- a/tools/fidl/fidlc/goldens/driver_handle.index.json.golden
+++ b/tools/fidl/fidlc/goldens/driver_handle.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../zircon/vdso/overview.fidl",
-        "data": "@available(platform=\"fuchsia\", added=7)\nlibrary zx",
-        "start_offset": 164,
+        "data": "zx",
+        "start_offset": 212,
         "end_offset": 214
       }
     }
diff --git a/tools/fidl/fidlc/goldens/encapsulated_structs.index.json.golden b/tools/fidl/fidlc/goldens/encapsulated_structs.index.json.golden
index 421aa87..8f90555 100644
--- a/tools/fidl/fidlc/goldens/encapsulated_structs.index.json.golden
+++ b/tools/fidl/fidlc/goldens/encapsulated_structs.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../zircon/vdso/overview.fidl",
-        "data": "@available(platform=\"fuchsia\", added=7)\nlibrary zx",
-        "start_offset": 164,
+        "data": "zx",
+        "start_offset": 212,
         "end_offset": 214
       }
     }
diff --git a/tools/fidl/fidlc/goldens/error_syntax.index.json.golden b/tools/fidl/fidlc/goldens/error_syntax.index.json.golden
index ec6cb5b..bdd98fb 100644
--- a/tools/fidl/fidlc/goldens/error_syntax.index.json.golden
+++ b/tools/fidl/fidlc/goldens/error_syntax.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/error_syntax/parent.test.fidl",
-        "data": "library test.errorsyntax.parent",
-        "start_offset": 165,
+        "data": "test.errorsyntax.parent",
+        "start_offset": 173,
         "end_offset": 196
       }
     }
diff --git a/tools/fidl/fidlc/goldens/foreign_type_in_response_used_through_compose.index.json.golden b/tools/fidl/fidlc/goldens/foreign_type_in_response_used_through_compose.index.json.golden
index 8fc6fe9..3e1ed2b 100644
--- a/tools/fidl/fidlc/goldens/foreign_type_in_response_used_through_compose.index.json.golden
+++ b/tools/fidl/fidlc/goldens/foreign_type_in_response_used_through_compose.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/foreign_type_in_response_used_through_compose/bottom.test.fidl",
-        "data": "library test.bottom",
-        "start_offset": 0,
+        "data": "test.bottom",
+        "start_offset": 8,
         "end_offset": 19
       }
     },
@@ -37,8 +37,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/foreign_type_in_response_used_through_compose/middle.test.fidl",
-        "data": "library test.middle",
-        "start_offset": 0,
+        "data": "test.middle",
+        "start_offset": 8,
         "end_offset": 19
       }
     }
diff --git a/tools/fidl/fidlc/goldens/handles.index.json.golden b/tools/fidl/fidlc/goldens/handles.index.json.golden
index 9c4d8d9..5a995aa 100644
--- a/tools/fidl/fidlc/goldens/handles.index.json.golden
+++ b/tools/fidl/fidlc/goldens/handles.index.json.golden
@@ -37,8 +37,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../sdk/fidl/fdf/handle.fidl",
-        "data": "library fdf",
-        "start_offset": 164,
+        "data": "fdf",
+        "start_offset": 172,
         "end_offset": 175
       }
     },
@@ -47,8 +47,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../zircon/vdso/overview.fidl",
-        "data": "@available(platform=\"fuchsia\", added=7)\nlibrary zx",
-        "start_offset": 164,
+        "data": "zx",
+        "start_offset": 212,
         "end_offset": 214
       }
     }
diff --git a/tools/fidl/fidlc/goldens/imported_const_values.index.json.golden b/tools/fidl/fidlc/goldens/imported_const_values.index.json.golden
index 835088e..a71d629 100644
--- a/tools/fidl/fidlc/goldens/imported_const_values.index.json.golden
+++ b/tools/fidl/fidlc/goldens/imported_const_values.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/imported_const_values/dependent.test.fidl",
-        "data": "library test.dependent",
-        "start_offset": 0,
+        "data": "test.dependent",
+        "start_offset": 8,
         "end_offset": 22
       }
     }
diff --git a/tools/fidl/fidlc/goldens/nullable.index.json.golden b/tools/fidl/fidlc/goldens/nullable.index.json.golden
index bd1c11c..a61933a 100644
--- a/tools/fidl/fidlc/goldens/nullable.index.json.golden
+++ b/tools/fidl/fidlc/goldens/nullable.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../zircon/vdso/overview.fidl",
-        "data": "@available(platform=\"fuchsia\", added=7)\nlibrary zx",
-        "start_offset": 164,
+        "data": "zx",
+        "start_offset": 212,
         "end_offset": 214
       }
     }
diff --git a/tools/fidl/fidlc/goldens/placement_of_attributes.index.json.golden b/tools/fidl/fidlc/goldens/placement_of_attributes.index.json.golden
index 7e1f719..2ec49ba 100644
--- a/tools/fidl/fidlc/goldens/placement_of_attributes.index.json.golden
+++ b/tools/fidl/fidlc/goldens/placement_of_attributes.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/placement_of_attributes/exampleusing.test.fidl",
-        "data": "library test.exampleusing",
-        "start_offset": 0,
+        "data": "test.exampleusing",
+        "start_offset": 8,
         "end_offset": 25
       }
     }
diff --git a/tools/fidl/fidlc/goldens/protocol_layouts.index.json.golden b/tools/fidl/fidlc/goldens/protocol_layouts.index.json.golden
index e740eb4..6b039cb 100644
--- a/tools/fidl/fidlc/goldens/protocol_layouts.index.json.golden
+++ b/tools/fidl/fidlc/goldens/protocol_layouts.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/protocol_layouts/imported.test.fidl",
-        "data": "library test.protocollayouts.imported",
-        "start_offset": 0,
+        "data": "test.protocollayouts.imported",
+        "start_offset": 8,
         "end_offset": 37
       }
     }
diff --git a/tools/fidl/fidlc/goldens/protocol_payloads.index.json.golden b/tools/fidl/fidlc/goldens/protocol_payloads.index.json.golden
index 3aec7bf..8dbfc85 100644
--- a/tools/fidl/fidlc/goldens/protocol_payloads.index.json.golden
+++ b/tools/fidl/fidlc/goldens/protocol_payloads.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/protocol_payloads/imported.test.fidl",
-        "data": "library test.protocolpayloads.imported",
-        "start_offset": 0,
+        "data": "test.protocolpayloads.imported",
+        "start_offset": 8,
         "end_offset": 38
       }
     }
diff --git a/tools/fidl/fidlc/goldens/protocols.index.json.golden b/tools/fidl/fidlc/goldens/protocols.index.json.golden
index 12ff25a..48081a0 100644
--- a/tools/fidl/fidlc/goldens/protocols.index.json.golden
+++ b/tools/fidl/fidlc/goldens/protocols.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../zircon/vdso/overview.fidl",
-        "data": "@available(platform=\"fuchsia\", added=7)\nlibrary zx",
-        "start_offset": 164,
+        "data": "zx",
+        "start_offset": 212,
         "end_offset": 214
       }
     }
diff --git a/tools/fidl/fidlc/goldens/struct_default_value_enum_library_reference.index.json.golden b/tools/fidl/fidlc/goldens/struct_default_value_enum_library_reference.index.json.golden
index dae1a12..5814083 100644
--- a/tools/fidl/fidlc/goldens/struct_default_value_enum_library_reference.index.json.golden
+++ b/tools/fidl/fidlc/goldens/struct_default_value_enum_library_reference.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/struct_default_value_enum_library_reference/dependent.test.fidl",
-        "data": "library test.dependent",
-        "start_offset": 0,
+        "data": "test.dependent",
+        "start_offset": 8,
         "end_offset": 22
       }
     }
diff --git a/tools/fidl/fidlc/goldens/transitive_dependencies.index.json.golden b/tools/fidl/fidlc/goldens/transitive_dependencies.index.json.golden
index e97676d..2df1bb2 100644
--- a/tools/fidl/fidlc/goldens/transitive_dependencies.index.json.golden
+++ b/tools/fidl/fidlc/goldens/transitive_dependencies.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/transitive_dependencies/middle.test.fidl",
-        "data": "library test.middle",
-        "start_offset": 0,
+        "data": "test.middle",
+        "start_offset": 8,
         "end_offset": 19
       }
     }
diff --git a/tools/fidl/fidlc/goldens/transitive_dependencies_compose.index.json.golden b/tools/fidl/fidlc/goldens/transitive_dependencies_compose.index.json.golden
index 1b32693..3f1d18c 100644
--- a/tools/fidl/fidlc/goldens/transitive_dependencies_compose.index.json.golden
+++ b/tools/fidl/fidlc/goldens/transitive_dependencies_compose.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/transitive_dependencies_compose/bottom.test.fidl",
-        "data": "library test.bottom",
-        "start_offset": 0,
+        "data": "test.bottom",
+        "start_offset": 8,
         "end_offset": 19
       }
     },
@@ -37,8 +37,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../tools/fidl/fidlc/testdata/transitive_dependencies_compose/middle.test.fidl",
-        "data": "library test.middle",
-        "start_offset": 0,
+        "data": "test.middle",
+        "start_offset": 8,
         "end_offset": 19
       }
     }
diff --git a/tools/fidl/fidlc/goldens/types_in_protocols.index.json.golden b/tools/fidl/fidlc/goldens/types_in_protocols.index.json.golden
index 9db0ecc..69125c6 100644
--- a/tools/fidl/fidlc/goldens/types_in_protocols.index.json.golden
+++ b/tools/fidl/fidlc/goldens/types_in_protocols.index.json.golden
@@ -27,8 +27,8 @@
       "library_location": {
         "is_virtual": false,
         "file": "../../zircon/vdso/overview.fidl",
-        "data": "@available(platform=\"fuchsia\", added=7)\nlibrary zx",
-        "start_offset": 164,
+        "data": "zx",
+        "start_offset": 212,
         "end_offset": 214
       }
     }
diff --git a/tools/fidl/fidlc/src/attribute_schema.cc b/tools/fidl/fidlc/src/attribute_schema.cc
index 4f10327..554136d 100644
--- a/tools/fidl/fidlc/src/attribute_schema.cc
+++ b/tools/fidl/fidlc/src/attribute_schema.cc
@@ -213,14 +213,7 @@
 }
 
 static bool RefersToHead(const std::vector<std::string_view>& components, const Decl* head_decl) {
-  auto head_name = head_decl->name.decl_name();
-  if (components.size() == 1 && components[0] == head_name) {
-    return true;
-  }
-  auto& library_name = head_decl->name.library()->name;
-  return components.size() == library_name.size() + 1 &&
-         std::equal(library_name.begin(), library_name.end(), components.begin()) &&
-         components.back() == head_name;
+  return components.size() == 1 && components[0] == head_decl->name.decl_name();
 }
 
 bool AttributeArgSchema::TryResolveAsHead(CompileStep* step, Reference& reference) const {
@@ -393,7 +386,7 @@
     return true;
   }
   ZX_ASSERT(arg->value->Value().kind == ConstantValue::Kind::kString);
-  auto name = static_cast<const StringConstantValue&>(arg->value->Value()).MakeContents();
+  auto name = static_cast<const StringConstantValue&>(arg->value->Value()).value;
   if (!IsValidDiscoverableName(name)) {
     return reporter->Fail(ErrInvalidDiscoverableName, arg->span, name);
   }
@@ -406,9 +399,8 @@
   ZX_ASSERT(element->kind == Element::Kind::kProtocol);
 
   auto arg = attribute->GetArg(AttributeArg::kDefaultAnonymousName);
-  auto& arg_value = static_cast<const StringConstantValue&>(arg->value->Value());
+  auto value = static_cast<const StringConstantValue&>(arg->value->Value()).value;
 
-  const std::string& value = arg_value.MakeContents();
   if (!Transport::FromTransportName(value)) {
     return reporter->Fail(ErrInvalidTransportType, attribute->span, value,
                           Transport::AllTransportNames());
diff --git a/tools/fidl/fidlc/src/attributes.cc b/tools/fidl/fidlc/src/attributes.cc
index 286a84c..cac864b 100644
--- a/tools/fidl/fidlc/src/attributes.cc
+++ b/tools/fidl/fidlc/src/attributes.cc
@@ -15,7 +15,7 @@
 }
 
 const AttributeArg* Attribute::GetArg(std::string_view arg_name) const {
-  std::string name = canonicalize(arg_name);
+  std::string name = Canonicalize(arg_name);
   for (const auto& arg : args) {
     if (arg->name && arg->name.value().data() == name) {
       return arg.get();
diff --git a/tools/fidl/fidlc/src/availability_step.cc b/tools/fidl/fidlc/src/availability_step.cc
index e17c0e2..2893883 100644
--- a/tools/fidl/fidlc/src/availability_step.cc
+++ b/tools/fidl/fidlc/src/availability_step.cc
@@ -180,8 +180,7 @@
     if (library_platform.is_unversioned()) {
       reporter()->Fail(ErrReservedPlatform, attribute->span, library_platform);
     } else if (!version_selection()->Contains(library_platform)) {
-      reporter()->Fail(ErrPlatformVersionNotSelected, attribute->span, library()->name,
-                       library_platform);
+      reporter()->Fail(ErrPlatformVersionNotSelected, attribute->span, library(), library_platform);
     }
     if (!init_args.added) {
       // Return early to avoid letting the -inf from Availability::Unbounded()
@@ -264,7 +263,7 @@
 }
 
 Platform AvailabilityStep::GetDefaultPlatform() {
-  auto platform = Platform::Parse(std::string(library()->name.front()));
+  auto platform = Platform::Parse(std::string(FirstComponent(library()->name)));
   ZX_ASSERT_MSG(platform, "library component should be valid platform");
   return platform.value();
 }
@@ -274,9 +273,8 @@
     return std::nullopt;
   }
   ZX_ASSERT(maybe_arg->value->Value().kind == ConstantValue::Kind::kString);
-  std::string str =
-      static_cast<const StringConstantValue*>(&maybe_arg->value->Value())->MakeContents();
-  auto platform = Platform::Parse(str);
+  auto str = static_cast<const StringConstantValue&>(maybe_arg->value->Value()).value;
+  auto platform = Platform::Parse(std::string(str));
   if (!platform) {
     reporter()->Fail(ErrInvalidPlatform, maybe_arg->value->span, str);
     return std::nullopt;
@@ -381,7 +379,7 @@
     auto set = element->availability.set();
     auto added = set.ranges().first.pair().first;
     auto name = element->GetName();
-    auto canonical_name = canonicalize(name);
+    auto canonical_name = Canonicalize(name);
     auto& same_canonical_name = by_canonical_name_[canonical_name];
     CheckForNameCollisions(element, set, name, canonical_name, same_canonical_name);
     same_canonical_name.insert(element);
diff --git a/tools/fidl/fidlc/src/compile_step.cc b/tools/fidl/fidlc/src/compile_step.cc
index 8f5b13d..e729692 100644
--- a/tools/fidl/fidlc/src/compile_step.cc
+++ b/tools/fidl/fidlc/src/compile_step.cc
@@ -14,8 +14,6 @@
 #include "tools/fidl/fidlc/src/experimental_flags.h"
 #include "tools/fidl/fidlc/src/flat_ast.h"
 #include "tools/fidl/fidlc/src/name.h"
-#include "tools/fidl/fidlc/src/names.h"
-#include "tools/fidl/fidlc/src/ordinals.h"
 #include "tools/fidl/fidlc/src/type_resolver.h"
 
 namespace fidlc {
@@ -398,14 +396,14 @@
       auto doc_comment_literal =
           static_cast<const RawDocCommentLiteral*>(literal_constant->literal);
       literal_constant->ResolveTo(
-          std::make_unique<DocCommentConstantValue>(doc_comment_literal->span().data()),
+          std::make_unique<DocCommentConstantValue>(doc_comment_literal->value),
           typespace()->GetUnboundedStringType());
       return true;
     }
     case RawLiteral::Kind::kString: {
-      literal_constant->ResolveTo(
-          std::make_unique<StringConstantValue>(literal_constant->literal->span().data()),
-          typespace()->GetUnboundedStringType());
+      auto string_literal = static_cast<const RawStringLiteral*>(literal_constant->literal);
+      literal_constant->ResolveTo(std::make_unique<StringConstantValue>(string_literal->value),
+                                  typespace()->GetUnboundedStringType());
       return true;
     }
     case RawLiteral::Kind::kBool: {
@@ -519,7 +517,7 @@
       switch (literal->kind) {
         case RawLiteral::Kind::kString: {
           auto string_literal = static_cast<const RawStringLiteral*>(literal);
-          auto inferred_size = string_literal_length(string_literal->span().data());
+          auto inferred_size = StringLiteralLength(string_literal->span().data());
           return typespace()->GetStringType(inferred_size);
         }
         case RawLiteral::Kind::kNumeric:
@@ -559,7 +557,7 @@
   Scope<std::string> scope;
   for (auto& attribute : attributes->attributes) {
     const auto original_name = attribute->name.data();
-    const auto canonical_name = canonicalize(original_name);
+    const auto canonical_name = Canonicalize(original_name);
     const auto result = scope.Insert(canonical_name, attribute->name);
     if (!result.ok()) {
       const auto previous_span = result.previous_occurrence();
@@ -585,7 +583,7 @@
       continue;
     }
     const auto original_name = arg->name.value().data();
-    const auto canonical_name = canonicalize(original_name);
+    const auto canonical_name = Canonicalize(original_name);
     const auto result = scope.Insert(canonical_name, arg->name.value());
     if (!result.ok()) {
       const auto previous_span = result.previous_occurrence();
@@ -930,13 +928,13 @@
   method->result_union = decl;
   for (auto& member : decl->members) {
     switch (member.ordinal->value) {
-      case kSuccessOrdinal:
+      case Protocol::Method::ResultUnionOrdinal::kSuccess:
         method->result_success_type_ctor = member.type_ctor.get();
         break;
-      case kDomainErrorOrdinal:
+      case Protocol::Method::ResultUnionOrdinal::kDomainError:
         method->result_domain_error_type_ctor = member.type_ctor.get();
         break;
-      case kFrameworkErrorOrdinal:
+      case Protocol::Method::ResultUnionOrdinal::kFrameworkError:
         break;
       default:
         ZX_PANIC("unexpected ordinal in result union");
@@ -964,7 +962,7 @@
     }
     for (auto& method : protocol->methods) {
       auto original_name = method.name.data();
-      auto canonical_name = canonicalize(original_name);
+      auto canonical_name = Canonicalize(original_name);
       if (auto result = canonical_names_.Insert(canonical_name, method.name); !result.ok()) {
         auto previous_span = result.previous_occurrence();
         if (original_name == previous_span.data()) {
@@ -976,9 +974,9 @@
                           previous_span, canonical_name);
         }
       }
-      if (auto& ordinal = method.generated_ordinal64) {
-        if (auto result = ordinals_.Insert(ordinal->value, method.name); !result.ok()) {
-          reporter_->Fail(ErrDuplicateMethodOrdinal, ordinal->span(), result.previous_occurrence());
+      if (method.ordinal != 0) {
+        if (auto result = ordinals_.Insert(method.ordinal, method.name); !result.ok()) {
+          reporter_->Fail(ErrDuplicateMethodOrdinal, method.name, result.previous_occurrence());
         }
       }
       original_protocol_->all_methods.push_back(
@@ -1042,26 +1040,41 @@
   PopulateAllMethods(protocol_declaration, reporter()).Run();
 }
 
-bool CompileStep::ValidateSelectorAndCalcOrdinal(const Name& protocol_name,
+void CompileStep::ValidateSelectorAndCalcOrdinal(const Name& protocol_name,
                                                  Protocol::Method* method) {
-  auto selector = GetSelector(method->attributes.get(), method->name);
-  if (!IsValidIdentifierComponent(selector) && !IsValidFullyQualifiedMethodIdentifier(selector)) {
-    return reporter()->Fail(
-        ErrInvalidSelectorValue,
-        method->attributes->Get("selector")->GetArg(AttributeArg::kDefaultAnonymousName)->span);
+  std::string selector;
+  std::string_view method_name = method->name.data();
+  if (auto attr = method->attributes->Get("selector")) {
+    if (auto arg = attr->GetArg(AttributeArg::kDefaultAnonymousName)) {
+      if (auto& constant = arg->value; constant && constant->IsResolved()) {
+        auto value = static_cast<const StringConstantValue&>(constant->Value()).value;
+        if (IsValidFullyQualifiedMethodIdentifier(value)) {
+          selector = value;
+        } else if (IsValidIdentifierComponent(value)) {
+          method_name = value;
+        } else {
+          reporter()->Fail(ErrInvalidSelectorValue, arg->span);
+          return;
+        }
+      }
+    }
   }
   // TODO(https://fxbug.dev/42157659): Remove.
-  auto library_name = library()->name;
-  if (library_name.size() == 2 && library_name[0] == "fuchsia" && library_name[1] == "io" &&
-      selector.find('/') == std::string::npos) {
-    return reporter()->Fail(ErrFuchsiaIoExplicitOrdinals, method->name);
+  if (selector.empty() && library()->name == "fuchsia.io") {
+    reporter()->Fail(ErrFuchsiaIoExplicitOrdinals, method->name);
+    return;
   }
-  auto ordinal = std::make_unique<RawOrdinal64>(
-      method_hasher()(library_name, protocol_name.decl_name(), selector, *method->identifier));
-  if (ordinal->value == 0)
-    return reporter()->Fail(ErrGeneratedZeroValueOrdinal, ordinal->span());
-  method->generated_ordinal64 = std::move(ordinal);
-  return true;
+  if (selector.empty()) {
+    selector.append(protocol_name.library()->name);
+    selector.push_back('/');
+    selector.append(protocol_name.decl_name());
+    selector.push_back('.');
+    selector.append(method_name);
+    ZX_ASSERT(IsValidFullyQualifiedMethodIdentifier(selector));
+  }
+  method->ordinal = method_hasher()(selector);
+  if (method->ordinal == 0)
+    reporter()->Fail(ErrGeneratedZeroValueOrdinal, method->name);
 }
 
 void CompileStep::ValidatePayload(const TypeConstructor* type_ctor) {
@@ -1183,9 +1196,9 @@
       const auto* default_value_type = member.type_ctor->type;
       if (!TypeCanBeConst(default_value_type)) {
         reporter()->Fail(ErrInvalidStructMemberType, struct_declaration->name.span().value(),
-                         NameIdentifier(member.name), default_value_type);
+                         member.name.data(), default_value_type);
       } else if (!ResolveConstant(member.maybe_default_value.get(), default_value_type)) {
-        reporter()->Fail(ErrCouldNotResolveMemberDefault, member.name, NameIdentifier(member.name));
+        reporter()->Fail(ErrCouldNotResolveMemberDefault, member.name, member.name.data());
       }
     }
   }
diff --git a/tools/fidl/fidlc/src/compile_step.h b/tools/fidl/fidlc/src/compile_step.h
index b2508f6..a9ed400 100644
--- a/tools/fidl/fidlc/src/compile_step.h
+++ b/tools/fidl/fidlc/src/compile_step.h
@@ -87,7 +87,7 @@
   bool ValidateBitsMembersAndCalcMask(Bits* bits_decl, MemberType* out_mask);
   template <typename MemberType>
   bool ValidateEnumMembersAndCalcUnknownValue(Enum* enum_decl, MemberType* out_unknown_value);
-  bool ValidateSelectorAndCalcOrdinal(const Name& protocol_name, Protocol::Method* method);
+  void ValidateSelectorAndCalcOrdinal(const Name& protocol_name, Protocol::Method* method);
   void ValidatePayload(const TypeConstructor* type_ctor);
   void ValidateDomainError(const TypeConstructor* type_ctor);
   template <typename DeclType>
diff --git a/tools/fidl/fidlc/src/compiler.cc b/tools/fidl/fidlc/src/compiler.cc
index 59257b0..139ff17 100644
--- a/tools/fidl/fidlc/src/compiler.cc
+++ b/tools/fidl/fidlc/src/compiler.cc
@@ -8,6 +8,9 @@
 
 #include <algorithm>
 
+#define BORINGSSL_NO_CXX
+#include <openssl/sha.h>
+
 #include "tools/fidl/fidlc/src/attribute_schema.h"
 #include "tools/fidl/fidlc/src/availability_step.h"
 #include "tools/fidl/fidlc/src/compile_step.h"
@@ -21,6 +24,25 @@
 
 namespace fidlc {
 
+uint64_t Sha256MethodHasher(std::string_view selector) {
+  uint8_t digest[SHA256_DIGEST_LENGTH];
+  SHA256(reinterpret_cast<const uint8_t*>(selector.data()), selector.size(), digest);
+  // The following dance ensures that we treat the bytes as a little-endian
+  // int64 regardless of host byte order.
+  // clang-format off
+  uint64_t ordinal =
+      static_cast<uint64_t>(digest[0]) |
+      static_cast<uint64_t>(digest[1]) << 8 |
+      static_cast<uint64_t>(digest[2]) << 16 |
+      static_cast<uint64_t>(digest[3]) << 24 |
+      static_cast<uint64_t>(digest[4]) << 32 |
+      static_cast<uint64_t>(digest[5]) << 40 |
+      static_cast<uint64_t>(digest[6]) << 48 |
+      static_cast<uint64_t>(digest[7]) << 56;
+  // clang-format on
+  return ordinal & 0x7fffffffffffffff;
+}
+
 Compiler::Compiler(Libraries* all_libraries, const VersionSelection* version_selection,
                    MethodHasher method_hasher, ExperimentalFlagSet experimental_flags)
     : reporter_(all_libraries->reporter()),
@@ -81,14 +103,13 @@
 bool Libraries::Insert(std::unique_ptr<Library> library) {
   auto [_, inserted] = libraries_by_name_.try_emplace(library->name, library.get());
   if (!inserted) {
-    return reporter_->Fail(ErrMultipleLibrariesWithSameName, library->arbitrary_name_span,
-                           library->name);
+    return reporter_->Fail(ErrMultipleLibrariesWithSameName, library->name_spans[0], library->name);
   }
   libraries_.push_back(std::move(library));
   return true;
 }
 
-Library* Libraries::Lookup(const std::vector<std::string_view>& library_name) const {
+Library* Libraries::Lookup(std::string_view library_name) const {
   auto iter = libraries_by_name_.find(library_name);
   return iter == libraries_by_name_.end() ? nullptr : iter->second;
 }
@@ -178,7 +199,7 @@
                                                   const std::vector<const Protocol*>& protocols) {
   // Ensure deterministic ordering.
   auto ordering = [](const Struct* a, const Struct* b) {
-    return NameFlatName(a->name) < NameFlatName(b->name);
+    return FullyQualifiedName(a->name) < FullyQualifiedName(b->name);
   };
   std::set<const Struct*, decltype(ordering)> external_structs(ordering);
 
@@ -429,8 +450,9 @@
   auto library = libraries_.back().get();
   auto compilation = std::make_unique<Compilation>();
   compilation->platform = &library->platform.value();
+  compilation->version_added = library->availability.set().ranges().first.pair().first;
   compilation->library_name = library->name;
-  compilation->library_declarations = library->library_name_declarations;
+  compilation->library_declarations = library->name_spans;
   compilation->library_attributes = library->attributes.get();
   filter_declarations(&compilation->declarations, library->declarations);
   compilation->external_structs = ExternalStructs(library, compilation->declarations.protocols);
diff --git a/tools/fidl/fidlc/src/compiler.h b/tools/fidl/fidlc/src/compiler.h
index 176b16f..3d0141a8 100644
--- a/tools/fidl/fidlc/src/compiler.h
+++ b/tools/fidl/fidlc/src/compiler.h
@@ -13,7 +13,6 @@
 #include "tools/fidl/fidlc/src/attribute_schema.h"
 #include "tools/fidl/fidlc/src/experimental_flags.h"
 #include "tools/fidl/fidlc/src/flat_ast.h"
-#include "tools/fidl/fidlc/src/ordinals.h"
 #include "tools/fidl/fidlc/src/reporter.h"
 #include "tools/fidl/fidlc/src/typespace.h"
 #include "tools/fidl/fidlc/src/versioning_types.h"
@@ -23,6 +22,9 @@
 
 class Libraries;
 
+using MethodHasher = uint64_t (*)(std::string_view);
+uint64_t Sha256MethodHasher(std::string_view selector);
+
 // Compiler consumes File ASTs and produces a compiled Library.
 class Compiler final {
  public:
@@ -57,7 +59,7 @@
     Typespace* typespace();
     VirtualSourceFile* generated_source_file();
     const VersionSelection* version_selection() { return compiler_->version_selection; }
-    const MethodHasher& method_hasher() { return compiler_->method_hasher_; }
+    MethodHasher method_hasher() { return compiler_->method_hasher_; }
     ExperimentalFlagSet experimental_flags() { return compiler_->experimental_flags_; }
 
     // Returns types that were created in the typespace while compiling this library.
@@ -108,7 +110,7 @@
   bool Insert(std::unique_ptr<Library> library);
 
   // Lookup a library by its |library_name|, or returns null if none is found.
-  Library* Lookup(const std::vector<std::string_view>& library_name) const;
+  Library* Lookup(std::string_view library_name) const;
 
   // Removes a library that was inserted before.
   //
@@ -149,7 +151,7 @@
   Reporter* reporter_;
   std::unique_ptr<Library> root_library_;
   std::vector<std::unique_ptr<Library>> libraries_;
-  std::map<std::vector<std::string_view>, Library*> libraries_by_name_;
+  std::map<std::string_view, Library*> libraries_by_name_;
   Typespace typespace_;
   AttributeSchemaMap attribute_schemas_;
 
@@ -187,9 +189,11 @@
 
   // The platform the library is versioned under.
   const Platform* platform;
+  // The version at which the library was added.
+  Version version_added = Version::Head();
   // The target library name and attributes. Note, we purposely do not store a
   // Library* to avoid accidentally reaching into its unfiltered decls.
-  std::vector<std::string_view> library_name;
+  std::string_view library_name;
   // Location where the target library is defined.
   std::vector<SourceSpan> library_declarations;
   // Stores all library references defined with using directives.
diff --git a/tools/fidl/fidlc/src/consume_step.cc b/tools/fidl/fidlc/src/consume_step.cc
index 2624e89..a789d9a 100644
--- a/tools/fidl/fidlc/src/consume_step.cc
+++ b/tools/fidl/fidlc/src/consume_step.cc
@@ -25,27 +25,13 @@
 
 void ConsumeStep::RunImpl() {
   // All fidl files in a library should agree on the library name.
-  std::vector<std::string_view> new_name;
-  for (const auto& part : file_->library_decl->path->components) {
-    new_name.push_back(part->span().data());
+  if (auto name = file_->library_decl->path->ToString(); library()->name.empty()) {
+    library()->name = std::move(name);
+  } else if (name != library()->name) {
+    reporter()->Fail(ErrFilesDisagreeOnLibraryName, file_->library_decl->path->span());
+    return;
   }
-  if (library()->name.empty()) {
-    library()->name = new_name;
-    library()->arbitrary_name_span = file_->library_decl->span();
-  } else {
-    if (new_name != library()->name) {
-      reporter()->Fail(ErrFilesDisagreeOnLibraryName,
-                       file_->library_decl->path->components[0]->span());
-      return;
-    }
-    // Prefer setting arbitrary_name_span to a file which has attributes on the
-    // library declaration, if any do, since it's conventional to put all
-    // library attributes and the doc comment in a single file (overview.fidl).
-    if (library()->attributes->Empty() && file_->library_decl->attributes) {
-      library()->arbitrary_name_span = file_->library_decl->span();
-    }
-  }
-  library()->library_name_declarations.emplace_back(file_->library_decl->path->span());
+  library()->name_spans.emplace_back(file_->library_decl->path->span());
 
   ConsumeAttributeList(std::move(file_->library_decl->attributes), &library()->attributes);
 
@@ -79,7 +65,7 @@
     if (library()->dependencies.Contains(name.span()->source_file().filename(),
                                          {name.span()->data()})) {
       reporter()->Fail(ErrDeclNameConflictsWithLibraryImport, name.span().value(), name);
-    } else if (auto canonical_decl_name = canonicalize(name.decl_name());
+    } else if (auto canonical_decl_name = Canonicalize(name.decl_name());
                library()->dependencies.Contains(name.span()->source_file().filename(),
                                                 {canonical_decl_name})) {
       reporter()->Fail(ErrDeclNameConflictsWithLibraryImportCanonical, name.span().value(), name,
@@ -192,15 +178,10 @@
     return;
   }
 
-  std::vector<std::string_view> library_name;
-  for (const auto& component : using_directive->using_path->components) {
-    library_name.push_back(component->span().data());
-  }
-
+  auto library_name = using_directive->using_path->ToString();
   Library* dep_library = all_libraries()->Lookup(library_name);
   if (!dep_library) {
-    reporter()->Fail(ErrUnknownLibrary, using_directive->using_path->components[0]->span(),
-                     library_name);
+    reporter()->Fail(ErrUnknownLibrary, using_directive->using_path->span(), library_name);
     return;
   }
 
@@ -283,8 +264,10 @@
   auto ordinal_source = SourceElement(Token(), Token());
   std::vector<Union::Member> result_members;
 
+  using Ordinal = Protocol::Method::ResultUnionOrdinal;
+
   result_members.emplace_back(
-      ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, kSuccessOrdinal)),
+      ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, Ordinal::kSuccess)),
       std::move(success_variant), success_variant_context->name(),
       std::make_unique<AttributeList>());
 
@@ -298,7 +281,7 @@
     ZX_ASSERT_MSG(error_type_ctor != nullptr, "missing err type ctor");
 
     result_members.emplace_back(
-        ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, kDomainErrorOrdinal)),
+        ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, Ordinal::kDomainError)),
         std::move(error_type_ctor), err_variant_context->name(), std::make_unique<AttributeList>());
   }
 
@@ -306,7 +289,7 @@
     std::unique_ptr<TypeConstructor> error_type_ctor = IdentifierTypeForDecl(framework_err_type_);
     ZX_ASSERT_MSG(error_type_ctor != nullptr, "missing framework_err type ctor");
     result_members.emplace_back(
-        ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, kFrameworkErrorOrdinal)),
+        ConsumeOrdinal(std::make_unique<RawOrdinal64>(ordinal_source, Ordinal::kFrameworkError)),
         std::move(error_type_ctor), framework_err_variant_context->name(),
         std::make_unique<AttributeList>());
   }
@@ -397,16 +380,15 @@
         // Note that although the success variant is named P_M_Response, in the
         // fidlc codebase we use the word "response" to refer to the outermost
         // type, which in this case is P_M_Result.
-        response_context->set_name_override(
-            StringJoin({protocol_name.decl_name(), method_name.data(), "Result"}, "_"));
+        auto prefix =
+            std::string(protocol_name.decl_name()) + "_" + std::string(method_name.data());
+        response_context->set_name_override(prefix + "_Result");
         success_variant_context =
             response_context->EnterMember(generated_source_file()->AddLine("response"));
-        success_variant_context->set_name_override(
-            StringJoin({protocol_name.decl_name(), method_name.data(), "Response"}, "_"));
+        success_variant_context->set_name_override(prefix + "_Response");
         err_variant_context =
             response_context->EnterMember(generated_source_file()->AddLine("err"));
-        err_variant_context->set_name_override(
-            StringJoin({protocol_name.decl_name(), method_name.data(), "Error"}, "_"));
+        err_variant_context->set_name_override(prefix + "_Error");
         framework_err_variant_context =
             response_context->EnterMember(generated_source_file()->AddLine("framework_err"));
 
@@ -436,8 +418,7 @@
       }
     }
     ZX_ASSERT(has_request || has_response);
-    methods.emplace_back(std::move(attributes), strictness,
-                         ConsumeIdentifier(std::move(method->identifier)), method_name, has_request,
+    methods.emplace_back(std::move(attributes), strictness, method_name, has_request,
                          std::move(maybe_request), has_response, std::move(maybe_response),
                          has_error);
   }
@@ -556,9 +537,9 @@
   }
   const ConstantValue& value = arg->value->Value();
   ZX_ASSERT(value.kind == ConstantValue::Kind::kString);
-  std::string str = static_cast<const StringConstantValue&>(value).MakeContents();
+  auto str = static_cast<const StringConstantValue&>(value).value;
   if (IsValidIdentifierComponent(str)) {
-    context->set_name_override(std::move(str));
+    context->set_name_override(std::string(str));
   } else {
     reporter()->Fail(ErrInvalidGeneratedName, arg->span);
   }
@@ -873,12 +854,6 @@
   return ptr;
 }
 
-const RawIdentifier* ConsumeStep::ConsumeIdentifier(std::unique_ptr<RawIdentifier> raw_identifier) {
-  auto ptr = raw_identifier.get();
-  library()->raw_identifiers.push_back(std::move(raw_identifier));
-  return ptr;
-}
-
 const RawOrdinal64* ConsumeStep::ConsumeOrdinal(std::unique_ptr<RawOrdinal64> raw_ordinal) {
   auto ptr = raw_ordinal.get();
   library()->raw_ordinals.push_back(std::move(raw_ordinal));
diff --git a/tools/fidl/fidlc/src/consume_step.h b/tools/fidl/fidlc/src/consume_step.h
index 55bb771..fe9b7e0 100644
--- a/tools/fidl/fidlc/src/consume_step.h
+++ b/tools/fidl/fidlc/src/consume_step.h
@@ -71,7 +71,6 @@
 
   // Elements stored in the library
   const RawLiteral* ConsumeLiteral(std::unique_ptr<RawLiteral> raw_literal);
-  const RawIdentifier* ConsumeIdentifier(std::unique_ptr<RawIdentifier> raw_identifier);
   const RawOrdinal64* ConsumeOrdinal(std::unique_ptr<RawOrdinal64> raw_ordinal);
 
   // Sets the naming context's generated name override to the @generated_name
diff --git a/tools/fidl/fidlc/src/diagnostic_types.cc b/tools/fidl/fidlc/src/diagnostic_types.cc
index f324c3a..2099c93 100644
--- a/tools/fidl/fidlc/src/diagnostic_types.cc
+++ b/tools/fidl/fidlc/src/diagnostic_types.cc
@@ -10,7 +10,6 @@
 
 #include "tools/fidl/fidlc/src/flat_ast.h"
 #include "tools/fidl/fidlc/src/names.h"
-#include "tools/fidl/fidlc/src/raw_ast.h"
 #include "tools/fidl/fidlc/src/source_span.h"
 
 namespace fidlc {
@@ -60,17 +59,13 @@
   }
 }
 
-std::string Display(const std::vector<std::string_view>& library_name) {
-  return NameLibrary(library_name);
-}
-
 std::string Display(const Attribute* a) { return std::string(a->name.data()); }
 
 std::string Display(const AttributeArg* a) {
   return a->name.has_value() ? std::string(a->name.value().data()) : "";
 }
 
-std::string Display(const Constant* c) { return NameFlatConstant(c); }
+std::string Display(const Constant* c) { return NameConstant(c); }
 
 std::string Display(Element::Kind k) {
   switch (k) {
@@ -145,7 +140,7 @@
   return ss.str();
 }
 
-std::string Display(const Type* t) { return NameFlatType(t); }
+std::string Display(const Type* t) { return NameType(t); }
 
 std::string Display(const Name& n) { return n.full_name(); }
 
diff --git a/tools/fidl/fidlc/src/diagnostic_types.h b/tools/fidl/fidlc/src/diagnostic_types.h
index 13c9943..fd7f65e 100644
--- a/tools/fidl/fidlc/src/diagnostic_types.h
+++ b/tools/fidl/fidlc/src/diagnostic_types.h
@@ -5,6 +5,7 @@
 #ifndef TOOLS_FIDL_FIDLC_SRC_DIAGNOSTIC_TYPES_H_
 #define TOOLS_FIDL_FIDLC_SRC_DIAGNOSTIC_TYPES_H_
 
+#include <lib/stdcompat/type_traits.h>
 #include <zircon/assert.h>
 
 #include <memory>
@@ -16,7 +17,6 @@
 #include "tools/fidl/fidlc/src/properties.h"
 #include "tools/fidl/fidlc/src/source_span.h"
 #include "tools/fidl/fidlc/src/token.h"
-#include "tools/fidl/fidlc/src/utils.h"
 #include "tools/fidl/fidlc/src/versioning_types.h"
 
 namespace fidlc {
@@ -33,7 +33,6 @@
 std::string Display(Token::KindAndSubkind t);
 std::string Display(Openness o);
 std::string Display(Protocol::Method::Kind k);
-std::string Display(const std::vector<std::string_view>& library_name);
 std::string Display(const Attribute* a);
 std::string Display(const AttributeArg* a);
 std::string Display(const Constant* c);
@@ -176,13 +175,14 @@
 
   template <ErrorId Id, typename... Args>
   static std::unique_ptr<Diagnostic> MakeError(const ErrorDef<Id, Args...>& def, SourceSpan span,
-                                               const identity_t<Args>&... args) {
+                                               const cpp20::type_identity_t<Args>&... args) {
     return std::make_unique<Diagnostic>(def, span, args...);
   }
 
   template <ErrorId Id, typename... Args>
   static std::unique_ptr<Diagnostic> MakeWarning(const WarningDef<Id, Args...>& def,
-                                                 SourceSpan span, const identity_t<Args>&... args) {
+                                                 SourceSpan span,
+                                                 const cpp20::type_identity_t<Args>&... args) {
     return std::make_unique<Diagnostic>(def, span, args...);
   }
 
diff --git a/tools/fidl/fidlc/src/diagnostics.h b/tools/fidl/fidlc/src/diagnostics.h
index 08f9b22..5123c70 100644
--- a/tools/fidl/fidlc/src/diagnostics.h
+++ b/tools/fidl/fidlc/src/diagnostics.h
@@ -92,30 +92,28 @@
     "library under a different name.");
 constexpr ErrorDef<40> ErrFilesDisagreeOnLibraryName(
     "Two files in the library disagree about the name of the library");
-constexpr ErrorDef<41, std::vector<std::string_view>> ErrMultipleLibrariesWithSameName(
+constexpr ErrorDef<41, std::string_view> ErrMultipleLibrariesWithSameName(
     "There are multiple libraries named '{0}'");
-constexpr ErrorDef<42, std::vector<std::string_view>> ErrDuplicateLibraryImport(
+constexpr ErrorDef<42, std::string_view> ErrDuplicateLibraryImport(
     "Library {0} already imported. Did you require it twice?");
-constexpr ErrorDef<43, std::vector<std::string_view>> ErrConflictingLibraryImport(
+constexpr ErrorDef<43, std::string_view> ErrConflictingLibraryImport(
     "import of library '{0}' conflicts with another library import");
-constexpr ErrorDef<44, std::vector<std::string_view>, std::string_view>
-    ErrConflictingLibraryImportAlias(
-        "import of library '{0}' under alias '{1}' conflicts with another library import");
+constexpr ErrorDef<44, std::string_view, std::string_view> ErrConflictingLibraryImportAlias(
+    "import of library '{0}' under alias '{1}' conflicts with another library import");
 constexpr ErrorDef<45> ErrAttributesNotAllowedOnLibraryImport(
     "attributes and doc comments are not allowed on `using` statements");
-constexpr ErrorDef<46, std::vector<std::string_view>> ErrUnknownLibrary(
+constexpr ErrorDef<46, std::string_view> ErrUnknownLibrary(
     "Could not find library named {0}. Did you include its sources with --files?");
 constexpr RetiredDef<47> ErrProtocolComposedMultipleTimes;
 constexpr ErrorDef<48> ErrOptionalTableMember("Table members cannot be optional");
 constexpr ErrorDef<49> ErrOptionalUnionMember("Union members cannot be optional");
 constexpr ErrorDef<50> ErrDeprecatedStructDefaults(
     "Struct defaults are deprecated and should not be used (see RFC-0160)");
-constexpr ErrorDef<51, std::vector<std::string_view>, std::vector<std::string_view>>
-    ErrUnknownDependentLibrary(
-        "Unknown dependent library {0} or reference to member of "
-        "library {1}. Did you require it with `using`?");
-constexpr ErrorDef<52, std::string_view, std::vector<std::string_view>> ErrNameNotFound(
-    "cannot find '{0}' in library '{1}'");
+constexpr ErrorDef<51, std::string_view, std::string_view> ErrUnknownDependentLibrary(
+    "Unknown dependent library {0} or reference to member of "
+    "library {1}. Did you require it with `using`?");
+constexpr ErrorDef<52, std::string_view, const Library *> ErrNameNotFound(
+    "cannot find '{0}' in {1}");
 constexpr ErrorDef<53, const Decl *> ErrCannotReferToMember("cannot refer to member of {0}");
 constexpr ErrorDef<54, const Decl *, std::string_view> ErrMemberNotFound("{0} has no member '{1}'");
 constexpr ErrorDef<55, const Element *, VersionRange, Platform, const Element *>
@@ -299,7 +297,7 @@
     "the argument 'platform' can only be used on the library's @available attribute");
 constexpr ErrorDef<150> ErrLibraryAvailabilityMissingAdded(
     "missing 'added' argument on the library's @available attribute");
-constexpr ErrorDef<151, std::vector<std::string_view>> ErrMissingLibraryAvailability(
+constexpr ErrorDef<151, std::string_view> ErrMissingLibraryAvailability(
     "to use the @available attribute here, you must also annotate the "
     "`library {0};` declaration in one of the library's files");
 constexpr ErrorDef<152, std::string_view> ErrInvalidPlatform(
@@ -352,9 +350,8 @@
 constexpr ErrorDef<177, Name> ErrResourceRightsPropertyMustReferToBits(
     "the rights property must be a uint32 or a uint32-based bits, "
     "but wasn't defined as such in resource {0}");
-constexpr ErrorDef<178, std::vector<std::string_view>, std::vector<std::string_view>>
-    ErrUnusedImport(
-        "Library {0} imports {1} but does not use it. Either use {1}, or remove import.");
+constexpr ErrorDef<178, const Library *, const Library *> ErrUnusedImport(
+    "{0} imports {1} but does not use it; either use it or remove the import");
 constexpr ErrorDef<179, Name> ErrNewTypeCannotHaveConstraint(
     "{0} is a newtype, which cannot carry constraints");
 constexpr ErrorDef<180, Name> ErrExperimentalZxCTypesDisallowed(
@@ -395,8 +392,8 @@
 constexpr ErrorDef<199> ErrOverlayMemberMustBeValue("overlays may not contain resource members",
                                                     {.documented = false});
 constexpr RetiredDef<200> ErrOverlayMustNotContainReserved;
-constexpr ErrorDef<201, std::vector<std::string_view>, Platform> ErrPlatformVersionNotSelected(
-    "library '{0}' belongs to platform '{1}', but no version was selected for it; "
+constexpr ErrorDef<201, const Library *, Platform> ErrPlatformVersionNotSelected(
+    "{0} belongs to platform '{1}', but no version was selected for it; "
     "please choose a version N by passing `--available {1}:N`");
 constexpr RetiredDef<202> ErrTransitionalNotAllowed;
 constexpr ErrorDef<203> ErrRemovedAndReplaced(
diff --git a/tools/fidl/fidlc/src/flat_ast.cc b/tools/fidl/fidlc/src/flat_ast.cc
index 1d9543a..ba11db4 100644
--- a/tools/fidl/fidlc/src/flat_ast.cc
+++ b/tools/fidl/fidlc/src/flat_ast.cc
@@ -64,7 +64,7 @@
 std::string_view Element::GetName() const {
   switch (kind) {
     case Kind::kLibrary:
-      ZX_PANIC("should not call GetName() on a library element");
+      return static_cast<const Library*>(this)->name;
     case Kind::kBits:
     case Kind::kBuiltin:
     case Kind::kConst:
@@ -192,8 +192,7 @@
   refs_.push_back(std::make_unique<LibraryRef>(span, dep_library));
   LibraryRef* ref = refs_.back().get();
 
-  const std::vector<std::string_view> name =
-      maybe_alias ? std::vector{maybe_alias->span().data()} : dep_library->name;
+  auto name = maybe_alias ? maybe_alias->span().data() : dep_library->name;
   auto iter = by_filename_.find(filename);
   if (iter == by_filename_.end()) {
     iter = by_filename_.emplace(filename, std::make_unique<PerFile>()).first;
@@ -209,23 +208,23 @@
   return RegisterResult::kSuccess;
 }
 
-bool Dependencies::Contains(std::string_view filename, const std::vector<std::string_view>& name) {
+bool Dependencies::Contains(std::string_view filename, std::string_view library_name) {
   const auto iter = by_filename_.find(filename);
   if (iter == by_filename_.end()) {
     return false;
   }
   const PerFile& per_file = *iter->second;
-  return per_file.refs.find(name) != per_file.refs.end();
+  return per_file.refs.find(library_name) != per_file.refs.end();
 }
 
 Library* Dependencies::LookupAndMarkUsed(std::string_view filename,
-                                         const std::vector<std::string_view>& name) const {
+                                         std::string_view library_name) const {
   auto iter1 = by_filename_.find(filename);
   if (iter1 == by_filename_.end()) {
     return nullptr;
   }
 
-  auto iter2 = iter1->second->refs.find(name);
+  auto iter2 = iter1->second->refs.find(library_name);
   if (iter2 == iter1->second->refs.end()) {
     return nullptr;
   }
@@ -235,21 +234,16 @@
   return ref->library;
 }
 
-void Dependencies::VerifyAllDependenciesWereUsed(const Library& for_library, Reporter* reporter) {
+void Dependencies::VerifyAllDependenciesWereUsed(const Library* for_library, Reporter* reporter) {
   for (const auto& [filename, per_file] : by_filename_) {
     for (const auto& [name, ref] : per_file->refs) {
       if (!ref->used) {
-        reporter->Fail(ErrUnusedImport, ref->span, for_library.name, ref->library->name);
+        reporter->Fail(ErrUnusedImport, ref->span, for_library, ref->library);
       }
     }
   }
 }
 
-std::string LibraryName(const std::vector<std::string_view>& components,
-                        std::string_view separator) {
-  return StringJoin(components, separator);
-}
-
 // static
 std::unique_ptr<Library> Library::CreateRootLibrary() {
   // TODO(https://fxbug.dev/42146818): Because this library doesn't get compiled, we have
@@ -257,7 +251,7 @@
   // availabilities). Perhaps we could make the root library less special and
   // compile it as well. That would require addressing circularity issues.
   auto library = std::make_unique<Library>();
-  library->name = {"fidl"};
+  library->name = "fidl";
   library->platform = Platform::Unversioned();
   library->availability.Init({.added = Version::Head()});
   library->availability.Inherit(Availability::Unbounded());
@@ -597,7 +591,7 @@
 }
 
 Protocol::Method Protocol::Method::Clone() const {
-  return Method(attributes->Clone(), strictness, identifier, name, has_request,
+  return Method(attributes->Clone(), strictness, name, has_request,
                 maybe_request ? maybe_request->Clone() : nullptr, has_response,
                 maybe_response ? maybe_response->Clone() : nullptr, has_error);
 }
diff --git a/tools/fidl/fidlc/src/flat_ast.h b/tools/fidl/fidlc/src/flat_ast.h
index 031369f..bab29fd 100644
--- a/tools/fidl/fidlc/src/flat_ast.h
+++ b/tools/fidl/fidlc/src/flat_ast.h
@@ -12,11 +12,9 @@
 #include <zircon/assert.h>
 
 #include <cstdint>
-#include <functional>
 #include <map>
 #include <optional>
 #include <set>
-#include <string>
 #include <string_view>
 #include <utility>
 #include <vector>
@@ -41,10 +39,6 @@
 struct RawIdentifier;
 struct RawOrdinal64;
 
-// This is needed (for now) to work around declaration order issues.
-std::string LibraryName(const std::vector<std::string_view>& components,
-                        std::string_view separator);
-
 struct Element {
   enum class Kind : uint8_t {
     kAlias,
@@ -660,20 +654,17 @@
 
 struct Protocol final : public Decl {
   struct Method : public Element {
-    Method(std::unique_ptr<AttributeList> attributes, Strictness strictness,
-           const RawIdentifier* identifier, SourceSpan name, bool has_request,
-           std::unique_ptr<TypeConstructor> maybe_request, bool has_response,
+    Method(std::unique_ptr<AttributeList> attributes, Strictness strictness, SourceSpan name,
+           bool has_request, std::unique_ptr<TypeConstructor> maybe_request, bool has_response,
            std::unique_ptr<TypeConstructor> maybe_response, bool has_error)
         : Element(Element::Kind::kProtocolMethod, std::move(attributes)),
           strictness(strictness),
-          identifier(identifier),
           name(name),
           has_request(has_request),
           maybe_request(std::move(maybe_request)),
           has_response(has_response),
           maybe_response(std::move(maybe_response)),
-          has_error(has_error),
-          generated_ordinal64(nullptr) {
+          has_error(has_error) {
       ZX_ASSERT(this->has_request || this->has_response);
     }
     Method Clone() const;
@@ -685,9 +676,13 @@
       return has_request ? Kind::kOneWay : Kind::kEvent;
     }
 
+    enum ResultUnionOrdinal : uint64_t {
+      kSuccess = 1,
+      kDomainError = 2,
+      kFrameworkError = 3,
+    };
+
     Strictness strictness;
-    // Owned by Library::raw_identifiers.
-    const RawIdentifier* identifier;
     SourceSpan name;
     bool has_request;
     std::unique_ptr<TypeConstructor> maybe_request;
@@ -697,7 +692,7 @@
     Protocol* owning_protocol = nullptr;
 
     // Set during compilation
-    std::unique_ptr<RawOrdinal64> generated_ordinal64;
+    uint64_t ordinal = 0;
     const Union* result_union = nullptr;
     const TypeConstructor* result_success_type_ctor = nullptr;
     const TypeConstructor* result_domain_error_type_ctor = nullptr;
@@ -825,17 +820,16 @@
                           const std::unique_ptr<RawIdentifier>& maybe_alias);
 
   // Returns true if this dependency set contains a library with the given name and filename.
-  bool Contains(std::string_view filename, const std::vector<std::string_view>& name);
+  bool Contains(std::string_view filename, std::string_view library_name);
 
   // Looks up a dependency by filename (within the importing library, since
   // "using" statements are file-scoped) and name (of the imported library).
   // Also marks the library as used. Returns null if no library is found.
-  Library* LookupAndMarkUsed(std::string_view filename,
-                             const std::vector<std::string_view>& name) const;
+  Library* LookupAndMarkUsed(std::string_view filename, std::string_view library_name) const;
 
   // VerifyAllDependenciesWereUsed reports an error for each dependency imported
   // with `using` that was never used in the file.
-  void VerifyAllDependenciesWereUsed(const Library& for_library, Reporter* reporter);
+  void VerifyAllDependenciesWereUsed(const Library* for_library, Reporter* reporter);
 
   // Returns all the dependencies.
   const std::set<Library*>& all() const { return dependencies_aggregate_; }
@@ -863,7 +857,7 @@
   // Per-file information about imports.
   struct PerFile {
     // References to dependencies, keyed by library name or by alias.
-    std::map<std::vector<std::string_view>, LibraryRef*> refs;
+    std::map<std::string_view, LibraryRef*> refs;
     // Set containing ref->library for every ref in |refs|.
     std::set<Library*> libraries;
   };
@@ -911,12 +905,8 @@
     std::vector<std::unique_ptr<Overlay>> overlays;
   };
 
-  std::vector<std::string_view> name;
-  // There is no unique SourceSpan for a library's name since it can be declared
-  // in multiple files, but we store an arbitrary one to use in error messages.
-  SourceSpan arbitrary_name_span;
-  // stores all library name declaration location
-  std::vector<SourceSpan> library_name_declarations;
+  std::string name;
+  std::vector<SourceSpan> name_spans;
   // Set during AvailabilityStep.
   std::optional<Platform> platform;
   Dependencies dependencies;
@@ -929,7 +919,6 @@
   // Library because there is no unique ownership (e.g. multiple Table::Member
   // instances can point to the same RawOrdinal64 after decomposition).
   std::vector<std::unique_ptr<RawLiteral>> raw_literals;
-  std::vector<std::unique_ptr<RawIdentifier>> raw_identifiers;
   std::vector<std::unique_ptr<RawOrdinal64>> raw_ordinals;
 };
 
diff --git a/tools/fidl/fidlc/src/index_json_generator.cc b/tools/fidl/fidlc/src/index_json_generator.cc
index 7efea6a..75440dd 100644
--- a/tools/fidl/fidlc/src/index_json_generator.cc
+++ b/tools/fidl/fidlc/src/index_json_generator.cc
@@ -16,7 +16,7 @@
 std::ostringstream IndexJSONGenerator::Produce() {
   ResetIndentLevel();
   GenerateObject([&]() {
-    GenerateObjectMember("name", LibraryName(compilation_->library_name, "."), Position::kFirst);
+    GenerateObjectMember("name", compilation_->library_name, Position::kFirst);
     GenerateObjectMember("lib_declarations", compilation_->library_declarations);
     GenerateObjectMember("using_declarations", compilation_->using_references);
     GenerateObjectMember("dependencies", compilation_->direct_and_composed_dependencies);
@@ -47,7 +47,7 @@
       for (auto& member : enumdecl->members) {
         Name full_name = enumdecl->name.WithMemberName(std::string(member.name.data()));
         auto member_identifier =
-            IndexJSONGenerator::ReferencedIdentifier(NameFlatName(full_name), member.name);
+            IndexJSONGenerator::ReferencedIdentifier(FullyQualifiedName(full_name), member.name);
         identifiers.emplace_back(member_identifier);
       }
     }
@@ -95,26 +95,26 @@
 void IndexJSONGenerator::Generate(std::pair<Library*, SourceSpan> reference) {
   GenerateObject([&]() {
     // for debugging purpose, include the span data
-    GenerateObjectMember("library_name", LibraryName(reference.first->name, "."), Position::kFirst);
+    GenerateObjectMember("library_name", reference.first->name, Position::kFirst);
     GenerateObjectMember("referenced_at", reference.second);
   });
 }
 
 void IndexJSONGenerator::Generate(const Compilation::Dependency& dependency) {
   GenerateObject([&]() {
-    GenerateObjectMember("library_name", LibraryName(dependency.library->name, "."),
-                         Position::kFirst);
-    GenerateObjectMember("library_location", dependency.library->arbitrary_name_span);
+    GenerateObjectMember("library_name", dependency.library->name, Position::kFirst);
+    GenerateObjectMember("library_location", dependency.library->name_spans[0]);
   });
 }
 
 void IndexJSONGenerator::Generate(const Constant& value) {
   GenerateObject([&]() {
-    GenerateObjectMember("type", NameFlatConstantKind(value.kind), Position::kFirst);
+    GenerateObjectMember("type", NameConstantKind(value.kind), Position::kFirst);
     switch (value.kind) {
       case Constant::Kind::kIdentifier: {
         auto identifier = static_cast<const IdentifierConstant*>(&value);
-        GenerateObjectMember("identifier", NameFlatName((identifier->reference.resolved().name())));
+        GenerateObjectMember("identifier",
+                             FullyQualifiedName((identifier->reference.resolved().name())));
         GenerateObjectMember("referenced_at", identifier->reference.span());
         break;
       }
@@ -134,13 +134,13 @@
 
 void IndexJSONGenerator::Generate(const Const& value) {
   GenerateObject([&]() {
-    GenerateObjectMember("identifier", NameFlatName(value.name), Position::kFirst);
+    GenerateObjectMember("identifier", FullyQualifiedName(value.name), Position::kFirst);
     GenerateObjectMember("location", value.name.span().value());
     GenerateObjectMember("value", value.value);
   });
 }
 
-void IndexJSONGenerator::Generate(const Name& name) { Generate(NameFlatName(name)); }
+void IndexJSONGenerator::Generate(const Name& name) { Generate(FullyQualifiedName(name)); }
 
 void IndexJSONGenerator::Generate(const Enum& value) {
   GenerateObject([&]() {
@@ -224,7 +224,7 @@
 void IndexJSONGenerator::Generate(const TypeConstructor* value) {
   auto type = value->type;
   GenerateObject([&]() {
-    GenerateObjectMember("kind", NameFlatTypeKind(type), Position::kFirst);
+    GenerateObjectMember("kind", NameTypeKind(type), Position::kFirst);
     // handle the non anonymous type identifier case only for now
     // parameterized types (arrays, vectors) are not handled yet
     if (type->kind == Type::Kind::kIdentifier) {
diff --git a/tools/fidl/fidlc/src/index_json_generator.h b/tools/fidl/fidlc/src/index_json_generator.h
index c21a911..6b45294 100644
--- a/tools/fidl/fidlc/src/index_json_generator.h
+++ b/tools/fidl/fidlc/src/index_json_generator.h
@@ -33,7 +33,7 @@
 
   // struct representing an identifier from dependency library referenced in target library
   struct ReferencedIdentifier {
-    explicit ReferencedIdentifier(const Name& name) : identifier(NameFlatName(name)) {
+    explicit ReferencedIdentifier(const Name& name) : identifier(FullyQualifiedName(name)) {
       ZX_ASSERT_MSG(name.span().has_value(), "anonymous name used as an identifier");
       span = name.span().value();
     }
diff --git a/tools/fidl/fidlc/src/json_generator.cc b/tools/fidl/fidlc/src/json_generator.cc
index 126a78a..6e112ff 100644
--- a/tools/fidl/fidlc/src/json_generator.cc
+++ b/tools/fidl/fidlc/src/json_generator.cc
@@ -87,7 +87,7 @@
     }
     case ConstantValue::Kind::kDocComment: {
       auto& doc_comment_constant = static_cast<const DocCommentConstantValue&>(value);
-      EmitString(doc_comment_constant.MakeContents());
+      EmitString(doc_comment_constant.value);
       break;
     }
     case ConstantValue::Kind::kString: {
@@ -139,7 +139,7 @@
 
 void JSONGenerator::Generate(const Constant& value) {
   GenerateObject([&]() {
-    GenerateObjectMember("kind", NameFlatConstantKind(value.kind), Position::kFirst);
+    GenerateObjectMember("kind", NameConstantKind(value.kind), Position::kFirst);
     GenerateObjectMember("value", value.Value());
     GenerateObjectMember("expression", value.span);
     switch (value.kind) {
@@ -163,7 +163,7 @@
 
 void JSONGenerator::Generate(const Type* value) {
   GenerateObject([&]() {
-    GenerateObjectMember("kind", NameFlatTypeKind(value), Position::kFirst);
+    GenerateObjectMember("kind", NameTypeKind(value), Position::kFirst);
 
     switch (value->kind) {
       case Type::Kind::kBox: {
@@ -198,7 +198,7 @@
         GenerateObjectMember(
             "rights", static_cast<const NumericConstantValue<uint32_t>*>(type->rights)->value);
         GenerateObjectMember("nullable", type->nullability);
-        GenerateObjectMember("resource_identifier", NameFlatName(type->resource_decl->name));
+        GenerateObjectMember("resource_identifier", FullyQualifiedName(type->resource_decl->name));
         break;
       }
       case Type::Kind::kPrimitive: {
@@ -263,7 +263,7 @@
 
 void JSONGenerator::Generate(const Attribute& value) {
   GenerateObject([&]() {
-    const auto& name = to_lower_snake_case(std::string(value.name.data()));
+    const auto& name = ToLowerSnakeCase(std::string(value.name.data()));
     GenerateObjectMember("name", name, Position::kFirst);
     GenerateObjectMember("arguments", value.args);
     ZX_ASSERT(value.span.valid());
@@ -286,17 +286,17 @@
 }
 
 void JSONGenerator::Generate(const Name& name) {
-  // TODO(https://fxbug.dev/42174095): NameFlatName omits the library name for builtins,
-  // since we want error messages to say "uint32" not "fidl/uint32". However,
-  // builtins MAX and HEAD can end up in the JSON IR as identifier constants,
-  // and to satisfy the schema we must produce a proper compound identifier
-  // (with a library name). We should solve this in a cleaner way.
+  // TODO(https://fxbug.dev/42174095): FullyQualifiedName omits the library name
+  // for builtins, since we want errors to say "uint32" not "fidl/uint32".
+  // However, builtins MAX and HEAD can end up in the JSON IR as identifier
+  // constants, and to satisfy the schema we must produce a proper compound
+  // identifier (with a library name). We should solve this in a cleaner way.
   if (name.is_intrinsic() && name.decl_name() == "MAX") {
     EmitString(std::string_view("fidl/MAX"));
   } else if (name.is_intrinsic() && name.decl_name() == "HEAD") {
     EmitString(std::string_view("fidl/HEAD"));
   } else {
-    EmitString(NameFlatName(name));
+    EmitString(FullyQualifiedName(name));
   }
 }
 
@@ -403,7 +403,7 @@
   ZX_ASSERT(method_with_info.method != nullptr);
   const auto& value = *method_with_info.method;
   GenerateObject([&]() {
-    GenerateObjectMember("ordinal", value.generated_ordinal64, Position::kFirst);
+    GenerateObjectMember("ordinal", value.ordinal, Position::kFirst);
     GenerateObjectMember("name", value.name);
     GenerateObjectMember("strict", value.strictness);
     GenerateObjectMember("location", NameSpan(value.name));
@@ -494,7 +494,7 @@
   GenerateObjectPunctuation(position);
   EmitObjectKey(key);
   GenerateObject([&]() {
-    GenerateObjectMember("kind", NameFlatTypeKind(type), Position::kFirst);
+    GenerateObjectMember("kind", NameTypeKind(type), Position::kFirst);
 
     switch (type->kind) {
       case Type::Kind::kArray: {
@@ -860,8 +860,7 @@
 
 void JSONGenerator::Generate(const Compilation::Dependency& dependency) {
   GenerateObject([&]() {
-    auto library_name = LibraryName(dependency.library->name, ".");
-    GenerateObjectMember("name", library_name, Position::kFirst);
+    GenerateObjectMember("name", dependency.library->name, Position::kFirst);
     GenerateExternalDeclarationsMember(dependency.declarations);
   });
 }
@@ -874,7 +873,7 @@
   } else {
     EmitObjectSeparator();
   }
-  EmitObjectKey(NameFlatName(name));
+  EmitObjectKey(FullyQualifiedName(name));
   EmitString(decl_kind);
 }
 
@@ -931,7 +930,7 @@
   } else {
     EmitObjectSeparator();
   }
-  EmitObjectKey(NameFlatName(name));
+  EmitObjectKey(FullyQualifiedName(name));
   GenerateObject([&]() {
     GenerateObjectMember("kind", decl_kind, Position::kFirst);
     if (maybe_resourceness) {
@@ -987,7 +986,7 @@
 std::ostringstream JSONGenerator::Produce() {
   ResetIndentLevel();
   GenerateObject([&]() {
-    GenerateObjectMember("name", LibraryName(compilation_->library_name, "."), Position::kFirst);
+    GenerateObjectMember("name", compilation_->library_name, Position::kFirst);
     GenerateObjectMember("platform", compilation_->platform->name());
 
     GenerateObjectPunctuation(Position::kSubsequent);
@@ -1033,7 +1032,7 @@
     std::vector<std::string> declaration_order;
     declaration_order.reserve(compilation_->declaration_order.size());
     for (const auto decl : compilation_->declaration_order) {
-      declaration_order.push_back(NameFlatName(decl->name));
+      declaration_order.push_back(FullyQualifiedName(decl->name));
     }
     GenerateObjectMember("declaration_order", declaration_order);
 
diff --git a/tools/fidl/fidlc/src/json_writer.h b/tools/fidl/fidlc/src/json_writer.h
index 0d9a109..cc85469 100644
--- a/tools/fidl/fidlc/src/json_writer.h
+++ b/tools/fidl/fidlc/src/json_writer.h
@@ -210,8 +210,9 @@
     os_ << "\"";
   }
 
-  // Emits a string literal given its raw FIDL source (including the quotes).
+  // Emits a string literal given its raw FIDL source.
   void EmitLiteral(std::string_view value) {
+    os_ << "\"";
     for (auto it = value.begin(); it != value.end(); ++it) {
       // FIDL's string literal syntax is similar to JSON's, so we can emit most
       // characters unchanged (including escape sequences \\, \", \n, \r, \t)
@@ -230,7 +231,7 @@
       }
       std::string_view codepoint_hex = value.substr(hex_begin - value.begin(), it - hex_begin);
       // Next, decode the code point X as an integer.
-      auto codepoint = decode_unicode_hex(codepoint_hex);
+      auto codepoint = DecodeUnicodeHex(codepoint_hex);
       if (codepoint <= 0xffff) {
         // This code point can be represented by a single \uNNNN in JSON.
         char buf[7];
@@ -247,6 +248,7 @@
         os_ << buf;
       }
     }
+    os_ << "\"";
   }
 
   template <typename T>
diff --git a/tools/fidl/fidlc/src/lexer.cc b/tools/fidl/fidlc/src/lexer.cc
index 54e8a9b..f10cfc4 100644
--- a/tools/fidl/fidlc/src/lexer.cc
+++ b/tools/fidl/fidlc/src/lexer.cc
@@ -282,7 +282,7 @@
           } else {
             SourceSpan span(std::string_view(current_ - 1 - unicode_hex_digits, unicode_hex_digits),
                             source_file_);
-            auto codepoint = decode_unicode_hex(span.data());
+            auto codepoint = DecodeUnicodeHex(span.data());
             if (codepoint > 0x10ffff) {
               reporter_->Fail(ErrUnicodeEscapeTooLarge, span, span.data());
             }
diff --git a/tools/fidl/fidlc/src/linter.cc b/tools/fidl/fidlc/src/linter.cc
index 39e725f..a74d5d9 100644
--- a/tools/fidl/fidlc/src/linter.cc
+++ b/tools/fidl/fidlc/src/linter.cc
@@ -474,7 +474,7 @@
       (const RawProtocolDeclaration& element) {
         linter.CheckCase("protocols", element.identifier, linter.invalid_case_for_decl_name(),
                          linter.upper_camel_);
-        for (const auto& word : id_to_words(to_string(element.identifier))) {
+        for (const auto& word : SplitIdentifierWords(to_string(element.identifier))) {
           if (word == "service") {
             linter.AddFinding(element.identifier, name_contains_service_check);
             break;
@@ -563,10 +563,10 @@
         if (element.provenance == RawAttribute::Provenance::kDocComment) {
           auto constant = static_cast<RawLiteralConstant*>(element.args.front()->value.get());
           auto doc_comment = static_cast<RawDocCommentLiteral*>(constant->literal.get());
-          if (re2::RE2::PartialMatch(doc_comment->MakeContents(), *copyright_regex)) {
+          if (re2::RE2::PartialMatch(doc_comment->value, *copyright_regex)) {
             linter.AddFinding(element, check, {}, "change '///' to '//'", "//");
           }
-          if (re2::RE2::PartialMatch(doc_comment->MakeContents(), *todo_regex)) {
+          if (re2::RE2::PartialMatch(doc_comment->value, *todo_regex)) {
             linter.AddFinding(element, todo_check, {}, "change '///' to '//'", "//");
           }
         }
diff --git a/tools/fidl/fidlc/src/linter.h b/tools/fidl/fidlc/src/linter.h
index b4b7a56..03fa0a1 100644
--- a/tools/fidl/fidlc/src/linter.h
+++ b/tools/fidl/fidlc/src/linter.h
@@ -73,8 +73,8 @@
 
  private:
   // Holds function pointers for an identify case type. For example,
-  // for "UpperCamelCase" type, |matches| points to is_upper_camel_case()
-  // and |convert| points to to_upper_camel_case().
+  // for "UpperCamelCase" type, |matches| points to IsUpperCamelCase()
+  // and |convert| points to ToUpperCamelCase().
   struct CaseType {
     fit::function<bool(std::string)> matches;
     fit::function<std::string(std::string)> convert;
@@ -181,9 +181,9 @@
   LintingTreeCallbacks callbacks_;
 
   // Case type functions used by CheckCase().
-  CaseType lower_snake_{is_lower_snake_case, to_lower_snake_case};
-  CaseType upper_snake_{is_upper_snake_case, to_upper_snake_case};
-  CaseType upper_camel_{is_upper_camel_case, to_upper_camel_case};
+  CaseType lower_snake_{IsLowerSnakeCase, ToLowerSnakeCase};
+  CaseType upper_snake_{IsUpperSnakeCase, ToUpperSnakeCase};
+  CaseType upper_camel_{IsUpperCamelCase, ToUpperCamelCase};
 
   // In IpcStyle, bits, protocols, protocol methods, structs, tables, unions,
   // and enums use UpperCamelCase. In CStyle used for syscalls, they
diff --git a/tools/fidl/fidlc/src/name.cc b/tools/fidl/fidlc/src/name.cc
index 47c9ecf..94f54c1 100644
--- a/tools/fidl/fidlc/src/name.cc
+++ b/tools/fidl/fidlc/src/name.cc
@@ -17,16 +17,16 @@
     case Kind::kDecl:
       return std::string(name.data());
     case Kind::kLayoutMember:
-      return to_upper_camel_case(std::string(name.data()));
+      return ToUpperCamelCase(std::string(name.data()));
     case Kind::kMethodRequest: {
-      std::string result = to_upper_camel_case(std::string(parent->name_.data()));
-      result.append(to_upper_camel_case(std::string(name.data())));
+      std::string result = ToUpperCamelCase(std::string(parent->name_.data()));
+      result.append(ToUpperCamelCase(std::string(name.data())));
       result.append("Request");
       return result;
     }
     case Kind::kMethodResponse: {
-      std::string result = to_upper_camel_case(std::string(parent->name_.data()));
-      result.append(to_upper_camel_case(std::string(name.data())));
+      std::string result = ToUpperCamelCase(std::string(parent->name_.data()));
+      result.append(ToUpperCamelCase(std::string(name.data())));
       result.append("Response");
       return result;
     }
diff --git a/tools/fidl/fidlc/src/names.cc b/tools/fidl/fidlc/src/names.cc
index 9babace..c945fd4 100644
--- a/tools/fidl/fidlc/src/names.cc
+++ b/tools/fidl/fidlc/src/names.cc
@@ -4,48 +4,12 @@
 
 #include "tools/fidl/fidlc/src/names.h"
 
-#include <zircon/assert.h>
-
 #include <sstream>
 
+#include "tools/fidl/fidlc/src/flat_ast.h"
+
 namespace fidlc {
 
-namespace {
-
-const char* NameNullability(bool is_nullable) { return is_nullable ? "nullable" : "nonnullable"; }
-
-const char* NameNullability(Nullability nullability) {
-  return NameNullability(nullability == Nullability::kNullable);
-}
-
-std::string NameSize(uint64_t size) {
-  if (size == std::numeric_limits<uint64_t>::max())
-    return "unbounded";
-  std::ostringstream name;
-  name << size;
-  return name.str();
-}
-
-std::string FormatName(const Name& name, std::string_view library_separator,
-                       std::string_view name_separator) {
-  std::string compiled_name;
-  if (name.library() != nullptr && !name.is_intrinsic()) {
-    compiled_name += LibraryName(name.library()->name, library_separator);
-    compiled_name += name_separator;
-  }
-  compiled_name += name.full_name();
-  return compiled_name;
-}
-
-std::string LengthPrefixedString(std::string_view str) {
-  std::ostringstream out;
-  out << str.length();
-  out << str;
-  return out.str();
-}
-
-}  // namespace
-
 std::string NameHandleSubtype(HandleSubtype subtype) {
   switch (subtype) {
     case HandleSubtype::kHandle:
@@ -111,8 +75,6 @@
   }
 }
 
-std::string NameHandleRights(RightsWrappedType rights) { return std::to_string(rights); }
-
 std::string NameRawLiteralKind(RawLiteral::Kind kind) {
   switch (kind) {
     case RawLiteral::Kind::kDocComment:
@@ -125,9 +87,7 @@
   }
 }
 
-std::string NameFlatName(const Name& name) { return FormatName(name, ".", "/"); }
-
-std::string NameFlatTypeKind(const Type* type) {
+std::string NameTypeKind(const Type* type) {
   switch (type->kind) {
     case Type::Kind::kArray:
       if (static_cast<const ArrayType*>(type)->IsStringArray()) {
@@ -161,7 +121,7 @@
   }
 }
 
-std::string NameFlatConstantKind(Constant::Kind kind) {
+std::string NameConstantKind(Constant::Kind kind) {
   switch (kind) {
     case Constant::Kind::kIdentifier:
       return "identifier";
@@ -172,76 +132,7 @@
   }
 }
 
-std::string NameHandleZXObjType(HandleSubtype subtype) {
-  switch (subtype) {
-    case HandleSubtype::kHandle:
-      return "ZX_OBJ_TYPE_NONE";
-    case HandleSubtype::kBti:
-      return "ZX_OBJ_TYPE_BTI";
-    case HandleSubtype::kChannel:
-      return "ZX_OBJ_TYPE_CHANNEL";
-    case HandleSubtype::kClock:
-      return "ZX_OBJ_TYPE_CLOCK";
-    case HandleSubtype::kEvent:
-      return "ZX_OBJ_TYPE_EVENT";
-    case HandleSubtype::kEventpair:
-      return "ZX_OBJ_TYPE_EVENTPAIR";
-    case HandleSubtype::kException:
-      return "ZX_OBJ_TYPE_EXCEPTION";
-    case HandleSubtype::kFifo:
-      return "ZX_OBJ_TYPE_FIFO";
-    case HandleSubtype::kGuest:
-      return "ZX_OBJ_TYPE_GUEST";
-    case HandleSubtype::kInterrupt:
-      return "ZX_OBJ_TYPE_INTERRUPT";
-    case HandleSubtype::kIob:
-      return "ZX_OBJ_TYPE_IOB";
-    case HandleSubtype::kIommu:
-      return "ZX_OBJ_TYPE_IOMMU";
-    case HandleSubtype::kJob:
-      return "ZX_OBJ_TYPE_JOB";
-    case HandleSubtype::kDebugLog:
-      return "ZX_OBJ_TYPE_LOG";
-    case HandleSubtype::kMsi:
-      return "ZX_OBJ_TYPE_MSI";
-    case HandleSubtype::kPager:
-      return "ZX_OBJ_TYPE_PAGER";
-    case HandleSubtype::kPciDevice:
-      return "ZX_OBJ_TYPE_PCI_DEVICE";
-    case HandleSubtype::kPmt:
-      return "ZX_OBJ_TYPE_PMT";
-    case HandleSubtype::kPort:
-      return "ZX_OBJ_TYPE_PORT";
-    case HandleSubtype::kProcess:
-      return "ZX_OBJ_TYPE_PROCESS";
-    case HandleSubtype::kProfile:
-      return "ZX_OBJ_TYPE_PROFILE";
-    case HandleSubtype::kResource:
-      return "ZX_OBJ_TYPE_RESOURCE";
-    case HandleSubtype::kSocket:
-      return "ZX_OBJ_TYPE_SOCKET";
-    case HandleSubtype::kStream:
-      return "ZX_OBJ_TYPE_STREAM";
-    case HandleSubtype::kSuspendToken:
-      return "ZX_OBJ_TYPE_SUSPEND_TOKEN";
-    case HandleSubtype::kThread:
-      return "ZX_OBJ_TYPE_THREAD";
-    case HandleSubtype::kTimer:
-      return "ZX_OBJ_TYPE_TIMER";
-    case HandleSubtype::kVcpu:
-      return "ZX_OBJ_TYPE_VCPU";
-    case HandleSubtype::kVmar:
-      return "ZX_OBJ_TYPE_VMAR";
-    case HandleSubtype::kVmo:
-      return "ZX_OBJ_TYPE_VMO";
-  }
-}
-
-std::string NameUnionTag(std::string_view union_name, const Union::Member& member) {
-  return std::string(union_name) + "Tag_" + NameIdentifier(member.name);
-}
-
-std::string NameFlatConstant(const Constant* constant) {
+std::string NameConstant(const Constant* constant) {
   switch (constant->kind) {
     case Constant::Kind::kLiteral: {
       auto literal_constant = static_cast<const LiteralConstant*>(constant);
@@ -249,21 +140,21 @@
     }
     case Constant::Kind::kIdentifier: {
       auto identifier_constant = static_cast<const IdentifierConstant*>(constant);
-      return NameFlatName(identifier_constant->reference.resolved().name());
+      return FullyQualifiedName(identifier_constant->reference.resolved().name());
     }
     case Constant::Kind::kBinaryOperator: {
       return std::string("binary operator");
     }
-  }  // switch
+  }
 }
 
-void NameFlatTypeHelper(std::ostringstream& buf, const Type* type) {
-  buf << NameFlatName(type->name);
+void NameTypeHelper(std::ostringstream& buf, const Type* type) {
+  buf << FullyQualifiedName(type->name);
   switch (type->kind) {
     case Type::Kind::kArray: {
       const auto* array_type = static_cast<const ArrayType*>(type);
       buf << '<';
-      NameFlatTypeHelper(buf, array_type->element_type);
+      NameTypeHelper(buf, array_type->element_type);
       if (*array_type->element_count != SizeValue::Max()) {
         buf << ", ";
         buf << array_type->element_count->value;
@@ -274,7 +165,7 @@
     case Type::Kind::kVector: {
       const auto* vector_type = static_cast<const VectorType*>(type);
       buf << '<';
-      NameFlatTypeHelper(buf, vector_type->element_type);
+      NameTypeHelper(buf, vector_type->element_type);
       buf << '>';
       if (vector_type->ElementCount() != SizeValue::Max().value) {
         buf << ':';
@@ -293,7 +184,7 @@
     case Type::Kind::kZxExperimentalPointer: {
       const auto* pointer_type = static_cast<const ZxExperimentalPointerType*>(type);
       buf << '<';
-      NameFlatTypeHelper(buf, pointer_type->pointee_type);
+      NameTypeHelper(buf, pointer_type->pointee_type);
       buf << '>';
       break;
     }
@@ -309,13 +200,13 @@
       const auto* transport_side = static_cast<const TransportSideType*>(type);
       buf << (transport_side->end == TransportSide::kClient ? "client" : "server");
       buf << ':';
-      buf << NameFlatName(transport_side->protocol_decl->name);
+      buf << FullyQualifiedName(transport_side->protocol_decl->name);
       break;
     }
     case Type::Kind::kBox: {
       const auto* box_type = static_cast<const BoxType*>(type);
       buf << '<';
-      buf << NameFlatName(box_type->boxed_type->name);
+      buf << FullyQualifiedName(box_type->boxed_type->name);
       buf << '>';
       break;
     }
@@ -332,152 +223,16 @@
   }
 }
 
-std::string NameFlatType(const Type* type) {
+std::string NameType(const Type* type) {
   std::ostringstream buf;
-  NameFlatTypeHelper(buf, type);
+  NameTypeHelper(buf, type);
   return buf.str();
 }
 
-std::string NameIdentifier(SourceSpan name) { return std::string(name.data()); }
-
-std::string NameLibrary(const std::vector<std::unique_ptr<RawIdentifier>>& components) {
-  std::string id;
-  for (const auto& component : components) {
-    if (!id.empty()) {
-      id.append(".");
-    }
-    id.append(component->span().data());
-  }
-  return id;
-}
-
-std::string NameLibrary(const std::vector<std::string_view>& library_name) {
-  return StringJoin(library_name, ".");
-}
-
-std::string NameLibraryCHeader(const std::vector<std::string_view>& library_name) {
-  return StringJoin(library_name, "/") + "/c/fidl.h";
-}
-
-std::string NameDiscoverable(const Protocol& protocol) {
-  return FormatName(protocol.name, ".", ".");
-}
-
-std::string NameMethod(std::string_view protocol_name, const Protocol::Method& method) {
-  return std::string(protocol_name) + NameIdentifier(method.name);
-}
-
-std::string NameOrdinal(std::string_view method_name) {
-  std::string ordinal_name(method_name);
-  ordinal_name += "Ordinal";
-  return ordinal_name;
-}
-
-std::string NameMessage(std::string_view method_name, MessageKind kind) {
-  std::string message_name(method_name);
-  switch (kind) {
-    case MessageKind::kRequest:
-      message_name += "RequestMessage";
-      break;
-    case MessageKind::kResponse:
-      message_name += "ResponseMessage";
-      break;
-    case MessageKind::kEvent:
-      message_name += "EventMessage";
-      break;
-  }
-  return message_name;
-}
-
-std::string NameTable(std::string_view table_name) { return std::string(table_name) + "Table"; }
-
-std::string NamePointer(std::string_view name) {
-  std::string pointer_name("Pointer");
-  pointer_name += LengthPrefixedString(name);
-  return pointer_name;
-}
-
-std::string NameMembers(std::string_view name) {
-  std::string members_name("Members");
-  members_name += LengthPrefixedString(name);
-  return members_name;
-}
-
-std::string NameFields(std::string_view name) {
-  std::string fields_name("Fields");
-  fields_name += LengthPrefixedString(name);
-  return fields_name;
-}
-
-std::string NameFieldsAltField(std::string_view name, uint32_t field_num) {
-  std::ostringstream fields_alt_field_name;
-  fields_alt_field_name << NameFields(name);
-  fields_alt_field_name << "_field";
-  fields_alt_field_name << field_num;
-  fields_alt_field_name << "_alt_field";
-  return fields_alt_field_name.str();
-}
-
-std::string NameCodedName(const Name& name) { return FormatName(name, "_", "_"); }
-
-std::string NameCodedNullableName(const Name& name) {
-  std::ostringstream nullable_name;
-  nullable_name << NameCodedName(name);
-  nullable_name << "NullableRef";
-  return nullable_name.str();
-}
-
-std::string NameCodedHandle(HandleSubtype subtype, RightsWrappedType rights,
-                            Nullability nullability) {
-  std::string name("Handle");
-  name += NameHandleSubtype(subtype);
-  name += NameHandleRights(rights);
-  name += NameNullability(nullability);
-  return name;
-}
-
-std::string NameCodedProtocolHandle(std::string_view protocol_name, Nullability nullability) {
-  std::string name("Protocol");
-  name += LengthPrefixedString(protocol_name);
-  name += NameNullability(nullability);
-  return name;
-}
-
-std::string NameCodedRequestHandle(std::string_view protocol_name, Nullability nullability) {
-  std::string name("Request");
-  name += LengthPrefixedString(protocol_name);
-  name += NameNullability(nullability);
-  return name;
-}
-
-std::string NameCodedArray(std::string_view element_name, uint64_t size) {
-  std::string name("Array");
-  name += NameSize(size);
-  name += "_";
-  name += LengthPrefixedString(element_name);
-  return name;
-}
-
-std::string NameCodedVector(std::string_view element_name, uint64_t max_size,
-                            Nullability nullability) {
-  std::string name("Vector");
-  name += NameSize(max_size);
-  name += NameNullability(nullability);
-  name += LengthPrefixedString(element_name);
-  return name;
-}
-
-std::string NameCodedString(uint64_t max_size, Nullability nullability) {
-  std::string name("String");
-  name += NameSize(max_size);
-  name += NameNullability(nullability);
-  return name;
-}
-
-std::string NameCodedZxExperimentalPointer(std::string_view pointee_name) {
-  std::string name("ZxExperimentalPointer");
-  name += LengthPrefixedString(pointee_name);
-  return name;
+std::string FullyQualifiedName(const Name& name) {
+  if (name.is_intrinsic())
+    return name.full_name();
+  return name.library()->name + "/" + name.full_name();
 }
 
 }  // namespace fidlc
diff --git a/tools/fidl/fidlc/src/names.h b/tools/fidl/fidlc/src/names.h
index 4f71448..4907958 100644
--- a/tools/fidl/fidlc/src/names.h
+++ b/tools/fidl/fidlc/src/names.h
@@ -5,56 +5,20 @@
 #ifndef TOOLS_FIDL_FIDLC_SRC_NAMES_H_
 #define TOOLS_FIDL_FIDLC_SRC_NAMES_H_
 
-#include <string>
-#include <string_view>
-
-#include "tools/fidl/fidlc/src/flat_ast.h"
 #include "tools/fidl/fidlc/src/properties.h"
 #include "tools/fidl/fidlc/src/raw_ast.h"
+#include "tools/fidl/fidlc/src/types.h"
+#include "tools/fidl/fidlc/src/values.h"
 
 namespace fidlc {
 
-std::string NameIdentifier(SourceSpan name);
-
-std::string NameLibrary(const std::vector<std::unique_ptr<RawIdentifier>>& components);
-std::string NameLibrary(const std::vector<std::string_view>& library_name);
-std::string NameLibraryCHeader(const std::vector<std::string_view>& library_name);
-
 std::string NameHandleSubtype(HandleSubtype subtype);
-std::string NameHandleRights(RightsWrappedType rights);
-std::string NameHandleZXObjType(HandleSubtype subtype);
-
 std::string NameRawLiteralKind(RawLiteral::Kind kind);
-
-std::string NameFlatName(const Name& name);
-std::string NameFlatConstantKind(Constant::Kind kind);
-std::string NameFlatTypeKind(const Type* type);
-std::string NameUnionTag(std::string_view union_name, const Union::Member& member);
-std::string NameFlatConstant(const Constant* constant);
-std::string NameFlatBinaryOperator(BinaryOperatorConstant::Operator op);
-std::string NameFlatType(const Type* type);
-std::string NameDiscoverable(const Protocol& protocol);
-std::string NameMethod(std::string_view protocol_name, const Protocol::Method& method);
-std::string NameOrdinal(std::string_view method_name);
-std::string NameMessage(std::string_view method_name, MessageKind kind);
-
-std::string NameTable(std::string_view table_name);
-std::string NamePointer(std::string_view name);
-std::string NameMembers(std::string_view name);
-std::string NameFields(std::string_view name);
-std::string NameFieldsAltField(std::string_view name, uint32_t field_num);
-
-std::string NameCodedName(const Name& name);
-std::string NameCodedNullableName(const Name& name);
-std::string NameCodedHandle(HandleSubtype subtype, RightsWrappedType rights,
-                            Nullability nullability);
-std::string NameCodedProtocolHandle(std::string_view protocol_name, Nullability nullability);
-std::string NameCodedRequestHandle(std::string_view protocol_name, Nullability nullability);
-std::string NameCodedArray(std::string_view element_name, uint64_t size);
-std::string NameCodedVector(std::string_view element_name, uint64_t max_size,
-                            Nullability nullability);
-std::string NameCodedString(uint64_t max_size, Nullability nullability);
-std::string NameCodedZxExperimentalPointer(std::string_view pointee_name);
+std::string NameConstantKind(Constant::Kind kind);
+std::string NameConstant(const Constant* constant);
+std::string NameTypeKind(const Type* type);
+std::string NameType(const Type* type);
+std::string FullyQualifiedName(const Name& name);
 
 }  // namespace fidlc
 
diff --git a/tools/fidl/fidlc/src/ordinals.cc b/tools/fidl/fidlc/src/ordinals.cc
deleted file mode 100644
index 24109c8..0000000
--- a/tools/fidl/fidlc/src/ordinals.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/fidl/fidlc/src/ordinals.h"
-
-#include <zircon/assert.h>
-
-#define BORINGSSL_NO_CXX
-#include <openssl/sha.h>
-
-#include "tools/fidl/fidlc/src/attributes.h"
-#include "tools/fidl/fidlc/src/raw_ast.h"
-
-namespace fidlc {
-
-std::string GetSelector(const AttributeList* attributes, SourceSpan name) {
-  const Attribute* maybe_selector_attr = attributes->Get("selector");
-  if (maybe_selector_attr != nullptr) {
-    auto selector_constant = maybe_selector_attr->GetArg(AttributeArg::kDefaultAnonymousName);
-    if (selector_constant != nullptr && selector_constant->value->IsResolved()) {
-      ZX_ASSERT(selector_constant->value->Value().kind == ConstantValue::Kind::kString);
-      auto& selector_string_constant =
-          static_cast<const StringConstantValue&>(selector_constant->value->Value());
-      return selector_string_constant.MakeContents();
-    }
-  }
-  return std::string(name.data().data(), name.data().size());
-}
-
-namespace {
-
-uint64_t CalcOrdinal(const std::string_view& full_name) {
-  uint8_t digest[SHA256_DIGEST_LENGTH];
-  SHA256(reinterpret_cast<const uint8_t*>(full_name.data()), full_name.size(), digest);
-  // The following dance ensures that we treat the bytes as a little-endian
-  // int64 regardless of host byte order.
-  // clang-format off
-  uint64_t ordinal =
-      static_cast<uint64_t>(digest[0]) |
-      static_cast<uint64_t>(digest[1]) << 8 |
-      static_cast<uint64_t>(digest[2]) << 16 |
-      static_cast<uint64_t>(digest[3]) << 24 |
-      static_cast<uint64_t>(digest[4]) << 32 |
-      static_cast<uint64_t>(digest[5]) << 40 |
-      static_cast<uint64_t>(digest[6]) << 48 |
-      static_cast<uint64_t>(digest[7]) << 56;
-  // clang-format on
-
-  return ordinal & 0x7fffffffffffffff;
-}
-
-}  // namespace
-
-RawOrdinal64 GetGeneratedOrdinal64(const std::vector<std::string_view>& library_name,
-                                   const std::string_view& protocol_name,
-                                   const std::string_view& selector_name,
-                                   const SourceElement& source_element) {
-  if (selector_name.find('/') != std::string_view::npos)
-    return RawOrdinal64(source_element, CalcOrdinal(selector_name));
-
-  // TODO(https://fxbug.dev/42069446): Move this closer (code wise) to NameFlatName, ideally sharing
-  // code.
-  std::string full_name;
-  bool once = false;
-  for (std::string_view id : library_name) {
-    if (once) {
-      full_name.push_back('.');
-    } else {
-      once = true;
-    }
-    full_name.append(id.data(), id.size());
-  }
-  full_name.append("/");
-  full_name.append(protocol_name.data(), protocol_name.size());
-  full_name.append(".");
-  full_name.append(selector_name);
-
-  return RawOrdinal64(source_element, CalcOrdinal(full_name));
-}
-
-}  // namespace fidlc
diff --git a/tools/fidl/fidlc/src/ordinals.h b/tools/fidl/fidlc/src/ordinals.h
deleted file mode 100644
index 9a0ae50e..0000000
--- a/tools/fidl/fidlc/src/ordinals.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef TOOLS_FIDL_FIDLC_SRC_ORDINALS_H_
-#define TOOLS_FIDL_FIDLC_SRC_ORDINALS_H_
-
-#include <lib/fit/function.h>
-
-#include <string_view>
-
-#include "tools/fidl/fidlc/src/source_span.h"
-
-namespace fidlc {
-
-struct AttributeList;
-struct RawOrdinal64;
-struct SourceElement;
-
-// Ordinals for method error result unions.
-const uint64_t kSuccessOrdinal = 1;
-const uint64_t kDomainErrorOrdinal = 2;
-const uint64_t kFrameworkErrorOrdinal = 3;
-
-using MethodHasher = fit::function<RawOrdinal64(
-    const std::vector<std::string_view>& library_name, const std::string_view& protocol_name,
-    const std::string_view& selector_name, const SourceElement& source_element)>;
-
-// Returns the selector. If the @selector attribute is present, the
-// function returns its value; otherwise, it returns the name parameter.
-std::string GetSelector(const AttributeList* attributes, SourceSpan name);
-
-// Computes the 64bits ordinal for this |method|.
-//
-// The ordinal value is equal to
-//
-//    *((int64_t *)sha256(library_name + "/" + protocol_name + "." + selector_name)) &
-//    0x7fffffffffffffff;
-//
-// Note: the slash separator is between the library_name and protocol_name.
-//
-// The selector_name is retrieved using GetSelector.
-RawOrdinal64 GetGeneratedOrdinal64(const std::vector<std::string_view>& library_name,
-                                   const std::string_view& protocol_name,
-                                   const std::string_view& selector_name,
-                                   const SourceElement& source_element);
-
-}  // namespace fidlc
-
-#endif  // TOOLS_FIDL_FIDLC_SRC_ORDINALS_H_
diff --git a/tools/fidl/fidlc/src/parser.cc b/tools/fidl/fidlc/src/parser.cc
index 1cb7d06..95e079e 100644
--- a/tools/fidl/fidlc/src/parser.cc
+++ b/tools/fidl/fidlc/src/parser.cc
@@ -58,19 +58,20 @@
 std::nullptr_t Parser::Fail() { return Fail(ErrUnexpectedToken); }
 
 template <ErrorId Id, typename... Args>
-std::nullptr_t Parser::Fail(const ErrorDef<Id, Args...>& err, const identity_t<Args>&... args) {
+std::nullptr_t Parser::Fail(const ErrorDef<Id, Args...>& err,
+                            const cpp20::type_identity_t<Args>&... args) {
   return Fail(err, last_token_, args...);
 }
 
 template <ErrorId Id, typename... Args>
 std::nullptr_t Parser::Fail(const ErrorDef<Id, Args...>& err, const Token token,
-                            const identity_t<Args>&... args) {
+                            const cpp20::type_identity_t<Args>&... args) {
   return Fail(err, token.span(), args...);
 }
 
 template <ErrorId Id, typename... Args>
 std::nullptr_t Parser::Fail(const ErrorDef<Id, Args...>& err, SourceSpan span,
-                            const identity_t<Args>&... args) {
+                            const cpp20::type_identity_t<Args>&... args) {
   if (Ok()) {
     reporter_->Fail(err, span, args...);
   }
@@ -1456,7 +1457,7 @@
       }
       case Token::Kind::kColon: {
         ConstraintOrSubtype after_colon = ParseTokenAfterColon();
-        std::visit(matchers{
+        std::visit(overloaded{
                        [&](std::unique_ptr<RawTypeConstraints>& constraint) -> void {
                          if (constraints != nullptr) {
                            Fail(ErrMultipleConstraintDefinitions, previous_token_.span());
@@ -1498,7 +1499,7 @@
   ZX_ASSERT_MSG(std::holds_alternative<std::unique_ptr<RawCompoundIdentifier>>(layout) ||
                     std::holds_alternative<std::unique_ptr<RawLayout>>(layout),
                 "must have set layout by this point");
-  std::visit(matchers{
+  std::visit(overloaded{
                  [&](std::unique_ptr<RawCompoundIdentifier>& named_layout) -> void {
                    layout_ref = std::make_unique<RawNamedLayoutReference>(
                        SourceElement(named_layout->start_token, named_layout->end_token),
diff --git a/tools/fidl/fidlc/src/parser.h b/tools/fidl/fidlc/src/parser.h
index 8abece8..4cca590 100644
--- a/tools/fidl/fidlc/src/parser.h
+++ b/tools/fidl/fidlc/src/parser.h
@@ -204,13 +204,14 @@
   // * They return nullptr rather than false.
   std::nullptr_t Fail();
   template <ErrorId Id, typename... Args>
-  std::nullptr_t Fail(const ErrorDef<Id, Args...>& err, const identity_t<Args>&... args);
+  std::nullptr_t Fail(const ErrorDef<Id, Args...>& err,
+                      const cpp20::type_identity_t<Args>&... args);
   template <ErrorId Id, typename... Args>
   std::nullptr_t Fail(const ErrorDef<Id, Args...>& err, Token token,
-                      const identity_t<Args>&... args);
+                      const cpp20::type_identity_t<Args>&... args);
   template <ErrorId Id, typename... Args>
   std::nullptr_t Fail(const ErrorDef<Id, Args...>& err, SourceSpan span,
-                      const identity_t<Args>&... args);
+                      const cpp20::type_identity_t<Args>&... args);
 
   // Reports an error if |modifiers| contains a modifier whose type is not
   // included in |Allowlist|. The |decl_token| should be "struct", "enum", etc.
diff --git a/tools/fidl/fidlc/src/raw_ast.cc b/tools/fidl/fidlc/src/raw_ast.cc
index e18b09c..0e559ff 100644
--- a/tools/fidl/fidlc/src/raw_ast.cc
+++ b/tools/fidl/fidlc/src/raw_ast.cc
@@ -28,6 +28,17 @@
   }
 }
 
+std::string RawCompoundIdentifier::ToString() const {
+  std::string str;
+  str.reserve(span().data().size());
+  for (auto it = components.begin(); it != components.end(); ++it) {
+    if (it != components.begin())
+      str.push_back('.');
+    str.append((*it)->span().data());
+  }
+  return str;
+}
+
 void RawDocCommentLiteral::Accept(TreeVisitor* visitor) const {
   SourceElementMark sem(visitor, *this);
 }
diff --git a/tools/fidl/fidlc/src/raw_ast.h b/tools/fidl/fidlc/src/raw_ast.h
index 091dfde..40574b1 100644
--- a/tools/fidl/fidlc/src/raw_ast.h
+++ b/tools/fidl/fidlc/src/raw_ast.h
@@ -93,6 +93,7 @@
       : SourceElement(element), components(std::move(components)) {}
 
   void Accept(TreeVisitor* visitor) const;
+  std::string ToString() const;
 
   std::vector<std::unique_ptr<RawIdentifier>> components;
 };
@@ -112,29 +113,22 @@
 
 struct RawDocCommentLiteral final : public RawLiteral {
   explicit RawDocCommentLiteral(const SourceElement& element)
-      : RawLiteral(element, Kind::kDocComment) {}
+      : RawLiteral(element, Kind::kDocComment),
+        value(StripDocCommentSlashes(element.span().data())) {}
 
   void Accept(TreeVisitor* visitor) const;
 
-  std::string MakeContents() const {
-    if (!has_span() || span().data().empty()) {
-      return "";
-    }
-    return strip_doc_comment_slashes(span().data());
-  }
+  std::string value;
 };
 
 struct RawStringLiteral final : public RawLiteral {
-  explicit RawStringLiteral(const SourceElement& element) : RawLiteral(element, Kind::kString) {}
+  explicit RawStringLiteral(const SourceElement& element)
+      : RawLiteral(element, Kind::kString),
+        value(StripStringLiteralQuotes(element.span().data())) {}
 
   void Accept(TreeVisitor* visitor) const;
 
-  std::string MakeContents() const {
-    if (!has_span() || span().data().empty()) {
-      return "";
-    }
-    return strip_string_literal_quotes(span().data());
-  }
+  std::string value;
 };
 
 struct RawNumericLiteral final : public RawLiteral {
diff --git a/tools/fidl/fidlc/src/reference.cc b/tools/fidl/fidlc/src/reference.cc
index d578653..e67a531 100644
--- a/tools/fidl/fidlc/src/reference.cc
+++ b/tools/fidl/fidlc/src/reference.cc
@@ -68,7 +68,7 @@
 Reference::Reference(Target target) : state_(RawSynthetic{target}) {}
 
 Reference::State Reference::state() const {
-  return std::visit(matchers{
+  return std::visit(overloaded{
                         [&](const RawSourced&) { return State::kRawSourced; },
                         [&](const RawSynthetic&) { return State::kRawSynthetic; },
                         [&](const Key&) { return State::kKey; },
diff --git a/tools/fidl/fidlc/src/reporter.h b/tools/fidl/fidlc/src/reporter.h
index a2cf172..51064ce 100644
--- a/tools/fidl/fidlc/src/reporter.h
+++ b/tools/fidl/fidlc/src/reporter.h
@@ -35,7 +35,8 @@
   };
 
   template <ErrorId Id, typename... Args>
-  bool Fail(const ErrorDef<Id, Args...>& def, SourceSpan span, const identity_t<Args>&... args) {
+  bool Fail(const ErrorDef<Id, Args...>& def, SourceSpan span,
+            const cpp20::type_identity_t<Args>&... args) {
     static_assert(Id <= kNumDiagnosticDefs,
                   "please add this ErrorDef to kAllDiagnosticDefs in diagnostics.h");
     Report(Diagnostic::MakeError(def, span, args...));
@@ -43,7 +44,8 @@
   }
 
   template <ErrorId Id, typename... Args>
-  void Warn(const WarningDef<Id, Args...>& def, SourceSpan span, const identity_t<Args>&... args) {
+  void Warn(const WarningDef<Id, Args...>& def, SourceSpan span,
+            const cpp20::type_identity_t<Args>&... args) {
     static_assert(Id <= kNumDiagnosticDefs,
                   "please add this WarningDef to kAllDiagnosticDefs in diagnostics.h");
     Report(Diagnostic::MakeWarning(def, span, args...));
diff --git a/tools/fidl/fidlc/src/resolve_step.cc b/tools/fidl/fidlc/src/resolve_step.cc
index 5e1a146..6af61e8 100644
--- a/tools/fidl/fidlc/src/resolve_step.cc
+++ b/tools/fidl/fidlc/src/resolve_step.cc
@@ -308,7 +308,7 @@
  public:
   Lookup(ResolveStep* step, const Reference& ref) : step_(step), ref_(ref) {}
 
-  const Library* TryLibrary(const std::vector<std::string_view>& name) {
+  const Library* TryLibrary(std::string_view name) {
     auto root_library = step_->all_libraries()->root_library();
     if (name == root_library->name) {
       return root_library;
@@ -342,7 +342,7 @@
     if (auto key = TryDecl(library, name)) {
       return key;
     }
-    reporter()->Fail(ErrNameNotFound, ref_.span(), name, library->name);
+    reporter()->Fail(ErrNameNotFound, ref_.span(), name, library);
     return std::nullopt;
   }
 
@@ -452,37 +452,8 @@
 }
 
 void ResolveStep::ParseSourcedReference(Reference& ref, Context context) {
-  // TOOD(https://fxbug.dev/42157590): Move this information to the FIDL language spec.
-  //
-  // Below is an outline of FIDL scoping semantics. We navigate it by moving
-  // down and to the right. That is, if a rule succeeds, we proceed to the
-  // indented one below it (if there is none, SUCCESS); if a rule fails, we try
-  // the same-indentation one below it (if there is none, FAIL).
-  //
-  // - X
-  //     - Resolve X as a decl within the current library.
-  //     - Resolve X as a decl within the root library.
-  //     - Resolve X as a contextual bits/enum member, if context exists.
-  // - X.Y
-  //     - Resolve X as a decl within the current library.
-  //         - Resolve Y as a member of X.
-  //     - Resolve X as a library name or alias.
-  //         - Resolve Y as a decl within X.
-  // - x.Y.Z where x represents 1+ components
-  //     - Resolve x.Y as a library name or alias.
-  //         - Resolve Z as a decl within x.Y.
-  //     - Resolve x as a library name or alias.
-  //         - Resolve Y as a decl within x.
-  //             - Resolve Z as a member of Y.
-  //
-  // Note that if you import libraries A and A.B, you cannot refer to bits/enum
-  // member [library A].B.C because it is interpreted as decl [library A.B].C.
-  // To do so, you must remove or alias one of the imports. We implement this
-  // behavior even if [library A.B].C does not exist, since otherwise
-  // introducing it would result in breakage at a distance. For FIDL code that
-  // follow the linter naming conventions (lowercase library, CamelCase decl),
-  // this will never come up in practice.
-
+  // This implements the identifier resolution algorithm from
+  // https://fuchsia.dev/fuchsia-src/reference/fidl/language/language#resolution-algorithm
   const auto& components = ref.raw_sourced().components;
   Lookup lookup(this, ref);
   switch (components.size()) {
@@ -494,25 +465,32 @@
       } else if (context.allow_contextual) {
         ref.MarkContextual();
       } else {
-        reporter()->Fail(ErrNameNotFound, ref.span(), components[0], library()->name);
+        reporter()->Fail(ErrNameNotFound, ref.span(), components[0], library());
       }
       break;
     }
     case 2: {
       if (auto key = lookup.TryDecl(library(), components[0])) {
         ref.SetKey(key.value().Member(components[1]));
-      } else if (auto dep_library = lookup.TryLibrary({components[0]})) {
+      } else if (auto dep_library = lookup.TryLibrary(components[0])) {
         if (auto key = lookup.MustDecl(dep_library, components[1])) {
           ref.SetKey(key.value());
         }
       } else {
-        reporter()->Fail(ErrNameNotFound, ref.span(), components[0], library()->name);
+        reporter()->Fail(ErrNameNotFound, ref.span(), components[0], library());
       }
       break;
     }
     default: {
-      std::vector<std::string_view> long_library_name(components.begin(), components.end() - 1);
-      std::vector<std::string_view> short_library_name(components.begin(), components.end() - 2);
+      std::string long_library_name;
+      size_t prev_size;
+      for (auto it = components.begin(); it != components.end() - 1; ++it) {
+        prev_size = long_library_name.size();
+        if (it != components.begin())
+          long_library_name.push_back('.');
+        long_library_name.append(*it);
+      }
+      auto short_library_name = std::string_view(long_library_name.data(), prev_size);
       if (auto dep_library = lookup.TryLibrary(long_library_name)) {
         if (auto key = lookup.MustDecl(dep_library, components.back())) {
           ref.SetKey(key.value());
@@ -589,13 +567,13 @@
   auto name = ref.contextual().name;
   auto subtype_enum = context.maybe_resource_subtype;
   if (!subtype_enum) {
-    reporter()->Fail(ErrNameNotFound, ref.span(), name, library()->name);
+    reporter()->Fail(ErrNameNotFound, ref.span(), name, library());
     return;
   }
   Lookup lookup(this, ref);
   auto member = lookup.TryMember(subtype_enum, name);
   if (!member) {
-    reporter()->Fail(ErrNameNotFound, ref.span(), name, library()->name);
+    reporter()->Fail(ErrNameNotFound, ref.span(), name, library());
     return;
   }
   ref.ResolveTo(Reference::Target(member, subtype_enum));
@@ -636,7 +614,7 @@
     }
     // TODO(https://fxbug.dev/42146818): Provide a nicer error message in the case where a
     // decl with that name does exist, but in a different version range.
-    reporter()->Fail(ErrNameNotFound, ref.span(), key.decl_name, key.library->name);
+    reporter()->Fail(ErrNameNotFound, ref.span(), key.decl_name, key.library);
     return nullptr;
   }
   // Case #2: source and target libraries are versioned in different platforms.
@@ -649,7 +627,7 @@
   }
   // TODO(https://fxbug.dev/42146818): Provide a nicer error message in the case where
   // a decl with that name does exist, but in a different version range.
-  reporter()->Fail(ErrNameNotFound, ref.span(), key.decl_name, key.library->name);
+  reporter()->Fail(ErrNameNotFound, ref.span(), key.decl_name, key.library);
   return nullptr;
 }
 
diff --git a/tools/fidl/fidlc/src/span_sequence_tree_visitor.h b/tools/fidl/fidlc/src/span_sequence_tree_visitor.h
index 4e093a9..d05cd68 100644
--- a/tools/fidl/fidlc/src/span_sequence_tree_visitor.h
+++ b/tools/fidl/fidlc/src/span_sequence_tree_visitor.h
@@ -8,6 +8,7 @@
 #include <lib/stdcompat/span.h>
 #include <zircon/assert.h>
 
+#include <set>
 #include <stack>
 
 #include "tools/fidl/fidlc/src/raw_ast.h"
diff --git a/tools/fidl/fidlc/src/transport.cc b/tools/fidl/fidlc/src/transport.cc
index 065e0e3..a403ddb 100644
--- a/tools/fidl/fidlc/src/transport.cc
+++ b/tools/fidl/fidlc/src/transport.cc
@@ -4,26 +4,17 @@
 
 #include "tools/fidl/fidlc/src/transport.h"
 
+#include "tools/fidl/fidlc/src/flat_ast.h"
+
 namespace fidlc {
 
-std::string_view HandleClassName(HandleClass handle_class) {
-  switch (handle_class) {
-    case HandleClass::kZircon:
-      return "zx.Handle";
-    case HandleClass::kDriver:
-      return "fdf.handle";
-    case HandleClass::kBanjo:
-      return "[banjo]";
-  };
-}
-
-std::optional<HandleClass> HandleClassFromName(std::string_view name) {
-  if (name == "zx.Handle") {
+std::optional<HandleClass> HandleClassFromName(const Name& name) {
+  auto& library = name.library()->name;
+  auto decl = name.decl_name();
+  if (library == "zx" && decl == "Handle")
     return HandleClass::kZircon;
-  }
-  if (name == "fdf.handle") {
+  if (library == "fdf" && decl == "handle")
     return HandleClass::kDriver;
-  }
   return std::nullopt;
 }
 
diff --git a/tools/fidl/fidlc/src/transport.h b/tools/fidl/fidlc/src/transport.h
index 266d009..a6b9e85 100644
--- a/tools/fidl/fidlc/src/transport.h
+++ b/tools/fidl/fidlc/src/transport.h
@@ -9,6 +9,8 @@
 #include <set>
 #include <vector>
 
+#include "tools/fidl/fidlc/src/name.h"
+
 namespace fidlc {
 
 // The class / namespace of the handle, used for compatibility checking with
@@ -19,8 +21,7 @@
   kBanjo,   // only referenced by client_end / server_end
 };
 
-std::string_view HandleClassName(HandleClass handle_class);
-std::optional<HandleClass> HandleClassFromName(std::string_view name);
+std::optional<HandleClass> HandleClassFromName(const Name& name);
 
 struct Transport {
   enum class Kind : uint8_t {
diff --git a/tools/fidl/fidlc/src/utils.cc b/tools/fidl/fidlc/src/utils.cc
index c670dc6..dbedf04 100644
--- a/tools/fidl/fidlc/src/utils.cc
+++ b/tools/fidl/fidlc/src/utils.cc
@@ -16,6 +16,8 @@
 
 const std::string kLibraryComponentPattern = "[a-z][a-z0-9]*";
 const std::string kIdentifierComponentPattern = "[A-Za-z]([A-Za-z0-9_]*[A-Za-z0-9])?";
+const std::string kLibraryPattern =
+    kLibraryComponentPattern + "(\\." + kLibraryComponentPattern + ")*";
 
 bool IsValidLibraryComponent(std::string_view component) {
   static const re2::RE2 kPattern("^" + kLibraryComponentPattern + "$");
@@ -28,55 +30,24 @@
 }
 
 bool IsValidFullyQualifiedMethodIdentifier(std::string_view fq_identifier) {
-  static const re2::RE2 kPattern("^" +
-                                 // library identifier
-                                 kLibraryComponentPattern + "(\\." + kLibraryComponentPattern +
-                                 ")*" +
-                                 // slash
-                                 "/" +
-                                 // protocol
-                                 kIdentifierComponentPattern +
-                                 // dot
-                                 "\\." +
-                                 // method
-                                 kIdentifierComponentPattern + "$");
+  static const re2::RE2 kPattern("^" + kLibraryPattern + "/" +
+                                 /* protocol */ kIdentifierComponentPattern + "\\." +
+                                 /* method */ kIdentifierComponentPattern + "$");
   return re2::RE2::FullMatch(fq_identifier, kPattern);
 }
 
 bool IsValidDiscoverableName(std::string_view discoverable_name) {
-  static const re2::RE2 kPattern("^" +
-                                 // library identifier
-                                 kLibraryComponentPattern + "(\\." + kLibraryComponentPattern +
-                                 ")*" +
-                                 // dot
-                                 "\\." +
-                                 // protocol
-                                 kIdentifierComponentPattern + "$");
+  static const re2::RE2 kPattern("^" + kLibraryPattern + "\\." + kIdentifierComponentPattern + "$");
   return re2::RE2::FullMatch(discoverable_name, kPattern);
 }
 
-bool ends_with_underscore(std::string_view str) {
-  ZX_ASSERT(!str.empty());
-  return str.back() == '_';
-}
-
-bool has_adjacent_underscores(std::string_view str) { return str.find("__") != std::string::npos; }
-
-bool has_konstant_k(std::string_view str) {
-  return str.size() >= 2 && str[0] == 'k' && isupper(str[1]);
-}
-
-std::string strip_string_literal_quotes(std::string_view str) {
+std::string StripStringLiteralQuotes(std::string_view str) {
   ZX_ASSERT_MSG(str.size() >= 2 && str[0] == '"' && str[str.size() - 1] == '"',
                 "string must start and end with '\"' style quotes");
   return std::string(str.data() + 1, str.size() - 2);
 }
 
-// NOTE: we currently explicitly only support UNIX line endings
-std::string strip_doc_comment_slashes(std::string_view str) {
-  // In English, this regex says: "any number of tabs/spaces, followed by three
-  // slashes is group 1, the remainder of the line is group 2.  Keep only group
-  // 2."
+std::string StripDocCommentSlashes(std::string_view str) {
   std::string no_slashes(str);
   re2::RE2::GlobalReplace(&no_slashes, "([\\t ]*\\/\\/\\/)(.*)", "\\2");
   if (no_slashes[no_slashes.size() - 1] != '\n') {
@@ -85,59 +56,40 @@
   return no_slashes;
 }
 
-std::string strip_konstant_k(std::string_view str) {
-  return std::string(has_konstant_k(str) ? str.substr(1) : str);
+static bool HasConstantK(std::string_view str) {
+  return str.size() >= 2 && str[0] == 'k' && isupper(str[1]);
 }
 
-bool is_lower_no_separator_case(std::string_view str) {
-  static re2::RE2 re{"^[a-z][a-z0-9]*$"};
-  return !str.empty() && re2::RE2::FullMatch(str, re);
+static std::string StripConstantK(std::string_view str) {
+  return std::string(HasConstantK(str) ? str.substr(1) : str);
 }
 
-bool is_lower_snake_case(std::string_view str) {
+bool IsLowerSnakeCase(std::string_view str) {
   static re2::RE2 re{"^[a-z][a-z0-9_]*$"};
   return !str.empty() && re2::RE2::FullMatch(str, re);
 }
 
-bool is_upper_snake_case(std::string_view str) {
+bool IsUpperSnakeCase(std::string_view str) {
   static re2::RE2 re{"^[A-Z][A-Z0-9_]*$"};
   return !str.empty() && re2::RE2::FullMatch(str, re);
 }
 
-bool is_lower_camel_case(std::string_view str) {
-  if (has_konstant_k(str)) {
+bool IsLowerCamelCase(std::string_view str) {
+  if (HasConstantK(str)) {
     return false;
   }
   static re2::RE2 re{"^[a-z][a-z0-9]*(([A-Z]{1,2}[a-z0-9]+)|(_[0-9]+))*([A-Z][a-z0-9]*)?$"};
   return !str.empty() && re2::RE2::FullMatch(str, re);
 }
 
-bool is_upper_camel_case(std::string_view str) {
+bool IsUpperCamelCase(std::string_view str) {
   static re2::RE2 re{
       "^(([A-Z]{1,2}[a-z0-9]+)(([A-Z]{1,2}[a-z0-9]+)|(_[0-9]+))*)?([A-Z][a-z0-9]*)?$"};
   return !str.empty() && re2::RE2::FullMatch(str, re);
 }
 
-bool is_konstant_case(std::string_view astr) {
-  if (!has_konstant_k(astr)) {
-    return false;
-  }
-  std::string str = strip_konstant_k(astr);
-  return is_upper_camel_case(str);
-}
-
-static void add_word(const std::string& word, std::vector<std::string>& words,
-                     const std::set<std::string>& stop_words) {
-  if (stop_words.find(word) == stop_words.end()) {
-    words.push_back(word);
-  }
-}
-
-std::vector<std::string> id_to_words(std::string_view astr) { return id_to_words(astr, {}); }
-
-std::vector<std::string> id_to_words(std::string_view astr,
-                                     const std::set<std::string>& stop_words) {
-  std::string str = strip_konstant_k(astr);
+std::vector<std::string> SplitIdentifierWords(std::string_view astr) {
+  std::string str = StripConstantK(astr);
   std::vector<std::string> words;
   std::string word;
   bool last_char_was_upper_or_begin = true;
@@ -145,7 +97,7 @@
     char ch = str[i];
     if (ch == '_' || ch == '-' || ch == '.') {
       if (!word.empty()) {
-        add_word(word, words, stop_words);
+        words.push_back(word);
         word.clear();
       }
       last_char_was_upper_or_begin = true;
@@ -153,7 +105,7 @@
       bool next_char_is_lower = ((i + 1) < str.size()) && islower(str[i + 1]);
       if (isupper(ch) && (!last_char_was_upper_or_begin || next_char_is_lower)) {
         if (!word.empty()) {
-          add_word(word, words, stop_words);
+          words.push_back(word);
           word.clear();
         }
       }
@@ -162,24 +114,15 @@
     }
   }
   if (!word.empty()) {
-    add_word(word, words, stop_words);
+    words.push_back(word);
   }
   return words;
 }
 
-std::string to_lower_no_separator_case(std::string_view astr) {
-  std::string str = strip_konstant_k(astr);
+std::string ToLowerSnakeCase(std::string_view astr) {
+  std::string str = StripConstantK(astr);
   std::string newid;
-  for (const auto& word : id_to_words(str)) {
-    newid.append(word);
-  }
-  return newid;
-}
-
-std::string to_lower_snake_case(std::string_view astr) {
-  std::string str = strip_konstant_k(astr);
-  std::string newid;
-  for (const auto& word : id_to_words(str)) {
+  for (const auto& word : SplitIdentifierWords(str)) {
     if (!newid.empty()) {
       newid.push_back('_');
     }
@@ -188,18 +131,18 @@
   return newid;
 }
 
-std::string to_upper_snake_case(std::string_view astr) {
-  std::string str = strip_konstant_k(astr);
-  auto newid = to_lower_snake_case(str);
+std::string ToUpperSnakeCase(std::string_view astr) {
+  std::string str = StripConstantK(astr);
+  auto newid = ToLowerSnakeCase(str);
   std::transform(newid.begin(), newid.end(), newid.begin(), ::toupper);
   return newid;
 }
 
-std::string to_lower_camel_case(std::string_view astr) {
-  std::string str = strip_konstant_k(astr);
+std::string ToLowerCamelCase(std::string_view astr) {
+  std::string str = StripConstantK(astr);
   bool prev_char_was_digit = false;
   std::string newid;
-  for (const auto& word : id_to_words(str)) {
+  for (const auto& word : SplitIdentifierWords(str)) {
     if (newid.empty()) {
       newid.append(word);
     } else {
@@ -214,11 +157,11 @@
   return newid;
 }
 
-std::string to_upper_camel_case(std::string_view astr) {
-  std::string str = strip_konstant_k(astr);
+std::string ToUpperCamelCase(std::string_view astr) {
+  std::string str = StripConstantK(astr);
   bool prev_char_was_digit = false;
   std::string newid;
-  for (const auto& word : id_to_words(str)) {
+  for (const auto& word : SplitIdentifierWords(str)) {
     if (prev_char_was_digit && isdigit(word[0])) {
       newid.push_back('_');
     }
@@ -229,9 +172,7 @@
   return newid;
 }
 
-std::string to_konstant_case(std::string_view str) { return "k" + to_upper_camel_case(str); }
-
-std::string canonicalize(std::string_view identifier) {
+std::string Canonicalize(std::string_view identifier) {
   const auto size = identifier.size();
   std::string canonical;
   char prev = '_';
@@ -253,56 +194,7 @@
   return canonical;
 }
 
-std::string StringJoin(const std::vector<std::string_view>& strings, std::string_view separator) {
-  std::string result;
-  bool first = true;
-  for (const auto& part : strings) {
-    if (!first) {
-      result += separator;
-    }
-    first = false;
-    result += part;
-  }
-  return result;
-}
-
-void PrintFinding(std::ostream& os, const Finding& finding) {
-  os << finding.message() << " [";
-  os << finding.subcategory();
-  os << ']';
-  if (finding.suggestion().has_value()) {
-    auto& suggestion = finding.suggestion();
-    os << "; " << suggestion->description();
-    if (suggestion->replacement().has_value()) {
-      os << "\n    Proposed replacement:  '" << *suggestion->replacement() << "'";
-    }
-  }
-}
-
-std::vector<std::string> FormatFindings(const Findings& findings, bool enable_color) {
-  std::vector<std::string> lint;
-  for (auto& finding : findings) {
-    std::stringstream ss;
-    PrintFinding(ss, finding);
-    auto warning = Reporter::Format("warning", finding.span(), ss.str(), enable_color);
-    lint.push_back(warning);
-  }
-  return lint;
-}
-
-bool OnlyWhitespaceChanged(std::string_view unformatted_input, std::string_view formatted_output) {
-  std::string formatted(formatted_output);
-  auto formatted_end = std::remove_if(formatted.begin(), formatted.end(), isspace);
-  formatted.erase(formatted_end, formatted.end());
-
-  std::string unformatted(unformatted_input);
-  auto unformatted_end = std::remove_if(unformatted.begin(), unformatted.end(), isspace);
-  unformatted.erase(unformatted_end, unformatted.end());
-
-  return formatted == unformatted;
-}
-
-uint32_t decode_unicode_hex(std::string_view str) {
+uint32_t DecodeUnicodeHex(std::string_view str) {
   char* endptr;
   unsigned long codepoint = strtoul(str.data(), &endptr, 16);
   ZX_ASSERT(codepoint != ULONG_MAX);
@@ -310,7 +202,7 @@
   return codepoint;
 }
 
-static size_t utf8_size_for_codepoint(uint32_t codepoint) {
+static size_t Utf8SizeForCodepoint(uint32_t codepoint) {
   if (codepoint <= 0x7f) {
     return 1;
   }
@@ -324,8 +216,8 @@
   return 4;
 }
 
-std::uint32_t string_literal_length(std::string_view str) {
-  std::uint32_t count = 0;
+uint32_t StringLiteralLength(std::string_view str) {
+  uint32_t count = 0;
   auto it = str.begin();
   ZX_ASSERT(*it == '"');
   ++it;
@@ -351,8 +243,8 @@
             ++it;
           }
           auto codepoint =
-              decode_unicode_hex(std::string_view(&(*codepoint_begin), it - codepoint_begin));
-          count += utf8_size_for_codepoint(codepoint) - 1;
+              DecodeUnicodeHex(std::string_view(&(*codepoint_begin), it - codepoint_begin));
+          count += Utf8SizeForCodepoint(codepoint) - 1;
           break;
         }
         default:
@@ -365,4 +257,28 @@
   return count;
 }
 
+void PrintFinding(std::ostream& os, const Finding& finding) {
+  os << finding.message() << " [";
+  os << finding.subcategory();
+  os << ']';
+  if (finding.suggestion().has_value()) {
+    auto& suggestion = finding.suggestion();
+    os << "; " << suggestion->description();
+    if (suggestion->replacement().has_value()) {
+      os << "\n    Proposed replacement:  '" << *suggestion->replacement() << "'";
+    }
+  }
+}
+
+std::vector<std::string> FormatFindings(const Findings& findings, bool enable_color) {
+  std::vector<std::string> lint;
+  for (auto& finding : findings) {
+    std::stringstream ss;
+    PrintFinding(ss, finding);
+    auto warning = Reporter::Format("warning", finding.span(), ss.str(), enable_color);
+    lint.push_back(warning);
+  }
+  return lint;
+}
+
 }  // namespace fidlc
diff --git a/tools/fidl/fidlc/src/utils.h b/tools/fidl/fidlc/src/utils.h
index 87bf0425..516f098 100644
--- a/tools/fidl/fidlc/src/utils.h
+++ b/tools/fidl/fidlc/src/utils.h
@@ -6,11 +6,11 @@
 #define TOOLS_FIDL_FIDLC_SRC_UTILS_H_
 
 #include <errno.h>
+#include <lib/stdcompat/span.h>
 #include <zircon/assert.h>
 
 #include <clocale>
 #include <cstring>
-#include <set>
 #include <string>
 #include <string_view>
 
@@ -20,47 +20,13 @@
 
 namespace fidlc {
 
-// Compares pointers by the values they point to.
-template <typename T>
-struct PtrCompare {
-  bool operator()(const T* left, const T* right) const { return *left < *right; }
-};
-
-// Identity function for types, equivalent to C++20 std::type_identity. Often
-// used to prevent arguments from participating in template argument deduction.
-// https://en.cppreference.com/w/cpp/language/template_argument_deduction#Non-deduced_contexts
-//
-// We use this to make error reporting more ergonomic. For example:
-//
-//     template <ErrorId Id, typename Args...>
-//     void Fail(const ErrorDef<Id, Args...>& err, const identity_t<Args...>& args);
-//
-//     ErrorDef<12, const Foo*> ErrOops("...");
-//
-//     Foo* foo = /* ... */;
-//     Fail(ErrOops, foo);
-//
-// Without the identity wrapper, both `err` and `args` participate in deduction
-// for Args, so the compiler complains that `const Foo*` and `Foo*` don't match.
-// With the identity wrapper, it deduces Args to be <const Foo*> solely based on
-// `err`, and instantiates `Fail(const ErrorDef<12, const Foo*>&, const Foo*&)`.
-// From there, `Fail(ErrOops, foo)` works because of implicit conversions.
-template <typename T>
-struct identity {
-  using type = T;
-};
-template <typename T>
-using identity_t = typename identity<T>::type;
-
-// Helper object for creating a callable argument to std::visit by passing in
-// lambdas for handling each variant (code comes from
-// https://en.cppreference.com/w/cpp/utility/variant/visit)
+// The std::visit helper from https://en.cppreference.com/w/cpp/utility/variant/visit.
 template <class... Ts>
-struct matchers : Ts... {
+struct overloaded : Ts... {
   using Ts::operator()...;
 };
 template <class... Ts>
-matchers(Ts...) -> matchers<Ts...>;
+overloaded(Ts...) -> overloaded<Ts...>;
 
 // Clones a vector of unique_ptr by calling Clone() on each element.
 template <typename T>
@@ -73,72 +39,64 @@
   return cloned;
 }
 
-constexpr char kWhitespaceChars[] = " \t\n\v\f\r";
-constexpr char kWhitespaceNoNewlineChars[] = " \t\v\f\r";
-
-inline bool IsWhitespace(char ch) { return ch != '\0' && strchr(kWhitespaceChars, ch) != nullptr; }
-
-inline bool IsWhitespaceNoNewline(char ch) {
-  return ch != '\0' && strchr(kWhitespaceNoNewlineChars, ch) != nullptr;
-}
-
-// Returns true if the view has anything other than whitespace
-inline bool IsBlank(std::string_view view) {
-  return view.find_first_not_of(kWhitespaceChars) == std::string::npos;
-}
-
-// IsValidLibraryComponent validates individual components of a library
-// identifier.
-//
+// Validators for parts of the FIDL grammar.
 // See https://fuchsia.dev/fuchsia-src/reference/fidl/language/language#identifiers
 bool IsValidLibraryComponent(std::string_view component);
-
-// IsValidIdentifierComponent validates individual components of an identifier
-// (other than a library identifier).
-//
-// See https://fuchsia.dev/fuchsia-src/reference/fidl/language/language#identifiers
 bool IsValidIdentifierComponent(std::string_view component);
-
-// IsValidFullyQualifiedMethodIdentifier validates fully qualified method
-// identifiers, i.e. a library identifier, followed by a slash, followed by a
-// protocol identifier, a dot, and lastly the method name.
 bool IsValidFullyQualifiedMethodIdentifier(std::string_view fq_identifier);
 
-// IsValidDiscoverableName validates a name for use in service discovery. This
-// is like a fully qualified identifier, but uses a dot instead of a slash so
-// that it can be used as a single component in a filesystem path.
+// Validates a @discoverable name. This is like a fully qualified identifier,
+// but uses a dot instead of a slash so it can be used in a filesystem path.
 bool IsValidDiscoverableName(std::string_view discoverable_name);
 
-inline bool LineFromOffsetIsBlank(std::string_view str, size_t offset) {
-  for (size_t i = offset; i < str.size() && str[i] != '\n'; i++) {
-    if (!IsWhitespaceNoNewline(str[i])) {
-      return false;
-    }
-  }
-  return true;
+// Removes the double quotes from the start and end of a string literal.
+std::string StripStringLiteralQuotes(std::string_view str);
+// Removes the indentation and "///" from each line of a doc comment.
+std::string StripDocCommentSlashes(std::string_view str);
+
+bool IsLowerSnakeCase(std::string_view str);
+bool IsUpperSnakeCase(std::string_view str);
+bool IsLowerCamelCase(std::string_view str);
+bool IsUpperCamelCase(std::string_view str);
+
+std::string ToLowerSnakeCase(std::string_view str);
+std::string ToUpperSnakeCase(std::string_view str);
+std::string ToLowerCamelCase(std::string_view str);
+std::string ToUpperCamelCase(std::string_view str);
+
+// Splits an identifier into lowercase words. Works for any naming style.
+std::vector<std::string> SplitIdentifierWords(std::string_view str);
+
+// Returns the canonical form of an identifier, used to detect name collisions
+// in FIDL libraries. For example, the identifiers "FooBar" and "FOO_BAR"
+// collide because both canonicalize to "foo_bar".
+std::string Canonicalize(std::string_view identifier);
+
+// Decodes 1 to 6 hex digits like "a" or "123" or "FFFFFF".
+uint32_t DecodeUnicodeHex(std::string_view str);
+
+// Given the source code of a string literal (including the double quotes),
+// returns the length of the UTF-8 string it represents in bytes.
+uint32_t StringLiteralLength(std::string_view str);
+
+// Returns the first component of a name with 0 or more dots, e.g. "foo.bar" -> "foo".
+inline std::string_view FirstComponent(std::string_view name) {
+  return name.substr(0, name.find('.'));
 }
 
-inline bool FirstLineIsBlank(std::string_view str) { return LineFromOffsetIsBlank(str, 0); }
-
-inline bool LineFromOffsetIsRegularComment(std::string_view view, size_t offset) {
-  size_t i = offset;
-  if ((i + 1 < view.size()) && view[i] == '/' && view[i + 1] == '/') {
-    // Doc comments, which start with three slashes, should not
-    // be treated as comments since they get internally converted
-    // to attributes. But comments that start with more than three
-    // slashes are not converted to doc comment attributes.
-    if (view.size() == 2) {
-      return true;
-    }
-    return (i + 2 == view.size()) || (view[i + 2] != '/') ||
-           ((i + 3 < view.size()) && (view[i + 3] == '/'));
-  }
-  return false;
+// Removes all whitespace characters from a string.
+inline std::string RemoveWhitespace(std::string str) {
+  str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
+  return str;
 }
 
-inline bool FirstLineIsRegularComment(std::string_view view) {
-  return LineFromOffsetIsRegularComment(view, 0);
-}
+// Used by fidl-lint FormatFindings, and for testing, this generates the linter
+// error message string in the format required for the Reporter.
+void PrintFinding(std::ostream& os, const Finding& finding);
+
+// Used by fidl-lint main() and for testing, this generates the linter error
+// messages for a list of findings.
+std::vector<std::string> FormatFindings(const Findings& findings, bool enable_color);
 
 enum class ParseNumericResult : uint8_t {
   kSuccess,
@@ -163,8 +121,7 @@
     if (input[0] == '-')
       return ParseNumericResult::kOutOfBounds;
     errno = 0;
-    // NOLINTNEXTLINE(google-runtime-int): strtoull returns unsigned long long.
-    unsigned long long value = strtoull(startptr, &endptr, base);
+    auto value = strtoull(startptr, &endptr, base);
     if (errno != 0)
       return ParseNumericResult::kMalformed;
     if (value > std::numeric_limits<NumericType>::max())
@@ -172,8 +129,7 @@
     *out_value = static_cast<NumericType>(value);
   } else if constexpr (std::is_integral_v<NumericType> && std::is_signed_v<NumericType>) {
     errno = 0;
-    // NOLINTNEXTLINE(google-runtime-int): strtoll returns long long.
-    long long value = strtoll(startptr, &endptr, base);
+    auto value = strtoll(startptr, &endptr, base);
     if (errno != 0)
       return ParseNumericResult::kMalformed;
     if (value > std::numeric_limits<NumericType>::max())
@@ -199,68 +155,6 @@
   return ParseNumericResult::kSuccess;
 }
 
-bool ends_with_underscore(std::string_view str);
-bool has_adjacent_underscores(std::string_view str);
-
-std::vector<std::string> id_to_words(std::string_view str);
-
-// Split the identifier into words, excluding words in the |stop_words| set.
-std::vector<std::string> id_to_words(std::string_view str, const std::set<std::string>& stop_words);
-
-bool is_konstant_case(std::string_view str);
-bool is_lower_no_separator_case(std::string_view str);
-bool is_lower_snake_case(std::string_view str);
-bool is_upper_snake_case(std::string_view str);
-bool is_lower_camel_case(std::string_view str);
-bool is_upper_camel_case(std::string_view str);
-
-std::string strip_string_literal_quotes(std::string_view str);
-std::string strip_doc_comment_slashes(std::string_view str);
-std::string strip_konstant_k(std::string_view str);
-std::string to_konstant_case(std::string_view str);
-std::string to_lower_no_separator_case(std::string_view str);
-std::string to_lower_snake_case(std::string_view str);
-std::string to_upper_snake_case(std::string_view str);
-std::string to_lower_camel_case(std::string_view str);
-std::string to_upper_camel_case(std::string_view str);
-
-// Decodes 1 to 6 hex digits like "a" or "123" or "FFFFFF".
-uint32_t decode_unicode_hex(std::string_view str);
-
-// string_literal_length returns the length of the string
-// represented by the provided string literal.
-// String literals start and end with double quotes,
-// and may contain escape characters.
-// For instance, the string Hello\n, i.e.
-// the word Hello followed by a newline character,
-// is represented as the string literal "Hello\n".
-// While the string literal itself has 9 characters,
-// the length of the string it represents is 6.
-//
-// PRECONDITION: str must be a valid string literal.
-std::uint32_t string_literal_length(std::string_view str);
-
-// Returns the canonical form of an identifier, used to detect name collisions
-// in FIDL libraries. For example, the identifers "FooBar" and "FOO_BAR" collide
-// because canonicalize returns "foo_bar" for both.
-std::string canonicalize(std::string_view identifier);
-
-std::string StringJoin(const std::vector<std::string_view>& strings, std::string_view separator);
-
-// Used by fidl-lint FormatFindings, and for testing,
-// this generates the linter error message string in the format
-// required for the Reporter.
-void PrintFinding(std::ostream& os, const Finding& finding);
-
-// Used by fidl-lint main() and for testing, this generates the linter error
-// messages for a list of findings.
-std::vector<std::string> FormatFindings(const Findings& findings, bool enable_color);
-
-// Gets a string with the original file contents, and a string with the
-// formatted file, and makes sure that the only difference is in the whitespace.
-// Used by the formatter to make sure that formatting was not destructive.
-bool OnlyWhitespaceChanged(std::string_view unformatted_input, std::string_view formatted_output);
-
 }  // namespace fidlc
 
 #endif  // TOOLS_FIDL_FIDLC_SRC_UTILS_H_
diff --git a/tools/fidl/fidlc/src/values.cc b/tools/fidl/fidlc/src/values.cc
index 40e52db..45316a5 100644
--- a/tools/fidl/fidlc/src/values.cc
+++ b/tools/fidl/fidlc/src/values.cc
@@ -119,13 +119,6 @@
   }
 }
 
-std::string DocCommentConstantValue::MakeContents() const {
-  if (value.empty()) {
-    return "";
-  }
-  return strip_doc_comment_slashes(value);
-}
-
 bool StringConstantValue::Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const {
   ZX_ASSERT(out_value != nullptr);
   switch (kind) {
@@ -137,13 +130,6 @@
   }
 }
 
-std::string StringConstantValue::MakeContents() const {
-  if (value.empty()) {
-    return "";
-  }
-  return strip_string_literal_quotes(value);
-}
-
 void Constant::ResolveTo(std::unique_ptr<ConstantValue> value, const Type* type) {
   ZX_ASSERT(value != nullptr);
   ZX_ASSERT_MSG(!IsResolved(), "constants should only be resolved once");
diff --git a/tools/fidl/fidlc/src/values.h b/tools/fidl/fidlc/src/values.h
index 16a6840b..c369224 100644
--- a/tools/fidl/fidlc/src/values.h
+++ b/tools/fidl/fidlc/src/values.h
@@ -183,16 +183,16 @@
       : ConstantValue(ConstantValue::Kind::kDocComment), value(value) {}
 
   friend std::ostream& operator<<(std::ostream& os, const DocCommentConstantValue& v) {
-    return os << v.value.data();
+    return os << v.value;
   }
 
   bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override;
-  std::string MakeContents() const;
 
   std::unique_ptr<ConstantValue> Clone() const override {
     return std::make_unique<DocCommentConstantValue>(value);
   }
 
+  // Refers to the std::string owned by the RawDocCommentLiteral.
   std::string_view value;
 };
 
@@ -201,17 +201,16 @@
       : ConstantValue(ConstantValue::Kind::kString), value(value) {}
 
   friend std::ostream& operator<<(std::ostream& os, const StringConstantValue& v) {
-    os << v.value.data();
-    return os;
+    return os << v.value;
   }
 
   bool Convert(Kind kind, std::unique_ptr<ConstantValue>* out_value) const override;
-  std::string MakeContents() const;
 
   std::unique_ptr<ConstantValue> Clone() const override {
     return std::make_unique<StringConstantValue>(value);
   }
 
+  // Refers to the std::string owned by the RawStringLiteral.
   std::string_view value;
 };
 
diff --git a/tools/fidl/fidlc/src/verify_steps.cc b/tools/fidl/fidlc/src/verify_steps.cc
index 9af5150..98dcd54 100644
--- a/tools/fidl/fidlc/src/verify_steps.cc
+++ b/tools/fidl/fidlc/src/verify_steps.cc
@@ -9,6 +9,7 @@
 #include "tools/fidl/fidlc/src/attribute_schema.h"
 #include "tools/fidl/fidlc/src/diagnostics.h"
 #include "tools/fidl/fidlc/src/flat_ast.h"
+#include "tools/fidl/fidlc/src/names.h"
 #include "tools/fidl/fidlc/src/transport.h"
 
 namespace fidlc {
@@ -58,12 +59,10 @@
         return Visit(static_cast<const BoxType*>(type)->boxed_type, span);
       case Type::Kind::kHandle: {
         const Resource* resource = static_cast<const HandleType*>(type)->resource_decl;
-        std::string handle_name = LibraryName(resource->name.library()->name, ".") + "." +
-                                  std::string(resource->name.decl_name());
-        std::optional<HandleClass> handle_class = HandleClassFromName(handle_name);
+        std::optional<HandleClass> handle_class = HandleClassFromName(resource->name);
         if (!handle_class.has_value() || !transport_->IsCompatible(handle_class.value())) {
-          reporter_->Fail(ErrHandleUsedInIncompatibleTransport, span, handle_name, transport_->name,
-                          protocol_);
+          reporter_->Fail(ErrHandleUsedInIncompatibleTransport, span,
+                          FullyQualifiedName(resource->name), transport_->name, protocol_);
         }
         return;
       }
@@ -142,7 +141,7 @@
 }
 
 void VerifyDependenciesStep::RunImpl() {
-  library()->dependencies.VerifyAllDependenciesWereUsed(*library(), reporter());
+  library()->dependencies.VerifyAllDependenciesWereUsed(library(), reporter());
 }
 
 }  // namespace fidlc
diff --git a/tools/fidl/fidlc/testdata/BUILD.gn b/tools/fidl/fidlc/testdata/BUILD.gn
index 5235d25..d3f6efd 100644
--- a/tools/fidl/fidlc/testdata/BUILD.gn
+++ b/tools/fidl/fidlc/testdata/BUILD.gn
@@ -80,7 +80,7 @@
     }
 
     if (filename == "versions.test.fidl") {
-      platform = "test"
+      versioned = "test:1"
       available = [
         "fuchsia:HEAD",
         "test:HEAD",
diff --git a/tools/fidl/fidlc/tests/BUILD.gn b/tools/fidl/fidlc/tests/BUILD.gn
index 2027a5a..084255e 100644
--- a/tools/fidl/fidlc/tests/BUILD.gn
+++ b/tools/fidl/fidlc/tests/BUILD.gn
@@ -45,12 +45,10 @@
     "alias_tests.cc",
     "array_tests.cc",
     "attributes_tests.cc",
-    "availability_interleaving_tests.cc",
     "bits_tests.cc",
     "canonical_names_tests.cc",
     "consts_tests.cc",
     "declaration_order_tests.cc",
-    "decomposition_tests.cc",
     "direct_dependencies_tests.cc",
     "enums_tests.cc",
     "errcat_docs_tests.cc",
@@ -90,7 +88,14 @@
     "union_tests.cc",
     "using_tests.cc",
     "utils_tests.cc",
-    "versioning_tests.cc",
+    "versioning_attribute_tests.cc",
+    "versioning_basic_tests.cc",
+    "versioning_decomposition_tests.cc",
+    "versioning_inheritance_tests.cc",
+    "versioning_interleaving_tests.cc",
+    "versioning_overlap_tests.cc",
+    "versioning_platform_tests.cc",
+    "versioning_replacement_tests.cc",
     "versioning_types_tests.cc",
     "virtual_source_tests.cc",
   ]
diff --git a/tools/fidl/fidlc/tests/alias_tests.cc b/tools/fidl/fidlc/tests/alias_tests.cc
index 242af69..e57faf8 100644
--- a/tools/fidl/fidlc/tests/alias_tests.cc
+++ b/tools/fidl/fidlc/tests/alias_tests.cc
@@ -40,7 +40,7 @@
   auto type_decl = library.LookupStruct("TypeDecl");
   ASSERT_NE(type_decl, nullptr);
   EXPECT_EQ(type_decl->members.size(), 2u);
-  ASSERT_NE(library.LookupAlias("AliasOfDecl"), nullptr);
+  ASSERT_TRUE(library.HasAlias("AliasOfDecl"));
 }
 
 TEST(AliasTests, GoodPrimitive) {
@@ -67,7 +67,7 @@
 
   auto invocation = msg->members[0].type_ctor->resolved_params;
   ASSERT_NE(invocation.from_alias, nullptr);
-  EXPECT_EQ(NameFlatName(invocation.from_alias->name), "example/alias_of_int16");
+  EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_int16");
   EXPECT_EQ(invocation.element_type_resolved, nullptr);
   EXPECT_EQ(invocation.size_resolved, nullptr);
   EXPECT_EQ(invocation.nullability, Nullability::kNonnullable);
@@ -97,7 +97,7 @@
 
   auto invocation = msg->members[0].type_ctor->resolved_params;
   ASSERT_NE(invocation.from_alias, nullptr);
-  EXPECT_EQ(NameFlatName(invocation.from_alias->name), "example/alias_of_int16");
+  EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_int16");
   EXPECT_EQ(invocation.element_type_resolved, nullptr);
   EXPECT_EQ(invocation.size_resolved, nullptr);
   EXPECT_EQ(invocation.nullability, Nullability::kNonnullable);
@@ -190,7 +190,7 @@
 
   auto invocation = msg->members[0].type_ctor->resolved_params;
   ASSERT_NE(invocation.from_alias, nullptr);
-  EXPECT_EQ(NameFlatName(invocation.from_alias->name), "example/alias_of_vector_of_string");
+  EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_vector_of_string");
   EXPECT_EQ(invocation.element_type_resolved, nullptr);
   EXPECT_EQ(invocation.size_resolved, nullptr);
   EXPECT_EQ(invocation.nullability, Nullability::kNonnullable);
@@ -251,7 +251,7 @@
 
   auto invocation = msg->members[0].type_ctor->resolved_params;
   ASSERT_NE(invocation.from_alias, nullptr);
-  EXPECT_EQ(NameFlatName(invocation.from_alias->name), "example/alias_of_vector_of_string");
+  EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_vector_of_string");
   EXPECT_EQ(invocation.element_type_resolved, nullptr);
   EXPECT_NE(invocation.size_resolved, nullptr);
   EXPECT_EQ(invocation.size_resolved->value, 8u);
@@ -290,7 +290,7 @@
 
   auto invocation = msg->members[0].type_ctor->resolved_params;
   ASSERT_NE(invocation.from_alias, nullptr);
-  EXPECT_EQ(NameFlatName(invocation.from_alias->name),
+  EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name),
             "example/alias_of_vector_of_string_nullable");
   EXPECT_EQ(invocation.element_type_resolved, nullptr);
   EXPECT_EQ(invocation.size_resolved, nullptr);
@@ -322,7 +322,7 @@
 
   auto invocation = msg->members[0].type_ctor->resolved_params;
   ASSERT_NE(invocation.from_alias, nullptr);
-  EXPECT_EQ(NameFlatName(invocation.from_alias->name), "example/alias_of_vector_of_string");
+  EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_vector_of_string");
   EXPECT_EQ(invocation.element_type_resolved, nullptr);
   EXPECT_EQ(invocation.size_resolved, nullptr);
   EXPECT_EQ(invocation.nullability, Nullability::kNullable);
diff --git a/tools/fidl/fidlc/tests/attributes_tests.cc b/tools/fidl/fidlc/tests/attributes_tests.cc
index a08b1c9..c4d324a 100644
--- a/tools/fidl/fidlc/tests/attributes_tests.cc
+++ b/tools/fidl/fidlc/tests/attributes_tests.cc
@@ -199,22 +199,22 @@
   EXPECT_TRUE(example_const->attributes->Get("doc")->GetArg("value"));
   auto& const_doc_value = static_cast<const DocCommentConstantValue&>(
       example_const->attributes->Get("doc")->GetArg("value")->value->Value());
-  EXPECT_EQ(const_doc_value.MakeContents(), " For EXAMPLE_CONSTANT\n");
+  EXPECT_EQ(const_doc_value.value, " For EXAMPLE_CONSTANT\n");
   EXPECT_TRUE(example_const->attributes->Get("deprecated")->GetArg("value"));
   auto& const_str_value = static_cast<const StringConstantValue&>(
       example_const->attributes->Get("deprecated")->GetArg("value")->value->Value());
-  EXPECT_EQ(const_str_value.MakeContents(), "Note");
+  EXPECT_EQ(const_str_value.value, "Note");
 
   auto example_enum = library.LookupEnum("ExampleEnum");
   ASSERT_NE(example_enum, nullptr);
   EXPECT_TRUE(example_enum->attributes->Get("doc")->GetArg("value"));
   auto& enum_doc_value = static_cast<const DocCommentConstantValue&>(
       example_enum->attributes->Get("doc")->GetArg("value")->value->Value());
-  EXPECT_EQ(enum_doc_value.MakeContents(), " For ExampleEnum\n");
+  EXPECT_EQ(enum_doc_value.value, " For ExampleEnum\n");
   EXPECT_TRUE(example_enum->attributes->Get("deprecated")->GetArg("value"));
   auto& enum_str_value = static_cast<const StringConstantValue&>(
       example_enum->attributes->Get("deprecated")->GetArg("value")->value->Value());
-  EXPECT_EQ(enum_str_value.MakeContents(), "Reason");
+  EXPECT_EQ(enum_str_value.value, "Reason");
   EXPECT_TRUE(example_enum->members.back().attributes->Get("unknown"));
 
   auto example_struct = library.LookupStruct("ExampleStruct");
@@ -222,15 +222,15 @@
   EXPECT_TRUE(example_struct->attributes->Get("doc")->GetArg("value"));
   auto& struct_doc_value = static_cast<const DocCommentConstantValue&>(
       example_struct->attributes->Get("doc")->GetArg("value")->value->Value());
-  EXPECT_EQ(struct_doc_value.MakeContents(), " For ExampleStruct\n");
+  EXPECT_EQ(struct_doc_value.value, " For ExampleStruct\n");
   EXPECT_TRUE(example_struct->attributes->Get("max_bytes")->GetArg("value"));
   auto& struct_str_value1 = static_cast<const StringConstantValue&>(
       example_struct->attributes->Get("max_bytes")->GetArg("value")->value->Value());
-  EXPECT_EQ(struct_str_value1.MakeContents(), "1234");
+  EXPECT_EQ(struct_str_value1.value, "1234");
   EXPECT_TRUE(example_struct->attributes->Get("max_handles")->GetArg("value"));
   auto& struct_str_value2 = static_cast<const StringConstantValue&>(
       example_struct->attributes->Get("max_handles")->GetArg("value")->value->Value());
-  EXPECT_EQ(struct_str_value2.MakeContents(), "5678");
+  EXPECT_EQ(struct_str_value2.value, "5678");
 
   auto example_anon = library.LookupTable("CustomName");
   ASSERT_NE(example_anon, nullptr);
@@ -238,7 +238,7 @@
 
   auto& generated_name_value = static_cast<const StringConstantValue&>(
       example_anon->attributes->Get("generated_name")->GetArg("value")->value->Value());
-  EXPECT_EQ(generated_name_value.MakeContents(), "CustomName");
+  EXPECT_EQ(generated_name_value.value, "CustomName");
 
   auto example_protocol = library.LookupProtocol("ExampleProtocol");
   ASSERT_NE(example_protocol, nullptr);
@@ -246,22 +246,22 @@
   EXPECT_TRUE(example_protocol->attributes->Get("doc")->GetArg("value"));
   auto& protocol_doc_value = static_cast<const DocCommentConstantValue&>(
       example_protocol->attributes->Get("doc")->GetArg("value")->value->Value());
-  EXPECT_EQ(protocol_doc_value.MakeContents(), " For ExampleProtocol\n");
+  EXPECT_EQ(protocol_doc_value.value, " For ExampleProtocol\n");
   EXPECT_TRUE(example_protocol->attributes->Get("transport")->GetArg("value"));
   auto& protocol_str_value = static_cast<const StringConstantValue&>(
       example_protocol->attributes->Get("transport")->GetArg("value")->value->Value());
-  EXPECT_EQ(protocol_str_value.MakeContents(), "Syscall");
+  EXPECT_EQ(protocol_str_value.value, "Syscall");
 
   auto& example_method = example_protocol->methods.front();
   EXPECT_TRUE(example_method.attributes->Get("internal"));
   EXPECT_TRUE(example_method.attributes->Get("doc")->GetArg("value"));
   auto& method_doc_value = static_cast<const DocCommentConstantValue&>(
       example_method.attributes->Get("doc")->GetArg("value")->value->Value());
-  EXPECT_EQ(method_doc_value.MakeContents(), " For ExampleMethod\n");
+  EXPECT_EQ(method_doc_value.value, " For ExampleMethod\n");
   EXPECT_TRUE(example_method.attributes->Get("selector")->GetArg("value"));
   auto& method_str_value = static_cast<const StringConstantValue&>(
       example_method.attributes->Get("selector")->GetArg("value")->value->Value());
-  EXPECT_EQ(method_str_value.MakeContents(), "Bar");
+  EXPECT_EQ(method_str_value.value, "Bar");
 
   auto example_service = library.LookupService("ExampleService");
   ASSERT_NE(example_service, nullptr);
@@ -269,22 +269,22 @@
   EXPECT_TRUE(example_service->attributes->Get("doc")->GetArg("value"));
   auto& service_doc_value = static_cast<const DocCommentConstantValue&>(
       example_service->attributes->Get("doc")->GetArg("value")->value->Value());
-  EXPECT_EQ(service_doc_value.MakeContents(), " For ExampleService\n");
+  EXPECT_EQ(service_doc_value.value, " For ExampleService\n");
   EXPECT_TRUE(example_service->attributes->Get("foo")->GetArg("value"));
   auto& service_str_value = static_cast<const StringConstantValue&>(
       example_service->attributes->Get("foo")->GetArg("value")->value->Value());
-  EXPECT_EQ(service_str_value.MakeContents(), "ExampleService");
+  EXPECT_EQ(service_str_value.value, "ExampleService");
 
   auto& example_service_member = example_service->members.front();
   EXPECT_TRUE(example_service_member.attributes->Get("no_doc"));
   EXPECT_TRUE(example_service_member.attributes->Get("doc")->GetArg("value"));
   auto& service_member_doc_value = static_cast<const DocCommentConstantValue&>(
       example_service_member.attributes->Get("doc")->GetArg("value")->value->Value());
-  EXPECT_EQ(service_member_doc_value.MakeContents(), " For ExampleProtocol\n");
+  EXPECT_EQ(service_member_doc_value.value, " For ExampleProtocol\n");
   EXPECT_TRUE(example_service_member.attributes->Get("foo")->GetArg("value"));
   auto& service_member_str_value = static_cast<const StringConstantValue&>(
       example_service_member.attributes->Get("foo")->GetArg("value")->value->Value());
-  EXPECT_EQ(service_member_str_value.MakeContents(), "ExampleProtocol");
+  EXPECT_EQ(service_member_str_value.value, "ExampleProtocol");
 }
 
 TEST(AttributesTests, BadNoAttributeOnUsingNotEventDoc) {
@@ -377,7 +377,7 @@
   EXPECT_TRUE(example_protocol->attributes->Get("duck"));
   auto& struct_str_value1 = static_cast<const StringConstantValue&>(
       example_protocol->attributes->Get("duck")->GetArg("value")->value->Value());
-  EXPECT_EQ(struct_str_value1.MakeContents(), "quack");
+  EXPECT_EQ(struct_str_value1.value, "quack");
 }
 
 // Ensures we detect typos early enough that we still report them, even if there
@@ -1075,7 +1075,7 @@
 
   std::unique_ptr<ConstantValue> resolved_foo;
   EXPECT_TRUE(foo->Value().Convert(ConstantValue::Kind::kString, &resolved_foo));
-  EXPECT_EQ(static_cast<StringConstantValue*>(resolved_foo.get())->MakeContents(), "abc");
+  EXPECT_EQ(static_cast<StringConstantValue*>(resolved_foo.get())->value, "abc");
 
   // Check `bar` arg.
   EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("bar"));
@@ -1165,7 +1165,7 @@
 
   std::unique_ptr<ConstantValue> resolved_string;
   EXPECT_TRUE(string_val->Value().Convert(ConstantValue::Kind::kString, &resolved_string));
-  EXPECT_EQ(static_cast<StringConstantValue*>(resolved_string.get())->MakeContents(), "foo");
+  EXPECT_EQ(static_cast<StringConstantValue*>(resolved_string.get())->value, "foo");
 
   // Check `bool` arg.
   EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("bool"));
@@ -1436,7 +1436,7 @@
 
   std::unique_ptr<ConstantValue> resolved_string;
   EXPECT_TRUE(string_val->Value().Convert(ConstantValue::Kind::kString, &resolved_string));
-  EXPECT_EQ(static_cast<StringConstantValue*>(resolved_string.get())->MakeContents(), "foo");
+  EXPECT_EQ(static_cast<StringConstantValue*>(resolved_string.get())->value, "foo");
 
   // Check `bool` arg.
   EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("bool"));
@@ -1695,7 +1695,7 @@
 @foo(nonexistent)
 type MyStruct = struct {};
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "nonexistent", "example");
+  library.ExpectFail(ErrNameNotFound, "nonexistent", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -1707,7 +1707,7 @@
 type MyStruct = struct {};
 )FIDL");
   library.AddAttributeSchema("foo").AddArg("value", AttributeArgSchema(ConstantValue::Kind::kBool));
-  library.ExpectFail(ErrNameNotFound, "nonexistent", "example");
+  library.ExpectFail(ErrNameNotFound, "nonexistent", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -1721,7 +1721,7 @@
   library.AddAttributeSchema("foo")
       .AddArg("first", AttributeArgSchema(ConstantValue::Kind::kBool))
       .AddArg("second", AttributeArgSchema(ConstantValue::Kind::kBool));
-  library.ExpectFail(ErrNameNotFound, "nonexistent", "example");
+  library.ExpectFail(ErrNameNotFound, "nonexistent", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -1859,7 +1859,7 @@
 @foo(nonexistent)
 library example;
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "nonexistent", "example");
+  library.ExpectFail(ErrNameNotFound, "nonexistent", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
diff --git a/tools/fidl/fidlc/tests/canonical_names_tests.cc b/tools/fidl/fidlc/tests/canonical_names_tests.cc
index ca625067..0b44139 100644
--- a/tools/fidl/fidlc/tests/canonical_names_tests.cc
+++ b/tools/fidl/fidlc/tests/canonical_names_tests.cc
@@ -515,10 +515,10 @@
       "a", "a1", "x_single_start", "single_end_x", "x_single_both_x", "single_x_middle",
   };
   const auto functions = {
-      to_lower_snake_case,
-      to_upper_snake_case,
-      to_lower_camel_case,
-      to_upper_camel_case,
+      ToLowerSnakeCase,
+      ToUpperSnakeCase,
+      ToLowerCamelCase,
+      ToUpperCamelCase,
   };
 
   for (const auto base_name : base_names) {
@@ -539,12 +539,12 @@
           // We compile name1 first, and see that name2 collides with it.
           library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, name2,
                              Element::Kind::kStruct, name1, "example.fidl:2:6",
-                             canonicalize(name1));
+                             Canonicalize(name1));
         } else {
           // We compile name2 first, and see that name1 collides with it.
           library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, name1,
                              Element::Kind::kStruct, name2, "example.fidl:3:6",
-                             canonicalize(name1));
+                             Canonicalize(name1));
         }
         ASSERT_COMPILER_DIAGNOSTICS(library);
       }
@@ -593,7 +593,7 @@
       auto fidl = s.str();
       SCOPED_TRACE(fidl);
       TestLibrary library(fidl);
-      library.ExpectFail(ErrNameNotFound, use_name, "example");
+      library.ExpectFail(ErrNameNotFound, use_name, "library 'example'");
       ASSERT_COMPILER_DIAGNOSTICS(library);
     }
   }
@@ -613,7 +613,7 @@
       << "const EXAMPLE bool = " << use_name << ";";
     auto fidl = s.str();
     TestLibrary library(fidl);
-    library.ExpectFail(ErrNameNotFound, use_name, "example");
+    library.ExpectFail(ErrNameNotFound, use_name, "library 'example'");
     ASSERT_COMPILER_DIAGNOSTICS(library);
   }
 }
diff --git a/tools/fidl/fidlc/tests/consts_tests.cc b/tools/fidl/fidlc/tests/consts_tests.cc
index c04eb20..de7724f 100644
--- a/tools/fidl/fidlc/tests/consts_tests.cc
+++ b/tools/fidl/fidlc/tests/consts_tests.cc
@@ -493,7 +493,7 @@
 
 type Example = struct { s string:dependency.MAX; };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "MAX", "dependency");
+  library.ExpectFail(ErrNameNotFound, "MAX", "library 'dependency'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
diff --git a/tools/fidl/fidlc/tests/direct_dependencies_tests.cc b/tools/fidl/fidlc/tests/direct_dependencies_tests.cc
index ccf9db96..85e584a 100644
--- a/tools/fidl/fidlc/tests/direct_dependencies_tests.cc
+++ b/tools/fidl/fidlc/tests/direct_dependencies_tests.cc
@@ -58,8 +58,8 @@
     auto deps = lib.direct_and_composed_dependencies();
     ASSERT_EQ(deps.size(), 2u);
     auto iter = deps.cbegin();
-    EXPECT_EQ(NameLibrary((*iter++).library->name), "dep1");
-    EXPECT_EQ(NameLibrary((*iter++).library->name), "dep2");
+    EXPECT_EQ((*iter++).library->name, "dep1");
+    EXPECT_EQ((*iter++).library->name, "dep2");
   }
 }
 
@@ -101,7 +101,7 @@
   auto deps = lib.direct_and_composed_dependencies();
   ASSERT_EQ(deps.size(), 1u);
   auto iter = deps.cbegin();
-  EXPECT_EQ(NameLibrary((*iter++).library->name), "dep1");
+  EXPECT_EQ((*iter++).library->name, "dep1");
 }
 
 TEST(DirectDependenciesTests, GoodDoesNotFollowNestedStruct) {
@@ -142,7 +142,7 @@
   auto deps = lib.direct_and_composed_dependencies();
   ASSERT_EQ(deps.size(), 1u);
   auto iter = deps.cbegin();
-  EXPECT_EQ(NameLibrary((*iter++).library->name), "dep1");
+  EXPECT_EQ((*iter++).library->name, "dep1");
 }
 
 TEST(DirectDependenciesTests, GoodErrorSyntaxSuccessType) {
@@ -179,8 +179,8 @@
   auto deps = lib.direct_and_composed_dependencies();
   ASSERT_EQ(deps.size(), 2u);
   auto iter = deps.cbegin();
-  EXPECT_EQ(NameLibrary((*iter++).library->name), "dep1");
-  EXPECT_EQ(NameLibrary((*iter++).library->name), "dep2");
+  EXPECT_EQ((*iter++).library->name, "dep1");
+  EXPECT_EQ((*iter++).library->name, "dep2");
 }
 
 TEST(DirectDependenciesTests, GoodErrorSyntaxErrorType) {
@@ -217,8 +217,8 @@
   auto deps = lib.direct_and_composed_dependencies();
   ASSERT_EQ(deps.size(), 2u);
   auto iter = deps.cbegin();
-  EXPECT_EQ(NameLibrary((*iter++).library->name), "dep1");
-  EXPECT_EQ(NameLibrary((*iter++).library->name), "dep2");
+  EXPECT_EQ((*iter++).library->name, "dep1");
+  EXPECT_EQ((*iter++).library->name, "dep2");
 }
 
 TEST(DirectDependenciesTests, GoodFlexibleResponse) {
@@ -255,8 +255,8 @@
   auto deps = lib.direct_and_composed_dependencies();
   ASSERT_EQ(deps.size(), 2u);
   auto iter = deps.cbegin();
-  EXPECT_EQ(NameLibrary((*iter++).library->name), "dep1");
-  EXPECT_EQ(NameLibrary((*iter++).library->name), "dep2");
+  EXPECT_EQ((*iter++).library->name, "dep1");
+  EXPECT_EQ((*iter++).library->name, "dep2");
 }
 
 }  // namespace
diff --git a/tools/fidl/fidlc/tests/errcat_docs_tests.cc b/tools/fidl/fidlc/tests/errcat_docs_tests.cc
index 6def417..10d6fa7 100644
--- a/tools/fidl/fidlc/tests/errcat_docs_tests.cc
+++ b/tools/fidl/fidlc/tests/errcat_docs_tests.cc
@@ -98,16 +98,11 @@
 
 TEST(ErrcatDocsTests, MarkdownFilesExist) {
   for (auto def : kAllDiagnosticDefs) {
+    if (!def->opts.documented)
+      continue;
     auto id = def->FormatId();
     auto path = TestLibrary::TestFilePath("error-catalog/_" + id + ".md");
-    bool exists = std::filesystem::exists(path);
-    if (def->opts.documented) {
-      EXPECT_TRUE(exists) << id << " is marked documented=true in diagnostics.h, "
-                          << "but the Markdown file " << path << " DOES NOT exist";
-    } else {
-      EXPECT_FALSE(exists) << id << " is marked documented=false in diagnostics.h, "
-                           << "but the Markdown file " << path << " DOES exists";
-    }
+    EXPECT_TRUE(std::filesystem::exists(path)) << "missing Markdown file " << path << " for " << id;
   }
 }
 
diff --git a/tools/fidl/fidlc/tests/errors_tests.cc b/tools/fidl/fidlc/tests/errors_tests.cc
index ef95d34..ac958ab 100644
--- a/tools/fidl/fidlc/tests/errors_tests.cc
+++ b/tools/fidl/fidlc/tests/errors_tests.cc
@@ -133,7 +133,7 @@
   TestLibrary library;
   library.AddFile("bad/fi-0052.test.fidl");
 
-  library.ExpectFail(ErrNameNotFound, "ParsingError", "test.bad.fi0052");
+  library.ExpectFail(ErrNameNotFound, "ParsingError", "library 'test.bad.fi0052'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
diff --git a/tools/fidl/fidlc/tests/formatter_tests.cc b/tools/fidl/fidlc/tests/formatter_tests.cc
index dd3fb43..278e665 100644
--- a/tools/fidl/fidlc/tests/formatter_tests.cc
+++ b/tools/fidl/fidlc/tests/formatter_tests.cc
@@ -7,13 +7,14 @@
 #include "tools/fidl/fidlc/src/formatter.h"
 #include "tools/fidl/fidlc/src/utils.h"
 
-#define ASSERT_FORMATTED(source, expected)            \
-  std::string actual = Format(source);                \
-  ASSERT_TRUE(OnlyWhitespaceChanged(source, actual)); \
+#define ASSERT_FORMATTED(source, expected)                       \
+  std::string actual = Format(source);                           \
+  ASSERT_EQ(RemoveWhitespace(source), RemoveWhitespace(actual)); \
   ASSERT_EQ(expected, actual);
 
 namespace fidlc {
 namespace {
+
 std::string Format(const std::string& source, bool reformat_and_compare = true) {
   SourceFile source_file("example.fidl", source);
 
diff --git a/tools/fidl/fidlc/tests/handle_tests.cc b/tools/fidl/fidlc/tests/handle_tests.cc
index 624c584..40c3759 100644
--- a/tools/fidl/fidlc/tests/handle_tests.cc
+++ b/tools/fidl/fidlc/tests/handle_tests.cc
@@ -162,7 +162,7 @@
 )FIDL");
   library.UseLibraryZx();
 
-  library.ExpectFail(ErrNameNotFound, "ZIPPY", "example");
+  library.ExpectFail(ErrNameNotFound, "ZIPPY", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -178,8 +178,8 @@
 )FIDL");
   library.UseLibraryZx();
 
-  library.ExpectFail(ErrNameNotFound, "handle", "example");
-  library.ExpectFail(ErrNameNotFound, "vmo", "example");
+  library.ExpectFail(ErrNameNotFound, "handle", "library 'example'");
+  library.ExpectFail(ErrNameNotFound, "vmo", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -278,7 +278,7 @@
     h handle;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "handle", "example");
+  library.ExpectFail(ErrNameNotFound, "handle", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -290,8 +290,8 @@
     h handle:VMO;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "handle", "example");
-  library.ExpectFail(ErrNameNotFound, "VMO", "example");
+  library.ExpectFail(ErrNameNotFound, "handle", "library 'example'");
+  library.ExpectFail(ErrNameNotFound, "VMO", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -305,8 +305,8 @@
     h my_handle:VMO;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "handle", "example");
-  library.ExpectFail(ErrNameNotFound, "VMO", "example");
+  library.ExpectFail(ErrNameNotFound, "handle", "library 'example'");
+  library.ExpectFail(ErrNameNotFound, "VMO", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
diff --git a/tools/fidl/fidlc/tests/ordinals_tests.cc b/tools/fidl/fidlc/tests/ordinals_tests.cc
index cd46797..8471552 100644
--- a/tools/fidl/fidlc/tests/ordinals_tests.cc
+++ b/tools/fidl/fidlc/tests/ordinals_tests.cc
@@ -14,26 +14,30 @@
 namespace fidlc {
 namespace {
 
-// Since a number of these tests rely on specific properties of 64b hashes
-// which are computationally prohibitive to reverse engineer, we rely on
-// a stubbed out method hasher `GetGeneratedOrdinal64ForTesting` defined
-// in test_library.h.
+uint64_t FakeMethodHasher(std::string_view selector) {
+  if (selector.find("HashesToZero") != std::string_view::npos)
+    return 0;
+  if (selector.find("Clash") != std::string_view::npos)
+    return 456789;
+  return Sha256MethodHasher(selector);
+}
 
 TEST(OrdinalsTests, BadOrdinalCannotBeZero) {
   TestLibrary library(R"FIDL(
-library methodhasher;
+library example;
 
 protocol Special {
     ThisOneHashesToZero() -> (struct { i int64; });
 };
 )FIDL");
+  library.method_hasher() = FakeMethodHasher;
   library.ExpectFail(ErrGeneratedZeroValueOrdinal);
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
 TEST(OrdinalsTests, BadClashingOrdinalValues) {
   TestLibrary library(R"FIDL(
-library methodhasher;
+library example;
 
 using zx;
 
@@ -42,6 +46,7 @@
     ClashTwo(struct { s string; }) -> (resource struct { r zx.Handle:CHANNEL; });
 };
 )FIDL");
+  library.method_hasher() = FakeMethodHasher;
   library.UseLibraryZx();
   library.ExpectFail(ErrDuplicateMethodOrdinal, "example.fidl:7:5");
   ASSERT_COMPILER_DIAGNOSTICS(library);
@@ -49,7 +54,7 @@
 
 TEST(OrdinalsTests, BadClashingOrdinalValuesWithAttribute) {
   TestLibrary library(R"FIDL(
-library methodhasher;
+library example;
 
 using zx;
 
@@ -60,6 +65,7 @@
     bar(struct { s string; }) -> (resource struct { r zx.Handle:CHANNEL; });
 };
 )FIDL");
+  library.method_hasher() = FakeMethodHasher;
   library.UseLibraryZx();
   library.ExpectFail(ErrDuplicateMethodOrdinal, "example.fidl:8:5");
   ASSERT_COMPILER_DIAGNOSTICS(library);
@@ -74,16 +80,17 @@
 
 TEST(OrdinalsTests, GoodAttributeResolvesClashes) {
   TestLibrary library(R"FIDL(
-library methodhasher;
+library example;
 
 using zx;
 
 protocol Special {
-    @selector("ClashOneReplacement")
+    @selector("SomethingElse")
     ClashOne(struct { s string; b bool; }) -> (struct { i int32; });
     ClashTwo(struct { s string; }) -> (resource struct { r zx.Handle:CHANNEL; });
 };
 )FIDL");
+  library.method_hasher() = FakeMethodHasher;
   library.UseLibraryZx();
   ASSERT_COMPILED(library);
 }
@@ -109,7 +116,7 @@
   uint64_t expected_hash64 = *(reinterpret_cast<uint64_t*>(digest64)) & 0x7fffffffffffffff;
 
   const Protocol* iface = library.LookupProtocol("protocol");
-  uint64_t actual_hash64 = iface->methods[0].generated_ordinal64->value;
+  uint64_t actual_hash64 = iface->methods[0].ordinal;
   ASSERT_EQ(actual_hash64, expected_hash64) << "Expected 64bits hash is not correct";
 }
 
@@ -130,7 +137,7 @@
   uint64_t expected_hash64 = *(reinterpret_cast<uint64_t*>(digest64)) & 0x7fffffffffffffff;
 
   const Protocol* iface = library.LookupProtocol("at");
-  uint64_t actual_hash64 = iface->methods[0].generated_ordinal64->value;
+  uint64_t actual_hash64 = iface->methods[0].ordinal;
   ASSERT_EQ(actual_hash64, expected_hash64) << "Expected 64bits hash is not correct";
 }
 
@@ -180,7 +187,7 @@
     all();
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "nonexistent", "not.important");
+  library.ExpectFail(ErrNameNotFound, "nonexistent", "library 'not.important'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -235,38 +242,38 @@
   //         hash = hashlib.sha256(fqn.encode()).digest()
   //         print(hash[7::-1].hex())
   //
-  EXPECT_EQ(iface->methods[0].generated_ordinal64->value, 0x3b1625372e15f1aeu);
-  EXPECT_EQ(iface->methods[1].generated_ordinal64->value, 0x4199e504fa71b5a4u);
-  EXPECT_EQ(iface->methods[2].generated_ordinal64->value, 0x247ca8a890628135u);
-  EXPECT_EQ(iface->methods[3].generated_ordinal64->value, 0x64f7c02cfffb7846u);
-  EXPECT_EQ(iface->methods[4].generated_ordinal64->value, 0x20d3f06c598f0cc3u);
-  EXPECT_EQ(iface->methods[5].generated_ordinal64->value, 0x1ce13806085dac7au);
-  EXPECT_EQ(iface->methods[6].generated_ordinal64->value, 0x09e1d4b200770defu);
-  EXPECT_EQ(iface->methods[7].generated_ordinal64->value, 0x53df65d26411d8eeu);
-  EXPECT_EQ(iface->methods[8].generated_ordinal64->value, 0x690c3617405590c7u);
-  EXPECT_EQ(iface->methods[9].generated_ordinal64->value, 0x4ff9ef5fb170f550u);
-  EXPECT_EQ(iface->methods[10].generated_ordinal64->value, 0x1542d4c21d8a6c00u);
-  EXPECT_EQ(iface->methods[11].generated_ordinal64->value, 0x564e9e47f7418e0fu);
-  EXPECT_EQ(iface->methods[12].generated_ordinal64->value, 0x29681e66f3506231u);
-  EXPECT_EQ(iface->methods[13].generated_ordinal64->value, 0x5ee63b26268f7760u);
-  EXPECT_EQ(iface->methods[14].generated_ordinal64->value, 0x256950edf00aac63u);
-  EXPECT_EQ(iface->methods[15].generated_ordinal64->value, 0x6b21c0ff1aa02896u);
-  EXPECT_EQ(iface->methods[16].generated_ordinal64->value, 0x5a54f3dca00089e9u);
-  EXPECT_EQ(iface->methods[17].generated_ordinal64->value, 0x772476706fa4be0eu);
-  EXPECT_EQ(iface->methods[18].generated_ordinal64->value, 0x294e338bf71a773bu);
-  EXPECT_EQ(iface->methods[19].generated_ordinal64->value, 0x5a6aa228cfb68d16u);
-  EXPECT_EQ(iface->methods[20].generated_ordinal64->value, 0x55a09c6b033f3f98u);
-  EXPECT_EQ(iface->methods[21].generated_ordinal64->value, 0x1192d5b856d22cd8u);
-  EXPECT_EQ(iface->methods[22].generated_ordinal64->value, 0x2e68bdea28f9ce7bu);
-  EXPECT_EQ(iface->methods[23].generated_ordinal64->value, 0x4c8ebf26900e4451u);
-  EXPECT_EQ(iface->methods[24].generated_ordinal64->value, 0x3df0dbe9378c4fd3u);
-  EXPECT_EQ(iface->methods[25].generated_ordinal64->value, 0x087268657bb0cad1u);
-  EXPECT_EQ(iface->methods[26].generated_ordinal64->value, 0x0aee6ad161a90ae1u);
-  EXPECT_EQ(iface->methods[27].generated_ordinal64->value, 0x44e6f2282baf727au);
-  EXPECT_EQ(iface->methods[28].generated_ordinal64->value, 0x3e8984f57ab5830du);
-  EXPECT_EQ(iface->methods[29].generated_ordinal64->value, 0x696f9f73a5cabd21u);
-  EXPECT_EQ(iface->methods[30].generated_ordinal64->value, 0x327d7b0d2389e054u);
-  EXPECT_EQ(iface->methods[31].generated_ordinal64->value, 0x54fd307bb5bfab2du);
+  EXPECT_EQ(iface->methods[0].ordinal, 0x3b1625372e15f1aeu);
+  EXPECT_EQ(iface->methods[1].ordinal, 0x4199e504fa71b5a4u);
+  EXPECT_EQ(iface->methods[2].ordinal, 0x247ca8a890628135u);
+  EXPECT_EQ(iface->methods[3].ordinal, 0x64f7c02cfffb7846u);
+  EXPECT_EQ(iface->methods[4].ordinal, 0x20d3f06c598f0cc3u);
+  EXPECT_EQ(iface->methods[5].ordinal, 0x1ce13806085dac7au);
+  EXPECT_EQ(iface->methods[6].ordinal, 0x09e1d4b200770defu);
+  EXPECT_EQ(iface->methods[7].ordinal, 0x53df65d26411d8eeu);
+  EXPECT_EQ(iface->methods[8].ordinal, 0x690c3617405590c7u);
+  EXPECT_EQ(iface->methods[9].ordinal, 0x4ff9ef5fb170f550u);
+  EXPECT_EQ(iface->methods[10].ordinal, 0x1542d4c21d8a6c00u);
+  EXPECT_EQ(iface->methods[11].ordinal, 0x564e9e47f7418e0fu);
+  EXPECT_EQ(iface->methods[12].ordinal, 0x29681e66f3506231u);
+  EXPECT_EQ(iface->methods[13].ordinal, 0x5ee63b26268f7760u);
+  EXPECT_EQ(iface->methods[14].ordinal, 0x256950edf00aac63u);
+  EXPECT_EQ(iface->methods[15].ordinal, 0x6b21c0ff1aa02896u);
+  EXPECT_EQ(iface->methods[16].ordinal, 0x5a54f3dca00089e9u);
+  EXPECT_EQ(iface->methods[17].ordinal, 0x772476706fa4be0eu);
+  EXPECT_EQ(iface->methods[18].ordinal, 0x294e338bf71a773bu);
+  EXPECT_EQ(iface->methods[19].ordinal, 0x5a6aa228cfb68d16u);
+  EXPECT_EQ(iface->methods[20].ordinal, 0x55a09c6b033f3f98u);
+  EXPECT_EQ(iface->methods[21].ordinal, 0x1192d5b856d22cd8u);
+  EXPECT_EQ(iface->methods[22].ordinal, 0x2e68bdea28f9ce7bu);
+  EXPECT_EQ(iface->methods[23].ordinal, 0x4c8ebf26900e4451u);
+  EXPECT_EQ(iface->methods[24].ordinal, 0x3df0dbe9378c4fd3u);
+  EXPECT_EQ(iface->methods[25].ordinal, 0x087268657bb0cad1u);
+  EXPECT_EQ(iface->methods[26].ordinal, 0x0aee6ad161a90ae1u);
+  EXPECT_EQ(iface->methods[27].ordinal, 0x44e6f2282baf727au);
+  EXPECT_EQ(iface->methods[28].ordinal, 0x3e8984f57ab5830du);
+  EXPECT_EQ(iface->methods[29].ordinal, 0x696f9f73a5cabd21u);
+  EXPECT_EQ(iface->methods[30].ordinal, 0x327d7b0d2389e054u);
+  EXPECT_EQ(iface->methods[31].ordinal, 0x54fd307bb5bfab2du);
 }
 
 TEST(OrdinalsTests, GoodHackToRenameFuchsiaIoToFuchsiaIoOneNoSelector) {
@@ -305,7 +312,7 @@
     compose Directory;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "Id", "example");
+  library.ExpectFail(ErrNameNotFound, "Id", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
diff --git a/tools/fidl/fidlc/tests/parsing_tests.cc b/tools/fidl/fidlc/tests/parsing_tests.cc
index f59e5a5..5a200da 100644
--- a/tools/fidl/fidlc/tests/parsing_tests.cc
+++ b/tools/fidl/fidlc/tests/parsing_tests.cc
@@ -26,7 +26,6 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-// Test that library name formatting checks are done in the parser
 TEST(ParsingTests, BadLibraryNameTest) {
   TestLibrary library;
   library.AddFile("bad/fi-0011.noformat.test.fidl");
@@ -34,8 +33,51 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-// Test that otherwise reserved words can be appropriately parsed when context
-// is clear.
+TEST(ParsingTests, GoodSpacesAroundDotsLibraryName) {
+  TestLibrary library(R"FIDL(
+library foo . bar;
+)FIDL");
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.name(), "foo.bar");
+}
+
+TEST(ParsingTests, GoodSpacesAroundDotsMemberName) {
+  TestLibrary library(R"FIDL(
+library example;
+
+type Foo = enum : fidl . uint32 {
+  A = 42;
+};
+const VALUE Foo = Foo . A;
+)FIDL");
+  ASSERT_COMPILED(library);
+  auto constant = library.LookupConstant("VALUE");
+  EXPECT_NE(constant, nullptr);
+  EXPECT_EQ(constant->value->Value().kind, ConstantValue::Kind::kUint32);
+  EXPECT_EQ(static_cast<const NumericConstantValue<uint32_t>&>(constant->value->Value()).value,
+            42u);
+}
+
+TEST(ParsingTests, GoodSpacesAroundDotsImport) {
+  SharedAmongstLibraries shared;
+  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
+library foo . bar . qux;
+
+type Type = struct {};
+const VALUE uint32 = 42;
+)FIDL");
+  ASSERT_COMPILED(dependency);
+  TestLibrary library(&shared, "example.fidl", R"FIDL(
+library example;
+
+using foo  .  bar  .  qux;
+alias Type = foo. bar. qux. Type;
+const VALUE uint32 = foo .bar .qux .VALUE;
+)FIDL");
+  ASSERT_COMPILED(library);
+}
+
+// Test that otherwise reserved words can be appropriately parsed when context is clear.
 TEST(ParsingTests, GoodParsingReservedWordsInStructTest) {
   TestLibrary library(R"FIDL(
 library example;
@@ -504,7 +546,7 @@
 
   std::unique_ptr<RawAttributeArg> arg = std::move(attribute->args[0]);
   auto arg_value = static_cast<RawLiteralConstant*>(arg->value.get());
-  ASSERT_EQ(static_cast<RawStringLiteral*>(arg_value->literal.get())->MakeContents(), "Bar");
+  ASSERT_EQ(static_cast<RawStringLiteral*>(arg_value->literal.get())->value, "Bar");
 }
 
 TEST(ParsingTests, BadAttributeWithDottedIdentifier) {
@@ -529,12 +571,12 @@
   std::unique_ptr<RawAttributeArg> arg1 = std::move(attribute->args[0]);
   ASSERT_EQ(arg1->maybe_name->span().data(), "bar");
   auto arg1_value = static_cast<RawLiteralConstant*>(arg1->value.get());
-  ASSERT_EQ(static_cast<RawStringLiteral*>(arg1_value->literal.get())->MakeContents(), "Bar");
+  ASSERT_EQ(static_cast<RawStringLiteral*>(arg1_value->literal.get())->value, "Bar");
 
   std::unique_ptr<RawAttributeArg> arg2 = std::move(attribute->args[1]);
   ASSERT_EQ(arg2->maybe_name->span().data(), "zork");
   auto arg2_value = static_cast<RawLiteralConstant*>(arg2->value.get());
-  ASSERT_EQ(static_cast<RawStringLiteral*>(arg2_value->literal.get())->MakeContents(), "Zoom");
+  ASSERT_EQ(static_cast<RawStringLiteral*>(arg2_value->literal.get())->value, "Zoom");
 }
 
 TEST(ParsingTests, GoodSimpleDocComment) {
@@ -554,7 +596,7 @@
 
   std::unique_ptr<RawAttributeArg> arg = std::move(attribute->args[0]);
   auto arg_value = static_cast<RawLiteralConstant*>(arg->value.get());
-  ASSERT_EQ(static_cast<RawDocCommentLiteral*>(arg_value->literal.get())->MakeContents(),
+  ASSERT_EQ(static_cast<RawDocCommentLiteral*>(arg_value->literal.get())->value,
             " A doc comment\n");
 }
 
@@ -580,7 +622,7 @@
 
   std::unique_ptr<RawAttributeArg> arg = std::move(attribute->args[0]);
   auto arg_value = static_cast<RawLiteralConstant*>(arg->value.get());
-  ASSERT_EQ(static_cast<RawDocCommentLiteral*>(arg_value->literal.get())->MakeContents(),
+  ASSERT_EQ(static_cast<RawDocCommentLiteral*>(arg_value->literal.get())->value,
             " A\n multiline\n comment!\n");
 }
 
diff --git a/tools/fidl/fidlc/tests/protocol_tests.cc b/tools/fidl/fidlc/tests/protocol_tests.cc
index 598fbc7..d81f57f 100644
--- a/tools/fidl/fidlc/tests/protocol_tests.cc
+++ b/tools/fidl/fidlc/tests/protocol_tests.cc
@@ -430,7 +430,7 @@
     compose MissingParent;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "MissingParent", "example");
+  library.ExpectFail(ErrNameNotFound, "MissingParent", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -556,8 +556,6 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-// See GetGeneratedOrdinal64ForTesting in test_library.h
-// See GetGeneratedOrdinal64ForTesting in test_library.h
 TEST(ProtocolTests, BadComposedProtocolsHaveClashingOrdinals) {
   TestLibrary library(R"FIDL(
 library methodhasher;
@@ -571,6 +569,7 @@
     ClashTwo();
 };
 )FIDL");
+  library.method_hasher() = [](std::string_view selector) -> uint64_t { return 42; };
   library.ExpectFail(ErrDuplicateMethodOrdinal, "example.fidl:5:4");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
diff --git a/tools/fidl/fidlc/tests/service_tests.cc b/tools/fidl/fidlc/tests/service_tests.cc
index 64d2d76..3227c24 100644
--- a/tools/fidl/fidlc/tests/service_tests.cc
+++ b/tools/fidl/fidlc/tests/service_tests.cc
@@ -48,15 +48,15 @@
   const auto& member0 = service->members[0];
   EXPECT_EQ(member0.name.data(), "some_protocol_first_first");
   const auto* type0 = static_cast<const TransportSideType*>(member0.type_ctor->type);
-  EXPECT_EQ(NameFlatName(type0->protocol_decl->name), "example/SomeProtocol1");
+  EXPECT_EQ(FullyQualifiedName(type0->protocol_decl->name), "example/SomeProtocol1");
   const auto& member1 = service->members[1];
   EXPECT_EQ(member1.name.data(), "some_protocol_first_second");
   const auto* type1 = static_cast<const TransportSideType*>(member1.type_ctor->type);
-  EXPECT_EQ(NameFlatName(type1->protocol_decl->name), "example/SomeProtocol1");
+  EXPECT_EQ(FullyQualifiedName(type1->protocol_decl->name), "example/SomeProtocol1");
   const auto& member2 = service->members[2];
   EXPECT_EQ(member2.name.data(), "some_protocol_second");
   const auto* type2 = static_cast<const TransportSideType*>(member2.type_ctor->type);
-  EXPECT_EQ(NameFlatName(type2->protocol_decl->name), "example/SomeProtocol2");
+  EXPECT_EQ(FullyQualifiedName(type2->protocol_decl->name), "example/SomeProtocol2");
 }
 
 TEST(ServiceTests, BadCannotHaveConflictingMembers) {
diff --git a/tools/fidl/fidlc/tests/structs_tests.cc b/tools/fidl/fidlc/tests/structs_tests.cc
index 050b62c..57cb371 100644
--- a/tools/fidl/fidlc/tests/structs_tests.cc
+++ b/tools/fidl/fidlc/tests/structs_tests.cc
@@ -62,7 +62,7 @@
     field int64 = A;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "A", "example");
+  library.ExpectFail(ErrNameNotFound, "A", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -201,7 +201,7 @@
     field MyEnum = A;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "A", "example");
+  library.ExpectFail(ErrNameNotFound, "A", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
diff --git a/tools/fidl/fidlc/tests/test_library.cc b/tools/fidl/fidlc/tests/test_library.cc
index 482f1e6..d0e9b8d 100644
--- a/tools/fidl/fidlc/tests/test_library.cc
+++ b/tools/fidl/fidlc/tests/test_library.cc
@@ -14,7 +14,7 @@
 
 namespace fidlc {
 
-void SharedAmongstLibraries::AddLibraryZx() {
+void SharedAmongstLibraries::UseLibraryZx() {
   TestLibrary zx_lib(this, "zx.fidl", R"FIDL(
 library zx;
 
@@ -43,7 +43,7 @@
   ZX_ASSERT_MSG(zx_lib.Compile(), "failed to compile library zx");
 }
 
-void SharedAmongstLibraries::AddLibraryFdf() {
+void SharedAmongstLibraries::UseLibraryFdf() {
   TestLibrary fdf_lib(this, "fdf.fidl", R"FIDL(
 library fdf;
 
@@ -147,31 +147,11 @@
   return parser.Success();
 }
 
-// See ordinals_tests.cc
-static RawOrdinal64 GetGeneratedOrdinal64ForTesting(
-    const std::vector<std::string_view>& library_name, const std::string_view& protocol_name,
-    const std::string_view& selector_name, const SourceElement& source_element) {
-  static std::map<std::string, uint64_t> special_selectors = {
-      {"ThisOneHashesToZero", 0},
-      {"ClashOne", 456789},
-      {"ClashOneReplacement", 987654},
-      {"ClashTwo", 456789},
-  };
-  if (library_name.size() == 1 && library_name[0] == "methodhasher" &&
-      (protocol_name == "Special" || protocol_name == "SpecialComposed")) {
-    auto it = special_selectors.find(std::string(selector_name));
-    ZX_ASSERT_MSG(it != special_selectors.end(), "only special selectors allowed");
-    return RawOrdinal64(source_element, it->second);
-  }
-  return GetGeneratedOrdinal64(library_name, protocol_name, selector_name, source_element);
-}
-
 // Compiles the library. Must have compiled all dependencies first, using the
 // same SharedAmongstLibraries object for all of them.
 bool TestLibrary::Compile() {
   used_ = true;
-  Compiler compiler(all_libraries(), version_selection(), GetGeneratedOrdinal64ForTesting,
-                    experimental_flags());
+  Compiler compiler(all_libraries(), version_selection(), method_hasher(), experimental_flags());
   for (auto source_file : all_sources_) {
     Lexer lexer(*source_file, reporter());
     Parser parser(&lexer, reporter(), experimental_flags());
@@ -229,18 +209,6 @@
   return passed;
 }
 
-const Library* TestLibrary::LookupLibrary(std::string_view name) {
-  std::vector<std::string_view> parts;
-  size_t dot_idx = 0;
-  for (size_t i = 0; dot_idx != std::string::npos; i = dot_idx + 1) {
-    dot_idx = name.find('.', i);
-    parts.push_back(name.substr(i, dot_idx));
-  }
-  auto library = all_libraries()->Lookup(parts);
-  ZX_ASSERT_MSG(library, "library not found");
-  return library;
-}
-
 const Bits* TestLibrary::LookupBits(std::string_view name) {
   for (const auto& bits_decl : compilation_->declarations.bits) {
     if (bits_decl->name.decl_name() == name) {
diff --git a/tools/fidl/fidlc/tests/test_library.h b/tools/fidl/fidlc/tests/test_library.h
index 45a730e..b98f8c3 100644
--- a/tools/fidl/fidlc/tests/test_library.h
+++ b/tools/fidl/fidlc/tests/test_library.h
@@ -18,9 +18,7 @@
 #include "tools/fidl/fidlc/src/findings.h"
 #include "tools/fidl/fidlc/src/flat_ast.h"
 #include "tools/fidl/fidlc/src/json_generator.h"
-#include "tools/fidl/fidlc/src/ordinals.h"
 #include "tools/fidl/fidlc/src/source_file.h"
-#include "tools/fidl/fidlc/src/utils.h"
 #include "tools/fidl/fidlc/src/versioning_types.h"
 #include "tools/fidl/fidlc/src/virtual_source_file.h"
 
@@ -66,14 +64,24 @@
   virtual Libraries* all_libraries() = 0;
   virtual VersionSelection* version_selection() = 0;
   virtual ExperimentalFlagSet& experimental_flags() = 0;
+  virtual MethodHasher& method_hasher() = 0;
+
+  // Adds and compiles a library similar to //zircon/vsdo/zx, defining "Handle",
+  // "ObjType", and "Rights".
+  virtual void UseLibraryZx() = 0;
+  // Adds and compiles a library defining fdf.handle and fdf.obj_type.
+  virtual void UseLibraryFdf() = 0;
 
   const std::vector<std::unique_ptr<Diagnostic>>& errors() { return reporter()->errors(); }
   const std::vector<std::unique_ptr<Diagnostic>>& warnings() { return reporter()->warnings(); }
   std::vector<Diagnostic*> Diagnostics() { return reporter()->Diagnostics(); }
   void set_warnings_as_errors(bool value) { reporter()->set_warnings_as_errors(value); }
   void PrintReports() { reporter()->PrintReports(/*enable_color=*/false); }
-  void SelectVersion(const std::string& platform, std::string_view version) {
-    version_selection()->Insert(Platform::Parse(platform).value(), Version::Parse(version).value());
+  void SelectVersion(std::string platform, std::string_view version) {
+    SelectVersion(std::move(platform), Version::Parse(version).value());
+  }
+  void SelectVersion(std::string platform, Version version) {
+    version_selection()->Insert(Platform::Parse(std::move(platform)).value(), version);
   }
   void EnableFlag(ExperimentalFlag flag) { experimental_flags().Enable(flag); }
 };
@@ -87,17 +95,13 @@
   SharedAmongstLibraries(const SharedAmongstLibraries&) = delete;
   SharedAmongstLibraries(SharedAmongstLibraries&&) = delete;
 
-  // Adds and compiles a library similar to //zircon/vsdo/zx, defining "Handle",
-  // "ObjType", and "Rights".
-  void AddLibraryZx();
-
-  // Adds and compiles a library defining fdf.handle and fdf.obj_type.
-  void AddLibraryFdf();
-
   Reporter* reporter() override { return &reporter_; }
   Libraries* all_libraries() override { return &all_libraries_; }
   VersionSelection* version_selection() override { return &version_selection_; }
   ExperimentalFlagSet& experimental_flags() override { return experimental_flags_; }
+  MethodHasher& method_hasher() override { return method_hasher_; }
+  void UseLibraryZx() override;
+  void UseLibraryFdf() override;
 
   std::vector<std::unique_ptr<SourceFile>>& all_sources_of_all_libraries() {
     return all_sources_of_all_libraries_;
@@ -106,6 +110,7 @@
  private:
   Reporter reporter_;
   VirtualSourceFile virtual_file_{"generated"};
+  MethodHasher method_hasher_ = Sha256MethodHasher;
   Libraries all_libraries_;
   std::vector<std::unique_ptr<SourceFile>> all_sources_of_all_libraries_;
   VersionSelection version_selection_;
@@ -151,24 +156,13 @@
 
   ~TestLibrary();
 
-  // Helper for making a single test library depend on library zx, without
-  // requiring an explicit SharedAmongstLibraries.
-  void UseLibraryZx() {
-    ZX_ASSERT_MSG(!compilation_, "must call before compiling");
-    owned_shared_.value().AddLibraryZx();
-  }
-
-  // Helper for making a single test library depend on library fdf, without
-  // requiring an explicit SharedAmongstLibraries.
-  void UseLibraryFdf() {
-    ZX_ASSERT_MSG(!compilation_, "must call before compiling");
-    owned_shared_.value().AddLibraryFdf();
-  }
-
   Reporter* reporter() override { return shared_->reporter(); }
   Libraries* all_libraries() override { return shared_->all_libraries(); }
   VersionSelection* version_selection() override { return shared_->version_selection(); }
   ExperimentalFlagSet& experimental_flags() override { return shared_->experimental_flags(); }
+  MethodHasher& method_hasher() override { return shared_->method_hasher(); }
+  void UseLibraryZx() override { shared_->UseLibraryZx(); }
+  void UseLibraryFdf() override { shared_->UseLibraryFdf(); }
 
   void AddSource(const std::string& filename, const std::string& raw_source_code);
 
@@ -184,14 +178,16 @@
   // Record that a particular error is expected during the compile.
   // The args can either match the ErrorDef's argument types, or they can be string literals.
   template <ErrorId Id, typename... Args>
-  void ExpectFail(const ErrorDef<Id, Args...>& def, identity_t<StringOrArg<Args>>... args) {
+  void ExpectFail(const ErrorDef<Id, Args...>& def,
+                  cpp20::type_identity_t<StringOrArg<Args>>... args) {
     expected_diagnostics_.push_back(internal::FormatDiagnostic(def.msg, args.string...));
   }
 
   // Record that a particular warning is expected during the compile.
   // The args can either match the WarningDef's argument types, or they can be string literals.
   template <ErrorId Id, typename... Args>
-  void ExpectWarn(const WarningDef<Id, Args...>& def, identity_t<StringOrArg<Args>>... args) {
+  void ExpectWarn(const WarningDef<Id, Args...>& def,
+                  cpp20::type_identity_t<StringOrArg<Args>>... args) {
     expected_diagnostics_.push_back(internal::FormatDiagnostic(def.msg, args.string...));
   }
 
@@ -219,13 +215,6 @@
     return out.str();
   }
 
-  // Note: We don't provide a convenient library() method because inspecting a
-  // Library is usually the wrong thing to do in tests. What usually matters is
-  // the Compilation, for which we provide compilation() and helpers like
-  // LookupStruct() etc. However, sometimes tests really need to get a Library*
-  // (e.g. to construct Name::Key), hence this method.
-  const Library* LookupLibrary(std::string_view name);
-
   const Bits* LookupBits(std::string_view name);
   const Const* LookupConstant(std::string_view name);
   const Enum* LookupEnum(std::string_view name);
@@ -239,6 +228,19 @@
   const Overlay* LookupOverlay(std::string_view name);
   const Protocol* LookupProtocol(std::string_view name);
 
+  bool HasBits(std::string_view name) { return LookupBits(name) != nullptr; }
+  bool HasConstant(std::string_view name) { return LookupConstant(name) != nullptr; }
+  bool HasEnum(std::string_view name) { return LookupEnum(name) != nullptr; }
+  bool HasResource(std::string_view name) { return LookupResource(name) != nullptr; }
+  bool HasService(std::string_view name) { return LookupService(name) != nullptr; }
+  bool HasStruct(std::string_view name) { return LookupStruct(name) != nullptr; }
+  bool HasNewType(std::string_view name) { return LookupNewType(name) != nullptr; }
+  bool HasTable(std::string_view name) { return LookupTable(name) != nullptr; }
+  bool HasAlias(std::string_view name) { return LookupAlias(name) != nullptr; }
+  bool HasUnion(std::string_view name) { return LookupUnion(name) != nullptr; }
+  bool HasOverlay(std::string_view name) { return LookupOverlay(name) != nullptr; }
+  bool HasProtocol(std::string_view name) { return LookupProtocol(name) != nullptr; }
+
   const SourceFile& source_file() const {
     ZX_ASSERT_MSG(all_sources_.size() == 1, "convenience method only possible with single source");
     return *all_sources_.at(0);
@@ -251,21 +253,15 @@
   const Findings& findings() const { return findings_; }
   const std::vector<std::string>& lints() const { return lints_; }
 
-  const Compilation* compilation() const {
-    ZX_ASSERT_MSG(compilation_, "must compile successfully before accessing compilation");
-    return compilation_.get();
-  }
-
+  std::string_view name() const { return compilation_->library_name; }
+  const Platform& platform() const { return *compilation_->platform; }
   const AttributeList* attributes() { return compilation_->library_attributes; }
-
   const std::vector<const Struct*>& external_structs() const {
     return compilation_->external_structs;
   }
-
   const std::vector<const Decl*>& declaration_order() const {
     return compilation_->declaration_order;
   }
-
   const std::vector<Compilation::Dependency>& direct_and_composed_dependencies() const {
     return compilation_->direct_and_composed_dependencies;
   }
diff --git a/tools/fidl/fidlc/tests/transport_tests.cc b/tools/fidl/fidlc/tests/transport_tests.cc
index f55966d..2917ddf 100644
--- a/tools/fidl/fidlc/tests/transport_tests.cc
+++ b/tools/fidl/fidlc/tests/transport_tests.cc
@@ -131,7 +131,7 @@
 };
 )FIDL");
   library.UseLibraryFdf();
-  library.ExpectFail(ErrHandleUsedInIncompatibleTransport, "fdf.handle", "Channel", "protocol 'P'");
+  library.ExpectFail(ErrHandleUsedInIncompatibleTransport, "fdf/handle", "Channel", "protocol 'P'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -260,7 +260,7 @@
   });
 };
 )FIDL");
-  library.ExpectFail(ErrHandleUsedInIncompatibleTransport, "example.handle", "Channel",
+  library.ExpectFail(ErrHandleUsedInIncompatibleTransport, "example/handle", "Channel",
                      "protocol 'P'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
@@ -269,7 +269,7 @@
   TestLibrary library;
   library.AddFile("bad/fi-0117.test.fidl");
   library.UseLibraryFdf();
-  library.ExpectFail(ErrHandleUsedInIncompatibleTransport, "fdf.handle", "Channel",
+  library.ExpectFail(ErrHandleUsedInIncompatibleTransport, "fdf/handle", "Channel",
                      "protocol 'Protocol'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
diff --git a/tools/fidl/fidlc/tests/types_tests.cc b/tools/fidl/fidlc/tests/types_tests.cc
index b4977f7..57837f9 100644
--- a/tools/fidl/fidlc/tests/types_tests.cc
+++ b/tools/fidl/fidlc/tests/types_tests.cc
@@ -145,7 +145,7 @@
 // sync, until the latter is generated.
 TEST(TypesTests, GoodRights) { static_assert(sizeof(RightsWrappedType) == sizeof(zx_rights_t)); }
 
-TEST(NewSyntaxTests, GoodTypeDeclOfAnonymousLayouts) {
+TEST(TypesTests, GoodTypeDeclOfAnonymousLayouts) {
   TestLibrary library(R"FIDL(
 library example;
 type TypeDecl = struct {
@@ -189,14 +189,14 @@
   EXPECT_EQ(type_decl_f4->members.size(), 1u);
 }
 
-TEST(NewSyntaxTests, BadTypeDeclOfNewTypeErrors) {
+TEST(TypesTests, BadTypeDeclOfNewTypeErrors) {
   TestLibrary library;
   library.AddFile("bad/fi-0062.test.fidl");
   library.ExpectFail(ErrNewTypesNotAllowed, "Matrix", "array");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(NewSyntaxTests, GoodTypeParameters) {
+TEST(TypesTests, GoodTypeParameters) {
   TestLibrary library(R"FIDL(
 library example;
 type Inner = struct{};
@@ -235,16 +235,16 @@
   auto type_decl_vector_anon = library.LookupStruct("V3");
   ASSERT_NE(type_decl_vector_anon, nullptr);
   EXPECT_EQ(type_decl_vector_anon->members.size(), 2u);
-  ASSERT_NE(library.LookupStruct("I0"), nullptr);
-  ASSERT_NE(library.LookupStruct("I1"), nullptr);
+  ASSERT_TRUE(library.HasStruct("I0"));
+  ASSERT_TRUE(library.HasStruct("I1"));
   auto type_decl_array_anon = library.LookupStruct("A3");
   ASSERT_NE(type_decl_array_anon, nullptr);
   EXPECT_EQ(type_decl_array_anon->members.size(), 2u);
-  ASSERT_NE(library.LookupStruct("I2"), nullptr);
-  ASSERT_NE(library.LookupStruct("I3"), nullptr);
+  ASSERT_TRUE(library.HasStruct("I2"));
+  ASSERT_TRUE(library.HasStruct("I3"));
 }
 
-TEST(NewSyntaxTests, GoodLayoutMemberConstraints) {
+TEST(TypesTests, GoodLayoutMemberConstraints) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -275,7 +275,7 @@
   EXPECT_EQ(u1_type->type_decl->kind, Decl::Kind::kUnion);
 }
 
-TEST(NewSyntaxTests, GoodConstraintsOnVectors) {
+TEST(TypesTests, GoodConstraintsOnVectors) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -427,7 +427,7 @@
   EXPECT_EQ(a15_type->ElementCount(), a15_invocation.size_resolved->value);
 }
 
-TEST(NewSyntaxTests, GoodConstraintsOnUnions) {
+TEST(TypesTests, GoodConstraintsOnUnions) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -474,7 +474,7 @@
   EXPECT_EQ(u5_type->nullability, Nullability::kNullable);
 }
 
-TEST(NewSyntaxTests, GoodConstraintsOnHandles) {
+TEST(TypesTests, GoodConstraintsOnHandles) {
   TestLibrary library(R"FIDL(
 library example;
 using zx;
@@ -532,14 +532,14 @@
   EXPECT_EQ(h5_type->nullability, Nullability::kNullable);
 }
 
-TEST(NewSyntaxTests, BadTooManyLayoutParameters) {
+TEST(TypesTests, BadTooManyLayoutParameters) {
   TestLibrary library;
   library.AddFile("bad/fi-0162-b.test.fidl");
   library.ExpectFail(ErrWrongNumberOfLayoutParameters, "uint8", 0, 1);
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(NewSyntaxTests, BadZeroParameters) {
+TEST(TypesTests, BadZeroParameters) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -553,7 +553,7 @@
   EXPECT_EQ(library.errors()[0]->span.data(), "array");
 }
 
-TEST(NewSyntaxTests, BadNotEnoughParameters) {
+TEST(TypesTests, BadNotEnoughParameters) {
   TestLibrary library;
   library.AddFile("bad/fi-0162-a.test.fidl");
   library.ExpectFail(ErrWrongNumberOfLayoutParameters, "array", 2, 1);
@@ -561,7 +561,7 @@
   EXPECT_EQ(library.errors()[0]->span.data(), "<8>");
 }
 
-TEST(NewSyntaxTests, BadTooManyConstraints) {
+TEST(TypesTests, BadTooManyConstraints) {
   TestLibrary library;
   library.AddFile("bad/fi-0164.test.fidl");
   library.ExpectFail(ErrTooManyConstraints, "string", 2, 3);
@@ -569,7 +569,7 @@
   EXPECT_EQ(library.errors()[0]->span.data(), "<0, optional, 20>");
 }
 
-TEST(NewSyntaxTests, BadParameterizedAnonymousLayout) {
+TEST(TypesTests, BadParameterizedAnonymousLayout) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -582,7 +582,7 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(NewSyntaxTests, BadConstrainTwice) {
+TEST(TypesTests, BadConstrainTwice) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -603,7 +603,7 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(NewSyntaxTests, GoodNoOverlappingConstraints) {
+TEST(TypesTests, GoodNoOverlappingConstraints) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -620,14 +620,14 @@
   ASSERT_COMPILED(library);
 }
 
-TEST(NewSyntaxTests, BadWantTypeLayoutParameter) {
+TEST(TypesTests, BadWantTypeLayoutParameter) {
   TestLibrary library;
   library.AddFile("bad/fi-0165.test.fidl");
   library.ExpectFail(ErrExpectedType);
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(NewSyntaxTests, BadWantValueLayoutParameter) {
+TEST(TypesTests, BadWantValueLayoutParameter) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -640,14 +640,14 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(NewSyntaxTests, BadUnresolvableConstraint) {
+TEST(TypesTests, BadUnresolvableConstraint) {
   TestLibrary library;
   library.AddFile("bad/fi-0166.test.fidl");
   library.ExpectFail(ErrUnexpectedConstraint, "vector");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(NewSyntaxTests, BadShadowedOptional) {
+TEST(TypesTests, BadShadowedOptional) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -662,7 +662,7 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(NewSyntaxTests, BadWrongConstraintType) {
+TEST(TypesTests, BadWrongConstraintType) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -676,7 +676,7 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(InternalTypes, CannotReferToUnqualifiedInternalType) {
+TEST(TypesTests, CannotReferToUnqualifiedInternalType) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -685,11 +685,11 @@
 };
 )FIDL");
 
-  library.ExpectFail(ErrNameNotFound, "FrameworkErr", "example");
+  library.ExpectFail(ErrNameNotFound, "FrameworkErr", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(InternalTypes, CannotReferToQualifiedInternalType) {
+TEST(TypesTests, CannotReferToQualifiedInternalType) {
   TestLibrary library(R"FIDL(
 library example;
 
@@ -698,7 +698,7 @@
 };
 )FIDL");
 
-  library.ExpectFail(ErrNameNotFound, "FrameworkErr", "fidl");
+  library.ExpectFail(ErrNameNotFound, "FrameworkErr", "library 'fidl'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
diff --git a/tools/fidl/fidlc/tests/typeshape_tests.cc b/tools/fidl/fidlc/tests/typeshape_tests.cc
index 7c7503d..df702b0 100644
--- a/tools/fidl/fidlc/tests/typeshape_tests.cc
+++ b/tools/fidl/fidlc/tests/typeshape_tests.cc
@@ -2396,14 +2396,14 @@
 
 // TODO(https://fxbug.dev/323940291): Enable this. Currently can't report the
 // error because there is no SourceSpan to use.
-TEST(TypeShapeTests, DISABLED_BadIntegerOverflowArray) {
+TEST(TypeshapeTests, DISABLED_BadIntegerOverflowArray) {
   TestLibrary library;
   library.AddFile("bad/fi-0207.test.fidl");
   library.ExpectFail(ErrTypeShapeIntegerOverflow, 536870912, '*', 8);
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(TypeShapeTests, BadIntegerOverflowStruct) {
+TEST(TypeshapeTests, BadIntegerOverflowStruct) {
   TestLibrary library(R"FIDL(
 library example;
 type Foo = struct {
@@ -2415,7 +2415,7 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(TypeShapeTests, BadInlineSizeExceedsLimit) {
+TEST(TypeshapeTests, BadInlineSizeExceedsLimit) {
   TestLibrary library(R"FIDL(
 library example;
 type Foo = struct {
diff --git a/tools/fidl/fidlc/tests/using_tests.cc b/tools/fidl/fidlc/tests/using_tests.cc
index 7272b35..c64edf6 100644
--- a/tools/fidl/fidlc/tests/using_tests.cc
+++ b/tools/fidl/fidlc/tests/using_tests.cc
@@ -109,7 +109,7 @@
     dep dependent.Bar;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "dependent", "example");
+  library.ExpectFail(ErrNameNotFound, "dependent", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -140,7 +140,7 @@
     dep1 dependent.Bar;
 };
 )FIDL");
-  library.ExpectFail(ErrNameNotFound, "dependent", "example");
+  library.ExpectFail(ErrNameNotFound, "dependent", "library 'example'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -282,7 +282,7 @@
   TestLibrary library(&shared);
   library.AddFile("bad/fi-0178.test.fidl");
 
-  library.ExpectFail(ErrUnusedImport, "test.bad.fi0178", "dependent");
+  library.ExpectFail(ErrUnusedImport, "library 'test.bad.fi0178'", "library 'dependent'");
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
@@ -305,7 +305,7 @@
 
   auto unused = shared.all_libraries()->Unused();
   ASSERT_EQ(unused.size(), 1u);
-  ASSERT_EQ(NameLibrary((*unused.begin())->name), "not.used");
+  ASSERT_EQ((*unused.begin())->name, "not.used");
 }
 
 TEST(UsingTests, BadLibraryDeclarationNameCollision) {
diff --git a/tools/fidl/fidlc/tests/utils_tests.cc b/tools/fidl/fidlc/tests/utils_tests.cc
index 01904b8..2c0a246f 100644
--- a/tools/fidl/fidlc/tests/utils_tests.cc
+++ b/tools/fidl/fidlc/tests/utils_tests.cc
@@ -13,9 +13,9 @@
 namespace fidlc {
 namespace {
 
-void compare_id_to_words(std::string_view id, std::string_view expected_lowercase_words) {
+void CompareIdToWords(std::string_view id, std::string_view expected_lowercase_words) {
   std::ostringstream actual;
-  for (const auto& word : id_to_words(id)) {
+  for (const auto& word : SplitIdentifierWords(id)) {
     if (actual.tellp() > 0) {
       actual << ' ';
     }
@@ -25,41 +25,41 @@
 }
 
 TEST(UtilsTests, IdToWords) {
-  compare_id_to_words("agent_request_count", "agent request count");
-  compare_id_to_words("common", "common");
-  compare_id_to_words("Service", "service");
-  compare_id_to_words("Blink32", "blink32");
-  compare_id_to_words("the21jumpStreet", "the21jump street");
-  compare_id_to_words("the21JumpStreet", "the21 jump street");
-  compare_id_to_words("onOntologyUpdate", "on ontology update");
-  compare_id_to_words("urlLoader", "url loader");
-  compare_id_to_words("onUrlLoader", "on url loader");
-  compare_id_to_words("OnOntologyUpdate", "on ontology update");
-  compare_id_to_words("UrlLoader", "url loader");
-  compare_id_to_words("OnUrlLoader", "on url loader");
-  compare_id_to_words("kUrlLoader", "url loader");
-  compare_id_to_words("kOnUrlLoader", "on url loader");
-  compare_id_to_words("WhatIfSomeoneDoes_This", "what if someone does this");
-  compare_id_to_words("SOME_CONST", "some const");
-  compare_id_to_words("NAME_MIN_LEN", "name min len");
-  compare_id_to_words("OnPress", "on press");
-  compare_id_to_words("URLLoader", "url loader");
-  compare_id_to_words("PPPOE", "pppoe");
-  compare_id_to_words("PPP_O_E", "ppp o e");
-  compare_id_to_words("PPP_o_E", "ppp o e");
+  CompareIdToWords("agent_request_count", "agent request count");
+  CompareIdToWords("common", "common");
+  CompareIdToWords("Service", "service");
+  CompareIdToWords("Blink32", "blink32");
+  CompareIdToWords("the21jumpStreet", "the21jump street");
+  CompareIdToWords("the21JumpStreet", "the21 jump street");
+  CompareIdToWords("onOntologyUpdate", "on ontology update");
+  CompareIdToWords("urlLoader", "url loader");
+  CompareIdToWords("onUrlLoader", "on url loader");
+  CompareIdToWords("OnOntologyUpdate", "on ontology update");
+  CompareIdToWords("UrlLoader", "url loader");
+  CompareIdToWords("OnUrlLoader", "on url loader");
+  CompareIdToWords("kUrlLoader", "url loader");
+  CompareIdToWords("kOnUrlLoader", "on url loader");
+  CompareIdToWords("WhatIfSomeoneDoes_This", "what if someone does this");
+  CompareIdToWords("SOME_CONST", "some const");
+  CompareIdToWords("NAME_MIN_LEN", "name min len");
+  CompareIdToWords("OnPress", "on press");
+  CompareIdToWords("URLLoader", "url loader");
+  CompareIdToWords("PPPOE", "pppoe");
+  CompareIdToWords("PPP_O_E", "ppp o e");
+  CompareIdToWords("PPP_o_E", "ppp o e");
 
   // Note the next two tests have expected results that may seem
   // counter-intuitive, but if IDs like "URLLoader" are expected to
   // translate to the words "url loader", then these translations
   // are consistent.
-  compare_id_to_words("PppOE", "ppp oe");
-  compare_id_to_words("PPPoE", "pp po e");
+  CompareIdToWords("PppOE", "ppp oe");
+  CompareIdToWords("PPPoE", "pp po e");
 }
 
-void case_test(bool valid_conversion, std::string case_name,
-               fit::function<bool(std::string)> is_case,
-               fit::function<std::string(std::string)> to_case, std::string original,
-               std::string expected) {
+void CaseTest(bool valid_conversion, std::string_view case_name,
+              fit::function<bool(std::string_view)> is_case,
+              fit::function<std::string(std::string_view)> to_case, std::string_view original,
+              std::string_view expected) {
   EXPECT_FALSE(is_case(original)) << original << " is " << case_name;
   std::string converted = to_case(original);
   EXPECT_EQ(converted, expected) << "from '" << original << "' to '" << converted << "' != '"
@@ -76,355 +76,131 @@
 }
 
 #define ASSERT_CASE(CASE, FROM, TO) \
-  case_test(/*valid_conversion=*/true, #CASE, is_##CASE##_case, to_##CASE##_case, FROM, TO)
+  CaseTest(/*valid_conversion=*/true, #CASE, Is##CASE##Case, To##CASE##Case, FROM, TO)
 
 #define ASSERT_BAD_CASE(CASE, FROM, TO) \
-  case_test(/*valid_conversion=*/false, #CASE, is_##CASE##_case, to_##CASE##_case, FROM, TO)
+  CaseTest(/*valid_conversion=*/false, #CASE, Is##CASE##Case, To##CASE##Case, FROM, TO)
 
 TEST(UtilsTests, UpperCamelCase) {
-  ASSERT_CASE(upper_camel, "x", "X");
-  ASSERT_CASE(upper_camel, "xy", "Xy");
-  ASSERT_BAD_CASE(upper_camel, "x_y", "XY");
-  ASSERT_CASE(upper_camel, "xyz_123", "Xyz123");
-  ASSERT_CASE(upper_camel, "xy_z_123", "XyZ123");
-  ASSERT_CASE(upper_camel, "xy_z123", "XyZ123");
-  ASSERT_CASE(upper_camel, "days_in_a_week", "DaysInAWeek");
-  ASSERT_CASE(upper_camel, "android8_0_0", "Android8_0_0");
-  ASSERT_CASE(upper_camel, "android_8_0_0", "Android8_0_0");
-  ASSERT_CASE(upper_camel, "x_marks_the_spot", "XMarksTheSpot");
-  ASSERT_CASE(upper_camel, "RealID", "RealId");
-  ASSERT_CASE(upper_camel, "real_id", "RealId");
-  ASSERT_BAD_CASE(upper_camel, "real_i_d", "RealID");
-  ASSERT_CASE(upper_camel, "real3d", "Real3d");
-  ASSERT_CASE(upper_camel, "real3_d", "Real3D");
-  ASSERT_CASE(upper_camel, "real_3d", "Real3d");
-  ASSERT_CASE(upper_camel, "real_3_d", "Real3D");
-  ASSERT_CASE(upper_camel, "hello_e_world", "HelloEWorld");
-  ASSERT_CASE(upper_camel, "hello_eworld", "HelloEworld");
-  ASSERT_CASE(upper_camel, "URLLoader", "UrlLoader");
-  ASSERT_CASE(upper_camel, "is_21Jump_street", "Is21JumpStreet");
-  ASSERT_CASE(upper_camel, "URLloader", "UrLloader");
-  ASSERT_CASE(upper_camel, "URLLoader", "UrlLoader");
-  ASSERT_CASE(upper_camel, "url_loader", "UrlLoader");
-  ASSERT_CASE(upper_camel, "URL_LOADER", "UrlLoader");
-  ASSERT_CASE(upper_camel, "urlLoader", "UrlLoader");
-  ASSERT_CASE(upper_camel, "kUrlLoader", "UrlLoader");
-  ASSERT_CASE(upper_camel, "kURLLoader", "UrlLoader");
+  ASSERT_CASE(UpperCamel, "x", "X");
+  ASSERT_CASE(UpperCamel, "xy", "Xy");
+  ASSERT_BAD_CASE(UpperCamel, "x_y", "XY");
+  ASSERT_CASE(UpperCamel, "xyz_123", "Xyz123");
+  ASSERT_CASE(UpperCamel, "xy_z_123", "XyZ123");
+  ASSERT_CASE(UpperCamel, "xy_z123", "XyZ123");
+  ASSERT_CASE(UpperCamel, "days_in_a_week", "DaysInAWeek");
+  ASSERT_CASE(UpperCamel, "android8_0_0", "Android8_0_0");
+  ASSERT_CASE(UpperCamel, "android_8_0_0", "Android8_0_0");
+  ASSERT_CASE(UpperCamel, "x_marks_the_spot", "XMarksTheSpot");
+  ASSERT_CASE(UpperCamel, "RealID", "RealId");
+  ASSERT_CASE(UpperCamel, "real_id", "RealId");
+  ASSERT_BAD_CASE(UpperCamel, "real_i_d", "RealID");
+  ASSERT_CASE(UpperCamel, "real3d", "Real3d");
+  ASSERT_CASE(UpperCamel, "real3_d", "Real3D");
+  ASSERT_CASE(UpperCamel, "real_3d", "Real3d");
+  ASSERT_CASE(UpperCamel, "real_3_d", "Real3D");
+  ASSERT_CASE(UpperCamel, "hello_e_world", "HelloEWorld");
+  ASSERT_CASE(UpperCamel, "hello_eworld", "HelloEworld");
+  ASSERT_CASE(UpperCamel, "URLLoader", "UrlLoader");
+  ASSERT_CASE(UpperCamel, "is_21Jump_street", "Is21JumpStreet");
+  ASSERT_CASE(UpperCamel, "URLloader", "UrLloader");
+  ASSERT_CASE(UpperCamel, "URLLoader", "UrlLoader");
+  ASSERT_CASE(UpperCamel, "url_loader", "UrlLoader");
+  ASSERT_CASE(UpperCamel, "URL_LOADER", "UrlLoader");
+  ASSERT_CASE(UpperCamel, "urlLoader", "UrlLoader");
+  ASSERT_CASE(UpperCamel, "kUrlLoader", "UrlLoader");
+  ASSERT_CASE(UpperCamel, "kURLLoader", "UrlLoader");
 }
 
 TEST(UtilsTests, LowerCamelCase) {
-  ASSERT_CASE(lower_camel, "X", "x");
-  ASSERT_CASE(lower_camel, "XY", "xy");
-  ASSERT_CASE(lower_camel, "X_Y", "xY");
-  ASSERT_CASE(lower_camel, "XYZ_123", "xyz123");
-  ASSERT_CASE(lower_camel, "XY_Z_123", "xyZ123");
-  ASSERT_CASE(lower_camel, "XY_Z123", "xyZ123");
-  ASSERT_CASE(lower_camel, "DAYS_IN_A_WEEK", "daysInAWeek");
-  ASSERT_CASE(lower_camel, "ANDROID8_0_0", "android8_0_0");
-  ASSERT_CASE(lower_camel, "ANDROID_8_0_0", "android8_0_0");
-  ASSERT_CASE(lower_camel, "X_MARKS_THE_SPOT", "xMarksTheSpot");
-  ASSERT_CASE(lower_camel, "realID", "realId");
-  ASSERT_CASE(lower_camel, "REAL_ID", "realId");
-  ASSERT_BAD_CASE(lower_camel, "REAL_I_D", "realID");
-  ASSERT_CASE(lower_camel, "REAL3D", "real3D");
-  ASSERT_CASE(lower_camel, "REAL3_D", "real3D");
-  ASSERT_CASE(lower_camel, "REAL_3D", "real3D");
-  ASSERT_CASE(lower_camel, "REAL_3_D", "real3D");
-  ASSERT_CASE(lower_camel, "HELLO_E_WORLD", "helloEWorld");
-  ASSERT_CASE(lower_camel, "HELLO_EWORLD", "helloEworld");
-  ASSERT_CASE(lower_camel, "URLLoader", "urlLoader");
-  ASSERT_CASE(lower_camel, "is_21Jump_street", "is21JumpStreet");
-  ASSERT_CASE(lower_camel, "URLloader", "urLloader");
-  ASSERT_CASE(lower_camel, "UrlLoader", "urlLoader");
-  ASSERT_CASE(lower_camel, "URLLoader", "urlLoader");
-  ASSERT_CASE(lower_camel, "url_loader", "urlLoader");
-  ASSERT_CASE(lower_camel, "URL_LOADER", "urlLoader");
-  ASSERT_CASE(lower_camel, "kUrlLoader", "urlLoader");
-  ASSERT_CASE(lower_camel, "kURLLoader", "urlLoader");
+  ASSERT_CASE(LowerCamel, "X", "x");
+  ASSERT_CASE(LowerCamel, "XY", "xy");
+  ASSERT_CASE(LowerCamel, "X_Y", "xY");
+  ASSERT_CASE(LowerCamel, "XYZ_123", "xyz123");
+  ASSERT_CASE(LowerCamel, "XY_Z_123", "xyZ123");
+  ASSERT_CASE(LowerCamel, "XY_Z123", "xyZ123");
+  ASSERT_CASE(LowerCamel, "DAYS_IN_A_WEEK", "daysInAWeek");
+  ASSERT_CASE(LowerCamel, "ANDROID8_0_0", "android8_0_0");
+  ASSERT_CASE(LowerCamel, "ANDROID_8_0_0", "android8_0_0");
+  ASSERT_CASE(LowerCamel, "X_MARKS_THE_SPOT", "xMarksTheSpot");
+  ASSERT_CASE(LowerCamel, "realID", "realId");
+  ASSERT_CASE(LowerCamel, "REAL_ID", "realId");
+  ASSERT_BAD_CASE(LowerCamel, "REAL_I_D", "realID");
+  ASSERT_CASE(LowerCamel, "REAL3D", "real3D");
+  ASSERT_CASE(LowerCamel, "REAL3_D", "real3D");
+  ASSERT_CASE(LowerCamel, "REAL_3D", "real3D");
+  ASSERT_CASE(LowerCamel, "REAL_3_D", "real3D");
+  ASSERT_CASE(LowerCamel, "HELLO_E_WORLD", "helloEWorld");
+  ASSERT_CASE(LowerCamel, "HELLO_EWORLD", "helloEworld");
+  ASSERT_CASE(LowerCamel, "URLLoader", "urlLoader");
+  ASSERT_CASE(LowerCamel, "is_21Jump_street", "is21JumpStreet");
+  ASSERT_CASE(LowerCamel, "URLloader", "urLloader");
+  ASSERT_CASE(LowerCamel, "UrlLoader", "urlLoader");
+  ASSERT_CASE(LowerCamel, "URLLoader", "urlLoader");
+  ASSERT_CASE(LowerCamel, "url_loader", "urlLoader");
+  ASSERT_CASE(LowerCamel, "URL_LOADER", "urlLoader");
+  ASSERT_CASE(LowerCamel, "kUrlLoader", "urlLoader");
+  ASSERT_CASE(LowerCamel, "kURLLoader", "urlLoader");
 }
 
 TEST(UtilsTests, UpperSnakeCase) {
-  ASSERT_CASE(upper_snake, "x", "X");
-  ASSERT_CASE(upper_snake, "xy", "XY");
-  ASSERT_CASE(upper_snake, "xY", "X_Y");
-  ASSERT_CASE(upper_snake, "xyz123", "XYZ123");
-  ASSERT_CASE(upper_snake, "xyz_123", "XYZ_123");
-  ASSERT_CASE(upper_snake, "xyZ123", "XY_Z123");
-  ASSERT_CASE(upper_snake, "daysInAWeek", "DAYS_IN_A_WEEK");
-  ASSERT_CASE(upper_snake, "android8_0_0", "ANDROID8_0_0");
-  ASSERT_CASE(upper_snake, "android_8_0_0", "ANDROID_8_0_0");
-  ASSERT_CASE(upper_snake, "xMarksTheSpot", "X_MARKS_THE_SPOT");
-  ASSERT_CASE(upper_snake, "realId", "REAL_ID");
-  ASSERT_CASE(upper_snake, "realID", "REAL_ID");
-  ASSERT_CASE(upper_snake, "real3d", "REAL3D");
-  ASSERT_CASE(upper_snake, "real3D", "REAL3_D");
-  ASSERT_CASE(upper_snake, "real_3d", "REAL_3D");
-  ASSERT_CASE(upper_snake, "real_3D", "REAL_3_D");
-  ASSERT_CASE(upper_snake, "helloEWorld", "HELLO_E_WORLD");
-  ASSERT_CASE(upper_snake, "helloEworld", "HELLO_EWORLD");
-  ASSERT_CASE(upper_snake, "URLLoader", "URL_LOADER");
-  ASSERT_CASE(upper_snake, "is_21Jump_street", "IS_21_JUMP_STREET");
-  ASSERT_CASE(upper_snake, "URLloader", "UR_LLOADER");
-  ASSERT_CASE(upper_snake, "UrlLoader", "URL_LOADER");
-  ASSERT_CASE(upper_snake, "URLLoader", "URL_LOADER");
-  ASSERT_CASE(upper_snake, "url_loader", "URL_LOADER");
-  ASSERT_CASE(upper_snake, "urlLoader", "URL_LOADER");
-  ASSERT_CASE(upper_snake, "kUrlLoader", "URL_LOADER");
-  ASSERT_CASE(upper_snake, "kURLLoader", "URL_LOADER");
+  ASSERT_CASE(UpperSnake, "x", "X");
+  ASSERT_CASE(UpperSnake, "xy", "XY");
+  ASSERT_CASE(UpperSnake, "xY", "X_Y");
+  ASSERT_CASE(UpperSnake, "xyz123", "XYZ123");
+  ASSERT_CASE(UpperSnake, "xyz_123", "XYZ_123");
+  ASSERT_CASE(UpperSnake, "xyZ123", "XY_Z123");
+  ASSERT_CASE(UpperSnake, "daysInAWeek", "DAYS_IN_A_WEEK");
+  ASSERT_CASE(UpperSnake, "android8_0_0", "ANDROID8_0_0");
+  ASSERT_CASE(UpperSnake, "android_8_0_0", "ANDROID_8_0_0");
+  ASSERT_CASE(UpperSnake, "xMarksTheSpot", "X_MARKS_THE_SPOT");
+  ASSERT_CASE(UpperSnake, "realId", "REAL_ID");
+  ASSERT_CASE(UpperSnake, "realID", "REAL_ID");
+  ASSERT_CASE(UpperSnake, "real3d", "REAL3D");
+  ASSERT_CASE(UpperSnake, "real3D", "REAL3_D");
+  ASSERT_CASE(UpperSnake, "real_3d", "REAL_3D");
+  ASSERT_CASE(UpperSnake, "real_3D", "REAL_3_D");
+  ASSERT_CASE(UpperSnake, "helloEWorld", "HELLO_E_WORLD");
+  ASSERT_CASE(UpperSnake, "helloEworld", "HELLO_EWORLD");
+  ASSERT_CASE(UpperSnake, "URLLoader", "URL_LOADER");
+  ASSERT_CASE(UpperSnake, "is_21Jump_street", "IS_21_JUMP_STREET");
+  ASSERT_CASE(UpperSnake, "URLloader", "UR_LLOADER");
+  ASSERT_CASE(UpperSnake, "UrlLoader", "URL_LOADER");
+  ASSERT_CASE(UpperSnake, "URLLoader", "URL_LOADER");
+  ASSERT_CASE(UpperSnake, "url_loader", "URL_LOADER");
+  ASSERT_CASE(UpperSnake, "urlLoader", "URL_LOADER");
+  ASSERT_CASE(UpperSnake, "kUrlLoader", "URL_LOADER");
+  ASSERT_CASE(UpperSnake, "kURLLoader", "URL_LOADER");
 }
 
 TEST(UtilsTests, LowerSnakeCase) {
-  ASSERT_CASE(lower_snake, "X", "x");
-  ASSERT_CASE(lower_snake, "Xy", "xy");
-  ASSERT_CASE(lower_snake, "XY", "xy");
-  ASSERT_CASE(lower_snake, "Xyz123", "xyz123");
-  ASSERT_CASE(lower_snake, "Xyz_123", "xyz_123");
-  ASSERT_CASE(lower_snake, "XyZ123", "xy_z123");
-  ASSERT_CASE(lower_snake, "DaysInAWeek", "days_in_a_week");
-  ASSERT_CASE(lower_snake, "Android8_0_0", "android8_0_0");
-  ASSERT_CASE(lower_snake, "Android_8_0_0", "android_8_0_0");
-  ASSERT_CASE(lower_snake, "XMarksTheSpot", "x_marks_the_spot");
-  ASSERT_CASE(lower_snake, "RealId", "real_id");
-  ASSERT_CASE(lower_snake, "RealID", "real_id");
-  ASSERT_CASE(lower_snake, "Real3d", "real3d");
-  ASSERT_CASE(lower_snake, "Real3D", "real3_d");
-  ASSERT_CASE(lower_snake, "Real_3d", "real_3d");
-  ASSERT_CASE(lower_snake, "Real_3D", "real_3_d");
-  ASSERT_CASE(lower_snake, "HelloEWorld", "hello_e_world");
-  ASSERT_CASE(lower_snake, "HelloEworld", "hello_eworld");
-  ASSERT_CASE(lower_snake, "URLLoader", "url_loader");
-  ASSERT_CASE(lower_snake, "is_21Jump_street", "is_21_jump_street");
-  ASSERT_CASE(lower_snake, "URLloader", "ur_lloader");
-  ASSERT_CASE(lower_snake, "UrlLoader", "url_loader");
-  ASSERT_CASE(lower_snake, "URLLoader", "url_loader");
-  ASSERT_CASE(lower_snake, "URL_LOADER", "url_loader");
-  ASSERT_CASE(lower_snake, "urlLoader", "url_loader");
-  ASSERT_CASE(lower_snake, "kUrlLoader", "url_loader");
-  ASSERT_CASE(lower_snake, "kURLLoader", "url_loader");
-}
-
-TEST(UtilsTests, KonstantCase) {
-  ASSERT_CASE(konstant, "URLLoader", "kUrlLoader");
-  ASSERT_CASE(konstant, "is_21Jump_street", "kIs21JumpStreet");
-  ASSERT_CASE(konstant, "URLloader", "kUrLloader");
-  ASSERT_CASE(konstant, "UrlLoader", "kUrlLoader");
-  ASSERT_CASE(konstant, "URLLoader", "kUrlLoader");
-  ASSERT_CASE(konstant, "url_loader", "kUrlLoader");
-  ASSERT_CASE(konstant, "URL_LOADER", "kUrlLoader");
-  ASSERT_CASE(konstant, "urlLoader", "kUrlLoader");
-  ASSERT_CASE(konstant, "kURLLoader", "kUrlLoader");
-}
-
-TEST(UtilsTests, LowerNoSeparatorCase) {
-  ASSERT_CASE(lower_no_separator, "URLLoader", "urlloader");
-  ASSERT_CASE(lower_no_separator, "is_21Jump_street", "is21jumpstreet");
-  ASSERT_CASE(lower_no_separator, "URLloader", "urlloader");
-  ASSERT_CASE(lower_no_separator, "UrlLoader", "urlloader");
-  ASSERT_CASE(lower_no_separator, "URLLoader", "urlloader");
-  ASSERT_CASE(lower_no_separator, "url_loader", "urlloader");
-  ASSERT_CASE(lower_no_separator, "URL_LOADER", "urlloader");
-  ASSERT_CASE(lower_no_separator, "urlLoader", "urlloader");
-  ASSERT_CASE(lower_no_separator, "kUrlLoader", "urlloader");
-  ASSERT_CASE(lower_no_separator, "kURLLoader", "urlloader");
-}
-
-TEST(UtilsTests, WhitespaceAndComments) {
-  ASSERT_TRUE(IsWhitespace(' '));
-  ASSERT_TRUE(IsWhitespace('\t'));
-  ASSERT_TRUE(IsWhitespace('\v'));
-  ASSERT_TRUE(IsWhitespace('\f'));
-  ASSERT_TRUE(IsWhitespace('\r'));
-  ASSERT_TRUE(IsWhitespace('\n'));
-  ASSERT_FALSE(IsWhitespace('\0'));
-  ASSERT_FALSE(IsWhitespace('_'));
-  ASSERT_FALSE(IsWhitespace('-'));
-  ASSERT_FALSE(IsWhitespace('A'));
-  ASSERT_FALSE(IsWhitespace('Z'));
-  ASSERT_FALSE(IsWhitespace('a'));
-  ASSERT_FALSE(IsWhitespace('z'));
-  ASSERT_FALSE(IsWhitespace('0'));
-  ASSERT_FALSE(IsWhitespace('9'));
-  ASSERT_FALSE(IsWhitespace('!'));
-
-  ASSERT_TRUE(IsWhitespaceNoNewline(' '));
-  ASSERT_TRUE(IsWhitespaceNoNewline('\t'));
-  ASSERT_TRUE(IsWhitespaceNoNewline('\v'));
-  ASSERT_TRUE(IsWhitespaceNoNewline('\f'));
-  ASSERT_TRUE(IsWhitespaceNoNewline('\r'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('\n'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('\0'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('_'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('-'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('A'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('Z'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('a'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('z'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('0'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('9'));
-  ASSERT_FALSE(IsWhitespaceNoNewline('!'));
-
-  ASSERT_TRUE(IsBlank(""));
-  ASSERT_TRUE(IsBlank(" "));
-  ASSERT_TRUE(IsBlank("\t"));
-  ASSERT_TRUE(IsBlank("\n"));
-  ASSERT_TRUE(IsBlank("\n\n\n"));
-  ASSERT_TRUE(IsBlank("  \n  \n  \n"));
-  ASSERT_TRUE(IsBlank(" \t\v\f\r\n"));
-  ASSERT_TRUE(IsBlank("     "));
-  ASSERT_TRUE(IsBlank(" \t \t "));
-  ASSERT_TRUE(IsBlank("\t \t \t"));
-  ASSERT_FALSE(IsBlank("multi\nline"));
-  ASSERT_FALSE(IsBlank("\nmore\nmulti\nline\n"));
-  ASSERT_FALSE(IsBlank("\t\t."));
-  ASSERT_FALSE(IsBlank("    ."));
-  ASSERT_FALSE(IsBlank(".    "));
-  ASSERT_FALSE(IsBlank("// Comment "));
-  ASSERT_FALSE(IsBlank("/// Doc Comment "));
-
-  ASSERT_TRUE(LineFromOffsetIsBlank("four", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four    ", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four    \n", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four  \t \t  ", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four    \n", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four    \t\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four    \n\t", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four    \nmore lines", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four    \nmore lines\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsBlank("four    \t\n\t", 4));
-  ASSERT_FALSE(LineFromOffsetIsBlank("four.", 4));
-  ASSERT_FALSE(LineFromOffsetIsBlank("four.\n", 4));
-  ASSERT_FALSE(LineFromOffsetIsBlank("fournot blank    \n", 4));
-  ASSERT_FALSE(LineFromOffsetIsBlank("four    more chars", 4));
-  ASSERT_FALSE(LineFromOffsetIsBlank("four    more chars\n", 4));
-
-  ASSERT_TRUE(FirstLineIsBlank(""));
-  ASSERT_TRUE(FirstLineIsBlank(""));
-  ASSERT_TRUE(FirstLineIsBlank("\n"));
-  ASSERT_TRUE(FirstLineIsBlank("    "));
-  ASSERT_TRUE(FirstLineIsBlank("    \n"));
-  ASSERT_TRUE(FirstLineIsBlank("  \t \t  "));
-  ASSERT_TRUE(FirstLineIsBlank("    \n"));
-  ASSERT_TRUE(FirstLineIsBlank("    \t\n"));
-  ASSERT_TRUE(FirstLineIsBlank("    \nmore lines"));
-  ASSERT_TRUE(FirstLineIsBlank("    \nmore lines\n"));
-  ASSERT_TRUE(FirstLineIsBlank("    \n\t"));
-  ASSERT_TRUE(FirstLineIsBlank("    \t\n\t"));
-  ASSERT_FALSE(FirstLineIsBlank("."));
-  ASSERT_FALSE(FirstLineIsBlank(".\n"));
-  ASSERT_FALSE(FirstLineIsBlank("not blank    \n"));
-  ASSERT_FALSE(FirstLineIsBlank("    more chars"));
-  ASSERT_FALSE(FirstLineIsBlank("    more chars\n"));
-
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//    ", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//    \n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//  \t\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//not blank    ", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//  not blank", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//not blank", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//not blank    \n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//  not blank\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//not blank\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//    \n\t", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//    \t\n\t", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//    \nmore lines", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four//    \nmore lines\n", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four.//", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four    .//\n", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("fourmore//    ", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four    more\n//    \n", 4));
-  //// Greater than 3 slashes are still interpreted as a regular comment
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////    ", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////    \n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////  \t\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////not blank    ", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////  not blank", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////not blank", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////not blank    \n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////  not blank\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four////not blank\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////    ", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////    \n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////  \t\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////not blank    ", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////  not blank", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////not blank", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////not blank    \n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////  not blank\n", 4));
-  ASSERT_TRUE(LineFromOffsetIsRegularComment("four/////not blank\n", 4));
-  /// FIDL Doc Comments start with 3 slashes, like this one
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///\n", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///    ", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///    \n", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///  \t\n", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///not blank    ", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///  not blank", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///not blank", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///not blank    \n", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///  not blank\n", 4));
-  ASSERT_FALSE(LineFromOffsetIsRegularComment("four///not blank\n", 4));
-
-  ASSERT_TRUE(FirstLineIsRegularComment("//"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//    "));
-  ASSERT_TRUE(FirstLineIsRegularComment("//    \n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//  \t\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//not blank    "));
-  ASSERT_TRUE(FirstLineIsRegularComment("//  not blank"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//not blank"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//not blank    \n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//  not blank\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//not blank\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//    \n\t"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//    \t\n\t"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//    \nmore lines"));
-  ASSERT_TRUE(FirstLineIsRegularComment("//    \nmore lines\n"));
-  ASSERT_FALSE(FirstLineIsRegularComment(".//"));
-  ASSERT_FALSE(FirstLineIsRegularComment("    .//\n"));
-  ASSERT_FALSE(FirstLineIsRegularComment("more//    "));
-  ASSERT_FALSE(FirstLineIsRegularComment("    more\n//    \n"));
-  //// Greater than 3 slashes are still interpreted as a regular comment
-  ASSERT_TRUE(FirstLineIsRegularComment("////"));
-  ASSERT_TRUE(FirstLineIsRegularComment("////\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("////    "));
-  ASSERT_TRUE(FirstLineIsRegularComment("////    \n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("////  \t\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("////not blank    "));
-  ASSERT_TRUE(FirstLineIsRegularComment("////  not blank"));
-  ASSERT_TRUE(FirstLineIsRegularComment("////not blank"));
-  ASSERT_TRUE(FirstLineIsRegularComment("////not blank    \n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("////  not blank\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("////not blank\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////    "));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////    \n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////  \t\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////not blank    "));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////  not blank"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////not blank"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////not blank    \n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////  not blank\n"));
-  ASSERT_TRUE(FirstLineIsRegularComment("/////not blank\n"));
-  /// FIDL Doc Comments start with 3 slashes, like this one
-  ASSERT_FALSE(FirstLineIsRegularComment("///"));
-  ASSERT_FALSE(FirstLineIsRegularComment("///\n"));
-  ASSERT_FALSE(FirstLineIsRegularComment("///    "));
-  ASSERT_FALSE(FirstLineIsRegularComment("///    \n"));
-  ASSERT_FALSE(FirstLineIsRegularComment("///  \t\n"));
-  ASSERT_FALSE(FirstLineIsRegularComment("///not blank    "));
-  ASSERT_FALSE(FirstLineIsRegularComment("///  not blank"));
-  ASSERT_FALSE(FirstLineIsRegularComment("///not blank"));
-  ASSERT_FALSE(FirstLineIsRegularComment("///not blank    \n"));
-  ASSERT_FALSE(FirstLineIsRegularComment("///  not blank\n"));
-  ASSERT_FALSE(FirstLineIsRegularComment("///not blank\n"));
+  ASSERT_CASE(LowerSnake, "X", "x");
+  ASSERT_CASE(LowerSnake, "Xy", "xy");
+  ASSERT_CASE(LowerSnake, "XY", "xy");
+  ASSERT_CASE(LowerSnake, "Xyz123", "xyz123");
+  ASSERT_CASE(LowerSnake, "Xyz_123", "xyz_123");
+  ASSERT_CASE(LowerSnake, "XyZ123", "xy_z123");
+  ASSERT_CASE(LowerSnake, "DaysInAWeek", "days_in_a_week");
+  ASSERT_CASE(LowerSnake, "Android8_0_0", "android8_0_0");
+  ASSERT_CASE(LowerSnake, "Android_8_0_0", "android_8_0_0");
+  ASSERT_CASE(LowerSnake, "XMarksTheSpot", "x_marks_the_spot");
+  ASSERT_CASE(LowerSnake, "RealId", "real_id");
+  ASSERT_CASE(LowerSnake, "RealID", "real_id");
+  ASSERT_CASE(LowerSnake, "Real3d", "real3d");
+  ASSERT_CASE(LowerSnake, "Real3D", "real3_d");
+  ASSERT_CASE(LowerSnake, "Real_3d", "real_3d");
+  ASSERT_CASE(LowerSnake, "Real_3D", "real_3_d");
+  ASSERT_CASE(LowerSnake, "HelloEWorld", "hello_e_world");
+  ASSERT_CASE(LowerSnake, "HelloEworld", "hello_eworld");
+  ASSERT_CASE(LowerSnake, "URLLoader", "url_loader");
+  ASSERT_CASE(LowerSnake, "is_21Jump_street", "is_21_jump_street");
+  ASSERT_CASE(LowerSnake, "URLloader", "ur_lloader");
+  ASSERT_CASE(LowerSnake, "UrlLoader", "url_loader");
+  ASSERT_CASE(LowerSnake, "URLLoader", "url_loader");
+  ASSERT_CASE(LowerSnake, "URL_LOADER", "url_loader");
+  ASSERT_CASE(LowerSnake, "urlLoader", "url_loader");
+  ASSERT_CASE(LowerSnake, "kUrlLoader", "url_loader");
+  ASSERT_CASE(LowerSnake, "kURLLoader", "url_loader");
 }
 
 TEST(UtilsTests, IsValidLibraryComponent) {
@@ -461,7 +237,7 @@
   ASSERT_FALSE(IsValidFullyQualifiedMethodIdentifier("long.liB/Protocol.Method"));
 }
 
-TEST(UtilsTests, IsOnlyWhitespace) {
+TEST(UtilsTests, RemoveWhitespace) {
   // ---------------40---------------- |
   std::string unformatted = R"FIDL(
 /// C1a
@@ -592,108 +368,107 @@
 }; // C35
 )FIDL";
 
-  ASSERT_TRUE(OnlyWhitespaceChanged(unformatted, formatted));
+  ASSERT_EQ(RemoveWhitespace(unformatted), RemoveWhitespace(formatted));
 }
 
-TEST(UtilsTests, CanonicalForm) {
-  EXPECT_EQ(canonicalize(""), "");
+TEST(UtilsTests, Canonicalize) {
+  EXPECT_EQ(Canonicalize(""), "");
 
   // Basic letter combinations.
-  EXPECT_EQ(canonicalize("a"), "a");
-  EXPECT_EQ(canonicalize("A"), "a");
-  EXPECT_EQ(canonicalize("ab"), "ab");
-  EXPECT_EQ(canonicalize("AB"), "ab");
-  EXPECT_EQ(canonicalize("Ab"), "ab");
-  EXPECT_EQ(canonicalize("aB"), "a_b");
-  EXPECT_EQ(canonicalize("a_b"), "a_b");
-  EXPECT_EQ(canonicalize("A_B"), "a_b");
-  EXPECT_EQ(canonicalize("A_b"), "a_b");
-  EXPECT_EQ(canonicalize("a_B"), "a_b");
+  EXPECT_EQ(Canonicalize("a"), "a");
+  EXPECT_EQ(Canonicalize("A"), "a");
+  EXPECT_EQ(Canonicalize("ab"), "ab");
+  EXPECT_EQ(Canonicalize("AB"), "ab");
+  EXPECT_EQ(Canonicalize("Ab"), "ab");
+  EXPECT_EQ(Canonicalize("aB"), "a_b");
+  EXPECT_EQ(Canonicalize("a_b"), "a_b");
+  EXPECT_EQ(Canonicalize("A_B"), "a_b");
+  EXPECT_EQ(Canonicalize("A_b"), "a_b");
+  EXPECT_EQ(Canonicalize("a_B"), "a_b");
 
   // Digits are treated like lowercase letters.
-  EXPECT_EQ(canonicalize("1"), "1");
-  EXPECT_EQ(canonicalize("a1"), "a1");
-  EXPECT_EQ(canonicalize("A1"), "a1");
+  EXPECT_EQ(Canonicalize("1"), "1");
+  EXPECT_EQ(Canonicalize("a1"), "a1");
+  EXPECT_EQ(Canonicalize("A1"), "a1");
 
   // Leading digits are illegal in FIDL identifiers, so these do not matter.
-  EXPECT_EQ(canonicalize("1a"), "1a");
-  EXPECT_EQ(canonicalize("1A"), "1_a");
-  EXPECT_EQ(canonicalize("12"), "12");
+  EXPECT_EQ(Canonicalize("1a"), "1a");
+  EXPECT_EQ(Canonicalize("1A"), "1_a");
+  EXPECT_EQ(Canonicalize("12"), "12");
 
   // Lower/upper snake/camel case conventions.
-  EXPECT_EQ(canonicalize("lowerCamelCase"), "lower_camel_case");
-  EXPECT_EQ(canonicalize("UpperCamelCase"), "upper_camel_case");
-  EXPECT_EQ(canonicalize("lower_snake_case"), "lower_snake_case");
-  EXPECT_EQ(canonicalize("UPPER_SNAKE_CASE"), "upper_snake_case");
-  EXPECT_EQ(canonicalize("Camel_With_Underscores"), "camel_with_underscores");
-  EXPECT_EQ(canonicalize("camelWithAOneLetterWord"), "camel_with_a_one_letter_word");
-  EXPECT_EQ(canonicalize("1_2__3___underscores"), "1_2_3_underscores");
+  EXPECT_EQ(Canonicalize("lowerCamelCase"), "lower_camel_case");
+  EXPECT_EQ(Canonicalize("UpperCamelCase"), "upper_camel_case");
+  EXPECT_EQ(Canonicalize("lower_snake_case"), "lower_snake_case");
+  EXPECT_EQ(Canonicalize("UpperSnake_CASE"), "upper_snake_case");
+  EXPECT_EQ(Canonicalize("Camel_With_Underscores"), "camel_with_underscores");
+  EXPECT_EQ(Canonicalize("camelWithAOneLetterWord"), "camel_with_a_one_letter_word");
+  EXPECT_EQ(Canonicalize("1_2__3___underscores"), "1_2_3_underscores");
 
   // Acronym casing.
-  EXPECT_EQ(canonicalize("HTTPServer"), "http_server");
-  EXPECT_EQ(canonicalize("HttpServer"), "http_server");
-  EXPECT_EQ(canonicalize("URLIsATLA"), "url_is_atla");
-  EXPECT_EQ(canonicalize("UrlIsATla"), "url_is_a_tla");
+  EXPECT_EQ(Canonicalize("HTTPServer"), "http_server");
+  EXPECT_EQ(Canonicalize("HttpServer"), "http_server");
+  EXPECT_EQ(Canonicalize("URLIsATLA"), "url_is_atla");
+  EXPECT_EQ(Canonicalize("UrlIsATla"), "url_is_a_tla");
 
   // Words with digits: H264 encoder.
-  EXPECT_EQ(canonicalize("h264encoder"), "h264encoder");
-  EXPECT_EQ(canonicalize("H264ENCODER"), "h264_encoder");
-  EXPECT_EQ(canonicalize("h264_encoder"), "h264_encoder");
-  EXPECT_EQ(canonicalize("H264_ENCODER"), "h264_encoder");
-  EXPECT_EQ(canonicalize("h264Encoder"), "h264_encoder");
-  EXPECT_EQ(canonicalize("H264Encoder"), "h264_encoder");
+  EXPECT_EQ(Canonicalize("h264encoder"), "h264encoder");
+  EXPECT_EQ(Canonicalize("H264ENCODER"), "h264_encoder");
+  EXPECT_EQ(Canonicalize("h264_encoder"), "h264_encoder");
+  EXPECT_EQ(Canonicalize("H264_ENCODER"), "h264_encoder");
+  EXPECT_EQ(Canonicalize("h264Encoder"), "h264_encoder");
+  EXPECT_EQ(Canonicalize("H264Encoder"), "h264_encoder");
 
   // Words with digits: DDR4 memory.
-  EXPECT_EQ(canonicalize("ddr4memory"), "ddr4memory");
-  EXPECT_EQ(canonicalize("DDR4MEMORY"), "ddr4_memory");
-  EXPECT_EQ(canonicalize("ddr4_memory"), "ddr4_memory");
-  EXPECT_EQ(canonicalize("DDR4_MEMORY"), "ddr4_memory");
-  EXPECT_EQ(canonicalize("ddr4Memory"), "ddr4_memory");
-  EXPECT_EQ(canonicalize("Ddr4Memory"), "ddr4_memory");
-  EXPECT_EQ(canonicalize("DDR4Memory"), "ddr4_memory");
+  EXPECT_EQ(Canonicalize("ddr4memory"), "ddr4memory");
+  EXPECT_EQ(Canonicalize("DDR4MEMORY"), "ddr4_memory");
+  EXPECT_EQ(Canonicalize("ddr4_memory"), "ddr4_memory");
+  EXPECT_EQ(Canonicalize("DDR4_MEMORY"), "ddr4_memory");
+  EXPECT_EQ(Canonicalize("ddr4Memory"), "ddr4_memory");
+  EXPECT_EQ(Canonicalize("Ddr4Memory"), "ddr4_memory");
+  EXPECT_EQ(Canonicalize("DDR4Memory"), "ddr4_memory");
 
   // Words with digits: A2DP profile.
-  EXPECT_EQ(canonicalize("a2dpprofile"), "a2dpprofile");
-  EXPECT_EQ(canonicalize("A2DPPROFILE"), "a2_dpprofile");
-  EXPECT_EQ(canonicalize("a2dp_profile"), "a2dp_profile");
-  EXPECT_EQ(canonicalize("A2DP_PROFILE"), "a2_dp_profile");
-  EXPECT_EQ(canonicalize("a2dpProfile"), "a2dp_profile");
-  EXPECT_EQ(canonicalize("A2dpProfile"), "a2dp_profile");
-  EXPECT_EQ(canonicalize("A2DPProfile"), "a2_dp_profile");
+  EXPECT_EQ(Canonicalize("a2dpprofile"), "a2dpprofile");
+  EXPECT_EQ(Canonicalize("A2DPPROFILE"), "a2_dpprofile");
+  EXPECT_EQ(Canonicalize("a2dp_profile"), "a2dp_profile");
+  EXPECT_EQ(Canonicalize("A2DP_PROFILE"), "a2_dp_profile");
+  EXPECT_EQ(Canonicalize("a2dpProfile"), "a2dp_profile");
+  EXPECT_EQ(Canonicalize("A2dpProfile"), "a2dp_profile");
+  EXPECT_EQ(Canonicalize("A2DPProfile"), "a2_dp_profile");
 
   // Words with digits: R2D2 is one word.
-  EXPECT_EQ(canonicalize("r2d2isoneword"), "r2d2isoneword");
-  EXPECT_EQ(canonicalize("R2D2ISONEWORD"), "r2_d2_isoneword");
-  EXPECT_EQ(canonicalize("r2d2_is_one_word"), "r2d2_is_one_word");
-  EXPECT_EQ(canonicalize("R2D2_IS_ONE_WORD"), "r2_d2_is_one_word");
-  EXPECT_EQ(canonicalize("r2d2IsOneWord"), "r2d2_is_one_word");
-  EXPECT_EQ(canonicalize("R2d2IsOneWord"), "r2d2_is_one_word");
-  EXPECT_EQ(canonicalize("R2D2IsOneWord"), "r2_d2_is_one_word");
+  EXPECT_EQ(Canonicalize("r2d2isoneword"), "r2d2isoneword");
+  EXPECT_EQ(Canonicalize("R2D2ISONEWORD"), "r2_d2_isoneword");
+  EXPECT_EQ(Canonicalize("r2d2_is_one_word"), "r2d2_is_one_word");
+  EXPECT_EQ(Canonicalize("R2D2_IS_ONE_WORD"), "r2_d2_is_one_word");
+  EXPECT_EQ(Canonicalize("r2d2IsOneWord"), "r2d2_is_one_word");
+  EXPECT_EQ(Canonicalize("R2d2IsOneWord"), "r2d2_is_one_word");
+  EXPECT_EQ(Canonicalize("R2D2IsOneWord"), "r2_d2_is_one_word");
 
   // Leading and trailing underscores are illegal in FIDL identifiers, so these
   // do not matter.
-  EXPECT_EQ(canonicalize("_"), "");
-  EXPECT_EQ(canonicalize("_a"), "a");
-  EXPECT_EQ(canonicalize("a_"), "a_");
-  EXPECT_EQ(canonicalize("_a_"), "a_");
-  EXPECT_EQ(canonicalize("__a__"), "a_");
+  EXPECT_EQ(Canonicalize("_"), "");
+  EXPECT_EQ(Canonicalize("_a"), "a");
+  EXPECT_EQ(Canonicalize("a_"), "a_");
+  EXPECT_EQ(Canonicalize("_a_"), "a_");
+  EXPECT_EQ(Canonicalize("__a__"), "a_");
 }
 
-TEST(UtilsTests, StringStripping) {
-  EXPECT_EQ(strip_konstant_k("kFoobar"), "Foobar");
-  EXPECT_EQ(strip_konstant_k("KFoobar"), "KFoobar");
+TEST(UtilsTests, StripStringLiteralQuotes) {
+  EXPECT_EQ(StripStringLiteralQuotes("\"\""), "");
+  EXPECT_EQ(StripStringLiteralQuotes("\"foobar\""), "foobar");
+}
 
-  EXPECT_EQ(strip_string_literal_quotes("\"\""), "");
-  EXPECT_EQ(strip_string_literal_quotes("\"foobar\""), "foobar");
-
-  EXPECT_EQ(strip_doc_comment_slashes(R"FIDL(
+TEST(UtilsTests, StripDocCommentSlashes) {
+  EXPECT_EQ(StripDocCommentSlashes(R"FIDL(
   /// A
   /// multiline
   /// comment!
 )FIDL"),
             "\n A\n multiline\n comment!\n");
 
-  EXPECT_EQ(strip_doc_comment_slashes(R"FIDL(
+  EXPECT_EQ(StripDocCommentSlashes(R"FIDL(
   ///
   /// With
   ///
@@ -704,7 +479,7 @@
 )FIDL"),
             "\n\n With\n\n empty\n\n lines\n\n");
 
-  EXPECT_EQ(strip_doc_comment_slashes(R"FIDL(
+  EXPECT_EQ(StripDocCommentSlashes(R"FIDL(
   /// With
 
   /// blank
@@ -714,7 +489,7 @@
 )FIDL"),
             "\n With\n\n blank\n\n\n lines\n");
 
-  EXPECT_EQ(strip_doc_comment_slashes(R"FIDL(
+  EXPECT_EQ(StripDocCommentSlashes(R"FIDL(
 	/// With
 		/// tabs
 	 /// in
@@ -724,7 +499,7 @@
 )FIDL"),
             "\n With\n tabs\n in\n addition\n to\n spaces\n");
 
-  EXPECT_EQ(strip_doc_comment_slashes(R"FIDL(
+  EXPECT_EQ(StripDocCommentSlashes(R"FIDL(
   /// Weird
 /// Offsets
   /// Slash///
@@ -735,26 +510,26 @@
 }
 
 TEST(UtilsTests, DecodeUnicodeHex) {
-  EXPECT_EQ(decode_unicode_hex("0"), 0x0u);
-  EXPECT_EQ(decode_unicode_hex("a"), 0xau);
-  EXPECT_EQ(decode_unicode_hex("12"), 0x12u);
-  EXPECT_EQ(decode_unicode_hex("123abc"), 0x123abcu);
-  EXPECT_EQ(decode_unicode_hex("ffffff"), 0xffffffu);
+  EXPECT_EQ(DecodeUnicodeHex("0"), 0x0u);
+  EXPECT_EQ(DecodeUnicodeHex("a"), 0xau);
+  EXPECT_EQ(DecodeUnicodeHex("12"), 0x12u);
+  EXPECT_EQ(DecodeUnicodeHex("123abc"), 0x123abcu);
+  EXPECT_EQ(DecodeUnicodeHex("ffffff"), 0xffffffu);
 }
 
 TEST(UtilsTests, StringLiteralLength) {
-  EXPECT_EQ(string_literal_length(R"("Hello")"), 5u);
-  EXPECT_EQ(string_literal_length(R"("\\")"), 1u);
-  EXPECT_EQ(string_literal_length(R"("\to")"), 2u);
-  EXPECT_EQ(string_literal_length(R"("\n")"), 1u);
-  EXPECT_EQ(string_literal_length(R"("\u{01F600}")"), 4u);
-  EXPECT_EQ(string_literal_length(R"("\u{2713}")"), 3u);
-  EXPECT_EQ(string_literal_length(R"("")"), 0u);
-  EXPECT_EQ(string_literal_length(R"("$")"), 1u);
-  EXPECT_EQ(string_literal_length(R"("¢")"), 2u);
-  EXPECT_EQ(string_literal_length(R"("€")"), 3u);
-  EXPECT_EQ(string_literal_length(R"("𐍈")"), 4u);
-  EXPECT_EQ(string_literal_length(R"("😁")"), 4u);
+  EXPECT_EQ(StringLiteralLength(R"("Hello")"), 5u);
+  EXPECT_EQ(StringLiteralLength(R"("\\")"), 1u);
+  EXPECT_EQ(StringLiteralLength(R"("\to")"), 2u);
+  EXPECT_EQ(StringLiteralLength(R"("\n")"), 1u);
+  EXPECT_EQ(StringLiteralLength(R"("\u{01F600}")"), 4u);
+  EXPECT_EQ(StringLiteralLength(R"("\u{2713}")"), 3u);
+  EXPECT_EQ(StringLiteralLength(R"("")"), 0u);
+  EXPECT_EQ(StringLiteralLength(R"("$")"), 1u);
+  EXPECT_EQ(StringLiteralLength(R"("¢")"), 2u);
+  EXPECT_EQ(StringLiteralLength(R"("€")"), 3u);
+  EXPECT_EQ(StringLiteralLength(R"("𐍈")"), 4u);
+  EXPECT_EQ(StringLiteralLength(R"("😁")"), 4u);
 }
 
 }  // namespace
diff --git a/tools/fidl/fidlc/tests/versioning_attribute_tests.cc b/tools/fidl/fidlc/tests/versioning_attribute_tests.cc
new file mode 100644
index 0000000..19b858e
--- /dev/null
+++ b/tools/fidl/fidlc/tests/versioning_attribute_tests.cc
@@ -0,0 +1,530 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "tools/fidl/fidlc/tests/test_library.h"
+
+// This file tests basic validation of the @available attribute. It does not
+// test the behavior of versioning beyond that.
+
+namespace fidlc {
+namespace {
+
+TEST(VersioningAttributeTests, BadMultipleLibraryDeclarationsAgree) {
+  TestLibrary library;
+  library.AddSource("first.fidl", R"FIDL(
+@available(added=1)
+library example;
+)FIDL");
+  library.AddSource("second.fidl", R"FIDL(
+@available(added=1)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrDuplicateAttribute, "available", "first.fidl:2:2");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadMultipleLibraryDeclarationsDisagree) {
+  TestLibrary library;
+  library.AddSource("first.fidl", R"FIDL(
+@available(added=1)
+library example;
+)FIDL");
+  library.AddSource("second.fidl", R"FIDL(
+@available(added=2)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrDuplicateAttribute, "available", "first.fidl:2:2");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadMultipleLibraryDeclarationsHead) {
+  TestLibrary library;
+  library.AddSource("first.fidl", R"FIDL(
+@available(added=HEAD)
+library example;
+)FIDL");
+  library.AddSource("second.fidl", R"FIDL(
+@available(added=HEAD)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  // TODO(https://fxbug.dev/42062904): Check for duplicate attributes earlier in
+  // compilation so that this is ErrDuplicateAttribute instead.
+  library.ExpectFail(ErrReferenceInLibraryAttribute);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, GoodAllArgumentsOnLibrary) {
+  TestLibrary library(R"FIDL(
+@available(platform="notexample", added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
+library example;
+)FIDL");
+  library.SelectVersion("notexample", "1");
+  ASSERT_COMPILED(library);
+}
+
+TEST(VersioningAttributeTests, GoodAllArgumentsOnDecl) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "1");
+  ASSERT_COMPILED(library);
+}
+
+TEST(VersioningAttributeTests, GoodAllArgumentsOnMember) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
+    member string;
+};
+)FIDL");
+  library.SelectVersion("example", "1");
+  ASSERT_COMPILED(library);
+}
+
+TEST(VersioningAttributeTests, GoodAttributeOnEverything) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1)
+const CONST uint32 = 1;
+
+@available(added=1)
+alias Alias = string;
+
+// TODO(https://fxbug.dev/42158155): Uncomment.
+// @available(added=1)
+// type Type = string;
+
+@available(added=1)
+type Bits = bits {
+    @available(added=1)
+    MEMBER = 1;
+};
+
+@available(added=1)
+type Enum = enum {
+    @available(added=1)
+    MEMBER = 1;
+};
+
+@available(added=1)
+type Struct = struct {
+    @available(added=1)
+    member string;
+};
+
+@available(added=1)
+type Table = table {
+    @available(added=1)
+    1: member string;
+};
+
+@available(added=1)
+type Union = union {
+    @available(added=1)
+    1: member string;
+};
+
+@available(added=1)
+protocol ProtocolToCompose {};
+
+@available(added=1)
+protocol Protocol {
+    @available(added=1)
+    compose ProtocolToCompose;
+
+    @available(added=1)
+    Method() -> ();
+};
+
+@available(added=1)
+service Service {
+    @available(added=1)
+    member client_end:Protocol;
+};
+
+@available(added=1)
+resource_definition Resource : uint32 {
+    properties {
+        @available(added=1)
+        subtype flexible enum : uint32 {};
+    };
+};
+)FIDL");
+  library.SelectVersion("example", "1");
+  ASSERT_COMPILED(library);
+
+  auto& unfiltered_decls = library.all_libraries()->Lookup("example")->declaration_order;
+  auto& filtered_decls = library.declaration_order();
+  // Because everything has the same availability, nothing gets split.
+  EXPECT_EQ(unfiltered_decls.size(), filtered_decls.size());
+}
+
+// TODO(https://fxbug.dev/42146818): Currently attributes `@HERE type Foo = struct {};` and
+// `type Foo = @HERE struct {};` are interchangeable. We just disallow using
+// both at once (ErrRedundantAttributePlacement). However, @available on the
+// anonymous layout is confusing so maybe we should rethink this design.
+TEST(VersioningAttributeTests, GoodAnonymousLayoutTopLevel) {
+  auto source = R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = @available(added=2) struct {};
+)FIDL";
+
+  {
+    TestLibrary library(source);
+    library.SelectVersion("example", "1");
+    ASSERT_COMPILED(library);
+    ASSERT_FALSE(library.HasStruct("Foo"));
+  }
+  {
+    TestLibrary library(source);
+    library.SelectVersion("example", "2");
+    ASSERT_COMPILED(library);
+    ASSERT_TRUE(library.HasStruct("Foo"));
+  }
+}
+
+TEST(VersioningAttributeTests, BadAnonymousLayoutInMember) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    member @available(added=2) struct {};
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidAttributePlacement, "available");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadInvalidVersionBelowMin) {
+  TestLibrary library(R"FIDL(
+@available(added=0)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidVersion, 0);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, GoodVersionMaxNumeric) {
+  TestLibrary library(R"FIDL(
+@available(added=9223372036854775807) // 2^63-1
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  ASSERT_COMPILED(library);
+}
+
+TEST(VersioningAttributeTests, BadInvalidVersionAboveMaxNumeric) {
+  TestLibrary library(R"FIDL(
+@available(added=9223372036854775808) // 2^63
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidVersion, 9223372036854775808u);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadInvalidVersionBeforeHeadOrdinal) {
+  TestLibrary library(R"FIDL(
+@available(added=18446744073709551613) // 2^64-3
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidVersion, 18446744073709551613u);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, GoodVersionHeadOrdinal) {
+  TestLibrary library(R"FIDL(
+@available(added=18446744073709551614) // 2^64-2
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  ASSERT_COMPILED(library);
+}
+
+TEST(VersioningAttributeTests, BadInvalidVersionLegacyOrdinal) {
+  TestLibrary library(R"FIDL(
+@available(added=18446744073709551615) // 2^64-1
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidVersion, 18446744073709551615u);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadInvalidVersionAfterLegacyOrdinal) {
+  TestLibrary library(R"FIDL(
+@available(added=18446744073709551616) // 2^64
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrCouldNotResolveAttributeArg);
+  library.ExpectFail(ErrConstantOverflowsType, "18446744073709551616", "uint64");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadInvalidVersionLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=LEGACY)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAttributeArgRequiresLiteral, "added", "available");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadInvalidVersionNegative) {
+  TestLibrary library(R"FIDL(
+@available(added=-1)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrCouldNotResolveAttributeArg);
+  library.ExpectFail(ErrConstantOverflowsType, "-1", "uint64");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadNoArguments) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0147.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrAvailableMissingArguments);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadLibraryMissingAddedOnlyRemoved) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0150-a.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrLibraryAvailabilityMissingAdded);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadLibraryMissingAddedOnlyPlatform) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0150-b.test.fidl");
+  library.SelectVersion("foo", "HEAD");
+  library.ExpectFail(ErrLibraryAvailabilityMissingAdded);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadLibraryReplaced) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0204.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrLibraryReplaced);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadNoteWithoutDeprecation) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0148.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrNoteWithoutDeprecation);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadRemovedAndReplaced) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0203.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrRemovedAndReplaced);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadPlatformNotOnLibrary) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(platform="bad")
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrPlatformNotOnLibrary);
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadUseInUnversionedLibrary) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0151.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrMissingLibraryAvailability, "test.bad.fi0151");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadUseInUnversionedLibraryReportedOncePerAttribute) {
+  TestLibrary library(R"FIDL(
+library example;
+
+@available(added=1)
+type Foo = struct {
+    @available(added=2)
+    member1 bool;
+    member2 bool;
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  // Note: Only twice, not a third time for member2.
+  library.ExpectFail(ErrMissingLibraryAvailability, "example");
+  library.ExpectFail(ErrMissingLibraryAvailability, "example");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadAddedEqualsRemoved) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0154-a.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added < removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadAddedEqualsReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, replaced=2)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added < replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadAddedGreaterThanRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=2, removed=1)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added < removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadAddedGreaterThanReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=3, replaced=2)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added < replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, GoodAddedEqualsDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=1, deprecated=1)
+library example;
+)FIDL");
+  library.SelectVersion("example", "1");
+  ASSERT_COMPILED(library);
+}
+
+TEST(VersioningAttributeTests, BadAddedGreaterThanDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=1)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadDeprecatedEqualsRemoved) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0154-b.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadDeprecatedEqualsReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1, deprecated=2, replaced=2)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadDeprecatedGreaterThanRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1, deprecated=3, removed=2)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadDeprecatedGreaterThanReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1, deprecated=3, replaced=2)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadLegacyTrueNotRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1, legacy=true)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadLegacyFalseNotRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1, legacy=false)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningAttributeTests, BadLegacyTrueNotRemovedMethod) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0182.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+}  // namespace
+}  // namespace fidlc
diff --git a/tools/fidl/fidlc/tests/versioning_basic_tests.cc b/tools/fidl/fidlc/tests/versioning_basic_tests.cc
new file mode 100644
index 0000000..5f88f4c
--- /dev/null
+++ b/tools/fidl/fidlc/tests/versioning_basic_tests.cc
@@ -0,0 +1,395 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "tools/fidl/fidlc/src/versioning_types.h"
+#include "tools/fidl/fidlc/tests/test_library.h"
+
+// This file tests basic FIDL versioning behavior, such as elements being
+// included in the output only between their `added` and `removed` versions.
+// Tests are run for all the versions given in INSTANTIATE_TEST_SUITE_P.
+
+namespace fidlc {
+namespace {
+
+class VersioningBasicTest : public testing::TestWithParam<Version> {};
+
+const Version V1 = Version::From(1).value();
+const Version V2 = Version::From(2).value();
+const Version HEAD = Version::Head();
+const Version LEGACY = Version::Legacy();
+
+INSTANTIATE_TEST_SUITE_P(VersioningBasicTests, VersioningBasicTest,
+                         testing::Values(V1, V2, HEAD, LEGACY),
+                         [](auto info) { return info.param.ToString(); });
+
+TEST_P(VersioningBasicTest, GoodLibraryDefault) {
+  TestLibrary library(R"FIDL(
+library example;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+}
+
+TEST_P(VersioningBasicTest, GoodLibraryAddedAtHead) {
+  TestLibrary library(R"FIDL(
+@available(added=HEAD)
+library example;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+}
+
+TEST_P(VersioningBasicTest, GoodLibraryAddedAtOne) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+}
+
+TEST_P(VersioningBasicTest, GoodLibraryAddedAndRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1, removed=2)
+library example;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+}
+
+TEST_P(VersioningBasicTest, GoodLibraryAddedAndDeprecatedAndRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1, deprecated=2, removed=HEAD)
+library example;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+}
+
+TEST_P(VersioningBasicTest, GoodLibraryAddedAndRemovedLegacyFalse) {
+  TestLibrary library(R"FIDL(
+@available(added=1, removed=2, legacy=false)
+library example;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+}
+
+TEST_P(VersioningBasicTest, GoodLibraryAddedAndRemovedLegacyTrue) {
+  TestLibrary library(R"FIDL(
+@available(added=1, removed=2, legacy=true)
+library example;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+}
+
+TEST_P(VersioningBasicTest, GoodDeclAddedAtHead) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=HEAD)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() >= HEAD);
+}
+
+TEST_P(VersioningBasicTest, GoodDeclAddedAtOne) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_TRUE(library.HasStruct("Foo"));
+}
+
+TEST_P(VersioningBasicTest, GoodDeclAddedAndRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1, removed=2)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() >= V1 && GetParam() < V2);
+}
+
+TEST_P(VersioningBasicTest, GoodDeclAddedAndReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1, replaced=2)
+type Foo = struct {};
+
+@available(added=2)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() > V1);
+}
+
+TEST_P(VersioningBasicTest, GoodDeclAddedAndDeprecatedAndRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1, deprecated=2, removed=HEAD)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  ASSERT_EQ(library.HasStruct("Foo"), GetParam() < HEAD);
+  if (GetParam() < HEAD) {
+    EXPECT_EQ(library.LookupStruct("Foo")->availability.is_deprecated(), GetParam() >= V2);
+  }
+}
+
+TEST_P(VersioningBasicTest, GoodDeclAddedAndRemovedLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1, removed=2, legacy=true)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1 || GetParam() == LEGACY);
+}
+
+TEST_P(VersioningBasicTest, GoodMemberAddedAtHead) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(added=HEAD)
+    member string;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.LookupStruct("Foo")->members.size(), GetParam() >= HEAD ? 1u : 0u);
+}
+
+TEST_P(VersioningBasicTest, GoodMemberAddedAtOne) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(added=1)
+    member string;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
+}
+
+TEST_P(VersioningBasicTest, GoodMemberAddedAndRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(added=1, removed=2)
+    member string;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.LookupStruct("Foo")->members.size(), GetParam() == V1 ? 1u : 0u);
+}
+
+TEST_P(VersioningBasicTest, GoodMemberAddedAndReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(added=1, replaced=2)
+    member string;
+    @available(added=2)
+    member uint32;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
+  EXPECT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
+            GetParam() == V1 ? Type::Kind::kString : Type::Kind::kPrimitive);
+}
+
+TEST_P(VersioningBasicTest, GoodMemberAddedAndDeprecatedAndRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(added=1, deprecated=2, removed=HEAD)
+    member string;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  ASSERT_EQ(library.LookupStruct("Foo")->members.size(), GetParam() < HEAD ? 1u : 0u);
+  if (GetParam() < HEAD) {
+    EXPECT_EQ(library.LookupStruct("Foo")->members.front().availability.is_deprecated(),
+              GetParam() >= V2);
+  }
+}
+
+TEST_P(VersioningBasicTest, GoodMemberAddedAndRemovedLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(added=1, removed=2, legacy=true)
+    member string;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.LookupStruct("Foo")->members.size(), GetParam() == V1 || GetParam() == LEGACY);
+}
+
+// TODO(https://fxbug.dev/42052719): Generalize this with more comprehensive tests in
+// versioning_interleaving_tests.cc.
+TEST_P(VersioningBasicTest, GoodRegularDeprecatedReferencesVersionedDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@deprecated
+const FOO uint32 = BAR;
+@available(deprecated=1)
+const BAR uint32 = 1;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+}
+
+// Previously this errored due to incorrect logic in deprecation checks.
+TEST_P(VersioningBasicTest, GoodDeprecationLogicRegression1) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(deprecated=1, removed=3)
+type Foo = struct {};
+
+@available(deprecated=1, removed=3)
+type Bar = struct {
+    foo Foo;
+    @available(added=2)
+    ensure_split_at_v2 string;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  ASSERT_EQ(library.HasStruct("Bar"), GetParam() <= V2);
+  if (GetParam() <= V2) {
+    EXPECT_EQ(library.LookupStruct("Bar")->members.size(), GetParam() == V1 ? 1u : 2u);
+  }
+}
+
+// Previously this crashed due to incorrect logic in deprecation checks.
+TEST_P(VersioningBasicTest, GoodDeprecationLogicRegression2) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(deprecated=1)
+type Foo = struct {};
+
+@available(deprecated=1, removed=3)
+type Bar = struct {
+    foo Foo;
+    @available(added=2)
+    ensure_split_at_v2 string;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  ASSERT_EQ(library.HasStruct("Bar"), GetParam() <= V2);
+  if (GetParam() <= V2) {
+    EXPECT_EQ(library.LookupStruct("Bar")->members.size(), GetParam() == V1 ? 1u : 2u);
+  }
+}
+
+TEST_P(VersioningBasicTest, GoodMultipleFiles) {
+  TestLibrary library;
+  library.AddSource("overview.fidl", R"FIDL(
+/// Some doc comment.
+@available(added=1)
+library example;
+)FIDL");
+  library.AddSource("first.fidl", R"FIDL(
+library example;
+
+@available(added=2)
+type Foo = struct {
+    bar box<Bar>;
+};
+)FIDL");
+  library.AddSource("second.fidl", R"FIDL(
+library example;
+
+@available(added=2)
+type Bar = struct {
+    foo box<Foo>;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  ASSERT_EQ(library.HasStruct("Foo"), GetParam() >= V2);
+  ASSERT_EQ(library.HasStruct("Bar"), GetParam() >= V2);
+}
+
+TEST_P(VersioningBasicTest, GoodMultipleLibraries) {
+  SharedAmongstLibraries shared;
+  shared.SelectVersion("platform", GetParam());
+  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
+@available(added=1)
+library platform.dependency;
+
+type Foo = struct {
+    @available(added=2)
+    member string;
+};
+)FIDL");
+  ASSERT_COMPILED(dependency);
+  TestLibrary example(&shared, "example.fidl", R"FIDL(
+@available(added=1)
+library platform.example;
+
+using platform.dependency;
+
+type ShouldBeSplit = struct {
+    foo platform.dependency.Foo;
+};
+)FIDL");
+  ASSERT_COMPILED(example);
+  ASSERT_EQ(example.LookupStruct("ShouldBeSplit")->type_shape->inline_size,
+            GetParam() == V1 ? 1u : 16u);
+}
+
+}  // namespace
+}  // namespace fidlc
diff --git a/tools/fidl/fidlc/tests/decomposition_tests.cc b/tools/fidl/fidlc/tests/versioning_decomposition_tests.cc
similarity index 96%
rename from tools/fidl/fidlc/tests/decomposition_tests.cc
rename to tools/fidl/fidlc/tests/versioning_decomposition_tests.cc
index 6935322..6c7edad 100644
--- a/tools/fidl/fidlc/tests/decomposition_tests.cc
+++ b/tools/fidl/fidlc/tests/versioning_decomposition_tests.cc
@@ -10,7 +10,6 @@
 
 // This file tests the temporal decomposition algorithm by comparing the JSON IR
 // resulting from a versioned library and its manually decomposed equivalents.
-// See also versioning_tests.cc and availability_interleaving_tests.cc.
 
 namespace fidlc {
 namespace {
@@ -74,20 +73,19 @@
 }
 
 // Platform name and library name for all test libraries in this file.
-const std::string kPlatformName = "example";
-const std::vector<std::string_view> kLibraryName = {kPlatformName};
+const char* kLibraryName = "example";
 
 // Helper function to implement ASSERT_EQUIVALENT.
 void AssertEquivalent(const std::string& left_fidl, const std::string& right_fidl,
                       std::string_view version) {
   TestLibrary left_lib(left_fidl);
-  left_lib.SelectVersion(kPlatformName, version);
+  left_lib.SelectVersion(kLibraryName, version);
   ASSERT_COMPILED(left_lib);
-  ASSERT_EQ(left_lib.compilation()->library_name, kLibraryName);
+  ASSERT_EQ(left_lib.name(), kLibraryName);
   TestLibrary right_lib(right_fidl);
-  right_lib.SelectVersion(kPlatformName, version);
+  right_lib.SelectVersion(kLibraryName, version);
   ASSERT_COMPILED(right_lib);
-  ASSERT_EQ(right_lib.compilation()->library_name, kLibraryName);
+  ASSERT_EQ(right_lib.name(), kLibraryName);
   auto left_json = ScrubJson(left_lib.GenerateJSON());
   auto right_json = ScrubJson(right_lib.GenerateJSON());
   if (left_json != right_json) {
@@ -111,7 +109,7 @@
     AssertEquivalent(left_fidl, right_fidl, version);              \
   }
 
-TEST(DecompositionTests, EquivalentToSelf) {
+TEST(VersioningDecompositionTests, EquivalentToSelf) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -124,7 +122,7 @@
 }
 
 // An unversioned library behaves the same as an unchanging versioned library.
-TEST(DecompositionTests, UnversionedLibrary) {
+TEST(VersioningDecompositionTests, UnversionedLibrary) {
   auto unversioned = R"FIDL(
 library example;
 
@@ -144,7 +142,7 @@
   ASSERT_EQUIVALENT(unversioned, versioned, "LEGACY");
 }
 
-TEST(DecompositionTests, AbsentLibraryIsEmpty) {
+TEST(VersioningDecompositionTests, AbsentLibraryIsEmpty) {
   auto fidl = R"FIDL(
 @available(added=2, removed=3)
 library example;
@@ -176,7 +174,7 @@
   ASSERT_EQUIVALENT(fidl, v3_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, SplitByMembership) {
+TEST(VersioningDecompositionTests, SplitByMembership) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -209,7 +207,7 @@
   ASSERT_EQUIVALENT(fidl, v2_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, SplitByReference) {
+TEST(VersioningDecompositionTests, SplitByReference) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -254,7 +252,7 @@
   ASSERT_EQUIVALENT(fidl, v2_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, SplitByTwoMembers) {
+TEST(VersioningDecompositionTests, SplitByTwoMembers) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -308,7 +306,7 @@
   ASSERT_EQUIVALENT(fidl, v3_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, Recursion) {
+TEST(VersioningDecompositionTests, Recursion) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -419,7 +417,7 @@
   ASSERT_EQUIVALENT(fidl, v4_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, MutualRecursion) {
+TEST(VersioningDecompositionTests, MutualRecursion) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -510,7 +508,7 @@
   ASSERT_EQUIVALENT(fidl, v5_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, MisalignedSwapping) {
+TEST(VersioningDecompositionTests, MisalignedSwapping) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -574,7 +572,7 @@
   ASSERT_EQUIVALENT(fidl, v4_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, StrictToFlexible) {
+TEST(VersioningDecompositionTests, StrictToFlexible) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -637,7 +635,7 @@
   ASSERT_EQUIVALENT(fidl, v4_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, NameReuse) {
+TEST(VersioningDecompositionTests, NameReuse) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -714,7 +712,7 @@
   ASSERT_EQUIVALENT(fidl, v7_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, ConstsAndConstraints) {
+TEST(VersioningDecompositionTests, ConstsAndConstraints) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -797,7 +795,7 @@
   ASSERT_EQUIVALENT(fidl, v5_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, AllElementsSplitByMembership) {
+TEST(VersioningDecompositionTests, AllElementsSplitByMembership) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -1031,7 +1029,7 @@
   ASSERT_EQUIVALENT(fidl, v5_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, AllElementsSplitByReference) {
+TEST(VersioningDecompositionTests, AllElementsSplitByReference) {
   auto fidl_prefix = R"FIDL(
 @available(added=1)
 library example;
@@ -1221,7 +1219,7 @@
   ASSERT_EQUIVALENT(fidl, v2_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, Complicated) {
+TEST(VersioningDecompositionTests, Complicated) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -1489,7 +1487,7 @@
   ASSERT_EQUIVALENT(fidl, v7_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, Legacy) {
+TEST(VersioningDecompositionTests, Legacy) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -1664,7 +1662,7 @@
   ASSERT_EQUIVALENT(fidl, legacy, "LEGACY");
 }
 
-TEST(DecompositionTests, ConvertNamedToAnonymous) {
+TEST(VersioningDecompositionTests, ConvertNamedToAnonymous) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
@@ -1709,7 +1707,7 @@
   ASSERT_EQUIVALENT(fidl, v2_onward, "LEGACY");
 }
 
-TEST(DecompositionTests, ConvertAnonymousToNamed) {
+TEST(VersioningDecompositionTests, ConvertAnonymousToNamed) {
   auto fidl = R"FIDL(
 @available(added=1)
 library example;
diff --git a/tools/fidl/fidlc/tests/versioning_inheritance_tests.cc b/tools/fidl/fidlc/tests/versioning_inheritance_tests.cc
new file mode 100644
index 0000000..f08406d4
--- /dev/null
+++ b/tools/fidl/fidlc/tests/versioning_inheritance_tests.cc
@@ -0,0 +1,919 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "tools/fidl/fidlc/tests/test_library.h"
+
+// This file tests the inheritance of the @available attribute and ways the
+// attribute can conflict with inherited values.
+
+namespace fidlc {
+namespace {
+
+TEST(VersioningInheritanceTests, GoodRedundantWithParent) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(added=2, deprecated=4, removed=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "2");
+  ASSERT_COMPILED(library);
+}
+
+TEST(VersioningInheritanceTests, BadAddedBeforeParentAdded) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0155-a.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
+                     "bad/fi-0155-a.test.fidl:4:12", "added", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, GoodAddedWhenParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(added=4)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "4");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_TRUE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, GoodAddedAfterParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(added=5)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "5");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_TRUE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, BadAddedWhenParentRemoved) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0155-b.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "4", "removed", "4",
+                     "bad/fi-0155-b.test.fidl:4:35", "added", "after", "removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadAddedWhenParentReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, replaced=6)
+type Foo = struct {
+    @available(added=6)
+    member bool;
+};
+
+@available(added=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "6", "replaced", "6",
+                     "example.fidl:5:35", "added", "after", "replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadAddedAfterParentRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(added=7)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "7", "removed", "6",
+                     "example.fidl:2:35", "added", "after", "removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadAddedAfterParentReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, replaced=6)
+type Foo = struct {
+    @available(added=7)
+    member bool;
+};
+
+@available(added=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "7", "replaced", "6",
+                     "example.fidl:5:35", "added", "after", "replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadDeprecatedBeforeParentAdded) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(deprecated=1)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "1", "added", "2",
+                     "example.fidl:2:12", "deprecated", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, GoodDeprecatedWhenParentAdded) {
+  TestLibrary library(R"FIDL(
+@available(added=2, removed=6) // never deprecated
+library example;
+
+@available(deprecated=2)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "2");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_TRUE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, GoodDeprecatedBeforeParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(deprecated=3)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "3");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_TRUE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, BadDeprecatedAfterParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(deprecated=5)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "5", "deprecated", "4",
+                     "example.fidl:2:21", "deprecated", "after", "deprecated");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadDeprecatedWhenParentRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(deprecated=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "6", "removed", "6",
+                     "example.fidl:2:35", "deprecated", "after", "removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadDeprecatedWhenParentReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, replaced=6)
+type Foo = struct {
+    @available(deprecated=6)
+    member bool;
+};
+
+@available(added=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "6", "replaced", "6",
+                     "example.fidl:5:35", "deprecated", "after", "replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadDeprecatedAfterParentRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(deprecated=7)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "7", "removed", "6",
+                     "example.fidl:2:35", "deprecated", "after", "removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadDeprecatedAfterParentReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, replaced=6)
+type Foo = struct {
+    @available(deprecated=7)
+    member bool;
+};
+
+@available(added=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "7", "replaced", "6",
+                     "example.fidl:5:35", "deprecated", "after", "replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadRemovedBeforeParentAdded) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(removed=1)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "1", "added", "2",
+                     "example.fidl:2:12", "removed", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadReplacedBeforeParentAdded) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, removed=6)
+type Foo = struct {
+    @available(replaced=1)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "1", "added", "2",
+                     "example.fidl:5:12", "replaced", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadRemovedWhenParentAdded) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(removed=2)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "2", "added", "2",
+                     "example.fidl:2:12", "removed", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadReplacedWhenParentAdded) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, removed=6)
+type Foo = struct {
+    @available(replaced=2)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "2", "added", "2",
+                     "example.fidl:5:12", "replaced", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, GoodRemovedBeforeParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(removed=3)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "2");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_FALSE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, GoodReplacedBeforeParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, removed=6)
+type Foo = struct {
+    @available(replaced=3)
+    member bool;
+    @available(added=3)
+    member uint32;
+};
+)FIDL");
+  library.SelectVersion("example", "2");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_FALSE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, GoodRemovedWhenParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(removed=4)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "3");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_FALSE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, GoodReplacedWhenParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, removed=6)
+type Foo = struct {
+    @available(replaced=4)
+    member bool;
+    @available(added=4)
+    member uint32;
+};
+)FIDL");
+  library.SelectVersion("example", "3");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_FALSE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, GoodRemovedAfterParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(removed=5)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "4");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_TRUE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, GoodReplacedAfterParentDeprecated) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, removed=6)
+type Foo = struct {
+    @available(replaced=5)
+    member bool;
+    @available(added=5)
+    member uint32;
+};
+)FIDL");
+  library.SelectVersion("example", "4");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_TRUE(foo->availability.is_deprecated());
+}
+
+TEST(VersioningInheritanceTests, BadRemovedAfterParentRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6)
+library example;
+
+@available(removed=7)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "7", "removed", "6",
+                     "example.fidl:2:35", "removed", "after", "removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadRemovedAfterParentReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, replaced=6)
+type Foo = struct {
+    @available(removed=7)
+    member bool;
+};
+
+@available(added=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "7", "replaced", "6",
+                     "example.fidl:5:35", "removed", "after", "replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadReplacedAfterParentRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, removed=6)
+type Foo = struct {
+    @available(replaced=7)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "7", "removed", "6",
+                     "example.fidl:5:35", "replaced", "after", "removed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadReplacedAfterParentReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, replaced=6)
+type Foo = struct {
+    @available(replaced=7)
+    member bool;
+};
+
+@available(added=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "7", "replaced", "6",
+                     "example.fidl:5:35", "replaced", "after", "replaced");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, GoodRemovedWhenParentReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, replaced=6)
+type Foo = struct {
+    @available(added=2, deprecated=4, removed=6)
+    member bool;
+};
+
+@available(added=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "6");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_TRUE(foo->members.empty());
+}
+
+TEST(VersioningInheritanceTests, BadReplacedWhenParentRemoved) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, removed=6)
+type Foo = struct {
+    @available(added=2, deprecated=4, replaced=6)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrReplacedWithoutReplacement, "member", Version::From(6).value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadReplacedWhenParentReplaced) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=4, replaced=6)
+type Foo = struct {
+    @available(added=2, deprecated=4, replaced=6)
+    member bool;
+};
+
+@available(added=6)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrReplacedWithoutReplacement, "member", Version::From(6).value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, GoodLegacyParentNotRemovedChildFalse) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4)
+library example;
+
+@available(removed=6, legacy=false)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "LEGACY");
+  ASSERT_COMPILED(library);
+  ASSERT_FALSE(library.HasStruct("Foo"));
+}
+
+TEST(VersioningInheritanceTests, GoodLegacyParentNotRemovedChildTrue) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4)
+library example;
+
+@available(removed=6, legacy=true)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "LEGACY");
+  ASSERT_COMPILED(library);
+  ASSERT_TRUE(library.HasStruct("Foo"));
+}
+
+TEST(VersioningInheritanceTests, GoodLegacyParentFalseChildFalse) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6, legacy=false)
+library example;
+
+@available(legacy=false)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "LEGACY");
+  ASSERT_COMPILED(library);
+  ASSERT_FALSE(library.HasStruct("Foo"));
+}
+
+TEST(VersioningInheritanceTests, BadLegacyParentFalseChildTrue) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6, legacy=false)
+library example;
+
+@available(legacy=true)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "6",
+                     "example.fidl:2:35");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, BadLegacyParentFalseChildTrueMethod) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0183.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "3",
+                     "bad/fi-0183.test.fidl:7:12");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningInheritanceTests, GoodLegacyParentTrueChildTrue) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6, legacy=true)
+library example;
+
+@available(legacy=true)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "LEGACY");
+  ASSERT_COMPILED(library);
+  ASSERT_TRUE(library.HasStruct("Foo"));
+}
+
+TEST(VersioningInheritanceTests, GoodLegacyParentTrueChildFalse) {
+  TestLibrary library(R"FIDL(
+@available(added=2, deprecated=4, removed=6, legacy=true)
+library example;
+
+@available(legacy=false)
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "LEGACY");
+  ASSERT_COMPILED(library);
+  ASSERT_FALSE(library.HasStruct("Foo"));
+}
+
+TEST(VersioningInheritanceTests, GoodMemberInheritsFromParent) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2)
+type Foo = struct {
+    @available(deprecated=3)
+    member1 bool;
+};
+)FIDL");
+  library.SelectVersion("example", "2");
+  ASSERT_COMPILED(library);
+
+  auto foo = library.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  EXPECT_EQ(foo->members.size(), 1u);
+}
+
+TEST(VersioningInheritanceTests, GoodComplexInheritance) {
+  // The following libraries all define a struct Bar with effective availability
+  // @available(added=2, deprecated=3, removed=4, legacy=true) in different ways.
+
+  std::vector<const char*> sources;
+
+  // Direct annotation.
+  sources.push_back(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=3, removed=4, legacy=true)
+type Bar = struct {};
+)FIDL");
+
+  // Fully inherit from library declaration.
+  sources.push_back(R"FIDL(
+@available(added=2, deprecated=3, removed=4, legacy=true)
+library example;
+
+type Bar = struct {};
+)FIDL");
+
+  // Partially inherit from library declaration.
+  sources.push_back(R"FIDL(
+@available(added=1, deprecated=3)
+library example;
+
+@available(added=2, removed=4, legacy=true)
+type Bar = struct {};
+)FIDL");
+
+  // Inherit from parent.
+  sources.push_back(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2, deprecated=3, removed=4, legacy=true)
+type Foo = struct {
+    member @generated_name("Bar") struct {};
+};
+)FIDL");
+
+  // Inherit from member.
+  sources.push_back(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(added=2, deprecated=3, removed=4, legacy=true)
+    member @generated_name("Bar") struct {};
+};
+)FIDL");
+
+  // Inherit from multiple, forward.
+  sources.push_back(R"FIDL(
+@available(added=2)
+library example;
+
+@available(deprecated=3)
+type Foo = struct {
+    @available(removed=4, legacy=true)
+    member @generated_name("Bar") struct {};
+};
+)FIDL");
+
+  // Inherit from multiple, backward.
+  sources.push_back(R"FIDL(
+@available(added=1, removed=4, legacy=true)
+library example;
+
+@available(deprecated=3)
+type Foo = struct {
+    @available(added=2)
+    member @generated_name("Bar") struct {};
+};
+)FIDL");
+
+  // Inherit from multiple, mixed.
+  sources.push_back(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2)
+type Foo = struct {
+    @available(deprecated=3, removed=4, legacy=true)
+    member @generated_name("Bar") struct {};
+};
+)FIDL");
+
+  // Inherit via nested layouts.
+  sources.push_back(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2)
+type Foo = struct {
+    @available(deprecated=3)
+    member1 struct {
+        @available(removed=4, legacy=true)
+        member2 struct {
+            member3 @generated_name("Bar") struct {};
+        };
+    };
+};
+)FIDL");
+
+  // Inherit via nested type constructors.
+  sources.push_back(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=2)
+type Foo = struct {
+    @available(deprecated=3, removed=4, legacy=true)
+    member1 vector<vector<vector<@generated_name("Bar") struct{}>>>;
+};
+)FIDL");
+
+  for (auto& source : sources) {
+    {
+      TestLibrary library(source);
+      library.SelectVersion("example", "1");
+      ASSERT_COMPILED(library);
+
+      auto bar = library.LookupStruct("Bar");
+      ASSERT_EQ(bar, nullptr);
+    }
+    {
+      TestLibrary library(source);
+      library.SelectVersion("example", "2");
+      ASSERT_COMPILED(library);
+
+      auto bar = library.LookupStruct("Bar");
+      ASSERT_NE(bar, nullptr);
+      EXPECT_FALSE(bar->availability.is_deprecated());
+    }
+    {
+      TestLibrary library(source);
+      library.SelectVersion("example", "3");
+      ASSERT_COMPILED(library);
+
+      auto bar = library.LookupStruct("Bar");
+      ASSERT_NE(bar, nullptr);
+      EXPECT_TRUE(bar->availability.is_deprecated());
+    }
+    {
+      TestLibrary library(source);
+      library.SelectVersion("example", "4");
+      ASSERT_COMPILED(library);
+
+      auto bar = library.LookupStruct("Bar");
+      ASSERT_EQ(bar, nullptr);
+    }
+    {
+      TestLibrary library(source);
+      library.SelectVersion("example", "LEGACY");
+      ASSERT_COMPILED(library);
+
+      auto bar = library.LookupStruct("Bar");
+      ASSERT_NE(bar, nullptr);
+    }
+  }
+}
+
+TEST(VersioningInheritanceTests, BadDeclConflictsWithParent) {
+  TestLibrary library(R"FIDL( // L1
+@available(added=2)           // L2
+library example;              // L3
+                              // L4
+@available(added=1)           // L5
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
+                     "example.fidl:2:12", "added", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+  EXPECT_EQ(library.errors()[0]->span.position().line, 5);
+}
+
+TEST(VersioningInheritanceTests, BadMemberConflictsWithParent) {
+  TestLibrary library(R"FIDL( // L1
+@available(added=1)           // L2
+library example;              // L3
+                              // L4
+@available(added=2)           // L5
+type Foo = struct {           // L6
+    @available(added=1)       // L7
+    member1 bool;
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
+                     "example.fidl:5:12", "added", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+  EXPECT_EQ(library.errors()[0]->span.position().line, 7);
+}
+
+TEST(VersioningInheritanceTests, BadMemberConflictsWithGrandParent) {
+  TestLibrary library(R"FIDL( // L1
+@available(added=2)           // L2
+library example;              // L3
+                              // L4
+@available(removed=3)         // L5
+type Foo = struct {           // L6
+    @available(added=1)       // L7
+    member1 bool;
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
+                     "example.fidl:2:12", "added", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+  EXPECT_EQ(library.errors()[0]->span.position().line, 7);
+}
+
+TEST(VersioningInheritanceTests, BadMemberConflictsWithGrandParentThroughAnonymous) {
+  TestLibrary library(R"FIDL( // L1
+@available(added=1)           // L2
+library example;              // L3
+                              // L4
+@available(added=2)           // L5
+type Foo = struct {           // L6
+    member1 struct {          // L7
+        @available(removed=1) // L8
+        member2 bool;
+    };
+};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "1", "added", "2",
+                     "example.fidl:5:12", "removed", "before", "added");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+  EXPECT_EQ(library.errors()[0]->span.position().line, 8);
+}
+
+TEST(VersioningInheritanceTests, BadLegacyConflictsWithRemoved) {
+  TestLibrary library(R"FIDL(  // L1
+@available(added=1, removed=2) // L2
+library example;               // L3
+                               // L4
+@available(legacy=true)        // L5
+type Foo = struct {};
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "2",
+                     "example.fidl:2:21");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+  EXPECT_EQ(library.errors()[0]->span.position().line, 5);
+}
+
+}  // namespace
+}  // namespace fidlc
diff --git a/tools/fidl/fidlc/tests/availability_interleaving_tests.cc b/tools/fidl/fidlc/tests/versioning_interleaving_tests.cc
similarity index 97%
rename from tools/fidl/fidlc/tests/availability_interleaving_tests.cc
rename to tools/fidl/fidlc/tests/versioning_interleaving_tests.cc
index 4182579..415ad00 100644
--- a/tools/fidl/fidlc/tests/availability_interleaving_tests.cc
+++ b/tools/fidl/fidlc/tests/versioning_interleaving_tests.cc
@@ -9,8 +9,7 @@
 #include "tools/fidl/fidlc/tests/test_library.h"
 
 // This file tests ways of interleaving the availability of a source element
-// with that of a target element that it references. See also
-// versioning_tests.cc and decomposition_tests.cc.
+// with that of a target element that it references.
 
 namespace fidlc {
 namespace {
@@ -395,7 +394,7 @@
   str.replace(str.find(placeholder), placeholder.size(), replacement);
 }
 
-TEST(AvailabilityInterleavingTests, SameLibrary) {
+TEST(VersioningInterleavingTests, SameLibrary) {
   for (auto& test_case : kTestCases) {
     auto attributes = test_case.Format();
     std::string fidl = R"FIDL(
@@ -436,7 +435,7 @@
   test_case.CompileAndAssert(example);
 }
 
-TEST(AvailabilityInterleavingTests, DeclToDeclExternal) {
+TEST(VersioningInterleavingTests, DeclToDeclExternal) {
   std::string example_fidl = R"FIDL(
 @available(added=1)
 library platform.example;
@@ -458,7 +457,7 @@
   }
 }
 
-TEST(AvailabilityInterleavingTests, LibraryToLibraryExternal) {
+TEST(VersioningInterleavingTests, LibraryToLibraryExternal) {
   std::string example_fidl = R"FIDL(
 ${source_available}
 library platform.example;
@@ -478,7 +477,7 @@
   }
 }
 
-TEST(AvailabilityInterleavingTests, LibraryToDeclExternal) {
+TEST(VersioningInterleavingTests, LibraryToDeclExternal) {
   std::string example_fidl = R"FIDL(
 ${source_available}
 library platform.example;
@@ -499,7 +498,7 @@
   }
 }
 
-TEST(AvailabilityInterleavingTests, DeclToLibraryExternal) {
+TEST(VersioningInterleavingTests, DeclToLibraryExternal) {
   std::string example_fidl = R"FIDL(
 @available(added=1)
 library platform.example;
@@ -520,7 +519,7 @@
   }
 }
 
-TEST(AvailabilityInterleavingTests, Error0055) {
+TEST(VersioningInterleavingTests, Error0055) {
   TestLibrary library;
   library.AddFile("bad/fi-0055.test.fidl");
   library.SelectVersion("test", "HEAD");
@@ -530,7 +529,7 @@
   ASSERT_COMPILER_DIAGNOSTICS(library);
 }
 
-TEST(AvailabilityInterleavingTests, Error0056) {
+TEST(VersioningInterleavingTests, Error0056) {
   SharedAmongstLibraries shared;
   shared.SelectVersion("foo", "HEAD");
   shared.SelectVersion("bar", "HEAD");
diff --git a/tools/fidl/fidlc/tests/versioning_overlap_tests.cc b/tools/fidl/fidlc/tests/versioning_overlap_tests.cc
new file mode 100644
index 0000000..c62a205
--- /dev/null
+++ b/tools/fidl/fidlc/tests/versioning_overlap_tests.cc
@@ -0,0 +1,601 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "tools/fidl/fidlc/tests/test_library.h"
+
+// This file tests ways of overlapping element availabilities.
+// Tests are run for all the versions given in INSTANTIATE_TEST_SUITE_P.
+
+namespace fidlc {
+namespace {
+
+class VersioningOverlapTest : public testing::TestWithParam<Version> {};
+
+const Version V1 = Version::From(1).value();
+const Version V2 = Version::From(2).value();
+const Version V3 = Version::From(3).value();
+
+INSTANTIATE_TEST_SUITE_P(VersioningOverlapTests, VersioningOverlapTest, testing::Values(V1, V2, V3),
+                         [](auto info) { return info.param.ToString(); });
+
+TEST_P(VersioningOverlapTest, GoodNoGap) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(replaced=2)
+type Foo = struct {};
+
+@available(added=2)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
+}
+
+TEST_P(VersioningOverlapTest, GoodWithGap) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=2)
+type Foo = struct {};
+
+@available(added=3)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V3);
+}
+
+TEST_P(VersioningOverlapTest, GoodNoGapCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=2)
+type foo = struct {};
+
+@available(added=2)
+type FOO = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("FOO"), GetParam() >= V2);
+}
+
+TEST_P(VersioningOverlapTest, GoodWithGapCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=2)
+type foo = struct {};
+
+@available(added=3)
+type FOO = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("FOO"), GetParam() >= V3);
+}
+
+TEST_P(VersioningOverlapTest, BadEqual) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {};
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameCollision, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
+                     "example.fidl:5:6");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadEqualLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=2, legacy=true)
+type Foo = struct {};
+@available(removed=2, legacy=true)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameCollision, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
+                     "example.fidl:6:6");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadEqualCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type foo = struct {};
+type FOO = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, "foo",
+                     Element::Kind::kTable, "FOO", "example.fidl:6:6", "foo");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadExample) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0036.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kEnum, "Color", Element::Kind::kEnum,
+                     "bad/fi-0036.test.fidl:7:6",
+                     VersionSet(VersionRange(Version::From(2).value(), Version::PosInf())),
+                     Platform::Parse("test").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadExampleCanonical) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0037.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kProtocol, "Color",
+                     Element::Kind::kConst, "COLOR", "bad/fi-0037.test.fidl:7:7", "color",
+                     VersionSet(VersionRange(Version::From(2).value(), Version::PosInf())),
+                     Platform::Parse("test").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadSubset) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {};
+@available(removed=2)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
+                     "example.fidl:5:6",
+                     VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadSubsetCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type foo = struct {};
+@available(removed=2)
+type FOO = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
+                     "FOO", "example.fidl:7:6", "foo",
+                     VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadIntersect) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=5)
+type Foo = struct {};
+@available(added=3)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
+                     "example.fidl:6:6",
+                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadIntersectCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=5)
+type foo = struct {};
+@available(added=3)
+type FOO = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
+                     "FOO", "example.fidl:8:6", "foo",
+                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadJustLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(replaced=2, legacy=true)
+type Foo = struct {};
+@available(added=2, removed=3, legacy=true)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
+                     "example.fidl:6:6",
+                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadJustLegacyCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=2, legacy=true)
+type foo = struct {};
+@available(added=2, removed=3, legacy=true)
+type FOO = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
+                     "FOO", "example.fidl:8:6", "foo",
+                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadIntersectLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(replaced=2, legacy=true)
+type Foo = struct {};
+@available(added=2)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
+                     "example.fidl:6:6",
+                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadIntersectLegacyCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=2, legacy=true)
+type foo = struct {};
+@available(added=2)
+type FOO = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
+                     "FOO", "example.fidl:8:6", "foo",
+                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMultiple) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {};
+@available(added=3)
+type Foo = table {};
+@available(added=HEAD)
+const Foo uint32 = 0;
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kStruct, "Foo", Element::Kind::kConst,
+                     "example.fidl:9:7",
+                     VersionSet(VersionRange(Version::Head(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
+                     "example.fidl:5:6",
+                     VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadRecursive) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(added=1, removed=5)
+type Foo = struct { member box<Foo>; };
+
+@available(added=3, removed=7)
+type Foo = struct { member box<Foo>; };
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kStruct, "Foo", Element::Kind::kStruct,
+                     "example.fidl:6:6",
+                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberEqual) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    member bool;
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameCollision, Element::Kind::kStructMember, "member",
+                     Element::Kind::kStructMember, "example.fidl:6:5");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberEqualLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(removed=2, legacy=true)
+    member bool;
+    @available(removed=2, legacy=true)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameCollision, Element::Kind::kStructMember, "member",
+                     Element::Kind::kStructMember, "example.fidl:7:5");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberEqualCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    member bool;
+    MEMBER bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStructMember, "MEMBER",
+                     Element::Kind::kStructMember, "member", "example.fidl:6:5", "member");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberSubset) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    member bool;
+    @available(removed=2)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
+                     Element::Kind::kStructMember, "example.fidl:6:5",
+                     VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberSubsetCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    member bool;
+    @available(removed=2)
+    MEMBER bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
+                     Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
+                     VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberIntersect) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(removed=5)
+    member bool;
+    @available(added=3)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
+                     Element::Kind::kStructMember, "example.fidl:7:5",
+                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberIntersectCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(removed=5)
+    member bool;
+    @available(added=3)
+    MEMBER bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
+                     Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
+                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberJustLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(replaced=2, legacy=true)
+    member bool;
+    @available(added=2, removed=3, legacy=true)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
+                     Element::Kind::kStructMember, "example.fidl:7:5",
+                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberJustLegacyCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(removed=2, legacy=true)
+    member bool;
+    @available(added=2, removed=3, legacy=true)
+    MEMBER bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
+                     Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
+                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberIntersectLegacy) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(replaced=2, legacy=true)
+    member bool;
+    @available(added=2)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
+                     Element::Kind::kStructMember, "example.fidl:7:5",
+                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberIntersectLegacyCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    @available(removed=2, legacy=true)
+    member bool;
+    @available(added=2)
+    MEMBER bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
+                     Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
+                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberMultiple) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    member bool;
+    @available(added=3)
+    member bool;
+    @available(added=HEAD)
+    member bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
+                     Element::Kind::kStructMember, "example.fidl:6:5",
+                     VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
+                     Element::Kind::kStructMember, "example.fidl:6:5",
+                     VersionSet(VersionRange(Version::Head(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningOverlapTest, BadMemberMultipleCanonical) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Foo = struct {
+    member bool;
+    @available(added=3)
+    Member bool;
+    @available(added=HEAD)
+    MEMBER bool;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "Member",
+                     Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
+                     VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
+                     Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
+                     VersionSet(VersionRange(Version::Head(), Version::PosInf())),
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+}  // namespace
+}  // namespace fidlc
diff --git a/tools/fidl/fidlc/tests/versioning_platform_tests.cc b/tools/fidl/fidlc/tests/versioning_platform_tests.cc
new file mode 100644
index 0000000..1ec22ae
--- /dev/null
+++ b/tools/fidl/fidlc/tests/versioning_platform_tests.cc
@@ -0,0 +1,245 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "tools/fidl/fidlc/tests/test_library.h"
+
+// This file tests the behavior of platforms in FIDL versioning.
+
+namespace fidlc {
+namespace {
+
+TEST(VersioningPlatformTests, GoodUnversionedOneComponent) {
+  TestLibrary library(R"FIDL(
+library example;
+)FIDL");
+  ASSERT_COMPILED(library);
+  EXPECT_TRUE(library.platform().is_unversioned());
+}
+
+TEST(VersioningPlatformTests, GoodUnversionedTwoComponents) {
+  TestLibrary library(R"FIDL(
+library example.something;
+)FIDL");
+  ASSERT_COMPILED(library);
+  EXPECT_TRUE(library.platform().is_unversioned());
+}
+
+TEST(VersioningPlatformTests, GoodImplicitOneComponent) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.platform(), Platform::Parse("example").value());
+  EXPECT_FALSE(library.platform().is_unversioned());
+}
+
+TEST(VersioningPlatformTests, GoodImplicitTwoComponents) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example.something;
+)FIDL");
+  library.SelectVersion("example", "HEAD");
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.platform(), Platform::Parse("example").value());
+  EXPECT_FALSE(library.platform().is_unversioned());
+}
+
+TEST(VersioningPlatformTests, GoodExplicit) {
+  TestLibrary library(R"FIDL(
+@available(platform="someplatform", added=HEAD)
+library example;
+)FIDL");
+  library.SelectVersion("someplatform", "HEAD");
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.platform(), Platform::Parse("someplatform").value());
+  EXPECT_FALSE(library.platform().is_unversioned());
+}
+
+TEST(VersioningPlatformTests, BadInvalid) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0152.test.fidl");
+  library.SelectVersion("test", "HEAD");
+  library.ExpectFail(ErrInvalidPlatform, "Spaces are not allowed");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningPlatformTests, BadReserved) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0208.test.fidl");
+  library.ExpectFail(ErrReservedPlatform, "unversioned");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningPlatformTests, BadExplicitNoVersionSelected) {
+  TestLibrary library;
+  library.AddFile("bad/fi-0201.test.fidl");
+  library.ExpectFail(ErrPlatformVersionNotSelected, "library 'test.bad.fi0201'",
+                     Platform::Parse("foo").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningPlatformTests, BadImplicitNoVersionSelected) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example.something;
+)FIDL");
+  library.ExpectFail(ErrPlatformVersionNotSelected, "library 'example.something'",
+                     Platform::Parse("example").value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST(VersioningPlatformTests, GoodMultipleBasic) {
+  SharedAmongstLibraries shared;
+  shared.SelectVersion("dependency", "3");
+  shared.SelectVersion("example", "HEAD");
+
+  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
+@available(added=2)
+library dependency;
+
+@available(added=3, deprecated=4, removed=5)
+type Foo = struct {};
+)FIDL");
+  ASSERT_COMPILED(dependency);
+
+  TestLibrary example(&shared, "example.fidl", R"FIDL(
+@available(added=1)
+library example;
+
+using dependency;
+
+type Foo = struct {
+    @available(deprecated=5)
+    dep dependency.Foo;
+};
+)FIDL");
+  ASSERT_COMPILED(example);
+}
+
+TEST(VersioningPlatformTests, GoodMultipleExplicit) {
+  SharedAmongstLibraries shared;
+  shared.SelectVersion("xyz", "3");
+  shared.SelectVersion("example", "HEAD");
+
+  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
+@available(platform="xyz", added=1)
+library dependency;
+
+@available(added=3, removed=4)
+type Foo = struct {};
+)FIDL");
+  ASSERT_COMPILED(dependency);
+
+  TestLibrary example(&shared, "example.fidl", R"FIDL(
+@available(added=1)
+library example;
+
+using dependency;
+
+alias Foo = dependency.Foo;
+)FIDL");
+  ASSERT_COMPILED(example);
+}
+
+TEST(VersioningPlatformTests, GoodMultipleUsesCorrectDecl) {
+  SharedAmongstLibraries shared;
+  shared.SelectVersion("dependency", "4");
+  shared.SelectVersion("example", "1");
+
+  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
+@available(added=2)
+library dependency;
+
+@available(deprecated=3, replaced=4)
+type Foo = resource struct {};
+
+@available(added=4, removed=5)
+type Foo = table {};
+)FIDL");
+  ASSERT_COMPILED(dependency);
+
+  TestLibrary example(&shared, "example.fidl", R"FIDL(
+@available(added=1)
+library example;
+
+using dependency;
+
+type Foo = struct {
+    dep dependency.Foo;
+};
+)FIDL");
+  ASSERT_COMPILED(example);
+
+  auto foo = example.LookupStruct("Foo");
+  ASSERT_NE(foo, nullptr);
+  ASSERT_EQ(foo->members.size(), 1u);
+  auto member_type = foo->members[0].type_ctor->type;
+  ASSERT_EQ(member_type->kind, Type::Kind::kIdentifier);
+  auto identifier_type = static_cast<const IdentifierType*>(member_type);
+  EXPECT_EQ(identifier_type->type_decl->kind, Decl::Kind::kTable);
+}
+
+TEST(VersioningPlatformTests, BadMultipleNameNotFound) {
+  SharedAmongstLibraries shared;
+  shared.SelectVersion("dependency", "HEAD");
+  shared.SelectVersion("example", "HEAD");
+
+  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
+@available(added=2)
+library dependency;
+
+@available(added=3, removed=5)
+type Foo = struct {};
+)FIDL");
+  ASSERT_COMPILED(dependency);
+
+  TestLibrary example(&shared, "example.fidl", R"FIDL(
+@available(added=1)
+library example;
+
+using dependency;
+
+type Foo = struct {
+    @available(deprecated=5)
+    dep dependency.Foo;
+};
+)FIDL");
+  example.ExpectFail(ErrNameNotFound, "Foo", "library 'dependency'");
+  example.ExpectFail(ErrNameNotFound, "Foo", "library 'dependency'");
+  ASSERT_COMPILER_DIAGNOSTICS(example);
+}
+
+TEST(VersioningPlatformTests, GoodMixVersionedAndUnversioned) {
+  SharedAmongstLibraries shared;
+  shared.SelectVersion("example", "1");
+
+  TestLibrary versioned(&shared, "versioned.fidl", R"FIDL(
+@available(added=1, removed=2)
+library example.versioned;
+
+type Foo = struct {};
+)FIDL");
+  ASSERT_COMPILED(versioned);
+
+  TestLibrary not_versioned(&shared, "not_versioned.fidl", R"FIDL(
+library example.notversioned;
+
+using example.versioned;
+
+alias Foo = example.versioned.Foo;
+)FIDL");
+  ASSERT_COMPILED(not_versioned);
+
+  // The example.notversioned library is considered added=HEAD in the special
+  // "unversioned" platform. (If it were instead in the "example" platform, it
+  // would appear empty because we're using `--available example:1`.)
+  ASSERT_NE(not_versioned.LookupAlias("Foo"), nullptr);
+}
+
+}  // namespace
+}  // namespace fidlc
diff --git a/tools/fidl/fidlc/tests/versioning_replacement_tests.cc b/tools/fidl/fidlc/tests/versioning_replacement_tests.cc
new file mode 100644
index 0000000..a8b54f1
--- /dev/null
+++ b/tools/fidl/fidlc/tests/versioning_replacement_tests.cc
@@ -0,0 +1,210 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "tools/fidl/fidlc/tests/test_library.h"
+
+// This file tests how FIDL versioning distinguishes "removal" from
+// "replacement", and validation that replacement is done correctly.
+// Tests are run for all the versions given in INSTANTIATE_TEST_SUITE_P.
+
+namespace fidlc {
+namespace {
+
+class VersioningReplacementTest : public testing::TestWithParam<Version> {};
+
+const Version V1 = Version::From(1).value();
+const Version V2 = Version::From(2).value();
+const Version V3 = Version::From(3).value();
+
+INSTANTIATE_TEST_SUITE_P(VersioningReplacementTests, VersioningReplacementTest,
+                         testing::Values(V1, V2, V3),
+                         [](auto info) { return info.param.ToString(); });
+
+TEST_P(VersioningReplacementTest, BadRemovedWithReplacement) {
+  TestLibrary library;
+  library.SelectVersion("test", GetParam());
+  library.AddFile("bad/fi-0205.test.fidl");
+  library.ExpectFail(ErrRemovedWithReplacement, "Bar", Version::From(2).value(),
+                     "bad/fi-0205.test.fidl:11:14");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningReplacementTest, BadRemovedNamedToAnonymous) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(removed=2)
+type Foo = struct {};
+
+type Bar = struct {
+    @available(added=2)
+    foo struct {};
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  library.ExpectFail(ErrRemovedWithReplacement, "Foo", Version::From(2).value(),
+                     "example.fidl:10:9");
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningReplacementTest, GoodRemovedAnonymousToNamed) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Bar = struct {
+    // The anonymous type "Foo" inherits removed=2, but removed/replaced
+    // does not apply to inherited availabilities.
+    @available(removed=2)
+    foo struct {};
+};
+
+@available(added=2)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
+}
+
+TEST_P(VersioningReplacementTest, GoodRemovedAnonymousToAnonymous) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Bar1 = struct {
+    // The anonymous type "Foo" inherits removed=2, but removed/replaced
+    // does not apply to inherited availabilities.
+    @available(removed=2)
+    foo struct {};
+};
+
+type Bar2 = struct {
+    @available(added=2)
+    foo table {};
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
+}
+
+TEST_P(VersioningReplacementTest, BadReplacedWithoutReplacement) {
+  TestLibrary library;
+  library.SelectVersion("test", GetParam());
+  library.AddFile("bad/fi-0206.test.fidl");
+  library.ExpectFail(ErrReplacedWithoutReplacement, "Bar", Version::From(2).value());
+  ASSERT_COMPILER_DIAGNOSTICS(library);
+}
+
+TEST_P(VersioningReplacementTest, GoodAnonymousReplacedWithoutReplacement) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Bar = struct {
+    // The anonymous type "Foo" inherits replaced=2, but removed/replaced
+    // validation does not apply to inherited availabilities.
+    @available(replaced=2)
+    foo struct {};
+    @available(added=2)
+    foo string;
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+}
+
+TEST_P(VersioningReplacementTest, GoodReplacedNamedToAnonymous) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(replaced=2)
+type Foo = struct {};
+
+type Bar = struct {
+    @available(added=2)
+    foo table {};
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
+}
+
+TEST_P(VersioningReplacementTest, GoodReplacedAnonymousToNamed) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Bar = struct {
+    @available(replaced=2)
+    foo struct {};
+    @available(added=2)
+    foo string;
+};
+
+@available(added=2)
+type Foo = table {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
+}
+
+TEST_P(VersioningReplacementTest, GoodReplacedAnonymousToAnonymous) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+type Bar1 = struct {
+    @available(replaced=2)
+    foo struct {};
+    @available(added=2)
+    foo string;
+};
+
+type Bar2 = struct {
+    @available(added=2)
+    foo table {};
+};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
+}
+
+TEST_P(VersioningReplacementTest, GoodReplacedTwice) {
+  TestLibrary library(R"FIDL(
+@available(added=1)
+library example;
+
+@available(replaced=2)
+type Foo = struct {};
+
+@available(added=2, replaced=3)
+type Foo = table {};
+
+@available(added=3)
+type Foo = union {};
+)FIDL");
+  library.SelectVersion("example", GetParam());
+  ASSERT_COMPILED(library);
+  EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
+  EXPECT_EQ(library.HasTable("Foo"), GetParam() == V2);
+  EXPECT_EQ(library.HasUnion("Foo"), GetParam() >= V3);
+}
+
+}  // namespace
+}  // namespace fidlc
diff --git a/tools/fidl/fidlc/tests/versioning_tests.cc b/tools/fidl/fidlc/tests/versioning_tests.cc
deleted file mode 100644
index 7289875..0000000
--- a/tools/fidl/fidlc/tests/versioning_tests.cc
+++ /dev/null
@@ -1,3396 +0,0 @@
-// Copyright 2022 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <optional>
-
-#include <gtest/gtest.h>
-
-#include "tools/fidl/fidlc/src/diagnostics.h"
-#include "tools/fidl/fidlc/src/versioning_types.h"
-#include "tools/fidl/fidlc/tests/test_library.h"
-
-// This file tests the behavior of the @available attribute. See also
-// decomposition_tests.cc and availability_interleaving_tests.cc.
-
-namespace fidlc {
-namespace {
-
-// Largest numeric version accepted by Version::Parse.
-const std::string kMaxNumericVersion = std::to_string((1ull << 63) - 1);
-
-TEST(VersioningTests, GoodUnversionedPlatformOneComponent) {
-  TestLibrary library(R"FIDL(
-library example;
-)FIDL");
-  ASSERT_COMPILED(library);
-
-  auto example = library.LookupLibrary("example");
-  EXPECT_TRUE(example->platform.value().is_unversioned());
-}
-
-TEST(VersioningTests, GoodUnversionedPlatformTwoComponents) {
-  TestLibrary library(R"FIDL(
-library example.something;
-)FIDL");
-  ASSERT_COMPILED(library);
-
-  auto example = library.LookupLibrary("example.something");
-  EXPECT_TRUE(example->platform.value().is_unversioned());
-}
-
-TEST(VersioningTests, GoodImplicitPlatformOneComponent) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  ASSERT_COMPILED(library);
-
-  auto example = library.LookupLibrary("example");
-  EXPECT_EQ(example->platform, Platform::Parse("example").value());
-  EXPECT_FALSE(example->platform.value().is_unversioned());
-}
-
-TEST(VersioningTests, GoodImplicitPlatformTwoComponents) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example.something;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  ASSERT_COMPILED(library);
-
-  auto example = library.LookupLibrary("example.something");
-  EXPECT_EQ(example->platform, Platform::Parse("example").value());
-  EXPECT_FALSE(example->platform.value().is_unversioned());
-}
-
-TEST(VersioningTests, GoodExplicitPlatform) {
-  TestLibrary library(R"FIDL(
-@available(platform="someplatform", added=HEAD)
-library example;
-)FIDL");
-  library.SelectVersion("someplatform", "HEAD");
-  ASSERT_COMPILED(library);
-
-  auto example = library.LookupLibrary("example");
-  EXPECT_EQ(example->platform, Platform::Parse("someplatform").value());
-  EXPECT_FALSE(example->platform.value().is_unversioned());
-}
-
-TEST(VersioningTests, BadInvalidPlatform) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0152.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrInvalidPlatform, "Spaces are not allowed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadReservedPlatform) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0208.test.fidl");
-  library.ExpectFail(ErrReservedPlatform, "unversioned");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadExplicitPlatformNoVersionSelected) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0201.test.fidl");
-  library.ExpectFail(ErrPlatformVersionNotSelected, "test.bad.fi0201",
-                     Platform::Parse("foo").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadImplicitPlatformNoVersionSelected) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example.something;
-)FIDL");
-  library.ExpectFail(ErrPlatformVersionNotSelected, "example.something",
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAttributeOnMultipleLibraryDeclarationsAgree) {
-  TestLibrary library;
-  library.AddSource("first.fidl", R"FIDL(
-@available(added=1)
-library example;
-)FIDL");
-  library.AddSource("second.fidl", R"FIDL(
-@available(added=1)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrDuplicateAttribute, "available", "first.fidl:2:2");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAttributeOnMultipleLibraryDeclarationsDisagree) {
-  TestLibrary library;
-  library.AddSource("first.fidl", R"FIDL(
-@available(added=1)
-library example;
-)FIDL");
-  library.AddSource("second.fidl", R"FIDL(
-@available(added=2)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrDuplicateAttribute, "available", "first.fidl:2:2");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAttributeOnMultipleLibraryDeclarationsHead) {
-  TestLibrary library;
-  library.AddSource("first.fidl", R"FIDL(
-@available(added=HEAD)
-library example;
-)FIDL");
-  library.AddSource("second.fidl", R"FIDL(
-@available(added=HEAD)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  // TODO(https://fxbug.dev/42062904): Check for duplicate attributes earlier in
-  // compilation so that this is ErrDuplicateAttribute instead.
-  library.ExpectFail(ErrReferenceInLibraryAttribute);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodLibraryDefault) {
-  auto source = R"FIDL(
-library example;
-)FIDL";
-
-  for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
-    TestLibrary library(source);
-    library.SelectVersion("example", version);
-    ASSERT_COMPILED(library);
-  }
-}
-
-TEST(VersioningTests, GoodLibraryAddedAtHead) {
-  auto source = R"FIDL(
-@available(added=HEAD)
-library example;
-)FIDL";
-
-  for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
-    TestLibrary library(source);
-    library.SelectVersion("example", version);
-    ASSERT_COMPILED(library);
-  }
-}
-
-TEST(VersioningTests, GoodLibraryAddedAtOne) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-  }
-}
-
-TEST(VersioningTests, GoodLibraryAddedAndRemoved) {
-  auto source = R"FIDL(
-@available(added=1, removed=2)
-library example;
-)FIDL";
-
-  for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
-    TestLibrary library(source);
-    library.SelectVersion("example", version);
-    ASSERT_COMPILED(library);
-  }
-}
-
-TEST(VersioningTests, GoodLibraryAddedAndDeprecatedAndRemoved) {
-  auto source = R"FIDL(
-@available(added=1, deprecated=2, removed=HEAD)
-library example;
-)FIDL";
-
-  for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
-    TestLibrary library(source);
-    library.SelectVersion("example", version);
-    ASSERT_COMPILED(library);
-  }
-}
-
-TEST(VersioningTests, GoodLibraryAddedAndRemovedLegacyFalse) {
-  auto source = R"FIDL(
-@available(added=1, removed=2, legacy=false)
-library example;
-)FIDL";
-
-  for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
-    TestLibrary library(source);
-    library.SelectVersion("example", version);
-    ASSERT_COMPILED(library);
-  }
-}
-
-TEST(VersioningTests, GoodLibraryAddedAndRemovedLegacyTrue) {
-  auto source = R"FIDL(
-@available(added=1, removed=2, legacy=true)
-library example;
-)FIDL";
-
-  for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
-    TestLibrary library(source);
-    library.SelectVersion("example", version);
-    ASSERT_COMPILED(library);
-  }
-}
-
-TEST(VersioningTests, GoodDeclAddedAtHead) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=HEAD)
-type Foo = struct {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodDeclAddedAtOne) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1)
-type Foo = struct {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodDeclAddedAndRemoved) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1, removed=2)
-type Foo = struct {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodDeclAddedAndReplaced) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1, replaced=2)
-type Foo = struct {};
-
-@available(added=2)
-type Foo = table {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-    ASSERT_NE(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-    ASSERT_NE(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-    ASSERT_NE(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-    ASSERT_NE(library.LookupTable("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodDeclAddedAndDeprecatedAndRemoved) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1, deprecated=2, removed=HEAD)
-type Foo = struct {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_FALSE(library.LookupStruct("Foo")->availability.is_deprecated());
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_TRUE(library.LookupStruct("Foo")->availability.is_deprecated());
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_TRUE(library.LookupStruct("Foo")->availability.is_deprecated());
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodDeclAddedAndRemovedLegacy) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1, removed=2, legacy=true)
-type Foo = struct {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    // The decl is re-added at LEGACY.
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodMemberAddedAtHead) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(added=HEAD)
-    member string;
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-}
-
-TEST(VersioningTests, GoodMemberAddedAtOne) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(added=1)
-    member string;
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-}
-
-TEST(VersioningTests, GoodMemberAddedAndRemoved) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(added=1, removed=2)
-    member string;
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-}
-
-TEST(VersioningTests, GoodMemberAddedAndReplaced) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(added=1, replaced=2)
-    member string;
-    @available(added=2)
-    member uint32;
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
-              Type::Kind::kString);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
-              Type::Kind::kPrimitive);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
-              Type::Kind::kPrimitive);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
-              Type::Kind::kPrimitive);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
-              Type::Kind::kPrimitive);
-  }
-}
-
-TEST(VersioningTests, GoodMemberAddedAndDeprecatedAndRemoved) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(added=1, deprecated=2, removed=HEAD)
-    member string;
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-    EXPECT_FALSE(library.LookupStruct("Foo")->members.front().availability.is_deprecated());
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-    EXPECT_TRUE(library.LookupStruct("Foo")->members.front().availability.is_deprecated());
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-    EXPECT_TRUE(library.LookupStruct("Foo")->members.front().availability.is_deprecated());
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-}
-
-TEST(VersioningTests, GoodMemberAddedAndRemovedLegacy) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(added=1, removed=2, legacy=true)
-    member string;
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", kMaxNumericVersion);
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "HEAD");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "LEGACY");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-    // The member is re-added at LEGACY.
-    ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
-  }
-}
-
-TEST(VersioningTests, GoodAllArgumentsOnLibrary) {
-  TestLibrary library(R"FIDL(
-@available(platform="notexample", added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
-library example;
-)FIDL");
-  library.SelectVersion("notexample", "1");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, GoodAllArgumentsOnDecl) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "1");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, GoodAllArgumentsOnMember) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
-    member string;
-};
-)FIDL");
-  library.SelectVersion("example", "1");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, GoodAttributeOnEverything) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1)
-const CONST uint32 = 1;
-
-@available(added=1)
-alias Alias = string;
-
-// TODO(https://fxbug.dev/42158155): Uncomment.
-// @available(added=1)
-// type Type = string;
-
-@available(added=1)
-type Bits = bits {
-    @available(added=1)
-    MEMBER = 1;
-};
-
-@available(added=1)
-type Enum = enum {
-    @available(added=1)
-    MEMBER = 1;
-};
-
-@available(added=1)
-type Struct = struct {
-    @available(added=1)
-    member string;
-};
-
-@available(added=1)
-type Table = table {
-    @available(added=1)
-    1: member string;
-};
-
-@available(added=1)
-type Union = union {
-    @available(added=1)
-    1: member string;
-};
-
-@available(added=1)
-protocol ProtocolToCompose {};
-
-@available(added=1)
-protocol Protocol {
-    @available(added=1)
-    compose ProtocolToCompose;
-
-    @available(added=1)
-    Method() -> ();
-};
-
-@available(added=1)
-service Service {
-    @available(added=1)
-    member client_end:Protocol;
-};
-
-@available(added=1)
-resource_definition Resource : uint32 {
-    properties {
-        @available(added=1)
-        subtype flexible enum : uint32 {};
-    };
-};
-)FIDL");
-  library.SelectVersion("example", "1");
-  ASSERT_COMPILED(library);
-
-  auto& unfiltered_decls = library.LookupLibrary("example")->declaration_order;
-  auto& filtered_decls = library.declaration_order();
-  // Because everything has the same availability, nothing gets split.
-  EXPECT_EQ(unfiltered_decls.size(), filtered_decls.size());
-}
-
-// TODO(https://fxbug.dev/42146818): Currently attributes `@HERE type Foo = struct {};` and
-// `type Foo = @HERE struct {};` are interchangeable. We just disallow using
-// both at once (ErrRedundantAttributePlacement). However, @available on the
-// anonymous layout is confusing so maybe we should rethink this design.
-TEST(VersioningTests, GoodAttributeOnAnonymousLayoutTopLevel) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = @available(added=2) struct {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-    ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-    ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, BadAttributeOnAnonymousLayoutInMember) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    member @available(added=2) struct {};
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidAttributePlacement, "available");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadInvalidVersionBelowMin) {
-  TestLibrary library(R"FIDL(
-@available(added=0)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidVersion, 0);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadInvalidVersionAboveMaxNumeric) {
-  TestLibrary library(R"FIDL(
-@available(added=9223372036854775808) // 2^63
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidVersion, 9223372036854775808u);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadInvalidVersionBeforeHeadOrdinal) {
-  TestLibrary library(R"FIDL(
-@available(added=18446744073709551613) // 2^64-3
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidVersion, 18446744073709551613u);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodVersionHeadOrdinal) {
-  TestLibrary library(R"FIDL(
-@available(added=18446744073709551614) // 2^64-2
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, BadInvalidVersionLegacyOrdinal) {
-  TestLibrary library(R"FIDL(
-@available(added=18446744073709551615) // 2^64-1
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidVersion, 18446744073709551615u);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadInvalidVersionAfterLegacyOrdinal) {
-  TestLibrary library(R"FIDL(
-@available(added=18446744073709551616) // 2^64
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrCouldNotResolveAttributeArg);
-  library.ExpectFail(ErrConstantOverflowsType, "18446744073709551616", "uint64");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadInvalidVersionLegacy) {
-  TestLibrary library(R"FIDL(
-@available(added=LEGACY)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAttributeArgRequiresLiteral, "added", "available");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadInvalidVersionNegative) {
-  TestLibrary library(R"FIDL(
-@available(added=-1)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrCouldNotResolveAttributeArg);
-  library.ExpectFail(ErrConstantOverflowsType, "-1", "uint64");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadNoArguments) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0147.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrAvailableMissingArguments);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadLibraryMissingAddedOnlyRemoved) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0150-a.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrLibraryAvailabilityMissingAdded);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadLibraryMissingAddedOnlyPlatform) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0150-b.test.fidl");
-  library.SelectVersion("foo", "HEAD");
-  library.ExpectFail(ErrLibraryAvailabilityMissingAdded);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadLibraryReplaced) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0204.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrLibraryReplaced);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadNoteWithoutDeprecation) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0148.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrNoteWithoutDeprecation);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadRemovedAndReplaced) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0203.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrRemovedAndReplaced);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadPlatformNotOnLibrary) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(platform="bad")
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrPlatformNotOnLibrary);
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadUseInUnversionedLibrary) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0151.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrMissingLibraryAvailability, "test.bad.fi0151");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadUseInUnversionedLibraryReportedOncePerAttribute) {
-  TestLibrary library(R"FIDL(
-library example;
-
-@available(added=1)
-type Foo = struct {
-    @available(added=2)
-    member1 bool;
-    member2 bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  // Note: Only twice, not a third time for member2.
-  library.ExpectFail(ErrMissingLibraryAvailability, "example");
-  library.ExpectFail(ErrMissingLibraryAvailability, "example");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAddedEqualsRemoved) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0154-a.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added < removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAddedEqualsReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, replaced=2)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added < replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAddedGreaterThanRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=2, removed=1)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added < removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAddedGreaterThanReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=3, replaced=2)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added < replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodAddedEqualsDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=1, deprecated=1)
-library example;
-)FIDL");
-  library.SelectVersion("example", "1");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, BadAddedGreaterThanDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=1)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedEqualsRemoved) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0154-b.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedEqualsReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1, deprecated=2, replaced=2)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedGreaterThanRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=1, deprecated=3, removed=2)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedGreaterThanReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1, deprecated=3, replaced=2)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadLegacyTrueNotRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=1, legacy=true)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadLegacyFalseNotRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=1, legacy=false)
-library example;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadLegacyTrueNotRemovedMethod) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0182.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodRedundantWithParent) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(added=2, deprecated=4, removed=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "2");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, BadAddedBeforeParentAdded) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0155-a.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
-                     "bad/fi-0155-a.test.fidl:4:12", "added", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodAddedWhenParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(added=4)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "4");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_TRUE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, GoodAddedAfterParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(added=5)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "5");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_TRUE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, BadAddedWhenParentRemoved) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0155-b.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "4", "removed", "4",
-                     "bad/fi-0155-b.test.fidl:4:35", "added", "after", "removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAddedWhenParentReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, replaced=6)
-type Foo = struct {
-    @available(added=6)
-    member bool;
-};
-
-@available(added=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "6", "replaced", "6",
-                     "example.fidl:5:35", "added", "after", "replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAddedAfterParentRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(added=7)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "7", "removed", "6",
-                     "example.fidl:2:35", "added", "after", "removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadAddedAfterParentReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, replaced=6)
-type Foo = struct {
-    @available(added=7)
-    member bool;
-};
-
-@available(added=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "7", "replaced", "6",
-                     "example.fidl:5:35", "added", "after", "replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedBeforeParentAdded) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(deprecated=1)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "1", "added", "2",
-                     "example.fidl:2:12", "deprecated", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodDeprecatedWhenParentAdded) {
-  TestLibrary library(R"FIDL(
-@available(added=2, removed=6) // never deprecated
-library example;
-
-@available(deprecated=2)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "2");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_TRUE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, GoodDeprecatedBeforeParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(deprecated=3)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "3");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_TRUE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, BadDeprecatedAfterParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(deprecated=5)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "5", "deprecated", "4",
-                     "example.fidl:2:21", "deprecated", "after", "deprecated");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedWhenParentRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(deprecated=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "6", "removed", "6",
-                     "example.fidl:2:35", "deprecated", "after", "removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedWhenParentReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, replaced=6)
-type Foo = struct {
-    @available(deprecated=6)
-    member bool;
-};
-
-@available(added=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "6", "replaced", "6",
-                     "example.fidl:5:35", "deprecated", "after", "replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedAfterParentRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(deprecated=7)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "7", "removed", "6",
-                     "example.fidl:2:35", "deprecated", "after", "removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadDeprecatedAfterParentReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, replaced=6)
-type Foo = struct {
-    @available(deprecated=7)
-    member bool;
-};
-
-@available(added=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "7", "replaced", "6",
-                     "example.fidl:5:35", "deprecated", "after", "replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadRemovedBeforeParentAdded) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(removed=1)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "1", "added", "2",
-                     "example.fidl:2:12", "removed", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadReplacedBeforeParentAdded) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, removed=6)
-type Foo = struct {
-    @available(replaced=1)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "1", "added", "2",
-                     "example.fidl:5:12", "replaced", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadRemovedWhenParentAdded) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(removed=2)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "2", "added", "2",
-                     "example.fidl:2:12", "removed", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadReplacedWhenParentAdded) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, removed=6)
-type Foo = struct {
-    @available(replaced=2)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "2", "added", "2",
-                     "example.fidl:5:12", "replaced", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodRemovedBeforeParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(removed=3)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "2");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_FALSE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, GoodReplacedBeforeParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, removed=6)
-type Foo = struct {
-    @available(replaced=3)
-    member bool;
-    @available(added=3)
-    member uint32;
-};
-)FIDL");
-  library.SelectVersion("example", "2");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_FALSE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, GoodRemovedWhenParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(removed=4)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "3");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_FALSE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, GoodReplacedWhenParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, removed=6)
-type Foo = struct {
-    @available(replaced=4)
-    member bool;
-    @available(added=4)
-    member uint32;
-};
-)FIDL");
-  library.SelectVersion("example", "3");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_FALSE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, GoodRemovedAfterParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(removed=5)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "4");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_TRUE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, GoodReplacedAfterParentDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, removed=6)
-type Foo = struct {
-    @available(replaced=5)
-    member bool;
-    @available(added=5)
-    member uint32;
-};
-)FIDL");
-  library.SelectVersion("example", "4");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_TRUE(foo->availability.is_deprecated());
-}
-
-TEST(VersioningTests, BadRemovedAfterParentRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6)
-library example;
-
-@available(removed=7)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "7", "removed", "6",
-                     "example.fidl:2:35", "removed", "after", "removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadRemovedAfterParentReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, replaced=6)
-type Foo = struct {
-    @available(removed=7)
-    member bool;
-};
-
-@available(added=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "7", "replaced", "6",
-                     "example.fidl:5:35", "removed", "after", "replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadReplacedAfterParentRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, removed=6)
-type Foo = struct {
-    @available(replaced=7)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "7", "removed", "6",
-                     "example.fidl:5:35", "replaced", "after", "removed");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadReplacedAfterParentReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, replaced=6)
-type Foo = struct {
-    @available(replaced=7)
-    member bool;
-};
-
-@available(added=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "7", "replaced", "6",
-                     "example.fidl:5:35", "replaced", "after", "replaced");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodRemovedWhenParentReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, replaced=6)
-type Foo = struct {
-    @available(added=2, deprecated=4, removed=6)
-    member bool;
-};
-
-@available(added=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "6");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_TRUE(foo->members.empty());
-}
-
-TEST(VersioningTests, BadReplacedWhenParentRemoved) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, removed=6)
-type Foo = struct {
-    @available(added=2, deprecated=4, replaced=6)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrReplacedWithoutReplacement, "member", Version::From(6).value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadReplacedWhenParentReplaced) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=4, replaced=6)
-type Foo = struct {
-    @available(added=2, deprecated=4, replaced=6)
-    member bool;
-};
-
-@available(added=6)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrReplacedWithoutReplacement, "member", Version::From(6).value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodLegacyParentNotRemovedChildFalse) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4)
-library example;
-
-@available(removed=6, legacy=false)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "LEGACY");
-  ASSERT_COMPILED(library);
-  ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-}
-
-TEST(VersioningTests, GoodLegacyParentNotRemovedChildTrue) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4)
-library example;
-
-@available(removed=6, legacy=true)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "LEGACY");
-  ASSERT_COMPILED(library);
-  ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-}
-
-TEST(VersioningTests, GoodLegacyParentFalseChildFalse) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6, legacy=false)
-library example;
-
-@available(legacy=false)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "LEGACY");
-  ASSERT_COMPILED(library);
-  ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-}
-
-TEST(VersioningTests, BadLegacyParentFalseChildTrue) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6, legacy=false)
-library example;
-
-@available(legacy=true)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "6",
-                     "example.fidl:2:35");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadLegacyParentFalseChildTrueMethod) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0183.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "3",
-                     "bad/fi-0183.test.fidl:7:12");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodLegacyParentTrueChildTrue) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6, legacy=true)
-library example;
-
-@available(legacy=true)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "LEGACY");
-  ASSERT_COMPILED(library);
-  ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-}
-
-TEST(VersioningTests, GoodLegacyParentTrueChildFalse) {
-  TestLibrary library(R"FIDL(
-@available(added=2, deprecated=4, removed=6, legacy=true)
-library example;
-
-@available(legacy=false)
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "LEGACY");
-  ASSERT_COMPILED(library);
-  ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
-}
-
-TEST(VersioningTests, GoodMemberInheritsFromParent) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2)
-type Foo = struct {
-    @available(deprecated=3)
-    member1 bool;
-};
-)FIDL");
-  library.SelectVersion("example", "2");
-  ASSERT_COMPILED(library);
-
-  auto foo = library.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  EXPECT_EQ(foo->members.size(), 1u);
-}
-
-TEST(VersioningTests, GoodComplexInheritance) {
-  // The following libraries all define a struct Bar with effective availability
-  // @available(added=2, deprecated=3, removed=4, legacy=true) in different ways.
-
-  std::vector<const char*> sources;
-
-  // Direct annotation.
-  sources.push_back(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=3, removed=4, legacy=true)
-type Bar = struct {};
-)FIDL");
-
-  // Fully inherit from library declaration.
-  sources.push_back(R"FIDL(
-@available(added=2, deprecated=3, removed=4, legacy=true)
-library example;
-
-type Bar = struct {};
-)FIDL");
-
-  // Partially inherit from library declaration.
-  sources.push_back(R"FIDL(
-@available(added=1, deprecated=3)
-library example;
-
-@available(added=2, removed=4, legacy=true)
-type Bar = struct {};
-)FIDL");
-
-  // Inherit from parent.
-  sources.push_back(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2, deprecated=3, removed=4, legacy=true)
-type Foo = struct {
-    member @generated_name("Bar") struct {};
-};
-)FIDL");
-
-  // Inherit from member.
-  sources.push_back(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(added=2, deprecated=3, removed=4, legacy=true)
-    member @generated_name("Bar") struct {};
-};
-)FIDL");
-
-  // Inherit from multiple, forward.
-  sources.push_back(R"FIDL(
-@available(added=2)
-library example;
-
-@available(deprecated=3)
-type Foo = struct {
-    @available(removed=4, legacy=true)
-    member @generated_name("Bar") struct {};
-};
-)FIDL");
-
-  // Inherit from multiple, backward.
-  sources.push_back(R"FIDL(
-@available(added=1, removed=4, legacy=true)
-library example;
-
-@available(deprecated=3)
-type Foo = struct {
-    @available(added=2)
-    member @generated_name("Bar") struct {};
-};
-)FIDL");
-
-  // Inherit from multiple, mixed.
-  sources.push_back(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2)
-type Foo = struct {
-    @available(deprecated=3, removed=4, legacy=true)
-    member @generated_name("Bar") struct {};
-};
-)FIDL");
-
-  // Inherit via nested layouts.
-  sources.push_back(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2)
-type Foo = struct {
-    @available(deprecated=3)
-    member1 struct {
-        @available(removed=4, legacy=true)
-        member2 struct {
-            member3 @generated_name("Bar") struct {};
-        };
-    };
-};
-)FIDL");
-
-  // Inherit via nested type constructors.
-  sources.push_back(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=2)
-type Foo = struct {
-    @available(deprecated=3, removed=4, legacy=true)
-    member1 vector<vector<vector<@generated_name("Bar") struct{}>>>;
-};
-)FIDL");
-
-  for (auto& source : sources) {
-    {
-      TestLibrary library(source);
-      library.SelectVersion("example", "1");
-      ASSERT_COMPILED(library);
-
-      auto bar = library.LookupStruct("Bar");
-      ASSERT_EQ(bar, nullptr);
-    }
-    {
-      TestLibrary library(source);
-      library.SelectVersion("example", "2");
-      ASSERT_COMPILED(library);
-
-      auto bar = library.LookupStruct("Bar");
-      ASSERT_NE(bar, nullptr);
-      EXPECT_FALSE(bar->availability.is_deprecated());
-    }
-    {
-      TestLibrary library(source);
-      library.SelectVersion("example", "3");
-      ASSERT_COMPILED(library);
-
-      auto bar = library.LookupStruct("Bar");
-      ASSERT_NE(bar, nullptr);
-      EXPECT_TRUE(bar->availability.is_deprecated());
-    }
-    {
-      TestLibrary library(source);
-      library.SelectVersion("example", "4");
-      ASSERT_COMPILED(library);
-
-      auto bar = library.LookupStruct("Bar");
-      ASSERT_EQ(bar, nullptr);
-    }
-    {
-      TestLibrary library(source);
-      library.SelectVersion("example", "LEGACY");
-      ASSERT_COMPILED(library);
-
-      auto bar = library.LookupStruct("Bar");
-      ASSERT_NE(bar, nullptr);
-    }
-  }
-}
-
-TEST(VersioningTests, BadDeclConflictsWithParent) {
-  TestLibrary library(R"FIDL( // L1
-@available(added=2)           // L2
-library example;              // L3
-                              // L4
-@available(added=1)           // L5
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
-                     "example.fidl:2:12", "added", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-  EXPECT_EQ(library.errors()[0]->span.position().line, 5);
-}
-
-TEST(VersioningTests, BadMemberConflictsWithParent) {
-  TestLibrary library(R"FIDL( // L1
-@available(added=1)           // L2
-library example;              // L3
-                              // L4
-@available(added=2)           // L5
-type Foo = struct {           // L6
-    @available(added=1)       // L7
-    member1 bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
-                     "example.fidl:5:12", "added", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-  EXPECT_EQ(library.errors()[0]->span.position().line, 7);
-}
-
-TEST(VersioningTests, BadMemberConflictsWithGrandParent) {
-  TestLibrary library(R"FIDL( // L1
-@available(added=2)           // L2
-library example;              // L3
-                              // L4
-@available(removed=3)         // L5
-type Foo = struct {           // L6
-    @available(added=1)       // L7
-    member1 bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
-                     "example.fidl:2:12", "added", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-  EXPECT_EQ(library.errors()[0]->span.position().line, 7);
-}
-
-TEST(VersioningTests, BadMemberConflictsWithGrandParentThroughAnonymous) {
-  TestLibrary library(R"FIDL( // L1
-@available(added=1)           // L2
-library example;              // L3
-                              // L4
-@available(added=2)           // L5
-type Foo = struct {           // L6
-    member1 struct {          // L7
-        @available(removed=1) // L8
-        member2 bool;
-    };
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "1", "added", "2",
-                     "example.fidl:5:12", "removed", "before", "added");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-  EXPECT_EQ(library.errors()[0]->span.position().line, 8);
-}
-
-TEST(VersioningTests, BadLegacyConflictsWithRemoved) {
-  TestLibrary library(R"FIDL(  // L1
-@available(added=1, removed=2) // L2
-library example;               // L3
-                               // L4
-@available(legacy=true)        // L5
-type Foo = struct {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "2",
-                     "example.fidl:2:21");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-  EXPECT_EQ(library.errors()[0]->span.position().line, 5);
-}
-
-TEST(VersioningTests, BadRemovedWithReplacement) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0205.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrRemovedWithReplacement, "Bar", Version::From(2).value(),
-                     "bad/fi-0205.test.fidl:11:14");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadRemovedNamedToAnonymous) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=2)
-type Foo = struct {};
-
-type Bar = struct {
-    @available(added=2)
-    foo struct {};
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrRemovedWithReplacement, "Foo", Version::From(2).value(),
-                     "example.fidl:10:9");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodRemovedAnonymousToNamed) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Bar = struct {
-    // The anonymous type "Foo" inherits removed=2, but removed/replaced
-    // does not apply to inherited availabilities.
-    @available(removed=2)
-    foo struct {};
-};
-
-@available(added=2)
-type Foo = table {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_NE(library.LookupTable("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodRemovedAnonymousToAnonymous) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Bar1 = struct {
-    // The anonymous type "Foo" inherits removed=2, but removed/replaced
-    // does not apply to inherited availabilities.
-    @available(removed=2)
-    foo struct {};
-};
-
-type Bar2 = struct {
-    @available(added=2)
-    foo table {};
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_NE(library.LookupTable("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, BadReplacedWithoutReplacement) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0206.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrReplacedWithoutReplacement, "Bar", Version::From(2).value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodAnonymousReplacedWithoutReplacement) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Bar = struct {
-    // The anonymous type "Foo" inherits replaced=2, but removed/replaced
-    // validation does not apply to inherited availabilities.
-    @available(replaced=2)
-    foo struct {};
-    @available(added=2)
-    foo string;
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodReplacedNamedToAnonymous) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(replaced=2)
-type Foo = struct {};
-
-type Bar = struct {
-    @available(added=2)
-    foo table {};
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_NE(library.LookupTable("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodReplacedAnonymousToNamed) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Bar = struct {
-    @available(replaced=2)
-    foo struct {};
-    @available(added=2)
-    foo string;
-};
-
-@available(added=2)
-type Foo = table {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_NE(library.LookupTable("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodReplacedAnonymousToAnonymous) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-type Bar1 = struct {
-    @available(replaced=2)
-    foo struct {};
-    @available(added=2)
-    foo string;
-};
-
-type Bar2 = struct {
-    @available(added=2)
-    foo table {};
-};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_NE(library.LookupTable("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodReplacedTwice) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(replaced=2)
-type Foo = struct {};
-
-@available(added=2, replaced=3)
-type Foo = table {};
-
-@available(added=3)
-type Foo = union {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-    EXPECT_EQ(library.LookupUnion("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_NE(library.LookupTable("Foo"), nullptr);
-    EXPECT_EQ(library.LookupUnion("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "3");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-    EXPECT_NE(library.LookupUnion("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodNonOverlappingNamesNoGap) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(replaced=2)
-type Foo = struct {};
-
-@available(added=2)
-type Foo = table {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_NE(library.LookupTable("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodNonOverlappingNamesWithGap) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=2)
-type Foo = struct {};
-
-@available(added=3)
-type Foo = table {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("Foo"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "3");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
-    EXPECT_NE(library.LookupTable("Foo"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodNonOverlappingNamesNoGapCanonical) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=2)
-type foo = struct {};
-
-@available(added=2)
-type FOO = table {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("FOO"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("foo"), nullptr);
-    EXPECT_NE(library.LookupTable("FOO"), nullptr);
-  }
-}
-
-TEST(VersioningTests, GoodNonOverlappingNamesWithGapCanonical) {
-  auto source = R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=2)
-type foo = struct {};
-
-@available(added=3)
-type FOO = table {};
-)FIDL";
-
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "1");
-    ASSERT_COMPILED(library);
-
-    EXPECT_NE(library.LookupStruct("foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("FOO"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "2");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("foo"), nullptr);
-    EXPECT_EQ(library.LookupTable("FOO"), nullptr);
-  }
-  {
-    TestLibrary library(source);
-    library.SelectVersion("example", "3");
-    ASSERT_COMPILED(library);
-
-    EXPECT_EQ(library.LookupStruct("foo"), nullptr);
-    EXPECT_NE(library.LookupTable("FOO"), nullptr);
-  }
-}
-
-TEST(VersioningTests, BadOverlappingNamesEqualToOther) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {};
-type Foo = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameCollision, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
-                     "example.fidl:5:6");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesEqualToOtherLegacy) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=2, legacy=true)
-type Foo = struct {};
-@available(removed=2, legacy=true)
-type Foo = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameCollision, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
-                     "example.fidl:6:6");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesEqualToOtherCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type foo = struct {};
-type FOO = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, "foo",
-                     Element::Kind::kTable, "FOO", "example.fidl:6:6", "foo");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesSimple) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0036.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kEnum, "Color", Element::Kind::kEnum,
-                     "bad/fi-0036.test.fidl:7:6",
-                     VersionSet(VersionRange(Version::From(2).value(), Version::PosInf())),
-                     Platform::Parse("test").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodOverlappingNamesSimpleFixAvailability) {
-  TestLibrary library;
-  library.AddFile("good/fi-0036.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesSimpleCanonical) {
-  TestLibrary library;
-  library.AddFile("bad/fi-0037.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kProtocol, "Color",
-                     Element::Kind::kConst, "COLOR", "bad/fi-0037.test.fidl:7:7", "color",
-                     VersionSet(VersionRange(Version::From(2).value(), Version::PosInf())),
-                     Platform::Parse("test").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, GoodOverlappingNamesSimpleCanonicalFixRename) {
-  TestLibrary library;
-  library.AddFile("good/fi-0037.test.fidl");
-  library.SelectVersion("test", "HEAD");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesContainsOther) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {};
-@available(removed=2)
-type Foo = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
-                     "example.fidl:5:6",
-                     VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesContainsOtherCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type foo = struct {};
-@available(removed=2)
-type FOO = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
-                     "FOO", "example.fidl:7:6", "foo",
-                     VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesIntersectsOther) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=5)
-type Foo = struct {};
-@available(added=3)
-type Foo = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
-                     "example.fidl:6:6",
-                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesIntersectsOtherCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=5)
-type foo = struct {};
-@available(added=3)
-type FOO = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
-                     "FOO", "example.fidl:8:6", "foo",
-                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesJustAtLegacy) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(replaced=2, legacy=true)
-type Foo = struct {};
-@available(added=2, removed=3, legacy=true)
-type Foo = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
-                     "example.fidl:6:6",
-                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesJustAtLegacyCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=2, legacy=true)
-type foo = struct {};
-@available(added=2, removed=3, legacy=true)
-type FOO = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
-                     "FOO", "example.fidl:8:6", "foo",
-                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesIntersectAtLegacy) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(replaced=2, legacy=true)
-type Foo = struct {};
-@available(added=2)
-type Foo = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
-                     "example.fidl:6:6",
-                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesIntersectAtLegacyCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(removed=2, legacy=true)
-type foo = struct {};
-@available(added=2)
-type FOO = table {};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
-                     "FOO", "example.fidl:8:6", "foo",
-                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesMultiple) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {};
-@available(added=3)
-type Foo = table {};
-@available(added=HEAD)
-const Foo uint32 = 0;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kStruct, "Foo", Element::Kind::kConst,
-                     "example.fidl:9:7",
-                     VersionSet(VersionRange(Version::Head(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
-                     "example.fidl:5:6",
-                     VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingNamesRecursive) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(added=1, removed=5)
-type Foo = struct { member box<Foo>; };
-
-@available(added=3, removed=7)
-type Foo = struct { member box<Foo>; };
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kStruct, "Foo", Element::Kind::kStruct,
-                     "example.fidl:6:6",
-                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesEqualToOther) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    member bool;
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameCollision, Element::Kind::kStructMember, "member",
-                     Element::Kind::kStructMember, "example.fidl:6:5");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesEqualToOtherLegacy) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(removed=2, legacy=true)
-    member bool;
-    @available(removed=2, legacy=true)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameCollision, Element::Kind::kStructMember, "member",
-                     Element::Kind::kStructMember, "example.fidl:7:5");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesEqualToOtherCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    member bool;
-    MEMBER bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStructMember, "MEMBER",
-                     Element::Kind::kStructMember, "member", "example.fidl:6:5", "member");
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesContainsOther) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    member bool;
-    @available(removed=2)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
-                     Element::Kind::kStructMember, "example.fidl:6:5",
-                     VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesContainsOtherCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    member bool;
-    @available(removed=2)
-    MEMBER bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
-                     Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
-                     VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesIntersectsOther) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(removed=5)
-    member bool;
-    @available(added=3)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
-                     Element::Kind::kStructMember, "example.fidl:7:5",
-                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesIntersectsOtherCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(removed=5)
-    member bool;
-    @available(added=3)
-    MEMBER bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
-                     Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
-                     VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesJustAtLegacy) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(replaced=2, legacy=true)
-    member bool;
-    @available(added=2, removed=3, legacy=true)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
-                     Element::Kind::kStructMember, "example.fidl:7:5",
-                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesJustAtLegacyCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(removed=2, legacy=true)
-    member bool;
-    @available(added=2, removed=3, legacy=true)
-    MEMBER bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
-                     Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
-                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesIntersectAtLegacy) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(replaced=2, legacy=true)
-    member bool;
-    @available(added=2)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
-                     Element::Kind::kStructMember, "example.fidl:7:5",
-                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesIntersectAtLegacyCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    @available(removed=2, legacy=true)
-    member bool;
-    @available(added=2)
-    MEMBER bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
-                     Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
-                     VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesMultiple) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    member bool;
-    @available(added=3)
-    member bool;
-    @available(added=HEAD)
-    member bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
-                     Element::Kind::kStructMember, "example.fidl:6:5",
-                     VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
-                     Element::Kind::kStructMember, "example.fidl:6:5",
-                     VersionSet(VersionRange(Version::Head(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-TEST(VersioningTests, BadOverlappingMemberNamesMultipleCanonical) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-type Foo = struct {
-    member bool;
-    @available(added=3)
-    Member bool;
-    @available(added=HEAD)
-    MEMBER bool;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "Member",
-                     Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
-                     VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
-                     Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
-                     VersionSet(VersionRange(Version::Head(), Version::PosInf())),
-                     Platform::Parse("example").value());
-  ASSERT_COMPILER_DIAGNOSTICS(library);
-}
-
-// TODO(https://fxbug.dev/42052719): Generalize this with more comprehensive tests in
-// availability_interleaving_tests.cc.
-TEST(VersioningTests, GoodRegularDeprecatedReferencesVersionedDeprecated) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@deprecated
-const FOO uint32 = BAR;
-@available(deprecated=1)
-const BAR uint32 = 1;
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  ASSERT_COMPILED(library);
-}
-
-// Previously this errored due to incorrect logic in deprecation checks.
-TEST(VersioningTests, GoodDeprecationLogicRegression1) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(deprecated=1, removed=3)
-type Foo = struct {};
-
-@available(deprecated=1, removed=3)
-type Bar = struct {
-    foo Foo;
-    @available(added=2)
-    ensure_split_at_v2 string;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  ASSERT_COMPILED(library);
-}
-
-// Previously this crashed due to incorrect logic in deprecation checks.
-TEST(VersioningTests, BadDeprecationLogicRegression2) {
-  TestLibrary library(R"FIDL(
-@available(added=1)
-library example;
-
-@available(deprecated=1)
-type Foo = struct {};
-
-@available(deprecated=1, removed=3)
-type Bar = struct {
-    foo Foo;
-    @available(added=2)
-    ensure_split_at_v2 string;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  ASSERT_COMPILED(library);
-}
-
-TEST(VersioningTests, GoodMultipleFiles) {
-  TestLibrary library;
-  library.AddSource("overview.fidl", R"FIDL(
-/// Some doc comment.
-@available(added=1)
-library example;
-)FIDL");
-  library.AddSource("first.fidl", R"FIDL(
-library example;
-
-@available(added=2)
-type Foo = struct {
-    bar box<Bar>;
-};
-)FIDL");
-  library.AddSource("second.fidl", R"FIDL(
-library example;
-
-@available(added=2)
-type Bar = struct {
-    foo box<Foo>;
-};
-)FIDL");
-  library.SelectVersion("example", "HEAD");
-  ASSERT_COMPILED(library);
-  ASSERT_NE(library.LookupStruct("Foo"), nullptr);
-  ASSERT_NE(library.LookupStruct("Bar"), nullptr);
-}
-
-TEST(VersioningTests, GoodSplitByDeclInExternalLibrary) {
-  SharedAmongstLibraries shared;
-  shared.SelectVersion("platform", "HEAD");
-
-  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
-@available(added=1)
-library platform.dependency;
-
-type Foo = struct {
-    @available(added=2)
-    member string;
-};
-)FIDL");
-  ASSERT_COMPILED(dependency);
-
-  TestLibrary example(&shared, "example.fidl", R"FIDL(
-@available(added=1)
-library platform.example;
-
-using platform.dependency;
-
-type ShouldBeSplit = struct {
-    foo platform.dependency.Foo;
-};
-)FIDL");
-  ASSERT_COMPILED(example);
-}
-
-TEST(VersioningTests, GoodMultiplePlatformsBasic) {
-  SharedAmongstLibraries shared;
-  shared.SelectVersion("dependency", "3");
-  shared.SelectVersion("example", "HEAD");
-
-  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
-@available(added=2)
-library dependency;
-
-@available(added=3, deprecated=4, removed=5)
-type Foo = struct {};
-)FIDL");
-  ASSERT_COMPILED(dependency);
-
-  TestLibrary example(&shared, "example.fidl", R"FIDL(
-@available(added=1)
-library example;
-
-using dependency;
-
-type Foo = struct {
-    @available(deprecated=5)
-    dep dependency.Foo;
-};
-)FIDL");
-  ASSERT_COMPILED(example);
-}
-
-TEST(VersioningTests, GoodMultiplePlatformsExplicitPlatform) {
-  SharedAmongstLibraries shared;
-  shared.SelectVersion("xyz", "3");
-  shared.SelectVersion("example", "HEAD");
-
-  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
-@available(platform="xyz", added=1)
-library dependency;
-
-@available(added=3, removed=4)
-type Foo = struct {};
-)FIDL");
-  ASSERT_COMPILED(dependency);
-
-  TestLibrary example(&shared, "example.fidl", R"FIDL(
-@available(added=1)
-library example;
-
-using dependency;
-
-alias Foo = dependency.Foo;
-)FIDL");
-  ASSERT_COMPILED(example);
-}
-
-TEST(VersioningTests, GoodMultiplePlatformsUsesCorrectDecl) {
-  SharedAmongstLibraries shared;
-  shared.SelectVersion("dependency", "4");
-  shared.SelectVersion("example", "1");
-
-  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
-@available(added=2)
-library dependency;
-
-@available(deprecated=3, replaced=4)
-type Foo = resource struct {};
-
-@available(added=4, removed=5)
-type Foo = table {};
-)FIDL");
-  ASSERT_COMPILED(dependency);
-
-  TestLibrary example(&shared, "example.fidl", R"FIDL(
-@available(added=1)
-library example;
-
-using dependency;
-
-type Foo = struct {
-    dep dependency.Foo;
-};
-)FIDL");
-  ASSERT_COMPILED(example);
-
-  auto foo = example.LookupStruct("Foo");
-  ASSERT_NE(foo, nullptr);
-  ASSERT_EQ(foo->members.size(), 1u);
-  auto member_type = foo->members[0].type_ctor->type;
-  ASSERT_EQ(member_type->kind, Type::Kind::kIdentifier);
-  auto identifier_type = static_cast<const IdentifierType*>(member_type);
-  EXPECT_EQ(identifier_type->type_decl->kind, Decl::Kind::kTable);
-}
-
-TEST(VersioningTests, BadMultiplePlatformsNameNotFound) {
-  SharedAmongstLibraries shared;
-  shared.SelectVersion("dependency", "HEAD");
-  shared.SelectVersion("example", "HEAD");
-
-  TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
-@available(added=2)
-library dependency;
-
-@available(added=3, removed=5)
-type Foo = struct {};
-)FIDL");
-  ASSERT_COMPILED(dependency);
-
-  TestLibrary example(&shared, "example.fidl", R"FIDL(
-@available(added=1)
-library example;
-
-using dependency;
-
-type Foo = struct {
-    @available(deprecated=5)
-    dep dependency.Foo;
-};
-)FIDL");
-  example.ExpectFail(ErrNameNotFound, "Foo", "dependency");
-  example.ExpectFail(ErrNameNotFound, "Foo", "dependency");
-  ASSERT_COMPILER_DIAGNOSTICS(example);
-}
-
-TEST(VersioningTests, GoodMixVersionedAndUnversioned) {
-  SharedAmongstLibraries shared;
-  shared.SelectVersion("example", "1");
-
-  TestLibrary versioned(&shared, "versioned.fidl", R"FIDL(
-@available(added=1, removed=2)
-library example.versioned;
-
-type Foo = struct {};
-)FIDL");
-  ASSERT_COMPILED(versioned);
-
-  TestLibrary not_versioned(&shared, "not_versioned.fidl", R"FIDL(
-library example.notversioned;
-
-using example.versioned;
-
-alias Foo = example.versioned.Foo;
-)FIDL");
-  ASSERT_COMPILED(not_versioned);
-
-  // The example.notversioned library is considered added=HEAD in the special
-  // "unversioned" platform. (If it were instead in the "example" platform, it
-  // would appear empty because we're using `--available example:1`.)
-  ASSERT_NE(not_versioned.LookupAlias("Foo"), nullptr);
-}
-
-}  // namespace
-}  // namespace fidlc
diff --git a/tools/fidl/fidlgen_cpp/codegen/fragment_bits.tmpl b/tools/fidl/fidlgen_cpp/codegen/fragment_bits.tmpl
index 96cd339..fb69111 100644
--- a/tools/fidl/fidlgen_cpp/codegen/fragment_bits.tmpl
+++ b/tools/fidl/fidlgen_cpp/codegen/fragment_bits.tmpl
@@ -124,8 +124,8 @@
 {{- define "Bits:Traits:WireTypesHeader" }}
 template <bool IsRecursive>
 struct internal::WireCodingTraits<{{ . }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof({{ .Type }});
-  static constexpr bool is_memcpy_compatible = {{ not .Strictness }};
+  static constexpr size_t kInlineSize = sizeof({{ .Type }});
+  static constexpr bool kIsMemcpyCompatible = {{ not .Strictness }};
 
   static void Encode(internal::WireEncoder* encoder, {{ . }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     {{- if .Strictness }}
@@ -167,8 +167,8 @@
 {{- define "Bits:Traits:NaturalTypesHeader" }}
   template <>
   struct internal::NaturalCodingTraits<{{ . }}, ::fidl::internal::NaturalCodingConstraintEmpty> {
-    static constexpr size_t inline_size_v2 = sizeof({{ .Type }});
-    static constexpr bool is_memcpy_compatible = {{ not .Strictness }};
+    static constexpr size_t kInlineSize = sizeof({{ .Type }});
+    static constexpr bool kIsMemcpyCompatible = {{ not .Strictness }};
 
     static void Encode(internal::NaturalEncoder* encoder, {{ . }}* value, size_t offset, size_t recursion_depth) {
       {{- if .Strictness }}
diff --git a/tools/fidl/fidlgen_cpp/codegen/fragment_enum.tmpl b/tools/fidl/fidlgen_cpp/codegen/fragment_enum.tmpl
index 6353830..f47b2ea 100644
--- a/tools/fidl/fidlgen_cpp/codegen/fragment_enum.tmpl
+++ b/tools/fidl/fidlgen_cpp/codegen/fragment_enum.tmpl
@@ -89,8 +89,8 @@
 {{- define "Enum:Traits:WireTypesHeader" }}
 template <bool IsRecursive>
 struct internal::WireCodingTraits<{{ . }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof({{ .Type }});
-  static constexpr bool is_memcpy_compatible = {{ not .Strictness }};
+  static constexpr size_t kInlineSize = sizeof({{ .Type }});
+  static constexpr bool kIsMemcpyCompatible = {{ not .Strictness }};
 
   static void Encode(internal::WireEncoder* encoder, {{ . }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     {{- if .Strictness }}
@@ -174,8 +174,8 @@
 {{- define "Enum:Traits:NaturalTypesHeader" }}
   template <>
   struct internal::NaturalCodingTraits<{{ . }}, ::fidl::internal::NaturalCodingConstraintEmpty> {
-    static constexpr size_t inline_size_v2 = sizeof({{ .Type }});
-    static constexpr bool is_memcpy_compatible = {{ not .Strictness }};
+    static constexpr size_t kInlineSize = sizeof({{ .Type }});
+    static constexpr bool kIsMemcpyCompatible = {{ not .Strictness }};
 
     static void Encode(internal::NaturalEncoder* encoder, {{ . }}* value, size_t offset, size_t recursion_depth) {
       {{- if .Strictness }}
diff --git a/tools/fidl/fidlgen_cpp/codegen/fragment_method_event.tmpl b/tools/fidl/fidlgen_cpp/codegen/fragment_method_event.tmpl
index 3e0d1b6..318dc72 100644
--- a/tools/fidl/fidlgen_cpp/codegen/fragment_method_event.tmpl
+++ b/tools/fidl/fidlgen_cpp/codegen/fragment_method_event.tmpl
@@ -41,7 +41,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<{{ .WireTransactionalEvent }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<{{ .WireTransactionalEvent }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = {{ .Response.TypeShapeV2.InlineSize }} + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = {{ .Response.TypeShapeV2.InlineSize }} + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, {{ .WireTransactionalEvent }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
diff --git a/tools/fidl/fidlgen_cpp/codegen/fragment_method_request.tmpl b/tools/fidl/fidlgen_cpp/codegen/fragment_method_request.tmpl
index 6cbec72..7f8a2ed 100644
--- a/tools/fidl/fidlgen_cpp/codegen/fragment_method_request.tmpl
+++ b/tools/fidl/fidlgen_cpp/codegen/fragment_method_request.tmpl
@@ -42,7 +42,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<{{ .WireTransactionalRequest }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<{{ .WireTransactionalRequest }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = {{ .Request.TypeShapeV2.InlineSize }} + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = {{ .Request.TypeShapeV2.InlineSize }} + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, {{ .WireTransactionalRequest }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/codegen/fragment_method_response.tmpl b/tools/fidl/fidlgen_cpp/codegen/fragment_method_response.tmpl
index c184ca43..73e2975 100644
--- a/tools/fidl/fidlgen_cpp/codegen/fragment_method_response.tmpl
+++ b/tools/fidl/fidlgen_cpp/codegen/fragment_method_response.tmpl
@@ -37,7 +37,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<{{ .WireResponse }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<{{ .WireResponse }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = {{ .Response.TypeShapeV2.InlineSize }};
+  static constexpr size_t kInlineSize = {{ .Response.TypeShapeV2.InlineSize }};
 
   static void Encode(
     internal::WireEncoder* encoder, {{ .WireResponse }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -82,7 +82,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<{{ .WireTransactionalResponse }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<{{ .WireTransactionalResponse }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = {{ .Response.TypeShapeV2.InlineSize }} + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = {{ .Response.TypeShapeV2.InlineSize }} + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, {{ .WireTransactionalResponse }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/codegen/fragment_struct.tmpl b/tools/fidl/fidlgen_cpp/codegen/fragment_struct.tmpl
index 8288b7d..3652c4b 100644
--- a/tools/fidl/fidlgen_cpp/codegen/fragment_struct.tmpl
+++ b/tools/fidl/fidlgen_cpp/codegen/fragment_struct.tmpl
@@ -83,7 +83,7 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<{{ . }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = {{ .TypeShapeV2.InlineSize }};
+  static constexpr size_t kInlineSize = {{ .TypeShapeV2.InlineSize }};
   static constexpr auto kMembers = std::make_tuple(
     {{- range $i, $m := .Members }}
       {{- if $i }}, {{ end -}}
@@ -91,11 +91,11 @@
     {{- end }});
   static constexpr bool kHasPadding = {{ gt (len .PaddingV2) 0 }};
   using Base = WireStructCodingTraitsBase<{{ . }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, {{ . }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof({{ . }}));
     } else {
       {{- range .PaddingV2 }}
diff --git a/tools/fidl/fidlgen_cpp/codegen/fragment_table.tmpl b/tools/fidl/fidlgen_cpp/codegen/fragment_table.tmpl
index b947ab0..26f235c9 100644
--- a/tools/fidl/fidlgen_cpp/codegen/fragment_table.tmpl
+++ b/tools/fidl/fidlgen_cpp/codegen/fragment_table.tmpl
@@ -383,8 +383,8 @@
 struct ::fidl::internal::WireCodingTraits<{{ . }}, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = {{ .TypeShapeV2.InlineSize }};
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = {{ .TypeShapeV2.InlineSize }};
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, {{ . }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -406,7 +406,7 @@
       switch (i) {
         {{- range .Members }}
         case {{ Sub .Ordinal 1 }}:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::kInlineSize;
           break;
         {{- end }}
       }
@@ -440,7 +440,7 @@
       switch (i) {
         {{- range .Members }}
         case {{ Sub .Ordinal 1 }}:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::kInlineSize;
           break;
         {{- end }}
       }
diff --git a/tools/fidl/fidlgen_cpp/codegen/fragment_union.tmpl b/tools/fidl/fidlgen_cpp/codegen/fragment_union.tmpl
index d26f440..9b38b19 100644
--- a/tools/fidl/fidlgen_cpp/codegen/fragment_union.tmpl
+++ b/tools/fidl/fidlgen_cpp/codegen/fragment_union.tmpl
@@ -241,8 +241,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<{{ . }}, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = {{ .TypeShapeV2.InlineSize }};
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = {{ .TypeShapeV2.InlineSize }};
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, {{ . }}* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -268,7 +268,7 @@
     switch (u->tag) {
       {{- range .Members }}
       case {{ .Ordinal }}: // {{ .TagName }}
-        encode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::kInlineSize;
         break;
       {{- end }}
       default:
@@ -313,7 +313,7 @@
     switch (tag) {
       {{- range .Members }}
       case {{ .TagName }}:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<{{ .Type }}, {{ .WireConstraint }}, IsRecursive>::kInlineSize;
         break;
       {{- end }}
       default:
diff --git a/tools/fidl/fidlgen_cpp/goldens/aliases_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/aliases_natural_types.h.golden
index 18ec3bd..2703aa8 100644
--- a/tools/fidl/fidlgen_cpp/goldens/aliases_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/aliases_natural_types.h.golden
@@ -298,8 +298,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_aliases::ObjType, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_aliases::ObjType* value, size_t offset, size_t recursion_depth) {
     switch (*value) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/aliases_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/aliases_wire_types.h.golden
index 7ff00f13..9b2365d 100644
--- a/tools/fidl/fidlgen_cpp/goldens/aliases_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/aliases_wire_types.h.golden
@@ -85,8 +85,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_aliases::wire::ObjType, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_aliases::wire::ObjType* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     switch (*value) {
@@ -146,15 +146,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_aliases::wire::ExampleOfUseOfAliases, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 88;
+  static constexpr size_t kInlineSize = 88;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false, 9>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false, 5>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_someotherlibrary::wire::ReferenceMe>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 5>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::channel, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::channel, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::channel, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, 0x80000000, true>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_aliases::wire::ExampleOfUseOfAliases, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_aliases::wire::ExampleOfUseOfAliases* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_aliases::wire::ExampleOfUseOfAliases));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
diff --git a/tools/fidl/fidlgen_cpp/goldens/anonymous_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/anonymous_natural_types.h.golden
index 113045b..9a44bd1 100644
--- a/tools/fidl/fidlgen_cpp/goldens/anonymous_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/anonymous_natural_types.h.golden
@@ -1093,8 +1093,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_anonymous::Flags, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint16_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint16_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_anonymous::Flags* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_anonymous::Flags>(offset) = *value;
@@ -1105,8 +1105,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_anonymous::BitsMember, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_anonymous::BitsMember* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_anonymous::BitsMember>(offset) = *value;
@@ -1118,8 +1118,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_anonymous::Op, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_anonymous::Op* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_anonymous::Op>(offset) = *value;
@@ -1130,8 +1130,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_anonymous::SomeProtocolSomeMethodError, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_anonymous::SomeProtocolSomeMethodError* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_anonymous::SomeProtocolSomeMethodError>(offset) = *value;
diff --git a/tools/fidl/fidlgen_cpp/goldens/anonymous_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/anonymous_wire_messaging.h.golden
index 76b4294..066eb8e 100644
--- a/tools/fidl/fidlgen_cpp/goldens/anonymous_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/anonymous_wire_messaging.h.golden
@@ -112,7 +112,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_anonymous::SomeProtocol::SomeMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_anonymous::SomeProtocol::SomeMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 32 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 32 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_anonymous::SomeProtocol::SomeMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -137,7 +137,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_anonymous::SomeProtocol::SomeMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_anonymous::SomeProtocol::SomeMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_anonymous::SomeProtocol::SomeMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -172,7 +172,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_anonymous::SomeProtocol::SomeMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_anonymous::SomeProtocol::SomeMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_anonymous::SomeProtocol::SomeMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/anonymous_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/anonymous_wire_types.h.golden
index 155cdbb..14f87b6 100644
--- a/tools/fidl/fidlgen_cpp/goldens/anonymous_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/anonymous_wire_types.h.golden
@@ -913,8 +913,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_anonymous::wire::Flags, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint16_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint16_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::Flags* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_anonymous::wire::Flags>() = *value;
@@ -925,8 +925,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_anonymous::wire::BitsMember, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::BitsMember* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_anonymous::wire::BitsMember>() = *value;
@@ -937,8 +937,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_anonymous::wire::Op, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::Op* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_anonymous::wire::Op>() = *value;
@@ -949,8 +949,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodError, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::SomeProtocolSomeMethodError* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_anonymous::wire::SomeProtocolSomeMethodError>() = *value;
@@ -984,15 +984,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::OverrideTest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 40;
+  static constexpr size_t kInlineSize = 40;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_anonymous::wire::Op, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::WireOptional<::test_anonymous::wire::Expression>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::WireOptional<::test_anonymous::wire::Expression>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_anonymous::wire::OverrideTest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_anonymous::wire::OverrideTest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_anonymous::wire::OverrideTest));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -1038,15 +1038,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::TableData, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_anonymous::wire::TableData, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_anonymous::wire::TableData* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_anonymous::wire::TableData));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->data, position + 0, recursion_depth);
@@ -1085,15 +1085,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 32;
+  static constexpr size_t kInlineSize = 32;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_anonymous::wire::UnionMember, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_anonymous::wire::TableMember, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_anonymous::wire::SomeProtocolSomeMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_anonymous::wire::SomeProtocolSomeMethodRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_anonymous::wire::SomeProtocolSomeMethodRequest));
     } else {
       internal::WireCodingTraits<::test_anonymous::wire::UnionMember, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::Encode(encoder, &value->union_member, position + 0, recursion_depth);
@@ -1134,15 +1134,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_anonymous::wire::BitsMember, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_anonymous::wire::SomeProtocolSomeMethodResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_anonymous::wire::SomeProtocolSomeMethodResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_anonymous::wire::SomeProtocolSomeMethodResponse));
     } else {
       internal::WireCodingTraits<::test_anonymous::wire::BitsMember, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->bits_member, position + 0, recursion_depth);
@@ -1180,8 +1180,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::FunctionApplication, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::FunctionApplication* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -1201,13 +1201,13 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false, 100>, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false, 100>, IsRecursive>::kInlineSize;
           break;
         case 2:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::WireOptional<::test_anonymous::wire::Expression>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintUnion<true>, false, 5>, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::WireOptional<::test_anonymous::wire::Expression>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintUnion<true>, false, 5>, IsRecursive>::kInlineSize;
           break;
         case 3:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::Flags, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::Flags, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -1242,13 +1242,13 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false, 100>, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false, 100>, IsRecursive>::kInlineSize;
           break;
         case 2:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::WireOptional<::test_anonymous::wire::Expression>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintUnion<true>, false, 5>, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::WireOptional<::test_anonymous::wire::Expression>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintUnion<true>, false, 5>, IsRecursive>::kInlineSize;
           break;
         case 3:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::Flags, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::Flags, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -1291,8 +1291,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::TableMember, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::TableMember* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -1312,7 +1312,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 1:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::test_anonymous::wire::TableData>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 10>, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::test_anonymous::wire::TableData>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 10>, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -1341,7 +1341,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 1:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::test_anonymous::wire::TableData>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 10>, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::test_anonymous::wire::TableData>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 10>, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -1376,8 +1376,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::Expression, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::Expression* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1401,13 +1401,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_anonymous::wire::Expression::Tag::kValue
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_anonymous::wire::Expression::Tag::kBinOp
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::OverrideTest, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::OverrideTest, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3:  // ::test_anonymous::wire::Expression::Tag::kFunctionApplication
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::FunctionApplication, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::FunctionApplication, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1453,13 +1453,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_anonymous::wire::Expression::Tag::kValue:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_anonymous::wire::Expression::Tag::kBinOp:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::OverrideTest, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::OverrideTest, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_anonymous::wire::Expression::Tag::kFunctionApplication:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::FunctionApplication, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::FunctionApplication, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1510,8 +1510,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::UnionMember, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::UnionMember* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1535,7 +1535,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 2:  // ::test_anonymous::wire::UnionMember::Tag::kUnionData
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1575,7 +1575,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_anonymous::wire::UnionMember::Tag::kUnionData:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1620,8 +1620,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_anonymous::wire::SomeProtocolSomeMethodResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1645,10 +1645,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_anonymous::wire::SomeProtocolSomeMethodResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_anonymous::wire::SomeProtocolSomeMethodResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodError, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodError, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1691,10 +1691,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_anonymous::wire::SomeProtocolSomeMethodResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_anonymous::wire::SomeProtocolSomeMethodResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodError, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_anonymous::wire::SomeProtocolSomeMethodError, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/arrays_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/arrays_wire_types.h.golden
index 2458ae1..aa8ab91 100644
--- a/tools/fidl/fidlgen_cpp/goldens/arrays_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/arrays_wire_types.h.golden
@@ -647,15 +647,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_arrays::wire::StructSmallArray, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_arrays::wire::StructSmallArray, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_arrays::wire::StructSmallArray* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_arrays::wire::StructSmallArray));
     } else {
       internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -693,15 +693,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_arrays::wire::StructLargeArray, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 400;
+  static constexpr size_t kInlineSize = 400;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_arrays::wire::StructLargeArray, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_arrays::wire::StructLargeArray* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_arrays::wire::StructLargeArray));
     } else {
       internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -739,8 +739,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_arrays::wire::TableSmallArray, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_arrays::wire::TableSmallArray* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -760,7 +760,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -789,7 +789,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -826,8 +826,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_arrays::wire::TableLargeArray, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_arrays::wire::TableLargeArray* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -847,7 +847,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -876,7 +876,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -911,8 +911,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_arrays::wire::UnionSmallArray, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_arrays::wire::UnionSmallArray* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -936,7 +936,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_arrays::wire::UnionSmallArray::Tag::kA
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -976,7 +976,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_arrays::wire::UnionSmallArray::Tag::kA:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 2>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1021,8 +1021,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_arrays::wire::UnionLargeArray, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_arrays::wire::UnionLargeArray* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1046,7 +1046,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_arrays::wire::UnionLargeArray::Tag::kA
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1086,7 +1086,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_arrays::wire::UnionLargeArray::Tag::kA:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint32_t, 100>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/bindings_denylist_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/bindings_denylist_wire_messaging.h.golden
index d0bda3e..0901b5a 100644
--- a/tools/fidl/fidlgen_cpp/goldens/bindings_denylist_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/bindings_denylist_wire_messaging.h.golden
@@ -625,7 +625,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -654,7 +654,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -689,7 +689,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -726,7 +726,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -755,7 +755,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -790,7 +790,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -827,7 +827,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -856,7 +856,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -891,7 +891,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -928,7 +928,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -957,7 +957,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -992,7 +992,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1029,7 +1029,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1058,7 +1058,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1093,7 +1093,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2526,7 +2526,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::ImportsSameNameContext::Unattributed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::ImportsSameNameContext::Unattributed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_bindingsdenylist::ImportsSameNameContext::Unattributed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2556,7 +2556,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::ImportsSameNameContext::AlwaysAppearsInImportingLibrary>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_bindingsdenylist::ImportsSameNameContext::AlwaysAppearsInImportingLibrary>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_bindingsdenylist::ImportsSameNameContext::AlwaysAppearsInImportingLibrary>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/bindings_denylist_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/bindings_denylist_wire_types.h.golden
index e6accaa..56ac1e9 100644
--- a/tools/fidl/fidlgen_cpp/goldens/bindings_denylist_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/bindings_denylist_wire_types.h.golden
@@ -551,15 +551,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartRequest));
     } else {
       internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -597,15 +597,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->b, position + 0, recursion_depth);
@@ -643,15 +643,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoRequest));
     } else {
       internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -689,15 +689,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->b, position + 0, recursion_depth);
@@ -735,15 +735,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerRequest));
     } else {
       internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -781,15 +781,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->b, position + 0, recursion_depth);
@@ -827,15 +827,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustRequest));
     } else {
       internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -873,15 +873,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->b, position + 0, recursion_depth);
@@ -919,15 +919,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerRequest));
     } else {
       internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -965,15 +965,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->b, position + 0, recursion_depth);
@@ -1011,15 +1011,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::MemberOnlyAppearsInImportingLibrary, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::MemberOnlyAppearsInImportingLibrary, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::MemberOnlyAppearsInImportingLibrary* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::MemberOnlyAppearsInImportingLibrary));
     } else {
       internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -1057,15 +1057,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::OnlyAppearsInImportingLibrary, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_bindingsdenylist::wire::MemberOnlyAppearsInImportingLibrary, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_bindingsdenylist::wire::OnlyAppearsInImportingLibrary, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::OnlyAppearsInImportingLibrary* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_bindingsdenylist::wire::OnlyAppearsInImportingLibrary));
     } else {
       internal::WireCodingTraits<::test_bindingsdenylist::wire::MemberOnlyAppearsInImportingLibrary, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->member_only_appears_in_importing_library, position + 0, recursion_depth);
@@ -1101,8 +1101,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::OnlyLlcpp, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::OnlyLlcpp* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1126,7 +1126,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_bindingsdenylist::wire::OnlyLlcpp::Tag::kX
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1166,7 +1166,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_bindingsdenylist::wire::OnlyLlcpp::Tag::kX:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1211,8 +1211,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1236,10 +1236,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1282,10 +1282,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyDartResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1333,8 +1333,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1358,10 +1358,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1404,10 +1404,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyGoResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1455,8 +1455,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1480,10 +1480,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1526,10 +1526,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyLibfuzzerResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1577,8 +1577,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1602,10 +1602,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1648,10 +1648,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenyRustResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1699,8 +1699,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1724,10 +1724,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1770,10 +1770,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_bindingsdenylist::wire::DenyEachBindingOnlyDenySyzkallerResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/bits_constants_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/bits_constants_natural_types.h.golden
index b81ab7d..f2454d830 100644
--- a/tools/fidl/fidlgen_cpp/goldens/bits_constants_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/bits_constants_natural_types.h.golden
@@ -34,8 +34,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_bitsconstants::BitsType, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_bitsconstants::BitsType* value, size_t offset, size_t recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~131ull)) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/bits_constants_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/bits_constants_wire_types.h.golden
index ddf56a7..d623f8b 100644
--- a/tools/fidl/fidlgen_cpp/goldens/bits_constants_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/bits_constants_wire_types.h.golden
@@ -45,8 +45,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_bitsconstants::wire::BitsType, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bitsconstants::wire::BitsType* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~131ull)) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/bits_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/bits_natural_types.h.golden
index 87e4ee3..a8ecca0 100644
--- a/tools/fidl/fidlgen_cpp/goldens/bits_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/bits_natural_types.h.golden
@@ -26,8 +26,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_bits::MyBits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_bits::MyBits* value, size_t offset, size_t recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~7ull)) {
@@ -44,8 +44,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_bits::StrictBits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint64_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint64_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_bits::StrictBits* value, size_t offset, size_t recursion_depth) {
     if (unlikely(static_cast<uint64_t>(*value) & ~9223372036854775809ull)) {
@@ -62,8 +62,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_bits::FlexibleBits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint64_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint64_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_bits::FlexibleBits* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_bits::FlexibleBits>(offset) = *value;
@@ -74,8 +74,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_bits::EmptyBits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_bits::EmptyBits* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_bits::EmptyBits>(offset) = *value;
diff --git a/tools/fidl/fidlgen_cpp/goldens/bits_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/bits_wire_types.h.golden
index 8079624..3891c2f 100644
--- a/tools/fidl/fidlgen_cpp/goldens/bits_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/bits_wire_types.h.golden
@@ -43,8 +43,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_bits::wire::MyBits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bits::wire::MyBits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~7ull)) {
@@ -62,8 +62,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_bits::wire::StrictBits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint64_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint64_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bits::wire::StrictBits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     if (unlikely(static_cast<uint64_t>(*value) & ~9223372036854775809ull)) {
@@ -81,8 +81,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_bits::wire::FlexibleBits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint64_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint64_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bits::wire::FlexibleBits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_bits::wire::FlexibleBits>() = *value;
@@ -93,8 +93,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_bits::wire::EmptyBits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_bits::wire::EmptyBits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_bits::wire::EmptyBits>() = *value;
diff --git a/tools/fidl/fidlgen_cpp/goldens/byte_and_bytes_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/byte_and_bytes_wire_types.h.golden
index 7f6ec56..b6426f1 100644
--- a/tools/fidl/fidlgen_cpp/goldens/byte_and_bytes_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/byte_and_bytes_wire_types.h.golden
@@ -63,15 +63,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_byteandbytes::wire::ByteAndBytes, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_byteandbytes::wire::ByteAndBytes, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_byteandbytes::wire::ByteAndBytes* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_byteandbytes::wire::ByteAndBytes));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->single_byte, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/consts_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/consts_natural_types.h.golden
index 7bb7b12..416cdcf 100644
--- a/tools/fidl/fidlgen_cpp/goldens/consts_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/consts_natural_types.h.golden
@@ -74,8 +74,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_consts::BitsType, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_consts::BitsType* value, size_t offset, size_t recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~3ull)) {
@@ -93,8 +93,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_consts::EnumType, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(int32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(int32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_consts::EnumType* value, size_t offset, size_t recursion_depth) {
     switch (*value) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/consts_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/consts_wire_types.h.golden
index 33d3669..ebc1a8c 100644
--- a/tools/fidl/fidlgen_cpp/goldens/consts_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/consts_wire_types.h.golden
@@ -87,8 +87,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_consts::wire::BitsType, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_consts::wire::BitsType* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~3ull)) {
@@ -106,8 +106,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_consts::wire::EnumType, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(int32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(int32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_consts::wire::EnumType* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     switch (*value) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/doc_comments_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/doc_comments_natural_types.h.golden
index 81f6f6e..625e515 100644
--- a/tools/fidl/fidlgen_cpp/goldens/doc_comments_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/doc_comments_natural_types.h.golden
@@ -484,8 +484,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_doccomments::MyStrictBits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_doccomments::MyStrictBits* value, size_t offset, size_t recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~3ull)) {
@@ -502,8 +502,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_doccomments::MyFlexibleBits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_doccomments::MyFlexibleBits* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_doccomments::MyFlexibleBits>(offset) = *value;
@@ -515,8 +515,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_doccomments::MyStrictEnum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_doccomments::MyStrictEnum* value, size_t offset, size_t recursion_depth) {
     switch (*value) {
@@ -543,8 +543,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_doccomments::MyFlexibleEnum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_doccomments::MyFlexibleEnum* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_doccomments::MyFlexibleEnum>(offset) = *value;
diff --git a/tools/fidl/fidlgen_cpp/goldens/doc_comments_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/doc_comments_wire_messaging.h.golden
index df4001a..d577cc1 100644
--- a/tools/fidl/fidlgen_cpp/goldens/doc_comments_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/doc_comments_wire_messaging.h.golden
@@ -110,7 +110,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_doccomments::Interface::Method>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_doccomments::Interface::Method>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_doccomments::Interface::Method>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -139,7 +139,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_doccomments::Interface::OnEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_doccomments::Interface::OnEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_doccomments::Interface::OnEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/doc_comments_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/doc_comments_wire_types.h.golden
index a17c1af..ba53fb9 100644
--- a/tools/fidl/fidlgen_cpp/goldens/doc_comments_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/doc_comments_wire_types.h.golden
@@ -406,8 +406,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_doccomments::wire::MyStrictBits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_doccomments::wire::MyStrictBits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~3ull)) {
@@ -425,8 +425,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_doccomments::wire::MyFlexibleBits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_doccomments::wire::MyFlexibleBits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_doccomments::wire::MyFlexibleBits>() = *value;
@@ -437,8 +437,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_doccomments::wire::MyStrictEnum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_doccomments::wire::MyStrictEnum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     switch (*value) {
@@ -466,8 +466,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_doccomments::wire::MyFlexibleEnum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_doccomments::wire::MyFlexibleEnum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_doccomments::wire::MyFlexibleEnum>() = *value;
@@ -499,15 +499,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_doccomments::wire::Struct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_doccomments::wire::Struct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_doccomments::wire::Struct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_doccomments::wire::Struct));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->field, position + 0, recursion_depth);
@@ -545,8 +545,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_doccomments::wire::Table, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_doccomments::wire::Table* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -566,7 +566,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -595,7 +595,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -630,8 +630,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_doccomments::wire::StrictUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_doccomments::wire::StrictUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -655,7 +655,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_doccomments::wire::StrictUnion::Tag::kField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -695,7 +695,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_doccomments::wire::StrictUnion::Tag::kField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -740,8 +740,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_doccomments::wire::FlexibleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_doccomments::wire::FlexibleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -765,7 +765,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_doccomments::wire::FlexibleUnion::Tag::kField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -805,7 +805,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_doccomments::wire::FlexibleUnion::Tag::kField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/driver_handle_driver_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/driver_handle_driver_wire_messaging.h.golden
index ed30584..b2309a2 100644
--- a/tools/fidl/fidlgen_cpp/goldens/driver_handle_driver_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/driver_handle_driver_wire_messaging.h.golden
@@ -208,7 +208,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_driverhandle::HandlesInProtocol::SendHandles>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_driverhandle::HandlesInProtocol::SendHandles>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_driverhandle::HandlesInProtocol::SendHandles>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/driver_handle_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/driver_handle_wire_types.h.golden
index 9412691..24f1668 100644
--- a/tools/fidl/fidlgen_cpp/goldens/driver_handle_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/driver_handle_wire_types.h.golden
@@ -363,15 +363,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_driverhandle::wire::ClientEndWrapper, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fdf::ClientEnd<::test_driverhandle::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_driverhandle::wire::ClientEndWrapper, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_driverhandle::wire::ClientEndWrapper* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_driverhandle::wire::ClientEndWrapper));
     } else {
       internal::WireCodingTraits<::fdf::ClientEnd<::test_driverhandle::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->value, position + 0, recursion_depth);
@@ -415,15 +415,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_driverhandle::wire::ServerEndWrapper, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fdf::ServerEnd<::test_driverhandle::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_driverhandle::wire::ServerEndWrapper, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_driverhandle::wire::ServerEndWrapper* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_driverhandle::wire::ServerEndWrapper));
     } else {
       internal::WireCodingTraits<::fdf::ServerEnd<::test_driverhandle::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->value, position + 0, recursion_depth);
@@ -467,15 +467,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_driverhandle::wire::HandlesInProtocolSendHandlesRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_driverhandle::wire::T, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_driverhandle::wire::HandlesInProtocolSendHandlesRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_driverhandle::wire::HandlesInProtocolSendHandlesRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_driverhandle::wire::HandlesInProtocolSendHandlesRequest));
     } else {
       internal::WireCodingTraits<::test_driverhandle::wire::T, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->t, position + 0, recursion_depth);
@@ -519,8 +519,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_driverhandle::wire::T, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_driverhandle::wire::T* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -540,10 +540,10 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::zx::event, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_EVENT, 0x80000000, false>, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::zx::event, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_EVENT, 0x80000000, false>, IsRecursive>::kInlineSize;
           break;
         case 1:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::fdf::ClientEnd<::test_driverhandle::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::fdf::ClientEnd<::test_driverhandle::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -575,10 +575,10 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::zx::event, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_EVENT, 0x80000000, false>, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::zx::event, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_EVENT, 0x80000000, false>, IsRecursive>::kInlineSize;
           break;
         case 1:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::fdf::ClientEnd<::test_driverhandle::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::fdf::ClientEnd<::test_driverhandle::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
diff --git a/tools/fidl/fidlgen_cpp/goldens/driver_one_way_driver_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/driver_one_way_driver_wire_messaging.h.golden
index d6863c1..3de262c 100644
--- a/tools/fidl/fidlgen_cpp/goldens/driver_one_way_driver_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/driver_one_way_driver_wire_messaging.h.golden
@@ -100,7 +100,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_driveroneway::OneWay::Send>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/driver_one_way_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/driver_one_way_wire_types.h.golden
index d0e74ac..752a05a 100644
--- a/tools/fidl/fidlgen_cpp/goldens/driver_one_way_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/driver_one_way_wire_types.h.golden
@@ -71,15 +71,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_driveroneway::wire::Payload, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_driveroneway::wire::Payload, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_driveroneway::wire::Payload* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_driveroneway::wire::Payload));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->value, position + 0, recursion_depth);
@@ -117,15 +117,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_driveroneway::wire::OneWaySendRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_driveroneway::wire::Payload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_driveroneway::wire::OneWaySendRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_driveroneway::wire::OneWaySendRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_driveroneway::wire::OneWaySendRequest));
     } else {
       internal::WireCodingTraits<::test_driveroneway::wire::Payload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->payload, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/driver_two_way_driver_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/driver_two_way_driver_wire_messaging.h.golden
index bdf1c5f..c6c5a7b 100644
--- a/tools/fidl/fidlgen_cpp/goldens/driver_two_way_driver_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/driver_two_way_driver_wire_messaging.h.golden
@@ -111,7 +111,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_drivertwoway::TwoWay::Add>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -137,7 +137,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_drivertwoway::TwoWay::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_drivertwoway::TwoWay::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 2;
+  static constexpr size_t kInlineSize = 2;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_drivertwoway::TwoWay::Add>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -172,7 +172,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_drivertwoway::TwoWay::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_drivertwoway::TwoWay::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 2 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 2 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_drivertwoway::TwoWay::Add>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/driver_two_way_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/driver_two_way_wire_types.h.golden
index 4bd5622e..8ecbe1b 100644
--- a/tools/fidl/fidlgen_cpp/goldens/driver_two_way_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/driver_two_way_wire_types.h.golden
@@ -74,15 +74,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_drivertwoway::wire::TwoWayAddRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_drivertwoway::wire::TwoWayAddRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_drivertwoway::wire::TwoWayAddRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_drivertwoway::wire::TwoWayAddRequest));
     } else {
       internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->addend1, position + 0, recursion_depth);
@@ -123,15 +123,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_drivertwoway::wire::TwoWayAddResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 2;
+  static constexpr size_t kInlineSize = 2;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_drivertwoway::wire::TwoWayAddResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_drivertwoway::wire::TwoWayAddResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_drivertwoway::wire::TwoWayAddResponse));
     } else {
       internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->sum, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/empty_struct_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/empty_struct_wire_messaging.h.golden
index 92d45c0..ad4b171 100644
--- a/tools/fidl/fidlgen_cpp/goldens/empty_struct_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/empty_struct_wire_messaging.h.golden
@@ -142,7 +142,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_emptystruct::EmptyProtocol::Send>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_emptystruct::EmptyProtocol::Send>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_emptystruct::EmptyProtocol::Send>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -182,7 +182,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_emptystruct::EmptyProtocol::Receive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_emptystruct::EmptyProtocol::Receive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_emptystruct::EmptyProtocol::Receive>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -222,7 +222,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_emptystruct::EmptyProtocol::SendAndReceive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_emptystruct::EmptyProtocol::SendAndReceive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_emptystruct::EmptyProtocol::SendAndReceive>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -248,7 +248,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_emptystruct::EmptyProtocol::SendAndReceive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_emptystruct::EmptyProtocol::SendAndReceive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_emptystruct::EmptyProtocol::SendAndReceive>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -283,7 +283,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_emptystruct::EmptyProtocol::SendAndReceive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_emptystruct::EmptyProtocol::SendAndReceive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_emptystruct::EmptyProtocol::SendAndReceive>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/empty_struct_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/empty_struct_wire_types.h.golden
index 1005370..4e13f40 100644
--- a/tools/fidl/fidlgen_cpp/goldens/empty_struct_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/empty_struct_wire_types.h.golden
@@ -88,15 +88,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_emptystruct::wire::Empty, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_emptystruct::wire::Empty, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_emptystruct::wire::Empty* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_emptystruct::wire::Empty));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -137,15 +137,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_emptystruct::wire::EmptyProtocolSendRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_emptystruct::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_emptystruct::wire::EmptyProtocolSendRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_emptystruct::wire::EmptyProtocolSendRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_emptystruct::wire::EmptyProtocolSendRequest));
     } else {
       internal::WireCodingTraits<::test_emptystruct::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->e, position + 0, recursion_depth);
@@ -183,15 +183,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_emptystruct::wire::EmptyProtocolReceiveRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_emptystruct::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_emptystruct::wire::EmptyProtocolReceiveRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_emptystruct::wire::EmptyProtocolReceiveRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_emptystruct::wire::EmptyProtocolReceiveRequest));
     } else {
       internal::WireCodingTraits<::test_emptystruct::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->e, position + 0, recursion_depth);
@@ -229,15 +229,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_emptystruct::wire::EmptyProtocolSendAndReceiveRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_emptystruct::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_emptystruct::wire::EmptyProtocolSendAndReceiveRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_emptystruct::wire::EmptyProtocolSendAndReceiveRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_emptystruct::wire::EmptyProtocolSendAndReceiveRequest));
     } else {
       internal::WireCodingTraits<::test_emptystruct::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->e, position + 0, recursion_depth);
@@ -275,15 +275,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_emptystruct::wire::EmptyProtocolSendAndReceiveResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_emptystruct::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_emptystruct::wire::EmptyProtocolSendAndReceiveResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_emptystruct::wire::EmptyProtocolSendAndReceiveResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_emptystruct::wire::EmptyProtocolSendAndReceiveResponse));
     } else {
       internal::WireCodingTraits<::test_emptystruct::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->e, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/encapsulated_structs_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/encapsulated_structs_wire_types.h.golden
index 41f4557..bfa88ff 100644
--- a/tools/fidl/fidlgen_cpp/goldens/encapsulated_structs_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/encapsulated_structs_wire_types.h.golden
@@ -119,15 +119,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_encapsulatedstructs::wire::Int8Int32, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_encapsulatedstructs::wire::Int8Int32, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_encapsulatedstructs::wire::Int8Int32* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_encapsulatedstructs::wire::Int8Int32));
     } else {
       internal::WireZeroPadding<uint32_t>(encoder, position + 0);
@@ -171,15 +171,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_encapsulatedstructs::wire::Int16Int8, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_encapsulatedstructs::wire::Int16Int8, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_encapsulatedstructs::wire::Int16Int8* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_encapsulatedstructs::wire::Int16Int8));
     } else {
       internal::WireZeroPadding<uint16_t>(encoder, position + 2);
@@ -222,15 +222,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_encapsulatedstructs::wire::ArrayInt16Int8, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 12;
+  static constexpr size_t kInlineSize = 12;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_encapsulatedstructs::wire::Int16Int8, 3>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_encapsulatedstructs::wire::ArrayInt16Int8, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_encapsulatedstructs::wire::ArrayInt16Int8* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_encapsulatedstructs::wire::ArrayInt16Int8));
     } else {
       internal::WireCodingTraits<::fidl::Array<::test_encapsulatedstructs::wire::Int16Int8, 3>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->arr, position + 0, recursion_depth);
@@ -270,15 +270,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_encapsulatedstructs::wire::StructPaddingTestStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 24;
+  static constexpr size_t kInlineSize = 24;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_encapsulatedstructs::wire::Int16Int8, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_encapsulatedstructs::wire::Int8Int32, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_encapsulatedstructs::wire::ArrayInt16Int8, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_encapsulatedstructs::wire::StructPaddingTestStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_encapsulatedstructs::wire::StructPaddingTestStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_encapsulatedstructs::wire::StructPaddingTestStruct));
     } else {
       internal::WireCodingTraits<::test_encapsulatedstructs::wire::Int16Int8, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->trailing, position + 0, recursion_depth);
@@ -327,15 +327,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_encapsulatedstructs::wire::NonInlineStructTestStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ObjectView<::test_encapsulatedstructs::wire::Int16Int8>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_encapsulatedstructs::wire::NonInlineStructTestStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_encapsulatedstructs::wire::NonInlineStructTestStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_encapsulatedstructs::wire::NonInlineStructTestStruct));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 8);
@@ -385,15 +385,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_encapsulatedstructs::wire::TopLevelStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 40;
+  static constexpr size_t kInlineSize = 40;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_encapsulatedstructs::wire::StructPaddingTestStruct, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_encapsulatedstructs::wire::NonInlineStructTestStruct, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_encapsulatedstructs::wire::TopLevelStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_encapsulatedstructs::wire::TopLevelStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_encapsulatedstructs::wire::TopLevelStruct));
     } else {
       internal::WireCodingTraits<::test_encapsulatedstructs::wire::StructPaddingTestStruct, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/enum_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/enum_natural_types.h.golden
index 17e3919..2a8de28 100644
--- a/tools/fidl/fidlgen_cpp/goldens/enum_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/enum_natural_types.h.golden
@@ -26,8 +26,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_enum::MyStrictEnum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_enum::MyStrictEnum* value, size_t offset, size_t recursion_depth) {
     switch (*value) {
@@ -54,8 +54,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_enum::MyFlexibleEnum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_enum::MyFlexibleEnum* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_enum::MyFlexibleEnum>(offset) = *value;
@@ -66,8 +66,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_enum::MyFlexibleEnumWithCustomUnknown, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_enum::MyFlexibleEnumWithCustomUnknown* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_enum::MyFlexibleEnumWithCustomUnknown>(offset) = *value;
@@ -78,8 +78,8 @@
 };
 template <>
 struct internal::NaturalCodingTraits<::test_enum::MyEmptyFlexibleEnum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_enum::MyEmptyFlexibleEnum* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_enum::MyEmptyFlexibleEnum>(offset) = *value;
diff --git a/tools/fidl/fidlgen_cpp/goldens/enum_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/enum_wire_types.h.golden
index 1e71d84..a2d31240 100644
--- a/tools/fidl/fidlgen_cpp/goldens/enum_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/enum_wire_types.h.golden
@@ -43,8 +43,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_enum::wire::MyStrictEnum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_enum::wire::MyStrictEnum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     switch (*value) {
@@ -72,8 +72,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_enum::wire::MyFlexibleEnum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_enum::wire::MyFlexibleEnum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_enum::wire::MyFlexibleEnum>() = *value;
@@ -84,8 +84,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_enum::wire::MyFlexibleEnumWithCustomUnknown, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_enum::wire::MyFlexibleEnumWithCustomUnknown* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_enum::wire::MyFlexibleEnumWithCustomUnknown>() = *value;
@@ -96,8 +96,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_enum::wire::MyEmptyFlexibleEnum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_enum::wire::MyEmptyFlexibleEnum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_enum::wire::MyEmptyFlexibleEnum>() = *value;
diff --git a/tools/fidl/fidlgen_cpp/goldens/error_syntax_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/error_syntax_wire_messaging.h.golden
index 654cac0..330b1694 100644
--- a/tools/fidl/fidlgen_cpp/goldens/error_syntax_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/error_syntax_wire_messaging.h.golden
@@ -141,7 +141,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -166,7 +166,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -201,7 +201,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::ComposedCallWhichMayFail>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -238,7 +238,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -263,7 +263,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -298,7 +298,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_errorsyntax::ExampleUseOfErrorSyntax::CallWhichMayFail>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/error_syntax_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/error_syntax_wire_types.h.golden
index 1460e67..494ecd07 100644
--- a/tools/fidl/fidlgen_cpp/goldens/error_syntax_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/error_syntax_wire_types.h.golden
@@ -150,15 +150,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailRequest));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->s, position + 0, recursion_depth);
@@ -196,15 +196,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResponse));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->value, position + 0, recursion_depth);
@@ -240,8 +240,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -265,10 +265,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -311,10 +311,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_errorsyntax::wire::ExampleUseOfErrorSyntaxCallWhichMayFailResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/error_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/error_wire_messaging.h.golden
index 7dcf050..bf5bdea 100644
--- a/tools/fidl/fidlgen_cpp/goldens/error_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/error_wire_messaging.h.golden
@@ -112,7 +112,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_error::Example::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_error::Example::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_error::Example::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -137,7 +137,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_error::Example::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_error::Example::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_error::Example::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -172,7 +172,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_error::Example::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_error::Example::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_error::Example::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/error_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/error_wire_types.h.golden
index 52fa515..51d835fc 100644
--- a/tools/fidl/fidlgen_cpp/goldens/error_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/error_wire_types.h.golden
@@ -149,15 +149,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_error::wire::ExampleFooRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_error::wire::ExampleFooRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_error::wire::ExampleFooRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_error::wire::ExampleFooRequest));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->s, position + 0, recursion_depth);
@@ -195,15 +195,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_error::wire::ExampleFooResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_error::wire::ExampleFooResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_error::wire::ExampleFooResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_error::wire::ExampleFooResponse));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->y, position + 0, recursion_depth);
@@ -239,8 +239,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_error::wire::ExampleFooResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_error::wire::ExampleFooResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -264,10 +264,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_error::wire::ExampleFooResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_error::wire::ExampleFooResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_error::wire::ExampleFooResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_error::wire::ExampleFooResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -310,10 +310,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_error::wire::ExampleFooResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_error::wire::ExampleFooResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_error::wire::ExampleFooResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_error::wire::ExampleFooResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/escaping_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/escaping_wire_types.h.golden
index 250c26d..179b57c 100644
--- a/tools/fidl/fidlgen_cpp/goldens/escaping_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/escaping_wire_types.h.golden
@@ -82,15 +82,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_escaping::wire::DocCommentWithQuotes, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_escaping::wire::DocCommentWithQuotes, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_escaping::wire::DocCommentWithQuotes* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_escaping::wire::DocCommentWithQuotes));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/foreign_type_in_response_used_through_compose_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/foreign_type_in_response_used_through_compose_wire_messaging.h.golden
index 820f2d0..1269db3 100644
--- a/tools/fidl/fidlgen_cpp/goldens/foreign_type_in_response_used_through_compose_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/foreign_type_in_response_used_through_compose_wire_messaging.h.golden
@@ -107,7 +107,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -129,7 +129,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -164,7 +164,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_foreigntypeinresponseusedthroughcompose::Top::GetFoo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/handles_in_types_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/handles_in_types_natural_types.h.golden
index db4bfb1..b26c87e 100644
--- a/tools/fidl/fidlgen_cpp/goldens/handles_in_types_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/handles_in_types_natural_types.h.golden
@@ -675,8 +675,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_handlesintypes::ObjType, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_handlesintypes::ObjType* value, size_t offset, size_t recursion_depth) {
     switch (*value) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/handles_in_types_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/handles_in_types_wire_types.h.golden
index f0fd937..8c48eb6 100644
--- a/tools/fidl/fidlgen_cpp/goldens/handles_in_types_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/handles_in_types_wire_types.h.golden
@@ -551,8 +551,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_handlesintypes::wire::ObjType, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_handlesintypes::wire::ObjType* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     switch (*value) {
@@ -610,15 +610,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_handlesintypes::wire::HandlesInTypes, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 96;
+  static constexpr size_t kInlineSize = 96;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::zx::vmo>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::zx::vmo, 5>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::Array<::zx::vmo, 5>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_handlesintypes::wire::TableWithHandle, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_handlesintypes::wire::UnionWithHandle, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_handlesintypes::wire::HandlesInTypes, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_handlesintypes::wire::HandlesInTypes* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_handlesintypes::wire::HandlesInTypes));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -681,15 +681,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_handlesintypes::wire::EmptyResourceStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_handlesintypes::wire::EmptyResourceStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_handlesintypes::wire::EmptyResourceStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_handlesintypes::wire::EmptyResourceStruct));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -736,8 +736,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_handlesintypes::wire::TableWithHandle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_handlesintypes::wire::TableWithHandle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -757,7 +757,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -786,7 +786,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -829,8 +829,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_handlesintypes::wire::EmptyResourceTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_handlesintypes::wire::EmptyResourceTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -908,8 +908,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_handlesintypes::wire::UnionWithHandle, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_handlesintypes::wire::UnionWithHandle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -933,7 +933,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_handlesintypes::wire::UnionWithHandle::Tag::kH
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -973,7 +973,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_handlesintypes::wire::UnionWithHandle::Tag::kH:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1024,8 +1024,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_handlesintypes::wire::EmptyResourceUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_handlesintypes::wire::EmptyResourceUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
diff --git a/tools/fidl/fidlgen_cpp/goldens/handles_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/handles_wire_types.h.golden
index bb47903..b0e390b 100644
--- a/tools/fidl/fidlgen_cpp/goldens/handles_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/handles_wire_types.h.golden
@@ -236,15 +236,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_handles::wire::Handles, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 136;
+  static constexpr size_t kInlineSize = 136;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::bti, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_BTI, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::channel, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::clock, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CLOCK, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::debuglog, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_DEBUGLOG, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::event, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_EVENT, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::eventpair, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_EVENTPAIR, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::exception, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_EXCEPTION, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::fifo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_FIFO, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::guest, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_GUEST, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::interrupt, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_INTERRUPT, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::iommu, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_IOMMU, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::job, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_JOB, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::msi, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_MSI, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::pager, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_PAGER, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::pmt, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_PMT, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::port, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_PORT, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::process, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_PROCESS, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::profile, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_PROFILE, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::resource, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_RESOURCE, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::stream, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_STREAM, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::suspend_token, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SUSPEND_TOKEN, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::thread, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_THREAD, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::timer, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_TIMER, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::vcpu, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VCPU, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::vmar, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMAR, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x5, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x1, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_handles::SomeProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_handles::SomeProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_handles::wire::Handles, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_handles::wire::Handles* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_handles::wire::Handles));
     } else {
       internal::WireCodingTraits<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>::Encode(encoder, &value->plain_handle, position + 0, recursion_depth);
@@ -389,15 +389,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_handles::wire::FdfHandles, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 12;
+  static constexpr size_t kInlineSize = 12;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fdf::Channel, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fdf::ClientEnd<::test_handles::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fdf::ServerEnd<::test_handles::DriverProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_handles::wire::FdfHandles, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_handles::wire::FdfHandles* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_handles::wire::FdfHandles));
     } else {
       internal::WireCodingTraits<::fdf::Channel, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, 0x80000000, false>, IsRecursive>::Encode(encoder, &value->fdf_channel_handle, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/imported_const_values_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/imported_const_values_wire_types.h.golden
index f251447..4277cc6 100644
--- a/tools/fidl/fidlgen_cpp/goldens/imported_const_values_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/imported_const_values_wire_types.h.golden
@@ -68,15 +68,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_importedconstvalues::wire::MyStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_importedconstvalues::wire::MyStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_importedconstvalues::wire::MyStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_importedconstvalues::wire::MyStruct));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/inheritance_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/inheritance_wire_messaging.h.golden
index dbded12..55906fa 100644
--- a/tools/fidl/fidlgen_cpp/goldens/inheritance_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/inheritance_wire_messaging.h.golden
@@ -113,7 +113,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_inheritance::Super::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_inheritance::Super::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_inheritance::Super::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -139,7 +139,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_inheritance::Super::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_inheritance::Super::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_inheritance::Super::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -174,7 +174,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_inheritance::Super::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_inheritance::Super::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_inheritance::Super::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -577,7 +577,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_inheritance::Sub::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_inheritance::Sub::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_inheritance::Sub::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -603,7 +603,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_inheritance::Sub::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_inheritance::Sub::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_inheritance::Sub::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -638,7 +638,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_inheritance::Sub::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_inheritance::Sub::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_inheritance::Sub::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/inheritance_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/inheritance_wire_types.h.golden
index 4a02565..c034b4f 100644
--- a/tools/fidl/fidlgen_cpp/goldens/inheritance_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/inheritance_wire_types.h.golden
@@ -70,15 +70,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_inheritance::wire::SuperFooRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_inheritance::wire::SuperFooRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_inheritance::wire::SuperFooRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_inheritance::wire::SuperFooRequest));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->s, position + 0, recursion_depth);
@@ -116,15 +116,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_inheritance::wire::SuperFooResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_inheritance::wire::SuperFooResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_inheritance::wire::SuperFooResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_inheritance::wire::SuperFooResponse));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->y, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/inheritance_with_recursive_decl_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/inheritance_with_recursive_decl_wire_messaging.h.golden
index 50ccbcd..ba99198 100644
--- a/tools/fidl/fidlgen_cpp/goldens/inheritance_with_recursive_decl_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/inheritance_with_recursive_decl_wire_messaging.h.golden
@@ -105,7 +105,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Parent::First>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Parent::First>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Parent::First>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -409,7 +409,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Child::First>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Child::First>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Child::First>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -450,7 +450,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Child::Second>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Child::Second>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_inheritancewithrecursivedecl::Child::Second>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/inheritance_with_recursive_decl_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/inheritance_with_recursive_decl_wire_types.h.golden
index 216bafe..8e12b8f4 100644
--- a/tools/fidl/fidlgen_cpp/goldens/inheritance_with_recursive_decl_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/inheritance_with_recursive_decl_wire_types.h.golden
@@ -86,15 +86,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_inheritancewithrecursivedecl::wire::ParentFirstRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_inheritancewithrecursivedecl::Parent>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_inheritancewithrecursivedecl::wire::ParentFirstRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_inheritancewithrecursivedecl::wire::ParentFirstRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_inheritancewithrecursivedecl::wire::ParentFirstRequest));
     } else {
       internal::WireCodingTraits<::fidl::ServerEnd<::test_inheritancewithrecursivedecl::Parent>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->request, position + 0, recursion_depth);
@@ -138,15 +138,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_inheritancewithrecursivedecl::wire::ChildSecondRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_inheritancewithrecursivedecl::Parent>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_inheritancewithrecursivedecl::wire::ChildSecondRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_inheritancewithrecursivedecl::wire::ChildSecondRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_inheritancewithrecursivedecl::wire::ChildSecondRequest));
     } else {
       internal::WireCodingTraits<::fidl::ServerEnd<::test_inheritancewithrecursivedecl::Parent>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->request, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/nullable_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/nullable_wire_messaging.h.golden
index 9ca282d..9cf446c 100644
--- a/tools/fidl/fidlgen_cpp/goldens/nullable_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/nullable_wire_messaging.h.golden
@@ -111,7 +111,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_nullable::SimpleProtocol::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_nullable::SimpleProtocol::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_nullable::SimpleProtocol::Add>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -137,7 +137,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_nullable::SimpleProtocol::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_nullable::SimpleProtocol::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_nullable::SimpleProtocol::Add>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -172,7 +172,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_nullable::SimpleProtocol::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_nullable::SimpleProtocol::Add>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_nullable::SimpleProtocol::Add>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/nullable_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/nullable_wire_types.h.golden
index f0437ab..c5d6469 100644
--- a/tools/fidl/fidlgen_cpp/goldens/nullable_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/nullable_wire_types.h.golden
@@ -210,15 +210,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::StructWithNullableString, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::StructWithNullableString, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::StructWithNullableString* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::StructWithNullableString));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<true>, IsRecursive>::Encode(encoder, &value->val, position + 0, recursion_depth);
@@ -256,15 +256,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::StructWithNullableVector, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<int32_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::StructWithNullableVector, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::StructWithNullableVector* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::StructWithNullableVector));
     } else {
       internal::WireCodingTraits<::fidl::VectorView<int32_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, true>, IsRecursive>::Encode(encoder, &value->val, position + 0, recursion_depth);
@@ -306,15 +306,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::StructWithNullableHandle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::StructWithNullableHandle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::StructWithNullableHandle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::StructWithNullableHandle));
     } else {
       internal::WireCodingTraits<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, true>, IsRecursive>::Encode(encoder, &value->val, position + 0, recursion_depth);
@@ -355,15 +355,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::SimpleProtocolAddRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::SimpleProtocolAddRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::SimpleProtocolAddRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::SimpleProtocolAddRequest));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -404,15 +404,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::SimpleProtocolAddResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::SimpleProtocolAddResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::SimpleProtocolAddResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::SimpleProtocolAddResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->sum, position + 0, recursion_depth);
@@ -454,15 +454,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::StructWithNullableProtocol, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_nullable::SimpleProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::StructWithNullableProtocol, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::StructWithNullableProtocol* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::StructWithNullableProtocol));
     } else {
       internal::WireCodingTraits<::fidl::ClientEnd<::test_nullable::SimpleProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>::Encode(encoder, &value->val, position + 0, recursion_depth);
@@ -506,15 +506,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::StructWithNullableRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_nullable::SimpleProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::StructWithNullableRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::StructWithNullableRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::StructWithNullableRequest));
     } else {
       internal::WireCodingTraits<::fidl::ServerEnd<::test_nullable::SimpleProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>::Encode(encoder, &value->val, position + 0, recursion_depth);
@@ -554,15 +554,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::Int32Wrapper, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::Int32Wrapper, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::Int32Wrapper* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::Int32Wrapper));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->val, position + 0, recursion_depth);
@@ -600,15 +600,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::StructWithNullableStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ObjectView<::test_nullable::wire::Int32Wrapper>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::StructWithNullableStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::StructWithNullableStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::StructWithNullableStruct));
     } else {
       internal::WireCodingTraits<::fidl::ObjectView<::test_nullable::wire::Int32Wrapper>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->val, position + 0, recursion_depth);
@@ -646,15 +646,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::StructWithNullableUnion, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::WireOptional<::test_nullable::wire::SimpleUnion>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_nullable::wire::StructWithNullableUnion, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_nullable::wire::StructWithNullableUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_nullable::wire::StructWithNullableUnion));
     } else {
       internal::WireCodingTraits<::fidl::WireOptional<::test_nullable::wire::SimpleUnion>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>::Encode(encoder, &value->val, position + 0, recursion_depth);
@@ -690,8 +690,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_nullable::wire::SimpleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_nullable::wire::SimpleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -715,10 +715,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_nullable::wire::SimpleUnion::Tag::kA
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_nullable::wire::SimpleUnion::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -761,10 +761,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_nullable::wire::SimpleUnion::Tag::kA:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_nullable::wire::SimpleUnion::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/padding_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/padding_wire_types.h.golden
index 69a87ca..a05d254 100644
--- a/tools/fidl/fidlgen_cpp/goldens/padding_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/padding_wire_types.h.golden
@@ -196,15 +196,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding1ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding1ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding1ByteEnd* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding1ByteEnd));
     } else {
       internal::WireZeroPadding<uint16_t>(encoder, position + 2);
@@ -248,15 +248,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding2ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding2ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding2ByteEnd* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding2ByteEnd));
     } else {
       internal::WireZeroPadding<uint32_t>(encoder, position + 4);
@@ -300,15 +300,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding3ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding3ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding3ByteEnd* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding3ByteEnd));
     } else {
       internal::WireZeroPadding<uint32_t>(encoder, position + 4);
@@ -352,15 +352,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding4ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding4ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding4ByteEnd* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding4ByteEnd));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 8);
@@ -405,15 +405,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding5ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding5ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding5ByteEnd* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding5ByteEnd));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 8);
@@ -460,15 +460,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding6ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding6ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding6ByteEnd* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding6ByteEnd));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 8);
@@ -512,15 +512,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding7ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding7ByteEnd, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding7ByteEnd* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding7ByteEnd));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 8);
@@ -564,15 +564,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding1ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding1ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding1ByteMiddle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding1ByteMiddle));
     } else {
       internal::WireZeroPadding<uint16_t>(encoder, position + 0);
@@ -616,15 +616,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding2ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding2ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding2ByteMiddle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding2ByteMiddle));
     } else {
       internal::WireZeroPadding<uint32_t>(encoder, position + 0);
@@ -668,15 +668,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding3ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding3ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding3ByteMiddle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding3ByteMiddle));
     } else {
       internal::WireZeroPadding<uint32_t>(encoder, position + 0);
@@ -720,15 +720,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding4ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding4ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding4ByteMiddle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding4ByteMiddle));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -773,15 +773,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding5ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding5ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding5ByteMiddle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding5ByteMiddle));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -828,15 +828,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding6ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding6ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding6ByteMiddle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding6ByteMiddle));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -880,15 +880,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding7ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding7ByteMiddle, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding7ByteMiddle* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding7ByteMiddle));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -934,15 +934,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding4ByteAlignmentLength12, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 12;
+  static constexpr size_t kInlineSize = 12;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding4ByteAlignmentLength12, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding4ByteAlignmentLength12* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding4ByteAlignmentLength12));
     } else {
       internal::WireZeroPadding<uint32_t>(encoder, position + 4);
@@ -995,15 +995,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_padding::wire::Padding2ByteAlignmentLength6, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 6;
+  static constexpr size_t kInlineSize = 6;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_padding::wire::Padding2ByteAlignmentLength6, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_padding::wire::Padding2ByteAlignmentLength6* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_padding::wire::Padding2ByteAlignmentLength6));
     } else {
       internal::WireZeroPadding<uint16_t>(encoder, position + 0);
diff --git a/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_natural_types.h.golden
index 289bdcc..9964ffe 100644
--- a/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_natural_types.h.golden
@@ -418,8 +418,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_placementofattributes::ExampleBits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_placementofattributes::ExampleBits* value, size_t offset, size_t recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~1ull)) {
@@ -437,8 +437,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_placementofattributes::ExampleEnum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_placementofattributes::ExampleEnum* value, size_t offset, size_t recursion_depth) {
     switch (*value) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_wire_messaging.h.golden
index 251f6ac..245c1ce 100644
--- a/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_wire_messaging.h.golden
@@ -101,7 +101,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_placementofattributes::ExampleProtocol::Method>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_placementofattributes::ExampleProtocol::Method>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 1 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_placementofattributes::ExampleProtocol::Method>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_wire_types.h.golden
index 0f2b764..e70e7e7 100644
--- a/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/placement_of_attributes_wire_types.h.golden
@@ -314,8 +314,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_placementofattributes::wire::ExampleBits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_placementofattributes::wire::ExampleBits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     if (unlikely(static_cast<uint32_t>(*value) & ~1ull)) {
@@ -333,8 +333,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_placementofattributes::wire::ExampleEnum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_placementofattributes::wire::ExampleEnum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     switch (*value) {
@@ -381,15 +381,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_placementofattributes::wire::ExampleProtocolMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_exampleusing::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_placementofattributes::wire::ExampleProtocolMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_placementofattributes::wire::ExampleProtocolMethodRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_placementofattributes::wire::ExampleProtocolMethodRequest));
     } else {
       internal::WireCodingTraits<::test_exampleusing::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->arg, position + 0, recursion_depth);
@@ -427,15 +427,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_placementofattributes::wire::ExampleStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_placementofattributes::wire::ExampleStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_placementofattributes::wire::ExampleStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_placementofattributes::wire::ExampleStruct));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->member, position + 0, recursion_depth);
@@ -473,8 +473,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_placementofattributes::wire::ExampleTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_placementofattributes::wire::ExampleTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -494,7 +494,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -523,7 +523,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -558,8 +558,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_placementofattributes::wire::ExampleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_placementofattributes::wire::ExampleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -583,7 +583,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_placementofattributes::wire::ExampleUnion::Tag::kVariant
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -623,7 +623,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_placementofattributes::wire::ExampleUnion::Tag::kVariant:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_same_library_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_same_library_wire_messaging.h.golden
index 835e273..82fb04d 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_same_library_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_same_library_wire_messaging.h.golden
@@ -318,7 +318,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::OneWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::OneWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::OneWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -358,7 +358,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -387,7 +387,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -422,7 +422,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -459,7 +459,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -488,7 +488,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -523,7 +523,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -562,7 +562,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::ComposedProtocol::OnAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::ComposedProtocol::OnAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::ComposedProtocol::OnAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -602,7 +602,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::OneWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::OneWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::OneWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -642,7 +642,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -671,7 +671,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -706,7 +706,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -743,7 +743,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -772,7 +772,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -807,7 +807,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::ComposedProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -846,7 +846,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::ComposedProtocol::OnNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::ComposedProtocol::OnNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::ComposedProtocol::OnNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2547,7 +2547,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2587,7 +2587,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2616,7 +2616,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2651,7 +2651,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2688,7 +2688,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2717,7 +2717,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2752,7 +2752,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2791,7 +2791,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2831,7 +2831,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2871,7 +2871,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2900,7 +2900,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2935,7 +2935,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2972,7 +2972,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3001,7 +3001,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3036,7 +3036,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3075,7 +3075,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3115,7 +3115,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3155,7 +3155,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3184,7 +3184,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3219,7 +3219,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3256,7 +3256,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3285,7 +3285,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3320,7 +3320,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3359,7 +3359,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3399,7 +3399,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::OneWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3439,7 +3439,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3468,7 +3468,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3503,7 +3503,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3540,7 +3540,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3569,7 +3569,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3604,7 +3604,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayoutssamelibrary::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3643,7 +3643,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayoutssamelibrary::MainProtocol::OnAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_same_library_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_same_library_wire_types.h.golden
index 4100647..73884bf 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_same_library_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_same_library_wire_types.h.golden
@@ -2272,8 +2272,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::TablePayload, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::TablePayload* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2294,7 +2294,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -2324,7 +2324,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -2362,8 +2362,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolOneWayAnonComposedRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::ComposedProtocolOneWayAnonComposedRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2384,7 +2384,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -2414,7 +2414,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -2452,8 +2452,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2474,7 +2474,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -2504,7 +2504,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -2542,8 +2542,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2564,7 +2564,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -2594,7 +2594,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -2632,8 +2632,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolOneWayAnonRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::MainProtocolOneWayAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2654,7 +2654,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -2684,7 +2684,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -2722,8 +2722,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2744,7 +2744,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -2774,7 +2774,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -2812,8 +2812,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2834,7 +2834,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -2864,7 +2864,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -2901,8 +2901,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::UnionPayload* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2927,7 +2927,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::UnionPayload::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2968,7 +2968,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::UnionPayload::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3014,8 +3014,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3040,7 +3040,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedRequest::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3081,7 +3081,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedRequest::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3127,8 +3127,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3153,7 +3153,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResponse::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3194,7 +3194,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResponse::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3240,8 +3240,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3266,10 +3266,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3313,10 +3313,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayAnonComposedWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3365,8 +3365,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolOnAnonComposedRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::ComposedProtocolOnAnonComposedRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3391,7 +3391,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::ComposedProtocolOnAnonComposedRequest::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3432,7 +3432,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::ComposedProtocolOnAnonComposedRequest::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3478,8 +3478,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayNamedComposedWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayNamedComposedWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3504,10 +3504,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayNamedComposedWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayNamedComposedWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3551,10 +3551,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayNamedComposedWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_protocollayoutssamelibrary::wire::ComposedProtocolTwoWayNamedComposedWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3603,8 +3603,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayLocalWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayLocalWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3629,10 +3629,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3676,10 +3676,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::UnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3728,8 +3728,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3754,7 +3754,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonRequest::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3795,7 +3795,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonRequest::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3841,8 +3841,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3867,7 +3867,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResponse::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3908,7 +3908,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResponse::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3954,8 +3954,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3980,10 +3980,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4027,10 +4027,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_protocollayoutssamelibrary::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4079,8 +4079,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayoutssamelibrary::wire::MainProtocolOnAnonRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayoutssamelibrary::wire::MainProtocolOnAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4105,7 +4105,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocollayoutssamelibrary::wire::MainProtocolOnAnonRequest::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4146,7 +4146,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayoutssamelibrary::wire::MainProtocolOnAnonRequest::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_wire_messaging.h.golden
index b7f7950..57b4e71 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_wire_messaging.h.golden
@@ -655,7 +655,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -695,7 +695,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -724,7 +724,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -759,7 +759,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -796,7 +796,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -825,7 +825,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -860,7 +860,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -899,7 +899,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnAnonComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnAnonComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -939,7 +939,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -979,7 +979,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1008,7 +1008,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1043,7 +1043,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1080,7 +1080,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1109,7 +1109,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1144,7 +1144,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayNamedComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1183,7 +1183,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnNamedComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnNamedComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1223,7 +1223,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1263,7 +1263,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1292,7 +1292,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1327,7 +1327,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1364,7 +1364,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayImportWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1393,7 +1393,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayImportWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1428,7 +1428,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayImportWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1467,7 +1467,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1507,7 +1507,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1547,7 +1547,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1576,7 +1576,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1611,7 +1611,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1648,7 +1648,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1677,7 +1677,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1712,7 +1712,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1751,7 +1751,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1791,7 +1791,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::OneWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1831,7 +1831,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1860,7 +1860,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1895,7 +1895,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1932,7 +1932,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1961,7 +1961,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1996,7 +1996,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2035,7 +2035,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayouts::MainProtocol::OnAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5095,7 +5095,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5135,7 +5135,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5164,7 +5164,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5199,7 +5199,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayNoError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5236,7 +5236,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5265,7 +5265,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5300,7 +5300,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::FlexibleTwoWayWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5339,7 +5339,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayouts::OpenProtocol::FlexibleEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayouts::OpenProtocol::FlexibleEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayouts::OpenProtocol::FlexibleEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5379,7 +5379,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5419,7 +5419,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5449,7 +5449,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5484,7 +5484,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayNoError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5521,7 +5521,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5550,7 +5550,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5585,7 +5585,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocollayouts::OpenProtocol::StrictTwoWayWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5624,7 +5624,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocollayouts::OpenProtocol::StrictEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocollayouts::OpenProtocol::StrictEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocollayouts::OpenProtocol::StrictEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5664,7 +5664,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleOneWayNamedPayload>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleOneWayNamedPayload>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocollayouts::OpenProtocol::FlexibleOneWayNamedPayload>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_wire_types.h.golden
index 90794ea..38ef9f8 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocol_layouts_wire_types.h.golden
@@ -1324,8 +1324,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::LocalTablePayload, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::LocalTablePayload* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -1345,7 +1345,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -1374,7 +1374,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -1411,8 +1411,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolOneWayAnonRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolOneWayAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -1432,7 +1432,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -1461,7 +1461,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -1498,8 +1498,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolTwoWayAnonResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -1519,7 +1519,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -1548,7 +1548,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -1585,8 +1585,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -1606,7 +1606,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -1635,7 +1635,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -1670,8 +1670,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::LocalUnionPayload, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::LocalUnionPayload* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1695,7 +1695,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocollayouts::wire::LocalUnionPayload::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1735,7 +1735,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayouts::wire::LocalUnionPayload::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1780,8 +1780,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayImportWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolTwoWayImportWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1805,10 +1805,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocollayouts::wire::MainProtocolTwoWayImportWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts_imported::wire::ImportUnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts_imported::wire::ImportUnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_protocollayouts::wire::MainProtocolTwoWayImportWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1851,10 +1851,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayouts::wire::MainProtocolTwoWayImportWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts_imported::wire::ImportUnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts_imported::wire::ImportUnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_protocollayouts::wire::MainProtocolTwoWayImportWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -1902,8 +1902,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayLocalWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolTwoWayLocalWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -1927,10 +1927,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocollayouts::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::LocalUnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::LocalUnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_protocollayouts::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1973,10 +1973,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayouts::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::LocalUnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::LocalUnionPayload, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_protocollayouts::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2024,8 +2024,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolTwoWayAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2049,7 +2049,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocollayouts::wire::MainProtocolTwoWayAnonRequest::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2089,7 +2089,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayouts::wire::MainProtocolTwoWayAnonRequest::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2134,8 +2134,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2159,7 +2159,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResponse::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2199,7 +2199,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResponse::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2244,8 +2244,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2269,10 +2269,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2315,10 +2315,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_protocollayouts::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2366,8 +2366,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocollayouts::wire::MainProtocolOnAnonRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocollayouts::wire::MainProtocolOnAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2391,7 +2391,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocollayouts::wire::MainProtocolOnAnonRequest::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2431,7 +2431,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocollayouts::wire::MainProtocolOnAnonRequest::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocol_payloads_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocol_payloads_wire_messaging.h.golden
index 3be838c..854782b 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocol_payloads_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocol_payloads_wire_messaging.h.golden
@@ -539,7 +539,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -579,7 +579,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -609,7 +609,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -644,7 +644,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -681,7 +681,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -710,7 +710,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -745,7 +745,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayComposedWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -784,7 +784,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnComposed>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnComposed>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -824,7 +824,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -864,7 +864,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -894,7 +894,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -929,7 +929,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -966,7 +966,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -995,7 +995,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1030,7 +1030,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayLocalWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1069,7 +1069,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnLocal>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnLocal>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1109,7 +1109,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1149,7 +1149,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1179,7 +1179,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1214,7 +1214,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1251,7 +1251,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1280,7 +1280,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1315,7 +1315,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayImportWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1354,7 +1354,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnImport>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnImport>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1394,7 +1394,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::OneWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1434,7 +1434,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1464,7 +1464,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1499,7 +1499,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1536,7 +1536,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1565,7 +1565,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1600,7 +1600,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolpayloads::MainProtocol::TwoWayAnonWithError>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1639,7 +1639,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnAnon>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocolpayloads::MainProtocol::OnAnon>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocol_payloads_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocol_payloads_wire_types.h.golden
index b2402ea..7fe7860 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocol_payloads_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocol_payloads_wire_types.h.golden
@@ -343,15 +343,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::LocalStructPayload, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolpayloads::wire::LocalStructPayload, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolpayloads::wire::LocalStructPayload* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolpayloads::wire::LocalStructPayload));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -393,15 +393,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolOneWayAnonRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolpayloads::wire::MainProtocolOneWayAnonRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolOneWayAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolpayloads::wire::MainProtocolOneWayAnonRequest));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -443,15 +443,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolpayloads::wire::MainProtocolTwoWayAnonRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolTwoWayAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolpayloads::wire::MainProtocolTwoWayAnonRequest));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -493,15 +493,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolpayloads::wire::MainProtocolTwoWayAnonResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolTwoWayAnonResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolpayloads::wire::MainProtocolTwoWayAnonResponse));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -543,15 +543,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorRequest));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -593,15 +593,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResponse));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -643,15 +643,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolOnAnonRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolpayloads::wire::MainProtocolOnAnonRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolOnAnonRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolpayloads::wire::MainProtocolOnAnonRequest));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -690,8 +690,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayLocalWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolTwoWayLocalWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -715,10 +715,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocolpayloads::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::LocalStructPayload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::LocalStructPayload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_protocolpayloads::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -761,10 +761,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocolpayloads::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::LocalStructPayload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::LocalStructPayload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_protocolpayloads::wire::MainProtocolTwoWayLocalWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -812,8 +812,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -837,10 +837,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -883,10 +883,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_protocolpayloads::wire::MainProtocolTwoWayAnonWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -934,8 +934,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolpayloads::wire::MainProtocolTwoWayImportWithErrorResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocolpayloads::wire::MainProtocolTwoWayImportWithErrorResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -959,10 +959,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_protocolpayloads::wire::MainProtocolTwoWayImportWithErrorResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads_imported::wire::ImportStructPayload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads_imported::wire::ImportStructPayload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_protocolpayloads::wire::MainProtocolTwoWayImportWithErrorResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1005,10 +1005,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocolpayloads::wire::MainProtocolTwoWayImportWithErrorResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads_imported::wire::ImportStructPayload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocolpayloads_imported::wire::ImportStructPayload, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_protocolpayloads::wire::MainProtocolTwoWayImportWithErrorResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocol_request_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocol_request_wire_messaging.h.golden
index 721562c..e293f8c 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocol_request_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocol_request_wire_messaging.h.golden
@@ -312,7 +312,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::GetChild>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::GetChild>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::GetChild>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -336,7 +336,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolrequest::Parent::GetChild>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolrequest::Parent::GetChild>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolrequest::Parent::GetChild>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -374,7 +374,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolrequest::Parent::GetChild>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolrequest::Parent::GetChild>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolrequest::Parent::GetChild>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -408,7 +408,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::GetChildRequest>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::GetChildRequest>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::GetChildRequest>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -432,7 +432,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocolrequest::Parent::GetChildRequest>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocolrequest::Parent::GetChildRequest>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocolrequest::Parent::GetChildRequest>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -470,7 +470,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocolrequest::Parent::GetChildRequest>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocolrequest::Parent::GetChildRequest>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocolrequest::Parent::GetChildRequest>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -511,7 +511,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::TakeChild>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::TakeChild>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::TakeChild>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -552,7 +552,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::TakeChildRequest>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::TakeChildRequest>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocolrequest::Parent::TakeChildRequest>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocol_request_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocol_request_wire_types.h.golden
index 6904f6c..e0b5c89 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocol_request_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocol_request_wire_types.h.golden
@@ -110,15 +110,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolrequest::wire::ParentGetChildResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_protocolrequest::Child>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolrequest::wire::ParentGetChildResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolrequest::wire::ParentGetChildResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolrequest::wire::ParentGetChildResponse));
     } else {
       internal::WireCodingTraits<::fidl::ClientEnd<::test_protocolrequest::Child>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->c, position + 0, recursion_depth);
@@ -162,15 +162,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolrequest::wire::ParentGetChildRequestResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_protocolrequest::Child>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolrequest::wire::ParentGetChildRequestResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolrequest::wire::ParentGetChildRequestResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolrequest::wire::ParentGetChildRequestResponse));
     } else {
       internal::WireCodingTraits<::fidl::ServerEnd<::test_protocolrequest::Child>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->r, position + 0, recursion_depth);
@@ -214,15 +214,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolrequest::wire::ParentTakeChildRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_protocolrequest::Child>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolrequest::wire::ParentTakeChildRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolrequest::wire::ParentTakeChildRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolrequest::wire::ParentTakeChildRequest));
     } else {
       internal::WireCodingTraits<::fidl::ClientEnd<::test_protocolrequest::Child>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->c, position + 0, recursion_depth);
@@ -266,15 +266,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocolrequest::wire::ParentTakeChildRequestRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_protocolrequest::Child>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocolrequest::wire::ParentTakeChildRequestRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_protocolrequest::wire::ParentTakeChildRequestRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocolrequest::wire::ParentTakeChildRequestRequest));
     } else {
       internal::WireCodingTraits<::fidl::ServerEnd<::test_protocolrequest::Child>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->r, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocols_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocols_natural_types.h.golden
index 7975f65..6ce3836 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocols_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocols_natural_types.h.golden
@@ -5322,8 +5322,8 @@
 
   template <>
   struct internal::NaturalCodingTraits<::test_protocols::ErrorEnum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-    static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-    static constexpr bool is_memcpy_compatible = false;
+    static constexpr size_t kInlineSize = sizeof(uint32_t);
+    static constexpr bool kIsMemcpyCompatible = false;
 
     static void Encode(internal::NaturalEncoder* encoder, ::test_protocols::ErrorEnum* value, size_t offset, size_t recursion_depth) {
       switch (*value) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocols_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocols_wire_messaging.h.golden
index dd00619..6128c3e 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocols_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocols_wire_messaging.h.golden
@@ -333,7 +333,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestNoResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestNoResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestNoResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -363,7 +363,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestEmptyResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -395,7 +395,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestEmptyResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -423,7 +423,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -449,7 +449,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -484,7 +484,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::NoRequestWithResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -520,7 +520,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestNoResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestNoResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestNoResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -559,7 +559,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestEmptyResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -595,7 +595,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestEmptyResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -628,7 +628,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -658,7 +658,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -693,7 +693,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithAndWithoutRequestResponse::WithRequestWithResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -726,7 +726,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocols::WithAndWithoutRequestResponse::OnEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocols::WithAndWithoutRequestResponse::OnEmptyResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocols::WithAndWithoutRequestResponse::OnEmptyResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -765,7 +765,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocols::WithAndWithoutRequestResponse::OnWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocols::WithAndWithoutRequestResponse::OnWithResponse>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocols::WithAndWithoutRequestResponse::OnWithResponse>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2071,7 +2071,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ResponseAsStruct>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ResponseAsStruct>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ResponseAsStruct>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2096,7 +2096,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithErrorSyntax::ResponseAsStruct>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithErrorSyntax::ResponseAsStruct>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithErrorSyntax::ResponseAsStruct>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2131,7 +2131,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ResponseAsStruct>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ResponseAsStruct>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ResponseAsStruct>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2163,7 +2163,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2188,7 +2188,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2223,7 +2223,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ErrorAsPrimitive>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2255,7 +2255,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ErrorAsEnum>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ErrorAsEnum>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::ErrorAsEnum>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2280,7 +2280,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithErrorSyntax::ErrorAsEnum>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithErrorSyntax::ErrorAsEnum>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithErrorSyntax::ErrorAsEnum>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2315,7 +2315,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ErrorAsEnum>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ErrorAsEnum>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::ErrorAsEnum>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2347,7 +2347,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::HandleInResult>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::HandleInResult>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithErrorSyntax::HandleInResult>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2374,7 +2374,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithErrorSyntax::HandleInResult>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithErrorSyntax::HandleInResult>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithErrorSyntax::HandleInResult>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2412,7 +2412,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::HandleInResult>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::HandleInResult>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithErrorSyntax::HandleInResult>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3568,7 +3568,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MethodA>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MethodA>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MethodA>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3610,7 +3610,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocols::ChannelProtocol::EventA>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocols::ChannelProtocol::EventA>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocols::ChannelProtocol::EventA>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3651,7 +3651,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MethodB>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MethodB>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MethodB>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3681,7 +3681,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::ChannelProtocol::MethodB>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::ChannelProtocol::MethodB>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::ChannelProtocol::MethodB>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3716,7 +3716,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::MethodB>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::MethodB>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 8 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::MethodB>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3755,7 +3755,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::TakeHandle>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::TakeHandle>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::TakeHandle>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3791,7 +3791,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::TakeHandle>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::TakeHandle>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::TakeHandle>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3827,7 +3827,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MutateSocket>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MutateSocket>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::ChannelProtocol::MutateSocket>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3859,7 +3859,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::ChannelProtocol::MutateSocket>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::ChannelProtocol::MutateSocket>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::ChannelProtocol::MutateSocket>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3897,7 +3897,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::MutateSocket>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::MutateSocket>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::ChannelProtocol::MutateSocket>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -4828,7 +4828,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::DiscoverableProtocol::Method>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::DiscoverableProtocol::Method>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::DiscoverableProtocol::Method>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5364,7 +5364,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::HandleRightsProtocol::NoResponseMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::HandleRightsProtocol::NoResponseMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::HandleRightsProtocol::NoResponseMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5407,7 +5407,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::HandleRightsProtocol::ResponseMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::HandleRightsProtocol::ResponseMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::HandleRightsProtocol::ResponseMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5439,7 +5439,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::HandleRightsProtocol::ResponseMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::HandleRightsProtocol::ResponseMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::HandleRightsProtocol::ResponseMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5477,7 +5477,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::HandleRightsProtocol::ResponseMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::HandleRightsProtocol::ResponseMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::HandleRightsProtocol::ResponseMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5522,7 +5522,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_protocols::HandleRightsProtocol::AnEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_protocols::HandleRightsProtocol::AnEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_protocols::HandleRightsProtocol::AnEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -6176,7 +6176,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::ClientEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::ClientEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::ClientEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6208,7 +6208,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithProtocolEnds::ClientEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithProtocolEnds::ClientEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithProtocolEnds::ClientEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -6246,7 +6246,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::ClientEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::ClientEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::ClientEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6289,7 +6289,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::ServerEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::ServerEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::ServerEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6321,7 +6321,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithProtocolEnds::ServerEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithProtocolEnds::ServerEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithProtocolEnds::ServerEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -6359,7 +6359,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::ServerEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::ServerEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::ServerEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6402,7 +6402,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::StructContainingEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::StructContainingEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::WithProtocolEnds::StructContainingEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6434,7 +6434,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::WithProtocolEnds::StructContainingEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::WithProtocolEnds::StructContainingEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::WithProtocolEnds::StructContainingEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -6472,7 +6472,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::StructContainingEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::StructContainingEnds>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::WithProtocolEnds::StructContainingEnds>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7336,7 +7336,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::ManyParameters::Fifteen>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::ManyParameters::Fifteen>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 15 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 15 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::ManyParameters::Fifteen>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7683,7 +7683,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_protocols::MethodWithUnion::UnionMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_protocols::MethodWithUnion::UnionMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_protocols::MethodWithUnion::UnionMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7713,7 +7713,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_protocols::MethodWithUnion::UnionMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_protocols::MethodWithUnion::UnionMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_protocols::MethodWithUnion::UnionMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7748,7 +7748,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_protocols::MethodWithUnion::UnionMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_protocols::MethodWithUnion::UnionMethod>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_protocols::MethodWithUnion::UnionMethod>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/protocols_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/protocols_wire_types.h.golden
index 41b3a42..e82be3e 100644
--- a/tools/fidl/fidlgen_cpp/goldens/protocols_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/protocols_wire_types.h.golden
@@ -1020,8 +1020,8 @@
   
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_protocols::wire::ErrorEnum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocols::wire::ErrorEnum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     switch (*value) {
@@ -1074,15 +1074,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithAndWithoutRequestResponseNoRequestWithResponseResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithAndWithoutRequestResponseNoRequestWithResponseResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithAndWithoutRequestResponseNoRequestWithResponseResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithAndWithoutRequestResponseNoRequestWithResponseResponse));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->ret, position + 0, recursion_depth);
@@ -1121,15 +1121,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithAndWithoutRequestResponseWithRequestNoResponseRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithAndWithoutRequestResponseWithRequestNoResponseRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithAndWithoutRequestResponseWithRequestNoResponseRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithAndWithoutRequestResponseWithRequestNoResponseRequest));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->arg, position + 0, recursion_depth);
@@ -1168,15 +1168,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithAndWithoutRequestResponseWithRequestEmptyResponseRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithAndWithoutRequestResponseWithRequestEmptyResponseRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithAndWithoutRequestResponseWithRequestEmptyResponseRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithAndWithoutRequestResponseWithRequestEmptyResponseRequest));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->arg, position + 0, recursion_depth);
@@ -1215,15 +1215,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithAndWithoutRequestResponseWithRequestWithResponseRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithAndWithoutRequestResponseWithRequestWithResponseRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithAndWithoutRequestResponseWithRequestWithResponseRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithAndWithoutRequestResponseWithRequestWithResponseRequest));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->arg, position + 0, recursion_depth);
@@ -1262,15 +1262,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithAndWithoutRequestResponseWithRequestWithResponseResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithAndWithoutRequestResponseWithRequestWithResponseResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithAndWithoutRequestResponseWithRequestWithResponseResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithAndWithoutRequestResponseWithRequestWithResponseResponse));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->ret, position + 0, recursion_depth);
@@ -1309,15 +1309,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithAndWithoutRequestResponseOnWithResponseRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithAndWithoutRequestResponseOnWithResponseRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithAndWithoutRequestResponseOnWithResponseRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithAndWithoutRequestResponseOnWithResponseRequest));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::Encode(encoder, &value->ret, position + 0, recursion_depth);
@@ -1358,15 +1358,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxResponseAsStructResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 24;
+  static constexpr size_t kInlineSize = 24;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithErrorSyntaxResponseAsStructResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithErrorSyntaxResponseAsStructResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithErrorSyntaxResponseAsStructResponse));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -1411,15 +1411,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -1461,15 +1461,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsEnumResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithErrorSyntaxErrorAsEnumResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithErrorSyntaxErrorAsEnumResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithErrorSyntaxErrorAsEnumResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -1514,15 +1514,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxHandleInResultResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithErrorSyntaxHandleInResultResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithErrorSyntaxHandleInResultResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithErrorSyntaxHandleInResultResponse));
     } else {
       internal::WireCodingTraits<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>::Encode(encoder, &value->h, position + 0, recursion_depth);
@@ -1565,15 +1565,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ChannelProtocolMethodARequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ChannelProtocolMethodARequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ChannelProtocolMethodARequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ChannelProtocolMethodARequest));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -1616,15 +1616,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ChannelProtocolEventARequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ChannelProtocolEventARequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ChannelProtocolEventARequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ChannelProtocolEventARequest));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -1667,15 +1667,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ChannelProtocolMethodBRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ChannelProtocolMethodBRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ChannelProtocolMethodBRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ChannelProtocolMethodBRequest));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -1717,15 +1717,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ChannelProtocolMethodBResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 8;
+  static constexpr size_t kInlineSize = 8;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ChannelProtocolMethodBResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ChannelProtocolMethodBResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ChannelProtocolMethodBResponse));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->result, position + 0, recursion_depth);
@@ -1767,15 +1767,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ChannelProtocolTakeHandleRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ChannelProtocolTakeHandleRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ChannelProtocolTakeHandleRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ChannelProtocolTakeHandleRequest));
     } else {
       internal::WireCodingTraits<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>::Encode(encoder, &value->h, position + 0, recursion_depth);
@@ -1820,15 +1820,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ChannelProtocolMutateSocketRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x80000000, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ChannelProtocolMutateSocketRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ChannelProtocolMutateSocketRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ChannelProtocolMutateSocketRequest));
     } else {
       internal::WireCodingTraits<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x80000000, false>, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -1873,15 +1873,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ChannelProtocolMutateSocketResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x80000000, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ChannelProtocolMutateSocketResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ChannelProtocolMutateSocketResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ChannelProtocolMutateSocketResponse));
     } else {
       internal::WireCodingTraits<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x80000000, false>, IsRecursive>::Encode(encoder, &value->b, position + 0, recursion_depth);
@@ -1924,15 +1924,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::SyscallProtocolMethodCRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::SyscallProtocolMethodCRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::SyscallProtocolMethodCRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::SyscallProtocolMethodCRequest));
     } else {
       internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->a, position + 0, recursion_depth);
@@ -1977,15 +1977,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::HandleRightsProtocolNoResponseMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x3, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::HandleRightsProtocolNoResponseMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::HandleRightsProtocolNoResponseMethodRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::HandleRightsProtocolNoResponseMethodRequest));
     } else {
       internal::WireCodingTraits<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x3, false>, IsRecursive>::Encode(encoder, &value->h, position + 0, recursion_depth);
@@ -2030,15 +2030,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::HandleRightsProtocolResponseMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x3, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::HandleRightsProtocolResponseMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::HandleRightsProtocolResponseMethodRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::HandleRightsProtocolResponseMethodRequest));
     } else {
       internal::WireCodingTraits<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x3, false>, IsRecursive>::Encode(encoder, &value->h, position + 0, recursion_depth);
@@ -2083,15 +2083,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::HandleRightsProtocolResponseMethodResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x2, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::HandleRightsProtocolResponseMethodResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::HandleRightsProtocolResponseMethodResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::HandleRightsProtocolResponseMethodResponse));
     } else {
       internal::WireCodingTraits<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x2, false>, IsRecursive>::Encode(encoder, &value->h, position + 0, recursion_depth);
@@ -2136,15 +2136,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::HandleRightsProtocolAnEventRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x3, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::HandleRightsProtocolAnEventRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::HandleRightsProtocolAnEventRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::HandleRightsProtocolAnEventRequest));
     } else {
       internal::WireCodingTraits<::zx::socket, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_SOCKET, 0x3, false>, IsRecursive>::Encode(encoder, &value->h, position + 0, recursion_depth);
@@ -2192,15 +2192,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ProtocolEnds, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ProtocolEnds, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ProtocolEnds* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ProtocolEnds));
     } else {
       internal::WireCodingTraits<::fidl::ClientEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->client, position + 0, recursion_depth);
@@ -2254,15 +2254,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithProtocolEndsClientEndsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithProtocolEndsClientEndsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithProtocolEndsClientEndsRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithProtocolEndsClientEndsRequest));
     } else {
       internal::WireCodingTraits<::fidl::ClientEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->in, position + 0, recursion_depth);
@@ -2307,15 +2307,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithProtocolEndsClientEndsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithProtocolEndsClientEndsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithProtocolEndsClientEndsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithProtocolEndsClientEndsResponse));
     } else {
       internal::WireCodingTraits<::fidl::ClientEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>::Encode(encoder, &value->out, position + 0, recursion_depth);
@@ -2360,15 +2360,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithProtocolEndsServerEndsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithProtocolEndsServerEndsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithProtocolEndsServerEndsRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithProtocolEndsServerEndsRequest));
     } else {
       internal::WireCodingTraits<::fidl::ServerEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>::Encode(encoder, &value->in, position + 0, recursion_depth);
@@ -2413,15 +2413,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithProtocolEndsServerEndsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithProtocolEndsServerEndsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithProtocolEndsServerEndsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithProtocolEndsServerEndsResponse));
     } else {
       internal::WireCodingTraits<::fidl::ServerEnd<::test_protocols::DiscoverableProtocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>::Encode(encoder, &value->out, position + 0, recursion_depth);
@@ -2466,15 +2466,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithProtocolEndsStructContainingEndsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_protocols::wire::ProtocolEnds, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithProtocolEndsStructContainingEndsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithProtocolEndsStructContainingEndsRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithProtocolEndsStructContainingEndsRequest));
     } else {
       internal::WireCodingTraits<::test_protocols::wire::ProtocolEnds, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->in, position + 0, recursion_depth);
@@ -2519,15 +2519,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithProtocolEndsStructContainingEndsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_protocols::wire::ProtocolEnds, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::WithProtocolEndsStructContainingEndsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::WithProtocolEndsStructContainingEndsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::WithProtocolEndsStructContainingEndsResponse));
     } else {
       internal::WireCodingTraits<::test_protocols::wire::ProtocolEnds, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->out, position + 0, recursion_depth);
@@ -2583,15 +2583,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::ManyParametersFifteenRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 15;
+  static constexpr size_t kInlineSize = 15;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::ManyParametersFifteenRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::ManyParametersFifteenRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::ManyParametersFifteenRequest));
     } else {
       internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->p1, position + 0, recursion_depth);
@@ -2672,15 +2672,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::MethodWithUnionUnionMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_protocols::wire::TheUnion, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::MethodWithUnionUnionMethodRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::MethodWithUnionUnionMethodRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::MethodWithUnionUnionMethodRequest));
     } else {
       internal::WireCodingTraits<::test_protocols::wire::TheUnion, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::Encode(encoder, &value->u, position + 0, recursion_depth);
@@ -2719,15 +2719,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::MethodWithUnionUnionMethodResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::WireOptional<::test_protocols::wire::TheUnion>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_protocols::wire::MethodWithUnionUnionMethodResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_protocols::wire::MethodWithUnionUnionMethodResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_protocols::wire::MethodWithUnionUnionMethodResponse));
     } else {
       internal::WireCodingTraits<::fidl::WireOptional<::test_protocols::wire::TheUnion>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>::Encode(encoder, &value->u, position + 0, recursion_depth);
@@ -2766,8 +2766,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxResponseAsStructResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocols::wire::WithErrorSyntaxResponseAsStructResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2792,10 +2792,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocols::wire::WithErrorSyntaxResponseAsStructResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxResponseAsStructResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxResponseAsStructResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_protocols::wire::WithErrorSyntaxResponseAsStructResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2839,10 +2839,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocols::wire::WithErrorSyntaxResponseAsStructResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxResponseAsStructResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxResponseAsStructResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_protocols::wire::WithErrorSyntaxResponseAsStructResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2891,8 +2891,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2917,10 +2917,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2964,10 +2964,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_protocols::wire::WithErrorSyntaxErrorAsPrimitiveResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3016,8 +3016,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsEnumResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocols::wire::WithErrorSyntaxErrorAsEnumResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3042,10 +3042,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocols::wire::WithErrorSyntaxErrorAsEnumResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsEnumResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsEnumResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_protocols::wire::WithErrorSyntaxErrorAsEnumResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::ErrorEnum, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::ErrorEnum, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3089,10 +3089,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocols::wire::WithErrorSyntaxErrorAsEnumResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsEnumResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxErrorAsEnumResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_protocols::wire::WithErrorSyntaxErrorAsEnumResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::ErrorEnum, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::ErrorEnum, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3144,8 +3144,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxHandleInResultResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocols::wire::WithErrorSyntaxHandleInResultResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3170,10 +3170,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocols::wire::WithErrorSyntaxHandleInResultResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxHandleInResultResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxHandleInResultResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_protocols::wire::WithErrorSyntaxHandleInResultResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3217,10 +3217,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocols::wire::WithErrorSyntaxHandleInResultResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxHandleInResultResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_protocols::wire::WithErrorSyntaxHandleInResultResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_protocols::wire::WithErrorSyntaxHandleInResultResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3272,8 +3272,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_protocols::wire::TheUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_protocols::wire::TheUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3298,7 +3298,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_protocols::wire::TheUnion::Tag::kV
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3339,7 +3339,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_protocols::wire::TheUnion::Tag::kV:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/request_flexible_envelope_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/request_flexible_envelope_wire_messaging.h.golden
index 7e92d28..2b1d91b 100644
--- a/tools/fidl/fidlgen_cpp/goldens/request_flexible_envelope_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/request_flexible_envelope_wire_messaging.h.golden
@@ -138,7 +138,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -164,7 +164,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -199,7 +199,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_requestflexibleenvelope::Protocol::RequestStrictResponseFlexible>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -236,7 +236,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -262,7 +262,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -297,7 +297,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_requestflexibleenvelope::Protocol::RequestFlexibleResponseStrict>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/request_flexible_envelope_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/request_flexible_envelope_wire_types.h.golden
index 417b281c..38472cb 100644
--- a/tools/fidl/fidlgen_cpp/goldens/request_flexible_envelope_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/request_flexible_envelope_wire_types.h.golden
@@ -237,15 +237,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_requestflexibleenvelope::wire::ProtocolRequestStrictResponseFlexibleRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_requestflexibleenvelope::wire::StrictFoo, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_requestflexibleenvelope::wire::ProtocolRequestStrictResponseFlexibleRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_requestflexibleenvelope::wire::ProtocolRequestStrictResponseFlexibleRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_requestflexibleenvelope::wire::ProtocolRequestStrictResponseFlexibleRequest));
     } else {
       internal::WireCodingTraits<::test_requestflexibleenvelope::wire::StrictFoo, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::Encode(encoder, &value->s, position + 0, recursion_depth);
@@ -283,15 +283,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_requestflexibleenvelope::wire::ProtocolRequestStrictResponseFlexibleResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_requestflexibleenvelope::wire::FlexibleFoo, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_requestflexibleenvelope::wire::ProtocolRequestStrictResponseFlexibleResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_requestflexibleenvelope::wire::ProtocolRequestStrictResponseFlexibleResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_requestflexibleenvelope::wire::ProtocolRequestStrictResponseFlexibleResponse));
     } else {
       internal::WireCodingTraits<::test_requestflexibleenvelope::wire::FlexibleFoo, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::Encode(encoder, &value->f, position + 0, recursion_depth);
@@ -329,15 +329,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_requestflexibleenvelope::wire::ProtocolRequestFlexibleResponseStrictRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_requestflexibleenvelope::wire::FlexibleFoo, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_requestflexibleenvelope::wire::ProtocolRequestFlexibleResponseStrictRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_requestflexibleenvelope::wire::ProtocolRequestFlexibleResponseStrictRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_requestflexibleenvelope::wire::ProtocolRequestFlexibleResponseStrictRequest));
     } else {
       internal::WireCodingTraits<::test_requestflexibleenvelope::wire::FlexibleFoo, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::Encode(encoder, &value->s, position + 0, recursion_depth);
@@ -375,15 +375,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_requestflexibleenvelope::wire::ProtocolRequestFlexibleResponseStrictResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_requestflexibleenvelope::wire::StrictFoo, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_requestflexibleenvelope::wire::ProtocolRequestFlexibleResponseStrictResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_requestflexibleenvelope::wire::ProtocolRequestFlexibleResponseStrictResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_requestflexibleenvelope::wire::ProtocolRequestFlexibleResponseStrictResponse));
     } else {
       internal::WireCodingTraits<::test_requestflexibleenvelope::wire::StrictFoo, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::Encode(encoder, &value->f, position + 0, recursion_depth);
@@ -419,8 +419,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_requestflexibleenvelope::wire::FlexibleFoo, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_requestflexibleenvelope::wire::FlexibleFoo* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -444,10 +444,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_requestflexibleenvelope::wire::FlexibleFoo::Tag::kS
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_requestflexibleenvelope::wire::FlexibleFoo::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -490,10 +490,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_requestflexibleenvelope::wire::FlexibleFoo::Tag::kS:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_requestflexibleenvelope::wire::FlexibleFoo::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -541,8 +541,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_requestflexibleenvelope::wire::StrictFoo, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_requestflexibleenvelope::wire::StrictFoo* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -566,10 +566,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_requestflexibleenvelope::wire::StrictFoo::Tag::kS
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case 2:  // ::test_requestflexibleenvelope::wire::StrictFoo::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -612,10 +612,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_requestflexibleenvelope::wire::StrictFoo::Tag::kS:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_requestflexibleenvelope::wire::StrictFoo::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/service_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/service_wire_messaging.h.golden
index d56c29c..aedc0c8 100644
--- a/tools/fidl/fidlgen_cpp/goldens/service_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/service_wire_messaging.h.golden
@@ -104,7 +104,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_service::FirstProtocol::MethodOnFirst>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_service::FirstProtocol::MethodOnFirst>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_service::FirstProtocol::MethodOnFirst>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -371,7 +371,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_service::SecondProtocol::MethodOnSecond>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_service::SecondProtocol::MethodOnSecond>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_service::SecondProtocol::MethodOnSecond>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/struct_default_value_enum_library_reference_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/struct_default_value_enum_library_reference_wire_types.h.golden
index 3b5ff00..dccdd33 100644
--- a/tools/fidl/fidlgen_cpp/goldens/struct_default_value_enum_library_reference_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/struct_default_value_enum_library_reference_wire_types.h.golden
@@ -64,15 +64,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_structdefaultvalueenumlibraryreference::wire::Foo, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_dependent::wire::MyEnum, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_structdefaultvalueenumlibraryreference::wire::Foo, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_structdefaultvalueenumlibraryreference::wire::Foo* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_structdefaultvalueenumlibraryreference::wire::Foo));
     } else {
       internal::WireCodingTraits<::test_dependent::wire::MyEnum, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->field, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/struct_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/struct_wire_types.h.golden
index 1b19121..d2ba4b3d 100644
--- a/tools/fidl/fidlgen_cpp/goldens/struct_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/struct_wire_types.h.golden
@@ -74,15 +74,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_struct::wire::Simple, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 2;
+  static constexpr size_t kInlineSize = 2;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_struct::wire::Simple, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_struct::wire::Simple* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_struct::wire::Simple));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->f1, position + 0, recursion_depth);
@@ -124,15 +124,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_struct::wire::BasicStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 24;
+  static constexpr size_t kInlineSize = 24;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_struct::wire::BasicStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_struct::wire::BasicStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_struct::wire::BasicStruct));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
diff --git a/tools/fidl/fidlgen_cpp/goldens/table_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/table_wire_types.h.golden
index 09d7107..b8e2fed 100644
--- a/tools/fidl/fidlgen_cpp/goldens/table_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/table_wire_types.h.golden
@@ -6964,8 +6964,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_table::wire::EmptyTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_table::wire::EmptyTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -7042,8 +7042,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_table::wire::SimpleTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_table::wire::SimpleTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -7064,10 +7064,10 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 4:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -7100,10 +7100,10 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 4:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -7144,8 +7144,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_table::wire::OlderSimpleTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_table::wire::OlderSimpleTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -7166,7 +7166,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -7196,7 +7196,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -7234,8 +7234,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_table::wire::NewerSimpleTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_table::wire::NewerSimpleTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -7256,13 +7256,13 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 4:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 5:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -7298,13 +7298,13 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 4:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 5:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -7348,8 +7348,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_table::wire::ReverseOrdinalTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_table::wire::ReverseOrdinalTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -7370,13 +7370,13 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 1:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 2:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -7412,13 +7412,13 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 1:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 2:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -7462,8 +7462,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_table::wire::TableWithAttributes, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_table::wire::TableWithAttributes* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -7484,7 +7484,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -7514,7 +7514,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -7552,8 +7552,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_table::wire::ExtensionTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_table::wire::ExtensionTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -7630,8 +7630,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_table::wire::SixtyFourOrdinalTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_table::wire::SixtyFourOrdinalTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -7652,196 +7652,196 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 1:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 2:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 3:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 4:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 5:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 6:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 7:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 8:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 9:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 10:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 11:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 12:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 13:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 14:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 15:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 16:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 17:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 18:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 19:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 20:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 21:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 22:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 23:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 24:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 25:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 26:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 27:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 28:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 29:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 30:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 31:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 32:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 33:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 34:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 35:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 36:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 37:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 38:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 39:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 40:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 41:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 42:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 43:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 44:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 45:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 46:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 47:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 48:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 49:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 50:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 51:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 52:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 53:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 54:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 55:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 56:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 57:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 58:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 59:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 60:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 61:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 62:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 63:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<::test_table::wire::ExtensionTable, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<::test_table::wire::ExtensionTable, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -8060,196 +8060,196 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 1:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 2:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 3:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 4:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 5:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 6:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 7:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 8:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 9:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 10:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 11:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 12:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 13:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 14:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 15:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 16:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 17:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 18:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 19:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 20:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 21:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 22:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 23:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 24:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 25:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 26:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 27:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 28:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 29:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 30:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 31:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 32:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 33:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 34:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 35:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 36:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 37:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 38:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 39:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 40:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 41:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 42:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 43:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 44:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 45:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 46:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 47:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 48:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 49:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 50:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 51:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 52:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 53:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 54:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 55:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 56:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 57:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 58:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 59:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 60:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 61:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 62:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
         case 63:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<::test_table::wire::ExtensionTable, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<::test_table::wire::ExtensionTable, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
diff --git a/tools/fidl/fidlgen_cpp/goldens/transitive_dependencies_compose_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/transitive_dependencies_compose_wire_messaging.h.golden
index 5e3714c..d1a4e5d 100644
--- a/tools/fidl/fidlgen_cpp/goldens/transitive_dependencies_compose_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/transitive_dependencies_compose_wire_messaging.h.golden
@@ -107,7 +107,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_transitivedependenciescompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_transitivedependenciescompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_transitivedependenciescompose::Top::GetFoo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -129,7 +129,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_transitivedependenciescompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_transitivedependenciescompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_transitivedependenciescompose::Top::GetFoo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -164,7 +164,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_transitivedependenciescompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_transitivedependenciescompose::Top::GetFoo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_transitivedependenciescompose::Top::GetFoo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/transitive_dependencies_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/transitive_dependencies_wire_types.h.golden
index 52d8afb..500a707 100644
--- a/tools/fidl/fidlgen_cpp/goldens/transitive_dependencies_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/transitive_dependencies_wire_types.h.golden
@@ -64,15 +64,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_transitivedependencies::wire::Baz, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_middle::wire::Bar, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_transitivedependencies::wire::Baz, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_transitivedependencies::wire::Baz* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_transitivedependencies::wire::Baz));
     } else {
       internal::WireCodingTraits<::test_middle::wire::Bar, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->g, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_natural_types.h.golden
index 5daa31f..9ca1a93 100644
--- a/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_natural_types.h.golden
@@ -5322,8 +5322,8 @@
 
   template <>
   struct internal::NaturalCodingTraits<::test_typesinprotocols::Bits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-    static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-    static constexpr bool is_memcpy_compatible = true;
+    static constexpr size_t kInlineSize = sizeof(uint32_t);
+    static constexpr bool kIsMemcpyCompatible = true;
 
     static void Encode(internal::NaturalEncoder* encoder, ::test_typesinprotocols::Bits* value, size_t offset, size_t recursion_depth) {
       *encoder->template GetPtr<::test_typesinprotocols::Bits>(offset) = *value;
@@ -5335,8 +5335,8 @@
 
   template <>
   struct internal::NaturalCodingTraits<::test_typesinprotocols::Enum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-    static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-    static constexpr bool is_memcpy_compatible = true;
+    static constexpr size_t kInlineSize = sizeof(uint32_t);
+    static constexpr bool kIsMemcpyCompatible = true;
 
     static void Encode(internal::NaturalEncoder* encoder, ::test_typesinprotocols::Enum* value, size_t offset, size_t recursion_depth) {
       *encoder->template GetPtr<::test_typesinprotocols::Enum>(offset) = *value;
diff --git a/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_wire_messaging.h.golden
index 88bb255..3fa3f6c 100644
--- a/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_wire_messaging.h.golden
@@ -1089,7 +1089,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 80 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 80 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1129,7 +1129,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 80 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 80 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1159,7 +1159,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 80;
+  static constexpr size_t kInlineSize = 80;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1194,7 +1194,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 80 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 80 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1226,7 +1226,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1251,7 +1251,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1286,7 +1286,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1325,7 +1325,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 80 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 80 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1365,7 +1365,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 72 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 72 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1405,7 +1405,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 72 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 72 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1435,7 +1435,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 72;
+  static constexpr size_t kInlineSize = 72;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1470,7 +1470,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 72 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 72 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1502,7 +1502,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1527,7 +1527,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1562,7 +1562,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1601,7 +1601,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 72 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 72 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1641,7 +1641,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 384 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 384 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1681,7 +1681,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 384 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 384 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1711,7 +1711,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 384;
+  static constexpr size_t kInlineSize = 384;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1746,7 +1746,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 384 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 384 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1778,7 +1778,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1803,7 +1803,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1838,7 +1838,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1877,7 +1877,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 384 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 384 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1917,7 +1917,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 328 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 328 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1957,7 +1957,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 328 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 328 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1987,7 +1987,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 328;
+  static constexpr size_t kInlineSize = 328;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2022,7 +2022,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 328 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 328 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2054,7 +2054,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2079,7 +2079,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2114,7 +2114,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2153,7 +2153,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 328 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 328 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2193,7 +2193,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 192 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 192 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2233,7 +2233,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 192 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 192 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2263,7 +2263,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 192;
+  static constexpr size_t kInlineSize = 192;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2298,7 +2298,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 192 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 192 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2330,7 +2330,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2355,7 +2355,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2390,7 +2390,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2429,7 +2429,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorBasic>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 192 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 192 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorBasic>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2469,7 +2469,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 112 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 112 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2509,7 +2509,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 112 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 112 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2539,7 +2539,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 112;
+  static constexpr size_t kInlineSize = 112;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2574,7 +2574,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 112 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 112 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2606,7 +2606,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2631,7 +2631,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2666,7 +2666,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2705,7 +2705,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorCompound>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 112 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 112 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorCompound>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2745,7 +2745,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 64 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 64 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayVectorOptional>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2785,7 +2785,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 64 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 64 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayVectorOptional>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2815,7 +2815,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 64;
+  static constexpr size_t kInlineSize = 64;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayVectorOptional>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2850,7 +2850,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 64 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 64 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayVectorOptional>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2882,7 +2882,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorVectorOptional>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2907,7 +2907,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorVectorOptional>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2942,7 +2942,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorVectorOptional>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2981,7 +2981,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorOptional>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 64 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 64 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventVectorOptional>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3021,7 +3021,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 144 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 144 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayArrayVectorNested>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3061,7 +3061,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 144 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 144 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3091,7 +3091,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 144;
+  static constexpr size_t kInlineSize = 144;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3126,7 +3126,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 144 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 144 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayArrayVectorNested>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3158,7 +3158,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3183,7 +3183,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3218,7 +3218,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorArrayVectorNested>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3257,7 +3257,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayVectorNested>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 144 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 144 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventArrayVectorNested>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3300,7 +3300,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 456 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 456 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::OneWayResource>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3343,7 +3343,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 456 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 456 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::TwoWayResource>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3375,7 +3375,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 456;
+  static constexpr size_t kInlineSize = 456;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::TwoWayResource>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3413,7 +3413,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 456 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 456 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::TwoWayResource>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3448,7 +3448,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_typesinprotocols::Protocol::ErrorResource>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3475,7 +3475,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_typesinprotocols::Protocol::ErrorResource>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -3513,7 +3513,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_typesinprotocols::Protocol::ErrorResource>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -3558,7 +3558,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventResource>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 456 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 456 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_typesinprotocols::Protocol::EventResource>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_wire_types.h.golden
index a99f092..3b86e3d 100644
--- a/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/types_in_protocols_wire_types.h.golden
@@ -1611,8 +1611,8 @@
   
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_typesinprotocols::wire::Bits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::Bits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_typesinprotocols::wire::Bits>() = *value;
@@ -1625,8 +1625,8 @@
   
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_typesinprotocols::wire::Enum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::Enum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_typesinprotocols::wire::Enum>() = *value;
@@ -1662,15 +1662,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Struct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::Struct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::Struct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::Struct));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -1715,15 +1715,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ResourceStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::ResourceStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ResourceStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::ResourceStruct));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -1779,15 +1779,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Basic, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 80;
+  static constexpr size_t kInlineSize = 80;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int16_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<double, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<true>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::Basic, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::Basic* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::Basic));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -1871,15 +1871,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Compound, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 72;
+  static constexpr size_t kInlineSize = 72;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_typesinprotocols::wire::Bits, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_typesinprotocols::wire::Enum, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_typesinprotocols::wire::Struct, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_typesinprotocols::wire::Table, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_typesinprotocols::wire::Union, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ObjectView<::test_typesinprotocols::wire::Struct>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::WireOptional<::test_typesinprotocols::wire::Union>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::Compound, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::Compound* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::Compound));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 8);
@@ -1949,15 +1949,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayBasic, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 384;
+  static constexpr size_t kInlineSize = 384;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<uint8_t, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<uint16_t, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<uint32_t, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<uint64_t, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<int8_t, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<int16_t, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<int32_t, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<int64_t, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<float, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<double, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::fidl::StringView, 5>, fidl::internal::WireCodingConstraintString<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::fidl::StringView, 5>, fidl::internal::WireCodingConstraintString<true>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::ArrayBasic, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ArrayBasic* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::ArrayBasic));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -2045,15 +2045,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayCompound, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 328;
+  static constexpr size_t kInlineSize = 328;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_typesinprotocols::wire::Bits, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_typesinprotocols::wire::Enum, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_typesinprotocols::wire::Struct, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_typesinprotocols::wire::Table, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_typesinprotocols::wire::Union, 5>, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::fidl::ObjectView<::test_typesinprotocols::wire::Struct>, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::fidl::WireOptional<::test_typesinprotocols::wire::Union>, 5>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::ArrayCompound, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ArrayCompound* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::ArrayCompound));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 40);
@@ -2123,15 +2123,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorBasic, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 192;
+  static constexpr size_t kInlineSize = 192;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<uint16_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<uint32_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<uint64_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<int8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<int16_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<int32_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<int64_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<float>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<double>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<true>, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::VectorBasic, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::VectorBasic* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::VectorBasic));
     } else {
       internal::WireCodingTraits<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>::Encode(encoder, &value->vector_uint8, position + 0, recursion_depth);
@@ -2209,15 +2209,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorCompound, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 112;
+  static constexpr size_t kInlineSize = 112;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::Bits>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::Enum>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::Struct>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::Table>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::Union>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintUnion<false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::ObjectView<::test_typesinprotocols::wire::Struct>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::WireOptional<::test_typesinprotocols::wire::Union>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintUnion<true>, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::VectorCompound, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::VectorCompound* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::VectorCompound));
     } else {
       internal::WireCodingTraits<::fidl::VectorView<::test_typesinprotocols::wire::Bits>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>::Encode(encoder, &value->vector_bits, position + 0, recursion_depth);
@@ -2277,15 +2277,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorOptional, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 64;
+  static constexpr size_t kInlineSize = 64;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::Struct>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::ObjectView<::test_typesinprotocols::wire::Struct>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::VectorOptional, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::VectorOptional* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::VectorOptional));
     } else {
       internal::WireCodingTraits<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, true>, IsRecursive>::Encode(encoder, &value->opt_vector_uint8, position + 0, recursion_depth);
@@ -2336,15 +2336,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayVectorNested, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 144;
+  static constexpr size_t kInlineSize = 144;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::fidl::Array<uint8_t, 5>, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::fidl::VectorView<uint8_t>, 5>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::Array<uint8_t, 5>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::VectorView<uint8_t>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, false>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::ArrayVectorNested, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ArrayVectorNested* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::ArrayVectorNested));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 24);
@@ -2423,15 +2423,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Resource, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 456;
+  static constexpr size_t kInlineSize = 456;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_typesinprotocols::Protocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_typesinprotocols::Protocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_typesinprotocols::wire::ResourceStruct, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_typesinprotocols::wire::ResourceTable, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_typesinprotocols::wire::ResourceUnion, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::handle, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::zx::vmo, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ClientEnd<::test_typesinprotocols::Protocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ServerEnd<::test_typesinprotocols::Protocol>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::ObjectView<::test_typesinprotocols::wire::ResourceStruct>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::WireOptional<::test_typesinprotocols::wire::ResourceUnion>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::zx::handle, 5>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::zx::vmo, 5>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::fidl::ClientEnd<::test_typesinprotocols::Protocol>, 5>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::fidl::ServerEnd<::test_typesinprotocols::Protocol>, 5>, fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_typesinprotocols::wire::ResourceStruct, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_typesinprotocols::wire::ResourceTable, 5>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::Array<::test_typesinprotocols::wire::ResourceUnion, 5>, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::zx::handle>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_NONE, 0x80000000, false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::zx::vmo>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_VMO, 0x80000000, false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::ClientEnd<::test_typesinprotocols::Protocol>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::ServerEnd<::test_typesinprotocols::Protocol>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintHandle<ZX_OBJ_TYPE_CHANNEL, ZX_DEFAULT_CHANNEL_RIGHTS, false>, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::ResourceStruct>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::ResourceTable>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::test_typesinprotocols::wire::ResourceUnion>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintUnion<false>, false>, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_typesinprotocols::wire::Resource, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_typesinprotocols::wire::Resource* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_typesinprotocols::wire::Resource));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 16);
@@ -2556,8 +2556,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Table, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::Table* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2637,8 +2637,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ResourceTable, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ResourceTable* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -2717,8 +2717,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Union, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::Union* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2743,7 +2743,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::Union::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2784,7 +2784,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::Union::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2833,8 +2833,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ResourceUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ResourceUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2859,7 +2859,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ResourceUnion::Tag::kB
-        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2900,7 +2900,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ResourceUnion::Tag::kB:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<bool, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2949,8 +2949,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorBasicResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorBasicResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2975,10 +2975,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorBasicResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Basic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Basic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorBasicResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3022,10 +3022,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorBasicResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Basic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Basic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorBasicResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3074,8 +3074,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorCompoundResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorCompoundResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3100,10 +3100,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorCompoundResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Compound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Compound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorCompoundResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3147,10 +3147,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorCompoundResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Compound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Compound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorCompoundResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3199,8 +3199,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorArrayBasicResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorArrayBasicResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3225,10 +3225,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorArrayBasicResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayBasic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayBasic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorArrayBasicResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3272,10 +3272,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorArrayBasicResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayBasic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayBasic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorArrayBasicResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3324,8 +3324,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorArrayCompoundResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorArrayCompoundResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3350,10 +3350,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorArrayCompoundResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayCompound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayCompound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorArrayCompoundResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3397,10 +3397,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorArrayCompoundResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayCompound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayCompound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorArrayCompoundResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3449,8 +3449,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorVectorBasicResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorVectorBasicResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3475,10 +3475,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorVectorBasicResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorBasic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorBasic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorVectorBasicResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3522,10 +3522,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorVectorBasicResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorBasic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorBasic, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorVectorBasicResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3574,8 +3574,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorVectorCompoundResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorVectorCompoundResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3600,10 +3600,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorVectorCompoundResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorCompound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorCompound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorVectorCompoundResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3647,10 +3647,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorVectorCompoundResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorCompound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorCompound, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorVectorCompoundResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3699,8 +3699,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorVectorOptionalResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorVectorOptionalResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3725,10 +3725,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorVectorOptionalResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorOptional, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorOptional, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorVectorOptionalResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3772,10 +3772,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorVectorOptionalResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorOptional, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::VectorOptional, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorVectorOptionalResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3824,8 +3824,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorArrayVectorNestedResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorArrayVectorNestedResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3850,10 +3850,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorArrayVectorNestedResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayVectorNested, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayVectorNested, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorArrayVectorNestedResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3897,10 +3897,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorArrayVectorNestedResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayVectorNested, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ArrayVectorNested, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorArrayVectorNestedResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3952,8 +3952,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::ProtocolErrorResourceResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_typesinprotocols::wire::ProtocolErrorResourceResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3978,10 +3978,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_typesinprotocols::wire::ProtocolErrorResourceResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Resource, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Resource, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_typesinprotocols::wire::ProtocolErrorResourceResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4025,10 +4025,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_typesinprotocols::wire::ProtocolErrorResourceResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Resource, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_typesinprotocols::wire::Resource, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_typesinprotocols::wire::ProtocolErrorResourceResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/union_sandwich_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/union_sandwich_wire_types.h.golden
index 0a16faa..dc71b63 100644
--- a/tools/fidl/fidlgen_cpp/goldens/union_sandwich_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/union_sandwich_wire_types.h.golden
@@ -329,15 +329,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::SandwichUnionSize8Alignment4, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 32;
+  static constexpr size_t kInlineSize = 32;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_unionsandwich::wire::UnionSize8Alignment4, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_unionsandwich::wire::SandwichUnionSize8Alignment4, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_unionsandwich::wire::SandwichUnionSize8Alignment4* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unionsandwich::wire::SandwichUnionSize8Alignment4));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -387,15 +387,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::SandwichUnionSize12Alignment4, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 32;
+  static constexpr size_t kInlineSize = 32;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_unionsandwich::wire::UnionSize12Alignment4, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_unionsandwich::wire::SandwichUnionSize12Alignment4, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_unionsandwich::wire::SandwichUnionSize12Alignment4* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unionsandwich::wire::SandwichUnionSize12Alignment4));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -444,15 +444,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::StructSize16Alignment8, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unionsandwich::wire::StructSize16Alignment8, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_unionsandwich::wire::StructSize16Alignment8* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unionsandwich::wire::StructSize16Alignment8));
     } else {
       internal::WireCodingTraits<uint64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->f1, position + 0, recursion_depth);
@@ -495,15 +495,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::SandwichUnionSize24Alignment8, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 32;
+  static constexpr size_t kInlineSize = 32;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_unionsandwich::wire::UnionSize24Alignment8, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_unionsandwich::wire::SandwichUnionSize24Alignment8, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_unionsandwich::wire::SandwichUnionSize24Alignment8* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unionsandwich::wire::SandwichUnionSize24Alignment8));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -553,15 +553,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::SandwichUnionSize36Alignment4, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 32;
+  static constexpr size_t kInlineSize = 32;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_unionsandwich::wire::UnionSize36Alignment4, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_unionsandwich::wire::SandwichUnionSize36Alignment4, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_unionsandwich::wire::SandwichUnionSize36Alignment4* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unionsandwich::wire::SandwichUnionSize36Alignment4));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -607,8 +607,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::UnionSize8Alignment4, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unionsandwich::wire::UnionSize8Alignment4* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -632,7 +632,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_unionsandwich::wire::UnionSize8Alignment4::Tag::kVariant
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -672,7 +672,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unionsandwich::wire::UnionSize8Alignment4::Tag::kVariant:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -717,8 +717,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::UnionSize12Alignment4, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unionsandwich::wire::UnionSize12Alignment4* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -742,7 +742,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_unionsandwich::wire::UnionSize12Alignment4::Tag::kVariant
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint8_t, 6>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint8_t, 6>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -782,7 +782,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unionsandwich::wire::UnionSize12Alignment4::Tag::kVariant:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint8_t, 6>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint8_t, 6>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -827,8 +827,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::UnionSize24Alignment8, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unionsandwich::wire::UnionSize24Alignment8* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -852,7 +852,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_unionsandwich::wire::UnionSize24Alignment8::Tag::kVariant
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::StructSize16Alignment8, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::StructSize16Alignment8, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -892,7 +892,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unionsandwich::wire::UnionSize24Alignment8::Tag::kVariant:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::StructSize16Alignment8, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::StructSize16Alignment8, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -937,8 +937,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unionsandwich::wire::UnionSize36Alignment4, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unionsandwich::wire::UnionSize36Alignment4* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -962,7 +962,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_unionsandwich::wire::UnionSize36Alignment4::Tag::kVariant
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint8_t, 32>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint8_t, 32>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -1002,7 +1002,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unionsandwich::wire::UnionSize36Alignment4::Tag::kVariant:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint8_t, 32>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::Array<uint8_t, 32>, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/union_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/union_wire_messaging.h.golden
index ab3ea59..d531d7f1 100644
--- a/tools/fidl/fidlgen_cpp/goldens/union_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/union_wire_messaging.h.golden
@@ -131,7 +131,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -153,7 +153,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -188,7 +188,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_union::TestProtocol::StrictUnionHenceResponseMayBeStackAllocated>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -220,7 +220,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -242,7 +242,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
       internal::WireEncoder* encoder, ::fidl::WireResponse<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -277,7 +277,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_union::TestProtocol::FlexibleUnionHenceResponseMustBeHeapAllocated>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/union_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/union_wire_types.h.golden
index ea7ec64..2954eff 100644
--- a/tools/fidl/fidlgen_cpp/goldens/union_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/union_wire_types.h.golden
@@ -2080,15 +2080,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false, 16>, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_union::wire::Pizza, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_union::wire::Pizza* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_union::wire::Pizza));
     } else {
       internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false, 16>, false>, IsRecursive>::Encode(encoder, &value->toppings, position + 0, recursion_depth);
@@ -2127,15 +2127,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::StringView, fidl::internal::WireCodingConstraintString<false, 16>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_union::wire::Pasta, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_union::wire::Pasta* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_union::wire::Pasta));
     } else {
       internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false, 16>, IsRecursive>::Encode(encoder, &value->sauce, position + 0, recursion_depth);
@@ -2174,15 +2174,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::NullableUnionStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::WireOptional<::test_union::wire::Union>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_union::wire::NullableUnionStruct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_union::wire::NullableUnionStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_union::wire::NullableUnionStruct));
     } else {
       internal::WireCodingTraits<::fidl::WireOptional<::test_union::wire::Union>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>::Encode(encoder, &value->the_union, position + 0, recursion_depth);
@@ -2221,15 +2221,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::Empty, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_union::wire::Empty, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_union::wire::Empty* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_union::wire::Empty));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -2271,15 +2271,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_union::wire::StrictBoundedUnion, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_union::wire::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_union::wire::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_union::wire::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse));
     } else {
       internal::WireCodingTraits<::test_union::wire::StrictBoundedUnion, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::Encode(encoder, &value->xu, position + 0, recursion_depth);
@@ -2318,15 +2318,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::test_union::wire::OlderSimpleUnion, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_union::wire::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_union::wire::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_union::wire::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse));
     } else {
       internal::WireCodingTraits<::test_union::wire::OlderSimpleUnion, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::Encode(encoder, &value->xu, position + 0, recursion_depth);
@@ -2365,15 +2365,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::StructWithNullableUnion, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::WireOptional<::test_union::wire::OlderSimpleUnion>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_union::wire::StructWithNullableUnion, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_union::wire::StructWithNullableUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_union::wire::StructWithNullableUnion));
     } else {
       internal::WireCodingTraits<::fidl::WireOptional<::test_union::wire::OlderSimpleUnion>, fidl::internal::WireCodingConstraintUnion<true>, IsRecursive>::Encode(encoder, &value->x1, position + 0, recursion_depth);
@@ -2414,15 +2414,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::UnionSandwich, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 32;
+  static constexpr size_t kInlineSize = 32;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::test_union::wire::ExplicitFlexibleUnion, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = true;
   using Base = WireStructCodingTraitsBase<::test_union::wire::UnionSandwich, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_union::wire::UnionSandwich* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_union::wire::UnionSandwich));
     } else {
       internal::WireZeroPadding<uint64_t>(encoder, position + 0);
@@ -2471,8 +2471,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::PizzaOrPasta, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::PizzaOrPasta* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2497,10 +2497,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::PizzaOrPasta::Tag::kPizza
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::PizzaOrPasta::Tag::kPasta
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2544,10 +2544,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::PizzaOrPasta::Tag::kPizza:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::PizzaOrPasta::Tag::kPasta:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2596,8 +2596,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::ExplicitPizzaOrPasta, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::ExplicitPizzaOrPasta* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2622,10 +2622,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::ExplicitPizzaOrPasta::Tag::kPizza
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 4: // ::test_union::wire::ExplicitPizzaOrPasta::Tag::kPasta
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2669,10 +2669,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::ExplicitPizzaOrPasta::Tag::kPizza:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::ExplicitPizzaOrPasta::Tag::kPasta:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2721,8 +2721,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::FlexiblePizzaOrPasta, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::FlexiblePizzaOrPasta* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2747,10 +2747,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::FlexiblePizzaOrPasta::Tag::kPizza
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::FlexiblePizzaOrPasta::Tag::kPasta
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2794,10 +2794,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::FlexiblePizzaOrPasta::Tag::kPizza:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::FlexiblePizzaOrPasta::Tag::kPasta:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2846,8 +2846,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::StrictPizzaOrPasta, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::StrictPizzaOrPasta* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2872,10 +2872,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::StrictPizzaOrPasta::Tag::kPizza
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::StrictPizzaOrPasta::Tag::kPasta
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -2919,10 +2919,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::StrictPizzaOrPasta::Tag::kPizza:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pizza, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::StrictPizzaOrPasta::Tag::kPasta:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Pasta, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -2971,8 +2971,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::Union, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::Union* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -2997,13 +2997,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::Union::Tag::kPrimitive
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::Union::Tag::kStringNeedsConstructor
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_union::wire::Union::Tag::kVectorStringAlsoNeedsConstructor
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3050,13 +3050,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::Union::Tag::kPrimitive:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::Union::Tag::kStringNeedsConstructor:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::Union::Tag::kVectorStringAlsoNeedsConstructor:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3108,8 +3108,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::FlexibleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::FlexibleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3134,13 +3134,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::FlexibleUnion::Tag::kPrimitive
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::FlexibleUnion::Tag::kStringNeedsConstructor
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_union::wire::FlexibleUnion::Tag::kVectorStringAlsoNeedsConstructor
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3187,13 +3187,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::FlexibleUnion::Tag::kPrimitive:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::FlexibleUnion::Tag::kStringNeedsConstructor:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::FlexibleUnion::Tag::kVectorStringAlsoNeedsConstructor:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3245,8 +3245,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::StrictUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::StrictUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3271,13 +3271,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::StrictUnion::Tag::kPrimitive
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::StrictUnion::Tag::kStringNeedsConstructor
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_union::wire::StrictUnion::Tag::kVectorStringAlsoNeedsConstructor
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3324,13 +3324,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::StrictUnion::Tag::kPrimitive:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::StrictUnion::Tag::kStringNeedsConstructor:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::StrictUnion::Tag::kVectorStringAlsoNeedsConstructor:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3382,8 +3382,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::FieldCollision, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::FieldCollision* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3408,7 +3408,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::FieldCollision::Tag::kFieldCollisionTag
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3449,7 +3449,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::FieldCollision::Tag::kFieldCollisionTag:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3495,8 +3495,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::ExplicitUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::ExplicitUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3521,10 +3521,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::ExplicitUnion::Tag::kPrimitive
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_union::wire::ExplicitUnion::Tag::kStringNeedsConstructor
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3568,10 +3568,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::ExplicitUnion::Tag::kPrimitive:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::ExplicitUnion::Tag::kStringNeedsConstructor:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3620,8 +3620,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::ReverseOrdinalUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::ReverseOrdinalUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3646,10 +3646,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::ReverseOrdinalUnion::Tag::kFirst
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::ReverseOrdinalUnion::Tag::kSecond
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3693,10 +3693,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::ReverseOrdinalUnion::Tag::kFirst:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::ReverseOrdinalUnion::Tag::kSecond:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3745,8 +3745,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::FlexibleFoo, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::FlexibleFoo* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3771,10 +3771,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::FlexibleFoo::Tag::kS
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::FlexibleFoo::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3818,10 +3818,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::FlexibleFoo::Tag::kS:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::FlexibleFoo::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3870,8 +3870,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::StrictFoo, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::StrictFoo* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -3896,10 +3896,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::StrictFoo::Tag::kS
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::StrictFoo::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -3943,10 +3943,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::StrictFoo::Tag::kS:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::StrictFoo::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -3995,8 +3995,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::ExplicitFoo, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::ExplicitFoo* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4021,10 +4021,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::ExplicitFoo::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::ExplicitFoo::Tag::kS
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4068,10 +4068,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::ExplicitFoo::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::ExplicitFoo::Tag::kS:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4120,8 +4120,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::ExplicitStrictFoo, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::ExplicitStrictFoo* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4146,10 +4146,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 2: // ::test_union::wire::ExplicitStrictFoo::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_union::wire::ExplicitStrictFoo::Tag::kS
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4193,10 +4193,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::ExplicitStrictFoo::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::ExplicitStrictFoo::Tag::kS:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4245,8 +4245,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::OlderSimpleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::OlderSimpleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4271,10 +4271,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::OlderSimpleUnion::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::OlderSimpleUnion::Tag::kF
-        encode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4318,10 +4318,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::OlderSimpleUnion::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::OlderSimpleUnion::Tag::kF:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4370,8 +4370,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::NewerSimpleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::NewerSimpleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4396,13 +4396,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::NewerSimpleUnion::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::NewerSimpleUnion::Tag::kS
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_union::wire::NewerSimpleUnion::Tag::kV
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4449,13 +4449,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::NewerSimpleUnion::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::NewerSimpleUnion::Tag::kS:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::NewerSimpleUnion::Tag::kV:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<::fidl::StringView>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintString<false>, false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4507,8 +4507,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::StrictSimpleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::StrictSimpleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4533,13 +4533,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::StrictSimpleUnion::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_union::wire::StrictSimpleUnion::Tag::kF
-        encode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_union::wire::StrictSimpleUnion::Tag::kS
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4586,13 +4586,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::StrictSimpleUnion::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::StrictSimpleUnion::Tag::kF:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::StrictSimpleUnion::Tag::kS:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::StringView, fidl::internal::WireCodingConstraintString<false>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4644,8 +4644,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::UnionContainingEmptyStruct, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::UnionContainingEmptyStruct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4670,7 +4670,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::UnionContainingEmptyStruct::Tag::kEmpty
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4711,7 +4711,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::UnionContainingEmptyStruct::Tag::kEmpty:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_union::wire::Empty, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4757,8 +4757,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::StrictBoundedUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::StrictBoundedUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4783,7 +4783,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::StrictBoundedUnion::Tag::kV
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 10>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 10>, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4824,7 +4824,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::StrictBoundedUnion::Tag::kV:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 10>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false, 10>, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4870,8 +4870,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::ExplicitFlexibleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::ExplicitFlexibleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -4896,10 +4896,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::ExplicitFlexibleUnion::Tag::kI
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 4: // ::test_union::wire::ExplicitFlexibleUnion::Tag::kF
-        encode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -4943,10 +4943,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::ExplicitFlexibleUnion::Tag::kI:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_union::wire::ExplicitFlexibleUnion::Tag::kF:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<float, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -4995,8 +4995,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::UnionWithAttributes, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::UnionWithAttributes* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -5021,7 +5021,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_union::wire::UnionWithAttributes::Tag::kX
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -5062,7 +5062,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_union::wire::UnionWithAttributes::Tag::kX:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int64_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -5108,8 +5108,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_union::wire::EmptyFlexibleUnion, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_union::wire::EmptyFlexibleUnion* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
diff --git a/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_driver_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_driver_wire_messaging.h.golden
index 51cd70c..fae5e70 100644
--- a/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_driver_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_driver_wire_messaging.h.golden
@@ -683,7 +683,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -713,7 +713,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -743,7 +743,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -775,7 +775,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -803,7 +803,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -829,7 +829,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -864,7 +864,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -896,7 +896,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -921,7 +921,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -956,7 +956,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -988,7 +988,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1013,7 +1013,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1048,7 +1048,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1080,7 +1080,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1105,7 +1105,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1140,7 +1140,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1172,7 +1172,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1197,7 +1197,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1232,7 +1232,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1264,7 +1264,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1289,7 +1289,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1324,7 +1324,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1356,7 +1356,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1381,7 +1381,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1416,7 +1416,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1448,7 +1448,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1473,7 +1473,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1508,7 +1508,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1540,7 +1540,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1565,7 +1565,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1600,7 +1600,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1632,7 +1632,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1657,7 +1657,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1692,7 +1692,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1724,7 +1724,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1749,7 +1749,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1784,7 +1784,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1816,7 +1816,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1841,7 +1841,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1876,7 +1876,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1908,7 +1908,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1933,7 +1933,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1968,7 +1968,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2000,7 +2000,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2025,7 +2025,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2060,7 +2060,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2092,7 +2092,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2117,7 +2117,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2152,7 +2152,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsDriverProtocol::FlexibleTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5254,7 +5254,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5284,7 +5284,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::FlexibleOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5314,7 +5314,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5346,7 +5346,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5374,7 +5374,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5400,7 +5400,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5435,7 +5435,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5467,7 +5467,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5492,7 +5492,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5527,7 +5527,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5559,7 +5559,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5584,7 +5584,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5619,7 +5619,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5651,7 +5651,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5676,7 +5676,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5711,7 +5711,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5743,7 +5743,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5768,7 +5768,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5803,7 +5803,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5835,7 +5835,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5860,7 +5860,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5895,7 +5895,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5927,7 +5927,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -5952,7 +5952,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -5987,7 +5987,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7801,7 +7801,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7831,7 +7831,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7863,7 +7863,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7891,7 +7891,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7917,7 +7917,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7952,7 +7952,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7984,7 +7984,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8009,7 +8009,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -8044,7 +8044,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8076,7 +8076,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8101,7 +8101,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -8136,7 +8136,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8168,7 +8168,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8193,7 +8193,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -8228,7 +8228,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8260,7 +8260,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8285,7 +8285,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -8320,7 +8320,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8352,7 +8352,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8377,7 +8377,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -8412,7 +8412,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8444,7 +8444,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -8469,7 +8469,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -8504,7 +8504,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedDriverProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_wire_messaging.h.golden
index b435016..1624db7 100644
--- a/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_wire_messaging.h.golden
@@ -841,7 +841,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -871,7 +871,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -901,7 +901,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -933,7 +933,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -961,7 +961,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -987,7 +987,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1022,7 +1022,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1054,7 +1054,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1079,7 +1079,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1114,7 +1114,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1146,7 +1146,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1171,7 +1171,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1206,7 +1206,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1238,7 +1238,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1263,7 +1263,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1298,7 +1298,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1330,7 +1330,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1355,7 +1355,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1390,7 +1390,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1422,7 +1422,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1447,7 +1447,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1482,7 +1482,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1514,7 +1514,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1539,7 +1539,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1574,7 +1574,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1606,7 +1606,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1631,7 +1631,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1666,7 +1666,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1698,7 +1698,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1723,7 +1723,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1758,7 +1758,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1790,7 +1790,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1815,7 +1815,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1850,7 +1850,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1882,7 +1882,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1907,7 +1907,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -1942,7 +1942,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1974,7 +1974,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -1999,7 +1999,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2034,7 +2034,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2066,7 +2066,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2091,7 +2091,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2126,7 +2126,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2158,7 +2158,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2183,7 +2183,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2218,7 +2218,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2250,7 +2250,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2275,7 +2275,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2310,7 +2310,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -2343,7 +2343,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2382,7 +2382,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2425,7 +2425,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2468,7 +2468,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::StrictEventTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2505,7 +2505,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2544,7 +2544,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2587,7 +2587,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -2630,7 +2630,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsProtocol::FlexibleEventTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -6816,7 +6816,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6846,7 +6846,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6876,7 +6876,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6908,7 +6908,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6936,7 +6936,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -6962,7 +6962,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -6997,7 +6997,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7029,7 +7029,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7054,7 +7054,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7089,7 +7089,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7121,7 +7121,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7146,7 +7146,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7181,7 +7181,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7213,7 +7213,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7238,7 +7238,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7273,7 +7273,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7305,7 +7305,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7330,7 +7330,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7365,7 +7365,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7397,7 +7397,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7422,7 +7422,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7457,7 +7457,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7489,7 +7489,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7514,7 +7514,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7549,7 +7549,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -7582,7 +7582,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7621,7 +7621,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7664,7 +7664,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7707,7 +7707,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::StrictEventTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7744,7 +7744,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7783,7 +7783,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7826,7 +7826,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -7869,7 +7869,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsAjarProtocol::FlexibleEventTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -10384,7 +10384,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictOneWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictOneWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10414,7 +10414,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10446,7 +10446,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWay>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWay>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10474,7 +10474,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10500,7 +10500,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -10535,7 +10535,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10567,7 +10567,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10592,7 +10592,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -10627,7 +10627,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10659,7 +10659,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10684,7 +10684,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -10719,7 +10719,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10751,7 +10751,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10776,7 +10776,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -10811,7 +10811,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10843,7 +10843,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10868,7 +10868,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -10903,7 +10903,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayFieldsErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10935,7 +10935,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -10960,7 +10960,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -10995,7 +10995,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayUnionErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -11027,7 +11027,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -11052,7 +11052,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::WireResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -11087,7 +11087,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalResponse<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictTwoWayTableErr>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
@@ -11120,7 +11120,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEvent>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEvent>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -11159,7 +11159,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventFields>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 4 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventFields>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -11202,7 +11202,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventUnion>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventUnion>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
@@ -11245,7 +11245,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : public WireStructCodingTraitsBase<::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventTable>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 16 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 16 + sizeof(fidl_message_header_t);
 
   static void Encode(
     internal::WireEncoder* encoder, ::fidl::internal::TransactionalEvent<::test_unknowninteractions::UnknownInteractionsClosedProtocol::StrictEventTable>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
diff --git a/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_wire_types.h.golden
index 35b7653..844dea2 100644
--- a/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/unknown_interactions_wire_types.h.golden
@@ -9515,15 +9515,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -9562,15 +9562,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -9612,15 +9612,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -9659,15 +9659,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -9709,15 +9709,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -9756,15 +9756,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -9806,15 +9806,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -9853,15 +9853,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventFieldsRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventFieldsRequest));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -9900,15 +9900,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventFieldsRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventFieldsRequest));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -9947,15 +9947,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -9994,15 +9994,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -10044,15 +10044,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10091,15 +10091,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventFieldsRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventFieldsRequest));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10138,15 +10138,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventFieldsRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventFieldsRequest));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10185,15 +10185,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10232,15 +10232,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -10282,15 +10282,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10329,15 +10329,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventFieldsRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventFieldsRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventFieldsRequest));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10376,15 +10376,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10423,15 +10423,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -10473,15 +10473,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10520,15 +10520,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -10570,15 +10570,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10617,15 +10617,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -10667,15 +10667,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10714,15 +10714,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10761,15 +10761,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -10811,15 +10811,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10858,15 +10858,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -10905,15 +10905,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 1;
+  static constexpr size_t kInlineSize = 1;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResponse));
     } else {
       internal::WireCodingTraits<uint8_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->__reserved, position + 0, recursion_depth);
@@ -10955,15 +10955,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
     internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResponse));
     } else {
       internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->some_field, position + 0, recursion_depth);
@@ -11003,8 +11003,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11025,7 +11025,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11055,7 +11055,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11093,8 +11093,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11115,7 +11115,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11145,7 +11145,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11183,8 +11183,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11205,7 +11205,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11235,7 +11235,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11273,8 +11273,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11295,7 +11295,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11325,7 +11325,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11363,8 +11363,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventTableRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventTableRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11385,7 +11385,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11415,7 +11415,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11453,8 +11453,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventTableRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventTableRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11475,7 +11475,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11505,7 +11505,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11543,8 +11543,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11565,7 +11565,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11595,7 +11595,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11633,8 +11633,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11655,7 +11655,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11685,7 +11685,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11723,8 +11723,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventTableRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventTableRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11745,7 +11745,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11775,7 +11775,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11813,8 +11813,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventTableRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventTableRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11835,7 +11835,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11865,7 +11865,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11903,8 +11903,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -11925,7 +11925,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -11955,7 +11955,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -11993,8 +11993,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12015,7 +12015,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12045,7 +12045,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12083,8 +12083,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventTableRequest, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventTableRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12105,7 +12105,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12135,7 +12135,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12173,8 +12173,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12195,7 +12195,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12225,7 +12225,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12263,8 +12263,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12285,7 +12285,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12315,7 +12315,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12353,8 +12353,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12375,7 +12375,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12405,7 +12405,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12443,8 +12443,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12465,7 +12465,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12495,7 +12495,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12533,8 +12533,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12555,7 +12555,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12585,7 +12585,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12623,8 +12623,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12645,7 +12645,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12675,7 +12675,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12713,8 +12713,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12735,7 +12735,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12765,7 +12765,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12803,8 +12803,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResponse, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
   : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -12825,7 +12825,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -12855,7 +12855,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -12892,8 +12892,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -12918,7 +12918,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -12959,7 +12959,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13005,8 +13005,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -13031,10 +13031,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -13078,10 +13078,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13130,8 +13130,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -13156,10 +13156,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -13203,10 +13203,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayFieldsErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13255,8 +13255,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -13281,7 +13281,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -13322,7 +13322,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13368,8 +13368,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -13394,10 +13394,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -13441,10 +13441,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayUnionErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13493,8 +13493,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -13519,10 +13519,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -13566,10 +13566,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictTwoWayTableErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13618,8 +13618,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -13644,10 +13644,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -13691,10 +13691,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13743,8 +13743,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -13769,10 +13769,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -13816,10 +13816,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13868,8 +13868,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -13894,7 +13894,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -13935,7 +13935,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -13981,8 +13981,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -14007,10 +14007,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -14054,10 +14054,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -14106,8 +14106,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -14132,10 +14132,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -14179,10 +14179,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -14231,8 +14231,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -14257,13 +14257,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -14310,13 +14310,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayErrResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -14368,8 +14368,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -14394,13 +14394,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -14447,13 +14447,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayFieldsErrResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -14505,8 +14505,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -14531,7 +14531,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -14572,7 +14572,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -14618,8 +14618,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -14644,13 +14644,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -14697,13 +14697,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayUnionErrResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -14755,8 +14755,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -14781,13 +14781,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -14834,13 +14834,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleTwoWayTableErrResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -14892,8 +14892,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventUnionRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventUnionRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -14918,7 +14918,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventUnionRequest::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -14959,7 +14959,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolStrictEventUnionRequest::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15005,8 +15005,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventUnionRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventUnionRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15031,7 +15031,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventUnionRequest::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -15072,7 +15072,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsProtocolFlexibleEventUnionRequest::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15118,8 +15118,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15144,7 +15144,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -15185,7 +15185,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15231,8 +15231,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15257,10 +15257,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -15304,10 +15304,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15356,8 +15356,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15382,10 +15382,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -15429,10 +15429,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayFieldsErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15481,8 +15481,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15507,7 +15507,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -15548,7 +15548,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15594,8 +15594,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15620,10 +15620,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -15667,10 +15667,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayUnionErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15719,8 +15719,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15745,10 +15745,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -15792,10 +15792,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictTwoWayTableErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15844,8 +15844,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventUnionRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventUnionRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15870,7 +15870,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventUnionRequest::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -15911,7 +15911,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolStrictEventUnionRequest::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -15957,8 +15957,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventUnionRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventUnionRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -15983,7 +15983,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventUnionRequest::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16024,7 +16024,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarProtocolFlexibleEventUnionRequest::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -16070,8 +16070,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -16096,7 +16096,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16137,7 +16137,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -16183,8 +16183,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -16209,10 +16209,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16256,10 +16256,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -16308,8 +16308,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -16334,10 +16334,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16381,10 +16381,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayFieldsErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -16433,8 +16433,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -16459,7 +16459,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16500,7 +16500,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -16546,8 +16546,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -16572,10 +16572,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16619,10 +16619,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayUnionErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -16671,8 +16671,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -16697,10 +16697,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16744,10 +16744,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictTwoWayTableErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -16796,8 +16796,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventUnionRequest, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventUnionRequest* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -16822,7 +16822,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventUnionRequest::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16863,7 +16863,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedProtocolStrictEventUnionRequest::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -16909,8 +16909,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -16935,7 +16935,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -16976,7 +16976,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17022,8 +17022,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -17048,10 +17048,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -17095,10 +17095,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17147,8 +17147,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -17173,10 +17173,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -17220,10 +17220,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayFieldsErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17272,8 +17272,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -17298,7 +17298,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -17339,7 +17339,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17385,8 +17385,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -17411,10 +17411,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -17458,10 +17458,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayUnionErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17510,8 +17510,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -17536,10 +17536,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -17583,10 +17583,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolStrictTwoWayTableErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17635,8 +17635,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -17661,10 +17661,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -17708,10 +17708,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17760,8 +17760,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -17786,10 +17786,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -17833,10 +17833,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17885,8 +17885,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -17911,7 +17911,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -17952,7 +17952,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -17998,8 +17998,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -18024,10 +18024,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -18071,10 +18071,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -18123,8 +18123,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -18149,10 +18149,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -18196,10 +18196,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -18248,8 +18248,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -18274,13 +18274,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -18327,13 +18327,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayErrResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -18385,8 +18385,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -18411,13 +18411,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -18464,13 +18464,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayFieldsErrResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -18522,8 +18522,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -18548,7 +18548,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -18589,7 +18589,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -18635,8 +18635,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -18661,13 +18661,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -18714,13 +18714,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayUnionErrResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -18772,8 +18772,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -18798,13 +18798,13 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 3: // ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResult::Tag::kFrameworkErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -18851,13 +18851,13 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsDriverProtocolFlexibleTwoWayTableErrResult::Tag::kFrameworkErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::fidl::internal::FrameworkErr, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -18909,8 +18909,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -18935,7 +18935,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -18976,7 +18976,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19022,8 +19022,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -19048,10 +19048,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -19095,10 +19095,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19147,8 +19147,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -19173,10 +19173,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -19220,10 +19220,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayFieldsErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19272,8 +19272,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -19298,7 +19298,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -19339,7 +19339,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19385,8 +19385,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -19411,10 +19411,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -19458,10 +19458,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19510,8 +19510,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -19536,10 +19536,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -19583,10 +19583,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsAjarDriverProtocolStrictTwoWayTableErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19635,8 +19635,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -19661,7 +19661,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -19702,7 +19702,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19748,8 +19748,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -19774,10 +19774,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -19821,10 +19821,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19873,8 +19873,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -19899,10 +19899,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -19946,10 +19946,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayFieldsErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -19998,8 +19998,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResponse, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResponse* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -20024,7 +20024,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -20065,7 +20065,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResponse::Tag::kSomeField:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -20111,8 +20111,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -20137,10 +20137,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -20184,10 +20184,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResponse, fidl::internal::WireCodingConstraintUnion<false>, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
@@ -20236,8 +20236,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResult, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResult* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -20262,10 +20262,10 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResult::Tag::kResponse
-        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case 2: // ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResult::Tag::kErr
-        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -20309,10 +20309,10 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResult::Tag::kResponse:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResponse, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       case ::test_unknowninteractions::wire::UnknownInteractionsClosedDriverProtocolStrictTwoWayTableErrResult::Tag::kErr:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<int32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_cpp/goldens/vectors_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/vectors_wire_types.h.golden
index 6fb55a8..e1c4b8c 100644
--- a/tools/fidl/fidlgen_cpp/goldens/vectors_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/vectors_wire_types.h.golden
@@ -66,15 +66,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_vectors::wire::ExampleUseOfVectors, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 32;
+  static constexpr size_t kInlineSize = 32;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>(), ::fidl::internal::WireStructMemberCodingInfo<::fidl::VectorView<::fidl::VectorView<bool>>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, false>, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_vectors::wire::ExampleUseOfVectors, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_vectors::wire::ExampleUseOfVectors* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_vectors::wire::ExampleUseOfVectors));
     } else {
       internal::WireCodingTraits<::fidl::VectorView<uint8_t>, fidl::internal::WireCodingConstraintVector<fidl::internal::WireCodingConstraintEmpty, false>, IsRecursive>::Encode(encoder, &value->vector_of_uint8, position + 0, recursion_depth);
diff --git a/tools/fidl/fidlgen_cpp/goldens/versions_natural_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/versions_natural_types.h.golden
index f715944d..b2fdb76 100644
--- a/tools/fidl/fidlgen_cpp/goldens/versions_natural_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/versions_natural_types.h.golden
@@ -327,8 +327,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_versions::Bits, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_versions::Bits* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_versions::Bits>(offset) = *value;
@@ -340,8 +340,8 @@
 
 template <>
 struct internal::NaturalCodingTraits<::test_versions::Enum, ::fidl::internal::NaturalCodingConstraintEmpty> {
-  static constexpr size_t inline_size_v2 = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::NaturalEncoder* encoder, ::test_versions::Enum* value, size_t offset, size_t recursion_depth) {
     *encoder->template GetPtr<::test_versions::Enum>(offset) = *value;
diff --git a/tools/fidl/fidlgen_cpp/goldens/versions_wire_messaging.h.golden b/tools/fidl/fidlgen_cpp/goldens/versions_wire_messaging.h.golden
index 1aab99c..b66ea8a 100644
--- a/tools/fidl/fidlgen_cpp/goldens/versions_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/versions_wire_messaging.h.golden
@@ -243,7 +243,7 @@
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::fidl::internal::TransactionalRequest<::test_versions::Protocol::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : public WireStructCodingTraitsBase<::fidl::internal::TransactionalRequest<::test_versions::Protocol::Foo>, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 0 + sizeof(fidl_message_header_t);
+  static constexpr size_t kInlineSize = 0 + sizeof(fidl_message_header_t);
 
   static void Encode(internal::WireEncoder* encoder, ::fidl::internal::TransactionalRequest<::test_versions::Protocol::Foo>* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<fidl_message_header_t>() = value->header;
diff --git a/tools/fidl/fidlgen_cpp/goldens/versions_wire_types.h.golden b/tools/fidl/fidlgen_cpp/goldens/versions_wire_types.h.golden
index 585624e..62a101c 100644
--- a/tools/fidl/fidlgen_cpp/goldens/versions_wire_types.h.golden
+++ b/tools/fidl/fidlgen_cpp/goldens/versions_wire_types.h.golden
@@ -310,8 +310,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_versions::wire::Bits, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_versions::wire::Bits* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_versions::wire::Bits>() = *value;
@@ -322,8 +322,8 @@
 
 template <bool IsRecursive>
 struct internal::WireCodingTraits<::test_versions::wire::Enum, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = sizeof(uint32_t);
-  static constexpr bool is_memcpy_compatible = true;
+  static constexpr size_t kInlineSize = sizeof(uint32_t);
+  static constexpr bool kIsMemcpyCompatible = true;
 
   static void Encode(internal::WireEncoder* encoder, ::test_versions::wire::Enum* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     *position.As<::test_versions::wire::Enum>() = *value;
@@ -355,15 +355,15 @@
 
 template <bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_versions::wire::Struct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive> {
-  static constexpr size_t inline_size = 4;
+  static constexpr size_t kInlineSize = 4;
   static constexpr auto kMembers = std::make_tuple(::fidl::internal::WireStructMemberCodingInfo<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>());
   static constexpr bool kHasPadding = false;
   using Base = WireStructCodingTraitsBase<::test_versions::wire::Struct, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>;
-  static constexpr bool is_memcpy_compatible = Base::is_memcpy_compatible;
+  static constexpr bool kIsMemcpyCompatible = Base::kIsMemcpyCompatible;
 
   static void Encode(
       internal::WireEncoder* encoder, ::test_versions::wire::Struct* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
-    if constexpr (is_memcpy_compatible) {
+    if constexpr (kIsMemcpyCompatible) {
       memcpy(position.As<void>(), value, sizeof(::test_versions::wire::Struct));
     } else {
       internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::Encode(encoder, &value->x, position + 0, recursion_depth);
@@ -401,8 +401,8 @@
 struct ::fidl::internal::WireCodingTraits<::test_versions::wire::Table, ::fidl::internal::WireCodingConstraintEmpty, IsRecursive>
     : ::fidl::internal::WireTableCodingTraitsBase<IsRecursive> {
   using Base = ::fidl::internal::WireTableCodingTraitsBase<IsRecursive>;
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_versions::wire::Table* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     RecursionDepth<IsRecursive> inner_depth = recursion_depth.Add(encoder, 2);
@@ -422,7 +422,7 @@
       size_t encode_inline_size = 0;
       switch (i) {
         case 0:
-          encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       ::fidl::internal::EncodeFn<IsRecursive> encode_fn = nullptr;
@@ -451,7 +451,7 @@
       size_t decode_inline_size = 0;
       switch (i) {
         case 0:
-          decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+          decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
           break;
       }
       DecodeFn<IsRecursive> decode_fn = nullptr;
@@ -486,8 +486,8 @@
 
 template <typename Constraint, bool IsRecursive>
 struct ::fidl::internal::WireCodingTraits<::test_versions::wire::Union, Constraint, IsRecursive> {
-  static constexpr size_t inline_size = 16;
-  static constexpr bool is_memcpy_compatible = false;
+  static constexpr size_t kInlineSize = 16;
+  static constexpr bool kIsMemcpyCompatible = false;
 
   static void Encode(internal::WireEncoder* encoder, ::test_versions::wire::Union* value, ::fidl::internal::WirePosition position, RecursionDepth<IsRecursive> recursion_depth) {
     fidl_union_t* u = reinterpret_cast<fidl_union_t*>(value);
@@ -511,7 +511,7 @@
     size_t encode_inline_size;
     switch (u->tag) {
       case 1:  // ::test_versions::wire::Union::Tag::kX
-        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        encode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         encode_inline_size = 0;
@@ -551,7 +551,7 @@
     size_t decode_inline_size;
     switch (tag) {
       case ::test_versions::wire::Union::Tag::kX:
-        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::inline_size;
+        decode_inline_size = ::fidl::internal::WireCodingTraits<uint32_t, fidl::internal::WireCodingConstraintEmpty, IsRecursive>::kInlineSize;
         break;
       default:
         decode_inline_size = 0;
diff --git a/tools/fidl/fidlgen_go/codegen/bits.tmpl b/tools/fidl/fidlgen_go/codegen/bits.tmpl
index 6f560cf..2bd9f80 100644
--- a/tools/fidl/fidlgen_go/codegen/bits.tmpl
+++ b/tools/fidl/fidlgen_go/codegen/bits.tmpl
@@ -5,55 +5,57 @@
 */}}
 
 {{- define "BitsDefinition" -}}
-{{range .DocComments}}
-//{{ . }}
-{{- end}}
-type {{ .Name }} {{ .Type }}
+{{- $bits := . }}
+
+{{ range $comment := $bits.DocComments }}
+//{{ $comment }}
+{{- end }}
+type {{ $bits.Name }} {{ $bits.Type }}
 const (
-	{{- range .Members }}
-	{{ $.Name }}{{ .Name }} {{ $.Name }} = {{ .Value }}
+	{{- range $memb := $bits.Members }}
+	{{ $bits.Name }}{{ $memb.Name }} {{ $bits.Name }} = {{ $memb.Value }}
 	{{- end }}
-	{{ .Name }}_Mask {{ .Name }} = {{ .Mask }}
+	{{ $bits.Name }}_Mask {{ $bits.Name }} = {{ $bits.Mask }}
 )
 
-func (_ {{ .Name }}) I_BitsMask() {{ .Name }} {
-	return {{ .Name }}_Mask
+func (_ {{ $bits.Name }}) I_BitsMask() {{ $bits.Name }} {
+	return {{ $bits.Name }}_Mask
 }
 
-func (_ {{ .Name }}) I_BitsIsStrict() bool {
-	return {{ .IsStrict }}
+func (_ {{ $bits.Name }}) I_BitsIsStrict() bool {
+	return {{ $bits.IsStrict }}
 }
 
-func (x {{ .Name }}) HasUnknownBits() bool {
+func (x {{ $bits.Name }}) HasUnknownBits() bool {
 	return x.GetUnknownBits() != 0
 }
 
-func (x {{ .Name }}) GetUnknownBits() uint64 {
-	return uint64(^{{ .Name }}_Mask & x)
+func (x {{ $bits.Name }}) GetUnknownBits() uint64 {
+	return uint64(^{{ $bits.Name }}_Mask & x)
 }
 
-func (x {{ .Name }}) InvertBits() {{ .Name }} {
-	return {{ .Name }}_Mask & ^x
+func (x {{ $bits.Name }}) InvertBits() {{ $bits.Name }} {
+	return {{ $bits.Name }}_Mask & ^x
 }
 
 // HasBits validates that all flipped bits in the mask are set.
-func (x {{ .Name }}) HasBits(mask {{ .Name }}) bool {
+func (x {{ $bits.Name }}) HasBits(mask {{ $bits.Name }}) bool {
 	return mask | x == x
 }
 
 // ClearBits ensures all flipped bits in the mask are unset.
-func (x {{ .Name }}) ClearBits(mask {{ .Name }}) {{ .Name }} {
+func (x {{ $bits.Name }}) ClearBits(mask {{ $bits.Name }}) {{ $bits.Name }} {
 	return ^mask & x
 }
 
-func (x {{.Name}}) String() string {
+func (x {{ $bits.Name }}) String() string {
 	var buf _strings.Builder
-	{{- range .Members }}
-	if {{ .Value }} & x != 0 {
+	{{- range $memb := $bits.Members }}
+	if {{ $memb.Value }} & x != 0 {
 		if buf.Len() != 0 {
 			buf.WriteRune('|')
 		}
-		buf.WriteString("{{.Name}}")
+		buf.WriteString("{{ $memb.Name }}")
 	}
 	{{- end }}
 	if buf.Len() == 0 {
diff --git a/tools/fidl/fidlgen_go/codegen/enum.tmpl b/tools/fidl/fidlgen_go/codegen/enum.tmpl
index 46f2c07..7605c21 100644
--- a/tools/fidl/fidlgen_go/codegen/enum.tmpl
+++ b/tools/fidl/fidlgen_go/codegen/enum.tmpl
@@ -5,45 +5,47 @@
 */}}
 
 {{- define "EnumDefinition" -}}
-{{range .DocComments}}
-//{{ . }}
-{{- end}}
-type {{ .Name }} {{ .Type }}
+{{- $enum := . }}
+
+{{ range $comment := .DocComments }}
+//{{ $comment }}
+{{- end }}
+type {{ $enum.Name }} {{ $enum.Type }}
 
 const (
-	{{- range .Members }}
-	{{ if .DocComments -}}
-	{{range .DocComments}}
-	//{{ . }}
-	{{- end}}
+	{{- range $memb := $enum.Members }}
+	{{ if $memb.DocComments -}}
+	{{ range $comment := $memb.DocComments }}
+	//{{ $comment }}
+	{{- end }}
 	{{ end -}}
-	{{ $.Name }}{{ .Name }} {{ $.Name }} = {{ .Value }}
+	{{ $enum.Name }}{{ $memb.Name }} {{ $enum.Name }} = {{ $memb.Value }}
 	{{- end }}
 
-{{ if .IsFlexible }}
-	// {{ .Name }}_Unknown is the default unknown placeholder.
-	{{ .Name }}_Unknown {{ .Name }} = {{ .UnknownValueForTmpl | printf "%#x" }}
+{{ if $enum.IsFlexible }}
+	// {{ $enum.Name }}_Unknown is the default unknown placeholder.
+	{{ $enum.Name }}_Unknown {{ $enum.Name }} = {{ $enum.UnknownValueForTmpl | printf "%#x" }}
 {{ end }}
 )
 
-func (_ {{.Name}}) I_EnumValues() []{{.Name}} {
-	return []{{.Name}}{
-		{{- range .Members }}
-		{{ $.Name }}{{ .Name }},
+func (_ {{ $enum.Name }}) I_EnumValues() []{{ $enum.Name }} {
+	return []{{ $enum.Name }}{
+		{{- range $memb := $enum.Members }}
+		{{ $enum.Name }}{{ $memb.Name }},
 		{{- end }}
 	}
 }
 
-func (_ {{.Name}}) I_EnumIsStrict() bool {
-	return {{ .IsStrict }}
+func (_ {{ $enum.Name }}) I_EnumIsStrict() bool {
+	return {{ $enum.IsStrict }}
 }
 
-func (x {{.Name}}) IsUnknown() bool {
-	{{- if .Members }}
+func (x {{ $enum.Name }}) IsUnknown() bool {
+	{{- if $enum.Members }}
 	switch x {
-		{{- range .Members }}
-		{{- if not .IsUnknown }}
-		case {{ .Value }}:
+		{{- range $memb := $enum.Members }}
+		{{- if not $memb.IsUnknown }}
+		case {{ $memb.Value }}:
 			return false
 		{{- end }}
 		{{- end }}
@@ -52,12 +54,12 @@
 	return true
 }
 
-func (x {{.Name}}) String() string {
-	{{- if .Members }}
+func (x {{ $enum.Name }}) String() string {
+	{{- if $enum.Members }}
 	switch x {
-	{{- range .Members }}
-	case {{ .Value }}:
-		return "{{.Name}}"
+	{{- range $memb := $enum.Members }}
+	case {{ $memb.Value }}:
+		return "{{ $memb.Name }}"
 	{{- end }}
 	}
 	{{- end }}
diff --git a/tools/fidl/fidlgen_go/codegen/library.tmpl b/tools/fidl/fidlgen_go/codegen/library.tmpl
index 06d790d..a15cbfd 100644
--- a/tools/fidl/fidlgen_go/codegen/library.tmpl
+++ b/tools/fidl/fidlgen_go/codegen/library.tmpl
@@ -5,54 +5,56 @@
 */}}
 
 {{- define "GenerateLibraryFile" -}}
+{{- $root := . }}
+
 // WARNING: This file is machine generated by fidlgen.
-{{ range $experiment := .Experiments }}
+{{ range $experiment := $root.Experiments }}
 // fidl_experiment = {{ $experiment }}
 {{- end }}
 
-package {{ .Name }}
+package {{ $root.Name }}
 
-{{if .Libraries}}
+{{ if $root.Libraries }}
 import (
-{{- range .Libraries }}
-	{{ .Alias }} "{{ .Path }}"
+{{- range $lib := $root.Libraries }}
+	{{ $lib.Alias }} "{{ $lib.Path }}"
 {{- end }}
 )
-{{end}}
+{{ end }}
 
-{{if .Consts}}
+{{ if $root.Consts }}
 const (
-{{- range $const := .Consts }}
-	{{- range .DocComments}}
-	//{{ . }}
-	{{- end}}
-	{{ .Name }} {{ .Type }} = {{ .Value }}
+{{- range $const := $root.Consts }}
+	{{- range $comment := $const.DocComments }}
+	//{{ $comment }}
+	{{- end }}
+	{{ $const.Name }} {{ $const.Type }} = {{ $const.Value }}
 {{- end }}
 )
-{{end}}
+{{ end }}
 
-{{ range .Aliases -}}
-type {{ .Name }} = {{ .Type }}
+{{ range $alias := $root.Aliases -}}
+type {{ $alias.Name }} = {{ $alias.Type }}
 {{ end -}}
-{{ range .Enums -}}
-var _ {{ $.BindingsAlias }}.Enum = {{ .Name }}(0)
-{{ template "EnumDefinition" . }}
+{{ range $enum := $root.Enums -}}
+var _ {{ $root.BindingsAlias }}.Enum = {{ $enum.Name }}(0)
+{{ template "EnumDefinition" $enum }}
 {{ end -}}
-{{ range .Bits -}}
-var _ {{ $.BindingsAlias }}.Bits = {{ .Name }}(0)
-{{ template "BitsDefinition" . }}
+{{ range $bits := $root.Bits -}}
+var _ {{ $root.BindingsAlias }}.Bits = {{ $bits.Name }}(0)
+{{ template "BitsDefinition" $bits }}
 {{ end -}}
-{{ range .Structs -}}
-{{ template "StructDefinition" . }}
+{{ range $struct := $root.Structs -}}
+{{ template "StructDefinition" $struct }}
 {{ end -}}
-{{ range .Unions -}}
-{{ template "UnionDefinition" . }}
+{{ range $union := $root.Unions -}}
+{{ template "UnionDefinition" $union }}
 {{ end -}}
-{{ range .Tables -}}
-{{ template "TableDefinition" . }}
+{{ range $table := $root.Tables -}}
+{{ template "TableDefinition" $table }}
 {{ end -}}
-{{ range $protocol := .Protocols -}}
-{{ range $transport, $_ := .Transports -}}{{ if eq $transport "Channel" -}}
+{{ range $protocol := $root.Protocols -}}
+{{ range $transport, $_ := $protocol.Transports -}}{{ if eq $transport "Channel" -}}
 {{ template "ProtocolDefinition" $protocol }}
 {{ end }}{{ end }}{{ end -}}
 
diff --git a/tools/fidl/fidlgen_go/codegen/protocol.tmpl b/tools/fidl/fidlgen_go/codegen/protocol.tmpl
index 55e686e..0b5b45a 100644
--- a/tools/fidl/fidlgen_go/codegen/protocol.tmpl
+++ b/tools/fidl/fidlgen_go/codegen/protocol.tmpl
@@ -5,64 +5,65 @@
 */}}
 
 {{- define "ProtocolDefinition" -}}
+{{- $protocol := . }}
 
 const (
-{{- range .Methods }}
-	{{ .OrdinalName }} uint64 = {{ .Ordinal | printf "%#x" }}
+{{- range $method := $protocol.Methods }}
+	{{ $method.OrdinalName }} uint64 = {{ $method.Ordinal | printf "%#x" }}
 {{- end }}
 )
 
-{{ if .Openness.IsClosed -}}
-type {{ .ProxyName }} _bindings.{{ .ProxyType }}
-{{ range .Methods }}
-{{range .DocComments}}
-//{{ . }}
-{{- end}}
-func (p *{{ $.ProxyName }}) {{ if .IsEvent -}}
-		{{ .EventExpectName }}
+{{ if $protocol.Openness.IsClosed -}}
+type {{ $protocol.ProxyName }} _bindings.{{ $protocol.ProxyType }}
+{{ range $method := $protocol.Methods }}
+{{ range $comment := $method.DocComments }}
+//{{ $comment }}
+{{- end }}
+func (p *{{ $.ProxyName }}) {{ if $method.IsEvent -}}
+		{{ $method.EventExpectName }}
 	{{- else -}}
-		{{ .Name }}
+		{{ $method.Name }}
 	{{- end -}}
-	{{- if .Request -}}
-	(ctx_ _bindings.Context, {{ .Request.NamesAndTypes }})
+	{{- if $method.Request -}}
+	(ctx_ _bindings.Context, {{ $method.Request.NamesAndTypes }})
 	{{- else -}}
 	(ctx_ _bindings.Context)
 	{{- end -}}
-	{{- if .HasResponse -}}
-	{{- if .Response }} ({{ .Response.Types }}, error)
+	{{- if $method.HasResponse -}}
+	{{- if $method.Response }} ({{ $method.Response.Types }}, error)
 	{{- else }} error{{ end -}}
 	{{- else }} error{{ end }} {
 
-	{{- if .HasRequest }}
-	{{- if .Request }}
-	req_ := &{{ .Request.Construct }}
+	{{- if $method.HasRequest }}
+	{{- if $method.Request }}
+	req_ := &{{ $method.Request.Construct }}
 	{{- else }}
 	var req_ _bindings.Message
 	{{- end }}
 	{{- end }}
-	{{- if .HasResponse }}
-	{{- if .Response }}
-	resp_ := &{{ .Response.Name }}{}
+	{{- if $method.HasResponse }}
+	{{- if $method.Response }}
+	resp_ := &{{ $method.Response.Name }}{}
 	{{- else }}
 	var resp_ _bindings.Message
 	{{- end }}
 	{{- end }}
-	{{- if .HasRequest }}
-		{{- if .HasResponse }}
-	err_ := ((*_bindings.{{ $.ProxyType }})(p)).Call({{ .OrdinalName }}, req_, resp_)
+	{{- if $method.HasRequest }}
+		{{- if $method.HasResponse }}
+	err_ := ((*_bindings.{{ $protocol.ProxyType }})(p)).Call({{ $method.OrdinalName }}, req_, resp_)
 		{{- else }}
-	err_ := ((*_bindings.{{ $.ProxyType }})(p)).Send({{ .OrdinalName }}, req_)
+	err_ := ((*_bindings.{{ $protocol.ProxyType }})(p)).Send({{ $method.OrdinalName }}, req_)
 		{{- end }}
 	{{- else }}
-		{{- if .HasResponse }}
-	err_ := ((*_bindings.{{ $.ProxyType }})(p)).Recv({{ .OrdinalName }}, resp_)
+		{{- if $method.HasResponse }}
+	err_ := ((*_bindings.{{ $protocol.ProxyType }})(p)).Recv({{ $method.OrdinalName }}, resp_)
 		{{- else }}
 	err_ := nil
 		{{- end }}
 	{{- end }}
-	{{- if .HasResponse }}
-	{{- if .Response }}
-	return {{ call .Response.Destructure "(*resp_)" }}, err_
+	{{- if $method.HasResponse }}
+	{{- if $method.Response }}
+	return {{ call $method.Response.Destructure "(*resp_)" }}, err_
 	{{- else }}
 	return err_
 	{{- end }}
@@ -72,61 +73,61 @@
 }
 {{- end }}
 
-{{range .DocComments}}
-//{{ . }}
-{{- end}}
-type {{ .Name }} interface {
-{{- range .Methods }}
-	{{- range .DocComments}}
-	//{{ . }}
-	{{- end}}
-	{{- if .HasRequest }}
-	{{- if .Request }}
-	{{ .Name }}(ctx_ _bindings.Context, {{ .Request.NamesAndTypes }})
-	{{- else }}
-	{{ .Name }}(ctx_ _bindings.Context)
+{{ range $comment := .DocComments }}
+//{{ $comment }}
+{{- end }}
+type {{ $protocol.Name }} interface {
+{{- range $method := $protocol.Methods }}
+	{{- range $comment := $method.DocComments }}
+	//{{ $comment }}
 	{{- end }}
-	{{- if .HasResponse -}}
-	{{- if .Response }} ({{ .Response.Types }}, error)
+	{{- if $method.HasRequest }}
+	{{- if $method.Request }}
+	{{ $method.Name }}(ctx_ _bindings.Context, {{ $method.Request.NamesAndTypes }})
+	{{- else }}
+	{{ $method.Name }}(ctx_ _bindings.Context)
+	{{- end }}
+	{{- if $method.HasResponse -}}
+	{{- if $method.Response }} ({{ $method.Response.Types }}, error)
 	{{- else }} error{{ end -}}
 	{{- else }} error{{ end }}
 	{{- end }}
 {{- end }}
 }
 
-{{- if eq .ProxyType "ChannelProxy" }}
-type {{ .RequestName }} _bindings.InterfaceRequest
+{{- if eq $protocol.ProxyType "ChannelProxy" }}
+type {{ $protocol.RequestName }} _bindings.InterfaceRequest
 
-func New{{ .RequestName }}() ({{ .RequestName }}, *{{ .ProxyName }}, error) {
+func New{{ $protocol.RequestName }}() ({{ $protocol.RequestName }}, *{{ $protocol.ProxyName }}, error) {
 	req, cli, err := _bindings.NewInterfaceRequest()
-	return {{ .RequestName }}(req), (*{{ .ProxyName }})(cli), err
+	return {{ $protocol.RequestName }}(req), (*{{ $protocol.ProxyName }})(cli), err
 }
 
-{{- if .ProtocolNameString }}
+{{- if $protocol.ProtocolNameString }}
 // Implements ServiceRequest.
-func (_ {{ .RequestName }}) Name() string {
-	return {{ .ProtocolNameString }}
+func (_ {{ $protocol.RequestName }}) Name() string {
+	return {{ $protocol.ProtocolNameString }}
 }
-func (c {{ .RequestName }}) ToChannel() _zx.Channel {
+func (c {{ $protocol.RequestName }}) ToChannel() _zx.Channel {
 	return c.Channel
 }
 
-const {{ .ProtocolNameConstant }} = {{ .ProtocolNameString }}
+const {{ $protocol.ProtocolNameConstant }} = {{ $protocol.ProtocolNameString }}
 {{- end }}
 {{- end }}
 
-type {{ .StubName }} struct {
-	Impl {{ .Name }}
+type {{ $protocol.StubName }} struct {
+	Impl {{ $protocol.Name }}
 }
 
-func (s_ *{{ .StubName }}) Dispatch(args_ _bindings.DispatchArgs) (_bindings.Message, bool, error) {
+func (s_ *{{ $protocol.StubName }}) Dispatch(args_ _bindings.DispatchArgs) (_bindings.Message, bool, error) {
 	switch args_.Ordinal {
-	{{- range .Methods }}
-	{{- if not .IsEvent }}
-	case {{ .OrdinalName }}:
-		{{- if .HasRequest }}
-		{{- if .Request }}
-		in_ := &{{ .Request.Name }}{}
+	{{- range $method := $protocol.Methods }}
+	{{- if not $method.IsEvent }}
+	case {{ $method.OrdinalName }}:
+		{{- if $method.HasRequest }}
+		{{- if $method.Request }}
+		in_ := &{{ $method.Request.Name }}{}
 		marshalerCtx, ok := _bindings.GetMarshalerContext(args_.Ctx)
 		if !ok {
 			return nil, false, _bindings.ErrMissingMarshalerContext
@@ -136,15 +137,15 @@
 		}
 		{{- end }}
 		{{- end }}
-		{{ if .Response }}{{- .Response.Names -}}, {{- end -}}
-		{{- if .Request -}}
-		err_ := s_.Impl.{{ .Name }}(args_.Ctx, {{ call .Request.Destructure "(*in_)" -}})
+		{{ if $method.Response }}{{- $method.Response.Names -}}, {{- end -}}
+		{{- if $method.Request -}}
+		err_ := s_.Impl.{{ $method.Name }}(args_.Ctx, {{ call $method.Request.Destructure "(*in_)" -}})
 		{{- else -}}
-		err_ := s_.Impl.{{ .Name }}(args_.Ctx)
+		err_ := s_.Impl.{{ $method.Name }}(args_.Ctx)
 		{{- end -}}
-		{{- if .HasResponse }}
-		{{- if .Response }}
-		out_ := &{{ .Response.Construct }}
+		{{- if $method.HasResponse }}
+		{{- if $method.Response }}
+		out_ := &{{ $method.Response.Construct }}
 		return out_, true, err_
 		{{- else }}
 		return nil, true, err_
@@ -158,67 +159,67 @@
 	return nil, false, _bindings.ErrUnknownOrdinal
 }
 
-type {{ .EventProxyName }} _bindings.{{ .ProxyType }}
-{{ range .Methods }}
-{{- if .IsEvent }}
-func (p *{{ $.EventProxyName }}) {{ .Name }}(
-	{{- if .Response -}}
-	{{- .Response.NamesAndTypes -}}
+type {{ $protocol.EventProxyName }} _bindings.{{ $protocol.ProxyType }}
+{{ range $method := $protocol.Methods }}
+{{- if $method.IsEvent }}
+func (p *{{ $protocol.EventProxyName }}) {{ $method.Name }}(
+	{{- if $method.Response -}}
+	{{- $method.Response.NamesAndTypes -}}
 	{{- end -}}
 	) error {
 
-	{{- if .HasResponse }}
-	{{- if .Response }}
-	event_ := &{{ .Response.Construct }}
+	{{- if $method.HasResponse }}
+	{{- if $method.Response }}
+	event_ := &{{ $method.Response.Construct }}
 	{{- else }}
 	var event_ _bindings.Message
 	{{- end }}
 	{{- end }}
-	return ((*_bindings.{{ $.ProxyType }})(p)).Send({{ .OrdinalName }}, event_)
+	return ((*_bindings.{{ $protocol.ProxyType }})(p)).Send({{ $method.OrdinalName }}, event_)
 }
 {{- end }}
 {{- end }}
-{{- else }}{{/* end of if .Openness.IsClosed */}}
+{{- else }}{{/* end of if $protocol.Openness.IsClosed */}}
 // Bindings for this protocol have not been generated because it is an
-// {{ .Openness }} protocol. If bindings for {{ .Openness }} protocols are
+// {{ $protocol.Openness }} protocol. If bindings for {{ $protocol.Openness }} protocols are
 // needed in Go, please contact the FIDL team: fidl-dev@fuchsia.dev.
-type {{ .ProxyName }} _bindings.{{ .ProxyType }}
+type {{ $protocol.ProxyName }} _bindings.{{ $protocol.ProxyType }}
 
 // Bindings for this protocol have not been generated because it is an
-// {{ .Openness }} protocol. If bindings for {{ .Openness }} protocols are
+// {{ $protocol.Openness }} protocol. If bindings for {{ $protocol.Openness }} protocols are
 // needed in Go, please contact the FIDL team: fidl-dev@fuchsia.dev.
-type {{ .Name }} interface {}
+type {{ $protocol.Name }} interface {}
 
-{{- if eq .ProxyType "ChannelProxy" }}
-type {{ .RequestName }} _bindings.InterfaceRequest
+{{- if eq $protocol.ProxyType "ChannelProxy" }}
+type {{ $protocol.RequestName }} _bindings.InterfaceRequest
 
-func New{{ .RequestName }}() ({{ .RequestName }}, *{{ .ProxyName }}, error) {
+func New{{ $protocol.RequestName }}() ({{ $protocol.RequestName }}, *{{ $protocol.ProxyName }}, error) {
 	req, cli, err := _bindings.NewInterfaceRequest()
-	return {{ .RequestName }}(req), (*{{ .ProxyName }})(cli), err
+	return {{ $protocol.RequestName }}(req), (*{{ $protocol.ProxyName }})(cli), err
 }
 
-{{- if .ProtocolNameString }}
+{{- if $protocol.ProtocolNameString }}
 // Implements ServiceRequest.
-func (_ {{ .RequestName }}) Name() string {
-	return {{ .ProtocolNameString }}
+func (_ {{ $protocol.RequestName }}) Name() string {
+	return {{ $protocol.ProtocolNameString }}
 }
-func (c {{ .RequestName }}) ToChannel() _zx.Channel {
+func (c {{ $protocol.RequestName }}) ToChannel() _zx.Channel {
 	return c.Channel
 }
 
-const {{ .ProtocolNameConstant }} = {{ .ProtocolNameString }}
+const {{ $protocol.ProtocolNameConstant }} = {{ $protocol.ProtocolNameString }}
 {{- end }}
 {{- end }}
 
 // Bindings for this protocol have not been generated because it is an
-// {{ .Openness }} protocol. If bindings for {{ .Openness }} protocols are
+// {{ $protocol.Openness }} protocol. If bindings for {{ $protocol.Openness }} protocols are
 // needed in Go, please contact the FIDL team: fidl-dev@fuchsia.dev.
-type {{ .StubName }} struct {}
+type {{ $protocol.StubName }} struct {}
 
 // Bindings for this protocol have not been generated because it is an
-// {{ .Openness }} protocol. If bindings for {{ .Openness }} protocols are
+// {{ $protocol.Openness }} protocol. If bindings for {{ $protocol.Openness }} protocols are
 // needed in Go, please contact the FIDL team: fidl-dev@fuchsia.dev.
-type {{ .EventProxyName }} struct {}
-{{- end }}{{/* end of else for if .Openness.IsClosed */}}
+type {{ $protocol.EventProxyName }} struct {}
+{{- end }}{{/* end of else for if $protocol.Openness.IsClosed */}}
 
 {{ end -}}
diff --git a/tools/fidl/fidlgen_go/codegen/struct.tmpl b/tools/fidl/fidlgen_go/codegen/struct.tmpl
index a8953ef..a7fda92 100644
--- a/tools/fidl/fidlgen_go/codegen/struct.tmpl
+++ b/tools/fidl/fidlgen_go/codegen/struct.tmpl
@@ -5,22 +5,24 @@
 */}}
 
 {{- define "StructDefinition" -}}
-{{range .DocComments}}
-//{{ . }}
-{{- end}}
-type {{ .Name }} struct {
-	_ struct{} `{{ .Tags }}`
-	{{- range .Members }}
-	{{- range .DocComments}}
-	//{{ . }}
-	{{- end}}
-	{{ .Name }} {{ .Type }} `{{ .Tags }}`
+{{- $struct := . }}
+
+{{ range $comment := $struct.DocComments }}
+//{{ $comment }}
+{{- end }}
+type {{ $struct.Name }} struct {
+	_ struct{} `{{ $struct.Tags }}`
+	{{- range $memb := $struct.Members }}
+	{{- range $comment := $memb.DocComments }}
+	//{{ $comment }}
+	{{- end }}
+	{{ $memb.Name }} {{ $memb.Type }} `{{ $memb.Tags }}`
 	{{- end }}
 }
 
-var _m{{ .Name }} = _bindings.CreateLazyMarshaler({{ .Name }}{})
+var _m{{ $struct.Name }} = _bindings.CreateLazyMarshaler({{ $struct.Name }}{})
 
-func (msg *{{ .Name }}) Marshaler() _bindings.Marshaler {
-	return _m{{ .Name }}
+func (msg *{{ $struct.Name }}) Marshaler() _bindings.Marshaler {
+	return _m{{ $struct.Name }}
 }
 {{- end -}}
diff --git a/tools/fidl/fidlgen_go/codegen/table.tmpl b/tools/fidl/fidlgen_go/codegen/table.tmpl
index 28f1caf..3d292bc 100644
--- a/tools/fidl/fidlgen_go/codegen/table.tmpl
+++ b/tools/fidl/fidlgen_go/codegen/table.tmpl
@@ -5,60 +5,61 @@
 */}}
 
 {{- define "TableDefinition" -}}
-{{range .DocComments}}
-//{{ . }}
-{{- end}}
-type {{ .Name }} struct {
-	_ struct{} `{{ .Tags }}`
+{{- $table := . }}
+
+{{ range $comment := .DocComments }}
+//{{ $comment }}
+{{- end }}
+type {{ $table.Name }} struct {
+	_ struct{} `{{ $table.Tags }}`
 	I_unknownData interface{}
-	{{- range .Members }}
-	{{- range .DocComments}}
-	//{{ . }}
-	{{- end}}
-	{{ .DataField }} {{ .Type }} `{{ .Tags }}`
-	{{ .PresenceField }} bool
+	{{- range $memb := $table.Members }}
+	{{- range $comment := $memb.DocComments }}
+	//{{ $comment }}
+	{{- end }}
+	{{ $memb.DataField }} {{ $memb.Type }} `{{ $memb.Tags }}`
+	{{ $memb.PresenceField }} bool
 	{{- end }}
 }
 
-var _m{{ .Name }} = _bindings.CreateLazyMarshaler({{ .Name }}{})
+var _m{{ $table.Name }} = _bindings.CreateLazyMarshaler({{ $table.Name }}{})
 
-func (msg *{{ .Name }}) Marshaler() _bindings.Marshaler {
-	return _m{{ .Name }}
+func (msg *{{ $table.Name }}) Marshaler() _bindings.Marshaler {
+	return _m{{ $table.Name }}
 }
 
-{{- range .Members }}
-
-func (u *{{ $.Name }}) {{ .Setter }}({{ .PrivateDataField }} {{ .Type }}) {
-	u.{{ .DataField }} = {{ .PrivateDataField }}
-	u.{{ .PresenceField }} = true
+{{ range $memb := .Members }}
+func (u *{{ $table.Name }}) {{ $memb.Setter }}({{ $memb.PrivateDataField }} {{ $memb.Type }}) {
+	u.{{ $memb.DataField }} = {{ $memb.PrivateDataField }}
+	u.{{ $memb.PresenceField }} = true
 }
 
-func (u *{{ $.Name }}) {{ .Getter }}() {{ .Type }} {
-	return u.{{ .DataField }}
+func (u *{{ $table.Name }}) {{ $memb.Getter }}() {{ $memb.Type }} {
+	return u.{{ $memb.DataField }}
 }
 
-func (u *{{ $.Name }}) {{ .GetterWithDefault }}(_default {{ .Type }}) {{ .Type }} {
-	if !u.{{ .Haser }}() {
+func (u *{{ $table.Name }}) {{ $memb.GetterWithDefault }}(_default {{ $memb.Type }}) {{ $memb.Type }} {
+	if !u.{{ $memb.Haser }}() {
 		return _default
 	}
-	return u.{{ .DataField }}
+	return u.{{ $memb.DataField }}
 }
 
-func (u *{{ $.Name }}) {{ .Haser }}() bool {
-	return u.{{ .PresenceField }}
+func (u *{{ $table.Name }}) {{ $memb.Haser }}() bool {
+	return u.{{ $memb.PresenceField }}
 }
 
-func (u *{{ $.Name }}) {{ .Clearer }}() {
-	u.{{ .PresenceField }} = false
+func (u *{{ $table.Name }}) {{ $memb.Clearer }}() {
+	u.{{ $memb.PresenceField }} = false
 }
-{{- end }}
+{{ end }}
 
-func (u *{{ .Name }}) HasUnknownData() bool {
+func (u *{{ $table.Name }}) HasUnknownData() bool {
 	return u.I_unknownData != nil
 }
 
-func (u *{{ .Name }}) GetUnknownData() map[uint64]{{ .UnknownDataType }} {
-	return u.I_unknownData.(map[uint64]{{ .UnknownDataType }})
+func (u *{{ $table.Name }}) GetUnknownData() map[uint64]{{ $table.UnknownDataType }} {
+	return u.I_unknownData.(map[uint64]{{ $table.UnknownDataType }})
 }
 
 {{- end -}}
diff --git a/tools/fidl/fidlgen_go/codegen/union.tmpl b/tools/fidl/fidlgen_go/codegen/union.tmpl
index 553aa76..bf9d7472 100644
--- a/tools/fidl/fidlgen_go/codegen/union.tmpl
+++ b/tools/fidl/fidlgen_go/codegen/union.tmpl
@@ -4,37 +4,39 @@
 // found in the LICENSE file.
 */}}
 
-{{- define "UnionDefinition" -}}
-type {{ .TagName }} uint64
+{{- define "UnionDefinition" }}
+{{- $union := . }}
+
+type {{ $union.TagName }} uint64
 const (
-	{{- if .IsFlexible }}
-	{{ $.Name }}_unknownData = 0  // 0x00000000
+	{{- if $union.IsFlexible }}
+	{{ $union.Name }}_unknownData = 0  // 0x00000000
 	{{- end }}
-	{{- range .Members }}
-	{{ $.Name }}{{ .Name }} = {{ .Ordinal }} // {{ .Ordinal | printf "%#08x" }}
+	{{- range $memb := $union.Members }}
+	{{ $union.Name }}{{ $memb.Name }} = {{ $memb.Ordinal }} // {{ $memb.Ordinal | printf "%#08x" }}
 	{{- end }}
 )
 
-{{range .DocComments}}
-//{{ . }}
-{{- end}}
-type {{ .Name }} struct {
-	{{ .TagName }} `{{ .Tags }}`
-	{{- if .IsFlexible }}
+{{ range $comment := $union.DocComments }}
+//{{ $comment }}
+{{- end }}
+type {{ $union.Name }} struct {
+	{{ $union.TagName }} `{{ $union.Tags }}`
+	{{- if $union.IsFlexible }}
 	I_unknownData interface{}
 	{{- end }}
-	{{- range .Members }}
-	{{- range .DocComments}}
-	//{{ . }}
-	{{- end}}
-	{{ .Name }} {{ .Type }}  `{{ .Tags }}`
+	{{- range $memb := $union.Members }}
+	{{- range $comment := $memb.DocComments }}
+	//{{ $comment }}
+	{{- end }}
+	{{ $memb.Name }} {{ $memb.Type }}  `{{ $memb.Tags }}`
 	{{- end }}
 }
 
-var _m{{ .Name }} = _bindings.CreateLazyMarshaler({{ .Name }}{})
+var _m{{ $union.Name }} = _bindings.CreateLazyMarshaler({{ $union.Name }}{})
 
-func (msg *{{ .Name }}) Marshaler() _bindings.Marshaler {
-	return _m{{ .Name }}
+func (msg *{{ $union.Name }}) Marshaler() _bindings.Marshaler {
+	return _m{{ $union.Name }}
 }
 
 {{- /*
@@ -46,14 +48,14 @@
 equality checks.
 */}}
 
-func (_m *{{ .Name }}) reset() {
-	switch _m.{{ .TagName }} {
-	{{- range .Members }}
-	case {{ .Ordinal }}:
-		var _zeroed {{ .Type }}
-		_m.{{ .Name }} = _zeroed
+func (_m *{{ $union.Name }}) reset() {
+	switch _m.{{ $union.TagName }} {
+	{{- range $memb := $union.Members }}
+	case {{ $memb.Ordinal }}:
+		var _zeroed {{ $memb.Type }}
+		_m.{{ $memb.Name }} = _zeroed
 	{{- end }}
-	{{- if .IsFlexible }}
+	{{- if $union.IsFlexible }}
 	default:
 		var _zeroed interface{}
 		_m.I_unknownData = _zeroed
@@ -61,43 +63,43 @@
 	}
 }
 
-func (_m *{{ .Name }}) Which() {{ .TagName }} {
-	{{- if .IsStrict }}
-	return _m.{{ .TagName }}
+func (_m *{{ $union.Name }}) Which() {{ $union.TagName }} {
+	{{- if $union.IsStrict }}
+	return _m.{{ $union.TagName }}
 	{{- else }}
-	switch _m.{{ .TagName }} {
-	{{- range .Members }}
-	case {{ .Ordinal }}:
-		return {{ $.Name }}{{ .Name }}
+	switch _m.{{ $union.TagName }} {
+	{{- range $memb := $union.Members }}
+	case {{ $memb.Ordinal }}:
+		return {{ $union.Name }}{{ $memb.Name }}
 	{{- end }}
 	default:
-		return {{ $.Name }}_unknownData
+		return {{ $union.Name }}_unknownData
 	}
 	{{- end }}
 }
 
-func (_m *{{ .Name }}) Ordinal() uint64 {
-	return uint64(_m.{{ .TagName }})
+func (_m *{{ $union.Name }}) Ordinal() uint64 {
+	return uint64(_m.{{ $union.TagName }})
 }
 
-{{- range .Members }}
+{{- range $memb := $union.Members }}
 
-func (_m *{{ $.Name }}) Set{{ .Name }}({{ .PrivateName }} {{ .Type }}) {
+func (_m *{{ $union.Name }}) Set{{ $memb.Name }}({{ $memb.PrivateName }} {{ $memb.Type }}) {
 	_m.reset()
-	_m.{{ $.TagName }} = {{ $.Name }}{{ .Name }}
-	_m.{{ .Name }} = {{ .PrivateName }}
+	_m.{{ $union.TagName }} = {{ $union.Name }}{{ $memb.Name }}
+	_m.{{ $memb.Name }} = {{ $memb.PrivateName }}
 }
 
-func {{ $.Name }}With{{ .Name }}({{ .PrivateName }} {{ .Type }}) {{ $.Name }} {
-	var _u {{ $.Name }}
-	_u.Set{{ .Name }}({{ .PrivateName }})
+func {{ $union.Name }}With{{ $memb.Name }}({{ $memb.PrivateName }} {{ $memb.Type }}) {{ $union.Name }} {
+	var _u {{ $union.Name }}
+	_u.Set{{ $memb.Name }}({{ $memb.PrivateName }})
 	return _u
 }
 {{- end }}
 
-{{- if .IsFlexible }}
-func (_m *{{ .Name }}) GetUnknownData() {{ .UnknownDataType }} {
-	return _m.I_unknownData.({{ .UnknownDataType }})
+{{- if $union.IsFlexible }}
+func (_m *{{ $union.Name }}) GetUnknownData() {{ $union.UnknownDataType }} {
+	return _m.I_unknownData.({{ $union.UnknownDataType }})
 }
 {{- end }}
 
diff --git a/tools/fidl/fidlgen_hlcpp/codegen/types_bits.tmpl b/tools/fidl/fidlgen_hlcpp/codegen/types_bits.tmpl
index 9677607a..06a85ac 100644
--- a/tools/fidl/fidlgen_hlcpp/codegen/types_bits.tmpl
+++ b/tools/fidl/fidlgen_hlcpp/codegen/types_bits.tmpl
@@ -184,7 +184,7 @@
 {{- define "BitsTraits" }}
 template <>
 struct CodingTraits<{{ . }}> {
-  static constexpr size_t inline_size_v2 = sizeof({{ . }});
+  static constexpr size_t kInlineSize = sizeof({{ . }});
   static void Encode(Encoder* encoder, {{ . }}* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
diff --git a/tools/fidl/fidlgen_hlcpp/codegen/types_enum.tmpl b/tools/fidl/fidlgen_hlcpp/codegen/types_enum.tmpl
index c638ae5..0a2818d 100644
--- a/tools/fidl/fidlgen_hlcpp/codegen/types_enum.tmpl
+++ b/tools/fidl/fidlgen_hlcpp/codegen/types_enum.tmpl
@@ -78,7 +78,7 @@
 {{- define "EnumTraits" }}
 template <>
 struct CodingTraits<{{ . }}> {
-  static constexpr size_t inline_size_v2 = sizeof({{ . }});
+  static constexpr size_t kInlineSize = sizeof({{ . }});
   static void Encode(Encoder* encoder, {{ . }}* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
diff --git a/tools/fidl/fidlgen_hlcpp/codegen/types_union.tmpl b/tools/fidl/fidlgen_hlcpp/codegen/types_union.tmpl
index 8a8f2f9..390cdf1 100644
--- a/tools/fidl/fidlgen_hlcpp/codegen/types_union.tmpl
+++ b/tools/fidl/fidlgen_hlcpp/codegen/types_union.tmpl
@@ -504,7 +504,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<{{ . }}>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<{{ . }}>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/aliases.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/aliases.h.golden
index 675b0fe..4728534 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/aliases.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/aliases.h.golden
@@ -94,7 +94,7 @@
 
 template <>
 struct CodingTraits<::test::aliases::obj_type> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::aliases::obj_type);
+  static constexpr size_t kInlineSize = sizeof(::test::aliases::obj_type);
   static void Encode(Encoder* encoder, ::test::aliases::obj_type* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/anonymous.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/anonymous.h.golden
index c46d2f0..e70100d1 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/anonymous.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/anonymous.h.golden
@@ -987,7 +987,7 @@
 
 template <>
 struct CodingTraits<::test::anonymous::Op> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::anonymous::Op);
+  static constexpr size_t kInlineSize = sizeof(::test::anonymous::Op);
   static void Encode(Encoder* encoder, ::test::anonymous::Op* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -1045,7 +1045,7 @@
 };
 template <>
 struct CodingTraits<::test::anonymous::Flags> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::anonymous::Flags);
+  static constexpr size_t kInlineSize = sizeof(::test::anonymous::Flags);
   static void Encode(Encoder* encoder, ::test::anonymous::Flags* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -1125,7 +1125,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::anonymous::Expression>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::anonymous::Expression>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1183,7 +1183,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::anonymous::UnionMember>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::anonymous::UnionMember>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1304,7 +1304,7 @@
 };
 template <>
 struct CodingTraits<::test::anonymous::BitsMember> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::anonymous::BitsMember);
+  static constexpr size_t kInlineSize = sizeof(::test::anonymous::BitsMember);
   static void Encode(Encoder* encoder, ::test::anonymous::BitsMember* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -1355,7 +1355,7 @@
 };
 template <>
 struct CodingTraits<::test::anonymous::SomeProtocol_SomeMethod_Error> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::anonymous::SomeProtocol_SomeMethod_Error);
+  static constexpr size_t kInlineSize = sizeof(::test::anonymous::SomeProtocol_SomeMethod_Error);
   static void Encode(Encoder* encoder, ::test::anonymous::SomeProtocol_SomeMethod_Error* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -1389,7 +1389,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::anonymous::SomeProtocol_SomeMethod_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::anonymous::SomeProtocol_SomeMethod_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/arrays.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/arrays.h.golden
index dd81583..64495e2 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/arrays.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/arrays.h.golden
@@ -470,7 +470,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::arrays::UnionSmallArray>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::arrays::UnionSmallArray>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -525,7 +525,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::arrays::UnionLargeArray>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::arrays::UnionLargeArray>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/bindings_denylist.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/bindings_denylist.h.golden
index 511eae25..6eef74a 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/bindings_denylist.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/bindings_denylist.h.golden
@@ -1135,7 +1135,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenyDart_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenyDart_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1236,7 +1236,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenyGo_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenyGo_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1337,7 +1337,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenyLibfuzzer_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenyLibfuzzer_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1438,7 +1438,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenyRust_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenyRust_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1539,7 +1539,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenySyzkaller_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::bindingsdenylist::DenyEachBinding_OnlyDenySyzkaller_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/bits.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/bits.h.golden
index 6b1400a..7f0653b 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/bits.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/bits.h.golden
@@ -319,7 +319,7 @@
 
 template <>
 struct CodingTraits<::test::bits::MyBits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::bits::MyBits);
+  static constexpr size_t kInlineSize = sizeof(::test::bits::MyBits);
   static void Encode(Encoder* encoder, ::test::bits::MyBits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -348,7 +348,7 @@
 };
 template <>
 struct CodingTraits<::test::bits::StrictBits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::bits::StrictBits);
+  static constexpr size_t kInlineSize = sizeof(::test::bits::StrictBits);
   static void Encode(Encoder* encoder, ::test::bits::StrictBits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -377,7 +377,7 @@
 };
 template <>
 struct CodingTraits<::test::bits::FlexibleBits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::bits::FlexibleBits);
+  static constexpr size_t kInlineSize = sizeof(::test::bits::FlexibleBits);
   static void Encode(Encoder* encoder, ::test::bits::FlexibleBits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -406,7 +406,7 @@
 };
 template <>
 struct CodingTraits<::test::bits::EmptyBits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::bits::EmptyBits);
+  static constexpr size_t kInlineSize = sizeof(::test::bits::EmptyBits);
   static void Encode(Encoder* encoder, ::test::bits::EmptyBits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/bits_constants.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/bits_constants.h.golden
index fd5f6bc..48dc100 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/bits_constants.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/bits_constants.h.golden
@@ -84,7 +84,7 @@
 
 template <>
 struct CodingTraits<::test::bitsconstants::BitsType> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::bitsconstants::BitsType);
+  static constexpr size_t kInlineSize = sizeof(::test::bitsconstants::BitsType);
   static void Encode(Encoder* encoder, ::test::bitsconstants::BitsType* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/consts.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/consts.h.golden
index 922c8f6..614318a 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/consts.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/consts.h.golden
@@ -135,7 +135,7 @@
 
 template <>
 struct CodingTraits<::test::consts::EnumType> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::consts::EnumType);
+  static constexpr size_t kInlineSize = sizeof(::test::consts::EnumType);
   static void Encode(Encoder* encoder, ::test::consts::EnumType* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -162,7 +162,7 @@
 
 template <>
 struct CodingTraits<::test::consts::BitsType> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::consts::BitsType);
+  static constexpr size_t kInlineSize = sizeof(::test::consts::BitsType);
   static void Encode(Encoder* encoder, ::test::consts::BitsType* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/doc_comments.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/doc_comments.h.golden
index f913fe2..5682a32 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/doc_comments.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/doc_comments.h.golden
@@ -588,7 +588,7 @@
 
 template <>
 struct CodingTraits<::test::doccomments::MyStrictBits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::doccomments::MyStrictBits);
+  static constexpr size_t kInlineSize = sizeof(::test::doccomments::MyStrictBits);
   static void Encode(Encoder* encoder, ::test::doccomments::MyStrictBits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -617,7 +617,7 @@
 };
 template <>
 struct CodingTraits<::test::doccomments::MyFlexibleBits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::doccomments::MyFlexibleBits);
+  static constexpr size_t kInlineSize = sizeof(::test::doccomments::MyFlexibleBits);
   static void Encode(Encoder* encoder, ::test::doccomments::MyFlexibleBits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -646,7 +646,7 @@
 };
 template <>
 struct CodingTraits<::test::doccomments::MyStrictEnum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::doccomments::MyStrictEnum);
+  static constexpr size_t kInlineSize = sizeof(::test::doccomments::MyStrictEnum);
   static void Encode(Encoder* encoder, ::test::doccomments::MyStrictEnum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -673,7 +673,7 @@
 
 template <>
 struct CodingTraits<::test::doccomments::MyFlexibleEnum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::doccomments::MyFlexibleEnum);
+  static constexpr size_t kInlineSize = sizeof(::test::doccomments::MyFlexibleEnum);
   static void Encode(Encoder* encoder, ::test::doccomments::MyFlexibleEnum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -729,7 +729,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::doccomments::StrictUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::doccomments::StrictUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -784,7 +784,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::doccomments::FlexibleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::doccomments::FlexibleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/enum.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/enum.h.golden
index 314d628..68fac75 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/enum.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/enum.h.golden
@@ -142,7 +142,7 @@
 
 template <>
 struct CodingTraits<::test::enum_::MyStrictEnum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::enum_::MyStrictEnum);
+  static constexpr size_t kInlineSize = sizeof(::test::enum_::MyStrictEnum);
   static void Encode(Encoder* encoder, ::test::enum_::MyStrictEnum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -169,7 +169,7 @@
 
 template <>
 struct CodingTraits<::test::enum_::MyFlexibleEnum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::enum_::MyFlexibleEnum);
+  static constexpr size_t kInlineSize = sizeof(::test::enum_::MyFlexibleEnum);
   static void Encode(Encoder* encoder, ::test::enum_::MyFlexibleEnum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -196,7 +196,7 @@
 
 template <>
 struct CodingTraits<::test::enum_::MyFlexibleEnumWithCustomUnknown> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::enum_::MyFlexibleEnumWithCustomUnknown);
+  static constexpr size_t kInlineSize = sizeof(::test::enum_::MyFlexibleEnumWithCustomUnknown);
   static void Encode(Encoder* encoder, ::test::enum_::MyFlexibleEnumWithCustomUnknown* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -223,7 +223,7 @@
 
 template <>
 struct CodingTraits<::test::enum_::MyEmptyFlexibleEnum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::enum_::MyEmptyFlexibleEnum);
+  static constexpr size_t kInlineSize = sizeof(::test::enum_::MyEmptyFlexibleEnum);
   static void Encode(Encoder* encoder, ::test::enum_::MyEmptyFlexibleEnum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/error.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/error.h.golden
index 36a0387..4709364 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/error.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/error.h.golden
@@ -278,7 +278,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::error::Example_foo_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::error::Example_foo_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/error_syntax.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/error_syntax.h.golden
index 038218e..9f396cf 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/error_syntax.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/error_syntax.h.golden
@@ -295,7 +295,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::errorsyntax::ExampleUseOfErrorSyntax_CallWhichMayFail_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::errorsyntax::ExampleUseOfErrorSyntax_CallWhichMayFail_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/handles_in_types.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/handles_in_types.h.golden
index adeca83..1b4d346 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/handles_in_types.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/handles_in_types.h.golden
@@ -410,7 +410,7 @@
 
 template <>
 struct CodingTraits<::test::handlesintypes::obj_type> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::handlesintypes::obj_type);
+  static constexpr size_t kInlineSize = sizeof(::test::handlesintypes::obj_type);
   static void Encode(Encoder* encoder, ::test::handlesintypes::obj_type* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -475,7 +475,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::handlesintypes::UnionWithHandle>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::handlesintypes::UnionWithHandle>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -625,7 +625,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::handlesintypes::EmptyResourceUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::handlesintypes::EmptyResourceUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/nullable.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/nullable.h.golden
index 7a0ea2c..a622407 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/nullable.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/nullable.h.golden
@@ -626,7 +626,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::nullable::SimpleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::nullable::SimpleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/placement_of_attributes.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/placement_of_attributes.h.golden
index e87d476..f50056f 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/placement_of_attributes.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/placement_of_attributes.h.golden
@@ -317,7 +317,7 @@
 
 template <>
 struct CodingTraits<::test::placementofattributes::ExampleBits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::placementofattributes::ExampleBits);
+  static constexpr size_t kInlineSize = sizeof(::test::placementofattributes::ExampleBits);
   static void Encode(Encoder* encoder, ::test::placementofattributes::ExampleBits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -346,7 +346,7 @@
 };
 template <>
 struct CodingTraits<::test::placementofattributes::ExampleEnum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::placementofattributes::ExampleEnum);
+  static constexpr size_t kInlineSize = sizeof(::test::placementofattributes::ExampleEnum);
   static void Encode(Encoder* encoder, ::test::placementofattributes::ExampleEnum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -448,7 +448,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::placementofattributes::ExampleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::placementofattributes::ExampleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/protocol_layouts.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/protocol_layouts.h.golden
index 9b2bf92..9a715de 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/protocol_layouts.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/protocol_layouts.h.golden
@@ -1404,7 +1404,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayouts::LocalUnionPayload>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayouts::LocalUnionPayload>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1458,7 +1458,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayouts::MainProtocol_TwoWayImportWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayouts::MainProtocol_TwoWayImportWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1515,7 +1515,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayouts::MainProtocol_TwoWayLocalWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayouts::MainProtocol_TwoWayLocalWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1596,7 +1596,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayouts::MainProtocolTwoWayAnonRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayouts::MainProtocolTwoWayAnonRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1698,7 +1698,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayouts::MainProtocol_TwoWayAnonWithError_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayouts::MainProtocol_TwoWayAnonWithError_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1752,7 +1752,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayouts::MainProtocol_TwoWayAnonWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayouts::MainProtocol_TwoWayAnonWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1809,7 +1809,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayouts::MainProtocolOnAnonRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayouts::MainProtocolOnAnonRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/protocol_layouts_same_library.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/protocol_layouts_same_library.h.golden
index ac12c8f..c60d1c8 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/protocol_layouts_same_library.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/protocol_layouts_same_library.h.golden
@@ -2060,7 +2060,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::UnionPayload>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::UnionPayload>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2139,7 +2139,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocolTwoWayAnonComposedRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocolTwoWayAnonComposedRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2242,7 +2242,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocol_TwoWayAnonComposedWithError_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocol_TwoWayAnonComposedWithError_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2297,7 +2297,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocol_TwoWayAnonComposedWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocol_TwoWayAnonComposedWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2354,7 +2354,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocolOnAnonComposedRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocolOnAnonComposedRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2409,7 +2409,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocol_TwoWayNamedComposedWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::ComposedProtocol_TwoWayNamedComposedWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2466,7 +2466,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocol_TwoWayLocalWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocol_TwoWayLocalWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2547,7 +2547,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocolTwoWayAnonRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocolTwoWayAnonRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2649,7 +2649,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocol_TwoWayAnonWithError_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocol_TwoWayAnonWithError_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2703,7 +2703,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocol_TwoWayAnonWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocol_TwoWayAnonWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2760,7 +2760,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocolOnAnonRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocollayoutssamelibrary::MainProtocolOnAnonRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/protocol_payloads.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/protocol_payloads.h.golden
index 4662377..793635b 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/protocol_payloads.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/protocol_payloads.h.golden
@@ -759,7 +759,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocolpayloads::MainProtocol_TwoWayLocalWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocolpayloads::MainProtocol_TwoWayLocalWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -941,7 +941,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocolpayloads::MainProtocol_TwoWayAnonWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocolpayloads::MainProtocol_TwoWayAnonWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -1023,7 +1023,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocolpayloads::MainProtocol_TwoWayImportWithError_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocolpayloads::MainProtocol_TwoWayImportWithError_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/protocols.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/protocols.h.golden
index 4616a80..e8acfd6 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/protocols.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/protocols.h.golden
@@ -2427,7 +2427,7 @@
 };
 template <>
 struct CodingTraits<::test::protocols::ErrorEnum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::protocols::ErrorEnum);
+  static constexpr size_t kInlineSize = sizeof(::test::protocols::ErrorEnum);
   static void Encode(Encoder* encoder, ::test::protocols::ErrorEnum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -2495,7 +2495,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocols::WithErrorSyntax_ResponseAsStruct_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocols::WithErrorSyntax_ResponseAsStruct_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2579,7 +2579,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocols::WithErrorSyntax_ErrorAsPrimitive_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocols::WithErrorSyntax_ErrorAsPrimitive_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2663,7 +2663,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocols::WithErrorSyntax_ErrorAsEnum_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocols::WithErrorSyntax_ErrorAsEnum_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2754,7 +2754,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocols::WithErrorSyntax_HandleInResult_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocols::WithErrorSyntax_HandleInResult_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3488,7 +3488,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::protocols::TheUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::protocols::TheUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/request_flexible_envelope.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/request_flexible_envelope.h.golden
index d1be826..336bb0f 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/request_flexible_envelope.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/request_flexible_envelope.h.golden
@@ -368,7 +368,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::requestflexibleenvelope::FlexibleFoo>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::requestflexibleenvelope::FlexibleFoo>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -424,7 +424,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::requestflexibleenvelope::StrictFoo>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::requestflexibleenvelope::StrictFoo>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/types_in_protocols.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/types_in_protocols.h.golden
index d279687..14461dd 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/types_in_protocols.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/types_in_protocols.h.golden
@@ -3354,7 +3354,7 @@
 
 template <>
 struct CodingTraits<::test::typesinprotocols::Bits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::typesinprotocols::Bits);
+  static constexpr size_t kInlineSize = sizeof(::test::typesinprotocols::Bits);
   static void Encode(Encoder* encoder, ::test::typesinprotocols::Bits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -3383,7 +3383,7 @@
 };
 template <>
 struct CodingTraits<::test::typesinprotocols::Enum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::typesinprotocols::Enum);
+  static constexpr size_t kInlineSize = sizeof(::test::typesinprotocols::Enum);
   static void Encode(Encoder* encoder, ::test::typesinprotocols::Enum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -3459,7 +3459,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Union>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Union>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3566,7 +3566,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::ResourceUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::ResourceUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4222,7 +4222,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorBasic_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorBasic_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4279,7 +4279,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorCompound_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorCompound_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4336,7 +4336,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorArrayBasic_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorArrayBasic_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4393,7 +4393,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorArrayCompound_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorArrayCompound_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4450,7 +4450,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorVectorBasic_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorVectorBasic_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4507,7 +4507,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorVectorCompound_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorVectorCompound_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4564,7 +4564,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorVectorOptional_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorVectorOptional_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4621,7 +4621,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorArrayVectorNested_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorArrayVectorNested_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -4680,7 +4680,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::typesinprotocols::Protocol_ErrorResource_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::typesinprotocols::Protocol_ErrorResource_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/union.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/union.h.golden
index 8f5f75f..5c4ac5d 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/union.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/union.h.golden
@@ -9,87 +9,60 @@
 namespace test {
 namespace union_ {
 
-
 //
 // Domain objects declarations
 //
 
-
 class Pizza;
 
-
 class Pasta;
 
-
 class PizzaOrPasta;
 
-
 class ExplicitPizzaOrPasta;
 
-
 class FlexiblePizzaOrPasta;
 
-
 class StrictPizzaOrPasta;
 
-
 class Union;
 
-
 class FlexibleUnion;
 
-
 class StrictUnion;
 
-
 class FieldCollision;
 
-
 class ExplicitUnion;
 
-
 class ReverseOrdinalUnion;
 
-
 class NullableUnionStruct;
 
-
 class FlexibleFoo;
 
-
 class StrictFoo;
 
-
 class ExplicitFoo;
 
-
 class ExplicitStrictFoo;
 
-
 class OlderSimpleUnion;
 
-
 class NewerSimpleUnion;
 
-
 class StrictSimpleUnion;
 
-
 class Empty;
 
-
 class UnionContainingEmptyStruct;
 
-
 class StrictBoundedUnion;
 
-
 class TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse;
 
-
 class TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse;
 
-
 #ifdef __Fuchsia__
 
 class TestProtocol;
@@ -97,34 +70,26 @@
 
 #endif  // __Fuchsia__
 
-
-
 class StructWithNullableUnion;
 
-
 class ExplicitFlexibleUnion;
 
-
 class UnionSandwich;
 
-
 class UnionWithAttributes;
 
-
 class EmptyFlexibleUnion;
 
-
-
 class Pizza final {
  public:
   static const fidl_type_t* FidlType;
-  
+
   ::std::vector<::std::string> toppings;
 
   static inline ::std::unique_ptr<Pizza> New() { return ::std::make_unique<Pizza>(); }
 
   void Encode(::fidl::Encoder* _encoder, size_t _offset,
-               cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
+              cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
   static void Decode(::fidl::Decoder* _decoder, Pizza* value, size_t _offset);
   zx_status_t Clone(Pizza* result) const;
 };
@@ -136,18 +101,16 @@
 
 using PizzaPtr = ::std::unique_ptr<Pizza>;
 
-
-
 class Pasta final {
  public:
   static const fidl_type_t* FidlType;
-  
+
   ::std::string sauce;
 
   static inline ::std::unique_ptr<Pasta> New() { return ::std::make_unique<Pasta>(); }
 
   void Encode(::fidl::Encoder* _encoder, size_t _offset,
-               cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
+              cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
   static void Decode(::fidl::Decoder* _decoder, Pasta* value, size_t _offset);
   zx_status_t Clone(Pasta* result) const;
 };
@@ -159,8 +122,6 @@
 
 using PastaPtr = ::std::unique_ptr<Pasta>;
 
-
-
 class PizzaOrPasta final {
  public:
   static const fidl_type_t* FidlType;
@@ -171,12 +132,11 @@
   PizzaOrPasta(PizzaOrPasta&&);
   PizzaOrPasta& operator=(PizzaOrPasta&&);
 
-  
   static PizzaOrPasta WithPizza(::test::union_::Pizza&&);
   static PizzaOrPasta WithPasta(::test::union_::Pasta&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
+
     kPizza = 1,  // 0x1
     kPasta = 2,  // 0x2
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -194,12 +154,12 @@
   }
 
   bool is_pizza() const { return tag_ == ::test::union_::PizzaOrPasta::Tag::kPizza; }
-  
+
   ::test::union_::Pizza& pizza() {
     EnsureStorageInitialized(::test::union_::PizzaOrPasta::Tag::kPizza);
     return pizza_;
   }
-  
+
   const ::test::union_::Pizza& pizza() const {
     ZX_ASSERT(is_pizza());
     return pizza_;
@@ -207,12 +167,12 @@
   PizzaOrPasta& set_pizza(::test::union_::Pizza value);
 
   bool is_pasta() const { return tag_ == ::test::union_::PizzaOrPasta::Tag::kPasta; }
-  
+
   ::test::union_::Pasta& pasta() {
     EnsureStorageInitialized(::test::union_::PizzaOrPasta::Tag::kPasta);
     return pasta_;
   }
-  
+
   const ::test::union_::Pasta& pasta() const {
     ZX_ASSERT(is_pasta());
     return pasta_;
@@ -220,9 +180,7 @@
   PizzaOrPasta& set_pasta(::test::union_::Pasta value);
 
   ::test::union_::PizzaOrPasta::Tag Which() const {
-    
     return ::test::union_::PizzaOrPasta::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -251,8 +209,6 @@
 
 using PizzaOrPastaPtr = ::std::unique_ptr<PizzaOrPasta>;
 
-
-
 class ExplicitPizzaOrPasta final {
  public:
   static const fidl_type_t* FidlType;
@@ -263,12 +219,11 @@
   ExplicitPizzaOrPasta(ExplicitPizzaOrPasta&&);
   ExplicitPizzaOrPasta& operator=(ExplicitPizzaOrPasta&&);
 
-  
   static ExplicitPizzaOrPasta WithPizza(::test::union_::Pizza&&);
   static ExplicitPizzaOrPasta WithPasta(::test::union_::Pasta&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
+
     kPizza = 1,  // 0x1
     kPasta = 4,  // 0x4
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -286,12 +241,12 @@
   }
 
   bool is_pizza() const { return tag_ == ::test::union_::ExplicitPizzaOrPasta::Tag::kPizza; }
-  
+
   ::test::union_::Pizza& pizza() {
     EnsureStorageInitialized(::test::union_::ExplicitPizzaOrPasta::Tag::kPizza);
     return pizza_;
   }
-  
+
   const ::test::union_::Pizza& pizza() const {
     ZX_ASSERT(is_pizza());
     return pizza_;
@@ -299,12 +254,12 @@
   ExplicitPizzaOrPasta& set_pizza(::test::union_::Pizza value);
 
   bool is_pasta() const { return tag_ == ::test::union_::ExplicitPizzaOrPasta::Tag::kPasta; }
-  
+
   ::test::union_::Pasta& pasta() {
     EnsureStorageInitialized(::test::union_::ExplicitPizzaOrPasta::Tag::kPasta);
     return pasta_;
   }
-  
+
   const ::test::union_::Pasta& pasta() const {
     ZX_ASSERT(is_pasta());
     return pasta_;
@@ -312,9 +267,7 @@
   ExplicitPizzaOrPasta& set_pasta(::test::union_::Pasta value);
 
   ::test::union_::ExplicitPizzaOrPasta::Tag Which() const {
-    
     return ::test::union_::ExplicitPizzaOrPasta::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -343,8 +296,6 @@
 
 using ExplicitPizzaOrPastaPtr = ::std::unique_ptr<ExplicitPizzaOrPasta>;
 
-
-
 class FlexiblePizzaOrPasta final {
  public:
   static const fidl_type_t* FidlType;
@@ -355,13 +306,12 @@
   FlexiblePizzaOrPasta(FlexiblePizzaOrPasta&&);
   FlexiblePizzaOrPasta& operator=(FlexiblePizzaOrPasta&&);
 
-  
   static FlexiblePizzaOrPasta WithPizza(::test::union_::Pizza&&);
   static FlexiblePizzaOrPasta WithPasta(::test::union_::Pasta&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     kPizza = 1,  // 0x1
     kPasta = 2,  // 0x2
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -379,12 +329,12 @@
   }
 
   bool is_pizza() const { return tag_ == ::test::union_::FlexiblePizzaOrPasta::Tag::kPizza; }
-  
+
   ::test::union_::Pizza& pizza() {
     EnsureStorageInitialized(::test::union_::FlexiblePizzaOrPasta::Tag::kPizza);
     return pizza_;
   }
-  
+
   const ::test::union_::Pizza& pizza() const {
     ZX_ASSERT(is_pizza());
     return pizza_;
@@ -392,12 +342,12 @@
   FlexiblePizzaOrPasta& set_pizza(::test::union_::Pizza value);
 
   bool is_pasta() const { return tag_ == ::test::union_::FlexiblePizzaOrPasta::Tag::kPasta; }
-  
+
   ::test::union_::Pasta& pasta() {
     EnsureStorageInitialized(::test::union_::FlexiblePizzaOrPasta::Tag::kPasta);
     return pasta_;
   }
-  
+
   const ::test::union_::Pasta& pasta() const {
     ZX_ASSERT(is_pasta());
     return pasta_;
@@ -406,7 +356,6 @@
   FlexiblePizzaOrPasta& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::FlexiblePizzaOrPasta::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::FlexiblePizzaOrPasta::Tag::Invalid:
       case ::test::union_::FlexiblePizzaOrPasta::Tag::kPizza:
@@ -415,7 +364,6 @@
       default:
         return ::test::union_::FlexiblePizzaOrPasta::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -451,8 +399,6 @@
 
 using FlexiblePizzaOrPastaPtr = ::std::unique_ptr<FlexiblePizzaOrPasta>;
 
-
-
 class StrictPizzaOrPasta final {
  public:
   static const fidl_type_t* FidlType;
@@ -463,12 +409,11 @@
   StrictPizzaOrPasta(StrictPizzaOrPasta&&);
   StrictPizzaOrPasta& operator=(StrictPizzaOrPasta&&);
 
-  
   static StrictPizzaOrPasta WithPizza(::test::union_::Pizza&&);
   static StrictPizzaOrPasta WithPasta(::test::union_::Pasta&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
+
     kPizza = 1,  // 0x1
     kPasta = 2,  // 0x2
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -486,12 +431,12 @@
   }
 
   bool is_pizza() const { return tag_ == ::test::union_::StrictPizzaOrPasta::Tag::kPizza; }
-  
+
   ::test::union_::Pizza& pizza() {
     EnsureStorageInitialized(::test::union_::StrictPizzaOrPasta::Tag::kPizza);
     return pizza_;
   }
-  
+
   const ::test::union_::Pizza& pizza() const {
     ZX_ASSERT(is_pizza());
     return pizza_;
@@ -499,12 +444,12 @@
   StrictPizzaOrPasta& set_pizza(::test::union_::Pizza value);
 
   bool is_pasta() const { return tag_ == ::test::union_::StrictPizzaOrPasta::Tag::kPasta; }
-  
+
   ::test::union_::Pasta& pasta() {
     EnsureStorageInitialized(::test::union_::StrictPizzaOrPasta::Tag::kPasta);
     return pasta_;
   }
-  
+
   const ::test::union_::Pasta& pasta() const {
     ZX_ASSERT(is_pasta());
     return pasta_;
@@ -512,9 +457,7 @@
   StrictPizzaOrPasta& set_pasta(::test::union_::Pasta value);
 
   ::test::union_::StrictPizzaOrPasta::Tag Which() const {
-    
     return ::test::union_::StrictPizzaOrPasta::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -543,8 +486,6 @@
 
 using StrictPizzaOrPastaPtr = ::std::unique_ptr<StrictPizzaOrPasta>;
 
-
-
 class Union final {
  public:
   static const fidl_type_t* FidlType;
@@ -555,15 +496,14 @@
   Union(Union&&);
   Union& operator=(Union&&);
 
-  
   static Union WithPrimitive(int32_t&&);
   static Union WithStringNeedsConstructor(::std::string&&);
   static Union WithVectorStringAlsoNeedsConstructor(::std::vector<::std::string>&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
-    kPrimitive = 1,  // 0x1
-    kStringNeedsConstructor = 2,  // 0x2
+
+    kPrimitive = 1,                         // 0x1
+    kStringNeedsConstructor = 2,            // 0x2
     kVectorStringAlsoNeedsConstructor = 3,  // 0x3
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -580,12 +520,12 @@
   }
 
   bool is_Primitive() const { return tag_ == ::test::union_::Union::Tag::kPrimitive; }
-  
+
   int32_t& Primitive() {
     EnsureStorageInitialized(::test::union_::Union::Tag::kPrimitive);
     return Primitive_;
   }
-  
+
   const int32_t& Primitive() const {
     ZX_ASSERT(is_Primitive());
     return Primitive_;
@@ -593,12 +533,12 @@
   Union& set_Primitive(int32_t value);
 
   bool is_StringNeedsConstructor() const { return tag_ == ::test::union_::Union::Tag::kStringNeedsConstructor; }
-  
+
   ::std::string& StringNeedsConstructor() {
     EnsureStorageInitialized(::test::union_::Union::Tag::kStringNeedsConstructor);
     return StringNeedsConstructor_;
   }
-  
+
   const ::std::string& StringNeedsConstructor() const {
     ZX_ASSERT(is_StringNeedsConstructor());
     return StringNeedsConstructor_;
@@ -606,12 +546,12 @@
   Union& set_StringNeedsConstructor(::std::string value);
 
   bool is_VectorStringAlsoNeedsConstructor() const { return tag_ == ::test::union_::Union::Tag::kVectorStringAlsoNeedsConstructor; }
-  
+
   ::std::vector<::std::string>& VectorStringAlsoNeedsConstructor() {
     EnsureStorageInitialized(::test::union_::Union::Tag::kVectorStringAlsoNeedsConstructor);
     return VectorStringAlsoNeedsConstructor_;
   }
-  
+
   const ::std::vector<::std::string>& VectorStringAlsoNeedsConstructor() const {
     ZX_ASSERT(is_VectorStringAlsoNeedsConstructor());
     return VectorStringAlsoNeedsConstructor_;
@@ -619,9 +559,7 @@
   Union& set_VectorStringAlsoNeedsConstructor(::std::vector<::std::string> value);
 
   ::test::union_::Union::Tag Which() const {
-    
     return ::test::union_::Union::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -651,8 +589,6 @@
 
 using UnionPtr = ::std::unique_ptr<Union>;
 
-
-
 class FlexibleUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -663,16 +599,15 @@
   FlexibleUnion(FlexibleUnion&&);
   FlexibleUnion& operator=(FlexibleUnion&&);
 
-  
   static FlexibleUnion WithPrimitive(int32_t&&);
   static FlexibleUnion WithStringNeedsConstructor(::std::string&&);
   static FlexibleUnion WithVectorStringAlsoNeedsConstructor(::std::vector<::std::string>&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
-    kPrimitive = 1,  // 0x1
-    kStringNeedsConstructor = 2,  // 0x2
+    kUnknown = 0,
+
+    kPrimitive = 1,                         // 0x1
+    kStringNeedsConstructor = 2,            // 0x2
     kVectorStringAlsoNeedsConstructor = 3,  // 0x3
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -689,12 +624,12 @@
   }
 
   bool is_Primitive() const { return tag_ == ::test::union_::FlexibleUnion::Tag::kPrimitive; }
-  
+
   int32_t& Primitive() {
     EnsureStorageInitialized(::test::union_::FlexibleUnion::Tag::kPrimitive);
     return Primitive_;
   }
-  
+
   const int32_t& Primitive() const {
     ZX_ASSERT(is_Primitive());
     return Primitive_;
@@ -702,12 +637,12 @@
   FlexibleUnion& set_Primitive(int32_t value);
 
   bool is_StringNeedsConstructor() const { return tag_ == ::test::union_::FlexibleUnion::Tag::kStringNeedsConstructor; }
-  
+
   ::std::string& StringNeedsConstructor() {
     EnsureStorageInitialized(::test::union_::FlexibleUnion::Tag::kStringNeedsConstructor);
     return StringNeedsConstructor_;
   }
-  
+
   const ::std::string& StringNeedsConstructor() const {
     ZX_ASSERT(is_StringNeedsConstructor());
     return StringNeedsConstructor_;
@@ -715,12 +650,12 @@
   FlexibleUnion& set_StringNeedsConstructor(::std::string value);
 
   bool is_VectorStringAlsoNeedsConstructor() const { return tag_ == ::test::union_::FlexibleUnion::Tag::kVectorStringAlsoNeedsConstructor; }
-  
+
   ::std::vector<::std::string>& VectorStringAlsoNeedsConstructor() {
     EnsureStorageInitialized(::test::union_::FlexibleUnion::Tag::kVectorStringAlsoNeedsConstructor);
     return VectorStringAlsoNeedsConstructor_;
   }
-  
+
   const ::std::vector<::std::string>& VectorStringAlsoNeedsConstructor() const {
     ZX_ASSERT(is_VectorStringAlsoNeedsConstructor());
     return VectorStringAlsoNeedsConstructor_;
@@ -729,7 +664,6 @@
   FlexibleUnion& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::FlexibleUnion::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::FlexibleUnion::Tag::Invalid:
       case ::test::union_::FlexibleUnion::Tag::kPrimitive:
@@ -739,7 +673,6 @@
       default:
         return ::test::union_::FlexibleUnion::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -776,8 +709,6 @@
 
 using FlexibleUnionPtr = ::std::unique_ptr<FlexibleUnion>;
 
-
-
 class StrictUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -788,15 +719,14 @@
   StrictUnion(StrictUnion&&);
   StrictUnion& operator=(StrictUnion&&);
 
-  
   static StrictUnion WithPrimitive(int32_t&&);
   static StrictUnion WithStringNeedsConstructor(::std::string&&);
   static StrictUnion WithVectorStringAlsoNeedsConstructor(::std::vector<::std::string>&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
-    kPrimitive = 1,  // 0x1
-    kStringNeedsConstructor = 2,  // 0x2
+
+    kPrimitive = 1,                         // 0x1
+    kStringNeedsConstructor = 2,            // 0x2
     kVectorStringAlsoNeedsConstructor = 3,  // 0x3
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -813,12 +743,12 @@
   }
 
   bool is_Primitive() const { return tag_ == ::test::union_::StrictUnion::Tag::kPrimitive; }
-  
+
   int32_t& Primitive() {
     EnsureStorageInitialized(::test::union_::StrictUnion::Tag::kPrimitive);
     return Primitive_;
   }
-  
+
   const int32_t& Primitive() const {
     ZX_ASSERT(is_Primitive());
     return Primitive_;
@@ -826,12 +756,12 @@
   StrictUnion& set_Primitive(int32_t value);
 
   bool is_StringNeedsConstructor() const { return tag_ == ::test::union_::StrictUnion::Tag::kStringNeedsConstructor; }
-  
+
   ::std::string& StringNeedsConstructor() {
     EnsureStorageInitialized(::test::union_::StrictUnion::Tag::kStringNeedsConstructor);
     return StringNeedsConstructor_;
   }
-  
+
   const ::std::string& StringNeedsConstructor() const {
     ZX_ASSERT(is_StringNeedsConstructor());
     return StringNeedsConstructor_;
@@ -839,12 +769,12 @@
   StrictUnion& set_StringNeedsConstructor(::std::string value);
 
   bool is_VectorStringAlsoNeedsConstructor() const { return tag_ == ::test::union_::StrictUnion::Tag::kVectorStringAlsoNeedsConstructor; }
-  
+
   ::std::vector<::std::string>& VectorStringAlsoNeedsConstructor() {
     EnsureStorageInitialized(::test::union_::StrictUnion::Tag::kVectorStringAlsoNeedsConstructor);
     return VectorStringAlsoNeedsConstructor_;
   }
-  
+
   const ::std::vector<::std::string>& VectorStringAlsoNeedsConstructor() const {
     ZX_ASSERT(is_VectorStringAlsoNeedsConstructor());
     return VectorStringAlsoNeedsConstructor_;
@@ -852,9 +782,7 @@
   StrictUnion& set_VectorStringAlsoNeedsConstructor(::std::vector<::std::string> value);
 
   ::test::union_::StrictUnion::Tag Which() const {
-    
     return ::test::union_::StrictUnion::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -884,8 +812,6 @@
 
 using StrictUnionPtr = ::std::unique_ptr<StrictUnion>;
 
-
-
 class FieldCollision final {
  public:
   static const fidl_type_t* FidlType;
@@ -896,11 +822,10 @@
   FieldCollision(FieldCollision&&);
   FieldCollision& operator=(FieldCollision&&);
 
-  
   static FieldCollision WithFieldCollisionTag(int32_t&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
+
     kFieldCollisionTag = 1,  // 0x1
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -917,12 +842,12 @@
   }
 
   bool is_field_collision_tag() const { return tag_ == ::test::union_::FieldCollision::Tag::kFieldCollisionTag; }
-  
+
   int32_t& field_collision_tag() {
     EnsureStorageInitialized(::test::union_::FieldCollision::Tag::kFieldCollisionTag);
     return field_collision_tag_;
   }
-  
+
   const int32_t& field_collision_tag() const {
     ZX_ASSERT(is_field_collision_tag());
     return field_collision_tag_;
@@ -930,9 +855,7 @@
   FieldCollision& set_field_collision_tag(int32_t value);
 
   ::test::union_::FieldCollision::Tag Which() const {
-    
     return ::test::union_::FieldCollision::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -960,8 +883,6 @@
 
 using FieldCollisionPtr = ::std::unique_ptr<FieldCollision>;
 
-
-
 class ExplicitUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -972,13 +893,12 @@
   ExplicitUnion(ExplicitUnion&&);
   ExplicitUnion& operator=(ExplicitUnion&&);
 
-  
   static ExplicitUnion WithPrimitive(int32_t&&);
   static ExplicitUnion WithStringNeedsConstructor(::std::string&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
-    kPrimitive = 1,  // 0x1
+
+    kPrimitive = 1,               // 0x1
     kStringNeedsConstructor = 3,  // 0x3
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -995,12 +915,12 @@
   }
 
   bool is_Primitive() const { return tag_ == ::test::union_::ExplicitUnion::Tag::kPrimitive; }
-  
+
   int32_t& Primitive() {
     EnsureStorageInitialized(::test::union_::ExplicitUnion::Tag::kPrimitive);
     return Primitive_;
   }
-  
+
   const int32_t& Primitive() const {
     ZX_ASSERT(is_Primitive());
     return Primitive_;
@@ -1008,12 +928,12 @@
   ExplicitUnion& set_Primitive(int32_t value);
 
   bool is_StringNeedsConstructor() const { return tag_ == ::test::union_::ExplicitUnion::Tag::kStringNeedsConstructor; }
-  
+
   ::std::string& StringNeedsConstructor() {
     EnsureStorageInitialized(::test::union_::ExplicitUnion::Tag::kStringNeedsConstructor);
     return StringNeedsConstructor_;
   }
-  
+
   const ::std::string& StringNeedsConstructor() const {
     ZX_ASSERT(is_StringNeedsConstructor());
     return StringNeedsConstructor_;
@@ -1021,9 +941,7 @@
   ExplicitUnion& set_StringNeedsConstructor(::std::string value);
 
   ::test::union_::ExplicitUnion::Tag Which() const {
-    
     return ::test::union_::ExplicitUnion::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1052,8 +970,6 @@
 
 using ExplicitUnionPtr = ::std::unique_ptr<ExplicitUnion>;
 
-
-
 class ReverseOrdinalUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -1064,13 +980,12 @@
   ReverseOrdinalUnion(ReverseOrdinalUnion&&);
   ReverseOrdinalUnion& operator=(ReverseOrdinalUnion&&);
 
-  
   static ReverseOrdinalUnion WithFirst(uint32_t&&);
   static ReverseOrdinalUnion WithSecond(uint32_t&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
-    kFirst = 1,  // 0x1
+
+    kFirst = 1,   // 0x1
     kSecond = 2,  // 0x2
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -1087,12 +1002,12 @@
   }
 
   bool is_first() const { return tag_ == ::test::union_::ReverseOrdinalUnion::Tag::kFirst; }
-  
+
   uint32_t& first() {
     EnsureStorageInitialized(::test::union_::ReverseOrdinalUnion::Tag::kFirst);
     return first_;
   }
-  
+
   const uint32_t& first() const {
     ZX_ASSERT(is_first());
     return first_;
@@ -1100,12 +1015,12 @@
   ReverseOrdinalUnion& set_first(uint32_t value);
 
   bool is_second() const { return tag_ == ::test::union_::ReverseOrdinalUnion::Tag::kSecond; }
-  
+
   uint32_t& second() {
     EnsureStorageInitialized(::test::union_::ReverseOrdinalUnion::Tag::kSecond);
     return second_;
   }
-  
+
   const uint32_t& second() const {
     ZX_ASSERT(is_second());
     return second_;
@@ -1113,9 +1028,7 @@
   ReverseOrdinalUnion& set_second(uint32_t value);
 
   ::test::union_::ReverseOrdinalUnion::Tag Which() const {
-    
     return ::test::union_::ReverseOrdinalUnion::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1144,18 +1057,16 @@
 
 using ReverseOrdinalUnionPtr = ::std::unique_ptr<ReverseOrdinalUnion>;
 
-
-
 class NullableUnionStruct final {
  public:
   static const fidl_type_t* FidlType;
-  
+
   ::std::unique_ptr<::test::union_::Union> the_union;
 
   static inline ::std::unique_ptr<NullableUnionStruct> New() { return ::std::make_unique<NullableUnionStruct>(); }
 
   void Encode(::fidl::Encoder* _encoder, size_t _offset,
-               cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
+              cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
   static void Decode(::fidl::Decoder* _decoder, NullableUnionStruct* value, size_t _offset);
   zx_status_t Clone(NullableUnionStruct* result) const;
 };
@@ -1167,8 +1078,6 @@
 
 using NullableUnionStructPtr = ::std::unique_ptr<NullableUnionStruct>;
 
-
-
 class FlexibleFoo final {
  public:
   static const fidl_type_t* FidlType;
@@ -1179,13 +1088,12 @@
   FlexibleFoo(FlexibleFoo&&);
   FlexibleFoo& operator=(FlexibleFoo&&);
 
-  
   static FlexibleFoo WithS(::std::string&&);
   static FlexibleFoo WithI(int32_t&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     kS = 1,  // 0x1
     kI = 2,  // 0x2
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -1203,12 +1111,12 @@
   }
 
   bool is_s() const { return tag_ == ::test::union_::FlexibleFoo::Tag::kS; }
-  
+
   ::std::string& s() {
     EnsureStorageInitialized(::test::union_::FlexibleFoo::Tag::kS);
     return s_;
   }
-  
+
   const ::std::string& s() const {
     ZX_ASSERT(is_s());
     return s_;
@@ -1216,12 +1124,12 @@
   FlexibleFoo& set_s(::std::string value);
 
   bool is_i() const { return tag_ == ::test::union_::FlexibleFoo::Tag::kI; }
-  
+
   int32_t& i() {
     EnsureStorageInitialized(::test::union_::FlexibleFoo::Tag::kI);
     return i_;
   }
-  
+
   const int32_t& i() const {
     ZX_ASSERT(is_i());
     return i_;
@@ -1230,7 +1138,6 @@
   FlexibleFoo& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::FlexibleFoo::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::FlexibleFoo::Tag::Invalid:
       case ::test::union_::FlexibleFoo::Tag::kS:
@@ -1239,7 +1146,6 @@
       default:
         return ::test::union_::FlexibleFoo::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1275,8 +1181,6 @@
 
 using FlexibleFooPtr = ::std::unique_ptr<FlexibleFoo>;
 
-
-
 class StrictFoo final {
  public:
   static const fidl_type_t* FidlType;
@@ -1287,12 +1191,11 @@
   StrictFoo(StrictFoo&&);
   StrictFoo& operator=(StrictFoo&&);
 
-  
   static StrictFoo WithS(::std::string&&);
   static StrictFoo WithI(int32_t&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
+
     kS = 1,  // 0x1
     kI = 2,  // 0x2
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -1310,12 +1213,12 @@
   }
 
   bool is_s() const { return tag_ == ::test::union_::StrictFoo::Tag::kS; }
-  
+
   ::std::string& s() {
     EnsureStorageInitialized(::test::union_::StrictFoo::Tag::kS);
     return s_;
   }
-  
+
   const ::std::string& s() const {
     ZX_ASSERT(is_s());
     return s_;
@@ -1323,12 +1226,12 @@
   StrictFoo& set_s(::std::string value);
 
   bool is_i() const { return tag_ == ::test::union_::StrictFoo::Tag::kI; }
-  
+
   int32_t& i() {
     EnsureStorageInitialized(::test::union_::StrictFoo::Tag::kI);
     return i_;
   }
-  
+
   const int32_t& i() const {
     ZX_ASSERT(is_i());
     return i_;
@@ -1336,9 +1239,7 @@
   StrictFoo& set_i(int32_t value);
 
   ::test::union_::StrictFoo::Tag Which() const {
-    
     return ::test::union_::StrictFoo::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1367,8 +1268,6 @@
 
 using StrictFooPtr = ::std::unique_ptr<StrictFoo>;
 
-
-
 class ExplicitFoo final {
  public:
   static const fidl_type_t* FidlType;
@@ -1379,13 +1278,12 @@
   ExplicitFoo(ExplicitFoo&&);
   ExplicitFoo& operator=(ExplicitFoo&&);
 
-  
   static ExplicitFoo WithI(int32_t&&);
   static ExplicitFoo WithS(::std::string&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     kI = 1,  // 0x1
     kS = 2,  // 0x2
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -1403,12 +1301,12 @@
   }
 
   bool is_i() const { return tag_ == ::test::union_::ExplicitFoo::Tag::kI; }
-  
+
   int32_t& i() {
     EnsureStorageInitialized(::test::union_::ExplicitFoo::Tag::kI);
     return i_;
   }
-  
+
   const int32_t& i() const {
     ZX_ASSERT(is_i());
     return i_;
@@ -1416,12 +1314,12 @@
   ExplicitFoo& set_i(int32_t value);
 
   bool is_s() const { return tag_ == ::test::union_::ExplicitFoo::Tag::kS; }
-  
+
   ::std::string& s() {
     EnsureStorageInitialized(::test::union_::ExplicitFoo::Tag::kS);
     return s_;
   }
-  
+
   const ::std::string& s() const {
     ZX_ASSERT(is_s());
     return s_;
@@ -1430,7 +1328,6 @@
   ExplicitFoo& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::ExplicitFoo::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::ExplicitFoo::Tag::Invalid:
       case ::test::union_::ExplicitFoo::Tag::kI:
@@ -1439,7 +1336,6 @@
       default:
         return ::test::union_::ExplicitFoo::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1475,8 +1371,6 @@
 
 using ExplicitFooPtr = ::std::unique_ptr<ExplicitFoo>;
 
-
-
 class ExplicitStrictFoo final {
  public:
   static const fidl_type_t* FidlType;
@@ -1487,12 +1381,11 @@
   ExplicitStrictFoo(ExplicitStrictFoo&&);
   ExplicitStrictFoo& operator=(ExplicitStrictFoo&&);
 
-  
   static ExplicitStrictFoo WithI(int32_t&&);
   static ExplicitStrictFoo WithS(::std::string&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
+
     kI = 2,  // 0x2
     kS = 3,  // 0x3
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -1510,12 +1403,12 @@
   }
 
   bool is_i() const { return tag_ == ::test::union_::ExplicitStrictFoo::Tag::kI; }
-  
+
   int32_t& i() {
     EnsureStorageInitialized(::test::union_::ExplicitStrictFoo::Tag::kI);
     return i_;
   }
-  
+
   const int32_t& i() const {
     ZX_ASSERT(is_i());
     return i_;
@@ -1523,12 +1416,12 @@
   ExplicitStrictFoo& set_i(int32_t value);
 
   bool is_s() const { return tag_ == ::test::union_::ExplicitStrictFoo::Tag::kS; }
-  
+
   ::std::string& s() {
     EnsureStorageInitialized(::test::union_::ExplicitStrictFoo::Tag::kS);
     return s_;
   }
-  
+
   const ::std::string& s() const {
     ZX_ASSERT(is_s());
     return s_;
@@ -1536,9 +1429,7 @@
   ExplicitStrictFoo& set_s(::std::string value);
 
   ::test::union_::ExplicitStrictFoo::Tag Which() const {
-    
     return ::test::union_::ExplicitStrictFoo::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1567,8 +1458,6 @@
 
 using ExplicitStrictFooPtr = ::std::unique_ptr<ExplicitStrictFoo>;
 
-
-
 class OlderSimpleUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -1579,13 +1468,12 @@
   OlderSimpleUnion(OlderSimpleUnion&&);
   OlderSimpleUnion& operator=(OlderSimpleUnion&&);
 
-  
   static OlderSimpleUnion WithI(int64_t&&);
   static OlderSimpleUnion WithF(float&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     kI = 1,  // 0x1
     kF = 2,  // 0x2
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -1603,12 +1491,12 @@
   }
 
   bool is_i() const { return tag_ == ::test::union_::OlderSimpleUnion::Tag::kI; }
-  
+
   int64_t& i() {
     EnsureStorageInitialized(::test::union_::OlderSimpleUnion::Tag::kI);
     return i_;
   }
-  
+
   const int64_t& i() const {
     ZX_ASSERT(is_i());
     return i_;
@@ -1616,12 +1504,12 @@
   OlderSimpleUnion& set_i(int64_t value);
 
   bool is_f() const { return tag_ == ::test::union_::OlderSimpleUnion::Tag::kF; }
-  
+
   float& f() {
     EnsureStorageInitialized(::test::union_::OlderSimpleUnion::Tag::kF);
     return f_;
   }
-  
+
   const float& f() const {
     ZX_ASSERT(is_f());
     return f_;
@@ -1630,7 +1518,6 @@
   OlderSimpleUnion& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::OlderSimpleUnion::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::OlderSimpleUnion::Tag::Invalid:
       case ::test::union_::OlderSimpleUnion::Tag::kI:
@@ -1639,7 +1526,6 @@
       default:
         return ::test::union_::OlderSimpleUnion::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1675,8 +1561,6 @@
 
 using OlderSimpleUnionPtr = ::std::unique_ptr<OlderSimpleUnion>;
 
-
-
 class NewerSimpleUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -1687,14 +1571,13 @@
   NewerSimpleUnion(NewerSimpleUnion&&);
   NewerSimpleUnion& operator=(NewerSimpleUnion&&);
 
-  
   static NewerSimpleUnion WithI(int64_t&&);
   static NewerSimpleUnion WithS(::std::string&&);
   static NewerSimpleUnion WithV(::std::vector<::std::string>&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     kI = 1,  // 0x1
     kS = 2,  // 0x2
     kV = 3,  // 0x3
@@ -1713,12 +1596,12 @@
   }
 
   bool is_i() const { return tag_ == ::test::union_::NewerSimpleUnion::Tag::kI; }
-  
+
   int64_t& i() {
     EnsureStorageInitialized(::test::union_::NewerSimpleUnion::Tag::kI);
     return i_;
   }
-  
+
   const int64_t& i() const {
     ZX_ASSERT(is_i());
     return i_;
@@ -1726,12 +1609,12 @@
   NewerSimpleUnion& set_i(int64_t value);
 
   bool is_s() const { return tag_ == ::test::union_::NewerSimpleUnion::Tag::kS; }
-  
+
   ::std::string& s() {
     EnsureStorageInitialized(::test::union_::NewerSimpleUnion::Tag::kS);
     return s_;
   }
-  
+
   const ::std::string& s() const {
     ZX_ASSERT(is_s());
     return s_;
@@ -1739,12 +1622,12 @@
   NewerSimpleUnion& set_s(::std::string value);
 
   bool is_v() const { return tag_ == ::test::union_::NewerSimpleUnion::Tag::kV; }
-  
+
   ::std::vector<::std::string>& v() {
     EnsureStorageInitialized(::test::union_::NewerSimpleUnion::Tag::kV);
     return v_;
   }
-  
+
   const ::std::vector<::std::string>& v() const {
     ZX_ASSERT(is_v());
     return v_;
@@ -1753,7 +1636,6 @@
   NewerSimpleUnion& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::NewerSimpleUnion::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::NewerSimpleUnion::Tag::Invalid:
       case ::test::union_::NewerSimpleUnion::Tag::kI:
@@ -1763,7 +1645,6 @@
       default:
         return ::test::union_::NewerSimpleUnion::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1800,8 +1681,6 @@
 
 using NewerSimpleUnionPtr = ::std::unique_ptr<NewerSimpleUnion>;
 
-
-
 class StrictSimpleUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -1812,13 +1691,12 @@
   StrictSimpleUnion(StrictSimpleUnion&&);
   StrictSimpleUnion& operator=(StrictSimpleUnion&&);
 
-  
   static StrictSimpleUnion WithI(int32_t&&);
   static StrictSimpleUnion WithF(float&&);
   static StrictSimpleUnion WithS(::std::string&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
+
     kI = 1,  // 0x1
     kF = 2,  // 0x2
     kS = 3,  // 0x3
@@ -1837,12 +1715,12 @@
   }
 
   bool is_i() const { return tag_ == ::test::union_::StrictSimpleUnion::Tag::kI; }
-  
+
   int32_t& i() {
     EnsureStorageInitialized(::test::union_::StrictSimpleUnion::Tag::kI);
     return i_;
   }
-  
+
   const int32_t& i() const {
     ZX_ASSERT(is_i());
     return i_;
@@ -1850,12 +1728,12 @@
   StrictSimpleUnion& set_i(int32_t value);
 
   bool is_f() const { return tag_ == ::test::union_::StrictSimpleUnion::Tag::kF; }
-  
+
   float& f() {
     EnsureStorageInitialized(::test::union_::StrictSimpleUnion::Tag::kF);
     return f_;
   }
-  
+
   const float& f() const {
     ZX_ASSERT(is_f());
     return f_;
@@ -1863,12 +1741,12 @@
   StrictSimpleUnion& set_f(float value);
 
   bool is_s() const { return tag_ == ::test::union_::StrictSimpleUnion::Tag::kS; }
-  
+
   ::std::string& s() {
     EnsureStorageInitialized(::test::union_::StrictSimpleUnion::Tag::kS);
     return s_;
   }
-  
+
   const ::std::string& s() const {
     ZX_ASSERT(is_s());
     return s_;
@@ -1876,9 +1754,7 @@
   StrictSimpleUnion& set_s(::std::string value);
 
   ::test::union_::StrictSimpleUnion::Tag Which() const {
-    
     return ::test::union_::StrictSimpleUnion::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -1908,18 +1784,16 @@
 
 using StrictSimpleUnionPtr = ::std::unique_ptr<StrictSimpleUnion>;
 
-
-
 class Empty final {
  public:
   static const fidl_type_t* FidlType;
-  
-  uint8_t __reserved= 0u;
+
+  uint8_t __reserved = 0u;
 
   static inline ::std::unique_ptr<Empty> New() { return ::std::make_unique<Empty>(); }
 
   void Encode(::fidl::Encoder* _encoder, size_t _offset,
-               cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
+              cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
   static void Decode(::fidl::Decoder* _decoder, Empty* value, size_t _offset);
   zx_status_t Clone(Empty* result) const;
 };
@@ -1931,8 +1805,6 @@
 
 using EmptyPtr = ::std::unique_ptr<Empty>;
 
-
-
 class UnionContainingEmptyStruct final {
  public:
   static const fidl_type_t* FidlType;
@@ -1943,12 +1815,11 @@
   UnionContainingEmptyStruct(UnionContainingEmptyStruct&&);
   UnionContainingEmptyStruct& operator=(UnionContainingEmptyStruct&&);
 
-  
   static UnionContainingEmptyStruct WithEmpty(::test::union_::Empty&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     kEmpty = 1,  // 0x1
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -1965,12 +1836,12 @@
   }
 
   bool is_empty() const { return tag_ == ::test::union_::UnionContainingEmptyStruct::Tag::kEmpty; }
-  
+
   ::test::union_::Empty& empty() {
     EnsureStorageInitialized(::test::union_::UnionContainingEmptyStruct::Tag::kEmpty);
     return empty_;
   }
-  
+
   const ::test::union_::Empty& empty() const {
     ZX_ASSERT(is_empty());
     return empty_;
@@ -1979,7 +1850,6 @@
   UnionContainingEmptyStruct& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::UnionContainingEmptyStruct::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::UnionContainingEmptyStruct::Tag::Invalid:
       case ::test::union_::UnionContainingEmptyStruct::Tag::kEmpty:
@@ -1987,7 +1857,6 @@
       default:
         return ::test::union_::UnionContainingEmptyStruct::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -2022,8 +1891,6 @@
 
 using UnionContainingEmptyStructPtr = ::std::unique_ptr<UnionContainingEmptyStruct>;
 
-
-
 class StrictBoundedUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -2034,11 +1901,10 @@
   StrictBoundedUnion(StrictBoundedUnion&&);
   StrictBoundedUnion& operator=(StrictBoundedUnion&&);
 
-  
   static StrictBoundedUnion WithV(::std::vector<uint8_t>&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  
+
     kV = 1,  // 0x1
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -2055,12 +1921,12 @@
   }
 
   bool is_v() const { return tag_ == ::test::union_::StrictBoundedUnion::Tag::kV; }
-  
+
   ::std::vector<uint8_t>& v() {
     EnsureStorageInitialized(::test::union_::StrictBoundedUnion::Tag::kV);
     return v_;
   }
-  
+
   const ::std::vector<uint8_t>& v() const {
     ZX_ASSERT(is_v());
     return v_;
@@ -2068,9 +1934,7 @@
   StrictBoundedUnion& set_v(::std::vector<uint8_t> value);
 
   ::test::union_::StrictBoundedUnion::Tag Which() const {
-    
     return ::test::union_::StrictBoundedUnion::Tag(tag_);
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -2098,18 +1962,16 @@
 
 using StrictBoundedUnionPtr = ::std::unique_ptr<StrictBoundedUnion>;
 
-
-
 class TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse final {
  public:
   static const fidl_type_t* FidlType;
-  
+
   ::test::union_::StrictBoundedUnion xu;
 
   static inline ::std::unique_ptr<TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse> New() { return ::std::make_unique<TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse>(); }
 
   void Encode(::fidl::Encoder* _encoder, size_t _offset,
-               cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
+              cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
   static void Decode(::fidl::Decoder* _decoder, TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse* value, size_t _offset);
   zx_status_t Clone(TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse* result) const;
 };
@@ -2121,18 +1983,16 @@
 
 using TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponsePtr = ::std::unique_ptr<TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse>;
 
-
-
 class TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse final {
  public:
   static const fidl_type_t* FidlType;
-  
+
   ::test::union_::OlderSimpleUnion xu;
 
   static inline ::std::unique_ptr<TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse> New() { return ::std::make_unique<TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse>(); }
 
   void Encode(::fidl::Encoder* _encoder, size_t _offset,
-               cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
+              cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
   static void Decode(::fidl::Decoder* _decoder, TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse* value, size_t _offset);
   zx_status_t Clone(TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse* result) const;
 };
@@ -2144,28 +2004,20 @@
 
 using TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponsePtr = ::std::unique_ptr<TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse>;
 
-
 #ifdef __Fuchsia__
 
-  
-  
-
-
-
 class TestProtocol_RequestEncoder {
  public:
   static ::fidl::HLCPPOutgoingMessage StrictUnionHenceResponseMayBeStackAllocated(::fidl::MessageEncoder* _encoder) {
-
     return _encoder->GetMessage();
   }
   static ::fidl::HLCPPOutgoingMessage FlexibleUnionHenceResponseMustBeHeapAllocated(::fidl::MessageEncoder* _encoder) {
-
     return _encoder->GetMessage();
   }
 };
-  namespace _internal {
+namespace _internal {
 __LOCAL extern "C" const fidl_type_t test_union_TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponseTable;
-  
+
 __LOCAL extern "C" const fidl_type_t test_union_TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponseTable;
 
 }  // namespace _internal
@@ -2175,14 +2027,12 @@
   static ::fidl::HLCPPOutgoingMessage StrictUnionHenceResponseMayBeStackAllocated(::fidl::MessageEncoder* _encoder, ::test::union_::StrictBoundedUnion* xu) {
     _encoder->Alloc(16);
     ::fidl::Encode(_encoder, xu, 0 + sizeof(fidl_message_header_t));
-    
 
     return _encoder->GetMessage();
   }
   static ::fidl::HLCPPOutgoingMessage FlexibleUnionHenceResponseMustBeHeapAllocated(::fidl::MessageEncoder* _encoder, ::test::union_::OlderSimpleUnion* xu) {
     _encoder->Alloc(16);
     ::fidl::Encode(_encoder, xu, 0 + sizeof(fidl_message_header_t));
-    
 
     return _encoder->GetMessage();
   }
@@ -2190,19 +2040,16 @@
 
 #endif  // __Fuchsia__
 
-
-
-
 class StructWithNullableUnion final {
  public:
   static const fidl_type_t* FidlType;
-  
+
   ::std::unique_ptr<::test::union_::OlderSimpleUnion> x1;
 
   static inline ::std::unique_ptr<StructWithNullableUnion> New() { return ::std::make_unique<StructWithNullableUnion>(); }
 
   void Encode(::fidl::Encoder* _encoder, size_t _offset,
-               cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
+              cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
   static void Decode(::fidl::Decoder* _decoder, StructWithNullableUnion* value, size_t _offset);
   zx_status_t Clone(StructWithNullableUnion* result) const;
 };
@@ -2214,8 +2061,6 @@
 
 using StructWithNullableUnionPtr = ::std::unique_ptr<StructWithNullableUnion>;
 
-
-
 class ExplicitFlexibleUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -2226,13 +2071,12 @@
   ExplicitFlexibleUnion(ExplicitFlexibleUnion&&);
   ExplicitFlexibleUnion& operator=(ExplicitFlexibleUnion&&);
 
-  
   static ExplicitFlexibleUnion WithI(int64_t&&);
   static ExplicitFlexibleUnion WithF(float&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     kI = 1,  // 0x1
     kF = 4,  // 0x4
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
@@ -2250,12 +2094,12 @@
   }
 
   bool is_i() const { return tag_ == ::test::union_::ExplicitFlexibleUnion::Tag::kI; }
-  
+
   int64_t& i() {
     EnsureStorageInitialized(::test::union_::ExplicitFlexibleUnion::Tag::kI);
     return i_;
   }
-  
+
   const int64_t& i() const {
     ZX_ASSERT(is_i());
     return i_;
@@ -2263,12 +2107,12 @@
   ExplicitFlexibleUnion& set_i(int64_t value);
 
   bool is_f() const { return tag_ == ::test::union_::ExplicitFlexibleUnion::Tag::kF; }
-  
+
   float& f() {
     EnsureStorageInitialized(::test::union_::ExplicitFlexibleUnion::Tag::kF);
     return f_;
   }
-  
+
   const float& f() const {
     ZX_ASSERT(is_f());
     return f_;
@@ -2277,7 +2121,6 @@
   ExplicitFlexibleUnion& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::ExplicitFlexibleUnion::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::ExplicitFlexibleUnion::Tag::Invalid:
       case ::test::union_::ExplicitFlexibleUnion::Tag::kI:
@@ -2286,7 +2129,6 @@
       default:
         return ::test::union_::ExplicitFlexibleUnion::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -2322,22 +2164,20 @@
 
 using ExplicitFlexibleUnionPtr = ::std::unique_ptr<ExplicitFlexibleUnion>;
 
-
-
 class UnionSandwich final {
  public:
   static const fidl_type_t* FidlType;
-  
+
   uint32_t a{};
-  
+
   ::test::union_::ExplicitFlexibleUnion u;
-  
+
   uint32_t b{};
 
   static inline ::std::unique_ptr<UnionSandwich> New() { return ::std::make_unique<UnionSandwich>(); }
 
   void Encode(::fidl::Encoder* _encoder, size_t _offset,
-               cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
+              cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt);
   static void Decode(::fidl::Decoder* _decoder, UnionSandwich* value, size_t _offset);
   zx_status_t Clone(UnionSandwich* result) const;
 };
@@ -2349,8 +2189,6 @@
 
 using UnionSandwichPtr = ::std::unique_ptr<UnionSandwich>;
 
-
-
 class UnionWithAttributes final {
  public:
   static const fidl_type_t* FidlType;
@@ -2361,12 +2199,11 @@
   UnionWithAttributes(UnionWithAttributes&&);
   UnionWithAttributes& operator=(UnionWithAttributes&&);
 
-  
   static UnionWithAttributes WithX(int64_t&&);
 
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     kX = 1,  // 0x1
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
@@ -2383,12 +2220,12 @@
   }
 
   bool is_x() const { return tag_ == ::test::union_::UnionWithAttributes::Tag::kX; }
-  
+
   int64_t& x() {
     EnsureStorageInitialized(::test::union_::UnionWithAttributes::Tag::kX);
     return x_;
   }
-  
+
   const int64_t& x() const {
     ZX_ASSERT(is_x());
     return x_;
@@ -2397,7 +2234,6 @@
   UnionWithAttributes& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::UnionWithAttributes::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::UnionWithAttributes::Tag::Invalid:
       case ::test::union_::UnionWithAttributes::Tag::kX:
@@ -2405,7 +2241,6 @@
       default:
         return ::test::union_::UnionWithAttributes::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -2440,8 +2275,6 @@
 
 using UnionWithAttributesPtr = ::std::unique_ptr<UnionWithAttributes>;
 
-
-
 class EmptyFlexibleUnion final {
  public:
   static const fidl_type_t* FidlType;
@@ -2452,11 +2285,9 @@
   EmptyFlexibleUnion(EmptyFlexibleUnion&&);
   EmptyFlexibleUnion& operator=(EmptyFlexibleUnion&&);
 
-  
-
   enum __attribute__((enum_extensibility(closed))) Tag : fidl_xunion_tag_t {
-  kUnknown = 0,
-  
+    kUnknown = 0,
+
     Invalid = ::std::numeric_limits<::fidl_union_tag_t>::max(),
   };
 
@@ -2473,14 +2304,12 @@
   EmptyFlexibleUnion& SetUnknownData(fidl_xunion_tag_t ordinal, std::vector<uint8_t> bytes);
 
   ::test::union_::EmptyFlexibleUnion::Tag Which() const {
-    
     switch (tag_) {
       case ::test::union_::EmptyFlexibleUnion::Tag::Invalid:
         return ::test::union_::EmptyFlexibleUnion::Tag(tag_);
       default:
         return ::test::union_::EmptyFlexibleUnion::Tag::kUnknown;
     }
-    
   }
 
   // You probably want to use Which() method instead of Ordinal(). Use Ordinal() only when you need
@@ -2514,7 +2343,6 @@
 
 using EmptyFlexibleUnionPtr = ::std::unique_ptr<EmptyFlexibleUnion>;
 
-
 }  // namespace union_
 }  // namespace test
 namespace fidl {
@@ -2523,24 +2351,19 @@
 struct CodingTraits<::test::union_::Pizza>
     : public EncodableCodingTraits<::test::union_::Pizza, 16> {};
 
-
-template<>
+template <>
 struct HasPadding<::test::union_::Pizza> : public std::true_type {};
 
-
-
-template<>
+template <>
 struct IsMemcpyCompatible<::test::union_::Pizza> : public internal::BoolConstant<
-    !HasPadding<::test::union_::Pizza>::value
-    && IsMemcpyCompatible<::std::vector<::std::string>>::value> {};
-
+                                                       !HasPadding<::test::union_::Pizza>::value && IsMemcpyCompatible<::std::vector<::std::string>>::value> {};
 
 inline zx_status_t Clone(const ::test::union_::Pizza& value,
                          ::test::union_::Pizza* result) {
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::Pizza> {
   bool operator()(const ::test::union_::Pizza& _lhs, const ::test::union_::Pizza& _rhs) const {
     if (!::fidl::Equals(_lhs.toppings, _rhs.toppings)) {
@@ -2553,24 +2376,19 @@
 struct CodingTraits<::test::union_::Pasta>
     : public EncodableCodingTraits<::test::union_::Pasta, 16> {};
 
-
-template<>
+template <>
 struct HasPadding<::test::union_::Pasta> : public std::true_type {};
 
-
-
-template<>
+template <>
 struct IsMemcpyCompatible<::test::union_::Pasta> : public internal::BoolConstant<
-    !HasPadding<::test::union_::Pasta>::value
-    && IsMemcpyCompatible<::std::string>::value> {};
-
+                                                       !HasPadding<::test::union_::Pasta>::value && IsMemcpyCompatible<::std::string>::value> {};
 
 inline zx_status_t Clone(const ::test::union_::Pasta& value,
                          ::test::union_::Pasta* result) {
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::Pasta> {
   bool operator()(const ::test::union_::Pasta& _lhs, const ::test::union_::Pasta& _rhs) const {
     if (!::fidl::Equals(_lhs.sauce, _rhs.sauce)) {
@@ -2588,7 +2406,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::PizzaOrPasta>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::PizzaOrPasta>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2616,7 +2434,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::PizzaOrPasta> {
   bool operator()(const ::test::union_::PizzaOrPasta& _lhs, const ::test::union_::PizzaOrPasta& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -2630,11 +2448,11 @@
         return ::fidl::Equals(_lhs.pizza_, _rhs.pizza_);
       case ::test::union_::PizzaOrPasta::Tag::kPasta:
         return ::fidl::Equals(_lhs.pasta_, _rhs.pasta_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::ExplicitPizzaOrPasta> : public std::true_type {};
@@ -2645,7 +2463,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::ExplicitPizzaOrPasta>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::ExplicitPizzaOrPasta>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2673,7 +2491,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::ExplicitPizzaOrPasta> {
   bool operator()(const ::test::union_::ExplicitPizzaOrPasta& _lhs, const ::test::union_::ExplicitPizzaOrPasta& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -2687,11 +2505,11 @@
         return ::fidl::Equals(_lhs.pizza_, _rhs.pizza_);
       case ::test::union_::ExplicitPizzaOrPasta::Tag::kPasta:
         return ::fidl::Equals(_lhs.pasta_, _rhs.pasta_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::FlexiblePizzaOrPasta> : public std::true_type {};
@@ -2702,7 +2520,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::FlexiblePizzaOrPasta>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::FlexiblePizzaOrPasta>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2730,7 +2548,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::FlexiblePizzaOrPasta> {
   bool operator()(const ::test::union_::FlexiblePizzaOrPasta& _lhs, const ::test::union_::FlexiblePizzaOrPasta& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -2746,8 +2564,8 @@
         return ::fidl::Equals(_lhs.pasta_, _rhs.pasta_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::StrictPizzaOrPasta> : public std::true_type {};
@@ -2758,7 +2576,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::StrictPizzaOrPasta>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::StrictPizzaOrPasta>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2786,7 +2604,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::StrictPizzaOrPasta> {
   bool operator()(const ::test::union_::StrictPizzaOrPasta& _lhs, const ::test::union_::StrictPizzaOrPasta& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -2800,11 +2618,11 @@
         return ::fidl::Equals(_lhs.pizza_, _rhs.pizza_);
       case ::test::union_::StrictPizzaOrPasta::Tag::kPasta:
         return ::fidl::Equals(_lhs.pasta_, _rhs.pasta_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::Union> : public std::true_type {};
@@ -2815,7 +2633,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::Union>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::Union>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2843,7 +2661,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::Union> {
   bool operator()(const ::test::union_::Union& _lhs, const ::test::union_::Union& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -2859,11 +2677,11 @@
         return ::fidl::Equals(_lhs.StringNeedsConstructor_, _rhs.StringNeedsConstructor_);
       case ::test::union_::Union::Tag::kVectorStringAlsoNeedsConstructor:
         return ::fidl::Equals(_lhs.VectorStringAlsoNeedsConstructor_, _rhs.VectorStringAlsoNeedsConstructor_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::FlexibleUnion> : public std::true_type {};
@@ -2874,7 +2692,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::FlexibleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::FlexibleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2902,7 +2720,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::FlexibleUnion> {
   bool operator()(const ::test::union_::FlexibleUnion& _lhs, const ::test::union_::FlexibleUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -2920,8 +2738,8 @@
         return ::fidl::Equals(_lhs.VectorStringAlsoNeedsConstructor_, _rhs.VectorStringAlsoNeedsConstructor_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::StrictUnion> : public std::true_type {};
@@ -2932,7 +2750,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::StrictUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::StrictUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -2960,7 +2778,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::StrictUnion> {
   bool operator()(const ::test::union_::StrictUnion& _lhs, const ::test::union_::StrictUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -2976,11 +2794,11 @@
         return ::fidl::Equals(_lhs.StringNeedsConstructor_, _rhs.StringNeedsConstructor_);
       case ::test::union_::StrictUnion::Tag::kVectorStringAlsoNeedsConstructor:
         return ::fidl::Equals(_lhs.VectorStringAlsoNeedsConstructor_, _rhs.VectorStringAlsoNeedsConstructor_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::FieldCollision> : public std::true_type {};
@@ -2991,7 +2809,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::FieldCollision>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::FieldCollision>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3019,7 +2837,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::FieldCollision> {
   bool operator()(const ::test::union_::FieldCollision& _lhs, const ::test::union_::FieldCollision& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3031,11 +2849,11 @@
         return true;
       case ::test::union_::FieldCollision::Tag::kFieldCollisionTag:
         return ::fidl::Equals(_lhs.field_collision_tag_, _rhs.field_collision_tag_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::ExplicitUnion> : public std::true_type {};
@@ -3046,7 +2864,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::ExplicitUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::ExplicitUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3074,7 +2892,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::ExplicitUnion> {
   bool operator()(const ::test::union_::ExplicitUnion& _lhs, const ::test::union_::ExplicitUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3088,11 +2906,11 @@
         return ::fidl::Equals(_lhs.Primitive_, _rhs.Primitive_);
       case ::test::union_::ExplicitUnion::Tag::kStringNeedsConstructor:
         return ::fidl::Equals(_lhs.StringNeedsConstructor_, _rhs.StringNeedsConstructor_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::ReverseOrdinalUnion> : public std::true_type {};
@@ -3103,7 +2921,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::ReverseOrdinalUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::ReverseOrdinalUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3131,7 +2949,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::ReverseOrdinalUnion> {
   bool operator()(const ::test::union_::ReverseOrdinalUnion& _lhs, const ::test::union_::ReverseOrdinalUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3145,34 +2963,29 @@
         return ::fidl::Equals(_lhs.first_, _rhs.first_);
       case ::test::union_::ReverseOrdinalUnion::Tag::kSecond:
         return ::fidl::Equals(_lhs.second_, _rhs.second_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct CodingTraits<::test::union_::NullableUnionStruct>
     : public EncodableCodingTraits<::test::union_::NullableUnionStruct, 16> {};
 
-
-template<>
+template <>
 struct HasPadding<::test::union_::NullableUnionStruct> : public std::true_type {};
 
-
-
-template<>
+template <>
 struct IsMemcpyCompatible<::test::union_::NullableUnionStruct> : public internal::BoolConstant<
-    !HasPadding<::test::union_::NullableUnionStruct>::value
-    && IsMemcpyCompatible<::std::unique_ptr<::test::union_::Union>>::value> {};
-
+                                                                     !HasPadding<::test::union_::NullableUnionStruct>::value && IsMemcpyCompatible<::std::unique_ptr<::test::union_::Union>>::value> {};
 
 inline zx_status_t Clone(const ::test::union_::NullableUnionStruct& value,
                          ::test::union_::NullableUnionStruct* result) {
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::NullableUnionStruct> {
   bool operator()(const ::test::union_::NullableUnionStruct& _lhs, const ::test::union_::NullableUnionStruct& _rhs) const {
     if (!::fidl::Equals(_lhs.the_union, _rhs.the_union)) {
@@ -3190,7 +3003,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::FlexibleFoo>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::FlexibleFoo>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3218,7 +3031,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::FlexibleFoo> {
   bool operator()(const ::test::union_::FlexibleFoo& _lhs, const ::test::union_::FlexibleFoo& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3234,8 +3047,8 @@
         return ::fidl::Equals(_lhs.i_, _rhs.i_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::StrictFoo> : public std::true_type {};
@@ -3246,7 +3059,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::StrictFoo>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::StrictFoo>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3274,7 +3087,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::StrictFoo> {
   bool operator()(const ::test::union_::StrictFoo& _lhs, const ::test::union_::StrictFoo& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3288,11 +3101,11 @@
         return ::fidl::Equals(_lhs.s_, _rhs.s_);
       case ::test::union_::StrictFoo::Tag::kI:
         return ::fidl::Equals(_lhs.i_, _rhs.i_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::ExplicitFoo> : public std::true_type {};
@@ -3303,7 +3116,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::ExplicitFoo>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::ExplicitFoo>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3331,7 +3144,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::ExplicitFoo> {
   bool operator()(const ::test::union_::ExplicitFoo& _lhs, const ::test::union_::ExplicitFoo& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3347,8 +3160,8 @@
         return ::fidl::Equals(_lhs.s_, _rhs.s_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::ExplicitStrictFoo> : public std::true_type {};
@@ -3359,7 +3172,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::ExplicitStrictFoo>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::ExplicitStrictFoo>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3387,7 +3200,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::ExplicitStrictFoo> {
   bool operator()(const ::test::union_::ExplicitStrictFoo& _lhs, const ::test::union_::ExplicitStrictFoo& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3401,11 +3214,11 @@
         return ::fidl::Equals(_lhs.i_, _rhs.i_);
       case ::test::union_::ExplicitStrictFoo::Tag::kS:
         return ::fidl::Equals(_lhs.s_, _rhs.s_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::OlderSimpleUnion> : public std::true_type {};
@@ -3416,7 +3229,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::OlderSimpleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::OlderSimpleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3444,7 +3257,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::OlderSimpleUnion> {
   bool operator()(const ::test::union_::OlderSimpleUnion& _lhs, const ::test::union_::OlderSimpleUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3460,8 +3273,8 @@
         return ::fidl::Equals(_lhs.f_, _rhs.f_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::NewerSimpleUnion> : public std::true_type {};
@@ -3472,7 +3285,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::NewerSimpleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::NewerSimpleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3500,7 +3313,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::NewerSimpleUnion> {
   bool operator()(const ::test::union_::NewerSimpleUnion& _lhs, const ::test::union_::NewerSimpleUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3518,8 +3331,8 @@
         return ::fidl::Equals(_lhs.v_, _rhs.v_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::StrictSimpleUnion> : public std::true_type {};
@@ -3530,7 +3343,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::StrictSimpleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::StrictSimpleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3558,7 +3371,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::StrictSimpleUnion> {
   bool operator()(const ::test::union_::StrictSimpleUnion& _lhs, const ::test::union_::StrictSimpleUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3574,31 +3387,26 @@
         return ::fidl::Equals(_lhs.f_, _rhs.f_);
       case ::test::union_::StrictSimpleUnion::Tag::kS:
         return ::fidl::Equals(_lhs.s_, _rhs.s_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct CodingTraits<::test::union_::Empty>
     : public EncodableCodingTraits<::test::union_::Empty, 1> {};
 
-
-
-
-template<>
+template <>
 struct IsMemcpyCompatible<::test::union_::Empty> : public internal::BoolConstant<
-    !HasPadding<::test::union_::Empty>::value
-    && IsMemcpyCompatible<uint8_t>::value> {};
-
+                                                       !HasPadding<::test::union_::Empty>::value && IsMemcpyCompatible<uint8_t>::value> {};
 
 inline zx_status_t Clone(const ::test::union_::Empty& value,
                          ::test::union_::Empty* result) {
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::Empty> {
   bool operator()(const ::test::union_::Empty& _lhs, const ::test::union_::Empty& _rhs) const {
     if (!::fidl::Equals(_lhs.__reserved, _rhs.__reserved)) {
@@ -3616,7 +3424,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::UnionContainingEmptyStruct>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::UnionContainingEmptyStruct>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3644,7 +3452,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::UnionContainingEmptyStruct> {
   bool operator()(const ::test::union_::UnionContainingEmptyStruct& _lhs, const ::test::union_::UnionContainingEmptyStruct& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3658,8 +3466,8 @@
         return ::fidl::Equals(_lhs.empty_, _rhs.empty_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::StrictBoundedUnion> : public std::true_type {};
@@ -3670,7 +3478,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::StrictBoundedUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::StrictBoundedUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3698,7 +3506,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::StrictBoundedUnion> {
   bool operator()(const ::test::union_::StrictBoundedUnion& _lhs, const ::test::union_::StrictBoundedUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3710,34 +3518,29 @@
         return true;
       case ::test::union_::StrictBoundedUnion::Tag::kV:
         return ::fidl::Equals(_lhs.v_, _rhs.v_);
-      
+
       default:
         return false;
-      }
     }
+  }
 };
 template <>
 struct CodingTraits<::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse>
     : public EncodableCodingTraits<::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse, 16> {};
 
-
-template<>
+template <>
 struct HasPadding<::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse> : public std::true_type {};
 
-
-
-template<>
+template <>
 struct IsMemcpyCompatible<::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse> : public internal::BoolConstant<
-    !HasPadding<::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse>::value
-    && IsMemcpyCompatible<::test::union_::StrictBoundedUnion>::value> {};
-
+                                                                                                                 !HasPadding<::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse>::value && IsMemcpyCompatible<::test::union_::StrictBoundedUnion>::value> {};
 
 inline zx_status_t Clone(const ::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse& value,
                          ::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse* result) {
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse> {
   bool operator()(const ::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse& _lhs, const ::test::union_::TestProtocolStrictUnionHenceResponseMayBeStackAllocatedResponse& _rhs) const {
     if (!::fidl::Equals(_lhs.xu, _rhs.xu)) {
@@ -3750,21 +3553,16 @@
 struct CodingTraits<::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse>
     : public EncodableCodingTraits<::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse, 16> {};
 
-
-
-
-template<>
+template <>
 struct IsMemcpyCompatible<::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse> : public internal::BoolConstant<
-    !HasPadding<::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse>::value
-    && IsMemcpyCompatible<::test::union_::OlderSimpleUnion>::value> {};
-
+                                                                                                                   !HasPadding<::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse>::value && IsMemcpyCompatible<::test::union_::OlderSimpleUnion>::value> {};
 
 inline zx_status_t Clone(const ::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse& value,
                          ::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse* result) {
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse> {
   bool operator()(const ::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse& _lhs, const ::test::union_::TestProtocolFlexibleUnionHenceResponseMustBeHeapAllocatedResponse& _rhs) const {
     if (!::fidl::Equals(_lhs.xu, _rhs.xu)) {
@@ -3777,21 +3575,16 @@
 struct CodingTraits<::test::union_::StructWithNullableUnion>
     : public EncodableCodingTraits<::test::union_::StructWithNullableUnion, 16> {};
 
-
-
-
-template<>
+template <>
 struct IsMemcpyCompatible<::test::union_::StructWithNullableUnion> : public internal::BoolConstant<
-    !HasPadding<::test::union_::StructWithNullableUnion>::value
-    && IsMemcpyCompatible<::std::unique_ptr<::test::union_::OlderSimpleUnion>>::value> {};
-
+                                                                         !HasPadding<::test::union_::StructWithNullableUnion>::value && IsMemcpyCompatible<::std::unique_ptr<::test::union_::OlderSimpleUnion>>::value> {};
 
 inline zx_status_t Clone(const ::test::union_::StructWithNullableUnion& value,
                          ::test::union_::StructWithNullableUnion* result) {
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::StructWithNullableUnion> {
   bool operator()(const ::test::union_::StructWithNullableUnion& _lhs, const ::test::union_::StructWithNullableUnion& _rhs) const {
     if (!::fidl::Equals(_lhs.x1, _rhs.x1)) {
@@ -3809,7 +3602,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::ExplicitFlexibleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::ExplicitFlexibleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3837,7 +3630,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::ExplicitFlexibleUnion> {
   bool operator()(const ::test::union_::ExplicitFlexibleUnion& _lhs, const ::test::union_::ExplicitFlexibleUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3853,32 +3646,26 @@
         return ::fidl::Equals(_lhs.f_, _rhs.f_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct CodingTraits<::test::union_::UnionSandwich>
     : public EncodableCodingTraits<::test::union_::UnionSandwich, 32> {};
 
-
-template<>
+template <>
 struct HasPadding<::test::union_::UnionSandwich> : public std::true_type {};
 
-
-
-template<>
+template <>
 struct IsMemcpyCompatible<::test::union_::UnionSandwich> : public internal::BoolConstant<
-    !HasPadding<::test::union_::UnionSandwich>::value
-    && IsMemcpyCompatible<uint32_t>::value
-    && IsMemcpyCompatible<::test::union_::ExplicitFlexibleUnion>::value> {};
-
+                                                               !HasPadding<::test::union_::UnionSandwich>::value && IsMemcpyCompatible<uint32_t>::value && IsMemcpyCompatible<::test::union_::ExplicitFlexibleUnion>::value> {};
 
 inline zx_status_t Clone(const ::test::union_::UnionSandwich& value,
                          ::test::union_::UnionSandwich* result) {
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::UnionSandwich> {
   bool operator()(const ::test::union_::UnionSandwich& _lhs, const ::test::union_::UnionSandwich& _rhs) const {
     if (!::fidl::Equals(_lhs.a, _rhs.a)) {
@@ -3902,7 +3689,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::UnionWithAttributes>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::UnionWithAttributes>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3930,7 +3717,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::UnionWithAttributes> {
   bool operator()(const ::test::union_::UnionWithAttributes& _lhs, const ::test::union_::UnionWithAttributes& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3944,8 +3731,8 @@
         return ::fidl::Equals(_lhs.x_, _rhs.x_);
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 template <>
 struct IsFidlXUnion<::test::union_::EmptyFlexibleUnion> : public std::true_type {};
@@ -3956,7 +3743,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::union_::EmptyFlexibleUnion>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::union_::EmptyFlexibleUnion>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -3984,7 +3771,7 @@
   return ::test::union_::Clone(value, result);
 }
 
-template<>
+template <>
 struct Equality<::test::union_::EmptyFlexibleUnion> {
   bool operator()(const ::test::union_::EmptyFlexibleUnion& _lhs, const ::test::union_::EmptyFlexibleUnion& _rhs) const {
     if (_lhs.Ordinal() != _rhs.Ordinal()) {
@@ -3996,8 +3783,8 @@
         return true;
       default:
         return ::fidl::Equals(_lhs.unknown_data_, _rhs.unknown_data_);
-      }
     }
+  }
 };
 
 //
@@ -4025,7 +3812,8 @@
 
 constexpr uint64_t kTestProtocol_FlexibleUnionHenceResponseMustBeHeapAllocated_Ordinal = 0x694fede3b8829ce2lu;
 
-constexpr ::fidl::MessageDynamicFlags kTestProtocol_FlexibleUnionHenceResponseMustBeHeapAllocated_DynamicFlags = ::fidl::MessageDynamicFlags::kStrictMethod;}  // namespace internal
+constexpr ::fidl::MessageDynamicFlags kTestProtocol_FlexibleUnionHenceResponseMustBeHeapAllocated_DynamicFlags = ::fidl::MessageDynamicFlags::kStrictMethod;
+}  // namespace internal
 
 #endif  // __Fuchsia__
 
@@ -4040,14 +3828,12 @@
   virtual ~TestProtocol();
   using StrictUnionHenceResponseMayBeStackAllocatedCallback =
       fit::function<void(::test::union_::StrictBoundedUnion)>;
-      
+
   virtual void StrictUnionHenceResponseMayBeStackAllocated(StrictUnionHenceResponseMayBeStackAllocatedCallback callback) = 0;
   using FlexibleUnionHenceResponseMustBeHeapAllocatedCallback =
       fit::function<void(::test::union_::OlderSimpleUnion)>;
-      
-  virtual void FlexibleUnionHenceResponseMustBeHeapAllocated(FlexibleUnionHenceResponseMustBeHeapAllocatedCallback callback) = 0;
 
-  
+  virtual void FlexibleUnionHenceResponseMustBeHeapAllocated(FlexibleUnionHenceResponseMustBeHeapAllocatedCallback callback) = 0;
 };
 
 class TestProtocol_RequestDecoder {
@@ -4092,9 +3878,6 @@
   // cts-coverage-fidl-name:test.union/TestProtocol.FlexibleUnionHenceResponseMustBeHeapAllocated
   void FlexibleUnionHenceResponseMustBeHeapAllocated(FlexibleUnionHenceResponseMustBeHeapAllocatedCallback callback) override;
 
-  
-
-
  private:
   TestProtocol_Proxy(const ::test::union_::TestProtocol_Proxy&) = delete;
   TestProtocol_Proxy& operator=(const ::test::union_::TestProtocol_Proxy&) = delete;
@@ -4124,7 +3907,7 @@
   // cts-coverage-fidl-name:test.union/TestProtocol.FlexibleUnionHenceResponseMustBeHeapAllocated
   zx_status_t FlexibleUnionHenceResponseMustBeHeapAllocated(::test::union_::OlderSimpleUnion* out_xu) override;
 
-  private:
+ private:
   ::fidl::internal::SynchronousProxy proxy_;
   friend class ::fidl::SynchronousInterfacePtr<TestProtocol>;
 };
@@ -4133,5 +3916,3 @@
 
 }  // namespace union_
 }  // namespace test
-
-
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/union_sandwich.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/union_sandwich.h.golden
index b66d2ce..94fe327 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/union_sandwich.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/union_sandwich.h.golden
@@ -451,7 +451,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unionsandwich::UnionSize8Alignment4>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unionsandwich::UnionSize8Alignment4>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -537,7 +537,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unionsandwich::UnionSize12Alignment4>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unionsandwich::UnionSize12Alignment4>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -648,7 +648,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unionsandwich::UnionSize24Alignment8>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unionsandwich::UnionSize24Alignment8>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -734,7 +734,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unionsandwich::UnionSize36Alignment4>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unionsandwich::UnionSize36Alignment4>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/unknown_interactions.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/unknown_interactions.h.golden
index c90f5bf..64ace82 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/unknown_interactions.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/unknown_interactions.h.golden
@@ -10171,7 +10171,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocolStrictTwoWayUnionResponse>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocolStrictTwoWayUnionResponse>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10276,7 +10276,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10360,7 +10360,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayFieldsErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayFieldsErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10417,7 +10417,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayUnionErr_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayUnionErr_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10471,7 +10471,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayUnionErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayUnionErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10552,7 +10552,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayTableErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_StrictTwoWayTableErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10636,7 +10636,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWay_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWay_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10720,7 +10720,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayFields_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayFields_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10777,7 +10777,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayUnion_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayUnion_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10831,7 +10831,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayUnion_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayUnion_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10912,7 +10912,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayTable_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayTable_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -10996,7 +10996,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11082,7 +11082,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayFieldsErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayFieldsErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11141,7 +11141,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayUnionErr_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayUnionErr_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11195,7 +11195,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayUnionErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayUnionErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11278,7 +11278,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayTableErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocol_FlexibleTwoWayTableErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11364,7 +11364,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocolStrictEventUnionRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocolStrictEventUnionRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11469,7 +11469,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocolFlexibleEventUnionRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsProtocolFlexibleEventUnionRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11574,7 +11574,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocolStrictTwoWayUnionResponse>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocolStrictTwoWayUnionResponse>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11679,7 +11679,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11763,7 +11763,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayFieldsErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayFieldsErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11820,7 +11820,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayUnionErr_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayUnionErr_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11874,7 +11874,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayUnionErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayUnionErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -11955,7 +11955,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayTableErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocol_StrictTwoWayTableErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12039,7 +12039,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocolStrictEventUnionRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocolStrictEventUnionRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12144,7 +12144,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocolFlexibleEventUnionRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarProtocolFlexibleEventUnionRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12249,7 +12249,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocolStrictTwoWayUnionResponse>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocolStrictTwoWayUnionResponse>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12354,7 +12354,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12438,7 +12438,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayFieldsErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayFieldsErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12495,7 +12495,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayUnionErr_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayUnionErr_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12549,7 +12549,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayUnionErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayUnionErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12630,7 +12630,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayTableErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocol_StrictTwoWayTableErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12714,7 +12714,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocolStrictEventUnionRequest>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedProtocolStrictEventUnionRequest>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12819,7 +12819,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocolStrictTwoWayUnionResponse>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocolStrictTwoWayUnionResponse>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -12924,7 +12924,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13008,7 +13008,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayFieldsErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayFieldsErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13065,7 +13065,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayUnionErr_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayUnionErr_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13119,7 +13119,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayUnionErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayUnionErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13200,7 +13200,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayTableErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_StrictTwoWayTableErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13284,7 +13284,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWay_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWay_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13368,7 +13368,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayFields_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayFields_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13425,7 +13425,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayUnion_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayUnion_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13479,7 +13479,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayUnion_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayUnion_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13560,7 +13560,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayTable_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayTable_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13644,7 +13644,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13730,7 +13730,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayFieldsErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayFieldsErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13789,7 +13789,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayUnionErr_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayUnionErr_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13843,7 +13843,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayUnionErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayUnionErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -13926,7 +13926,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayTableErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsDriverProtocol_FlexibleTwoWayTableErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14012,7 +14012,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionResponse>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocolStrictTwoWayUnionResponse>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14117,7 +14117,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14201,7 +14201,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayFieldsErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayFieldsErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14258,7 +14258,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayUnionErr_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayUnionErr_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14312,7 +14312,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayUnionErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayUnionErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14393,7 +14393,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayTableErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsAjarDriverProtocol_StrictTwoWayTableErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14477,7 +14477,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionResponse>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocolStrictTwoWayUnionResponse>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14582,7 +14582,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14666,7 +14666,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayFieldsErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayFieldsErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14723,7 +14723,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayUnionErr_Response>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayUnionErr_Response>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14777,7 +14777,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayUnionErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayUnionErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
@@ -14858,7 +14858,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayTableErr_Result>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::unknowninteractions::UnknownInteractionsClosedDriverProtocol_StrictTwoWayTableErr_Result>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/fidlgen_hlcpp/goldens/versions.h.golden b/tools/fidl/fidlgen_hlcpp/goldens/versions.h.golden
index ffca3e0..0a37350 100644
--- a/tools/fidl/fidlgen_hlcpp/goldens/versions.h.golden
+++ b/tools/fidl/fidlgen_hlcpp/goldens/versions.h.golden
@@ -391,7 +391,7 @@
 
 template <>
 struct CodingTraits<::test::versions::Bits> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::versions::Bits);
+  static constexpr size_t kInlineSize = sizeof(::test::versions::Bits);
   static void Encode(Encoder* encoder, ::test::versions::Bits* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -420,7 +420,7 @@
 };
 template <>
 struct CodingTraits<::test::versions::Enum> {
-  static constexpr size_t inline_size_v2 = sizeof(::test::versions::Enum);
+  static constexpr size_t kInlineSize = sizeof(::test::versions::Enum);
   static void Encode(Encoder* encoder, ::test::versions::Enum* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info) {
     ZX_DEBUG_ASSERT(!maybe_handle_info);
@@ -500,7 +500,7 @@
 
 template <>
 struct CodingTraits<std::unique_ptr<::test::versions::Union>> {
-  static constexpr size_t inline_size_v2 = 16;
+  static constexpr size_t kInlineSize = 16;
 
   static void Encode(Encoder* encoder, std::unique_ptr<::test::versions::Union>* value, size_t offset,
                      cpp17::optional<::fidl::HandleInformation> maybe_handle_info = cpp17::nullopt) {
diff --git a/tools/fidl/runtime-compat/src/ir.rs b/tools/fidl/runtime-compat/src/ir.rs
index b44d6d7..0bd9b00 100644
--- a/tools/fidl/runtime-compat/src/ir.rs
+++ b/tools/fidl/runtime-compat/src/ir.rs
@@ -371,7 +371,7 @@
             ir_path.clone(),
             "--name".to_string(),
             library_name.to_string(),
-            "--platform".to_string(),
+            "--versioned".to_string(),
             "fuchsia".to_string(),
         ];
 
diff --git a/tools/funnel/src/main.rs b/tools/funnel/src/main.rs
index 7133033..71ea5c6 100644
--- a/tools/funnel/src/main.rs
+++ b/tools/funnel/src/main.rs
@@ -44,7 +44,8 @@
 #[derive(FromArgs)]
 /// ffx Remote forwarding.
 struct Funnel {
-    /// the level to log at.
+    /// sets the log level for  output (default = Error). Other
+    /// possible values are Info, Debug, Warn, and Trace
     #[argh(option, short = 'l', default = "default_log_level()")]
     log_level: LevelFilter,
 
diff --git a/tools/funnel/src/ssh.rs b/tools/funnel/src/ssh.rs
index 8ea9af0..5ea7cb7 100644
--- a/tools/funnel/src/ssh.rs
+++ b/tools/funnel/src/ssh.rs
@@ -88,7 +88,7 @@
         ssh_cmd = ssh_cmd.arg(arg);
     }
     ssh_cmd = ssh_cmd.arg(host.clone());
-    ssh_cmd = ssh_cmd.arg(format!(r#"echo 'Tunnel established'; sleep infinity"#));
+    ssh_cmd = ssh_cmd.arg(format!(r#"echo 'Tunnel established';echo 'Do not forget to run `ffx target add [::1]:8022`'; sleep infinity"#));
 
     // Disable stdin
     ssh_cmd = ssh_cmd.stdin(Stdio::null());
diff --git a/tools/fuzz/fuzzer.go b/tools/fuzz/fuzzer.go
index ca8df1b..6e5ec66 100644
--- a/tools/fuzz/fuzzer.go
+++ b/tools/fuzz/fuzzer.go
@@ -131,10 +131,6 @@
 			f.pkg, f.component, strings.TrimPrefix(relpath, "tmp/"))
 	}
 
-	if strings.HasPrefix(relpath, "pkg/") {
-		return fmt.Sprintf("/pkgfs/packages/%s/0/%s", f.pkg, relpath[4:])
-	}
-
 	if strings.HasPrefix(relpath, "data/") {
 		return fmt.Sprintf("/data/r/sys/fuchsia.com:%s:0#meta:%s/%s",
 			f.pkg, f.manifest, relpath[5:])
diff --git a/tools/integration/testsharder/shard.go b/tools/integration/testsharder/shard.go
index edf2eafb..40a532d 100644
--- a/tools/integration/testsharder/shard.go
+++ b/tools/integration/testsharder/shard.go
@@ -60,6 +60,10 @@
 	// ProductBundle is the name of the product bundle describing the system
 	// against which the test should be run.
 	ProductBundle string `json:"product_bundle,omitempty"`
+
+	// BootupTimeoutSecs is the timeout in seconds that the provided product
+	// bundle/environment is expected to take to boot up the target.
+	BootupTimeoutSecs int `json:"bootup_timeout_secs,omitempty"`
 }
 
 // TargetCPU returns the CPU architecture of the target this shard will run against.
@@ -249,10 +253,11 @@
 			if spec.Test.Isolated {
 				name := fmt.Sprintf("%s-%s", environmentName(e), normalizeTestName(spec.Test.Name))
 				shards = append(shards, &Shard{
-					Name:          name,
-					Tests:         []Test{test},
-					ProductBundle: spec.ProductBundle,
-					Env:           e,
+					Name:              name,
+					Tests:             []Test{test},
+					ProductBundle:     spec.ProductBundle,
+					BootupTimeoutSecs: spec.BootupTimeoutSecs,
+					Env:               e,
 				})
 			} else {
 				tests = append(tests, test)
diff --git a/tools/lib/cm_fidl_analyzer/src/component_instance.rs b/tools/lib/cm_fidl_analyzer/src/component_instance.rs
index ab92878..1e94e69 100644
--- a/tools/lib/cm_fidl_analyzer/src/component_instance.rs
+++ b/tools/lib/cm_fidl_analyzer/src/component_instance.rs
@@ -96,7 +96,7 @@
         let environment = EnvironmentForAnalyzer::new_for_child(&parent, child)?;
         let instanced_moniker = parent.instanced_moniker.child(
             InstancedChildName::try_new(
-                child.child_moniker.name(),
+                child.child_moniker.name().as_str(),
                 child.child_moniker.collection().map(|c| c.as_str()),
                 0,
             )
diff --git a/tools/lib/cm_fidl_analyzer/src/component_model.rs b/tools/lib/cm_fidl_analyzer/src/component_model.rs
index d002252..b0fea3b 100644
--- a/tools/lib/cm_fidl_analyzer/src/component_model.rs
+++ b/tools/lib/cm_fidl_analyzer/src/component_model.rs
@@ -293,13 +293,7 @@
     ) {
         let mut children = vec![];
         for child_decl in instance.decl.children.iter() {
-            let child_moniker = match ChildName::try_new(&child_decl.name, None) {
-                Ok(cm) => cm,
-                Err(err) => {
-                    result.errors.push(anyhow!(err));
-                    continue;
-                }
-            };
+            let child_moniker = ChildName::from((child_decl.name.clone(), None));
             match Self::get_absolute_child_url(&child_decl.url, instance) {
                 Ok(url) => {
                     children.push(Child {
@@ -1713,7 +1707,7 @@
                     .source(cm_rust::OfferSource::Void)
                     .name("my_config")
                     .target(cm_rust::OfferTarget::Child(cm_rust::ChildRef {
-                        name: "child".into(),
+                        name: "child".parse().unwrap(),
                         collection: None,
                     }))
                     .availability(cm_rust::Availability::Optional),
diff --git a/tools/lib/cm_fidl_analyzer/tests/src/routing.rs b/tools/lib/cm_fidl_analyzer/tests/src/routing.rs
index 9b79e11..4e2eb71 100644
--- a/tools/lib/cm_fidl_analyzer/tests/src/routing.rs
+++ b/tools/lib/cm_fidl_analyzer/tests/src/routing.rs
@@ -552,7 +552,7 @@
                             .name("foo")
                             .target_name("foo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target(offer_target_static_child("b")),
                     )
                     .service_default("foo")
                     .child_default("b")
@@ -592,7 +592,7 @@
                             .name("foo")
                             .target_name("foo")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .target(offer_target_static_child("b")),
                     )
                     .service_default("foo")
                     .child_default("b")
@@ -669,8 +669,8 @@
                         OfferBuilder::service()
                             .name("foo")
                             .target_name("foo")
-                            .source(OfferSource::static_child("c".into()))
-                            .target(OfferTarget::static_child("b".to_string())),
+                            .source(offer_source_static_child("c"))
+                            .target(offer_target_static_child("b")),
                     )
                     .child_default("b")
                     .child_default("c")
@@ -800,26 +800,32 @@
                         OfferBuilder::event_stream()
                             .name("started")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::Child(ChildRef {
-                                name: "b".into(),
-                                collection: None,
-                            }))
+                            .target_static_child("b")
                             .scope(vec![
-                                EventScope::Child(ChildRef { name: "b".into(), collection: None }),
-                                EventScope::Child(ChildRef { name: "c".into(), collection: None }),
+                                EventScope::Child(ChildRef {
+                                    name: "b".parse().unwrap(),
+                                    collection: None,
+                                }),
+                                EventScope::Child(ChildRef {
+                                    name: "c".parse().unwrap(),
+                                    collection: None,
+                                }),
                             ]),
                     )
                     .offer(
                         OfferBuilder::event_stream()
                             .name("started")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::Child(ChildRef {
-                                name: "c".into(),
-                                collection: None,
-                            }))
+                            .target_static_child("c")
                             .scope(vec![
-                                EventScope::Child(ChildRef { name: "b".into(), collection: None }),
-                                EventScope::Child(ChildRef { name: "c".into(), collection: None }),
+                                EventScope::Child(ChildRef {
+                                    name: "b".parse().unwrap(),
+                                    collection: None,
+                                }),
+                                EventScope::Child(ChildRef {
+                                    name: "c".parse().unwrap(),
+                                    collection: None,
+                                }),
                             ]),
                     )
                     .child_default("b")
@@ -840,12 +846,9 @@
                         OfferBuilder::event_stream()
                             .name("started")
                             .source(OfferSource::Parent)
-                            .target(OfferTarget::Child(ChildRef {
-                                name: "d".into(),
-                                collection: None,
-                            }))
+                            .target_static_child("d")
                             .scope(vec![EventScope::Child(ChildRef {
-                                name: "e".into(),
+                                name: "e".parse().unwrap(),
                                 collection: None,
                             })]),
                     )
@@ -988,7 +991,7 @@
                         ResolverRegistration {
                             resolver: "base".parse().unwrap(),
                             source: RegistrationSource::Self_,
-                            scheme: "base".into(),
+                            scheme: "base".parse().unwrap(),
                         },
                     ))
                     .resolver_default("base")
@@ -1032,7 +1035,7 @@
                         ResolverRegistration {
                             resolver: "base".parse().unwrap(),
                             source: RegistrationSource::Self_,
-                            scheme: "base".into(),
+                            scheme: "base".parse().unwrap(),
                         },
                     ))
                     .resolver_default("base")
@@ -1121,7 +1124,7 @@
             .name("foo")
             .target_name("bar")
             .source(OfferSource::Self_)
-            .target(OfferTarget::Child(ChildRef { name: "b".into(), collection: None }))
+            .target_static_child("b")
             .build();
         let protocol_decl = CapabilityBuilder::protocol().name("foo").build();
         let components = vec![
@@ -1166,7 +1169,7 @@
     async fn map_route_use_from_child() {
         let use_decl = UseBuilder::protocol()
             .name("bar")
-            .source(UseSource::Child("b".into()))
+            .source(UseSource::Child("b".parse().unwrap()))
             .path("/svc/hippo")
             .build();
         let expose_decl = ExposeBuilder::protocol()
@@ -1254,8 +1257,8 @@
         let a_offer_decl = OfferBuilder::directory()
             .name("baz_data")
             .target_name("foobar_data")
-            .source(OfferSource::static_child("b".to_string()))
-            .target(OfferTarget::static_child("c".to_string()))
+            .source(offer_source_static_child("b"))
+            .target(offer_target_static_child("c"))
             .rights(fio::R_STAR_DIR)
             .build();
         let b_expose_decl = ExposeBuilder::directory()
@@ -1418,7 +1421,7 @@
         let offer_storage_decl = OfferBuilder::storage()
             .name("cache")
             .source(OfferSource::Self_)
-            .target(OfferTarget::static_child("b".to_string()))
+            .target(offer_target_static_child("b"))
             .build();
         let use_storage_decl = UseBuilder::storage().name("cache").path("/storage").build();
         let components = vec![
@@ -1486,7 +1489,7 @@
         let offer_realm_decl = OfferBuilder::protocol()
             .name("fuchsia.component.Realm")
             .source(OfferSource::Framework)
-            .target(OfferTarget::static_child("b".to_string()))
+            .target(offer_target_static_child("b"))
             .build();
         let use_realm_decl = UseBuilder::protocol().name("fuchsia.component.Realm").build();
 
@@ -1541,7 +1544,7 @@
             .name("foo")
             .target_name("bar")
             .source(OfferSource::Parent)
-            .target(OfferTarget::static_child("b".to_string()))
+            .target(offer_target_static_child("b"))
             .build();
         let use_decl = UseBuilder::protocol().name("bar").path("/svc/hippo").build();
         let capability_decl = CapabilityBuilder::protocol()
@@ -1594,7 +1597,7 @@
         let registration_decl = ResolverRegistration {
             resolver: "base".parse().unwrap(),
             source: RegistrationSource::Child("c".to_string()),
-            scheme: "base".into(),
+            scheme: "base".parse().unwrap(),
         };
         let expose_decl =
             ExposeBuilder::resolver().name("base").source(ExposeSource::Self_).build();
@@ -1887,7 +1890,7 @@
             .name("foo_data")
             .target_name("bar_data")
             .source(OfferSource::Self_)
-            .target(OfferTarget::static_child("b".to_string()))
+            .target(offer_target_static_child("b"))
             .rights(fio::R_STAR_DIR)
             .build();
         let directory_decl =
@@ -2046,7 +2049,7 @@
         let offer_protocol_decl = OfferBuilder::protocol()
             .name("fuchsia.examples.Echo")
             .source(OfferSource::Void)
-            .target(OfferTarget::static_child("b".to_string()))
+            .target(offer_target_static_child("b"))
             .availability(Availability::Optional)
             .build();
 
@@ -2094,8 +2097,8 @@
 
         let offer_protocol_decl = OfferBuilder::protocol()
             .name("fuchsia.examples.Echo")
-            .source(OfferSource::static_child("c".to_string()))
-            .target(OfferTarget::static_child("b".to_string()))
+            .source(offer_source_static_child("c"))
+            .target(offer_target_static_child("b"))
             .build();
 
         let components = vec![
diff --git a/tools/lib/cm_fidl_analyzer/tests/src/storage.rs b/tools/lib/cm_fidl_analyzer/tests/src/storage.rs
index cf5fc34..42e33fa 100644
--- a/tools/lib/cm_fidl_analyzer/tests/src/storage.rs
+++ b/tools/lib/cm_fidl_analyzer/tests/src/storage.rs
@@ -7,9 +7,7 @@
         crate::routing::RoutingTestBuilderForAnalyzer,
         cm_fidl_analyzer::route::VerifyRouteResult,
         cm_moniker::InstancedMoniker,
-        cm_rust::{
-            CapabilityDecl, CapabilityTypeName, OfferSource, OfferTarget, StorageDirectorySource,
-        },
+        cm_rust::{CapabilityDecl, CapabilityTypeName, OfferSource, StorageDirectorySource},
         cm_rust_testing::*,
         component_id_index::InstanceId,
         fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_io as fio,
@@ -189,7 +187,7 @@
                         OfferBuilder::storage()
                             .name("cache")
                             .source(OfferSource::Self_)
-                            .target(OfferTarget::static_child("consumer".to_string())),
+                            .target(offer_target_static_child("consumer")),
                     )
                     .child_default("consumer")
                     .build(),
@@ -250,7 +248,7 @@
         let offer_directory_decl = OfferBuilder::directory()
             .name("data")
             .source(OfferSource::Self_)
-            .target(OfferTarget::static_child("storage_provider".to_string()))
+            .target(offer_target_static_child("storage_provider"))
             .rights(fio::RW_STAR_DIR)
             .build();
         let storage_decl = CapabilityBuilder::storage()
@@ -262,7 +260,7 @@
         let offer_storage_decl = OfferBuilder::storage()
             .name("cache")
             .source(OfferSource::Self_)
-            .target(OfferTarget::static_child("not_consumer".to_string()))
+            .target(offer_target_static_child("not_consumer"))
             .build();
         let components = vec![
             (
diff --git a/tools/lib/syslog/syslog.go b/tools/lib/syslog/syslog.go
index 87a5a0b0..e04f150 100644
--- a/tools/lib/syslog/syslog.go
+++ b/tools/lib/syslog/syslog.go
@@ -44,7 +44,7 @@
 }
 
 func ffxLogWithArgs(args ...string) []string {
-	return []string{"log", "--no-color", "--no-symbolize"}
+	return []string{"log", "--no-color", "--symbolize", "off"}
 }
 
 // NewSyslogger creates a new Syslogger, given an SSH session with a Fuchsia instance.
@@ -75,6 +75,8 @@
 func (s *Syslogger) Stream(ctx context.Context, output io.Writer) <-chan error {
 	errs := make(chan error, 1)
 	sendErr := func(errs chan error, err error) {
+		// Wait a bit for any listeners to clear the channel first.
+		time.Sleep(500 * time.Millisecond)
 		select {
 		case <-errs:
 			// Clear the channel if nobody is listening.
@@ -139,19 +141,26 @@
 			}
 
 			logger.Errorf(ctx, "syslog: SSH client unresponsive; will attempt to reconnect and continue streaming: %s", err)
-			if s.client != nil {
-				if err := s.client.ReconnectWithBackoff(ctx, retry.NewConstantBackoff(defaultReconnectInterval)); err != nil {
-					// The context probably got cancelled before we were able to
-					// reconnect.
-					if ctx.Err() != nil {
-						logger.Errorf(ctx, "syslog: %s: %s", constants.CtxReconnectError, ctx.Err())
-					}
-					s.running = false
-					sendErr(errs, err)
-					close(errs)
-					return
-				}
+			var reconnectErr error
+			if s.ffx != nil {
+				reconnectErr = retry.Retry(ctx, retry.WithMaxDuration(retry.NewConstantBackoff(defaultReconnectInterval), 30*time.Second), func() error {
+					return s.ffx.RunWithTarget(ctx, "target", "wait", "-t", "10")
+				}, nil)
+			} else {
+				reconnectErr = s.client.ReconnectWithBackoff(ctx, retry.NewConstantBackoff(defaultReconnectInterval))
 			}
+			if reconnectErr != nil {
+				// The context probably got cancelled before we were able to
+				// reconnect.
+				if ctx.Err() != nil {
+					logger.Errorf(ctx, "syslog: %s: %s", constants.CtxReconnectError, ctx.Err())
+				}
+				s.running = false
+				sendErr(errs, err)
+				close(errs)
+				return
+			}
+
 			// Start streaming from the beginning of the system's uptime again now that
 			// we're rebooting.
 			if s.ffx != nil {
diff --git a/tools/orchestrate/orchestrator.go b/tools/orchestrate/orchestrator.go
index e0264de..0d07949 100644
--- a/tools/orchestrate/orchestrator.go
+++ b/tools/orchestrate/orchestrator.go
@@ -365,7 +365,7 @@
 		return fmt.Errorf("os.Create: %w", err)
 	}
 	r.targetLogFile = logFile
-	cmd := r.ffx.Cmd("log", "--no-symbolize")
+	cmd := r.ffx.Cmd("log", "--symbolize", "off")
 	cmd.Stdout = logFile
 	cmd.Stderr = logFile
 	if err := cmd.Start(); err != nil {
diff --git a/tools/pbtool/src/transfer_manifest.rs b/tools/pbtool/src/transfer_manifest.rs
index f1465af..e76eb2a 100644
--- a/tools/pbtool/src/transfer_manifest.rs
+++ b/tools/pbtool/src/transfer_manifest.rs
@@ -244,7 +244,7 @@
                 name: "fuchsia.com".into(),
                 metadata_path: pb_path.join("repository"),
                 blobs_path: pb_path.join("blobs"),
-                delivery_blob_type: None,
+                delivery_blob_type: 1,
                 root_private_key_path: None,
                 targets_private_key_path: Some(pb_path.join("keys/targets.json")),
                 snapshot_private_key_path: Some(pb_path.join("keys/snapshot.json")),
diff --git a/tools/testing/tefmocheck/string_in_log_check.go b/tools/testing/tefmocheck/string_in_log_check.go
index e49cf6f..f631cfb 100644
--- a/tools/testing/tefmocheck/string_in_log_check.go
+++ b/tools/testing/tefmocheck/string_in_log_check.go
@@ -602,6 +602,13 @@
 			Type:         swarmingOutputType,
 			OnlyOnStates: []string{"TIMED_OUT"},
 		},
+		&stringInLogCheck{
+			String:          fmt.Sprintf("botanist ERROR: %s", botanistconstants.FailedToCaptureSyslogMsg),
+			Type:            swarmingOutputType,
+			AlwaysFlake:     true,
+			AttributeToTest: true,
+			AddTag:          true,
+		},
 		// For https://fxbug.dev/42130052.
 		// Kernel panics and other low-level errors often cause crashes that
 		// manifest as SSH failures, so this check must come after all
diff --git a/zircon/kernel/BUILD.gn b/zircon/kernel/BUILD.gn
index 17fe6e8..7afaeee 100644
--- a/zircon/kernel/BUILD.gn
+++ b/zircon/kernel/BUILD.gn
@@ -60,6 +60,7 @@
 
       toolchain_tags = [
         "kernel",
+        "no-floating-point",
         "standalone",
       ]
 
diff --git a/zircon/kernel/arch/arm64/BUILD.gn b/zircon/kernel/arch/arm64/BUILD.gn
index abf45a4..e598a02 100644
--- a/zircon/kernel/arch/arm64/BUILD.gn
+++ b/zircon/kernel/arch/arm64/BUILD.gn
@@ -18,6 +18,7 @@
     configs = [ "//zircon/kernel/arch/arm64:physmem_config" ]
     toolchain_tags = [
       "kernel",
+      "no-floating-point",
       "strict-align",
     ]
     exclude_variant_tags = [ "instrumented" ]
diff --git a/zircon/kernel/arch/arm64/fpu.cc b/zircon/kernel/arch/arm64/fpu.cc
index 0018348..a93fa07 100644
--- a/zircon/kernel/arch/arm64/fpu.cc
+++ b/zircon/kernel/arch/arm64/fpu.cc
@@ -81,12 +81,12 @@
   // These are 32-bit values, but the msr instruction always uses a
   // 64-bit destination register.
   uint64_t fpcr, fpsr;
-  __asm__(
+  __asm__ volatile(
       ".arch_extension fp\n"
       "mrs %0, fpcr\n"
       ".arch_extension nofp\n"
       : "=r"(fpcr));
-  __asm__(
+  __asm__ volatile(
       ".arch_extension fp\n"
       "mrs %0, fpsr\n"
       ".arch_extension nofp\n"
diff --git a/zircon/kernel/arch/arm64/include/arch/aspace.h b/zircon/kernel/arch/arm64/include/arch/aspace.h
index 23f0bad..bc917d5 100644
--- a/zircon/kernel/arch/arm64/include/arch/aspace.h
+++ b/zircon/kernel/arch/arm64/include/arch/aspace.h
@@ -16,6 +16,7 @@
 #include <fbl/canary.h>
 #include <kernel/mutex.h>
 #include <vm/arch_vm_aspace.h>
+#include <vm/mapping_cursor.h>
 
 enum class ArmAspaceType {
   kUser,        // Userspace address space.
@@ -107,9 +108,9 @@
   void FreePageTable(void* vaddr, paddr_t paddr, ConsistencyManager& cm,
                      Reclaim reclaim = Reclaim::No) TA_REQ(lock_);
 
-  ssize_t MapPageTable(vaddr_t vaddr_in, vaddr_t vaddr_rel_in, paddr_t paddr_in, size_t size_in,
-                       pte_t attrs, uint index_shift, volatile pte_t* page_table,
-                       ConsistencyManager& cm) TA_REQ(lock_);
+  zx_status_t MapPageTable(pte_t attrs, uint index_shift, volatile pte_t* page_table,
+                           ExistingEntryAction existing_action, MappingCursor& cursor,
+                           ConsistencyManager& cm) TA_REQ(lock_);
 
   ssize_t UnmapPageTable(vaddr_t vaddr, vaddr_t vaddr_rel, size_t size, EnlargeOperation enlarge,
                          uint index_shift, volatile pte_t* page_table, ConsistencyManager& cm,
@@ -138,8 +139,6 @@
                              volatile pte_t* page_table, ConsistencyManager& cm) TA_REQ(lock_);
 
   pte_t MmuParamsFromFlags(uint mmu_flags);
-  ssize_t MapPages(vaddr_t vaddr, paddr_t paddr, size_t size, pte_t attrs, vaddr_t vaddr_base,
-                   ConsistencyManager& cm) TA_REQ(lock_);
 
   ssize_t UnmapPages(vaddr_t vaddr, size_t size, EnlargeOperation enlarge, vaddr_t vaddr_base,
                      ConsistencyManager& cm) TA_REQ(lock_);
diff --git a/zircon/kernel/arch/arm64/mmu.cc b/zircon/kernel/arch/arm64/mmu.cc
index c116fe9..ae010b5 100644
--- a/zircon/kernel/arch/arm64/mmu.cc
+++ b/zircon/kernel/arch/arm64/mmu.cc
@@ -30,7 +30,6 @@
 #include <arch/arm64/hypervisor/el2_state.h>
 #include <arch/aspace.h>
 #include <fbl/auto_lock.h>
-#include <fbl/bits.h>
 #include <kernel/auto_preempt_disabler.h>
 #include <kernel/mutex.h>
 #include <ktl/algorithm.h>
@@ -495,9 +494,7 @@
     DEBUG_ASSERT(IS_PAGE_ALIGNED(va));
     DEBUG_ASSERT(aspace_.IsValidVaddr(va));
 
-    pending_tlbs_[num_pending_tlbs_].terminal = terminal;
-    pending_tlbs_[num_pending_tlbs_].va_shifted = va >> 1;
-    num_pending_tlbs_++;
+    pending_tlbs_[num_pending_tlbs_++] = {va, terminal};
   }
 
   // Performs any pending synchronization of TLBs and page table walkers. Includes the DSB to ensure
@@ -531,9 +528,9 @@
       }
     } else {
       for (size_t i = 0; i < num_pending_tlbs_; i++) {
-        const vaddr_t va = pending_tlbs_[i].va_shifted << 1;
+        const vaddr_t va = pending_tlbs_[i].va();
         DEBUG_ASSERT(aspace_.IsValidVaddr(va));
-        aspace_.FlushTLBEntry(va, pending_tlbs_[i].terminal);
+        aspace_.FlushTLBEntry(va, pending_tlbs_[i].terminal());
       }
       cm_single_tlb_invalidates.Add(num_pending_tlbs_);
     }
@@ -564,23 +561,32 @@
 
   // Pending TLBs to flush are stored as 63 bits, with the bottom bit stolen to store the terminal
   // flag. 63 bits is more than enough as these entries are page aligned at the minimum.
-  FBL_BITFIELD_DEF_START(PendingTlbs, uint64_t)
-  FBL_BITFIELD_MEMBER(terminal, 0, 1);
-  FBL_BITFIELD_MEMBER(va_shifted, 1, 63);
-  FBL_BITFIELD_DEF_END();
+  struct PendingTlbs {
+    PendingTlbs() = default;
+    PendingTlbs(uint64_t va, bool terminal) : va_terminal_(va | terminal) {}
 
-  PendingTlbs pending_tlbs_[kMaxPendingTlbs];
+    bool terminal() const { return va_terminal_ & 1; }
+    uint64_t va() const { return va_terminal_ & ~1UL; }
 
-  size_t num_pending_tlbs_ = 0;
+   private:
+    // address[63:1], terminal[0]
+    uint64_t va_terminal_;
+  };
 
-  // vm_page_t's to release to the PMM after the TLB invalidation occurs.
-  list_node to_free_ = LIST_INITIAL_VALUE(to_free_);
+  static_assert(sizeof(PendingTlbs) == 8);
 
   // The aspace we are invalidating TLBs for.
   const ArmArchVmAspace& aspace_;
 
-  // pending ISB
+  // Pending ISB
   bool isb_pending_ = false;
+
+  // vm_page_t's to release to the PMM after the TLB invalidation occurs.
+  list_node to_free_ = LIST_INITIAL_VALUE(to_free_);
+
+  // The main list of pending TLBs.
+  size_t num_pending_tlbs_ = 0;
+  PendingTlbs pending_tlbs_[kMaxPendingTlbs];
 };
 
 uint64_t ArmArchVmAspace::Tcr() const {
@@ -923,49 +929,24 @@
   return unmap_size;
 }
 
-ssize_t ArmArchVmAspace::MapPageTable(vaddr_t vaddr_in, vaddr_t vaddr_rel_in, paddr_t paddr_in,
-                                      size_t size_in, pte_t attrs, const uint index_shift,
-                                      volatile pte_t* page_table, ConsistencyManager& cm) {
-  vaddr_t vaddr = vaddr_in;
-  vaddr_t vaddr_rel = vaddr_rel_in;
-  paddr_t paddr = paddr_in;
-  size_t size = size_in;
-
+zx_status_t ArmArchVmAspace::MapPageTable(pte_t attrs, uint index_shift, volatile pte_t* page_table,
+                                          ExistingEntryAction existing_action,
+                                          MappingCursor& cursor, ConsistencyManager& cm) {
   const vaddr_t block_size = 1UL << index_shift;
-  const vaddr_t block_mask = block_size - 1;
-  LTRACEF("vaddr %#" PRIxPTR ", vaddr_rel %#" PRIxPTR ", paddr %#" PRIxPTR
-          ", size %#zx, attrs %#" PRIx64 ", index shift %u, page_size_shift %u, page_table %p\n",
-          vaddr, vaddr_rel, paddr, size, attrs, index_shift, page_size_shift_, page_table);
+  const uint num_entries = (1u << (page_size_shift_ - 3));
+  const uint64_t index_mask = num_entries - 1;
+  uint index = static_cast<uint>((cursor.vaddr_rel() >> index_shift) & index_mask);
 
-  if ((vaddr_rel | paddr | size) & ((1UL << page_size_shift_) - 1)) {
-    TRACEF("not page aligned: vaddr %#" PRIxPTR ", vaddr_rel %#" PRIxPTR ",paddr %#" PRIxPTR
-           ", size %#zx\n",
-           vaddr, vaddr_rel, paddr, size);
-    return ZX_ERR_INVALID_ARGS;
-  }
-
-  auto cleanup = fit::defer([&]() {
-    AssertHeld(lock_);
-    // Unmapping what we have just mapped in should never fail, and we should not have to enlarge
-    // the unmap for it to succeed.
-    ssize_t result = UnmapPageTable(vaddr_in, vaddr_rel_in, size_in - size, EnlargeOperation::No,
-                                    index_shift, page_table, cm);
-    ASSERT(result >= 0);
-  });
-
-  size_t mapped_size = 0;
-  while (size) {
-    const vaddr_t vaddr_rem = vaddr_rel & block_mask;
-    const size_t chunk_size = ktl::min(size, block_size - vaddr_rem);
-    const vaddr_t index = vaddr_rel >> index_shift;
+  for (; index != num_entries && cursor.size() != 0; ++index) {
     pte_t pte = page_table[index];
 
     // if we're at an unaligned address, not trying to map a block, and not at the terminal level,
     // recurse one more level of the page table tree
-    if (((vaddr_rel | paddr) & block_mask) || (chunk_size != block_size) ||
+    const bool level_valigned = IS_ALIGNED(cursor.vaddr_rel(), block_size);
+    const bool level_paligned = IS_ALIGNED(cursor.paddr(), block_size);
+    if (!level_valigned || !level_paligned || cursor.PageRemaining() < block_size ||
         (index_shift > MMU_PTE_DESCRIPTOR_BLOCK_MAX_SHIFT)) {
       // Lookup the next level page table, allocating if required.
-      bool allocated_page_table = false;
       paddr_t page_table_paddr = 0;
       volatile pte_t* next_page_table = nullptr;
 
@@ -974,9 +955,15 @@
           zx_status_t ret = AllocPageTable(&page_table_paddr);
           if (ret) {
             TRACEF("failed to allocate page table\n");
-            return ret;
+            // The mapping wasn't fully updated, but there is work here
+            // that might need to be undone.
+            size_t partial_update = ktl::min(block_size, cursor.size());
+            // Cancel paddr tracking so we account for the virtual range we need to
+            // unmap without needing to increment in page appropriate amounts.
+            cursor.DropPAddrs();
+            cursor.ConsumeVAddr(partial_update);
+            return ZX_ERR_NO_MEMORY;
           }
-          allocated_page_table = true;
           void* pt_vaddr = paddr_to_physmap(page_table_paddr);
 
           LTRACEF("allocated page table, vaddr %p, paddr 0x%lx\n", pt_vaddr, page_table_paddr);
@@ -994,9 +981,9 @@
           update_pte(&page_table[index], pte);
 
           // Tell the consistency manager that we've mapped an inner node.
-          cm.MapEntry(vaddr, false);
+          cm.MapEntry(cursor.vaddr(), false);
 
-          LTRACEF("pte %p[%#" PRIxPTR "] = %#" PRIx64 "\n", page_table, index, pte);
+          LTRACEF("pte %p[%u] = %#" PRIx64 "\n", page_table, index, pte);
           next_page_table = static_cast<volatile pte_t*>(pt_vaddr);
           break;
         }
@@ -1018,54 +1005,35 @@
       }
       DEBUG_ASSERT(next_page_table);
 
-      ssize_t ret = MapPageTable(vaddr, vaddr_rem, paddr, chunk_size, attrs,
-                                 index_shift - (page_size_shift_ - 3), next_page_table, cm);
-      if (ret < 0) {
-        if (allocated_page_table) {
-          // We just allocated this page table. The unmap in err will not clean it up as the size
-          // we pass in will not cause us to look at this page table. This is reasonable as if we
-          // didn't allocate the page table then we shouldn't look into and potentially unmap
-          // anything from that page table.
-          // Since we just allocated it there should be nothing in it, otherwise the MapPageTable
-          // call would not have failed.
-          DEBUG_ASSERT(page_table_is_clear(next_page_table, page_size_shift_));
-          update_pte(&page_table[index], MMU_PTE_DESCRIPTOR_INVALID);
-
-          // We can safely defer TLB flushing as the consistency manager will not return the backing
-          // page to the PMM until after the tlb is flushed.
-          cm.FlushEntry(vaddr, false);
-          FreePageTable(const_cast<pte_t*>(next_page_table), page_table_paddr, cm);
-        }
+      zx_status_t ret = MapPageTable(attrs, index_shift - (page_size_shift_ - 3), next_page_table,
+                                     existing_action, cursor, cm);
+      if (ret != ZX_OK) {
         return ret;
       }
-      DEBUG_ASSERT(static_cast<size_t>(ret) == chunk_size);
     } else {
       if (is_pte_valid(pte)) {
-        LTRACEF("page table entry already in use, index %#" PRIxPTR ", %#" PRIx64 "\n", index, pte);
-        return ZX_ERR_ALREADY_EXISTS;
-      }
-
-      pte = paddr | attrs;
-      if (index_shift > page_size_shift_) {
-        pte |= MMU_PTE_L012_DESCRIPTOR_BLOCK;
+        if (existing_action == ExistingEntryAction::Error) {
+          LTRACEF("page table entry already in use, index %u %#" PRIx64 "\n", index, pte);
+          return ZX_ERR_ALREADY_EXISTS;
+        }
       } else {
-        pte |= MMU_PTE_L3_DESCRIPTOR_PAGE;
-      }
-      LTRACEF("pte %p[%#" PRIxPTR "] = %#" PRIx64 " (paddr %#lx)\n", page_table, index, pte, paddr);
-      update_pte(&page_table[index], pte);
+        pte = cursor.paddr() | attrs;
+        if (index_shift > page_size_shift_) {
+          pte |= MMU_PTE_L012_DESCRIPTOR_BLOCK;
+        } else {
+          pte |= MMU_PTE_L3_DESCRIPTOR_PAGE;
+        }
+        LTRACEF("pte %p[%u] = %#" PRIx64 " (paddr %#lx)\n", page_table, index, pte, cursor.paddr());
+        update_pte(&page_table[index], pte);
 
-      // Tell the consistency manager we've mapped a new page.
-      cm.MapEntry(vaddr, true);
+        // Tell the consistency manager we've mapped a new page.
+        cm.MapEntry(cursor.vaddr(), true);
+      }
+      cursor.ConsumePAddr(block_size);
     }
-    vaddr += chunk_size;
-    vaddr_rel += chunk_size;
-    paddr += chunk_size;
-    size -= chunk_size;
-    mapped_size += chunk_size;
   }
 
-  cleanup.cancel();
-  return mapped_size;
+  return ZX_OK;
 }
 
 zx_status_t ArmArchVmAspace::ProtectPageTable(vaddr_t vaddr_in, vaddr_t vaddr_rel_in,
@@ -1312,27 +1280,6 @@
   }
 }
 
-ssize_t ArmArchVmAspace::MapPages(vaddr_t vaddr, paddr_t paddr, size_t size, pte_t attrs,
-                                  vaddr_t vaddr_base, ConsistencyManager& cm) {
-  vaddr_t vaddr_rel = vaddr - vaddr_base;
-  vaddr_t vaddr_rel_max = 1UL << top_size_shift_;
-
-  LTRACEF("vaddr %#" PRIxPTR ", paddr %#" PRIxPTR ", size %#" PRIxPTR ", attrs %#" PRIx64
-          ", asid %#x\n",
-          vaddr, paddr, size, attrs, asid_);
-
-  if (vaddr_rel > vaddr_rel_max - size || size > vaddr_rel_max) {
-    TRACEF("vaddr %#" PRIxPTR ", size %#" PRIxPTR " out of range vaddr %#" PRIxPTR
-           ", size %#" PRIxPTR "\n",
-           vaddr, size, vaddr_base, vaddr_rel_max);
-    return ZX_ERR_INVALID_ARGS;
-  }
-
-  LOCAL_KTRACE("mmu map", ("vaddr", vaddr), ("size", size));
-  ssize_t ret = MapPageTable(vaddr, vaddr_rel, paddr, size, attrs, top_index_shift_, tt_virt_, cm);
-  return ret;
-}
-
 ssize_t ArmArchVmAspace::UnmapPages(vaddr_t vaddr, size_t size, EnlargeOperation enlarge,
                                     vaddr_t vaddr_base, ConsistencyManager& cm) {
   vaddr_t vaddr_rel = vaddr - vaddr_base;
@@ -1424,7 +1371,6 @@
     return ZX_OK;
   }
 
-  ssize_t ret;
   {
     Guard<CriticalMutex> a{&lock_};
     ASSERT(updates_enabled_);
@@ -1443,22 +1389,34 @@
     pte_t attrs = MmuParamsFromFlags(mmu_flags);
 
     ConsistencyManager cm(*this);
-    ret = MapPages(vaddr, paddr, count * PAGE_SIZE, attrs, vaddr_base_, cm);
+    MappingCursor cursor(/*paddrs=*/&paddr, /*paddr_count=*/1, /*page_size=*/count * PAGE_SIZE,
+                         /*vaddr=*/vaddr);
+    if (!cursor.SetVaddrRelativeOffset(vaddr_base_, 1ull << top_size_shift_)) {
+      return ZX_ERR_OUT_OF_RANGE;
+    }
+    zx_status_t status =
+        MapPageTable(attrs, top_index_shift_, tt_virt_, ExistingEntryAction::Error, cursor, cm);
     MarkAspaceModified();
+    if (status != ZX_OK) {
+      if (cursor.vaddr() > vaddr) {
+        UnmapPages(vaddr, cursor.vaddr() - vaddr, EnlargeOperation::No, vaddr_base_, cm);
+      }
+      return status;
+    }
+    DEBUG_ASSERT(cursor.size() == 0);
   }
 
   if (mapped) {
-    *mapped = (ret > 0) ? (ret / PAGE_SIZE) : 0u;
-    DEBUG_ASSERT(*mapped <= count);
+    *mapped = count;
   }
 
 #if __has_feature(address_sanitizer)
-  if (ret >= 0 && type_ == ArmAspaceType::kKernel) {
-    asan_map_shadow_for(vaddr, ret);
+  if (type_ == ArmAspaceType::kKernel) {
+    asan_map_shadow_for(vaddr, count * PAGE_SIZE);
   }
 #endif  // __has_feature(address_sanitizer)
 
-  return (ret < 0) ? (zx_status_t)ret : ZX_OK;
+  return ZX_OK;
 }
 
 zx_status_t ArmArchVmAspace::Map(vaddr_t vaddr, paddr_t* phys, size_t count, uint mmu_flags,
@@ -1494,7 +1452,6 @@
     return ZX_OK;
   }
 
-  size_t total_mapped = 0;
   {
     Guard<CriticalMutex> a{&lock_};
     ASSERT(updates_enabled_);
@@ -1510,37 +1467,23 @@
     }
     pte_t attrs = MmuParamsFromFlags(mmu_flags);
 
-    ssize_t ret;
-    size_t idx = 0;
     ConsistencyManager cm(*this);
-    auto undo = fit::defer([&]() TA_NO_THREAD_SAFETY_ANALYSIS {
-      if (idx > 0) {
-        UnmapPages(vaddr, idx * PAGE_SIZE, EnlargeOperation::No, vaddr_base_, cm);
-      }
-    });
-
-    vaddr_t v = vaddr;
-    for (; idx < count; ++idx) {
-      paddr_t paddr = phys[idx];
-      DEBUG_ASSERT(IS_PAGE_ALIGNED(paddr));
-      ret = MapPages(v, paddr, PAGE_SIZE, attrs, vaddr_base_, cm);
-      MarkAspaceModified();
-      if (ret < 0) {
-        zx_status_t status = static_cast<zx_status_t>(ret);
-        if (status != ZX_ERR_ALREADY_EXISTS || existing_action == ExistingEntryAction::Error) {
-          return status;
-        }
-      }
-
-      v += PAGE_SIZE;
-      if (ret > 0) {
-        total_mapped += ret / PAGE_SIZE;
-      }
+    MappingCursor cursor(/*paddrs=*/phys, /*paddr_count=*/count, /*page_size=*/PAGE_SIZE,
+                         /*vaddr=*/vaddr);
+    if (!cursor.SetVaddrRelativeOffset(vaddr_base_, 1ull << top_size_shift_)) {
+      return ZX_ERR_OUT_OF_RANGE;
     }
-    undo.cancel();
+    zx_status_t status =
+        MapPageTable(attrs, top_index_shift_, tt_virt_, existing_action, cursor, cm);
+    MarkAspaceModified();
+    if (status != ZX_OK) {
+      if (cursor.vaddr() > vaddr) {
+        UnmapPages(vaddr, cursor.vaddr() - vaddr, EnlargeOperation::No, vaddr_base_, cm);
+      }
+      return status;
+    }
+    DEBUG_ASSERT(cursor.size() == 0);
   }
-  DEBUG_ASSERT(total_mapped <= count);
-  DEBUG_ASSERT(existing_action != ExistingEntryAction::Error || total_mapped == count);
 
   if (mapped) {
     // For ExistingEntryAction::Error, we should have mapped all the addresses we were asked to.
@@ -1551,7 +1494,7 @@
 
 #if __has_feature(address_sanitizer)
   if (type_ == ArmAspaceType::kKernel) {
-    asan_map_shadow_for(vaddr, total_mapped * PAGE_SIZE);
+    asan_map_shadow_for(vaddr, count * PAGE_SIZE);
   }
 #endif  // __has_feature(address_sanitizer)
 
diff --git a/zircon/kernel/arch/riscv64/include/arch/aspace.h b/zircon/kernel/arch/riscv64/include/arch/aspace.h
index 9e37fc7..65248c1 100644
--- a/zircon/kernel/arch/riscv64/include/arch/aspace.h
+++ b/zircon/kernel/arch/riscv64/include/arch/aspace.h
@@ -14,6 +14,7 @@
 
 #include <arch/riscv64/mmu.h>
 #include <vm/arch_vm_aspace.h>
+#include <vm/mapping_cursor.h>
 
 enum class Riscv64AspaceType {
   kUser,    // Userspace address space.
@@ -114,9 +115,9 @@
 
   void FreePageTable(void* vaddr, paddr_t paddr, ConsistencyManager& cm) TA_REQ(lock_);
 
-  zx::result<size_t> MapPageTable(vaddr_t vaddr_in, vaddr_t vaddr_rel, paddr_t paddr_in,
-                                  size_t size_in, pte_t attrs, uint level,
-                                  volatile pte_t* page_table, ConsistencyManager& cm) TA_REQ(lock_);
+  zx_status_t MapPageTable(pte_t attrs, uint level, volatile pte_t* page_table,
+                           ExistingEntryAction existing_action, MappingCursor& cursor,
+                           ConsistencyManager& cm) TA_REQ(lock_);
 
   zx::result<size_t> UnmapPageTable(vaddr_t vaddr, vaddr_t vaddr_rel, size_t size,
                                     EnlargeOperation enlarge, uint level,
@@ -145,9 +146,6 @@
   zx_status_t SplitLargePage(vaddr_t vaddr, uint level, vaddr_t pt_index,
                              volatile pte_t* page_table, ConsistencyManager& cm) TA_REQ(lock_);
 
-  zx::result<size_t> MapPages(vaddr_t vaddr, paddr_t paddr, size_t size, pte_t attrs,
-                              ConsistencyManager& cm) TA_REQ(lock_);
-
   zx::result<size_t> UnmapPages(vaddr_t vaddr, size_t size, EnlargeOperation enlarge,
                                 ConsistencyManager& cm) TA_REQ(lock_);
 
diff --git a/zircon/kernel/arch/riscv64/mmu.cc b/zircon/kernel/arch/riscv64/mmu.cc
index 2150ad2..b7443b6 100644
--- a/zircon/kernel/arch/riscv64/mmu.cc
+++ b/zircon/kernel/arch/riscv64/mmu.cc
@@ -745,45 +745,20 @@
   return zx::ok(unmap_size);
 }
 
-zx::result<size_t> Riscv64ArchVmAspace::MapPageTable(vaddr_t vaddr_in, vaddr_t vaddr_rel_in,
-                                                     paddr_t paddr_in, size_t size_in, pte_t attrs,
-                                                     uint level, volatile pte_t* page_table,
-                                                     ConsistencyManager& cm) {
-  vaddr_t vaddr = vaddr_in;
-  vaddr_t vaddr_rel = vaddr_rel_in;
-  paddr_t paddr = paddr_in;
-  size_t size = size_in;
-
+zx_status_t Riscv64ArchVmAspace::MapPageTable(pte_t attrs, uint level, volatile pte_t* page_table,
+                                              ExistingEntryAction existing_action,
+                                              MappingCursor& cursor, ConsistencyManager& cm) {
   const vaddr_t block_size = page_size_per_level(level);
-  const vaddr_t block_mask = block_size - 1;
+  uint index = vaddr_to_index(cursor.vaddr(), level);
 
-  LTRACEF("vaddr %#" PRIxPTR ", vaddr_rel %#" PRIxPTR ", paddr %#" PRIxPTR
-          ", size %#zx, attrs %#" PRIx64 ", level %u, page_table %p\n",
-          vaddr, vaddr_rel, paddr, size, attrs, level, page_table);
-
-  if ((vaddr_rel | paddr | size) & (PAGE_MASK)) {
-    TRACEF("not page aligned\n");
-    return zx::error_result(ZX_ERR_INVALID_ARGS);
-  }
-
-  auto cleanup = fit::defer([&]() {
-    AssertHeld(lock_);
-    zx::result<size_t> result = UnmapPageTable(vaddr_in, vaddr_rel_in, size_in - size,
-                                               EnlargeOperation::No, level, page_table, cm);
-    DEBUG_ASSERT(result.is_ok());
-  });
-
-  size_t mapped_size = 0;
-  while (size) {
-    const vaddr_t vaddr_rem = vaddr_rel & block_mask;
-    const size_t chunk_size = ktl::min(size, block_size - vaddr_rem);
-    const vaddr_t index = vaddr_to_index(vaddr_rel, level);
+  for (; index != RISCV64_MMU_PT_ENTRIES && cursor.size() != 0; ++index) {
     pte_t pte = page_table[index];
 
     // if we're at an unaligned address, and not trying to map a block larger than 1GB,
     // recurse one more level of the page table tree
-    if (((vaddr_rel | paddr) & block_mask) || (chunk_size != block_size) || (level > 2)) {
-      bool allocated_page_table = false;
+    const bool level_valigned = IS_ALIGNED(cursor.vaddr_rel(), block_size);
+    const bool level_paligned = IS_ALIGNED(cursor.paddr(), block_size);
+    if (!level_valigned || !level_paligned || cursor.PageRemaining() < block_size || (level > 2)) {
       paddr_t page_table_paddr = 0;
       volatile pte_t* next_page_table = nullptr;
 
@@ -791,10 +766,16 @@
         zx::result<paddr_t> result = AllocPageTable();
         if (result.is_error()) {
           TRACEF("failed to allocate page table\n");
-          return result.take_error();
+          // The mapping wasn't fully updated, but there is work here
+          // that might need to be undone.
+          size_t partial_update = ktl::min(block_size, cursor.size());
+          // Cancel paddr tracking so we account for the virtual range we need to
+          // unmap without needing to increment in page appropriate amounts.
+          cursor.DropPAddrs();
+          cursor.ConsumeVAddr(partial_update);
+          return result.status_value();
         }
         page_table_paddr = result.value();
-        allocated_page_table = true;
         void* pt_vaddr = paddr_to_physmap(page_table_paddr);
 
         LTRACEF("allocated page table, vaddr %p, paddr 0x%lx\n", pt_vaddr, page_table_paddr);
@@ -815,73 +796,53 @@
         }
         // We do not need to sync the walker, despite writing a new entry, as this is a
         // non-terminal entry and so is irrelevant to the walker anyway.
-        LTRACEF("pte %p[%#" PRIxPTR "] = %#" PRIx64 " (paddr %#lx)\n", page_table, index, pte,
-                paddr);
+        LTRACEF("pte %p[%u] = %#" PRIx64 " (paddr %#lx)\n", page_table, index, pte,
+                page_table_paddr);
         next_page_table = static_cast<volatile pte_t*>(pt_vaddr);
       } else if (!riscv64_pte_is_leaf(pte)) {
         page_table_paddr = riscv64_pte_pa(pte);
         LTRACEF("found page table %#" PRIxPTR "\n", page_table_paddr);
         next_page_table = static_cast<volatile pte_t*>(paddr_to_physmap(page_table_paddr));
       } else {
-        return zx::error_result(ZX_ERR_ALREADY_EXISTS);
+        return ZX_ERR_ALREADY_EXISTS;
       }
       DEBUG_ASSERT(next_page_table);
 
-      zx::result<size_t> result =
-          MapPageTable(vaddr, vaddr_rem, paddr, chunk_size, attrs, level - 1, next_page_table, cm);
-      if (result.is_error()) {
-        if (allocated_page_table) {
-          // We just allocated this page table. The unmap in err will not clean it up as the size
-          // we pass in will not cause us to look at this page table. This is reasonable as if we
-          // didn't allocate the page table then we shouldn't look into and potentially unmap
-          // anything from that page table.
-          // Since we just allocated it there should be nothing in it, otherwise the MapPageTable
-          // call would not have failed.
-          DEBUG_ASSERT(page_table_is_clear(next_page_table));
-          page_table[index] = 0;
-
-          // We can safely defer TLB flushing as the consistency manager will not return the backing
-          // page to the PMM until after the tlb is flushed.
-          cm.FlushEntry(vaddr, false);
-          FreePageTable(const_cast<pte_t*>(next_page_table), page_table_paddr, cm);
-        }
+      zx_status_t result =
+          MapPageTable(attrs, level - 1, next_page_table, existing_action, cursor, cm);
+      if (result != ZX_OK) {
         return result;
       }
-      DEBUG_ASSERT(result.value() == chunk_size);
     } else {
       if (riscv64_pte_is_valid(pte)) {
-        LTRACEF("page table entry already in use, index %#" PRIxPTR ", %#" PRIx64 "\n", index, pte);
-        return zx::error_result(ZX_ERR_ALREADY_EXISTS);
-      }
+        if (existing_action == ExistingEntryAction::Error) {
+          LTRACEF("page table entry already in use, index %u, %#" PRIx64 "\n", index, pte);
+          return ZX_ERR_ALREADY_EXISTS;
+        }
+      } else {
+        pte = riscv64_pte_pa_to_pte(cursor.paddr()) | attrs;
+        LTRACEF("pte %p[%u] = %#" PRIx64 "\n", page_table, index, pte);
+        page_table[index] = pte;
 
-      pte = riscv64_pte_pa_to_pte(paddr) | attrs;
-      LTRACEF("pte %p[%#" PRIxPTR "] = %#" PRIx64 "\n", page_table, index, pte);
-      page_table[index] = pte;
-
-      // Flush the TLB on map as well, unlike most architectures.
-      if (IsKernel()) {
-        // Normally we only need a local fence here and secondary cpus at worse would only
-        // get a spurious page fault. However, since spurious PFs are not tolerated in the
-        // kernel we want to do a full flush via the ConsistencyManager for kernel addresses.
-        cm.FlushEntry(vaddr, true);
-      } else if (IsUser()) {
-        // Perform a local sfence.vma on the single page in the local asid. If another cpu were
-        // to page fault on this user address, it will sfence.vma in its PF handler.
-        riscv64_tlb_flush_address_one_asid(vaddr, asid_);
-        kcounter_add(cm_local_page_invalidate, 1);
-      } else [[unlikely]] {
-        PANIC_UNIMPLEMENTED;
+        // Flush the TLB on map as well, unlike most architectures.
+        if (IsKernel()) {
+          // Normally we only need a local fence here and secondary cpus at worse would only
+          // get a spurious page fault. However, since spurious PFs are not tolerated in the
+          // kernel we want to do a full flush via the ConsistencyManager for kernel addresses.
+          cm.FlushEntry(cursor.vaddr(), true);
+        } else if (IsUser()) {
+          // Perform a local sfence.vma on the single page in the local asid. If another cpu were
+          // to page fault on this user address, it will sfence.vma in its PF handler.
+          riscv64_tlb_flush_address_one_asid(cursor.vaddr(), asid_);
+          kcounter_add(cm_local_page_invalidate, 1);
+        } else [[unlikely]] {
+          PANIC_UNIMPLEMENTED;
+        }
       }
+      cursor.ConsumePAddr(block_size);
     }
-    vaddr += chunk_size;
-    vaddr_rel += chunk_size;
-    paddr += chunk_size;
-    size -= chunk_size;
-    mapped_size += chunk_size;
   }
-
-  cleanup.cancel();
-  return zx::ok(mapped_size);
+  return ZX_OK;
 }
 
 zx_status_t Riscv64ArchVmAspace::ProtectPageTable(vaddr_t vaddr_in, vaddr_t vaddr_rel_in,
@@ -1060,15 +1021,6 @@
   }
 }
 
-zx::result<size_t> Riscv64ArchVmAspace::MapPages(vaddr_t vaddr, paddr_t paddr, size_t size,
-                                                 pte_t attrs, ConsistencyManager& cm) {
-  LOCAL_KTRACE("mmu map", (vaddr & ~PAGE_MASK) | ((size >> PAGE_SIZE_SHIFT) & PAGE_MASK));
-  uint level = RISCV64_MMU_PT_LEVELS - 1;
-  zx::result<size_t> ret = MapPageTable(vaddr, vaddr, paddr, size, attrs, level, tt_virt_, cm);
-  mb();
-  return ret;
-}
-
 zx::result<size_t> Riscv64ArchVmAspace::UnmapPages(vaddr_t vaddr, size_t size,
                                                    EnlargeOperation enlarge,
                                                    ConsistencyManager& cm) {
@@ -1121,13 +1073,26 @@
 
   ConsistencyManager cm(*this);
   const pte_t attrs = mmu_flags_to_pte_attr(mmu_flags, IsKernel());
-  zx::result<size_t> result = MapPages(vaddr, paddr, count * PAGE_SIZE, attrs, cm);
+  MappingCursor cursor(/*paddrs=*/&paddr, /*paddr_count=*/1, /*page_size=*/count * PAGE_SIZE,
+                       /*vaddr=*/vaddr);
+  zx_status_t result = MapPageTable(attrs, RISCV64_MMU_PT_LEVELS - 1, tt_virt_,
+                                    ExistingEntryAction::Error, cursor, cm);
+  mb();
+  if (result != ZX_OK) {
+    if (cursor.vaddr() > vaddr) {
+      zx::result<size_t> unmap_result =
+          UnmapPages(vaddr, cursor.vaddr() - vaddr, EnlargeOperation::No, cm);
+      ASSERT(unmap_result.is_ok());
+    }
+    return result;
+  }
+  DEBUG_ASSERT(cursor.size() == 0);
+
   if (mapped) {
-    *mapped = result.is_ok() ? result.value() / PAGE_SIZE : 0u;
-    DEBUG_ASSERT(*mapped <= count);
+    *mapped = count;
   }
 
-  return result.status_value();
+  return ZX_OK;
 }
 
 zx_status_t Riscv64ArchVmAspace::Map(vaddr_t vaddr, paddr_t* phys, size_t count, uint mmu_flags,
@@ -1162,7 +1127,6 @@
     return ZX_OK;
   }
 
-  size_t total_mapped = 0;
   {
     Guard<Mutex> a{AssertOrderedLock, &lock_, LockOrder()};
     if (mmu_flags & ARCH_MMU_FLAG_PERM_EXECUTE) {
@@ -1172,35 +1136,22 @@
       }
     }
 
-    size_t idx = 0;
     ConsistencyManager cm(*this);
-    auto undo = fit::defer([&]() TA_NO_THREAD_SAFETY_ANALYSIS {
-      if (idx > 0) {
-        zx::result<size_t> result = UnmapPages(vaddr, idx * PAGE_SIZE, EnlargeOperation::No, cm);
-        DEBUG_ASSERT(result.is_ok());
-      }
-    });
-
     const pte_t attrs = mmu_flags_to_pte_attr(mmu_flags, IsKernel());
-    vaddr_t v = vaddr;
-    for (; idx < count; ++idx) {
-      paddr_t paddr = phys[idx];
-      DEBUG_ASSERT(IS_PAGE_ALIGNED(paddr));
-      zx::result<size_t> result = MapPages(v, paddr, PAGE_SIZE, attrs, cm);
-      if (result.is_error()) {
-        if (result.error_value() != ZX_ERR_ALREADY_EXISTS ||
-            existing_action == ExistingEntryAction::Error) {
-          return result.error_value();
-        }
-      } else {
-        total_mapped += result.value() / PAGE_SIZE;
+    MappingCursor cursor(/*paddrs=*/phys, /*paddr_count=*/count, /*page_size=*/PAGE_SIZE,
+                         /*vaddr=*/vaddr);
+    zx_status_t result =
+        MapPageTable(attrs, RISCV64_MMU_PT_LEVELS - 1, tt_virt_, existing_action, cursor, cm);
+    mb();
+    if (result != ZX_OK) {
+      if (cursor.vaddr() > vaddr) {
+        zx::result<size_t> unmap_result =
+            UnmapPages(vaddr, cursor.vaddr() - vaddr, EnlargeOperation::No, cm);
+        ASSERT(unmap_result.is_ok());
       }
-
-      v += PAGE_SIZE;
+      return result;
     }
-    undo.cancel();
   }
-  DEBUG_ASSERT(total_mapped <= count);
 
   if (mapped) {
     // For ExistingEntryAction::Error, we should have mapped all the addresses we were asked to.
diff --git a/zircon/kernel/arch/riscv64/phys/boot-shim/linux-riscv64-boot-shim.cc b/zircon/kernel/arch/riscv64/phys/boot-shim/linux-riscv64-boot-shim.cc
index a1c4d80..3b722f9 100644
--- a/zircon/kernel/arch/riscv64/phys/boot-shim/linux-riscv64-boot-shim.cc
+++ b/zircon/kernel/arch/riscv64/phys/boot-shim/linux-riscv64-boot-shim.cc
@@ -105,5 +105,6 @@
     boot.Log();
     boot.Boot();
   }
-  __UNREACHABLE;
+
+  abort();
 }
diff --git a/zircon/kernel/arch/x86/crashlog.cc b/zircon/kernel/arch/x86/crashlog.cc
index 62419bc..eea4ab9 100644
--- a/zircon/kernel/arch/x86/crashlog.cc
+++ b/zircon/kernel/arch/x86/crashlog.cc
@@ -34,6 +34,7 @@
             " R13: %#18" PRIx64 "\n"
             " R14: %#18" PRIx64 "\n"
             " R15: %#18" PRIx64 "\n"
+            "vector: %#18" PRIx64 "\n"
             "errc: %#18" PRIx64 "\n"
             "\n",
             // clang-format on
@@ -41,7 +42,7 @@
             regs.iframe->rbx, regs.iframe->rcx, regs.iframe->rdx, regs.iframe->rsi,
             regs.iframe->rdi, regs.iframe->rbp, regs.iframe->user_sp, regs.iframe->r8,
             regs.iframe->r9, regs.iframe->r10, regs.iframe->r11, regs.iframe->r12, regs.iframe->r13,
-            regs.iframe->r14, regs.iframe->r15, regs.iframe->err_code);
+            regs.iframe->r14, regs.iframe->r15, regs.iframe->vector, regs.iframe->err_code);
   } else {
     fprintf(&target, "x64 REGISTERS: missing\n");
   }
diff --git a/zircon/kernel/arch/x86/page_tables/include/arch/x86/page_tables/page_tables.h b/zircon/kernel/arch/x86/page_tables/include/arch/x86/page_tables/page_tables.h
index 2bd7550..67f487b 100644
--- a/zircon/kernel/arch/x86/page_tables/include/arch/x86/page_tables/page_tables.h
+++ b/zircon/kernel/arch/x86/page_tables/include/arch/x86/page_tables/page_tables.h
@@ -976,14 +976,14 @@
           //   2. it is already writable - we shouldn't downgrade permissions.
           if (!remapping_same_address || !mmu_flags_ro) {
             UpdateEntry(cm, PageTableLevel::PT_L, cursor.vaddr(), existing_entry, cursor.paddr(),
-                        term_flags, /*was_terminal=*/false);
+                        term_flags, /*was_terminal=*/true);
           }
         } else if (existing_action == ExistingEntryAction::Error) {
           return ZX_ERR_ALREADY_EXISTS;
         }
       } else {
         UpdateEntry(cm, PageTableLevel::PT_L, cursor.vaddr(), existing_entry, cursor.paddr(),
-                    term_flags, /*was_terminal=*/false);
+                    term_flags, /*was_terminal=*/true);
       }
       cursor.ConsumePAddr(PAGE_SIZE);
     }
diff --git a/zircon/kernel/arch/x86/phys/BUILD.gn b/zircon/kernel/arch/x86/phys/BUILD.gn
index 3b409e4..af7e6b8 100644
--- a/zircon/kernel/arch/x86/phys/BUILD.gn
+++ b/zircon/kernel/arch/x86/phys/BUILD.gn
@@ -20,7 +20,10 @@
     environment = "kernel.phys32"
     with_shared = false
 
-    toolchain_tags = [ "kernel" ]
+    toolchain_tags = [
+      "kernel",
+      "no-floating-point",
+    ]
 
     configs = [ "//zircon/kernel/arch/x86/phys:phys32_config" ]
 
diff --git a/zircon/kernel/arch/x86/registers.cc b/zircon/kernel/arch/x86/registers.cc
index a03ee7f..8c5577c 100644
--- a/zircon/kernel/arch/x86/registers.cc
+++ b/zircon/kernel/arch/x86/registers.cc
@@ -760,5 +760,5 @@
   fprintf(file,
           " R12: %#18" PRIx64 " R13: %#18" PRIx64 " R14: %#18" PRIx64 " R15: %#18" PRIx64 "\n",
           frame.r12, frame.r13, frame.r14, frame.r15);
-  fprintf(file, "errc: %#18" PRIx64 "\n", frame.err_code);
+  fprintf(file, " vector: %#15" PRIx64 " errc: %#17" PRIx64 "\n", frame.vector, frame.err_code);
 }
diff --git a/zircon/kernel/arch/x86/start.S b/zircon/kernel/arch/x86/start.S
index e4149e5..8d3e409 100644
--- a/zircon/kernel/arch/x86/start.S
+++ b/zircon/kernel/arch/x86/start.S
@@ -98,9 +98,6 @@
     // This is in .bss, so now it's safe to set it.
     mov %r15, PHYS(kernel_entry_ticks)
 
-    /* give the boot allocator a chance to compute the physical address of the kernel */
-    call boot_alloc_init
-
 .Lpaging_setup64:
     /* initialize the default page tables */
     /* Setting the First PML4E with a PDP table reference*/
diff --git a/zircon/kernel/dev/pdev/hw_watchdog/console.cc b/zircon/kernel/dev/pdev/hw_watchdog/console.cc
index faa00dc..3b5cb30 100644
--- a/zircon/kernel/dev/pdev/hw_watchdog/console.cc
+++ b/zircon/kernel/dev/pdev/hw_watchdog/console.cc
@@ -163,6 +163,6 @@
 
 STATIC_COMMAND_START
 STATIC_COMMAND("wdt", "hardware watchdog commands", &cmd_watchdog)
-STATIC_COMMAND_END(gfx)
+STATIC_COMMAND_END(wdt)
 
 #endif
diff --git a/zircon/kernel/dev/udisplay/BUILD.gn b/zircon/kernel/dev/udisplay/BUILD.gn
deleted file mode 100644
index 1392466..0000000
--- a/zircon/kernel/dev/udisplay/BUILD.gn
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2019 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-
-import("//build/zircon/migrated_targets.gni")
-
-zx_library("udisplay") {
-  sources = [ "udisplay.cc" ]
-  deps = [
-    "//zircon/kernel/lib/crashlog",
-    "//zircon/kernel/lib/debuglog",
-    "//zircon/kernel/lib/fbl",
-    "//zircon/kernel/lib/gfx",
-    "//zircon/kernel/lib/gfxconsole",
-    "//zircon/kernel/lib/io",
-    "//zircon/kernel/lib/ktl",
-    "//zircon/kernel/vm:headers",
-  ]
-}
diff --git a/zircon/kernel/dev/udisplay/include/dev/udisplay.h b/zircon/kernel/dev/udisplay/include/dev/udisplay.h
deleted file mode 100644
index 6e27453..0000000
--- a/zircon/kernel/dev/udisplay/include/dev/udisplay.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016 The Fuchsia Authors
-//
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file or at
-// https://opensource.org/licenses/MIT
-
-#ifndef ZIRCON_KERNEL_DEV_UDISPLAY_INCLUDE_DEV_UDISPLAY_H_
-#define ZIRCON_KERNEL_DEV_UDISPLAY_INCLUDE_DEV_UDISPLAY_H_
-
-#include <zircon/compiler.h>
-#include <zircon/types.h>
-
-#include <dev/display.h>
-
-__BEGIN_CDECLS
-
-zx_status_t udisplay_init(void);
-zx_status_t udisplay_set_display_info(display_info* display);
-zx_status_t udisplay_bind_gfxconsole(void);
-
-__END_CDECLS
-
-#ifdef __cplusplus
-
-#include <fbl/ref_ptr.h>
-
-class VmObject;
-zx_status_t udisplay_set_framebuffer(fbl::RefPtr<VmObject> vmo);
-void udisplay_clear_framebuffer_vmo(void);
-
-#endif
-
-#endif  // ZIRCON_KERNEL_DEV_UDISPLAY_INCLUDE_DEV_UDISPLAY_H_
diff --git a/zircon/kernel/dev/udisplay/udisplay.cc b/zircon/kernel/dev/udisplay/udisplay.cc
deleted file mode 100644
index 0763dbe..0000000
--- a/zircon/kernel/dev/udisplay/udisplay.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2016 The Fuchsia Authors
-//
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file or at
-// https://opensource.org/licenses/MIT
-
-#include <assert.h>
-#include <lib/crashlog.h>
-#include <lib/debuglog.h>
-#include <lib/gfxconsole.h>
-#include <lib/io.h>
-#include <platform.h>
-#include <stdlib.h>
-#include <string.h>
-#include <trace.h>
-#include <zircon/boot/crash-reason.h>
-
-#include <dev/udisplay.h>
-#include <ktl/move.h>
-#include <platform/crashlog.h>
-#include <vm/vm_address_region.h>
-#include <vm/vm_aspace.h>
-#include <vm/vm_object.h>
-
-#include <ktl/enforce.h>
-
-#define LOCAL_TRACE 0
-
-constexpr uint kFramebufferArchMmuFlags = ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_WRITE;
-
-struct udisplay_info {
-  void* framebuffer_virt;
-  size_t framebuffer_size;
-  display_info info;
-  fbl::RefPtr<VmMapping> framebuffer_vmo_mapping;
-};
-
-static struct udisplay_info g_udisplay = {};
-
-zx_status_t udisplay_init(void) { return ZX_OK; }
-
-void udisplay_clear_framebuffer_vmo() {
-  if (g_udisplay.framebuffer_vmo_mapping) {
-    g_udisplay.framebuffer_size = 0;
-    g_udisplay.framebuffer_virt = 0;
-    g_udisplay.framebuffer_vmo_mapping->Destroy();
-    g_udisplay.framebuffer_vmo_mapping = nullptr;
-  }
-}
-
-zx_status_t udisplay_set_framebuffer(fbl::RefPtr<VmObject> vmo) {
-  udisplay_clear_framebuffer_vmo();
-
-  const size_t size = vmo->size();
-  zx::result<VmAddressRegion::MapResult> mapping_result =
-      VmAspace::kernel_aspace()->RootVmar()->CreateVmMapping(
-          0 /* ignored */, size, 0 /* align pow2 */, 0 /* vmar flags */, ktl::move(vmo), 0,
-          kFramebufferArchMmuFlags, "framebuffer_vmo");
-  if (mapping_result.is_error()) {
-    return mapping_result.status_value();
-  }
-
-  zx_status_t status = mapping_result->mapping->MapRange(0, size, true);
-  if (status != ZX_OK) {
-    mapping_result->mapping->Destroy();
-    return status;
-  }
-
-  g_udisplay.framebuffer_virt = reinterpret_cast<void*>(mapping_result->base);
-
-  g_udisplay.framebuffer_size = size;
-  g_udisplay.framebuffer_vmo_mapping = mapping_result->mapping;
-  return ZX_OK;
-}
-
-zx_status_t udisplay_set_display_info(display_info* display) {
-  memcpy(&g_udisplay.info, display, sizeof(display_info));
-  return ZX_OK;
-}
-
-zx_status_t udisplay_bind_gfxconsole(void) {
-  if (g_udisplay.framebuffer_virt == 0)
-    return ZX_ERR_NOT_FOUND;
-
-  // bind the display to the gfxconsole
-  g_udisplay.info.framebuffer = g_udisplay.framebuffer_virt;
-  g_udisplay.info.flags = DISPLAY_FLAG_NEEDS_CACHE_FLUSH | DISPLAY_FLAG_CRASH_FRAMEBUFFER;
-  gfxconsole_bind_display(&g_udisplay.info, nullptr);
-
-  return ZX_OK;
-}
diff --git a/zircon/kernel/include/dev/display.h b/zircon/kernel/include/dev/display.h
deleted file mode 100644
index b089cbb..0000000
--- a/zircon/kernel/include/dev/display.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The Fuchsia Authors
-// Copyright (c) 2008-2010 Travis Geiselbrecht
-//
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file or at
-// https://opensource.org/licenses/MIT
-
-#ifndef ZIRCON_KERNEL_INCLUDE_DEV_DISPLAY_H_
-#define ZIRCON_KERNEL_INCLUDE_DEV_DISPLAY_H_
-
-#include <inttypes.h>
-#include <sys/types.h>
-#include <zircon/compiler.h>
-#include <zircon/types.h>
-
-// Forward-declared; defined in <lib/zbi-format/graphics.h>.
-using zbi_pixel_format_t = uint32_t;
-
-int display_init(void *framebuffer);
-int display_enable(bool enable);
-void display_pre_freq_change(void);
-void display_post_freq_change(void);
-
-// Has no effect if DISPLAY_FLAG_CRASH_FRAMEBUFFER is set
-#define DISPLAY_FLAG_HW_FRAMEBUFFER (1 << 0)
-#define DISPLAY_FLAG_NEEDS_CACHE_FLUSH (1 << 1)
-
-// gfxconsole will not allocate a backing buffer
-// or do any other allocations
-#define DISPLAY_FLAG_CRASH_FRAMEBUFFER (1 << 2)
-
-struct display_info {
-  void *framebuffer;
-  zbi_pixel_format_t format;
-  uint width;
-  uint height;
-  uint stride;
-
-  uint32_t flags;
-
-  // Update function
-  void (*flush)(uint starty, uint endy);
-};
-
-zx_status_t display_get_info(display_info *info);
-
-#endif  // ZIRCON_KERNEL_INCLUDE_DEV_DISPLAY_H_
diff --git a/zircon/kernel/include/platform.h b/zircon/kernel/include/platform.h
index 0c01d248..b371f33 100644
--- a/zircon/kernel/include/platform.h
+++ b/zircon/kernel/include/platform.h
@@ -71,9 +71,6 @@
 // Returns true if this system has a debug serial port that is enabled
 bool platform_serial_enabled();
 
-// Returns true if the early graphics console is enabled
-bool platform_early_console_enabled();
-
 // Accessors for the HW reboot reason which may or may not have been delivered
 // by the bootloader.
 void platform_set_hw_reboot_reason(zbi_hw_reboot_reason_t reason);
diff --git a/zircon/kernel/kernel/thread.cc b/zircon/kernel/kernel/thread.cc
index dd12254..321cab1 100644
--- a/zircon/kernel/kernel/thread.cc
+++ b/zircon/kernel/kernel/thread.cc
@@ -363,6 +363,23 @@
 void Thread::Resume() {
   canary_.Assert();
 
+  // We cannot allow a resume to happen if we are holding any spinlocks, unless
+  // local preemption has been disabled.  If we have local preemption enabled,
+  // and a spinlock held, then it is theoretically possible for our current CPU
+  // to be chosen as the target for the thread being resumed, triggering a local
+  // preemption event.  This is illegal; being preempted while holding a
+  // spinlock means that we might lose our CPU while holding a spinlock.
+  //
+  // So, assert this here.  Either we have no spinlocks, or preemption has
+  // already been disabled (presumably to the point where we have dropped all of
+  // our spinlocks)
+  DEBUG_ASSERT_MSG((arch_num_spinlocks_held() == 0) ||
+                       (Thread::Current::Get()->preemption_state().PreemptIsEnabled() == false),
+                   "It is illegal to Resume a thread when any spinlocks are held unless local "
+                   "preemption is disabled.  (spinlocks held %u, preemption enabled %d)",
+                   arch_num_spinlocks_held(),
+                   Thread::Current::Get()->preemption_state().PreemptIsEnabled());
+
   Guard<MonitoredSpinLock, IrqSave> guard{ThreadLock::Get(), SOURCE_TAG};
 
   if (state() == THREAD_DEATH) {
diff --git a/zircon/kernel/lib/boot-options/boot-options.cc b/zircon/kernel/lib/boot-options/boot-options.cc
index 9cb4cf0..a263308 100644
--- a/zircon/kernel/lib/boot-options/boot-options.cc
+++ b/zircon/kernel/lib/boot-options/boot-options.cc
@@ -296,7 +296,7 @@
 
 // Overloads for various types.
 
-bool BootOptions::Parse(std::string_view value, bool BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, bool BootOptions::* member) {
   // Any other value, even an empty value, means true.
   this->*member = value != "false" && value != "0" && value != "off";
   return true;
@@ -306,25 +306,25 @@
   fprintf(out, "%s", value ? "true" : "false");
 }
 
-bool BootOptions::Parse(std::string_view value, uint64_t BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, uint64_t BootOptions::* member) {
   return ParseIntValue(value, this->*member);
 }
 
 void BootOptions::PrintValue(const uint64_t& value, FILE* out) { fprintf(out, "%#" PRIx64, value); }
 
-bool BootOptions::Parse(std::string_view value, uint32_t BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, uint32_t BootOptions::* member) {
   return ParseIntValue(value, this->*member);
 }
 
 void BootOptions::PrintValue(const uint32_t& value, FILE* out) { fprintf(out, "%#" PRIx32, value); }
 
-bool BootOptions::Parse(std::string_view value, uint8_t BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, uint8_t BootOptions::* member) {
   return ParseIntValue(value, this->*member);
 }
 
 void BootOptions::PrintValue(const uint8_t& value, FILE* out) { fprintf(out, "%#" PRIx8, value); }
 
-bool BootOptions::Parse(std::string_view value, SmallString BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, SmallString BootOptions::* member) {
   SmallString& result = this->*member;
   size_t wrote = value.copy(result.data(), result.size());
   // In the event of a value of size greater or equal to SmallString's capacity,
@@ -338,7 +338,7 @@
   fprintf(out, "%s", value.data());
 }
 
-bool BootOptions::Parse(std::string_view value, RedactedHex BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, RedactedHex BootOptions::* member) {
   RedactedHex& result = this->*member;
   if (std::all_of(value.begin(), value.end(), isxdigit)) {
     result.len = value.copy(result.hex.data(), result.hex.size());
@@ -353,7 +353,7 @@
   }
 }
 
-bool BootOptions::Parse(std::string_view value, uart::all::Driver BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, uart::all::Driver BootOptions::* member) {
   if (!uart::all::WithAllDrivers<UartParser>{this->*member}.Parse(value)) {
     // Probably has nowhere to go, but anyway.
     printf("WARN: Unrecognized serial console setting '%.*s' ignored\n",
@@ -367,7 +367,7 @@
   std::visit([out](const auto& uart) { uart.Unparse(out); }, value);
 }
 
-bool BootOptions::Parse(std::string_view value, OomBehavior BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, OomBehavior BootOptions::* member) {
   return Enum<OomBehavior>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -375,7 +375,7 @@
   Enum<OomBehavior>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, EntropyTestSource BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, EntropyTestSource BootOptions::* member) {
   return Enum<EntropyTestSource>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -383,7 +383,7 @@
   Enum<EntropyTestSource>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, PageTableEvictionPolicy BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, PageTableEvictionPolicy BootOptions::* member) {
   return Enum<PageTableEvictionPolicy>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -391,15 +391,7 @@
   Enum<PageTableEvictionPolicy>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, GfxConsoleFont BootOptions::*member) {
-  return Enum<GfxConsoleFont>(EnumParser{value, &(this->*member)}).Check();
-}
-
-void BootOptions::PrintValue(const GfxConsoleFont& value, FILE* out) {
-  Enum<GfxConsoleFont>(EnumPrinter{value, out});
-}
-
-bool BootOptions::Parse(std::string_view value, SerialDebugSyscalls BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, SerialDebugSyscalls BootOptions::* member) {
   return Enum<SerialDebugSyscalls>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -407,7 +399,7 @@
   Enum<SerialDebugSyscalls>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, RootJobBehavior BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, RootJobBehavior BootOptions::* member) {
   return Enum<RootJobBehavior>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -415,7 +407,7 @@
   Enum<RootJobBehavior>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, WallclockType BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, WallclockType BootOptions::* member) {
   return Enum<WallclockType>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -423,7 +415,7 @@
   Enum<WallclockType>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, ScannerLruAction BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, ScannerLruAction BootOptions::* member) {
   return Enum<ScannerLruAction>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -431,7 +423,7 @@
   Enum<ScannerLruAction>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, CompressionStrategy BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, CompressionStrategy BootOptions::* member) {
   return Enum<CompressionStrategy>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -439,7 +431,7 @@
   Enum<CompressionStrategy>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, CompressionStorageStrategy BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, CompressionStorageStrategy BootOptions::* member) {
   return Enum<CompressionStorageStrategy>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -448,7 +440,7 @@
 }
 
 bool BootOptions::Parse(std::string_view value,
-                        std::optional<RamReservation> BootOptions::*member) {
+                        std::optional<RamReservation> BootOptions::* member) {
   if (value.empty()) {
     this->*member = std::nullopt;
   } else if (auto size = ParseInt(value, &value); !size) {
@@ -481,7 +473,7 @@
 
 #if BOOT_OPTIONS_TESTONLY_OPTIONS
 
-bool BootOptions::Parse(std::string_view value, TestEnum BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, TestEnum BootOptions::* member) {
   return Enum<TestEnum>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -489,7 +481,7 @@
   Enum<TestEnum>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, TestStruct BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, TestStruct BootOptions::* member) {
   if (value != "test") {
     printf("WARN: Ignored unknown value '%.*s' for test option\n", static_cast<int>(value.size()),
            value.data());
@@ -506,7 +498,7 @@
 
 #if BOOT_OPTIONS_GENERATOR || defined(__aarch64__)
 
-bool BootOptions::Parse(std::string_view value, Arm64PhysPsciReset BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, Arm64PhysPsciReset BootOptions::* member) {
   return Enum<Arm64PhysPsciReset>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -514,7 +506,7 @@
   Enum<Arm64PhysPsciReset>(EnumPrinter{value, out});
 }
 
-bool BootOptions::Parse(std::string_view value, Arm64AlternateVbar BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, Arm64AlternateVbar BootOptions::* member) {
   return Enum<Arm64AlternateVbar>(EnumParser{value, &(this->*member)}).Check();
 }
 
@@ -526,7 +518,7 @@
 
 #if BOOT_OPTIONS_GENERATOR || defined(__x86_64__)
 
-bool BootOptions::Parse(std::string_view value, IntelHwpPolicy BootOptions::*member) {
+bool BootOptions::Parse(std::string_view value, IntelHwpPolicy BootOptions::* member) {
   return Enum<IntelHwpPolicy>(EnumParser{value, &(this->*member)}).Check();
 }
 
diff --git a/zircon/kernel/lib/boot-options/enum.h b/zircon/kernel/lib/boot-options/enum.h
index ca49667..b477f65 100644
--- a/zircon/kernel/lib/boot-options/enum.h
+++ b/zircon/kernel/lib/boot-options/enum.h
@@ -60,13 +60,6 @@
 };
 
 template <>
-inline constexpr auto Enum<GfxConsoleFont> = [](auto&& Switch) {
-  return Switch  //
-      .Case("9x16", GfxConsoleFont::k9x16)
-      .Case("18x32", GfxConsoleFont::k18x32);
-};
-
-template <>
 inline constexpr auto Enum<RootJobBehavior> = [](auto&& Switch) {
   return Switch  //
       .Case("halt", RootJobBehavior::kHalt)
diff --git a/zircon/kernel/lib/boot-options/include/lib/boot-options/boot-options.h b/zircon/kernel/lib/boot-options/include/lib/boot-options/boot-options.h
index 6b82e36..8d4ace1 100644
--- a/zircon/kernel/lib/boot-options/include/lib/boot-options/boot-options.h
+++ b/zircon/kernel/lib/boot-options/include/lib/boot-options/boot-options.h
@@ -100,8 +100,8 @@
 
   // Overloads parse and print values of various types.
   // |Parse| returns true on successfully parsing the value.
-#define OPTION_TYPE(T)                                  \
-  bool Parse(std::string_view, T BootOptions::*member); \
+#define OPTION_TYPE(T)                                   \
+  bool Parse(std::string_view, T BootOptions::* member); \
   static void PrintValue(const T& value, FILE* out = stdout)
 
   OPTION_TYPE(bool);
@@ -112,7 +112,6 @@
   OPTION_TYPE(RedactedHex);
   OPTION_TYPE(OomBehavior);
   OPTION_TYPE(EntropyTestSource);
-  OPTION_TYPE(GfxConsoleFont);
   OPTION_TYPE(SerialDebugSyscalls);
   OPTION_TYPE(PageTableEvictionPolicy);
   OPTION_TYPE(RootJobBehavior);
diff --git a/zircon/kernel/lib/boot-options/include/lib/boot-options/options.inc b/zircon/kernel/lib/boot-options/include/lib/boot-options/options.inc
index 3a9df0b..a277f3a 100644
--- a/zircon/kernel/lib/boot-options/include/lib/boot-options/options.inc
+++ b/zircon/kernel/lib/boot-options/include/lib/boot-options/options.inc
@@ -312,6 +312,16 @@
 holistic time measurements.
 )""")
 
+DEFINE_OPTION("kernel.phys.backtrace-max", uint32_t, phys_backtrace_max, {64}, R"""(
+When there is a crash in the kernel's early boot phase, it can print out
+backtraces on the serial console; it prints both a backtrace based on frame
+pointers and, when built to use shadow call stacks also a parallel backtrace
+based on the shadow call stack.  Each backtrace will print no more than this
+many frames.  (Most backtraces will end with the outermost frame before hitting
+the limit.)  Setting the limit to zero prints unlimited frames, which for the
+frame-pointers backtrace can get into an infinite loop with some bugs.
+)""")
+
 DEFINE_OPTION("kernel.phys.print-stack-max", uint32_t, phys_print_stack_max, {1024}, R"""(
 When there is a crash in the kernel's early boot phase, it can print out stack
 contents on the serial console.  This is the maximum size (in bytes) of stack
@@ -480,20 +490,6 @@
 the WDT at all.
 )""")
 
-DEFINE_OPTION("gfxconsole.early", bool, gfx_console_early, {false}, R"""(
-This option requests that the kernel start a graphics console
-during early boot (if possible), to display kernel debug print
-messages while the system is starting.  When userspace starts up, a usermode
-graphics console driver takes over.
-
-The early kernel console can be slow on some platforms, so if it is not
-needed for debugging it may speed up boot to disable it.
-)""")
-
-DEFINE_OPTION("gfxconsole.font", GfxConsoleFont, gfx_console_font, {GfxConsoleFont::k9x16}, R"""(
-This option asks the graphics console to use a specific font.
-)""")
-
 DEFINE_OPTION("kernel.halt-on-panic", bool, halt_on_panic, {false}, R"""(
 If this option is set, the system will halt on a kernel panic instead
 of rebooting. To enable halt-on-panic, pass the kernel command line
@@ -598,6 +594,15 @@
 This value should be greater than or equal to `kernel.page-scanner.min-aging-interval`.
 )""")
 
+DEFINE_OPTION("kernel.page-scanner.accessed-scan-interval", uint32_t,
+              page_scanner_accessed_scan_interval, {3}, R"""(
+Sets the time, in seconds, between harvesting page access information. Lower values provide greater
+age fidelity and will improve accuracy of page reclamation choices at the expense of increased CPU
+time spent harvesting.
+
+There is no benefit to setting this to be lower than the `kernel.page-scanner.min-aging-interval`.
+)""")
+
 DEFINE_OPTION("kernel.page-scanner.active-ratio-multiplier", uint32_t,
               page_scanner_active_ratio_multiplier, {2}, R"""(
 Controls the allowable ratio of active pages, compared to inactive pages, before aging is triggered.
diff --git a/zircon/kernel/lib/boot-options/include/lib/boot-options/types.h b/zircon/kernel/lib/boot-options/include/lib/boot-options/types.h
index 3baf398..6b9d21c 100644
--- a/zircon/kernel/lib/boot-options/include/lib/boot-options/types.h
+++ b/zircon/kernel/lib/boot-options/include/lib/boot-options/types.h
@@ -69,9 +69,6 @@
 // See kernel.page-scanner.eviction_policy.
 enum class PageTableEvictionPolicy { kOnRequest, kNever, kAlways };
 
-// See gfxconsole.font.
-enum class GfxConsoleFont { k9x16, k18x32 };
-
 // See kernel.enable-serial-syscalls.
 enum class SerialDebugSyscalls {
   kDisabled,
diff --git a/zircon/kernel/lib/debuglog/BUILD.gn b/zircon/kernel/lib/debuglog/BUILD.gn
index ed8ed0b..7980dcc 100644
--- a/zircon/kernel/lib/debuglog/BUILD.gn
+++ b/zircon/kernel/lib/debuglog/BUILD.gn
@@ -11,7 +11,6 @@
   deps = [
     ":tests",
     "//sdk/lib/fit",
-    "//zircon/kernel/dev/udisplay:headers",
     "//zircon/kernel/lib/boot-options",
     "//zircon/kernel/lib/crashlog",
     "//zircon/kernel/lib/init",
diff --git a/zircon/kernel/lib/debuglog/debuglog.cc b/zircon/kernel/lib/debuglog/debuglog.cc
index 37b243d..b402a20 100644
--- a/zircon/kernel/lib/debuglog/debuglog.cc
+++ b/zircon/kernel/lib/debuglog/debuglog.cc
@@ -19,7 +19,6 @@
 #include <zircon/errors.h>
 #include <zircon/types.h>
 
-#include <dev/udisplay.h>
 #include <kernel/auto_lock.h>
 #include <kernel/lockdep.h>
 #include <kernel/mutex.h>
@@ -96,7 +95,7 @@
     notifier_state_.thread->Resume();
   }
 
-  if (platform_serial_enabled() || platform_early_console_enabled()) {
+  if (platform_serial_enabled()) {
     auto dumper_thunk = [](void* arg) -> int { return static_cast<DLog*>(arg)->DumperThread(); };
     if ((dumper_state_.thread = Thread::Create(kDlogDumperThreadName, dumper_thunk, this,
                                                HIGH_PRIORITY - 2)) != NULL) {
@@ -170,8 +169,6 @@
 }
 
 void DLog::BluescreenInit() {
-  udisplay_bind_gfxconsole();
-
   // replay debuglog?
 
   // Print panic string.
@@ -370,10 +367,7 @@
   return target.used_region().size();
 }
 
-void DLog::OutputLogMessage(ktl::string_view log) {
-  console_write(log);
-  dlog_serial_write(log);
-}
+void DLog::OutputLogMessage(ktl::string_view log) { dlog_serial_write(log); }
 
 // The debuglog notifier thread observes when the debuglog is
 // written and calls the notify callback on any readers that
@@ -615,5 +609,4 @@
 zx_status_t dlog_shutdown(zx_time_t deadline) { return DLOG->Shutdown(deadline); }
 size_t dlog_render_to_crashlog(ktl::span<char> target) { return DLOG->RenderToCrashlog(target); }
 
-LK_INIT_HOOK(
-    debuglog, [](uint level) { DLOG->StartThreads(); }, LK_INIT_LEVEL_PLATFORM)
+LK_INIT_HOOK(debuglog, [](uint level) { DLOG->StartThreads(); }, LK_INIT_LEVEL_PLATFORM)
diff --git a/zircon/kernel/lib/devicetree/testing/data/BUILD.gn b/zircon/kernel/lib/devicetree/testing/data/BUILD.gn
index 9423012..f9561bb 100644
--- a/zircon/kernel/lib/devicetree/testing/data/BUILD.gn
+++ b/zircon/kernel/lib/devicetree/testing/data/BUILD.gn
@@ -27,6 +27,9 @@
 # Synthetic devicetree source files meant for testing, they are not required to reflect any real node.
 dts_synthetic = [
   "synthetic/arm_gic2_no_msi.dts",
+  "synthetic/arm_gic3_stride.dts",
+  "synthetic/arm_gic3_four_stride.dts",
+  "synthetic/arm_gic3_subsumed_stride.dts",
   "synthetic/arm_timer.dts",
   "synthetic/arm_timer_no_frequency_override.dts",
   "synthetic/chosen.dts",
diff --git a/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_four_stride.dts b/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_four_stride.dts
new file mode 100644
index 0000000..e70ab14
--- /dev/null
+++ b/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_four_stride.dts
@@ -0,0 +1,26 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/dts-v1/;
+
+/ {
+    interrupt-parent = <0x8001>;
+    #size-cells = <0x01>;
+    #address-cells = <0x01>;
+    memory@40000000 {
+        reg = <0x00 0x40000000 0x02 0x00>;
+        device_type = "memory";
+    };
+
+    intc@8000000 {
+      phandle = <0x8001>;
+      interrupts = <0x01 0x09 0x04>;
+      reg = <0x8000000 0x10000 0x8100000 0x10000>;
+      #redistributor-regions = <0x04>;
+      redistributor-stride = <0x0 0x20000>;
+      compatible = "arm,gic-v3";
+      interrupt-controller;
+      #interrupt-cells = <0x03>;
+    };
+};
diff --git a/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_stride.dts b/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_stride.dts
new file mode 100644
index 0000000..4a61e95
--- /dev/null
+++ b/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_stride.dts
@@ -0,0 +1,26 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/dts-v1/;
+
+/ {
+    interrupt-parent = <0x8001>;
+    #size-cells = <0x01>;
+    #address-cells = <0x01>;
+    memory@40000000 {
+        reg = <0x00 0x40000000 0x02 0x00>;
+        device_type = "memory";
+    };
+
+    intc@8000000 {
+      phandle = <0x8001>;
+      interrupts = <0x01 0x09 0x04>;
+      reg = <0x8000000 0x10000 0x8100000 0x10000>;
+      #redistributor-regions = <0x01>;
+      redistributor-stride = <0x0 0x20000>;
+      compatible = "arm,gic-v3";
+      interrupt-controller;
+      #interrupt-cells = <0x03>;
+    };
+};
diff --git a/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_subsumed_stride.dts b/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_subsumed_stride.dts
new file mode 100644
index 0000000..3d7dd33
--- /dev/null
+++ b/zircon/kernel/lib/devicetree/testing/data/synthetic/arm_gic3_subsumed_stride.dts
@@ -0,0 +1,26 @@
+// Copyright 2023 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/dts-v1/;
+
+/ {
+    interrupt-parent = <0x8001>;
+    #size-cells = <0x01>;
+    #address-cells = <0x01>;
+    memory@40000000 {
+        reg = <0x00 0x40000000 0x02 0x00>;
+        device_type = "memory";
+    };
+
+    intc@8000000 {
+      phandle = <0x8001>;
+      interrupts = <0x01 0x09 0x04>;
+      reg = <0x8000000 0x10000 0x8100000 0x20000>;
+      #redistributor-regions = <0x01>;
+      redistributor-stride = <0x0 0x20000>;
+      compatible = "arm,gic-v3";
+      interrupt-controller;
+      #interrupt-cells = <0x03>;
+    };
+};
diff --git a/zircon/kernel/lib/gfx/BUILD.gn b/zircon/kernel/lib/gfx/BUILD.gn
deleted file mode 100644
index ce6a650..0000000
--- a/zircon/kernel/lib/gfx/BUILD.gn
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2019 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-
-import("//build/zircon/migrated_targets.gni")
-
-zx_library("gfx") {
-  sources = [ "gfx.cc" ]
-  deps = [
-    "//sdk/lib/zbi-format",
-    "//zircon/kernel/lib/console",
-  ]
-  public_deps = [ "//zircon/system/ulib/gfx-common" ]
-}
diff --git a/zircon/kernel/lib/gfx/gfx.cc b/zircon/kernel/lib/gfx/gfx.cc
deleted file mode 100644
index f6a1bf6..0000000
--- a/zircon/kernel/lib/gfx/gfx.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2016 The Fuchsia Authors
-// Copyright (c) 2008-2010, 2015 Travis Geiselbrecht
-//
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file or at
-// https://opensource.org/licenses/MIT
-
-#include <debug.h>
-#include <lib/gfx.h>
-#include <lib/zbi-format/graphics.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <trace.h>
-#include <zircon/errors.h>
-#include <zircon/types.h>
-
-#include <arch/ops.h>
-#include <dev/display.h>
-
-#define LOCAL_TRACE 0
-
-static void kernel_gfx_log(const char* format, ...) {
-  if (LOCAL_TRACE) {
-    va_list args;
-    va_start(args, format);
-    vprintf(format, args);
-    va_end(args);
-  }
-}
-
-static void kernel_gfx_flush_cache(void* ptr, size_t size) {
-  arch_clean_cache_range(reinterpret_cast<vaddr_t>(ptr), size);
-}
-
-static const gfx_context g_kernel_ctx = {
-    .log = kernel_gfx_log,
-    .panic = panic,
-    .flush_cache = kernel_gfx_flush_cache,
-};
-
-/**
- * @brief  Create a new graphics surface object
- */
-gfx_surface* gfx_create_surface(void* ptr, uint width, uint height, uint stride, gfx_format format,
-                                uint32_t flags) {
-  return gfx_create_surface_with_context(ptr, &g_kernel_ctx, width, height, stride, format, flags);
-}
-
-/**
- * @brief  Create a new graphics surface object from a display
- */
-gfx_surface* gfx_create_surface_from_display(struct display_info* info) {
-  gfx_surface* surface = static_cast<gfx_surface*>(calloc(1, sizeof(*surface)));
-  if (surface == NULL)
-    return NULL;
-  if (gfx_init_surface_from_display(surface, info)) {
-    free(surface);
-    return NULL;
-  }
-  return surface;
-}
-
-zx_status_t gfx_init_surface_from_display(gfx_surface* surface, struct display_info* info) {
-  zx_status_t r;
-  switch (info->format) {
-    case ZBI_PIXEL_FORMAT_RGB_565:
-    case ZBI_PIXEL_FORMAT_RGB_332:
-    case ZBI_PIXEL_FORMAT_RGB_2220:
-    case ZBI_PIXEL_FORMAT_ARGB_8888:
-    case ZBI_PIXEL_FORMAT_RGB_X888:
-    case ZBI_PIXEL_FORMAT_MONO_8:
-      // supported formats
-      break;
-    default:
-      dprintf(CRITICAL, "invalid graphics format %x", info->format);
-      return ZX_ERR_INVALID_ARGS;
-  }
-
-  uint32_t flags = (info->flags & DISPLAY_FLAG_NEEDS_CACHE_FLUSH) ? GFX_FLAG_FLUSH_CPU_CACHE : 0;
-  r = gfx_init_surface(surface, info->framebuffer, info->width, info->height, info->stride,
-                       info->format, flags);
-
-  surface->flush = info->flush;
-  return r;
-}
-
-/**
- * @brief  Write a test pattern to the default display.
- */
-void gfx_draw_pattern(void) {
-  struct display_info info;
-  if (display_get_info(&info) < 0)
-    return;
-
-  gfx_surface* surface = gfx_create_surface_from_display(&info);
-  DEBUG_ASSERT(surface != nullptr);
-
-  uint x, y;
-  for (y = 0; y < surface->height; y++) {
-    for (x = 0; x < surface->width; x++) {
-      uint scaledx;
-      uint scaledy;
-
-      scaledx = x * 256 / surface->width;
-      scaledy = y * 256 / surface->height;
-
-      gfx_putpixel(surface, x, y,
-                   (0xff << 24) | (scaledx * scaledy) << 16 | (scaledx >> 1) << 8 | scaledy >> 1);
-    }
-  }
-
-  gfx_flush(surface);
-
-  gfx_surface_destroy(surface);
-}
-
-/**
- * @brief  Fill default display with white
- */
-[[maybe_unused]] static void gfx_draw_pattern_white(void) {
-  struct display_info info;
-  if (display_get_info(&info) < 0)
-    return;
-
-  gfx_surface* surface = gfx_create_surface_from_display(&info);
-  DEBUG_ASSERT(surface != nullptr);
-
-  uint x, y;
-  for (y = 0; y < surface->height; y++) {
-    for (x = 0; x < surface->width; x++) {
-      gfx_putpixel(surface, x, y, 0xFFFFFFFF);
-    }
-  }
-
-  gfx_flush(surface);
-
-  gfx_surface_destroy(surface);
-}
-
-#if LK_DEBUGLEVEL > 1
-#include <lib/console.h>
-
-static int cmd_gfx(int argc, const cmd_args* argv, uint32_t flags);
-
-STATIC_COMMAND_START
-STATIC_COMMAND("gfx", "gfx commands", &cmd_gfx)
-STATIC_COMMAND_END(gfx)
-
-static int gfx_draw_rgb_bars(gfx_surface* surface) {
-  uint x, y;
-
-  uint step = surface->height * 100 / 256;
-  uint color;
-
-  for (y = 0; y < surface->height; y++) {
-    // R
-    for (x = 0; x < surface->width / 3; x++) {
-      color = y * 100 / step;
-      gfx_putpixel(surface, x, y, 0xff << 24 | color << 16);
-    }
-    // G
-    for (; x < 2 * (surface->width / 3); x++) {
-      color = y * 100 / step;
-      gfx_putpixel(surface, x, y, 0xff << 24 | color << 8);
-    }
-    // B
-    for (; x < surface->width; x++) {
-      color = y * 100 / step;
-      gfx_putpixel(surface, x, y, 0xff << 24 | color);
-    }
-  }
-
-  return 0;
-}
-
-static int cmd_gfx(int argc, const cmd_args* argv, uint32_t flags) {
-  if (argc < 2) {
-    printf("not enough arguments:\n");
-    printf("%s display_info : output information bout the current display\n", argv[0].str);
-    printf("%s rgb_bars   : Fill frame buffer with rgb bars\n", argv[0].str);
-    printf("%s test_pattern : Fill frame with test pattern\n", argv[0].str);
-    printf("%s fill r g b   : Fill frame buffer with RGB888 value and force update\n", argv[0].str);
-
-    return -1;
-  }
-
-  display_info info;
-  if (display_get_info(&info) < 0) {
-    printf("no display to draw on!\n");
-    return -1;
-  }
-
-  gfx_surface* surface = gfx_create_surface_from_display(&info);
-  DEBUG_ASSERT(surface != nullptr);
-
-  if (!strcmp(argv[1].str, "display_info")) {
-    printf("display:\n");
-    printf("\tframebuffer %p\n", info.framebuffer);
-    printf("\twidth %u height %u stride %u\n", info.width, info.height, info.stride);
-    printf("\tformat 0x%x\n", info.format);
-    printf("\tflags 0x%x\n", info.flags);
-  } else if (!strcmp(argv[1].str, "rgb_bars")) {
-    gfx_draw_rgb_bars(surface);
-  } else if (!strcmp(argv[1].str, "test_pattern")) {
-    gfx_draw_pattern();
-  } else if (!strcmp(argv[1].str, "fill")) {
-    uint x, y;
-
-    uint fillval =
-        static_cast<uint>((0xff << 24) | (argv[2].u << 16) | (argv[3].u << 8) | argv[4].u);
-    for (y = 0; y < surface->height; y++) {
-      for (x = 0; x < surface->width; x++) {
-        /* write pixel to frame buffer */
-        gfx_putpixel(surface, x, y, fillval);
-      }
-    }
-  }
-
-  gfx_flush(surface);
-
-  gfx_surface_destroy(surface);
-
-  return 0;
-}
-
-#endif
diff --git a/zircon/kernel/lib/gfx/include/lib/gfx.h b/zircon/kernel/lib/gfx/include/lib/gfx.h
deleted file mode 100644
index 14df8b2..0000000
--- a/zircon/kernel/lib/gfx/include/lib/gfx.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2016 The Fuchsia Authors
-// Copyright (c) 2010 Travis Geiselbrecht
-//
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file or at
-// https://opensource.org/licenses/MIT
-
-#ifndef ZIRCON_KERNEL_LIB_GFX_INCLUDE_LIB_GFX_H_
-#define ZIRCON_KERNEL_LIB_GFX_INCLUDE_LIB_GFX_H_
-
-#include <sys/types.h>
-
-#include <gfx-common/gfx-common.h>
-
-__BEGIN_CDECLS
-
-// surface setup
-gfx_surface* gfx_create_surface(void* ptr, uint width, uint height, uint stride, gfx_format format,
-                                uint32_t flags);
-
-// utility routine to make a surface out of a display info
-struct display_info;
-gfx_surface* gfx_create_surface_from_display(struct display_info*);
-zx_status_t gfx_init_surface_from_display(gfx_surface* surface, struct display_info*);
-
-// utility routine to fill the display with a little moire pattern
-void gfx_draw_pattern(void);
-
-__END_CDECLS
-
-#endif  // ZIRCON_KERNEL_LIB_GFX_INCLUDE_LIB_GFX_H_
diff --git a/zircon/kernel/lib/gfxconsole/BUILD.gn b/zircon/kernel/lib/gfxconsole/BUILD.gn
deleted file mode 100644
index 66f35b5..0000000
--- a/zircon/kernel/lib/gfxconsole/BUILD.gn
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2019 The Fuchsia Authors
-#
-# Use of this source code is governed by a MIT-style
-# license that can be found in the LICENSE file or at
-# https://opensource.org/licenses/MIT
-
-import("//build/zircon/migrated_targets.gni")
-
-zx_library("gfxconsole") {
-  sources = [ "gfxconsole.cc" ]
-  deps = [
-    "//zircon/kernel/lib/boot-options",
-    "//zircon/kernel/lib/gfx",
-    "//zircon/kernel/lib/io",
-    "//zircon/system/ulib/gfx-font",
-  ]
-  public_deps = [
-    # <lib/gfxconsole.h> has #include <lib/gfx.h>.
-    "//zircon/kernel/lib/gfx",
-  ]
-}
diff --git a/zircon/kernel/lib/gfxconsole/gfxconsole.cc b/zircon/kernel/lib/gfxconsole/gfxconsole.cc
deleted file mode 100644
index bbd1d4f..0000000
--- a/zircon/kernel/lib/gfxconsole/gfxconsole.cc
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright 2016 The Fuchsia Authors
-// Copyright (c) 2008-2010, 2015 Travis Geiselbrecht
-//
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file or at
-// https://opensource.org/licenses/MIT
-
-/**
- * @file
- * @brief  Manage graphics console
- *
- * This file contains functions to provide stdout to the graphics console.
- *
- * @ingroup graphics
- */
-
-#include <align.h>
-#include <assert.h>
-#include <debug.h>
-#include <lib/boot-options/boot-options.h>
-#include <lib/boot-options/types.h>
-#include <lib/gfx-font/gfx-font.h>
-#include <lib/gfx.h>
-#include <lib/gfxconsole.h>
-#include <lib/io.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <dev/display.h>
-
-#define TEXT_COLOR 0xffffffff
-#define BACK_COLOR 0xff000000
-
-#define CRASH_TEXT_COLOR 0xffffffff
-#define CRASH_BACK_COLOR 0xffe000e0
-
-/** @addtogroup graphics
- * @{
- */
-
-/**
- * @brief  Represent state of graphics console
- */
-static struct {
-  // main surface to draw on
-  gfx_surface* surface;
-  // underlying hw surface, if different from above
-  gfx_surface* hw_surface;
-
-  // surface to do single line sub-region flushing with
-  gfx_surface line;
-  uint linestride;
-
-  uint rows, columns;
-  uint extray;  // extra pixels left over if the rows doesn't fit precisely
-
-  uint x, y;
-
-  uint32_t front_color;
-  uint32_t back_color;
-} gfxconsole;
-
-static void draw_char(char c, const gfx_font_t* font) {
-  gfx_putchar(gfxconsole.surface, font, c, gfxconsole.x * font->width, gfxconsole.y * font->height,
-              gfxconsole.front_color, gfxconsole.back_color);
-}
-
-void gfxconsole_putpixel(unsigned x, unsigned y, unsigned color) {
-  gfx_putpixel(gfxconsole.surface, x, y, color);
-}
-
-static const gfx_font_t* font = &gfx_font_9x16;
-
-static bool gfxconsole_putc(char c) {
-  static enum { NORMAL, ESCAPE } state = NORMAL;
-  static uint32_t p_num = 0;
-  bool inval = 0;
-
-  if (state == NORMAL) {
-    switch (c) {
-      case '\r':
-        gfxconsole.x = 0;
-        break;
-      case '\n':
-        gfxconsole.y++;
-        inval = 1;
-        break;
-      case '\b':
-        // back up one character unless we're at the left side
-        if (gfxconsole.x > 0) {
-          gfxconsole.x--;
-        }
-        break;
-      case '\t':
-        gfxconsole.x = ROUNDUP(gfxconsole.x + 1, 8);
-        break;
-      case 0x1b:
-        p_num = 0;
-        state = ESCAPE;
-        break;
-      default:
-        draw_char(c, font);
-        gfxconsole.x++;
-        break;
-    }
-  } else if (state == ESCAPE) {
-    if (c >= '0' && c <= '9') {
-      p_num = (p_num * 10) + (c - '0');
-    } else if (c == 'D') {
-      if (p_num <= gfxconsole.x)
-        gfxconsole.x -= p_num;
-      state = NORMAL;
-    } else if (c == '[') {
-      // eat this character
-    } else {
-      draw_char(c, font);
-      gfxconsole.x++;
-      state = NORMAL;
-    }
-  }
-
-  if (gfxconsole.x >= gfxconsole.columns) {
-    gfxconsole.x = 0;
-    gfxconsole.y++;
-    inval = 1;
-  }
-  if (gfxconsole.y >= gfxconsole.rows) {
-    // scroll up
-    gfx_copyrect(gfxconsole.surface, 0, font->height, gfxconsole.surface->width,
-                 gfxconsole.surface->height - font->height - gfxconsole.extray, 0, 0);
-    gfxconsole.y--;
-
-    // clear the bottom line
-    gfx_fillrect(gfxconsole.surface, 0,
-                 gfxconsole.surface->height - font->height - gfxconsole.extray,
-                 gfxconsole.surface->width, font->height, gfxconsole.back_color);
-    gfx_flush(gfxconsole.surface);
-    inval = 1;
-  }
-  return inval;
-}
-
-static void gfxconsole_print_callback(PrintCallback* cb, ktl::string_view str) {
-  int refresh_full_screen = 0;
-  for (char c : str) {
-    if (c == '\n')
-      gfxconsole_putc('\r');
-    refresh_full_screen |= gfxconsole_putc(c);
-  }
-
-  // blit from the software surface to the hardware
-  if (gfxconsole.surface != gfxconsole.hw_surface) {
-    if (refresh_full_screen) {
-      gfx_surface_blend(gfxconsole.hw_surface, gfxconsole.surface, 0, 0);
-    } else {
-      // Only re-blit the active console line.
-      // Since blend only works in whole surfaces, configure a sub-surface
-      // to use as the blend source.
-      gfxconsole.line.ptr =
-          ((uint8_t*)gfxconsole.surface->ptr) + (gfxconsole.y * gfxconsole.linestride);
-      gfx_surface_blend(gfxconsole.hw_surface, &gfxconsole.line, 0, gfxconsole.y * font->height);
-    }
-    gfx_flush(gfxconsole.hw_surface);
-  } else {
-    gfx_flush(gfxconsole.surface);
-  }
-}
-
-static PrintCallback cb{gfxconsole_print_callback};
-
-static void gfxconsole_setup(gfx_surface* surface, gfx_surface* hw_surface) {
-  switch (gBootOptions->gfx_console_font) {
-    case GfxConsoleFont::k9x16:
-      font = &gfx_font_9x16;
-      break;
-    case GfxConsoleFont::k18x32:
-      font = &gfx_font_18x32;
-      break;
-  }
-
-  // set up the surface
-  gfxconsole.surface = surface;
-  gfxconsole.hw_surface = hw_surface;
-
-  // set up line-height sub-surface, for line-only invalidation
-  memcpy(&gfxconsole.line, surface, sizeof(*surface));
-  gfxconsole.line.height = font->height;
-  gfxconsole.linestride = surface->stride * surface->pixelsize * font->height;
-
-  // calculate how many rows/columns we have
-  gfxconsole.rows = surface->height / font->height;
-  gfxconsole.columns = surface->width / font->width;
-  gfxconsole.extray = surface->height - (gfxconsole.rows * font->height);
-
-  dprintf(SPEW, "gfxconsole: rows %u, columns %u, extray %u\n", gfxconsole.rows, gfxconsole.columns,
-          gfxconsole.extray);
-}
-
-static void gfxconsole_clear(bool crash_console) {
-  // start in the upper left
-  gfxconsole.x = 0;
-  gfxconsole.y = 0;
-
-  if (crash_console) {
-    gfxconsole.front_color = CRASH_TEXT_COLOR;
-    gfxconsole.back_color = CRASH_BACK_COLOR;
-  } else {
-    gfxconsole.front_color = TEXT_COLOR;
-    gfxconsole.back_color = BACK_COLOR;
-  }
-
-  // fill screen with back color
-  gfx_fillrect(gfxconsole.surface, 0, 0, gfxconsole.surface->width, gfxconsole.surface->height,
-               gfxconsole.back_color);
-  gfx_flush(gfxconsole.surface);
-}
-
-/**
- * @brief  Initialize graphics console on given drawing surface.
- *
- * The graphics console subsystem is initialized, and registered as
- * an output device for debug output.
- */
-void gfxconsole_start(gfx_surface* surface, gfx_surface* hw_surface) {
-  DEBUG_ASSERT(gfxconsole.surface == NULL);
-
-  gfxconsole_setup(surface, hw_surface);
-  gfxconsole_clear(false);
-
-  // register for debug callbacks
-  register_print_callback(&cb);
-}
-
-static gfx_surface hw_surface;
-static gfx_surface sw_surface;
-static struct display_info dispinfo;
-
-zx_status_t gfxconsole_display_get_info(struct display_info* info) {
-  if (gfxconsole.surface) {
-    memcpy(info, &dispinfo, sizeof(*info));
-    return 0;
-  } else {
-    return -1;
-  }
-}
-
-/**
- * @brief  Initialize graphics console and bind to a display
- *
- * If the display was previously initialized, first it is shut down and
- * detached from the print callback.
- *
- * If the new display_info is NULL, nothing else is done, otherwise the
- * display is initialized against the provided display_info.
- *
- * If raw_sw_fb is non-NULL it is a memory large enough to be a backing
- * surface (stride * height * pixelsize) for the provided hardware display.
- * This is used for very early framebuffer init before the heap is alive.
- */
-void gfxconsole_bind_display(struct display_info* info, void* raw_sw_fb) {
-  static bool active = false;
-  bool same_as_before = false;
-  struct gfx_surface hw;
-
-  if (active) {
-    // on re-init or detach, we need to unhook from print callbacks
-    active = false;
-    unregister_print_callback(&cb);
-  }
-  if (info == NULL) {
-    return;
-  }
-
-  if (gfx_init_surface_from_display(&hw, info)) {
-    return;
-  }
-  if (info->flags & DISPLAY_FLAG_CRASH_FRAMEBUFFER) {
-    // "bluescreen" path. no allocations allowed
-    memcpy(&hw_surface, &hw, sizeof(hw));
-    gfxconsole_setup(&hw_surface, &hw_surface);
-    memcpy(&dispinfo, info, sizeof(*info));
-    gfxconsole_clear(true);
-    register_print_callback(&cb);
-    active = true;
-    return;
-  }
-  if ((hw.format == hw_surface.format) && (hw.width == hw_surface.width) &&
-      (hw.height == hw_surface.height) && (hw.stride == hw_surface.stride) &&
-      (hw.pixelsize == hw_surface.pixelsize)) {
-    // we are binding to a new hw surface with the same properties
-    // as the existing one
-    same_as_before = true;
-  } else {
-    // we cannot re-use the sw backing surface, so destroy it
-    if (sw_surface.ptr && (sw_surface.flags & GFX_FLAG_FREE_ON_DESTROY)) {
-      free(sw_surface.ptr);
-    }
-    memset(&sw_surface, 0, sizeof(sw_surface));
-  }
-  memcpy(&hw_surface, &hw, sizeof(hw));
-
-  gfx_surface* s = &hw_surface;
-  if (info->flags & DISPLAY_FLAG_HW_FRAMEBUFFER) {
-    if (!same_as_before) {
-      // we can't re-use the existing sw_surface, create a new one
-      if (gfx_init_surface(&sw_surface, raw_sw_fb, hw_surface.width, hw_surface.height,
-                           hw_surface.stride, hw_surface.format, 0)) {
-        return;
-      }
-    }
-    s = &sw_surface;
-  } else {
-    // for non-hw surfaces we're not using a backing surface
-    // so we can't be the same as before and must fully init
-    same_as_before = false;
-  }
-
-  gfxconsole_setup(s, &hw_surface);
-
-  if (!same_as_before) {
-    // on first init, or different-backing-buffer re-init
-    // we clear and reset to x,y @ 0,0
-    gfxconsole_clear(false);
-  }
-
-  memcpy(&dispinfo, info, sizeof(*info));
-  register_print_callback(&cb);
-  active = true;
-}
-
-void gfxconsole_flush() {
-  if (gfxconsole.surface != gfxconsole.hw_surface) {
-    gfx_surface_blend(gfxconsole.hw_surface, gfxconsole.surface, 0, 0);
-    gfx_flush(gfxconsole.hw_surface);
-  } else {
-    gfx_flush(gfxconsole.surface);
-  }
-}
diff --git a/zircon/kernel/lib/gfxconsole/include/lib/gfxconsole.h b/zircon/kernel/lib/gfxconsole/include/lib/gfxconsole.h
deleted file mode 100644
index 6e337d9..0000000
--- a/zircon/kernel/lib/gfxconsole/include/lib/gfxconsole.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 The Fuchsia Authors
-// Copyright (c) 2010 Travis Geiselbrecht
-//
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file or at
-// https://opensource.org/licenses/MIT
-
-#ifndef ZIRCON_KERNEL_LIB_GFXCONSOLE_INCLUDE_LIB_GFXCONSOLE_H_
-#define ZIRCON_KERNEL_LIB_GFXCONSOLE_INCLUDE_LIB_GFXCONSOLE_H_
-
-#include <lib/gfx.h>
-#include <zircon/compiler.h>
-#include <zircon/types.h>
-
-__BEGIN_CDECLS
-
-zx_status_t gfxconsole_display_get_info(struct display_info* info);
-void gfxconsole_start(gfx_surface* surface, gfx_surface* hw_surface);
-void gfxconsole_bind_display(struct display_info* info, void* raw_sw_fb);
-void gfxconsole_putpixel(unsigned x, unsigned y, unsigned color);
-void gfxconsole_flush(void);
-
-__END_CDECLS
-
-#endif  // ZIRCON_KERNEL_LIB_GFXCONSOLE_INCLUDE_LIB_GFXCONSOLE_H_
diff --git a/zircon/kernel/lib/instrumentation/ubsan/BUILD.gn b/zircon/kernel/lib/instrumentation/ubsan/BUILD.gn
index a8992f4..0af3044 100644
--- a/zircon/kernel/lib/instrumentation/ubsan/BUILD.gn
+++ b/zircon/kernel/lib/instrumentation/ubsan/BUILD.gn
@@ -4,39 +4,12 @@
 # license that can be found in the LICENSE file or at
 # https://opensource.org/licenses/MIT
 
-import("//build/zircon/zircon_cpu.gni")
-
-_ubsan_tag = [ "ubsan" ]
-_toolchain_tags = toolchain_variant.tags
-is_ubsan = _toolchain_tags + _ubsan_tag - _ubsan_tag != _toolchain_tags
-
 source_set("runtime") {
   if (is_ubsan) {
-    # The support code doesn't get compiled with instrumentation itself.
-    # Disabling it on the command-line not only saves adding NO_UBSAN
-    # annotations to each function, but covers inline functions from shared
-    # header files that shouldn't all be annotated for their other callers.
-    # The former could be addressed via `#pragma clang attribute`, but the
-    # latter cannot be.
-    configs -= [ "//build/config/sanitizers:ubsan" ]
     sources = [ "runtime.cc" ]
     deps = [
-      "..:headers",
+      "//src/lib/ubsan-custom:handlers",
       "//zircon/kernel/lib/crashlog",
     ]
   }
 }
-
-config("ubsan") {
-  cflags = [
-    "-fsanitize=undefined",
-
-    # Checks whether an implicit truncation caused data loss. It's not
-    # undefined behavior but most of the time it is unintentional.
-    "-fsanitize=implicit-integer-truncation",
-
-    # The kernel has some _Nonnull annotations, this would check
-    # them at runtime.
-    "-fsanitize=nullability",
-  ]
-}
diff --git a/zircon/kernel/lib/instrumentation/ubsan/runtime.cc b/zircon/kernel/lib/instrumentation/ubsan/runtime.cc
index 9b7089e..f153225 100644
--- a/zircon/kernel/lib/instrumentation/ubsan/runtime.cc
+++ b/zircon/kernel/lib/instrumentation/ubsan/runtime.cc
@@ -5,186 +5,12 @@
 // https://opensource.org/licenses/MIT
 
 #include <lib/crashlog.h>
-#include <lib/fit/defer.h>
+#include <lib/ubsan-custom/handlers.h>
 #include <platform.h>
-#include <stdint.h>
-#include <zircon/assert.h>
+#include <stdio.h>
 
-// LLVM provides no documentation on the ABI between the compiler and
-// the runtime.  The set of function signatures here was culled from
-// the LLVM sources for the compiler instrumentation and the runtime.
-//
-// See
-// https://github.com/llvm/llvm-project/tree/eb8ebabfb0efcae69e682b592f12366c3b82e78d/compiler-rt/lib/ubsan
-
-namespace {
-
-/// Situations in which we might emit a check for the suitability of a
-/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in
-/// clang.
-enum TypeCheckKind : uint8_t {
-  /// Checking the operand of a load. Must be suitably sized and aligned.
-  TCK_Load,
-  /// Checking the destination of a store. Must be suitably sized and aligned.
-  TCK_Store,
-  /// Checking the bound value in a reference binding. Must be suitably sized
-  /// and aligned, but is not required to refer to an object (until the
-  /// reference is used), per core issue 453.
-  TCK_ReferenceBinding,
-  /// Checking the object expression in a non-static data member access. Must
-  /// be an object within its lifetime.
-  TCK_MemberAccess,
-  /// Checking the 'this' pointer for a call to a non-static member function.
-  /// Must be an object within its lifetime.
-  TCK_MemberCall,
-  /// Checking the 'this' pointer for a constructor call.
-  TCK_ConstructorCall,
-  /// Checking the operand of a static_cast to a derived pointer type. Must be
-  /// null or an object within its lifetime.
-  TCK_DowncastPointer,
-  /// Checking the operand of a static_cast to a derived reference type. Must
-  /// be an object within its lifetime.
-  TCK_DowncastReference,
-  /// Checking the operand of a cast to a base object. Must be suitably sized
-  /// and aligned.
-  TCK_Upcast,
-  /// Checking the operand of a cast to a virtual base object. Must be an
-  /// object within its lifetime.
-  TCK_UpcastToVirtualBase,
-  /// Checking the value assigned to a _Nonnull pointer. Must not be null.
-  TCK_NonnullAssign,
-  /// Checking the operand of a dynamic_cast or a typeid expression.  Must be
-  /// null or an object within its lifetime.
-  TCK_DynamicOperation
-};
-
-struct SourceLocation {
-  const char* filename;
-  uint32_t line;
-  uint32_t column;
-};
-
-struct TypeDescriptor {
-  uint16_t TypeKind;
-  uint16_t TypeInfo;
-  char TypeName[];
-};
-
-struct NonNullArgData {
-  SourceLocation Loc;
-  SourceLocation AttrLoc;
-  int32_t ArgIndex;
-};
-
-struct TypeMismatchData {
-  SourceLocation Loc;
-  const TypeDescriptor& Type;
-  uint8_t LogAlignment;
-  TypeCheckKind TypeCheckKind;
-};
-
-struct FunctionTypeMismatchData {
-  SourceLocation Loc;
-  const TypeDescriptor& Type;
-};
-
-struct UnreachableData {
-  SourceLocation Loc;
-};
-
-struct AlignmentAssumptionData {
-  SourceLocation Loc;
-  SourceLocation AssumptionLoc;
-  const TypeDescriptor& Type;
-};
-
-using ValueHandle = uintptr_t;
-
-const char* TypeCheckKindMsg(TypeCheckKind kind) {
-  switch (kind) {
-    case TCK_Load:
-      return "load of";
-    case TCK_Store:
-      return "store to";
-    case TCK_ReferenceBinding:
-      return "reference binding to";
-    case TCK_MemberAccess:
-      return "member access within";
-    case TCK_MemberCall:
-      return "member call on";
-    case TCK_ConstructorCall:
-      return "constructor call on";
-    case TCK_DowncastPointer:
-      return "downcast of";
-    case TCK_DowncastReference:
-      return "downcast of";
-    case TCK_Upcast:
-      return "upcast of";
-    case TCK_UpcastToVirtualBase:
-      return "cast to virtual base of";
-    case TCK_NonnullAssign:
-      return "_Nonnull binding to";
-    case TCK_DynamicOperation:
-      return "dynamic operation on";
-    default:
-      panic("invalid type check kind %d", kind);
-  }
-}
-
-struct OverflowData {
-  SourceLocation Loc;
-  const TypeDescriptor& Type;
-};
-
-struct ReportOptions {
-  // If FromUnrecoverableHandler is specified, UBSan runtime handler is not
-  // expected to return.
-  bool FromUnrecoverableHandler;
-  /// pc/bp are used to unwind the stack trace.
-  uintptr_t pc;
-  uintptr_t bp;
-};
-
-struct InvalidValueData {
-  SourceLocation Loc;
-  const TypeDescriptor& Type;
-};
-
-// Known implicit conversion check kinds.
-enum ImplicitConversionCheckKind : uint8_t {
-  ICCK_IntegerTruncation = 0,  // Legacy, was only used by clang 7.
-  ICCK_UnsignedIntegerTruncation = 1,
-  ICCK_SignedIntegerTruncation = 2,
-  ICCK_IntegerSignChange = 3,
-  ICCK_SignedIntegerTruncationOrSignChange = 4,
-};
-
-struct ImplicitConversionData {
-  SourceLocation Loc;
-  const TypeDescriptor& FromType;
-  const TypeDescriptor& ToType;
-  ImplicitConversionCheckKind Kind;
-};
-
-struct OutOfBoundsData {
-  SourceLocation Loc;
-  const TypeDescriptor& ArrayType;
-  const TypeDescriptor& IndexType;
-};
-
-struct ShiftOutOfBoundsData {
-  SourceLocation Loc;
-  const TypeDescriptor& LHSType;
-  const TypeDescriptor& RHSType;
-};
-
-struct PointerOverflowData {
-  SourceLocation Loc;
-};
-
-auto UbsanPanicStart(const char* check, SourceLocation& loc,
-                     void* caller = __builtin_return_address(0),
-                     void* frame = __builtin_frame_address(0)) {
+ubsan::Report::Report(const char* check, const ubsan::SourceLocation& loc,  //
+                      void* caller, void* frame) {
   platform_panic_start();
   fprintf(&stdout_panic_buffer,
           "\n"
@@ -194,143 +20,11 @@
 
   fprintf(&stdout_panic_buffer, "UBSAN CHECK FAILED at (%s:%d): %s\n", loc.filename, loc.line,
           check);
-
-  return fit::defer([]() {
-    fprintf(&stdout_panic_buffer, "\n");
-    platform_halt(HALT_ACTION_HALT, ZirconCrashReason::Panic);
-  });
 }
 
-void PrintTypeDescriptor(const TypeDescriptor& type, const char* prefix = NULL) {
-  // TODO(https://fxbug.dev/42056251): Improve logging by interpreting TypeDescriptor values.
-  if (prefix) {
-    printf("%s:", prefix);
-  }
-  printf("Type Kind (0x%04hx)\tInfo (0x%04hx)\tName %s\n", type.TypeKind, type.TypeInfo,
-         type.TypeName);
+ubsan::Report::~Report() {
+  fprintf(&stdout_panic_buffer, "\n");
+  platform_halt(HALT_ACTION_HALT, ZirconCrashReason::Panic);
 }
 
-}  // namespace
-
-extern "C" {
-
-void __ubsan_handle_nonnull_arg(NonNullArgData* Data) {
-  auto start = UbsanPanicStart("NULL ARG passed to NonNullarg parameter.", Data->Loc);
-}
-
-void __ubsan_handle_type_mismatch_v1(TypeMismatchData* Data, ValueHandle Pointer) {
-  auto start = UbsanPanicStart("Type Mismatch", Data->Loc);
-
-  const uintptr_t Alignment = (uintptr_t)1 << Data->LogAlignment;
-  const uintptr_t AlignmentMask = Alignment - 1;
-
-  printf("Pointer: 0x%016lx\n", Pointer);
-  printf("Alignment: 0x%lx bytes\n", Alignment);
-
-  if (Pointer & AlignmentMask) {
-    printf("%s misaligned address 0x%016lx\n", TypeCheckKindMsg(Data->TypeCheckKind), Pointer);
-  } else {
-    printf("TypeCheck Kind: %s (0x%hhx)\n", TypeCheckKindMsg(Data->TypeCheckKind),
-           Data->TypeCheckKind);
-  }
-
-  PrintTypeDescriptor(Data->Type);
-}
-
-void __ubsan_handle_function_type_mismatch(FunctionTypeMismatchData* Data, ValueHandle Val) {
-  auto start = UbsanPanicStart("Function Type Mismatch", Data->Loc);
-
-  PrintTypeDescriptor(Data->Type);
-}
-
-#define UBSAN_OVERFLOW_HANDLER(handler_name, op)                            \
-  void handler_name(OverflowData* Data, ValueHandle LHS, ValueHandle RHS) { \
-    auto start = UbsanPanicStart("Integer " op " overflow\n", Data->Loc);   \
-    printf("LHS: 0x%016lx\n", LHS);                                         \
-    printf("RHS: 0x%016lx\n", RHS);                                         \
-    PrintTypeDescriptor(Data->Type);                                        \
-  }
-
-UBSAN_OVERFLOW_HANDLER(__ubsan_handle_add_overflow, "ADD")
-UBSAN_OVERFLOW_HANDLER(__ubsan_handle_mul_overflow, "MUL")
-UBSAN_OVERFLOW_HANDLER(__ubsan_handle_sub_overflow, "SUB")
-
-void __ubsan_handle_divrem_overflow(OverflowData* Data, ValueHandle LHS, ValueHandle RHS,
-                                    ReportOptions Opts) {
-  auto start = UbsanPanicStart("Integer DIVREM overflow", Data->Loc);
-  printf("LHS: 0x%016lx\n", LHS);
-  printf("RHS: 0x%016lx\n", RHS);
-  PrintTypeDescriptor(Data->Type);
-}
-
-void __ubsan_handle_negate_overflow(OverflowData* Data, ValueHandle OldVal) {
-  auto start = UbsanPanicStart("Integer NEGATE overflow", Data->Loc);
-  printf("old value: 0x%016lx\n", OldVal);
-  PrintTypeDescriptor(Data->Type);
-}
-
-void __ubsan_handle_load_invalid_value(InvalidValueData* Data, ValueHandle Val) {
-  auto start = UbsanPanicStart("Load invalid value into enum/bool", Data->Loc);
-  printf("Val: 0x%016lx\n", Val);
-  PrintTypeDescriptor(Data->Type);
-}
-
-void __ubsan_handle_implicit_conversion(ImplicitConversionData* Data, ValueHandle Src,
-                                        ValueHandle Dst) {
-  auto start = UbsanPanicStart("Implicit Conversion", Data->Loc);
-  printf("Src: 0x%016lx\n", Src);
-  printf("Dst: 0x%016lx\n", Dst);
-  PrintTypeDescriptor(Data->FromType, "From");
-  PrintTypeDescriptor(Data->ToType, "To");
-}
-
-void __ubsan_handle_out_of_bounds(OutOfBoundsData* Data, ValueHandle Index) {
-  auto start = UbsanPanicStart("Out of bounds access", Data->Loc);
-  printf("Index: 0x%016lx\n", Index);
-  PrintTypeDescriptor(Data->ArrayType, "Array");
-  PrintTypeDescriptor(Data->IndexType, "Index");
-}
-
-void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData* Data, ValueHandle LHS,
-                                        ValueHandle RHS) {
-  auto start = UbsanPanicStart("SHIFT overflow", Data->Loc);
-  printf("LHS: 0x%016lx\n", LHS);
-  printf("RHS: 0x%016lx\n", RHS);
-  PrintTypeDescriptor(Data->LHSType, "LHS");
-  PrintTypeDescriptor(Data->RHSType, "RHS");
-}
-
-void __ubsan_handle_pointer_overflow(PointerOverflowData* Data, ValueHandle Base,
-                                     ValueHandle Result) {
-  auto start = UbsanPanicStart("POINTER overflow", Data->Loc);
-  printf("Base: 0x%016lx\n", Base);
-  printf("Result: 0x%016lx\n", Result);
-}
-
-void __ubsan_handle_builtin_unreachable(UnreachableData* Data) {
-  auto start = UbsanPanicStart("Executed unreachable code", Data->Loc);
-}
-
-void __ubsan_handle_alignment_assumption(AlignmentAssumptionData* Data, ValueHandle Pointer,
-                                         ValueHandle Alignment, ValueHandle Offset) {
-  auto start = UbsanPanicStart("Alignment Assumption violation", Data->Loc);
-  PrintTypeDescriptor(Data->Type);
-  printf("Pointer: 0x%016lx\n", Pointer);
-  printf("Alignment: 0x%016lx\n", Alignment);
-  printf("Offset: 0x%016lx\n", Offset);
-}
-
-// TODO(https://fxbug.dev/42056251): Add missing handlers:
-// * invalid_builtin
-// * nonnull_return_v1
-// * nullability_return_v1
-// * nullability_arg
-// * cfi_check_fail
-// * cfi_bad_type
-
-// NOTE: The following functions should never be generated in the kernel ubsan:
-//  * missing_return
-//  * vla_bound_not_positive
-//  * float_cast_overflow
-
-}  // extern "C"
+void ubsan::VPrintf(const char* fmt, va_list args) { vprintf(fmt, args); }
diff --git a/zircon/kernel/lib/io/console.cc b/zircon/kernel/lib/io/console.cc
index 3679886..5b80a84 100644
--- a/zircon/kernel/lib/io/console.cc
+++ b/zircon/kernel/lib/io/console.cc
@@ -28,8 +28,6 @@
 enum class SkipPersistedDebuglog { No = 0, Yes };
 
 DECLARE_SINGLETON_SPINLOCK_WITH_TYPE(dputc_spin_lock, MonitoredSpinLock);
-DECLARE_SINGLETON_SPINLOCK_WITH_TYPE(print_spin_lock, MonitoredSpinLock);
-static fbl::DoublyLinkedList<PrintCallback*> print_callbacks TA_GUARDED(print_spin_lock::Get());
 
 }  // namespace
 
@@ -40,15 +38,6 @@
   platform_dputs_irq(str.data(), str.size());
 }
 
-void console_write(ktl::string_view str) {
-  // Print to any registered console loggers.
-  Guard<MonitoredSpinLock, IrqSave> guard{print_spin_lock::Get(), SOURCE_TAG};
-
-  for (PrintCallback& print_callback : print_callbacks) {
-    print_callback.Print(str);
-  }
-}
-
 static void stdout_write(ktl::string_view str, SkipPersistedDebuglog skip_pdlog) {
   if (skip_pdlog == SkipPersistedDebuglog::No) {
     persistent_dlog_write(str);
@@ -58,7 +47,6 @@
     if (dlog_write(DEBUGLOG_INFO, 0, str) == ZX_OK)
       return;
   }
-  console_write(str);
   serial_write(str);
 }
 
@@ -117,18 +105,6 @@
   }
 }
 
-void register_print_callback(PrintCallback* cb) {
-  Guard<MonitoredSpinLock, IrqSave> guard{print_spin_lock::Get(), SOURCE_TAG};
-
-  print_callbacks.push_front(cb);
-}
-
-void unregister_print_callback(PrintCallback* cb) {
-  Guard<MonitoredSpinLock, IrqSave> guard{print_spin_lock::Get(), SOURCE_TAG};
-
-  print_callbacks.erase(*cb);
-}
-
 // This is what printf calls.  Really this could and should be const.
 // But all the stdio function signatures require non-const `FILE*`.
 FILE FILE::stdout_{[](void*, ktl::string_view str) {
@@ -137,12 +113,6 @@
                    },
                    nullptr};
 
-FILE gConsoleFile{[](void*, ktl::string_view str) {
-                    console_write(str);
-                    return static_cast<int>(str.size());
-                  },
-                  nullptr};
-
 FILE gSerialFile{[](void*, ktl::string_view str) {
                    serial_write(str);
                    return static_cast<int>(str.size());
diff --git a/zircon/kernel/lib/io/include/lib/io.h b/zircon/kernel/lib/io/include/lib/io.h
index f6fe75c..f2906cf 100644
--- a/zircon/kernel/lib/io/include/lib/io.h
+++ b/zircon/kernel/lib/io/include/lib/io.h
@@ -16,36 +16,10 @@
 #include <ktl/array.h>
 #include <ktl/string_view.h>
 
-class PrintCallback : public fbl::DoublyLinkedListable<PrintCallback*> {
- public:
-  PrintCallback(const PrintCallback&) = delete;
-  PrintCallback(PrintCallback&&) = delete;
-  PrintCallback& operator=(const PrintCallback&) = delete;
-  PrintCallback& operator=(PrintCallback&&) = delete;
-
-  using Callback = void(PrintCallback* cb, ktl::string_view str);
-
-  constexpr explicit PrintCallback(Callback* callback) : callback_(callback) {}
-
-  void Print(ktl::string_view str) {
-    if (callback_)
-      callback_(this, str);
-  }
-
- private:
-  Callback* callback_;
-};
-
-// Register a callback to receive debug prints.
-void register_print_callback(PrintCallback* cb);
-void unregister_print_callback(PrintCallback* cb);
-
-// Back doors to directly write to the kernel serial and console, respectively.
+// Back door to directly write to the kernel serial port.
 void serial_write(ktl::string_view str);
-void console_write(ktl::string_view str);
 
 extern FILE gSerialFile;
-extern FILE gConsoleFile;
 extern FILE gStdoutUnbuffered;
 extern FILE gStdoutNoPersist;
 
diff --git a/zircon/kernel/lib/ktrace/BUILD.gn b/zircon/kernel/lib/ktrace/BUILD.gn
index ab8ce2f..2bcaa32 100644
--- a/zircon/kernel/lib/ktrace/BUILD.gn
+++ b/zircon/kernel/lib/ktrace/BUILD.gn
@@ -41,6 +41,7 @@
     "//sdk/lib/zbi-format/*",
     "//src/lib/elfldltl/*",
     "//src/lib/llvm-profdata/*",
+    "//src/lib/ubsan-custom/*",
     "//src/lib/zbitl/*",
     "//src/performance/lib/fxt/*",
     "//third_party/zstd/*",
diff --git a/zircon/kernel/lib/page_cache/include/lib/page_cache.h b/zircon/kernel/lib/page_cache/include/lib/page_cache.h
index 4b2221f..3c5e050 100644
--- a/zircon/kernel/lib/page_cache/include/lib/page_cache.h
+++ b/zircon/kernel/lib/page_cache/include/lib/page_cache.h
@@ -113,8 +113,7 @@
     DEBUG_ASSERT(per_cpu_caches_ != nullptr);
 
     // Fall back to the PMM for low mem/loaned pages.
-    if (alloc_flags &
-        (PMM_ALLOC_FLAG_LO_MEM | PMM_ALLOC_FLAG_MUST_BORROW | PMM_ALLOC_FLAG_CAN_BORROW)) {
+    if (alloc_flags & (PMM_ALLOC_FLAG_LO_MEM | PMM_ALLOC_FLAG_LOANED)) {
       list_node page_list = LIST_INITIAL_VALUE(page_list);
       const zx_status_t status = pmm_alloc_pages(page_count, alloc_flags, &page_list);
       if (status != ZX_OK) {
diff --git a/zircon/kernel/lib/sched/README.md b/zircon/kernel/lib/sched/README.md
index 36677be..4c74bd0 100644
--- a/zircon/kernel/lib/sched/README.md
+++ b/zircon/kernel/lib/sched/README.md
@@ -4,3 +4,62 @@
 Despite its primary intended application within the kernel, this library aims to
 remain environment-agnostic, especially for exercise within non-kernel, testing
 contexts.
+
+# Bandwidth model
+
+_Bandwidth_ refers to the amount of execution time available to a thread over
+time, and the _bandwidth model_ refers to the manner in which that time is
+modeled and allocated to threads.
+
+A thread's work is framed as happening within fixed-width, recurring time
+intervals called _activation periods_. The duration is a property of the thread
+and is referred to as its _period_. When the current activation period
+_expires_, it is _reactivated_ and the time allocated to the thread within it is
+reset. This chunking of work into periods arises naturally in many practical
+contexts like the duration between VSyncs in graphical contexts and the
+frequency of polling by device drivers. Accordingly, a period is better regarded
+as a looser, slack-encoding, often externally-prescribed duration in which a
+thread is expected to perform its work rather than a precise measure of the
+duration of that intended work, which is instead referred to as the thread's
+_capacity_.
+
+A thread's work has two components: _firm_ and _flexible_. Firm work is that
+which is _required_ to occur within a period; it is specified directly as the
+thread property of _firm capacity_. Flexible work is that which happens on a
+best-effort basis, utilizing remaining bandwidth - if any - after firm work has
+been accounted for; it is specified indirectly as the thread property of
+_flexible weight_. Flexible weight gives a conventional measure of the
+importance of the desired flexible work, with a thread's _flexible capacity_
+being derived from the proportion of its weight to the sum of all such weights
+across the set of threads (naturally scaled by a firm utilization factor). The
+_(total/effective) capacity_ of a thread is the sum of its firm and flexible
+capacities, giving the total duration of execution time a thread expects within
+an activation period.
+
+All _runnable_ threads (i.e., the currently running thread or those queued and
+ready to be run) contribute both firm and flexible demand.
+
+## Thread selection
+
+At all times, the thread that is selected next is the active one with the
+earliest finish time (if any). In the event of a tie of finish times, the one
+with the earlier start time is picked - and then in the event of a tie of start
+times, the thread with the lowest address is expediently picked (which is a
+small bias that should not persist across runs of the system).
+
+This process is facilitated by `sched::RunQueue`.
+
+## Preemption time
+
+When a thread is selected, the _preemption time_ - the time at which the next
+selection process should take place, potentially preempting the currently
+executing thread - is calculated as well. This should be triggered as soon as
+there is a state transition affecting the bandwidth of the just-selected thread
+or the one that would become eligible next, and is calculated as the earlier of
+the following times:
+
+* When the currently selected thread finishes its activation period;
+* When the currently selected thread would reach its capacity if allowed to
+  continue uninterrupted;
+* The starting time of a thread - if any - that would be eligible at the earlier
+  of the above times and finish before the currently selected.
diff --git a/zircon/kernel/lib/sched/include/lib/sched/run-queue.h b/zircon/kernel/lib/sched/include/lib/sched/run-queue.h
index 2d47e3c..300f551 100644
--- a/zircon/kernel/lib/sched/include/lib/sched/run-queue.h
+++ b/zircon/kernel/lib/sched/include/lib/sched/run-queue.h
@@ -58,12 +58,18 @@
   const Thread* current_thread() const { return current_; }
 
   // The total duration within the thread's activation period in which the
-  // thread is expected to complete its work. This can be regarded as a measure
-  // of the expected worst-case runtime.
+  // thread is expected to complete its firm and flexible work . This can be
+  // regarded as a measure of the expected worst-case runtime given current
+  // bandwidth subscription.
   Duration CapacityOf(const Thread& thread) const {
-    // TODO(https://fxbug.dev/328641440): Account for flexible capacity when
-    // introduced.
-    return thread.firm_capacity();
+    return thread.firm_capacity() + FlexibleCapacityOf(thread);
+  }
+
+  // Given current bandwidth subscription, the duration of time we expect to be
+  // allotted to a thread's flexible work within its period.
+  Duration FlexibleCapacityOf(const Thread& thread) const {
+    return (Utilization{1} - total_firm_utilization()) * FlexibleUtilizationOf(thread) *
+           thread.period();
   }
 
   // The remaining time expected for the thread to be scheduled within its
@@ -82,17 +88,27 @@
   // the thread is or will be active).
   void Queue(Thread& thread, Time now) {
     ZX_DEBUG_ASSERT(!thread.IsQueued());
+
+    // Contribute ready demand ahead of the IsExpired() check, as that is
+    // dependent on this quantity.
+    ready_firm_utilization_ += thread.firm_utilization();
+    ready_flexible_demand_ += thread.flexible_weight();
+
     if (IsExpired(thread, now)) {
       thread.Reactivate(now);
     }
     ready_.insert(&thread);
+    thread.set_state(ThreadState::kReady);
   }
 
   // Dequeues the thread from the run queue (provided the thread was already
   // contained).
   void Dequeue(Thread& thread) {
     ZX_DEBUG_ASSERT(thread.IsQueued());
+    ZX_DEBUG_ASSERT(thread.state() == ThreadState::kReady);
     ready_.erase(thread);
+    ready_firm_utilization_ -= thread.firm_utilization();
+    ready_flexible_demand_ -= thread.flexible_weight();
   }
 
   struct SelectNextThreadResult {
@@ -103,14 +119,8 @@
   // Selects the next thread to run and also gives the time at which the
   // preemption timer should fire for the subsequent round of scheduling.
   //
-  // The next thread is the one that is active and has the earliest finish time
-  // within its current period. In the event of a tie of finish times, the one
-  // with the earlier start time is picked - and then in the event of a tie of
-  // start times, the thread with the lowest address is expediently picked
-  // (which is a small bias that should not persist across runs of the system).
-  //
-  // If no threads are eligible, nullptr is returned, along with the time at
-  // which the next thread should become eligible.
+  // See //zircon/kernel/lib/sched/README.md#thread-selection for more detail on
+  // the behavior of this method.
   SelectNextThreadResult SelectNextThread(Time now) {
     // The next eligible might actually be expired (e.g., due to bandwidth
     // oversubscription), in which case it should be reactivated and
@@ -137,6 +147,7 @@
     } else {
       if (next) {
         Dequeue(*next);
+        next->set_state(ThreadState::kRunning);
       }
       if (current_) {
         Queue(*current_, now);
@@ -224,6 +235,22 @@
     return it->run_queue_.subtree_min_finish;
   }
 
+  FlexibleWeight total_flexible_demand() const {
+    return (current_ ? current_->flexible_weight() : FlexibleWeight{0}) + ready_flexible_demand_;
+  }
+
+  Utilization total_firm_utilization() const {
+    Utilization utilization =
+        (current_ ? current_->firm_utilization() : Utilization{0}) + ready_firm_utilization_;
+    // Clamp to account for oversubscription.
+    return std::min(Utilization{1}, utilization);
+  }
+
+  Utilization FlexibleUtilizationOf(const Thread& thread) const {
+    FlexibleWeight demand = total_flexible_demand();
+    return demand == 0 ? Utilization{0} : thread.flexible_weight() / demand;
+  }
+
   // Returns the thread eligible to scheduled at a given time with the minimal
   // finish time.
   mutable_iterator FindNextEligibleThread(Time time) {
@@ -287,6 +314,12 @@
 
   // The tree of threads ready to be run.
   Tree ready_;
+
+  // The aggregate flexible weight across all ready threads.
+  FlexibleWeight ready_flexible_demand_{0};
+
+  // The aggregate firm utilization across all ready threads.
+  Utilization ready_firm_utilization_{0};
 };
 
 }  // namespace sched
diff --git a/zircon/kernel/lib/sched/include/lib/sched/thread-base.h b/zircon/kernel/lib/sched/include/lib/sched/thread-base.h
index cc7821f..1054b00 100644
--- a/zircon/kernel/lib/sched/include/lib/sched/thread-base.h
+++ b/zircon/kernel/lib/sched/include/lib/sched/thread-base.h
@@ -22,6 +22,25 @@
 using Duration = ffl::Fixed<zx_duration_t, 0>;
 using Time = ffl::Fixed<zx_time_t, 0>;
 
+// Flexible work weight.
+//
+// Gives a measure of priority for the flexible portion of a thread's work
+// (i.e., that done on a best-effort basis all other required/firm work is
+// accomplished).
+//
+// Weights should not be negative; however, the value is signed for consistency
+// with Time and Duration, which are the primary types used in conjunction with
+// FlexibleWeight. This is to make it less likely that expressions involving
+// weights are accidentally promoted to unsigned.
+using FlexibleWeight = ffl::Fixed<int64_t, 16>;
+
+// The utilization factor of a thread's desired work, defined as the ratio
+// between a thread's capacity (firm, flexible, or total) and its period.
+//
+// The 20bit fractional component represents the utilization with a precision
+// of ~1us.
+using Utilization = ffl::Fixed<int64_t, 20>;
+
 // The parameters that specify a thread's activation period (i.e., the
 // recurring cycle in which it is scheduled).
 struct BandwidthParameters {
@@ -31,6 +50,23 @@
   // The duration within a given activation period in which a thread is expected
   // to complete its *required* work.
   Duration firm_capacity;
+
+  // The weight of the flexible portion of a thread's work. Zero is equivalent
+  // to the thread not having flexible work to do, its total capacity being
+  // equal to its firm capacity.
+  FlexibleWeight flexible_weight;
+};
+
+// The scheduling state of a thread.
+enum class ThreadState : uint8_t {
+  // The thread is in its initialed state and not yet schedulable.
+  kInitial,
+
+  // The thread is schedulable and not yet running.
+  kReady,
+
+  // The thread is currently running (or selected to be run).
+  kRunning,
 };
 
 // The base thread class from which we expect schedulable thread types to
@@ -40,9 +76,14 @@
 class ThreadBase {
  public:
   constexpr ThreadBase(BandwidthParameters bandwidth, Time start)
-      : period_(bandwidth.period), firm_capacity_(bandwidth.firm_capacity) {
-    ZX_ASSERT(bandwidth.period >= bandwidth.firm_capacity);
-    ZX_ASSERT(bandwidth.firm_capacity > 0);
+      : period_(bandwidth.period),                //
+        firm_capacity_(bandwidth.firm_capacity),  //
+        flexible_weight_(bandwidth.flexible_weight) {
+    ZX_DEBUG_ASSERT(bandwidth.period >= bandwidth.firm_capacity);
+    ZX_DEBUG_ASSERT(bandwidth.period > 0);
+    ZX_DEBUG_ASSERT(bandwidth.firm_capacity >= 0);
+    ZX_DEBUG_ASSERT(bandwidth.flexible_weight >= 0);
+    ZX_DEBUG_ASSERT(bandwidth.firm_capacity != 0 || bandwidth.flexible_weight != 0);
     Reactivate(start);
   }
 
@@ -50,6 +91,12 @@
 
   constexpr Duration firm_capacity() const { return firm_capacity_; }
 
+  constexpr FlexibleWeight flexible_weight() const { return flexible_weight_; }
+
+  // The total proportion of the period in which the thread is expected to run
+  // in order to complete its required work.
+  constexpr Utilization firm_utilization() const { return firm_capacity() / period(); }
+
   // The start of the thread's current activation period.
   constexpr Time start() const { return start_; }
 
@@ -60,6 +107,12 @@
   // period.
   constexpr Duration time_slice_used() const { return time_slice_used_; }
 
+  // Returns the scheduling state of the thread.
+  constexpr ThreadState state() const { return state_; }
+
+  // Sets the scheduling state of the thread.
+  void set_state(ThreadState state) { state_ = state; }
+
   // Whether the thread is active at the provided time (i.e., whether that time
   // falls within the current activation period).
   constexpr bool IsActive(Time now) const { return start() <= now && now < finish(); }
@@ -88,9 +141,12 @@
 
   Duration period_{0};
   Duration firm_capacity_{0};
+  FlexibleWeight flexible_weight_{0};
   Time start_{Time::Min()};
   Duration time_slice_used_{0};
 
+  ThreadState state_ = ThreadState::kInitial;
+
   // Encapsulates the state specific to the run queue.
   struct RunQueueState {
     fbl::WAVLTreeNodeState<Thread*> node;
diff --git a/zircon/kernel/lib/sched/run-queue-fuzzer.cc b/zircon/kernel/lib/sched/run-queue-fuzzer.cc
index 6bf38e7..d0ec4c5 100644
--- a/zircon/kernel/lib/sched/run-queue-fuzzer.cc
+++ b/zircon/kernel/lib/sched/run-queue-fuzzer.cc
@@ -21,26 +21,36 @@
 namespace {
 
 using Duration = sched::Duration;
+using FlexibleWeight = sched::FlexibleWeight;
 using Time = sched::Time;
 
 Time ConsumeTime(FuzzedDataProvider& provider) {
   return Time{provider.ConsumeIntegral<zx_time_t>()};
 }
 
-Duration ConsumeDuration(FuzzedDataProvider& provider, Duration max = Duration::Max()) {
-  ZX_ASSERT(max > 0);
-  return Duration{provider.ConsumeIntegralInRange<zx_duration_t>(1, max.raw_value())};
+FlexibleWeight ConsumeFlexibleWeight(FuzzedDataProvider& provider, FlexibleWeight min) {
+  return FlexibleWeight{
+      provider.ConsumeIntegralInRange<int64_t>(min.raw_value(), FlexibleWeight::Max().raw_value())};
+}
+
+Duration ConsumeDuration(FuzzedDataProvider& provider, Duration min, Duration max) {
+  ZX_ASSERT(min >= 0);
+  ZX_ASSERT(max >= min);
+  return Duration{provider.ConsumeIntegralInRange<zx_duration_t>(min.raw_value(), max.raw_value())};
 }
 
 TestThread* AllocateNewThread(FuzzedDataProvider& provider,
                               std::vector<std::unique_ptr<TestThread>>& threads) {
   Time start = ConsumeTime(provider);
-  Duration period = ConsumeDuration(provider, (Time::Max() - start) + Time{1});
-  Duration firm_capacity = ConsumeDuration(provider, period);
+  Duration period = ConsumeDuration(provider, Duration{1}, (Time::Max() - start) + Time{1});
+  Duration firm_capacity = ConsumeDuration(provider, Duration{0}, period);
+  FlexibleWeight flexible_weight =
+      ConsumeFlexibleWeight(provider, FlexibleWeight{firm_capacity == 0 ? 1 : 0});
   threads.emplace_back(std::make_unique<TestThread>(
       sched::BandwidthParameters{
           .period = period,
           .firm_capacity = firm_capacity,
+          .flexible_weight = flexible_weight,
       },
       start));
   return threads.back().get();
diff --git a/zircon/kernel/lib/sched/run-queue-tests.cc b/zircon/kernel/lib/sched/run-queue-tests.cc
index ad6fc05..d0c39bd 100644
--- a/zircon/kernel/lib/sched/run-queue-tests.cc
+++ b/zircon/kernel/lib/sched/run-queue-tests.cc
@@ -5,6 +5,7 @@
 // https://opensource.org/licenses/MIT
 
 #include <lib/sched/run-queue.h>
+#include <lib/sched/thread-base.h>
 
 #include <array>
 #include <cstddef>
@@ -16,6 +17,7 @@
 namespace {
 
 using Duration = sched::Duration;
+using FlexibleWeight = sched::FlexibleWeight;
 using Time = sched::Time;
 
 TEST(RunQueueTests, Empty) {
@@ -154,7 +156,7 @@
   EXPECT_EQ(queue.end(), it);
 }
 
-TEST(RunQueueTests, SelectNextThread) {
+TEST(RunQueueTests, SelectNextFirmThread) {
   // Empty: no next thread.
   {
     constexpr Time kNow{Start(0)};
@@ -449,4 +451,160 @@
   }
 }
 
+TEST(RunQueueTests, FlexibleWork) {
+  std::array threads = {
+      TestThread{{Period(4), Capacity(0), FlexibleWeight{1}}, Start(0)},
+      TestThread{{Period(4), Capacity(0), FlexibleWeight{2}}, Start(0)},
+      TestThread{{Period(4), Capacity(0), FlexibleWeight{1}}, Start(0)},
+  };
+  TestThread& threadA = threads[0];
+  TestThread& threadB = threads[1];
+  TestThread& threadC = threads[2];
+
+  sched::RunQueue<TestThread> queue;
+  queue.Queue(threadA, Start(0));
+  queue.Queue(threadB, Start(0));
+  queue.Queue(threadC, Start(0));
+
+  EXPECT_EQ(Capacity(1), queue.FlexibleCapacityOf(threadA));
+  EXPECT_EQ(Capacity(1), queue.CapacityOf(threadA));
+
+  EXPECT_EQ(Capacity(2), queue.FlexibleCapacityOf(threadB));
+  EXPECT_EQ(Capacity(2), queue.CapacityOf(threadB));
+
+  EXPECT_EQ(Capacity(1), queue.FlexibleCapacityOf(threadC));
+  EXPECT_EQ(Capacity(1), queue.CapacityOf(threadC));
+
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(0));
+    EXPECT_EQ(&threadA, next);
+    EXPECT_EQ(Time{1}, preemption);
+  }
+  threadA.Tick(Duration{1});
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(1));
+    EXPECT_EQ(&threadB, next);
+    EXPECT_EQ(Time{3}, preemption);
+  }
+  threadB.Tick(Duration{2});
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(3));
+    EXPECT_EQ(&threadC, next);
+    EXPECT_EQ(Time{4}, preemption);
+  }
+}
+
+TEST(RunQueueTests, HybridWorkWithoutBandwidthForFlexible) {
+  TestThread threadA = {{Period(5), Capacity(1), FlexibleWeight{1}}, Start(0)};
+  TestThread threadB = {{Period(10), Capacity(8), FlexibleWeight{0}}, Start(0)};
+
+  sched::RunQueue<TestThread> queue;
+  queue.Queue(threadA, Start(0));
+  queue.Queue(threadB, Start(0));
+
+  // Firm work soaks up available bandwidth: no capacity for flexible work
+  EXPECT_EQ(Capacity(0), queue.FlexibleCapacityOf(threadA));
+  EXPECT_EQ(Capacity(1), queue.CapacityOf(threadA));
+
+  EXPECT_EQ(Capacity(0), queue.FlexibleCapacityOf(threadB));
+  EXPECT_EQ(Capacity(8), queue.CapacityOf(threadB));
+
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(0));
+    EXPECT_EQ(&threadA, next);
+    EXPECT_EQ(Time{1}, preemption);
+  }
+  threadA.Tick(Duration{1});
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(1));
+    EXPECT_EQ(&threadB, next);
+    EXPECT_EQ(Time{9}, preemption);
+  }
+  threadB.Tick(Duration{8});
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(9));
+    EXPECT_EQ(&threadA, next);
+    EXPECT_EQ(Time{10}, preemption);
+  }
+  threadA.Tick(Duration{1});
+}
+
+TEST(RunQueueTests, HybridWorkWithBandwidthForFlexible) {
+  TestThread threadA = {{Period(5), Capacity(1), FlexibleWeight{1}}, Start(0)};
+  TestThread threadB = {{Period(10), Capacity(6), FlexibleWeight{0}}, Start(0)};
+
+  sched::RunQueue<TestThread> queue;
+  queue.Queue(threadA, Start(0));
+  queue.Queue(threadB, Start(0));
+
+  EXPECT_EQ(Capacity(1), queue.FlexibleCapacityOf(threadA));
+  EXPECT_EQ(Capacity(2), queue.CapacityOf(threadA));
+
+  EXPECT_EQ(Capacity(0), queue.FlexibleCapacityOf(threadB));
+  EXPECT_EQ(Capacity(6), queue.CapacityOf(threadB));
+
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(0));
+    EXPECT_EQ(&threadA, next);
+    EXPECT_EQ(Time{2}, preemption);
+  }
+  threadA.Tick(Duration{2});
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(2));
+    EXPECT_EQ(&threadB, next);
+    EXPECT_EQ(Time{8}, preemption);
+  }
+  threadB.Tick(Duration{6});
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(8));
+    EXPECT_EQ(&threadA, next);
+    EXPECT_EQ(Time{10}, preemption);
+  }
+  threadA.Tick(Duration{2});
+}
+
+TEST(RunQueueTests, ThreadStateManagement) {
+  TestThread threadA{{Period(5), Capacity(1)}, Start(0)};
+  TestThread threadB{{Period(10), Capacity(2)}, Start(0)};
+
+  EXPECT_EQ(sched::ThreadState::kInitial, threadA.state());
+  EXPECT_EQ(sched::ThreadState::kInitial, threadB.state());
+
+  sched::RunQueue<TestThread> queue;
+  queue.Queue(threadA, Start(0));
+  queue.Queue(threadB, Start(0));
+
+  EXPECT_EQ(sched::ThreadState::kReady, threadA.state());
+  EXPECT_EQ(sched::ThreadState::kReady, threadB.state());
+
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(0));
+    EXPECT_EQ(&threadA, next);
+    EXPECT_EQ(Time{1}, preemption);
+    threadA.Tick(Duration{1});
+  }
+
+  EXPECT_EQ(sched::ThreadState::kRunning, threadA.state());
+  EXPECT_EQ(sched::ThreadState::kReady, threadB.state());
+
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(1));
+    EXPECT_EQ(&threadB, next);
+    EXPECT_EQ(Time{3}, preemption);
+    threadB.Tick(Duration{2});
+  }
+
+  EXPECT_EQ(sched::ThreadState::kReady, threadA.state());
+  EXPECT_EQ(sched::ThreadState::kRunning, threadB.state());
+
+  {
+    auto [next, preemption] = queue.SelectNextThread(Start(3));
+    EXPECT_EQ(nullptr, next);
+    EXPECT_EQ(Time{5}, preemption);
+  }
+
+  EXPECT_EQ(sched::ThreadState::kReady, threadA.state());
+  EXPECT_EQ(sched::ThreadState::kReady, threadB.state());
+}
+
 }  // namespace
diff --git a/zircon/kernel/lib/sched/thread-base-tests.cc b/zircon/kernel/lib/sched/thread-base-tests.cc
index b18e663..3c3ec54 100644
--- a/zircon/kernel/lib/sched/thread-base-tests.cc
+++ b/zircon/kernel/lib/sched/thread-base-tests.cc
@@ -8,6 +8,7 @@
 
 #include <gtest/gtest.h>
 
+#include "lib/sched/thread-base.h"
 #include "test-thread.h"
 
 namespace {
@@ -15,6 +16,11 @@
 using Duration = sched::Duration;
 using Time = sched::Time;
 
+TEST(ThreadBaseTests, InitialState) {
+  TestThread thread{{Period(10), Capacity(5)}, Start(0)};
+  EXPECT_EQ(sched::ThreadState::kInitial, thread.state());
+}
+
 TEST(ThreadBaseTests, Start) {
   {
     TestThread thread{{Period(10), Capacity(5)}, Start(0)};
diff --git a/zircon/kernel/lib/syscalls/BUILD.gn b/zircon/kernel/lib/syscalls/BUILD.gn
index a321475..68d303b 100644
--- a/zircon/kernel/lib/syscalls/BUILD.gn
+++ b/zircon/kernel/lib/syscalls/BUILD.gn
@@ -62,14 +62,12 @@
   deps = [
     ":dispatch",
     ":headers",
-    "//zircon/kernel/dev/udisplay",
     "//zircon/kernel/lib/boot-options",
     "//zircon/kernel/lib/console",
     "//zircon/kernel/lib/counters",
     "//zircon/kernel/lib/crashlog",
     "//zircon/kernel/lib/crypto",
     "//zircon/kernel/lib/fbl",
-    "//zircon/kernel/lib/gfxconsole",
     "//zircon/kernel/lib/heap",
     "//zircon/kernel/lib/io",
     "//zircon/kernel/lib/kpci",
diff --git a/zircon/kernel/lib/syscalls/ddk.cc b/zircon/kernel/lib/syscalls/ddk.cc
index aee3b01..3fe4d8c 100644
--- a/zircon/kernel/lib/syscalls/ddk.cc
+++ b/zircon/kernel/lib/syscalls/ddk.cc
@@ -24,7 +24,6 @@
 
 #include <dev/interrupt.h>
 #include <dev/iommu.h>
-#include <dev/udisplay.h>
 #include <fbl/inline_array.h>
 #include <object/bus_transaction_initiator_dispatcher.h>
 #include <object/handle.h>
@@ -203,41 +202,7 @@
 zx_status_t sys_framebuffer_set_range(zx_handle_t hrsrc, zx_handle_t vmo_handle, uint32_t len,
                                       uint32_t format, uint32_t width, uint32_t height,
                                       uint32_t stride) {
-  zx_status_t status;
-  if ((status = validate_resource_kind_base(hrsrc, ZX_RSRC_KIND_SYSTEM,
-                                            ZX_RSRC_SYSTEM_FRAMEBUFFER_BASE)) < 0) {
-    return status;
-  }
-
-  if (vmo_handle == ZX_HANDLE_INVALID) {
-    udisplay_clear_framebuffer_vmo();
-    return ZX_OK;
-  }
-
-  auto up = ProcessDispatcher::GetCurrent();
-
-  // lookup the dispatcher from handle
-  fbl::RefPtr<VmObjectDispatcher> vmo;
-  status = up->handle_table().GetDispatcher(*up, vmo_handle, &vmo);
-  if (status != ZX_OK) {
-    return status;
-  }
-
-  status = udisplay_set_framebuffer(vmo->vmo());
-  if (status != ZX_OK) {
-    return status;
-  }
-
-  display_info di;
-  memset(&di, 0, sizeof(display_info));
-  di.format = format;
-  di.width = width;
-  di.height = height;
-  di.stride = stride;
-  di.flags = DISPLAY_FLAG_HW_FRAMEBUFFER;
-  udisplay_set_display_info(&di);
-
-  return ZX_OK;
+  return ZX_ERR_NOT_SUPPORTED;
 }
 
 // zx_status_t zx_iommu_create
diff --git a/zircon/kernel/lib/syscalls/ddk_pci.cc b/zircon/kernel/lib/syscalls/ddk_pci.cc
index 797e7355..8812af3 100644
--- a/zircon/kernel/lib/syscalls/ddk_pci.cc
+++ b/zircon/kernel/lib/syscalls/ddk_pci.cc
@@ -5,7 +5,6 @@
 // https://opensource.org/licenses/MIT
 
 #include <align.h>
-#include <lib/gfxconsole.h>
 #include <lib/pci/pio.h>
 #include <lib/user_copy/user_ptr.h>
 #include <platform.h>
@@ -45,14 +44,6 @@
 
 #define LOCAL_TRACE 0
 
-// If we were built with the GFX console, make sure that it is un-bound when
-// user mode takes control of PCI.  Note: there should probably be a cleaner way
-// of doing this.  Not all system have PCI, and (eventually) not all systems
-// will attempt to initialize PCI.  Someday, there should be a different way of
-// handing off from early/BSOD kernel mode graphics to user mode.
-#include <lib/gfxconsole.h>
-static inline void shutdown_early_init_console() { gfxconsole_bind_display(nullptr, nullptr); }
-
 #ifdef WITH_KERNEL_PCIE
 namespace {
 struct FreeDeleter {
@@ -434,7 +425,6 @@
     return ret;
   }
 
-  shutdown_early_init_console();
   return ZX_OK;
 }
 
@@ -789,7 +779,6 @@
 #else   // WITH_KERNEL_PCIE
 // zx_status_t zx_pci_init
 zx_status_t sys_pci_init(zx_handle_t, user_in_ptr<const zx_pci_init_arg_t>, uint32_t) {
-  shutdown_early_init_console();
   return ZX_OK;
 }
 
diff --git a/zircon/kernel/lib/syscalls/zircon.cc b/zircon/kernel/lib/syscalls/zircon.cc
index 9c569f7..4764a2c 100644
--- a/zircon/kernel/lib/syscalls/zircon.cc
+++ b/zircon/kernel/lib/syscalls/zircon.cc
@@ -125,18 +125,19 @@
 // zx_status_t zx_debuglog_create
 zx_status_t sys_debuglog_create(zx_handle_t rsrc, uint32_t options, zx_handle_t* out) {
   LTRACEF("options 0x%x\n", options);
-
   // To support allowing the libc dynamic linker to emit log messages even
   // before process bootstrap is complete, we allow creating a debuglog with
   // options == 0 (write-only) without yet having a valid `rsrc` handle.
   // Otherwise, we should require a valid `rsrc` handle.
   // Inversely: if a resource handle is given, or if `options` is nonzero,
-  // require that `rsrc` be a valid root resource handle.
-  if (rsrc != ZX_HANDLE_INVALID || options != 0) {
-    // TODO(https://fxbug.dev/42105834): finer grained validation
-    zx_status_t status = validate_resource(rsrc, ZX_RSRC_KIND_ROOT);
-    if (status != ZX_OK)
+  // require that `rsrc` be a valid debuglog resource handle.
+  if (rsrc != ZX_HANDLE_INVALID) {
+    if (zx_status_t status = validate_resource_kind_base(rsrc, ZX_RSRC_KIND_SYSTEM,
+                                                         ZX_RSRC_SYSTEM_DEBUGLOG_BASE) != ZX_OK)
       return status;
+  } else {
+    if (options != 0)
+      return ZX_ERR_BAD_HANDLE;
   }
 
   // Ensure only valid options were given provided. The only valid flag is currently
diff --git a/zircon/kernel/lib/userabi/userboot/BUILD.gn b/zircon/kernel/lib/userabi/userboot/BUILD.gn
index 5a8bc03..1e58417 100644
--- a/zircon/kernel/lib/userabi/userboot/BUILD.gn
+++ b/zircon/kernel/lib/userabi/userboot/BUILD.gn
@@ -45,7 +45,10 @@
       # userboot can't use any instrumentation runtimes.
       exclude_variant_tags = [ "instrumented" ]
 
-      toolchain_tags = [ "standalone" ]
+      toolchain_tags = [
+        "no-floating-point",
+        "standalone",
+      ]
     }
   }
 }
diff --git a/zircon/kernel/phys/BUILD.gn b/zircon/kernel/phys/BUILD.gn
index f92e73e..ed8d7fd 100644
--- a/zircon/kernel/phys/BUILD.gn
+++ b/zircon/kernel/phys/BUILD.gn
@@ -41,7 +41,10 @@
       with_shared = false
       is_pic_default = true
 
-      toolchain_tags = [ "kernel" ]
+      toolchain_tags = [
+        "kernel",
+        "no-floating-point",
+      ]
 
       configs = [ "//zircon/kernel/phys:phys_config" ]
 
diff --git a/zircon/kernel/phys/efi/BUILD.gn b/zircon/kernel/phys/efi/BUILD.gn
index 256e58d..d0803c6 100644
--- a/zircon/kernel/phys/efi/BUILD.gn
+++ b/zircon/kernel/phys/efi/BUILD.gn
@@ -21,8 +21,9 @@
       with_shared = false
 
       toolchain_tags = [
-        "kernel",
         "efi",
+        "kernel",
+        "no-floating-point",
       ]
 
       configs = [ "//zircon/kernel/phys/efi:efi_config" ]
diff --git a/zircon/kernel/phys/include/phys/symbolize.h b/zircon/kernel/phys/include/phys/symbolize.h
index d83f5bd..3aaf895 100644
--- a/zircon/kernel/phys/include/phys/symbolize.h
+++ b/zircon/kernel/phys/include/phys/symbolize.h
@@ -107,17 +107,26 @@
   // Print a backtrace, ensuring context has been printed beforehand.
   // This takes any container of uintptr_t, so FramePointer works.
   template <typename T>
-  PHYS_SINGLETHREAD void BackTrace(const T& pcs, unsigned int n = 0) {
+  PHYS_SINGLETHREAD void BackTrace(const T& pcs, unsigned int n, unsigned int max) {
     Context();
     for (uintptr_t pc : pcs) {
+      if (max != 0 && n >= max) {
+        writer_.Prefix(name_)
+            .Literal("Backtrace truncated before frame #")
+            .DecimalDigits(n)
+            .Newline();
+        break;
+      }
       BackTraceFrame(n++, pc);
     }
   }
 
-  // Print both flavors of backtrace together.
+  // Print both flavors of backtrace together.  If the optional interrupt_pc
+  // argument is supplied, then it's inserted as frame 0 and marked as exact PC
+  // (whereas all frame-pointer and shadow-call-stack frames are marked as RA).
   PHYS_SINGLETHREAD void PrintBacktraces(const FramePointerBacktrace& frame_pointers,
                                          const arch::ShadowCallStackBacktrace& shadow_call_stack,
-                                         unsigned int n = 0);
+                                         ktl::optional<uintptr_t> interrupt_pc = ktl::nullopt);
 
   // Print the trigger markup element for a dumpfile.
   void DumpFile(ktl::string_view announce, size_t size_bytes, ktl::string_view sink_name,
diff --git a/zircon/kernel/phys/lib/boot-shim/devicetree-arm-gic-item-test.cc b/zircon/kernel/phys/lib/boot-shim/devicetree-arm-gic-item-test.cc
index 42cae4a..5575e85 100644
--- a/zircon/kernel/phys/lib/boot-shim/devicetree-arm-gic-item-test.cc
+++ b/zircon/kernel/phys/lib/boot-shim/devicetree-arm-gic-item-test.cc
@@ -142,6 +142,143 @@
   ASSERT_TRUE(present, "ZBI Driver for GIC V2 missing.");
 }
 
+TEST_F(ArmDevicetreeGicItemTest, GicV3Uint64Stride) {
+  constexpr auto kExpectedMmio = cpp20::to_array<boot_shim::DevicetreeMmioRange>({
+      {
+          .address = 0x8000000,
+          .size = 0x10000,
+      },
+      // Reflects the GICR base and stride
+      {
+          .address = 0x8100000,
+          .size = 0x20000,
+      },
+  });
+
+  std::array<std::byte, 256> image_buffer;
+  zbitl::Image<cpp20::span<std::byte>> image(image_buffer);
+  ASSERT_TRUE(image.clear().is_ok());
+
+  auto fdt = arm_gic3_stride();
+  boot_shim::DevicetreeBootShim<boot_shim::ArmDevicetreeGicItem> shim("test", fdt);
+  shim.set_mmio_observer(get_mmio_observer());
+
+  ASSERT_TRUE(shim.Init());
+  boot_shim::testing::CheckMmioRanges(mmio_ranges(), kExpectedMmio);
+  EXPECT_TRUE(shim.AppendItems(image).is_ok());
+
+  // Look for a gic 3 driver.
+  bool present = false;
+  for (auto [header, payload] : image) {
+    if (header->type == ZBI_TYPE_KERNEL_DRIVER && header->extra == ZBI_KERNEL_DRIVER_ARM_GIC_V3) {
+      present = true;
+      ASSERT_GE(payload.size(), sizeof(zbi_dcfg_arm_gic_v3_driver_t));
+      auto* dcfg = reinterpret_cast<zbi_dcfg_arm_gic_v3_driver_t*>(payload.data());
+      EXPECT_EQ(dcfg->mmio_phys, 0x08000000);
+      EXPECT_EQ(dcfg->gicd_offset, 0x0);
+      EXPECT_EQ(dcfg->gicr_offset, 0x0100000);
+      EXPECT_EQ(dcfg->gicr_stride, 0x20000);
+      EXPECT_EQ(dcfg->ipi_base, 0x0);
+      EXPECT_FALSE(dcfg->optional);
+      break;
+    }
+  }
+  image.ignore_error();
+  ASSERT_TRUE(present, "ZBI Driver for GIC V3 missing.");
+}
+
+TEST_F(ArmDevicetreeGicItemTest, GicV3FourStride) {
+  constexpr auto kExpectedMmio = cpp20::to_array<boot_shim::DevicetreeMmioRange>({
+      {
+          .address = 0x8000000,
+          .size = 0x10000,
+      },
+      // Reflects the GICR base and aggregate stride (4 regions)
+      {
+          .address = 0x8100000,
+          .size = 0x80000,
+      },
+  });
+
+  std::array<std::byte, 256> image_buffer;
+  zbitl::Image<cpp20::span<std::byte>> image(image_buffer);
+  ASSERT_TRUE(image.clear().is_ok());
+
+  auto fdt = arm_gic3_four_stride();
+  boot_shim::DevicetreeBootShim<boot_shim::ArmDevicetreeGicItem> shim("test", fdt);
+  shim.set_mmio_observer(get_mmio_observer());
+
+  ASSERT_TRUE(shim.Init());
+  boot_shim::testing::CheckMmioRanges(mmio_ranges(), kExpectedMmio);
+  EXPECT_TRUE(shim.AppendItems(image).is_ok());
+
+  // Look for a gic 3 driver.
+  bool present = false;
+  for (auto [header, payload] : image) {
+    if (header->type == ZBI_TYPE_KERNEL_DRIVER && header->extra == ZBI_KERNEL_DRIVER_ARM_GIC_V3) {
+      present = true;
+      ASSERT_GE(payload.size(), sizeof(zbi_dcfg_arm_gic_v3_driver_t));
+      auto* dcfg = reinterpret_cast<zbi_dcfg_arm_gic_v3_driver_t*>(payload.data());
+      EXPECT_EQ(dcfg->mmio_phys, 0x08000000);
+      EXPECT_EQ(dcfg->gicd_offset, 0x0);
+      EXPECT_EQ(dcfg->gicr_offset, 0x0100000);
+      EXPECT_EQ(dcfg->gicr_stride, 0x20000);
+      EXPECT_EQ(dcfg->ipi_base, 0x0);
+      EXPECT_FALSE(dcfg->optional);
+      break;
+    }
+  }
+  image.ignore_error();
+  ASSERT_TRUE(present, "ZBI Driver for GIC V3 missing.");
+}
+
+TEST_F(ArmDevicetreeGicItemTest, GicV3SubsumedStride) {
+  constexpr auto kExpectedMmio = cpp20::to_array<boot_shim::DevicetreeMmioRange>({
+      {
+          .address = 0x8000000,
+          .size = 0x10000,
+      },
+      // Reflects the GICR base which matches the stride
+      {
+          .address = 0x8100000,
+          .size = 0x20000,
+      },
+  });
+
+  std::array<std::byte, 256> image_buffer;
+  zbitl::Image<cpp20::span<std::byte>> image(image_buffer);
+  ASSERT_TRUE(image.clear().is_ok());
+
+  auto fdt = arm_gic3_subsumed_stride();
+  boot_shim::DevicetreeBootShim<boot_shim::ArmDevicetreeGicItem> shim("test", fdt);
+  shim.set_mmio_observer(get_mmio_observer());
+
+  ASSERT_TRUE(shim.Init());
+  boot_shim::testing::CheckMmioRanges(mmio_ranges(), kExpectedMmio);
+  EXPECT_TRUE(shim.AppendItems(image).is_ok());
+
+  // Look for a gic 3 driver.
+  bool present = false;
+  for (auto [header, payload] : image) {
+    if (header->type == ZBI_TYPE_KERNEL_DRIVER && header->extra == ZBI_KERNEL_DRIVER_ARM_GIC_V3) {
+      present = true;
+      ASSERT_GE(payload.size(), sizeof(zbi_dcfg_arm_gic_v3_driver_t));
+      auto* dcfg = reinterpret_cast<zbi_dcfg_arm_gic_v3_driver_t*>(payload.data());
+      EXPECT_EQ(dcfg->mmio_phys, 0x08000000);
+      EXPECT_EQ(dcfg->gicd_offset, 0x0);
+      EXPECT_EQ(dcfg->gicr_offset, 0x0100000);
+      EXPECT_EQ(dcfg->gicr_stride, 0x20000);
+      EXPECT_EQ(dcfg->ipi_base, 0x0);
+      EXPECT_FALSE(dcfg->optional);
+      break;
+    }
+  }
+  image.ignore_error();
+  ASSERT_TRUE(present, "ZBI Driver for GIC V3 missing.");
+}
+
+
+
 // We dont support GicV3 with MSI yet, not reflected in the driver configuration.
 TEST_F(ArmDevicetreeGicItemTest, ParseQemuGicV3) {
   constexpr auto kExpectedMmio = cpp20::to_array<boot_shim::DevicetreeMmioRange>({
diff --git a/zircon/kernel/phys/lib/boot-shim/devicetree-arm-gic-item.cc b/zircon/kernel/phys/lib/boot-shim/devicetree-arm-gic-item.cc
index fc5499b..c98b690 100644
--- a/zircon/kernel/phys/lib/boot-shim/devicetree-arm-gic-item.cc
+++ b/zircon/kernel/phys/lib/boot-shim/devicetree-arm-gic-item.cc
@@ -116,6 +116,7 @@
   auto& reg = *reg_ptr;
 
   auto [redistributor_stride] = decoder.FindProperties("redistributor-stride");
+  auto [redistributor_regions] = decoder.FindProperties("#redistributor-regions");
 
   zbi_dcfg_arm_gic_v3_driver_t dcfg{};
 
@@ -132,7 +133,6 @@
       return devicetree::ScanState::kDone;
     }
     (*mmio_observer_)(DevicetreeMmioRange::From(reg[GicV3Regs::kGicd]));
-    (*mmio_observer_)(DevicetreeMmioRange::From(reg[GicV3Regs::kGicr]));
     dcfg.mmio_phys = std::min(*gicd, *gicr);
     dcfg.gicr_offset = *gicr - dcfg.mmio_phys;
     dcfg.gicd_offset = *gicd - dcfg.mmio_phys;
@@ -140,6 +140,10 @@
     if (redistributor_stride) {
       if (auto stride = redistributor_stride->AsUint32()) {
         dcfg.gicr_stride = *stride;
+      } else if (auto stride64 = redistributor_stride->AsUint64())  {
+        dcfg.gicr_stride = *stride64;
+      } else {
+        OnError("GIC v3: failed to parse redistributor stride.");
       }
     } else {
       // See:
@@ -153,7 +157,28 @@
       dcfg.gicr_stride = 2 * 64 << 10;
     }
   }
-
+  auto regions = 1;
+  if (redistributor_stride && redistributor_regions) {
+      if (auto parsed_regions = redistributor_regions->AsUint32()) {
+        regions = *parsed_regions;
+      }
+  }
+  if (regions < 1 || regions > 256) {
+    OnError("GIC v3: Out of bounds '#redistributor-stride'.");
+    regions = 1;
+  }
+  // N.b., many GICv3 definitions only declare a single redistribution region
+  // rather than one per-cpu.  They instead ensure the reg for the GICR includes
+  // all the redistributors within its range.  We observe the larger of the
+  // definitions for MmioRange purposes.
+  if (reg[GicV3Regs::kGicr].size() > dcfg.gicr_stride * regions) {
+    (*mmio_observer_)(DevicetreeMmioRange::From(reg[GicV3Regs::kGicr]));
+  } else {
+    const size_t total_size = static_cast<size_t>(dcfg.gicr_stride * regions);
+    const DevicetreeMmioRange range = { .address = reg[GicV3Regs::kGicr].address().value(),
+                                        .size = total_size };
+    (*mmio_observer_)(range);
+  }
   dcfg.ipi_base = 0;
   dcfg.optional = false;
   set_payload(dcfg);
diff --git a/zircon/kernel/phys/lib/boot-shim/devicetree-test-fixture.cc b/zircon/kernel/phys/lib/boot-shim/devicetree-test-fixture.cc
index 572d1f8..a7f5e68 100644
--- a/zircon/kernel/phys/lib/boot-shim/devicetree-test-fixture.cc
+++ b/zircon/kernel/phys/lib/boot-shim/devicetree-test-fixture.cc
@@ -14,6 +14,9 @@
 
 std::optional<LoadedDtb> SyntheticDevicetreeTest::empty_dtb_ = std::nullopt;
 std::optional<LoadedDtb> SyntheticDevicetreeTest::arm_gic2_no_msi_ = std::nullopt;
+std::optional<LoadedDtb> SyntheticDevicetreeTest::arm_gic3_stride_ = std::nullopt;
+std::optional<LoadedDtb> SyntheticDevicetreeTest::arm_gic3_four_stride_ = std::nullopt;
+std::optional<LoadedDtb> SyntheticDevicetreeTest::arm_gic3_subsumed_stride_ = std::nullopt;
 
 std::optional<LoadedDtb> ArmDevicetreeTest::crosvm_arm_ = std::nullopt;
 std::optional<LoadedDtb> ArmDevicetreeTest::qemu_arm_gic3_ = std::nullopt;
diff --git a/zircon/kernel/phys/lib/boot-shim/include/lib/boot-shim/testing/devicetree-test-fixture.h b/zircon/kernel/phys/lib/boot-shim/include/lib/boot-shim/testing/devicetree-test-fixture.h
index 103494b..aff5b50 100644
--- a/zircon/kernel/phys/lib/boot-shim/include/lib/boot-shim/testing/devicetree-test-fixture.h
+++ b/zircon/kernel/phys/lib/boot-shim/include/lib/boot-shim/testing/devicetree-test-fixture.h
@@ -30,16 +30,34 @@
     loaded_dtb = LoadDtb("arm_gic2_no_msi.dtb");
     ASSERT_TRUE(loaded_dtb.is_ok(), "%s", loaded_dtb.error_value().c_str());
     arm_gic2_no_msi_ = std::move(loaded_dtb).value();
+
+    loaded_dtb = LoadDtb("arm_gic3_stride.dtb");
+    ASSERT_TRUE(loaded_dtb.is_ok(), "%s", loaded_dtb.error_value().c_str());
+    arm_gic3_stride_ = std::move(loaded_dtb).value();
+
+    loaded_dtb = LoadDtb("arm_gic3_four_stride.dtb");
+    ASSERT_TRUE(loaded_dtb.is_ok(), "%s", loaded_dtb.error_value().c_str());
+    arm_gic3_four_stride_ = std::move(loaded_dtb).value();
+
+    loaded_dtb = LoadDtb("arm_gic3_subsumed_stride.dtb");
+    ASSERT_TRUE(loaded_dtb.is_ok(), "%s", loaded_dtb.error_value().c_str());
+    arm_gic3_subsumed_stride_ = std::move(loaded_dtb).value();
   }
 
   static void TearDownTestSuite() { empty_dtb_ = std::nullopt; }
 
   auto empty_fdt() { return empty_dtb_->fdt(); }
   auto arm_gic2_no_msi() { return arm_gic2_no_msi_->fdt(); }
+  auto arm_gic3_stride() { return arm_gic3_stride_->fdt(); }
+  auto arm_gic3_four_stride() { return arm_gic3_four_stride_->fdt(); }
+  auto arm_gic3_subsumed_stride() { return arm_gic3_subsumed_stride_->fdt(); }
 
  private:
   static std::optional<LoadedDtb> empty_dtb_;
   static std::optional<LoadedDtb> arm_gic2_no_msi_;
+  static std::optional<LoadedDtb> arm_gic3_stride_;
+  static std::optional<LoadedDtb> arm_gic3_four_stride_;
+  static std::optional<LoadedDtb> arm_gic3_subsumed_stride_;
 };
 
 // Devicetree Test fixture that provides members to existing ARM dtbs.
diff --git a/zircon/kernel/phys/phys-elf-module.ld b/zircon/kernel/phys/phys-elf-module.ld
index 57bb5aa..8afc0ab 100644
--- a/zircon/kernel/phys/phys-elf-module.ld
+++ b/zircon/kernel/phys/phys-elf-module.ld
@@ -18,11 +18,11 @@
   .rela.dyn : { INPUT_SECTION_FLAGS(SHF_ALLOC) *(.rela.*) }
   .rel.dyn : { INPUT_SECTION_FLAGS(SHF_ALLOC) *(.rel.*) }
 
-  .rodata : { *(.rodata*) }
+  .rodata : { *(.rodata*) *(.srodata*) }
 
   . = ALIGN(CONSTANT(MAXPAGESIZE));
 
-  .text : { *(.text*) }
+  .text : { *(.stext*) *(.text*) }
 
    PROVIDE_HIDDEN(_etext = .);
 
@@ -45,7 +45,7 @@
     KEEP(*(.fini_array))
   }
 
-  .data.rel.ro : { *(.data.rel.ro*) }
+  .data.rel.ro : {  *(.sdata.rel.ro*) *(.data.rel.ro*) }
 
   .dynamic : { *(.dynamic) }
 
@@ -53,13 +53,13 @@
 
   . = DATA_SEGMENT_RELRO_END (0, .);
 
-  .data : { *(.data*) *(COMMON) }
+  .data : { *(.sdata*) *(.data*) }
 
    PROVIDE_HIDDEN(_edata = .);
 
    PROVIDE_HIDDEN(__bss_start = .);
 
-  .bss : { *(.bss*) }
+  .bss : { *(.sbss*) *(.bss* COMMON) }
 
    PROVIDE_HIDDEN(_end = .);
   . = DATA_SEGMENT_END (.);
diff --git a/zircon/kernel/phys/phys.ld b/zircon/kernel/phys/phys.ld
index 4b626dc..30f1f1b 100644
--- a/zircon/kernel/phys/phys.ld
+++ b/zircon/kernel/phys/phys.ld
@@ -42,7 +42,7 @@
   } :load
 
   .text : {
-    *(.text*)
+    *(.text*) *(.stext*)
   }
 
   /*
@@ -77,7 +77,7 @@
   }
 
   .rodata : {
-    *(.rodata*)
+    *(.srodata*) *(.rodata*)
 
     /*
      * Provide the link-time load address, required for relocation calculations.
@@ -147,9 +147,7 @@
    */
   __llvm_prf_data : { *(__llvm_prf_data) }
 
-  .data : {
-    *(.data*)
-  }
+  .data : { *(.sdata*) *(.data*) }
 
   /*
    * Instrumentation data.  Orphans placement can put this in weird places,
@@ -174,7 +172,7 @@
      */
     PROVIDE_HIDDEN(_edata = .);
 
-    *(.bss* .sbss* COMMON)
+    *(.sbss*) *(.bss* COMMON)
 
     /*
      * The start.S code relies on the alignment of the end of .bss as well.
diff --git a/zircon/kernel/phys/symbolize.cc b/zircon/kernel/phys/symbolize.cc
index 63a8edd..4e63aaa 100644
--- a/zircon/kernel/phys/symbolize.cc
+++ b/zircon/kernel/phys/symbolize.cc
@@ -118,26 +118,33 @@
 
 void Symbolize::PrintBacktraces(const Symbolize::FramePointerBacktrace& frame_pointers,
                                 const arch::ShadowCallStackBacktrace& shadow_call_stack,
-                                unsigned int n) {
+                                ktl::optional<uintptr_t> interrupt_pc) {
   Context();
-  if (frame_pointers.empty()) {
-    Printf("%s: Frame pointer backtrace is empty!\n", name_);
-  } else {
-    Printf("%s: Backtrace (via frame pointers):\n", name_);
-    BackTrace(frame_pointers, n);
-  }
-  if (BootShadowCallStack::kEnabled) {
-    if (shadow_call_stack.empty()) {
-      Printf("%s: Shadow call stack backtrace is empty!\n", name_);
+
+  // For either kind of backtrace, the interrupt_pc is a special frame #0 if
+  // it's present.  It gets printed after other messages about the backtrace as
+  // a whole, just as if it were stack.front() in a case with no interrupt_pc.
+  auto backtrace = [configured_max = gBootOptions ? gBootOptions->phys_backtrace_max : 0,  //
+                    this, interrupt_pc](const auto& stack, const char* which) PHYS_SINGLETHREAD {
+    Printf("%s: Backtrace (via %s)%s%s\n", name_, which, stack.empty() ? " is empty!" : ":",
+           (stack.empty() && interrupt_pc) ? "  Only the interrupted PC is available:" : "");
+    if (interrupt_pc) {
+      BackTraceFrame(0, *interrupt_pc, true);
+      BackTrace(stack, 1, configured_max);
     } else {
-      Printf("%s: Backtrace (via shadow call stack):\n", name_);
+      BackTrace(stack, 0, configured_max);
     }
-    BackTrace(shadow_call_stack, n);
+  };
+
+  backtrace(frame_pointers, "frame pointers");
+
+  if (BootShadowCallStack::kEnabled) {
+    backtrace(shadow_call_stack, "shadow call stack");
   }
 }
 
 void Symbolize::PrintStack(uintptr_t sp, ktl::optional<size_t> max_size_bytes) {
-  const size_t configured_max = gBootOptions->phys_print_stack_max;
+  const size_t configured_max = gBootOptions ? gBootOptions->phys_print_stack_max : 1024;
   auto maybe_dump_stack = [max = max_size_bytes.value_or(configured_max), sp,
                            this](const auto& stack) -> bool {
     if (!stack.boot_stack.IsOnStack(sp)) {
@@ -260,32 +267,108 @@
 
 void Symbolize::PrintException(uint64_t vector, const char* vector_name,
                                const PhysExceptionState& exc) {
+  // To avoid re-entry cascades from exceptions during the steps of this
+  // function, maintain a progress indicator.
+  enum Progress : unsigned int {
+    kNotInUse,
+    kEntered,
+    kChecked,
+    kVector,
+    kContext,
+    kRegs,
+    kFp,
+    kScs,
+    kPrintBt,
+    kStack,
+    kStepLimit,
+  };
+  constexpr unsigned int kSteps = kStepLimit - 1;
+  static Progress gProgress = kNotInUse;
+
+  // `return_after(kJustDid)` returns false normally, and returns true if we
+  // should bail out early because we've already gotten this far and re-entered
+  // without getting farther.
+  constexpr auto return_after = [](Progress step) -> bool {
+    if (gProgress < step) [[likely]] {
+      ZX_ASSERT_MSG(gProgress == step - 1, ": Hit return_after(%u) with gProgress=%u", step,
+                    gProgress);
+      gProgress = step;
+      return false;
+    }
+
+    if (gProgress > step) {
+      // This is a re-entry, but we haven't yet gotten as far as the last entry
+      // got, so keep going to report details about the re-entry.
+      printf(
+          "PrintException reached step %u of %u on re-entry after previously reaching step %u.\n",
+          step, kSteps, gProgress);
+      return false;
+    }
+
+    // This is a re-entry after not getting farther than this last time.  So it
+    // could be a cascade of repeated re-entry that would continue forever if
+    // we attempted to go past the step just completed.  Don't even attempt a
+    // printf here before recording the first step, so we identify a re-entry
+    // that's just from printf on the early-return paths above for later steps.
+    if (step != kEntered) {
+      printf("PrintException truncated after %u of %u steps in re-entry.\n", step, kSteps);
+    }
+    return true;
+  };
+
+  // The kChecked step just makes sure we won't even try the printf in the
+  // early-return case if we re-entered from that very printf at kChecked.
+  if (return_after(kEntered) || return_after(kChecked)) {
+    return;
+  }
+
   Printf("%s: exception vector %s (%#" PRIx64 ")\n", Symbolize::name_, vector_name, vector);
+  if (return_after(kVector)) {
+    return;
+  }
 
   // Always print the context, even if it was printed earlier.
   context_done_ = false;
   Context();
+  if (return_after(kContext)) {
+    return;
+  }
 
   PrintRegisters(exc);
-
-  BackTraceFrame(0, exc.pc(), true);
+  if (return_after(kRegs)) {
+    return;
+  }
 
   // Collect each kind of backtrace if possible.
   FramePointerBacktrace fp_backtrace;
   arch::ShadowCallStackBacktrace scs_backtrace;
 
   fp_backtrace = FramePointerBacktrace::BackTrace(exc.fp());
+  if (return_after(kFp)) {
+    return;
+  }
 
   uint64_t scsp = exc.shadow_call_sp();
   scs_backtrace = boot_shadow_call_stack.BackTrace(scsp);
   if (scs_backtrace.empty()) {
     scs_backtrace = phys_exception_shadow_call_stack.BackTrace(scsp);
   }
+  if (return_after(kScs)) {
+    return;
+  }
 
   // Print whatever we have.
-  PrintBacktraces(fp_backtrace, scs_backtrace);
+  PrintBacktraces(fp_backtrace, scs_backtrace, exc.pc());
+  if (return_after(kPrintBt)) {
+    return;
+  }
 
   PrintStack(exc.sp());
+  if (return_after(kStack)) {
+    return;
+  }
+
+  gProgress = kNotInUse;
 }
 
 void PrintPhysException(uint64_t vector, const char* vector_name, const PhysExceptionState& regs) {
diff --git a/zircon/kernel/phys/test/backtrace-test.cc b/zircon/kernel/phys/test/backtrace-test.cc
index 5c09345..e58edb9 100644
--- a/zircon/kernel/phys/test/backtrace-test.cc
+++ b/zircon/kernel/phys/test/backtrace-test.cc
@@ -34,13 +34,29 @@
   const ptrdiff_t fp_depth = bt_depth(fp_bt);
 
   printf("Printing frame pointer backtrace, %td frames:\n", fp_depth);
-  gSymbolize->BackTrace(fp_bt);
+  gSymbolize->BackTrace(fp_bt, 0, 0);
+
+  const unsigned int fp_max = static_cast<unsigned int>(fp_depth - 2);
+  constexpr unsigned int fp_bias = 3;
+  printf(
+      "Printing frame pointer backtrace, %td frames but"
+      " starting at #%u and truncated to %u frames total:\n",
+      fp_depth, fp_bias, fp_max);
+  gSymbolize->BackTrace(fp_bt, fp_bias, fp_bias + fp_max);
 
   const auto scs_bt = CollectScs();
   const ptrdiff_t scs_depth = bt_depth(scs_bt);
   if (BootShadowCallStack::kEnabled) {
     printf("Printing shadow call stack backtrace, %td frames:\n", scs_depth);
-    gSymbolize->BackTrace(scs_bt);
+    gSymbolize->BackTrace(scs_bt, 0, 0);
+
+    const unsigned int scs_max = static_cast<unsigned int>(scs_depth - 2);
+    constexpr unsigned int scs_bias = 3;
+    printf(
+        "Printing shadow call stack backtrace, %td frames but"
+        " starting at #%u and truncated to %u frames total:\n",
+        scs_depth, scs_bias, scs_max);
+    gSymbolize->BackTrace(scs_bt, scs_bias, scs_bias + scs_max);
 
     ZX_ASSERT(fp_depth == scs_depth);
 
diff --git a/zircon/kernel/platform/generic-arm/platform.cc b/zircon/kernel/platform/generic-arm/platform.cc
index 1e5f1e5..7ceac98 100644
--- a/zircon/kernel/platform/generic-arm/platform.cc
+++ b/zircon/kernel/platform/generic-arm/platform.cc
@@ -31,7 +31,6 @@
 #include <arch/arm64/mp.h>
 #include <arch/arm64/periphmap.h>
 #include <arch/mp.h>
-#include <dev/display.h>
 #include <dev/hw_rng.h>
 #include <dev/interrupt.h>
 #include <dev/power.h>
@@ -515,9 +514,6 @@
   return 0;
 }
 
-/* no built in framebuffer */
-zx_status_t display_get_info(display_info* info) { return ZX_ERR_NOT_FOUND; }
-
 void platform_specific_halt(platform_halt_action suggested_action, zircon_crash_reason_t reason,
                             bool halt_on_panic) {
   if (suggested_action == HALT_ACTION_REBOOT) {
@@ -587,8 +583,6 @@
                  (void*)kernel_dst_phys);
 }
 
-bool platform_early_console_enabled() { return false; }
-
 // Initialize Resource system after the heap is initialized.
 static void arm_resource_dispatcher_init_hook(unsigned int rl) {
   // 64 bit address space for MMIO on ARM64
diff --git a/zircon/kernel/platform/generic-riscv64/BUILD.gn b/zircon/kernel/platform/generic-riscv64/BUILD.gn
index 2f07e96..89373230 100644
--- a/zircon/kernel/platform/generic-riscv64/BUILD.gn
+++ b/zircon/kernel/platform/generic-riscv64/BUILD.gn
@@ -42,9 +42,5 @@
     "//zircon/system/ulib/ram-crashlog",
   ]
 
-  # TODO-rvbringup: hack to solve a lack of dep from lib/debuglog to dev/udisplay when building
-  # with kernel_no_userabi
-  deps += [ "//zircon/kernel/dev/udisplay" ]
-
   public_deps = [ "//zircon/system/ulib/affine" ]
 }
diff --git a/zircon/kernel/platform/generic-riscv64/platform.cc b/zircon/kernel/platform/generic-riscv64/platform.cc
index 3b88487..19e121f 100644
--- a/zircon/kernel/platform/generic-riscv64/platform.cc
+++ b/zircon/kernel/platform/generic-riscv64/platform.cc
@@ -28,7 +28,6 @@
 #include <arch/mp.h>
 #include <arch/riscv64.h>
 #include <arch/riscv64/sbi.h>
-#include <dev/display.h>
 #include <dev/hw_rng.h>
 #include <dev/interrupt.h>
 #include <dev/power.h>
@@ -594,9 +593,6 @@
   return 0;
 }
 
-/* no built in framebuffer */
-zx_status_t display_get_info(struct display_info* info) { return ZX_ERR_NOT_FOUND; }
-
 void platform_specific_halt(platform_halt_action suggested_action, zircon_crash_reason_t reason,
                             bool halt_on_panic) {
   TRACEF("suggested_action %u, reason %u, halt_on_panic %d\n", suggested_action,
@@ -651,8 +647,6 @@
   PANIC_UNIMPLEMENTED;
 }
 
-bool platform_early_console_enabled() { return false; }
-
 // Initialize Resource system after the heap is initialized.
 static void riscv64_resource_dispatcher_init_hook(unsigned int rl) {
   // 64 bit address space for MMIO on RISCV64
diff --git a/zircon/kernel/platform/pc/BUILD.gn b/zircon/kernel/platform/pc/BUILD.gn
index b7a688a..c671449 100644
--- a/zircon/kernel/platform/pc/BUILD.gn
+++ b/zircon/kernel/platform/pc/BUILD.gn
@@ -46,7 +46,6 @@
     "//zircon/kernel/lib/efi",
     "//zircon/kernel/lib/fbl",
     "//zircon/kernel/lib/fixed_point",
-    "//zircon/kernel/lib/gfxconsole",
     "//zircon/kernel/lib/init",
     "//zircon/kernel/lib/jtrace:headers",
     "//zircon/kernel/lib/ktl",
diff --git a/zircon/kernel/platform/pc/platform.cc b/zircon/kernel/platform/pc/platform.cc
index 264dda7..30f28c7 100644
--- a/zircon/kernel/platform/pc/platform.cc
+++ b/zircon/kernel/platform/pc/platform.cc
@@ -59,7 +59,6 @@
 #include <platform/pc/bootloader.h>
 #include <platform/pc/smbios.h>
 #include <platform/ram_mappable_crashlog.h>
-#include <vm/bootalloc.h>
 #include <vm/bootreserve.h>
 #include <vm/physmap.h>
 #include <vm/pmm.h>
@@ -80,8 +79,6 @@
 }  // namespace crashlog_impls
 }  // namespace
 
-static bool early_console_disabled;
-
 static void platform_save_bootloader_data(void) {
   if (gPhysHandoff->arch_handoff.framebuffer) {
     bootloader.fb = gPhysHandoff->arch_handoff.framebuffer.value();
@@ -101,12 +98,6 @@
     crashlog_impls::ram_mappable.Initialize(nvram.base, nvram.length);
     PlatformCrashlog::Bind(crashlog_impls::ram_mappable.Get());
   }
-
-  // Prevent the early boot allocator from handing out the memory the ZBI data
-  // is located in.
-  ktl::span<ktl::byte> zbi = ZbiInPhysmap();
-  auto phys = reinterpret_cast<uintptr_t>(zbi.data());
-  boot_alloc_reserve(phys, zbi.size_bytes());
 }
 
 static void boot_reserve_zbi() {
@@ -114,78 +105,6 @@
   boot_reserve_add_range(physmap_to_paddr(zbi.data()), ROUNDUP_PAGE_SIZE(zbi.size_bytes()));
 }
 
-#include <lib/gfxconsole.h>
-
-#include <dev/display.h>
-
-zx_status_t display_get_info(struct display_info* info) {
-  return gfxconsole_display_get_info(info);
-}
-
-bool platform_early_console_enabled() { return !early_console_disabled; }
-
-static void platform_early_display_init(void) {
-  display_info info;
-  void* bits;
-
-  if (bootloader.fb.base == 0) {
-    return;
-  }
-
-  if (!gBootOptions->gfx_console_early) {
-    early_console_disabled = true;
-    return;
-  }
-
-  // allocate an offscreen buffer of worst-case size, page aligned
-  bits = boot_alloc_mem(8192 + bootloader.fb.height * bootloader.fb.stride * 4);
-  bits = (void*)((((uintptr_t)bits) + 4095) & (~4095));
-
-  memset(&info, 0, sizeof(info));
-  info.format = bootloader.fb.format;
-  info.width = bootloader.fb.width;
-  info.height = bootloader.fb.height;
-  info.stride = bootloader.fb.stride;
-  info.flags = DISPLAY_FLAG_HW_FRAMEBUFFER;
-  info.framebuffer = (void*)X86_PHYS_TO_VIRT(bootloader.fb.base);
-
-  gfxconsole_bind_display(&info, bits);
-}
-
-/* Ensure the framebuffer is write-combining as soon as we have the VMM.
- * Some system firmware has the MTRRs for the framebuffer set to Uncached.
- * Since dealing with MTRRs is rather complicated, we wait for the VMM to
- * come up so we can use PAT to manage the memory types. */
-static void platform_ensure_display_memtype(uint level) {
-  if (bootloader.fb.base == 0) {
-    return;
-  }
-  if (early_console_disabled) {
-    return;
-  }
-  display_info info;
-  memset(&info, 0, sizeof(info));
-  info.format = bootloader.fb.format;
-  info.width = bootloader.fb.width;
-  info.height = bootloader.fb.height;
-  info.stride = bootloader.fb.stride;
-  info.flags = DISPLAY_FLAG_HW_FRAMEBUFFER;
-
-  void* addr = NULL;
-  zx_status_t status = VmAspace::kernel_aspace()->AllocPhysical(
-      "boot_fb", ROUNDUP(info.stride * info.height * 4, PAGE_SIZE), &addr, PAGE_SIZE_SHIFT,
-      bootloader.fb.base, 0 /* vmm flags */,
-      ARCH_MMU_FLAG_WRITE_COMBINING | ARCH_MMU_FLAG_PERM_READ | ARCH_MMU_FLAG_PERM_WRITE);
-  if (status != ZX_OK) {
-    TRACEF("Failed to map boot_fb: %d\n", status);
-    return;
-  }
-
-  info.framebuffer = addr;
-  gfxconsole_bind_display(&info, NULL);
-}
-LK_INIT_HOOK(display_memtype, &platform_ensure_display_memtype, LK_INIT_LEVEL_VM + 1)
-
 static void platform_init_crashlog(void) {
   // Nothing to do if we have already selected a crashlog implementation.
   if (PlatformCrashlog::HasNonTrivialImpl()) {
@@ -309,9 +228,6 @@
   platform_init_console();
 #endif
 
-  /* if the bootloader has framebuffer info, use it for early console */
-  platform_early_display_init();
-
   /* initialize the ACPI parser */
   PlatformInitAcpi(gPhysHandoff->acpi_rsdp.value_or(0));
 
diff --git a/zircon/kernel/vm/debug_compressor.cc b/zircon/kernel/vm/debug_compressor.cc
index 30f8a0d..d46f60a 100644
--- a/zircon/kernel/vm/debug_compressor.cc
+++ b/zircon/kernel/vm/debug_compressor.cc
@@ -8,6 +8,7 @@
 #include <lib/crypto/global_prng.h>
 
 #include <fbl/ref_counted_upgradeable.h>
+#include <kernel/auto_preempt_disabler.h>
 #include <vm/compression.h>
 #include <vm/debug_compressor.h>
 #include <vm/vm_cow_pages.h>
@@ -150,6 +151,7 @@
     return ZX_ERR_NO_MEMORY;
   }
 
+  AnnotatedAutoPreemptDisabler apd;
   Guard<SpinLock, IrqSave> guard{&lock_};
   ASSERT(!thread_);
   list_ = ktl::move(list);
diff --git a/zircon/kernel/vm/include/vm/page_queues.h b/zircon/kernel/vm/include/vm/page_queues.h
index c8d141d..db3f9e8 100644
--- a/zircon/kernel/vm/include/vm/page_queues.h
+++ b/zircon/kernel/vm/include/vm/page_queues.h
@@ -140,7 +140,21 @@
   // Tells the page queue this page has been accessed, and it should have its position in the queues
   // updated. This method will take the internal page queues lock and should not be used for
   // accessed harvesting, where MarkAccessedDeferredCount should be used instead.
-  void MarkAccessed(vm_page_t* page);
+  void MarkAccessed(vm_page_t* page) {
+    // Can retrieve the queue ref and do a short circuit check for whether mark accessed is
+    // necessary. Although this check is racy, since we do not yet hold the lock, we will either:
+    //  * Race and fail to mark accessed - this is fine since racing implies a newly added page,
+    //    which would be added to the mru queue anyway.
+    //  * Race and attempt to spuriously mark accessed - this is fine as we will check again with
+    //    the lock held.
+    auto queue_ref = page->object.get_page_queue_ref();
+    const uint8_t queue = queue_ref.load(ktl::memory_order_relaxed);
+    if (queue < PageQueueReclaimDontNeed) {
+      return;
+    }
+    // With the early check complete, continue with the non-inlined longer body.
+    MarkAccessedContinued(page);
+  }
 
   // Provides access to the underlying lock, allowing _Locked variants to be called. Use of this is
   // highly discouraged as the underlying lock is a CriticalMutex which disables preemption.
@@ -633,6 +647,10 @@
   void MaybeTriggerLruProcessing() TA_EXCL(lock_);
   bool NeedsLruProcessing() const;
 
+  // MarkAccessed is split into a small inlinable portion that attempts to short circuit, and this
+  // main implementation that does the actual accessed marking if needed.
+  void MarkAccessedContinued(vm_page_t* page);
+
   // Returns true if a page is both in one of the Reclaim queues, and succeeds the passed in
   // validator, which takes a fbl::RefPtr<VmCowPages>.
   template <typename F>
diff --git a/zircon/kernel/vm/include/vm/pmm.h b/zircon/kernel/vm/include/vm/pmm.h
index f87d955..ea2c1b9 100644
--- a/zircon/kernel/vm/include/vm/pmm.h
+++ b/zircon/kernel/vm/include/vm/pmm.h
@@ -61,9 +61,9 @@
 #define PMM_ALLOC_FLAG_CAN_WAIT (1 << 1)
 // The default (flag not set) is to not allocate a loaned page, so that we don't end up with loaned
 // pages allocated for arbitrary purposes that prevent us from getting the loaned page back quickly.
-#define PMM_ALLOC_FLAG_CAN_BORROW (1 << 2)
-// Require a loaned page, and fail to allocate if a loaned page isn't available.
-#define PMM_ALLOC_FLAG_MUST_BORROW (1 << 3)
+// This flag switches to requiring a loaned page, and will fail if a loaned page isn't available,
+// even if there are other free pages available.
+#define PMM_ALLOC_FLAG_LOANED (1 << 2)
 
 // Allocate count pages of physical memory, adding to the tail of the passed list.
 // The list must be initialized.
diff --git a/zircon/kernel/vm/include/vm/vm_cow_pages.h b/zircon/kernel/vm/include/vm/vm_cow_pages.h
index 43bf96b..9f3bffd 100644
--- a/zircon/kernel/vm/include/vm/vm_cow_pages.h
+++ b/zircon/kernel/vm/include/vm/vm_cow_pages.h
@@ -989,11 +989,6 @@
   // Places a newly added, not yet pinned, page into the appropriate page queue.
   void SetNotPinnedLocked(vm_page_t* page, uint64_t offset) TA_REQ(lock());
 
-  // Updates any meta data for accessing a page. Currently this moves pager backed pages around in
-  // the page queue to track which ones were recently accessed for the purposes of eviction. In
-  // terms of functional correctness this never has to be called.
-  void UpdateOnAccessLocked(vm_page_t* page, uint pf_flags) TA_REQ(lock());
-
   // Updates the page's dirty state to the one specified, and also moves the page between page
   // queues if required by the dirty state. |dirty_state| should be a valid dirty tracking state,
   // i.e. one of Clean, AwaitingClean, or Dirty.
@@ -1590,7 +1585,7 @@
   // updating. Increments the cursor.
   __ALWAYS_INLINE RequireResult CursorAsResult() TA_REQ(lock()) {
     if (mark_accessed_) {
-      owner()->UpdateOnAccessLocked(owner_cursor_->Page(), 0);
+      pmm_page_queues()->MarkAccessed(owner_cursor_->Page());
     }
     // Inform PageAsResult whether the owner_ is the target_, but otherwise let it calculate the
     // actual writability of the page.
diff --git a/zircon/kernel/vm/page_queues.cc b/zircon/kernel/vm/page_queues.cc
index 28e65b4..5773cff 100644
--- a/zircon/kernel/vm/page_queues.cc
+++ b/zircon/kernel/vm/page_queues.cc
@@ -909,16 +909,17 @@
   MaybeTriggerAgingLocked(dps);
 }
 
-void PageQueues::MarkAccessed(vm_page_t* page) {
+void PageQueues::MarkAccessedContinued(vm_page_t* page) {
+  // Although we can get called with the zero page, it would not be in a reclaimable queue and so
+  // we should have returned in the MarkAccessed wrapper.
+  DEBUG_ASSERT(page != vm_get_zero_page());
+
   pq_accessed_normal.Add(1);
-  DeferPendingSignals dps{*this};
-  Guard<SpinLock, IrqSave> guard{&lock_};
 
   auto queue_ref = page->object.get_page_queue_ref();
 
-  // The page can be the zero page, but in that case we'll return early below.
-  DEBUG_ASSERT(page != vm_get_zero_page() ||
-               queue_ref.load(ktl::memory_order_relaxed) < PageQueueReclaimDontNeed);
+  DeferPendingSignals dps{*this};
+  Guard<SpinLock, IrqSave> guard{&lock_};
 
   // We need to check the current queue to see if it is in the reclaimable range. Between checking
   // this and updating the queue it could change, however it would only change as a result of
diff --git a/zircon/kernel/vm/pmm_arena.h b/zircon/kernel/vm/pmm_arena.h
index e430aee..1f5a1e1 100644
--- a/zircon/kernel/vm/pmm_arena.h
+++ b/zircon/kernel/vm/pmm_arena.h
@@ -10,13 +10,12 @@
 #include <trace.h>
 #include <zircon/types.h>
 
-#include <fbl/intrusive_double_list.h>
 #include <fbl/macros.h>
 #include <vm/pmm.h>
 
 class PmmNode;
 
-class PmmArena : public fbl::DoublyLinkedListable<PmmArena*> {
+class PmmArena {
  public:
   constexpr PmmArena() = default;
   ~PmmArena() = default;
diff --git a/zircon/kernel/vm/pmm_node.cc b/zircon/kernel/vm/pmm_node.cc
index 2a0d73b..31dfb5d 100644
--- a/zircon/kernel/vm/pmm_node.cc
+++ b/zircon/kernel/vm/pmm_node.cc
@@ -22,7 +22,6 @@
 #include <kernel/mp.h>
 #include <kernel/thread.h>
 #include <pretty/cpp/sizes.h>
-#include <vm/bootalloc.h>
 #include <vm/physmap.h>
 #include <vm/pmm.h>
 #include <vm/pmm_checker.h>
@@ -77,45 +76,31 @@
   DEBUG_ASSERT(IS_PAGE_ALIGNED(info->size));
   DEBUG_ASSERT(info->size > 0);
 
-  // allocate a c++ arena object
-  PmmArena* arena = new (boot_alloc_mem(sizeof(PmmArena))) PmmArena();
+  // Allocate an arena object out of the array inside PmmNode
+  if (used_arena_count_ >= kArenaCount) {
+    printf("PMM: pmm_add_arena failed to allocate arena\n");
+    return ZX_ERR_NO_MEMORY;
+  }
+  PmmArena* arena = &arenas_[used_arena_count_++];
 
-  // initialize the object
+  // Initialize the object.
   auto status = arena->Init(info, this);
   if (status != ZX_OK) {
-    // leaks boot allocator memory
-    arena->~PmmArena();
+    used_arena_count_--;
     printf("PMM: pmm_add_arena failed to initialize arena\n");
     return status;
   }
 
-  // walk the arena list, inserting in ascending order of arena base address
-  for (auto& a : arena_list_) {
-    if (a.base() > arena->base()) {
-      arena_list_.insert(a, arena);
-      goto done_add;
-    }
-  }
-
-  // walked off the end, add it to the end of the list
-  arena_list_.push_back(arena);
-
-done_add:
   arena_cumulative_size_ += info->size;
 
   return ZX_OK;
 }
 
-size_t PmmNode::NumArenas() const {
-  Guard<Mutex> guard{&lock_};
-  return arena_list_.size();
-}
-
 zx_status_t PmmNode::GetArenaInfo(size_t count, uint64_t i, pmm_arena_info_t* buffer,
                                   size_t buffer_size) {
   Guard<Mutex> guard{&lock_};
 
-  if ((count == 0) || (count + i > arena_list_.size()) || (i >= arena_list_.size())) {
+  if ((count == 0) || (count + i > active_arenas().size()) || (i >= active_arenas().size())) {
     return ZX_ERR_OUT_OF_RANGE;
   }
   const size_t size_required = count * sizeof(pmm_arena_info_t);
@@ -124,7 +109,7 @@
   }
 
   // Skip the first |i| elements.
-  auto iter = arena_list_.begin();
+  auto iter = active_arenas().begin();
   for (uint64_t j = 0; j < i; j++) {
     iter++;
   }
@@ -267,15 +252,11 @@
     Guard<Mutex> guard{&lock_};
     free_list_had_fill_pattern = all_free_pages_filled_;
 
-    // If the caller sets PMM_ALLOC_FLAG_MUST_BORROW, the caller must also set
-    // PMM_ALLOC_FLAG_CAN_BORROW, and must not set PMM_ALLOC_FLAG_CAN_WAIT.
+    // The PMM_ALLOC_FLAG_LOANED flag is not compatible with PMM_ALLOC_FLAG_CAN_WAIT
     DEBUG_ASSERT(
-        !(alloc_flags & PMM_ALLOC_FLAG_MUST_BORROW) ||
-        ((alloc_flags & PMM_ALLOC_FLAG_CAN_BORROW) && !((alloc_flags & PMM_ALLOC_FLAG_CAN_WAIT))));
-    const bool can_borrow = pmm_physical_page_borrowing_config()->is_any_borrowing_enabled() &&
-                            !!(alloc_flags & PMM_ALLOC_FLAG_CAN_BORROW);
-    const bool must_borrow = can_borrow && !!(alloc_flags & PMM_ALLOC_FLAG_MUST_BORROW);
-    const bool use_loaned_list = can_borrow && (!list_is_empty(&free_loaned_list_) || must_borrow);
+        !((alloc_flags & PMM_ALLOC_FLAG_LOANED) && (alloc_flags & PMM_ALLOC_FLAG_CAN_WAIT)));
+    const bool use_loaned_list = pmm_physical_page_borrowing_config()->is_any_borrowing_enabled() &&
+                                 (alloc_flags & PMM_ALLOC_FLAG_LOANED);
     list_node* const which_list = use_loaned_list ? &free_loaned_list_ : &free_list_;
 
     // Note that we do not care if the allocation is happening from the loaned list or not since if
@@ -289,14 +270,14 @@
 
     page = list_remove_head_type(which_list, vm_page, queue_node);
     if (!page) {
-      if (!must_borrow) {
+      if (!use_loaned_list) {
         // Allocation failures from the regular free list are likely to become user-visible.
         ReportAllocFailureLocked();
       }
       return ZX_ERR_NO_MEMORY;
     }
 
-    DEBUG_ASSERT(can_borrow || !page->is_loaned());
+    DEBUG_ASSERT(use_loaned_list || !page->is_loaned());
     AllocPageHelperLocked(page);
 
     if (use_loaned_list) {
@@ -339,15 +320,6 @@
     return status;
   }
 
-  // If the caller sets PMM_ALLOC_FLAG_MUST_BORROW, the caller must also set
-  // PMM_ALLOC_FLAG_CAN_BORROW, and must not set PMM_ALLOC_FLAG_CAN_WAIT.
-  DEBUG_ASSERT(
-      !(alloc_flags & PMM_ALLOC_FLAG_MUST_BORROW) ||
-      ((alloc_flags & PMM_ALLOC_FLAG_CAN_BORROW) && !((alloc_flags & PMM_ALLOC_FLAG_CAN_WAIT))));
-  const bool can_borrow = pmm_physical_page_borrowing_config()->is_any_borrowing_enabled() &&
-                          !!(alloc_flags & PMM_ALLOC_FLAG_CAN_BORROW);
-  const bool must_borrow = can_borrow && !!(alloc_flags & PMM_ALLOC_FLAG_MUST_BORROW);
-
   bool free_list_had_fill_pattern = false;
 
   {
@@ -355,88 +327,61 @@
     Guard<Mutex> guard{&lock_};
     free_list_had_fill_pattern = all_free_pages_filled_;
 
-    uint64_t free_count;
-    if (must_borrow) {
-      free_count = 0;
-    } else {
-      free_count = free_count_.load(ktl::memory_order_relaxed);
-    }
-    uint64_t available_count = free_count;
-    uint64_t free_loaned_count = 0;
-    if (can_borrow) {
-      free_loaned_count = free_loaned_count_.load(ktl::memory_order_relaxed);
-      available_count += free_loaned_count;
-    }
+    // The PMM_ALLOC_FLAG_LOANED flag is not compatible with PMM_ALLOC_FLAG_CAN_WAIT
+    DEBUG_ASSERT(
+        !((alloc_flags & PMM_ALLOC_FLAG_LOANED) && (alloc_flags & PMM_ALLOC_FLAG_CAN_WAIT)));
+    const bool use_loaned_list = pmm_physical_page_borrowing_config()->is_any_borrowing_enabled() &&
+                                 (alloc_flags & PMM_ALLOC_FLAG_LOANED);
+    list_node* const which_list = use_loaned_list ? &free_loaned_list_ : &free_list_;
+    uint64_t free_count = use_loaned_list ? free_loaned_count_.load(ktl::memory_order_relaxed)
+                                          : free_count_.load(ktl::memory_order_relaxed);
 
-    if (unlikely(count > available_count)) {
+    if (unlikely(count > free_count)) {
       if ((alloc_flags & PMM_ALLOC_FLAG_CAN_WAIT) && !never_return_should_wait_) {
         pmm_alloc_delayed.Add(1);
         return ZX_ERR_SHOULD_WAIT;
       }
-      if (!must_borrow) {
+      if (!use_loaned_list) {
         // Allocation failures from the regular free list are likely to become user-visible.
         ReportAllocFailureLocked();
       }
       return ZX_ERR_NO_MEMORY;
     }
-    // Prefer to allocate from loaned, if allowed by this allocation.  If loaned is not allowed by
-    // this allocation, free_loaned_count will be zero here.
-    DEBUG_ASSERT(can_borrow || !free_loaned_count);
-    DEBUG_ASSERT(!must_borrow || !free_count);
-    uint64_t from_loaned_free = ktl::min(count, free_loaned_count);
-    uint64_t from_free = count - from_loaned_free;
 
-    DecrementFreeCountLocked(from_free);
+    // For simplicity of oom state detection we decrement the free count and then check for whether
+    // we should wait or not. The error case is unlikely, and hence not performance critical, so
+    // having to redundantly re-increment is not a big deal.
+    if (use_loaned_list) {
+      DecrementFreeLoanedCountLocked(count);
+    } else {
+      DecrementFreeCountLocked(count);
+    }
 
-    // For simplicity of oom state detection we do this check after decrementing the free count,
-    // since the error case is unlikely and not performance critical. Even if no pages are being
-    // requested from the regular free list (if loaned pages can be used) we still fail in the oom
-    // state since we would prefer those loaned pages to be used to fulfill allocations that cannot
-    // be delayed.
     if ((alloc_flags & PMM_ALLOC_FLAG_CAN_WAIT) && InOomStateLocked() &&
         !never_return_should_wait_) {
-      IncrementFreeCountLocked(from_free);
+      // Loaned allocations do not support waiting, so we never have to undo the loaned count.
+      DEBUG_ASSERT(!use_loaned_list);
+      IncrementFreeCountLocked(count);
       pmm_alloc_delayed.Add(1);
       return ZX_ERR_SHOULD_WAIT;
     }
 
-    DecrementFreeLoanedCountLocked(from_loaned_free);
+    auto node = which_list;
+    while (count > 0) {
+      node = list_next(which_list, node);
+      DEBUG_ASSERT(use_loaned_list || !containerof(node, vm_page, queue_node)->is_loaned());
+      AllocPageHelperLocked(containerof(node, vm_page, queue_node));
+      --count;
+    }
 
-    do {
-      DEBUG_ASSERT(count == from_loaned_free + from_free);
-      list_node* which_list;
-      size_t which_count;
-      if (can_borrow && !list_is_empty(&free_loaned_list_)) {
-        which_list = &free_loaned_list_;
-        which_count = from_loaned_free;
-        from_loaned_free = 0;
-      } else {
-        DEBUG_ASSERT(!must_borrow);
-        which_list = &free_list_;
-        which_count = from_free;
-        from_free = 0;
-      }
-      count -= which_count;
-
-      DEBUG_ASSERT(which_count > 0);
-      auto node = which_list;
-      while (which_count > 0) {
-        node = list_next(which_list, node);
-        DEBUG_ASSERT(can_borrow || !containerof(node, vm_page, queue_node)->is_loaned());
-        AllocPageHelperLocked(containerof(node, vm_page, queue_node));
-        --which_count;
-      }
-
-      list_node tmp_list = LIST_INITIAL_VALUE(tmp_list);
-      list_split_after(which_list, node, &tmp_list);
-      if (list_is_empty(list)) {
-        list_move(which_list, list);
-      } else {
-        list_splice_after(which_list, list_peek_tail(list));
-      }
-      list_move(&tmp_list, which_list);
-      DEBUG_ASSERT(count == from_loaned_free + from_free);
-    } while (count > 0);
+    list_node tmp_list = LIST_INITIAL_VALUE(tmp_list);
+    list_split_after(which_list, node, &tmp_list);
+    if (list_is_empty(list)) {
+      list_move(which_list, list);
+    } else {
+      list_splice_after(which_list, list_peek_tail(list));
+    }
+    list_move(&tmp_list, which_list);
   }
 
   if (free_list_had_fill_pattern) {
@@ -474,7 +419,7 @@
     free_list_had_fill_pattern = all_free_pages_filled_;
 
     // walk through the arenas, looking to see if the physical page belongs to it
-    for (auto& a : arena_list_) {
+    for (auto& a : active_arenas()) {
       for (; allocated < count && a.address_in_arena(address); address += PAGE_SIZE) {
         vm_page_t* page = a.FindSpecific(address);
         if (!page) {
@@ -539,8 +484,7 @@
     alignment_log2 = PAGE_SIZE_SHIFT;
   }
 
-  DEBUG_ASSERT(!(alloc_flags & (PMM_ALLOC_FLAG_CAN_BORROW | PMM_ALLOC_FLAG_MUST_BORROW |
-                                PMM_ALLOC_FLAG_CAN_WAIT)));
+  DEBUG_ASSERT(!(alloc_flags & (PMM_ALLOC_FLAG_LOANED | PMM_ALLOC_FLAG_CAN_WAIT)));
   // pa and list must be valid pointers
   DEBUG_ASSERT(pa);
   DEBUG_ASSERT(list);
@@ -548,7 +492,7 @@
   AutoPreemptDisabler preempt_disable;
   Guard<Mutex> guard{&lock_};
 
-  for (auto& a : arena_list_) {
+  for (auto& a : active_arenas()) {
     // FindFreeContiguous will search the arena for FREE pages. As we hold lock_, any pages in the
     // FREE state are assumed to be owned by us, and would only be modified if lock_ were held.
     vm_page_t* p = a.FindFreeContiguous(count, alignment_log2);
@@ -789,7 +733,7 @@
         "%zu\n",
         this, free_count, free_count * PAGE_SIZE, free_loaned_count, free_loaned_count * PAGE_SIZE,
         arena_cumulative_size_);
-    for (auto& a : arena_list_) {
+    for (const auto& a : active_arenas()) {
       a.Dump(false, false);
     }
   };
@@ -1107,7 +1051,7 @@
   // pmm_node.
   DEBUG_ASSERT(mp_get_active_mask() != 0);
 
-  if (unlikely(arena_list_.is_empty())) {
+  if (unlikely(active_arenas().empty())) {
     // We're in a unit test, using ManagedPmmNode which has no arenas.  So fall back to the global
     // pmm_node (which has at least one arena) to find the actual vm_page_t for each page.
     //
@@ -1121,11 +1065,11 @@
     return;
   }
 
-  // We have at least one arena, so use arena_list_ directly.
+  // We have at least one arena, so use active_arenas() directly.
   paddr_t end = start + count * PAGE_SIZE;
   DEBUG_ASSERT(start <= end);
   paddr_t page_addr = start;
-  for (auto& a : arena_list_) {
+  for (auto& a : active_arenas()) {
     for (; page_addr < end && a.address_in_arena(page_addr); page_addr += PAGE_SIZE) {
       vm_page_t* page = a.FindSpecific(page_addr);
       DEBUG_ASSERT(page);
diff --git a/zircon/kernel/vm/pmm_node.h b/zircon/kernel/vm/pmm_node.h
index ceefeb8..e5a96b1 100644
--- a/zircon/kernel/vm/pmm_node.h
+++ b/zircon/kernel/vm/pmm_node.h
@@ -11,6 +11,7 @@
 #include <kernel/event.h>
 #include <kernel/lockdep.h>
 #include <kernel/mutex.h>
+#include <ktl/span.h>
 #include <vm/compression.h>
 #include <vm/loan_sweeper.h>
 #include <vm/physical_page_borrowing_config.h>
@@ -81,8 +82,11 @@
 
   zx_status_t AddArena(const pmm_arena_info_t* info);
 
-  // Returns the number of arenas.
-  size_t NumArenas() const;
+  // Returns the number of active arenas.
+  size_t NumArenas() const {
+    Guard<Mutex> guard{&lock_};
+    return active_arenas().size();
+  }
 
   // Copies |count| pmm_arena_info_t objects into |buffer| starting with the |i|-th arena ordered by
   // base address.  For example, passing an |i| of 1 would skip the 1st arena.
@@ -224,8 +228,6 @@
   ktl::atomic<uint64_t> loaned_count_ TA_GUARDED(lock_) = 0;
   ktl::atomic<uint64_t> loan_cancelled_count_ TA_GUARDED(lock_) = 0;
 
-  fbl::SizedDoublyLinkedList<PmmArena*> arena_list_ TA_GUARDED(lock_);
-
   // Free pages where !loaned.
   list_node free_list_ TA_GUARDED(lock_) = LIST_INITIAL_VALUE(free_list_);
   // Free pages where loaned && !loan_cancelled.
@@ -287,12 +289,27 @@
   // The rng state for random waiting on allocations. This allows us to use rand_r, which requires
   // no further thread synchronization, unlike rand().
   uintptr_t random_should_wait_seed_ TA_GUARDED(lock_) = 0;
+
+  // Arenas are allocated from the node itself to avoid any boot allocations. Walking linearly
+  // through them at run time should also be fairly efficient.
+  static const size_t kArenaCount = 16;
+  size_t used_arena_count_ TA_GUARDED(lock_) = 0;
+  PmmArena arenas_[kArenaCount] TA_GUARDED(lock_);
+
+  // Return the span of arenas from the built-in array that are known to be active. Used in loops
+  // that iterate across all arenas.
+  ktl::span<PmmArena> active_arenas() TA_REQ(lock_) {
+    return ktl::span<PmmArena>(arenas_, used_arena_count_);
+  }
+  ktl::span<const PmmArena> active_arenas() const TA_REQ(lock_) {
+    return ktl::span<const PmmArena>(arenas_, used_arena_count_);
+  }
 };
 
 // We don't need to hold the arena lock while executing this, since it is
 // only accesses values that are set once during system initialization.
 inline vm_page_t* PmmNode::PaddrToPage(paddr_t addr) TA_NO_THREAD_SAFETY_ANALYSIS {
-  for (auto& a : arena_list_) {
+  for (auto& a : active_arenas()) {
     if (a.address_in_arena(addr)) {
       size_t index = (addr - a.base()) / PAGE_SIZE;
       return a.get_page(index);
diff --git a/zircon/kernel/vm/scanner.cc b/zircon/kernel/vm/scanner.cc
index f0fe3fe..e58d633 100644
--- a/zircon/kernel/vm/scanner.cc
+++ b/zircon/kernel/vm/scanner.cc
@@ -391,10 +391,11 @@
   pmm_page_queues()->SetActiveRatioMultiplier(gBootOptions->page_scanner_active_ratio_multiplier);
   pmm_page_queues()->StartThreads(ZX_SEC(gBootOptions->page_scanner_min_aging_interval),
                                   ZX_SEC(gBootOptions->page_scanner_max_aging_interval));
-  // Set the access scan to 1 second over the min page scanning interval. This both ensures that the
-  // access scan period is never 0, and always gives the page scanner a chance to trigger harvesting
-  // first if it is rapidly aging.
-  accessed_scan_period = ZX_SEC(gBootOptions->page_scanner_min_aging_interval + 1u);
+  // Set the access scan to at least 1 second over the min page scanning interval. This both ensures
+  // that the access scan period is never 0 and that redundant scanning before the page queues can
+  // age does not occur.
+  accessed_scan_period = ZX_SEC(ktl::max(gBootOptions->page_scanner_min_aging_interval + 1u,
+                                         gBootOptions->page_scanner_accessed_scan_interval));
 
   if (fbl::RefPtr<VmCompression> compression = VmCompression::CreateDefault()) {
     zx_status_t status = pmm_set_page_compression(ktl::move(compression));
diff --git a/zircon/kernel/vm/unittests/pmm_unittest.cc b/zircon/kernel/vm/unittests/pmm_unittest.cc
index 265ac98..b6a8ea1 100644
--- a/zircon/kernel/vm/unittests/pmm_unittest.cc
+++ b/zircon/kernel/vm/unittests/pmm_unittest.cc
@@ -190,9 +190,8 @@
   EXPECT_EQ(0u, node.node().CountLoanedNotFreePages());
 
   EXPECT_EQ(0u, list_length(&list));
-  status = node.node().AllocPages(kLoanCount,
-                                  PMM_ALLOC_FLAG_MUST_BORROW | PMM_ALLOC_FLAG_CAN_BORROW, &list);
-  EXPECT_EQ(ZX_OK, status, "pmm_alloc_pages PMM_ALLOC_FLAG_MUST_BORROW");
+  status = node.node().AllocPages(kLoanCount, PMM_ALLOC_FLAG_LOANED, &list);
+  EXPECT_EQ(ZX_OK, status, "pmm_alloc_pages PMM_ALLOC_FLAG_LOANED");
   EXPECT_EQ(kLoanCount, list_length(&list));
 
   list_for_every_entry (&list, page, vm_page_t, queue_node) {
@@ -229,11 +228,11 @@
   EXPECT_EQ(kLoanCount, node.node().CountLoanedNotFreePages());
 
   EXPECT_EQ(0u, list_length(&list));
-  status = node.node().AllocPages(kNotLoanCount + 1, PMM_ALLOC_FLAG_CAN_BORROW, &list);
+  status = node.node().AllocPages(kNotLoanCount + 1, PMM_ALLOC_FLAG_LOANED, &list);
   EXPECT_EQ(ZX_ERR_NO_MEMORY, status, "try to allocate a loan_cancelled page");
 
   EXPECT_EQ(0u, list_length(&list));
-  status = node.node().AllocPages(kNotLoanCount, PMM_ALLOC_FLAG_CAN_BORROW, &list);
+  status = node.node().AllocPages(kNotLoanCount, PMM_ALLOC_FLAG_ANY, &list);
   EXPECT_EQ(ZX_OK, status, "allocate all the not-loaned pages");
 
   list_for_every_entry (&list, page, vm_page_t, queue_node) {
@@ -358,8 +357,7 @@
   node.node().BeginLoan(&list);
 
   EXPECT_EQ(0u, list_length(&list));
-  status = node.node().AllocPages(kLoanCount,
-                                  PMM_ALLOC_FLAG_MUST_BORROW | PMM_ALLOC_FLAG_CAN_BORROW, &list);
+  status = node.node().AllocPages(kLoanCount, PMM_ALLOC_FLAG_LOANED, &list);
   EXPECT_EQ(ZX_OK, status, "allocate kLoanCount pages");
   EXPECT_EQ(kLoanCount, list_length(&list));
 
diff --git a/zircon/kernel/vm/vm_cow_pages.cc b/zircon/kernel/vm/vm_cow_pages.cc
index d435006..be8b44f 100644
--- a/zircon/kernel/vm/vm_cow_pages.cc
+++ b/zircon/kernel/vm/vm_cow_pages.cc
@@ -314,7 +314,7 @@
       page_source_(ktl::move(page_source)),
       discardable_tracker_(ktl::move(discardable_tracker)) {
   DEBUG_ASSERT(IS_PAGE_ALIGNED(size));
-  DEBUG_ASSERT(!(pmm_alloc_flags & PMM_ALLOC_FLAG_CAN_BORROW));
+  DEBUG_ASSERT(!(pmm_alloc_flags & PMM_ALLOC_FLAG_LOANED));
 }
 
 void VmCowPages::TransitionToAliveLocked() {
@@ -2311,7 +2311,7 @@
           // until the pager has a chance to respond to the DIRTY request.
           if (is_page_clean(page)) {
             AssertHeld(lock_ref());
-            UpdateOnAccessLocked(page, VMM_PF_FLAG_SW_FAULT);
+            pmm_page_queues()->MarkAccessed(page);
           }
         } else if (p->IsIntervalZero()) {
           if (p->IsIntervalStart() || p->IsIntervalSlot()) {
@@ -2397,25 +2397,6 @@
   return status;
 }
 
-void VmCowPages::UpdateOnAccessLocked(vm_page_t* page, uint pf_flags) {
-  PageQueues* pq = pmm_page_queues();
-  // We only care about updating on access if we can reclaim pages, which if reclamation is limited
-  // to pager backed can be skipped if eviction isn't possible.
-  if (pq->ReclaimIsOnlyPagerBacked() && !can_evict()) {
-    return;
-  }
-
-  // Don't make the page accessed for hardware faults. These accesses, if any actually end up
-  // happening, will be detected by the accessed bits in the page tables.
-  // For non hardware faults, the kernel might use the page directly through the physmap, which will
-  // not cause accessed information to be updated and so we consider it accessed at this point.
-  if (pf_flags & VMM_PF_FLAG_HW_FAULT) {
-    return;
-  }
-
-  pq->MarkAccessed(page);
-}
-
 inline VmCowPages::LookupCursor::RequireResult VmCowPages::LookupCursor::PageAsResultNoIncrement(
     vm_page_t* page, bool in_target) {
   // The page is writable if it's present in the target (non owned pages are never writable) and it
@@ -2470,9 +2451,9 @@
 zx::result<VmCowPages::LookupCursor::RequireResult>
 VmCowPages::LookupCursor::TargetAllocateCopyPageAsResult(vm_page_t* source, DirtyState dirty_state,
                                                          LazyPageRequest* page_request) {
-  // The general pmm_alloc_flags_ are not allowed to contain the BORROW option, and this is relied
+  // The general pmm_alloc_flags_ are not allowed to contain the LOANED option, and this is relied
   // upon below to assume the page allocated cannot be loaned.
-  DEBUG_ASSERT(!(target_->pmm_alloc_flags_ & PMM_ALLOC_FLAG_CAN_BORROW));
+  DEBUG_ASSERT(!(target_->pmm_alloc_flags_ & PMM_ALLOC_FLAG_LOANED));
 
   vm_page_t* out_page = nullptr;
   zx_status_t status = AllocateCopyPage(target_->pmm_alloc_flags_, source->paddr(), alloc_list_,
@@ -2659,7 +2640,7 @@
   vm_page_t* page = CursorIsUsablePage(will_write) ? owner_cursor_->Page() : nullptr;
 
   if (page && mark_accessed_) {
-    owner()->UpdateOnAccessLocked(page, 0);
+    pmm_page_queues()->MarkAccessed(page);
   }
 
   IncrementCursor();
@@ -2806,7 +2787,7 @@
     // Although we are not returning the page, the act of forking counts as an access, and this is
     // an access regardless of whether the final returned page should be considered accessed, so
     // ignore the mark_accessed_ check here.
-    owner()->UpdateOnAccessLocked(owner_cursor_->Page(), 0);
+    pmm_page_queues()->MarkAccessed(owner_cursor_->Page());
     if (!owner()->is_hidden_locked()) {
       // Directly copying the page from the owner into the target.
       return TargetAllocateCopyPageAsResult(owner_cursor_->Page(), DirtyState::Untracked,
@@ -5152,7 +5133,7 @@
       // CAN_WAIT flag cannot be combined and so we remove it if it exists.
       uint32_t pmm_alloc_flags = pmm_alloc_flags_;
       pmm_alloc_flags &= ~PMM_ALLOC_FLAG_CAN_WAIT;
-      pmm_alloc_flags |= PMM_ALLOC_FLAG_MUST_BORROW | PMM_ALLOC_FLAG_CAN_BORROW;
+      pmm_alloc_flags |= PMM_ALLOC_FLAG_LOANED;
       vm_page_t* new_page;
       zx_status_t alloc_status = pmm_alloc_page(pmm_alloc_flags, &new_page);
       // If we got a loaned page, replace the page in src_page, else just continue with src_page
@@ -6122,7 +6103,7 @@
     // usage. A possible approach might involve moving to a separate queue when we skip the page for
     // eviction. Pages move out of said queue when accessed, and continue aging as other pages.
     // Pages in the queue are considered for eviction pre-OOM, but ignored otherwise.
-    UpdateOnAccessLocked(page, VMM_PF_FLAG_SW_FAULT);
+    pmm_page_queues()->MarkAccessed(page);
     vm_vmo_always_need_skipped_reclaim.Add(1);
     return false;
   }
@@ -6159,7 +6140,7 @@
         ZX_CACHE_POLICY_CACHED) {
       // Cannot compress uncached mappings. To avoid this page remaining in the reclamation list we
       // simulate an access.
-      UpdateOnAccessLocked(page, VMM_PF_FLAG_SW_FAULT);
+      pmm_page_queues()->MarkAccessed(page);
       return false;
     }
   }
@@ -6286,7 +6267,7 @@
   if (high_priority_count_ != 0) {
     // Not allowed to reclaim. To avoid this page remaining in a reclamation list we simulate an
     // access.
-    UpdateOnAccessLocked(page, VMM_PF_FLAG_SW_FAULT);
+    pmm_page_queues()->MarkAccessed(page);
     return false;
   }
 
@@ -6299,7 +6280,7 @@
   // No other reclamation strategies, so to avoid this page remaining in a reclamation list we
   // simulate an access. Do not want to place it in the ReclaimFailed queue since our failure was
   // not based on page contents.
-  UpdateOnAccessLocked(page, VMM_PF_FLAG_SW_FAULT);
+  pmm_page_queues()->MarkAccessed(page);
   // Keep a count as having no reclamation strategy is probably a sign of miss-configuration.
   vm_vmo_no_reclamation_strategy.Add(1);
   return false;
@@ -6451,9 +6432,9 @@
     // Loaned page allocations will always precisely succeed or fail and the CAN_WAIT flag cannot be
     // combined and so we remove it if it exists.
     pmm_alloc_flags &= ~PMM_ALLOC_FLAG_CAN_WAIT;
-    pmm_alloc_flags |= PMM_ALLOC_FLAG_CAN_BORROW | PMM_ALLOC_FLAG_MUST_BORROW;
+    pmm_alloc_flags |= PMM_ALLOC_FLAG_LOANED;
   } else {
-    pmm_alloc_flags &= ~PMM_ALLOC_FLAG_CAN_BORROW;
+    pmm_alloc_flags &= ~PMM_ALLOC_FLAG_LOANED;
   }
 
   // We stack-own a loaned page from pmm_alloc_page() to SwapPageLocked() OR from SwapPageLocked()
diff --git a/zircon/public/sysroot/sdk/BUILD.gn b/zircon/public/sysroot/sdk/BUILD.gn
index 59972f3..718ce3f8 100644
--- a/zircon/public/sysroot/sdk/BUILD.gn
+++ b/zircon/public/sysroot/sdk/BUILD.gn
@@ -124,7 +124,7 @@
       "libc.ifs",
       "zircon.ifs",
     ]
-    if (override_target_api_level == -1) {
+    if (override_target_api_level == "PLATFORM") {
       versions = {
         if (target_cpu == "arm64") {
           arm64 = version_content
@@ -179,7 +179,7 @@
     "--manifest=" + rebase_path(outputs[1], root_build_dir),
     "--depfile=" + rebase_path(depfile, root_build_dir),
   ]
-  if (override_target_api_level == -1) {
+  if (override_target_api_level == "PLATFORM") {
     args += [ "--location=/versions/$target_cpu/debug_libs" ]
   }
   deps = [ ":sysroot-meta-json" ] + sysroot_sdk_deps
diff --git a/zircon/public/sysroot/sdk/sysroot.api b/zircon/public/sysroot/sdk/sysroot.api
index 00d1331..3200c70 100644
--- a/zircon/public/sysroot/sdk/sysroot.api
+++ b/zircon/public/sysroot/sdk/sysroot.api
@@ -155,13 +155,13 @@
   "include/zircon/assert.h": "ea975b9e0a60a5bb0a546b0b26caea9d",
   "include/zircon/availability.h": "22ec8dd7ea4b5498883887060097ae89",
   "include/zircon/boot/crash-reason.h": "8bc53e5d654937ec3c2f0473640b3963",
-  "include/zircon/compiler.h": "5eb589aa84a72b3b352c12a407e59de5",
+  "include/zircon/compiler.h": "1402ccd28a20a70b434cff669a8e9d3d",
   "include/zircon/device/audio.h": "17f5fd6a7240b8d11e7791b440237059",
   "include/zircon/dlfcn.h": "28285c191e9a046125a2065cb482d6ec",
   "include/zircon/errors.h": "2cedd2f5229af61131f107330cbd3181",
   "include/zircon/exception.h": "425c558088583172dc860b894ac6ea0a",
   "include/zircon/features.h": "e11068f50324e55d6e7f0e4ec00f4db9",
-  "include/zircon/fidl.h": "590372a4ca0a056cf9d9be82323f0c98",
+  "include/zircon/fidl.h": "94a76da7a8ef4f48f948e0ba395f3b4d",
   "include/zircon/hw/debug/arm64.h": "da4c4dad07e5bbe4f6b09a6aa0b0ec70",
   "include/zircon/hw/debug/x86.h": "650133fd836a6ca92b979be57a46fc28",
   "include/zircon/hw/gpt.h": "8bb129c95f49edd90ff2205a0c1e3d7e",
diff --git a/zircon/system/public/zircon/compiler.h b/zircon/system/public/zircon/compiler.h
index 6d29c18..a34dafb 100644
--- a/zircon/system/public/zircon/compiler.h
+++ b/zircon/system/public/zircon/compiler.h
@@ -278,13 +278,6 @@
 // Get the offset of `field` from the beginning of the struct or class `type`.
 #define __offsetof(type, field) __builtin_offsetof(type, field)
 
-// Return the number of elements in the given C-style array.
-//
-// TODO: add type check
-#if !defined(countof) && !defined(__cplusplus)
-#define countof(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
 // Perform an arithmetic operation, returning "true" if the operation overflowed.
 //
 // Equivalent to: { *result = a + b; return _overflow_occurred; }
diff --git a/zircon/system/public/zircon/fidl.h b/zircon/system/public/zircon/fidl.h
index b3f9824a..7116bac 100644
--- a/zircon/system/public/zircon/fidl.h
+++ b/zircon/system/public/zircon/fidl.h
@@ -54,10 +54,8 @@
 #define FIDL_ALLOC_ABSENT ((uintptr_t)0)
 
 // Out of line allocations are all 8 byte aligned.
-// TODO(https://fxbug.dev/42119024): Remove either this FIDL_ALIGN macro or the FidlAlign function in
-// fidl/internal.h.
 #define FIDL_ALIGNMENT ((size_t)8)
-#define FIDL_ALIGN(a) (((a) + 7u) & ~7u)
+#define FIDL_ALIGN(a) (((a) + 7ull) & ~7ull)
 #define FIDL_ALIGNDECL alignas(FIDL_ALIGNMENT)
 
 // The maximum depth of out-of-line objects in the wire format.
diff --git a/zircon/system/ulib/async-default/BUILD.gn b/zircon/system/ulib/async-default/BUILD.gn
index be94a21..cf9046d05 100644
--- a/zircon/system/ulib/async-default/BUILD.gn
+++ b/zircon/system/ulib/async-default/BUILD.gn
@@ -8,7 +8,7 @@
 
 zx_library("async-default") {
   sdk = "shared"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [ "lib/async/default.h" ]
   sources = [ "default.c" ]
   public_deps = [
diff --git a/zircon/system/ulib/async-loop/BUILD.gn b/zircon/system/ulib/async-loop/BUILD.gn
index 6829667..c89fb2b4 100644
--- a/zircon/system/ulib/async-loop/BUILD.gn
+++ b/zircon/system/ulib/async-loop/BUILD.gn
@@ -6,7 +6,7 @@
 
 zx_library("async-loop") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [ "lib/async-loop/loop.h" ]
   configs += [ "//build/config:all_source" ]
   sources = [ "loop.c" ]
@@ -19,7 +19,7 @@
 
 zx_library("async-loop-cpp") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [ "lib/async-loop/cpp/loop.h" ]
   sources = [ "loop_wrapper.cc" ]
   deps = [
@@ -36,7 +36,7 @@
 
 zx_library("async-loop-default") {
   sdk = "static"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [ "lib/async-loop/default.h" ]
 
   sources = [ "default.c" ]
diff --git a/zircon/system/ulib/async-testing/BUILD.gn b/zircon/system/ulib/async-testing/BUILD.gn
index e8be128..cdbfdc3 100644
--- a/zircon/system/ulib/async-testing/BUILD.gn
+++ b/zircon/system/ulib/async-testing/BUILD.gn
@@ -6,7 +6,7 @@
 
 zx_library("async-testing") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [
     "lib/async-testing/dispatcher_stub.h",
     "lib/async-testing/test_loop.h",
diff --git a/zircon/system/ulib/async/BUILD.gn b/zircon/system/ulib/async/BUILD.gn
index 73fe3e5..c800879 100644
--- a/zircon/system/ulib/async/BUILD.gn
+++ b/zircon/system/ulib/async/BUILD.gn
@@ -6,7 +6,7 @@
 
 zx_library("async") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [
     "lib/async/dispatcher.h",
     "lib/async/irq.h",
@@ -36,7 +36,7 @@
 
 zx_library("async-cpp") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [
     "lib/async/cpp/executor.h",
     "lib/async/cpp/irq.h",
diff --git a/zircon/system/ulib/c/BUILD.gn b/zircon/system/ulib/c/BUILD.gn
index 8969c1f..a590842 100644
--- a/zircon/system/ulib/c/BUILD.gn
+++ b/zircon/system/ulib/c/BUILD.gn
@@ -67,6 +67,9 @@
 
 # libc.gni uses these configs.
 
+# This is used for all libc-related sources, because some of the local code
+# still ties into the old musl implementation.  When the interactions with musl
+# internals are fully replaced, only llvm-libc.config will be needed.
 config("internal.config") {
   visibility = [ "./*" ]
   configs = [
@@ -75,12 +78,11 @@
   ]
 }
 
+# This is needed for the expectations of the llvm-libc source code, whether
+# compiled into libc or just into unit test code.
 config("llvm-libc.config") {
   visibility = [ "./*" ]
-  defines = [
-    "LIBC_COPT_USE_C_ASSERT=1",
-    "LIBC_NAMESPACE=__llvm_libc",
-  ]
+  defines = [ "LIBC_COPT_USE_C_ASSERT=1" ]
   include_dirs = [
     libc,
     llvm_libc,
@@ -93,19 +95,64 @@
   }
 }
 
+# This is needed when compiling libc-related code for use in unit tests.
 config("testonly.config") {
   visibility = [ "./*" ]
-  defines = [ "LIBC_COPT_TEST_USE_FUCHSIA=1" ]
+  defines = [
+    "LIBC_COPT_TEST_USE_FUCHSIA=1",
+
+    # This namespace is different from the one used below for building libc
+    # itself, mostly just for more visual clarity looking at backtraces from
+    # unit test code and such.  Since the unit test code only ever gets linked
+    # into a program using libc.so and not statically linked with the non-test
+    # libc code, it's not actually ambiguous what it means in the context of
+    # which binary contained the symbol.  But using a separate name is clearer.
+    "LIBC_NAMESPACE=llvm_libc_unittest",
+  ]
+}
+
+# This is needed for compilations of libc-related code to be used in
+# production, not in unit tests.  This applies both to things used outside of
+# libc proper, such as the separate printf_core integrations; and to libc.so
+# itself, which uses llvm-libc-extra.config, below.
+config("llvm-libc-public.config") {
+  configs = [ ":llvm-libc.config" ]
+
+  defines = [
+    # This namespace is invisible to anything outside libc.so, though in an
+    # eventual libc.a for static linking it would be visible at static link
+    # time.  The separate integrations of parts of libc internals, such as
+    # printf_core, also use this namespace because the libc_source_set()s they
+    # depend on are shared targets that also go into libc proper.  In effect,
+    # those separate integrations are using subsets of what an eventual libc.a
+    # could provide to those use cases.
+    #
+    # TODO(mcgrathr): There's no important reason to make it either the same or
+    # different from the upstream default of `__llvm_libc`, but it seems like
+    # `__fuchsia_libc` would be preferable just to make it more clear that this
+    # build is quite different from the llvm-libc source tree's own cmake (or
+    # Bazel) build of the same llvm-libc code.  For now, there are a few places
+    # that hard-code `__llvm_libc` elsewhere in the source tree.  Perhaps
+    # rewire those to use some shared source of truth with this somehow.
+    "LIBC_NAMESPACE=__llvm_libc",
+  ]
 }
 
 config("llvm-libc-export.config") {
   visibility = [ "./*" ]
-  defines = [
-    "LIBC_COPT_PUBLIC_PACKAGING=1",
-    "LIBC_INLINE=inline",
-  ]
+
+  configs = [ ":llvm-libc-public.config" ]
+
+  defines = [ "LIBC_COPT_PUBLIC_PACKAGING=1" ]
+
   if (toolchain_environment == "user.libc") {
-    configs = [ ":llvm-libc-function-attr.config" ]
+    configs += [ ":llvm-libc-function-attr.config" ]
+
+    # libfuzzer also uses libc internally.  By removing the fuzzing
+    # instrumentation we avoid it adding noise to the fuzzing coverage.
+    # TODO(https://fxbug.dev/25073): Once a cleaner solution is found, remove
+    # this.
+    configs += [ "//build/config/zircon:no_fuzzer" ]
   }
 }
 
diff --git a/zircon/system/ulib/c/fenv/BUILD.gn b/zircon/system/ulib/c/fenv/BUILD.gn
index 359b848..228ec75 100644
--- a/zircon/system/ulib/c/fenv/BUILD.gn
+++ b/zircon/system/ulib/c/fenv/BUILD.gn
@@ -47,7 +47,12 @@
   sources = [
     "enabled_exceptions_test.cpp",
     "exception_flags_test.cpp",
-    "exception_status_test.cpp",
+
+    # TODO(https://fxbug.dev/334985146): Disabled to allow next roll,
+    # when https://fxrev.dev/1028378 can land to re-enable it along
+    # with adding new functions the new upstream version now uses.
+    #"exception_status_test.cpp",
+
     "feclearexcept_test.cpp",
     "feholdexcept_test.cpp",
     "feupdateenv_test.cpp",
diff --git a/zircon/system/ulib/c/libc.gni b/zircon/system/ulib/c/libc.gni
index 1f41eec..c2ebed3 100644
--- a/zircon/system/ulib/c/libc.gni
+++ b/zircon/system/ulib/c/libc.gni
@@ -28,14 +28,7 @@
 libc_testonly_configs = libc_configs + [ "$libc:testonly.config" ]
 
 # These additional configs are needed when compiling for the real libc.
-libc_configs += [
-  "$libc:llvm-libc-export.config",
-
-  # libfuzzer also uses libc internally.  By removing the fuzzing
-  # instrumentation we avoid it adding noise to the fuzzing coverage.
-  # TODO(25073): Once a cleaner solution is found, remove this.
-  "//build/config/zircon:no_fuzzer",
-]
+libc_configs += [ "$libc:llvm-libc-export.config" ]
 
 # Define source_set() targets for some libc code.
 #
@@ -379,9 +372,10 @@
   target_dir = rebase_path(".", libc)
   test_target = "$target_name.unittests"
 
+  source_dir = target_dir
   if (defined(invoker.dir)) {
     # This doesn't affect the logic above, but overrides the subdir used below.
-    target_dir = invoker.dir
+    source_dir = invoker.dir
   }
 
   cpu_functions = []
@@ -419,7 +413,7 @@
                              "visibility",
                            ])
 
-    dir = "$llvm_libc/src/$target_dir"
+    dir = "$llvm_libc/src/$source_dir"
 
     if (!defined(invoker.public)) {
       public = []
@@ -476,7 +470,7 @@
   }
 
   libc_test(test_target) {
-    dir = "$llvm_libc/test/src/$target_dir"
+    dir = "$llvm_libc/test/src/$source_dir"
     deps = [ ":$main_target.testonly" ]
     sources = []
 
diff --git a/zircon/system/ulib/c/scudo/custom_scudo_config.h b/zircon/system/ulib/c/scudo/custom_scudo_config.h
index dbf6a869..291a8e9 100644
--- a/zircon/system/ulib/c/scudo/custom_scudo_config.h
+++ b/zircon/system/ulib/c/scudo/custom_scudo_config.h
@@ -16,13 +16,11 @@
     using SizeClassMap = FuchsiaSizeClassMap;
 #if defined(__riscv)
     // Support 39-bit VMA for riscv-64
-    static const uptr RegionSizeLog = 28U;
+    static const uptr RegionSizeLog = 27U;
     static const uptr GroupSizeLog = 19U;
-    static const bool EnableContiguousRegions = false;
 #else
     static const uptr RegionSizeLog = 30U;
     static const uptr GroupSizeLog = 21U;
-    static const bool EnableContiguousRegions = true;
 #endif
     typedef u32 CompactPtrT;
     static const bool EnableRandomOffset = true;
diff --git a/zircon/system/ulib/c/stdio/printf_core/BUILD.gn b/zircon/system/ulib/c/stdio/printf_core/BUILD.gn
index 78438db..71cba12 100644
--- a/zircon/system/ulib/c/stdio/printf_core/BUILD.gn
+++ b/zircon/system/ulib/c/stdio/printf_core/BUILD.gn
@@ -27,8 +27,10 @@
     "LIBC_COPT_PRINTF_DISABLE_WRITE_INT",
   ]
 
-  # Don't support FP types in minimal environments.
-  if (is_kernel || toolchain_environment == "user.basic") {
+  # Don't support FP types if the toolchain doesn't.
+  _no_floating_point = toolchain_variant.tags + [ "no-floating-point" ] -
+                       [ "no-floating-point" ] != toolchain_variant.tags
+  if (_no_floating_point) {
     defines += [ "LIBC_COPT_PRINTF_DISABLE_FLOAT" ]
   }
 
@@ -55,6 +57,10 @@
 
 source_set("wrapper") {
   public = [ "wrapper.h" ]
-  public_configs = [ "../..:llvm-libc.config" ]
+
+  # The llvm-libc headers used by wrapper.h need defines and include_dirs as
+  # used for building libc itself.
+  public_configs = [ "../..:llvm-libc-public.config" ]
+
   deps = [ ":printf_core" ]
 }
diff --git a/zircon/system/ulib/c/stdio/printf_core/wrapper.h b/zircon/system/ulib/c/stdio/printf_core/wrapper.h
index 32070f0..c8bed0a 100644
--- a/zircon/system/ulib/c/stdio/printf_core/wrapper.h
+++ b/zircon/system/ulib/c/stdio/printf_core/wrapper.h
@@ -5,6 +5,19 @@
 #ifndef ZIRCON_SYSTEM_ULIB_C_STDIO_PRINTF_CORE_WRAPPER_H_
 #define ZIRCON_SYSTEM_ULIB_C_STDIO_PRINTF_CORE_WRAPPER_H_
 
+// TODO(https://fxbug.dev/42105189): These are defined as macros in
+// <zircon/compiler.h> and used by some other headers such as in libzx.  This
+// conflicts with their use as scoped identifiers in the llvm-libc code reached
+// from this header, when this header is included in someplace that also
+// includes <zircon/compiler.h> and those headers that rely on its macros.
+// <zircon/compiler.h> should not be defining macros in the public namespace
+// this way, but until that's fixed work around the issue by hiding the macros
+// during the evaluation of the llvm-libc headers.
+#pragma push_macro("add_overflow")
+#undef add_overflow
+#pragma push_macro("sub_overflow")
+#undef sub_overflow
+
 #include <cstdarg>
 #include <string_view>
 #include <type_traits>
@@ -111,4 +124,8 @@
 
 }  // namespace LIBC_NAMESPACE::printf_core
 
+// TODO(https://fxbug.dev/42105189): See comment above.
+#pragma pop_macro("add_overflow")
+#pragma pop_macro("sub_overflow")
+
 #endif  // ZIRCON_SYSTEM_ULIB_C_STDIO_PRINTF_CORE_WRAPPER_H_
diff --git a/zircon/system/ulib/c/string/BUILD.gn b/zircon/system/ulib/c/string/BUILD.gn
index 3afbf09..bf650822 100644
--- a/zircon/system/ulib/c/string/BUILD.gn
+++ b/zircon/system/ulib/c/string/BUILD.gn
@@ -186,12 +186,19 @@
     "strsignal",
   ]
 
-  local_deps = [ ":StringUtil" ]
+  deps = [ ":StringUtil" ]
 }
 
-libc_source_set("StringUtil") {
+llvm_libc_source_set("StringUtil") {
   visibility = [ ":*" ]
-  dir = "$llvm_libc/src/__support/StringUtil"
+
+  dir = "__support/StringUtil"
+
+  # This doesn't define any functions with tests of their own, but it's still
+  # an llvm_libc_source_set() to get the dual production and testonly targets.
+  # (There will also be an unused empty unittests subtarget.)
+  functions = []
+
   public = [
     "error_to_string.h",
     "signal_to_string.h",
diff --git a/zircon/system/ulib/ddk-platform-defs/BUILD.bazel b/zircon/system/ulib/ddk-platform-defs/BUILD.bazel
new file mode 100644
index 0000000..06acaf7
--- /dev/null
+++ b/zircon/system/ulib/ddk-platform-defs/BUILD.bazel
@@ -0,0 +1,18 @@
+# Copyright 2024 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# library that holds ddk-platform defs
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+    name = "ddk-platform-defs",
+    hdrs = [
+        "include/lib/ddk/platform-defs.h",
+    ],
+    includes = [
+        "include",
+    ],
+    target_compatible_with = ["@platforms//os:fuchsia"],
+)
diff --git a/zircon/system/ulib/ddk-platform-defs/BUILD.gn b/zircon/system/ulib/ddk-platform-defs/BUILD.gn
index 0bf7d82..770e8c8 100644
--- a/zircon/system/ulib/ddk-platform-defs/BUILD.gn
+++ b/zircon/system/ulib/ddk-platform-defs/BUILD.gn
@@ -6,7 +6,7 @@
 
 zx_library("ddk-platform-defs") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [ "lib/ddk/platform-defs.h" ]
 
   sources = []
diff --git a/zircon/system/ulib/debugdata/datasink.cc b/zircon/system/ulib/debugdata/datasink.cc
index 4a85030..c6a6859 100644
--- a/zircon/system/ulib/debugdata/datasink.cc
+++ b/zircon/system/ulib/debugdata/datasink.cc
@@ -48,12 +48,11 @@
 #include <profile/InstrProfData.inc>
 };
 
-// TODO(b/42086151): The layout of the profiles defined in InstrProfData.inc has changed via
-// https://reviews.llvm.org/D138846.
-// llvm_profile_header_v8 and llvm_profile_data_format_v8 defines the layout of the
-// profiles that have profile version 8 and below. Remove these after Rust toolchain switches to the
-// profile version 9 and above.
-struct llvm_profile_header_v8 {
+// llvm_profile_header_v9 and llvm_profile_data_format_v9 define the layout of the
+// profiles that have profile version 9.
+// TODO(b/42086151): Remove these after Rust toolchain switches to the
+// profile version 10 and above.
+struct llvm_profile_header_v9 {
   uint64_t Magic;
   uint64_t Version;
   uint64_t BinaryIdsSize;
@@ -61,20 +60,25 @@
   uint64_t PaddingBytesBeforeCounters;
   uint64_t NumCounters;
   uint64_t PaddingBytesAfterCounters;
+  uint64_t NumBitmapBytes;
+  uint64_t PaddingBytesAfterBitmapBytes;
   uint64_t NamesSize;
   uint64_t CountersDelta;
+  uint64_t BitmapDelta;
   uint64_t NamesDelta;
   uint64_t ValueKindLast;
 };
 
-struct llvm_profile_data_format_v8 {
+struct llvm_profile_data_format_v9 {
   uint64_t NameRef;
   uint64_t FuncHash;
   IntPtrT CounterPtr;
+  IntPtrT BitmapPtr;
   IntPtrT FunctionPointer;
   IntPtrT Values;
   uint32_t NumCounters;
   uint16_t NumValueSites;
+  uint32_t NumBitmapBytes;
 };
 
 std::error_code ReadFile(const fbl::unique_fd& fd, uint8_t* data, size_t size) {
@@ -147,29 +151,29 @@
   return fbl::String::Concat({parent, child});
 }
 
-// TODO(https://fxbug.dev/42086151): Remove this function after Rust toolchain switches to the
-// raw profile version 9 and above.
-bool ProfilesCompatibleVersion8(const uint8_t* dst, const uint8_t* src) {
-  const llvm_profile_header_v8* src_header = reinterpret_cast<const llvm_profile_header_v8*>(src);
-  const llvm_profile_header_v8* dst_header = reinterpret_cast<const llvm_profile_header_v8*>(dst);
+// TODO(https://fxbug.dev/333945525): Remove this function after Rust toolchain switches to the
+// raw profile version 10 and above.
+bool ProfilesCompatibleVersion9(const uint8_t* dst, const uint8_t* src) {
+  const llvm_profile_header_v9* src_header = reinterpret_cast<const llvm_profile_header_v9*>(src);
+  const llvm_profile_header_v9* dst_header = reinterpret_cast<const llvm_profile_header_v9*>(dst);
 
   if (src_header->NumData != dst_header->NumData ||
       src_header->NumCounters != dst_header->NumCounters ||
       src_header->NamesSize != dst_header->NamesSize)
     return false;
 
-  const llvm_profile_data_format_v8* src_data_start =
-      reinterpret_cast<const llvm_profile_data_format_v8*>(src + sizeof(*src_header));
-  src_data_start = reinterpret_cast<const llvm_profile_data_format_v8*>(
+  const llvm_profile_data_format_v9* src_data_start =
+      reinterpret_cast<const llvm_profile_data_format_v9*>(src + sizeof(*src_header));
+  src_data_start = reinterpret_cast<const llvm_profile_data_format_v9*>(
       reinterpret_cast<const uint8_t*>(src_data_start) + src_header->BinaryIdsSize);
-  const llvm_profile_data_format_v8* src_data_end = src_data_start + src_header->NumData;
-  const llvm_profile_data_format_v8* dst_data_start =
-      reinterpret_cast<const llvm_profile_data_format_v8*>(dst + sizeof(*dst_header));
-  dst_data_start = reinterpret_cast<const llvm_profile_data_format_v8*>(
+  const llvm_profile_data_format_v9* src_data_end = src_data_start + src_header->NumData;
+  const llvm_profile_data_format_v9* dst_data_start =
+      reinterpret_cast<const llvm_profile_data_format_v9*>(dst + sizeof(*dst_header));
+  dst_data_start = reinterpret_cast<const llvm_profile_data_format_v9*>(
       reinterpret_cast<const uint8_t*>(dst_data_start) + dst_header->BinaryIdsSize);
-  const llvm_profile_data_format_v8* dst_data_end = dst_data_start + dst_header->NumData;
+  const llvm_profile_data_format_v9* dst_data_end = dst_data_start + dst_header->NumData;
 
-  for (const llvm_profile_data_format_v8 *src_data = src_data_start, *dst_data = dst_data_start;
+  for (const llvm_profile_data_format_v9 *src_data = src_data_start, *dst_data = dst_data_start;
        src_data < src_data_end && dst_data < dst_data_end; ++src_data, ++dst_data) {
     if (src_data->NameRef != dst_data->NameRef || src_data->FuncHash != dst_data->FuncHash ||
         src_data->NumCounters != dst_data->NumCounters)
@@ -187,11 +191,11 @@
   if (src_header->Magic != dst_header->Magic || src_header->Version != dst_header->Version)
     return false;
 
-  // Check that raw profiles use version 8 and above because older versions are not supported.
-  ZX_ASSERT(src_header->Version >= 8 && dst_header->Version >= 8);
+  // Check that raw profiles use version 9 and above because older versions are not supported.
+  ZX_ASSERT(src_header->Version >= 9 && dst_header->Version >= 9);
 
-  if (src_header->Version == 8 && dst_header->Version == 8)
-    return ProfilesCompatibleVersion8(dst, src);
+  if (src_header->Version == 9 && dst_header->Version == 9)
+    return ProfilesCompatibleVersion9(dst, src);
 
   if (src_header->NumData != dst_header->NumData ||
       src_header->NumCounters != dst_header->NumCounters ||
@@ -219,29 +223,29 @@
   return true;
 }
 
-// TODO(https://fxbug.dev/42086151): Remove this function after Rust toolchain switches to the
-// raw profile version 9 and above.
-uint8_t* MergeProfilesVersion8(uint8_t* dst, const uint8_t* src) {
-  const llvm_profile_header_v8* src_header = reinterpret_cast<const llvm_profile_header_v8*>(src);
-  const llvm_profile_data_format_v8* src_data_start =
-      reinterpret_cast<const llvm_profile_data_format_v8*>(src + sizeof(*src_header));
-  src_data_start = reinterpret_cast<const llvm_profile_data_format_v8*>(
+// TODO(https://fxbug.dev/333945525): Remove this function after Rust toolchain switches to the
+// raw profile version 10 and above.
+uint8_t* MergeProfilesVersion9(uint8_t* dst, const uint8_t* src) {
+  const llvm_profile_header_v9* src_header = reinterpret_cast<const llvm_profile_header_v9*>(src);
+  const llvm_profile_data_format_v9* src_data_start =
+      reinterpret_cast<const llvm_profile_data_format_v9*>(src + sizeof(*src_header));
+  src_data_start = reinterpret_cast<const llvm_profile_data_format_v9*>(
       reinterpret_cast<const uint8_t*>(src_data_start) + src_header->BinaryIdsSize);
-  const llvm_profile_data_format_v8* src_data_end = src_data_start + src_header->NumData;
+  const llvm_profile_data_format_v9* src_data_end = src_data_start + src_header->NumData;
   const uint64_t* src_counters_start = reinterpret_cast<const uint64_t*>(src_data_end);
   uintptr_t src_counters_delta = src_header->CountersDelta;
 
-  llvm_profile_header_v8* dst_header = reinterpret_cast<llvm_profile_header_v8*>(dst);
-  llvm_profile_data_format_v8* dst_data_start =
-      reinterpret_cast<llvm_profile_data_format_v8*>(dst + sizeof(*dst_header));
-  dst_data_start = reinterpret_cast<llvm_profile_data_format_v8*>(
+  llvm_profile_header_v9* dst_header = reinterpret_cast<llvm_profile_header_v9*>(dst);
+  llvm_profile_data_format_v9* dst_data_start =
+      reinterpret_cast<llvm_profile_data_format_v9*>(dst + sizeof(*dst_header));
+  dst_data_start = reinterpret_cast<llvm_profile_data_format_v9*>(
       reinterpret_cast<uint8_t*>(dst_data_start) + dst_header->BinaryIdsSize);
-  llvm_profile_data_format_v8* dst_data_end = dst_data_start + dst_header->NumData;
+  llvm_profile_data_format_v9* dst_data_end = dst_data_start + dst_header->NumData;
   uint64_t* dst_counters_start = reinterpret_cast<uint64_t*>(dst_data_end);
   uintptr_t dst_counters_delta = dst_header->CountersDelta;
 
-  const llvm_profile_data_format_v8* src_data = src_data_start;
-  llvm_profile_data_format_v8* dst_data = dst_data_start;
+  const llvm_profile_data_format_v9* src_data = src_data_start;
+  llvm_profile_data_format_v9* dst_data = dst_data_start;
 
   for (; src_data < src_data_end && dst_data < dst_data_end; src_data++, dst_data++) {
     const uint64_t* src_counters =
@@ -263,8 +267,8 @@
 // Note that this function does not check whether the profiles are compatible.
 uint8_t* MergeProfiles(uint8_t* dst, const uint8_t* src) {
   const __llvm_profile_header* src_header = reinterpret_cast<const __llvm_profile_header*>(src);
-  if (src_header->Version <= 8)
-    return MergeProfilesVersion8(dst, src);
+  if (src_header->Version == 9)
+    return MergeProfilesVersion9(dst, src);
 
   const __llvm_profile_data* src_data_start =
       reinterpret_cast<const __llvm_profile_data*>(src + sizeof(*src_header));
diff --git a/zircon/system/ulib/hwreg/BUILD.gn b/zircon/system/ulib/hwreg/BUILD.gn
index 3e352a1..4a2739b 100644
--- a/zircon/system/ulib/hwreg/BUILD.gn
+++ b/zircon/system/ulib/hwreg/BUILD.gn
@@ -61,7 +61,7 @@
 
 # Subset of API exported via the SDK.
 sdk_source_set("hwreg_sdk") {
-  category = "experimental"
+  category = "partner"
   sdk_name = "hwreg"
 
   include_dirs = [ "include" ]
diff --git a/zircon/system/ulib/hwreg/hwreg.api b/zircon/system/ulib/hwreg/hwreg.api
new file mode 100644
index 0000000..3b173c6
--- /dev/null
+++ b/zircon/system/ulib/hwreg/hwreg.api
@@ -0,0 +1,5 @@
+{
+  "pkg/hwreg/include/hwreg/bitfields.h": "c69468518238458364ef6608ab2796eb",
+  "pkg/hwreg/include/hwreg/internal.h": "66dbbbf06b19ee66fadea51b27a2dcf5",
+  "pkg/hwreg/include/hwreg/mmio.h": "a113c5806ffb204af26c95edc97c7335"
+}
\ No newline at end of file
diff --git a/zircon/system/ulib/inspect/BUILD.gn b/zircon/system/ulib/inspect/BUILD.gn
index 95269a8..f748f67 100644
--- a/zircon/system/ulib/inspect/BUILD.gn
+++ b/zircon/system/ulib/inspect/BUILD.gn
@@ -6,7 +6,7 @@
 
 zx_library("inspect") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [
     "lib/inspect/cpp/inspect.h",
     "lib/inspect/cpp/inspector.h",
diff --git a/zircon/system/ulib/inspector/registers.cc b/zircon/system/ulib/inspector/registers.cc
index 56ac894..7d81389 100644
--- a/zircon/system/ulib/inspector/registers.cc
+++ b/zircon/system/ulib/inspector/registers.cc
@@ -39,8 +39,10 @@
           regs->r12, regs->r13, regs->r14, regs->r15);
   fprintf(f, " fs.base: %#18" PRIx64 " gs.base: %#18" PRIx64 "\n", regs->fs_base, regs->gs_base);
   if (excp_data) {
-    // errc value is 17 on purpose, errc is 4 characters
-    fprintf(f, " errc: %#17" PRIx64 "\n", excp_data->err_code);
+    // These are padded differently to line up with the labels above given the
+    // specific lengths of the "vector:" and "errc:" labels.
+    fprintf(f, " vector: %#15" PRIx64 " errc: %#17" PRIx64 "\n", excp_data->vector,
+            excp_data->err_code);
   }
 }
 
diff --git a/zircon/system/ulib/ldmsg/ldmsg.c b/zircon/system/ulib/ldmsg/ldmsg.c
index e7412ca..f9f33f0 100644
--- a/zircon/system/ulib/ldmsg/ldmsg.c
+++ b/zircon/system/ulib/ldmsg/ldmsg.c
@@ -13,11 +13,6 @@
 
 static_assert(sizeof(ldmsg_req_t) == 1024, "Loader service requests can be at most 1024 bytes.");
 
-static size_t FidlAlign(size_t offset) {
-  const size_t alignment_mask = FIDL_ALIGNMENT - 1;
-  return (offset + alignment_mask) & ~alignment_mask;
-}
-
 zx_status_t ldmsg_req_encode(uint64_t ordinal, ldmsg_req_t* req, size_t* req_len_out,
                              const char* data, size_t len) {
   fidl_init_txn_header(&req->header, 0, ordinal, 0);
@@ -57,7 +52,7 @@
 
   // Make sure to zero out the extra bytes required by alignment constraints.
   size_t req_len_unaligned = sizeof(fidl_message_header_t) + offset + len;
-  *req_len_out = FidlAlign(req_len_unaligned);
+  *req_len_out = FIDL_ALIGN(req_len_unaligned);
   memset((char*)req + req_len_unaligned, 0, *req_len_out - req_len_unaligned);
   return ZX_OK;
 }
@@ -91,7 +86,7 @@
 
   size_t size = req->common.string.size;
   if (LDMSG_MAX_PAYLOAD - offset - 1 < size ||
-      req_len != FidlAlign(sizeof(fidl_message_header_t) + offset + size))
+      req_len != FIDL_ALIGN(sizeof(fidl_message_header_t) + offset + size))
     return ZX_ERR_INVALID_ARGS;
 
   // Null terminate the string. The message isn't required to have a null
diff --git a/zircon/system/ulib/mmio-ptr/BUILD.gn b/zircon/system/ulib/mmio-ptr/BUILD.gn
index 3f703b8..94a165c 100644
--- a/zircon/system/ulib/mmio-ptr/BUILD.gn
+++ b/zircon/system/ulib/mmio-ptr/BUILD.gn
@@ -8,7 +8,7 @@
   sources = []
 
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [ "lib/mmio-ptr/mmio-ptr.h" ]
 }
 
diff --git a/zircon/system/ulib/pretty/test/test.c b/zircon/system/ulib/pretty/test/test.c
index 7a056f3..cd37860 100644
--- a/zircon/system/ulib/pretty/test/test.c
+++ b/zircon/system/ulib/pretty/test/test.c
@@ -8,6 +8,8 @@
 #include <pretty/sizes.h>
 #include <zxtest/zxtest.h>
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 typedef struct {
   const size_t input;
   const char unit;
@@ -113,7 +115,7 @@
 TEST(PrettyTests, format_size_fixed_test) {
   char str[MAX_FORMAT_SIZE_LEN];
   char msg[128];
-  for (unsigned int i = 0; i < countof(format_size_test_cases); i++) {
+  for (unsigned int i = 0; i < ARRAY_SIZE(format_size_test_cases); i++) {
     const format_size_test_case_t* tc = format_size_test_cases + i;
     memset(str, 0, sizeof(str));
     char* ret = format_size_fixed(str, sizeof(str), tc->input, tc->unit);
diff --git a/zircon/system/ulib/sync/BUILD.gn b/zircon/system/ulib/sync/BUILD.gn
index e5c3115..c3b8b9f 100644
--- a/zircon/system/ulib/sync/BUILD.gn
+++ b/zircon/system/ulib/sync/BUILD.gn
@@ -7,7 +7,7 @@
 
 zx_library("sync") {
   sdk = "static"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = [
     "lib/sync/internal/condition-template.h",
     "lib/sync/internal/mutex-internal.h",
diff --git a/zircon/system/ulib/syslog/BUILD.gn b/zircon/system/ulib/syslog/BUILD.gn
index d4fcfbb..815d23c 100644
--- a/zircon/system/ulib/syslog/BUILD.gn
+++ b/zircon/system/ulib/syslog/BUILD.gn
@@ -80,7 +80,7 @@
 
 zx_library("syslog") {
   sdk = "shared"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = syslog_headers
 
   sources = [
@@ -111,7 +111,7 @@
 
 zx_library("syslog-headers") {
   sdk = "static"
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk_headers = syslog_headers
   visibility = syslog_headers_visibility_allowlist
 }
diff --git a/zircon/system/ulib/trace-engine/BUILD.gn b/zircon/system/ulib/trace-engine/BUILD.gn
index 839ad11..7994363 100644
--- a/zircon/system/ulib/trace-engine/BUILD.gn
+++ b/zircon/system/ulib/trace-engine/BUILD.gn
@@ -84,7 +84,7 @@
 # The default version for the normal case.
 trace_engine_library("trace-engine") {
   sdk = "shared"
-  sdk_publishable = true
+  sdk_publishable = "partner"
 
   # TODO(https://fxbug.dev/42136089): delete the below and fix compiler warnings
   extra_configs = [ "//build/config:Wno-conversion" ]
diff --git a/zircon/system/ulib/trace-provider/BUILD.gn b/zircon/system/ulib/trace-provider/BUILD.gn
index 83a2d4f..f854091 100644
--- a/zircon/system/ulib/trace-provider/BUILD.gn
+++ b/zircon/system/ulib/trace-provider/BUILD.gn
@@ -124,7 +124,7 @@
 # TODO(https://fxbug.dev/42096938): Add start.cc to this library in order to match the
 # non-shared version of the library.
 trace_provider_library("trace-provider-so") {
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk = "shared"
 
   defines = [ "SHARED_LIBRARY" ]
diff --git a/zircon/system/ulib/trace-vthread/BUILD.gn b/zircon/system/ulib/trace-vthread/BUILD.gn
index 34d95ef..76604a1 100644
--- a/zircon/system/ulib/trace-vthread/BUILD.gn
+++ b/zircon/system/ulib/trace-vthread/BUILD.gn
@@ -37,7 +37,7 @@
     "trace-vthread/internal/event_vthread.h",
     "trace-vthread/event_vthread.h",
   ]
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sources = [ "event_vthread.cc" ]
   sdk_headers_for_internal_use = [ "trace-vthread/internal/event_vthread.h" ]
   public_deps = [
diff --git a/zircon/system/ulib/trace/BUILD.gn b/zircon/system/ulib/trace/BUILD.gn
index 9ae9e95..a61ef39 100644
--- a/zircon/system/ulib/trace/BUILD.gn
+++ b/zircon/system/ulib/trace/BUILD.gn
@@ -91,7 +91,7 @@
 # C++ and C++ SDK libraries can't be published as "static".
 # TODO(https://fxbug.dev/42097099): libtrace-engine.so is getting linked into places it shouldn't.
 trace_library("trace") {
-  sdk_publishable = true
+  sdk_publishable = "partner"
   sdk = "source"
   public_deps = [ "//zircon/system/ulib/trace-engine" ]
   deps = [ "//zircon/system/ulib/trace-engine" ]
diff --git a/zircon/system/ulib/zx/BUILD.gn b/zircon/system/ulib/zx/BUILD.gn
index fa80f07..5a5132e 100644
--- a/zircon/system/ulib/zx/BUILD.gn
+++ b/zircon/system/ulib/zx/BUILD.gn
@@ -6,7 +6,7 @@
 
 zx_library("zx") {
   sdk = "source"
-  sdk_publishable = true
+  sdk_publishable = "partner"
 
   sdk_headers = [ "lib/zx/result.h" ]
   sources = []
diff --git a/zircon/system/utest/core/bad-syscall/bad-syscall.cc b/zircon/system/utest/core/bad-syscall/bad-syscall.cc
index 5dabc3e..08f740b 100644
--- a/zircon/system/utest/core/bad-syscall/bad-syscall.cc
+++ b/zircon/system/utest/core/bad-syscall/bad-syscall.cc
@@ -58,7 +58,7 @@
 
 #if defined(__x86_64__) && !defined(ENABLE_USER_PCI)
 TEST(BadAccessTest, PciCfgPioRw) {
-  EXPECT_EQ(zx_pci_cfg_pio_rw(standalone::GetRootResource()->get(), 0, 0, 0, 0,
+  EXPECT_EQ(zx_pci_cfg_pio_rw(standalone::GetIoportResource()->get(), 0, 0, 0, 0,
                               reinterpret_cast<uint32_t*>(unmapped_addr), 0, true),
             ZX_ERR_INVALID_ARGS);
 }
diff --git a/zircon/system/utest/core/bti/bti.cc b/zircon/system/utest/core/bti/bti.cc
index d9ebef4..3f6d6a9 100644
--- a/zircon/system/utest/core/bti/bti.cc
+++ b/zircon/system/utest/core/bti/bti.cc
@@ -23,8 +23,15 @@
   zx::pmt pmt;
 
   zx_iommu_desc_dummy_t desc;
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
 }
@@ -34,9 +41,14 @@
   zx::bti bti;
 
   zx_iommu_desc_dummy_t desc;
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
 
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
 
@@ -75,8 +87,14 @@
   zx::iommu iommu;
   zx::bti bti;
   zx_iommu_desc_dummy_t desc;
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
 
@@ -110,8 +128,14 @@
   zx::iommu iommu;
   zx::bti bti;
   zx_iommu_desc_dummy_t desc;
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
 
@@ -133,8 +157,15 @@
   zx::bti bti;
   zx::pmt pmt;
   zx_iommu_desc_dummy_t desc;
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
 
@@ -154,8 +185,15 @@
   zx::bti bti;
   zx::pmt pmt;
   zx_iommu_desc_dummy_t desc;
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
 
@@ -182,8 +220,15 @@
   zx::bti bti;
   zx::pmt pmt;
   zx_iommu_desc_dummy_t desc;
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
   // Query the info on the bti. It should have no pmos, and no quarantines:
@@ -222,8 +267,15 @@
   zx::iommu iommu;
   zx::bti bti;
   zx_iommu_desc_dummy_t desc;
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
 
@@ -299,8 +351,15 @@
   zx::iommu iommu;
   zx::bti bti;
   zx_iommu_desc_dummy_t desc;
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc,
-                            sizeof(desc), iommu.reset_and_get_address()),
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+                            iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
 
@@ -360,7 +419,14 @@
   zx::bti bti;
   zx_iommu_desc_dummy_t desc;
 
-  ASSERT_EQ(zx_iommu_create(standalone::GetRootResource()->get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+
+  ASSERT_EQ(zx_iommu_create(iommu_resource.get(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc),
                             iommu.reset_and_get_address()),
             ZX_OK);
   ASSERT_EQ(zx::bti::create(iommu, 0, 0xdeadbeef, &bti), ZX_OK);
diff --git a/zircon/system/utest/core/debuglog/debuglog.cc b/zircon/system/utest/core/debuglog/debuglog.cc
index c8be4c4..5ca73b9 100644
--- a/zircon/system/utest/core/debuglog/debuglog.cc
+++ b/zircon/system/utest/core/debuglog/debuglog.cc
@@ -13,8 +13,14 @@
 
 TEST(DebugLogTest, WriteRead) {
   zx_handle_t log_handle = 0;
-  ASSERT_OK(
-      zx_debuglog_create(standalone::GetRootResource()->get(), ZX_LOG_FLAG_READABLE, &log_handle));
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUGLOG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debuglog_resource = std::move(result.value());
+
+  ASSERT_OK(zx_debuglog_create(debuglog_resource.get(), ZX_LOG_FLAG_READABLE, &log_handle));
 
   // Ensure something is written.
   static const char kTestMsg[] = "Debuglog test message.\n";
@@ -38,35 +44,44 @@
 
 TEST(DebugLogTest, InvalidOptions) {
   zx_handle_t log_handle = 0;
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUGLOG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debuglog_resource = std::move(result.value());
 
   // Ensure giving invalid options returns an error.
-  EXPECT_EQ(zx_debuglog_create(standalone::GetRootResource()->get(), 1, &log_handle),
-            ZX_ERR_INVALID_ARGS);
+  EXPECT_EQ(zx_debuglog_create(debuglog_resource.get(), 1, &log_handle), ZX_ERR_INVALID_ARGS);
   EXPECT_EQ(log_handle, 0);
 
-  EXPECT_EQ(zx_debuglog_create(standalone::GetRootResource()->get(), 1 | ZX_LOG_FLAG_READABLE,
-                               &log_handle),
+  EXPECT_EQ(zx_debuglog_create(debuglog_resource.get(), 1 | ZX_LOG_FLAG_READABLE, &log_handle),
             ZX_ERR_INVALID_ARGS);
   EXPECT_EQ(log_handle, 0);
 }
 
 TEST(DebugLogTest, InvalidHandleAllowedOnlyForWrite) {
   zx_handle_t log_handle = 0;
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
 
-  // Requesting a read-write handle with a valid root resource should work
-  ASSERT_OK(
-      zx_debuglog_create(standalone::GetRootResource()->get(), ZX_LOG_FLAG_READABLE, &log_handle));
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUGLOG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debuglog_resource = std::move(result.value());
+
+  // Requesting a read-write handle with a valid debuglog resource should work
+  ASSERT_OK(zx_debuglog_create(debuglog_resource.get(), ZX_LOG_FLAG_READABLE, &log_handle));
   ASSERT_OK(zx_handle_close(log_handle));
   log_handle = ZX_HANDLE_INVALID;
 
-  // Requesting a write-only handle with an invalid root resource should work,
+  // Requesting a write-only handle with an invalid resource should work,
   // since the dynamic linker needs to be able to log something somewhere when
   // it can't bootstrap a process
   ASSERT_OK(zx_debuglog_create(ZX_HANDLE_INVALID, 0, &log_handle));
   ASSERT_OK(zx_handle_close(log_handle));
   log_handle = ZX_HANDLE_INVALID;
 
-  // But requesting a read-write handle with an invalid root resource represents
+  // But requesting a read-write handle with an invalid resource represents
   // an information leak, so the kernel checks the first arg, and if it's not a
   // valid handle, then we get an error
   EXPECT_EQ(zx_debuglog_create(ZX_HANDLE_INVALID, ZX_LOG_FLAG_READABLE, &log_handle),
@@ -75,8 +90,14 @@
 
 TEST(DebugLogTest, MaxMessageSize) {
   zx_handle_t log_handle = ZX_HANDLE_INVALID;
-  ASSERT_OK(
-      zx_debuglog_create(standalone::GetRootResource()->get(), ZX_LOG_FLAG_READABLE, &log_handle));
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUGLOG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debuglog_resource = std::move(result.value());
+
+  ASSERT_OK(zx_debuglog_create(debuglog_resource.get(), ZX_LOG_FLAG_READABLE, &log_handle));
 
   // msg is too large and should be truncated.
   char msg[ZX_LOG_RECORD_DATA_MAX + 1];
diff --git a/zircon/system/utest/core/interrupt/fixture.h b/zircon/system/utest/core/interrupt/fixture.h
index 0602f46..35bbc89 100644
--- a/zircon/system/utest/core/interrupt/fixture.h
+++ b/zircon/system/utest/core/interrupt/fixture.h
@@ -20,29 +20,43 @@
 class ResourceFixture : public zxtest::Test {
  public:
   void SetUp() override {
-    root_resource_ = standalone::GetRootResource();
     irq_resource_ = standalone::GetIrqResource();
 
+    zx::unowned_resource system_resource = standalone::GetSystemResource();
+
     zx_iommu_desc_dummy_t desc = {};
+
+    zx::result<zx::resource> get_iommu_resource =
+        standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+    ASSERT_OK(get_iommu_resource.status_value());
+    iommu_resource_ = std::move(get_iommu_resource.value());
+
+    zx::result<zx::resource> get_msi_resource =
+        standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_MSI_BASE);
+    ASSERT_OK(get_msi_resource.status_value());
+    msi_resource_ = std::move(get_msi_resource.value());
+
     ASSERT_OK(
-        zx::iommu::create(*root_resource_, ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu_));
+        zx::iommu::create(iommu_resource_, ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu_));
     ASSERT_OK(zx::bti::create(iommu_, 0, 0xdeadbeef, &bti_));
   }
 
   bool MsiTestsSupported() {
     zx::msi msi;
-    return !(zx::msi::allocate(*root_resource_, 1, &msi) == ZX_ERR_NOT_SUPPORTED);
+    return !(zx::msi::allocate(msi_resource_, 1, &msi) == ZX_ERR_NOT_SUPPORTED);
   }
 
  protected:
   zx::unowned_bti bti() { return bti_.borrow(); }
-  zx::unowned_resource& root_resource() { return root_resource_; }
   zx::unowned_resource& irq_resource() { return irq_resource_; }
+  zx::resource& iommu_resource() { return iommu_resource_; }
+  zx::resource& msi_resource() { return msi_resource_; }
   zx::unowned_iommu iommu() { return iommu_.borrow(); }
 
  private:
-  zx::unowned_resource root_resource_;
   zx::unowned_resource irq_resource_;
+  zx::resource iommu_resource_;
+  zx::resource msi_resource_;
   zx::iommu iommu_;
   zx::bti bti_;
 };
diff --git a/zircon/system/utest/core/interrupt/interrupt-test.cc b/zircon/system/utest/core/interrupt/interrupt-test.cc
index 190eccf..bc0db7a 100644
--- a/zircon/system/utest/core/interrupt/interrupt-test.cc
+++ b/zircon/system/utest/core/interrupt/interrupt-test.cc
@@ -84,7 +84,7 @@
 TEST_F(InterruptTest, VirtualNotWakeable) {
   zx::interrupt interrupt;
   ASSERT_EQ(ZX_ERR_INVALID_ARGS,
-            zx::interrupt::create(*root_resource(), 0,
+            zx::interrupt::create(*irq_resource(), 0,
                                   ZX_INTERRUPT_VIRTUAL | ZX_INTERRUPT_WAKE_VECTOR, &interrupt));
 }
 
diff --git a/zircon/system/utest/core/interrupt/msi-test.cc b/zircon/system/utest/core/interrupt/msi-test.cc
index 50dfae9..1ee6055 100644
--- a/zircon/system/utest/core/interrupt/msi-test.cc
+++ b/zircon/system/utest/core/interrupt/msi-test.cc
@@ -83,7 +83,7 @@
 
   for (const auto& test : kTests) {
     zx::msi msi = {};
-    EXPECT_EQ(test.first, zx::msi::allocate(*root_resource(), test.second, &msi),
+    EXPECT_EQ(test.first, zx::msi::allocate(msi_resource(), test.second, &msi),
               "irq_cnt = %u failed.", test.second);
   }
 }
@@ -142,7 +142,7 @@
   constexpr uint32_t msi_cnt = 8;
   auto msi_test_vmo = std::move(result.value());
   auto& vmo = msi_test_vmo->vmo();
-  ASSERT_OK(zx::msi::allocate(*root_resource(), msi_cnt, &msi));
+  ASSERT_OK(zx::msi::allocate(msi_resource(), msi_cnt, &msi));
   zx_info_msi_t msi_info;
   ASSERT_OK(msi.get_info(ZX_INFO_MSI, &msi_info, sizeof(msi_info), nullptr, nullptr));
   zx_info_vmo_t vmo_info;
@@ -190,7 +190,7 @@
 
   zx::msi msi;
   constexpr uint32_t msi_cnt = 8;
-  ASSERT_OK(zx::msi::allocate(*root_resource(), msi_cnt, &msi));
+  ASSERT_OK(zx::msi::allocate(msi_resource(), msi_cnt, &msi));
   zx::interrupt interrupt, interrupt_dup;
 
   auto msi_test_vmo = std::move(result.value());
@@ -236,7 +236,7 @@
 
   const uint32_t msi_cnt = 8;
   zx::msi msi = {};
-  ASSERT_OK(zx::msi::allocate(*root_resource(), msi_cnt, &msi));
+  ASSERT_OK(zx::msi::allocate(msi_resource(), msi_cnt, &msi));
 
   auto msi_test_vmo = std::move(result.value());
   auto& vmo = msi_test_vmo->vmo();
@@ -295,7 +295,7 @@
   const size_t msi_cnt = 1;
   ASSERT_OK(zx::vmo::create_contiguous(*bti(), zx_system_get_page_size(), 0, &vmo));
   zx::msi msi;
-  ASSERT_OK(zx::msi::allocate(*root_resource(), msi_cnt, &msi));
+  ASSERT_OK(zx::msi::allocate(msi_resource(), msi_cnt, &msi));
 
   zx::interrupt interrupt;
   ASSERT_NE(ZX_OK, zx::msi::create(msi, 0, 0, vmo, 0, &interrupt));
diff --git a/zircon/system/utest/core/pager/snapshot.cc b/zircon/system/utest/core/pager/snapshot.cc
index ab21242..ed6906e 100644
--- a/zircon/system/utest/core/pager/snapshot.cc
+++ b/zircon/system/utest/core/pager/snapshot.cc
@@ -945,10 +945,10 @@
 
 // Ensures that a snapshot-modified child can not be created on a VMO with pinned pages.
 TEST(Snapshot, PinBeforeCreateFailure) {
-  auto root_resource = maybe_standalone::GetRootResource();
+  auto system_resource = maybe_standalone::GetSystemResource();
 
-  if (!*root_resource) {
-    printf("Root resource not available, skipping\n");
+  if (!*system_resource) {
+    printf("System resource not available, skipping\n");
     return;
   }
 
@@ -971,7 +971,12 @@
     }
   });
 
-  ASSERT_OK(zx::iommu::create(*root_resource, ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
+  zx::result<zx::resource> result =
+      maybe_standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_OK(zx::iommu::create(iommu_resource, ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
   EXPECT_OK(zx::bti::create(iommu, 0, 0xdead1eaf, &bti));
 
   auto name = "PinBeforeCreateFailure";
diff --git a/zircon/system/utest/core/thread-sampler/thread-sampler.cc b/zircon/system/utest/core/thread-sampler/thread-sampler.cc
index aa9e22a..720a9c4a 100644
--- a/zircon/system/utest/core/thread-sampler/thread-sampler.cc
+++ b/zircon/system/utest/core/thread-sampler/thread-sampler.cc
@@ -53,8 +53,15 @@
       .buffer_size = buffer_size,
   };
   zx::iob sampler;
-  zx_status_t create_res = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                             sampler.reset_and_get_address());
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debug_resource = std::move(result.value());
+
+  zx_status_t create_res =
+      zx_sampler_create(debug_resource.get(), 0, &config, sampler.reset_and_get_address());
   if constexpr (!sampler_enabled) {
     ASSERT_EQ(create_res, ZX_ERR_NOT_SUPPORTED);
     return;
@@ -108,10 +115,17 @@
       .period = zx::msec(1).get(),
       .buffer_size = buffer_size,
   };
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debug_resource = std::move(result.value());
+
   {
     zx::iob buffers;
-    zx_status_t create_res = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                               buffers.reset_and_get_address());
+    zx_status_t create_res =
+        zx_sampler_create(debug_resource.get(), 0, &config, buffers.reset_and_get_address());
     if constexpr (!sampler_enabled) {
       ASSERT_EQ(create_res, ZX_ERR_NOT_SUPPORTED);
       return;
@@ -119,16 +133,15 @@
     ASSERT_OK(create_res);
 
     zx::iob new_buffers;
-    zx_status_t create_res_bad = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                                   new_buffers.reset_and_get_address());
+    zx_status_t create_res_bad =
+        zx_sampler_create(debug_resource.get(), 0, &config, new_buffers.reset_and_get_address());
 
     EXPECT_EQ(create_res_bad, ZX_ERR_ALREADY_EXISTS);
   }
 
   // Once the buffer is released, a new sampler can now be created
   zx::iob buffers;
-  ASSERT_OK(zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                              buffers.reset_and_get_address()));
+  ASSERT_OK(zx_sampler_create(debug_resource.get(), 0, &config, buffers.reset_and_get_address()));
 }
 
 TEST(ThreadSampler, DroppedSampler) {
@@ -139,8 +152,15 @@
       .buffer_size = buffer_size,
   };
   zx::iob sampler;
-  zx_status_t create_res = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                             sampler.reset_and_get_address());
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debug_resource = std::move(result.value());
+
+  zx_status_t create_res =
+      zx_sampler_create(debug_resource.get(), 0, &config, sampler.reset_and_get_address());
   if constexpr (!sampler_enabled) {
     ASSERT_EQ(create_res, ZX_ERR_NOT_SUPPORTED);
     return;
@@ -163,8 +183,7 @@
   sampler.reset();
 
   // And create a new one
-  create_res = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                 sampler.reset_and_get_address());
+  create_res = zx_sampler_create(debug_resource.get(), 0, &config, sampler.reset_and_get_address());
   ASSERT_OK(create_res);
   ASSERT_OK(zx_sampler_attach(sampler.get(), native_handle));
   ASSERT_OK(zx_sampler_start(sampler.get()));
@@ -205,8 +224,15 @@
       .buffer_size = buffer_size,
   };
   zx::iob sampler;
-  zx_status_t create_res = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                             sampler.reset_and_get_address());
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debug_resource = std::move(result.value());
+
+  zx_status_t create_res =
+      zx_sampler_create(debug_resource.get(), 0, &config, sampler.reset_and_get_address());
   if constexpr (!sampler_enabled) {
     ASSERT_EQ(create_res, ZX_ERR_NOT_SUPPORTED);
     return;
@@ -258,8 +284,15 @@
       .buffer_size = buffer_size,
   };
   zx::iob sampler;
-  zx_status_t create_res = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                             sampler.reset_and_get_address());
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debug_resource = std::move(result.value());
+
+  zx_status_t create_res =
+      zx_sampler_create(debug_resource.get(), 0, &config, sampler.reset_and_get_address());
   if constexpr (!sampler_enabled) {
     ASSERT_EQ(create_res, ZX_ERR_NOT_SUPPORTED);
     return;
@@ -295,8 +328,15 @@
       .buffer_size = buffer_size,
   };
   zx::iob sampler;
-  zx_status_t create_res = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                             sampler.reset_and_get_address());
+
+  zx::unowned_resource system_resource = standalone::GetSystemResource();
+  zx::result<zx::resource> result =
+      standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_DEBUG_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource debug_resource = std::move(result.value());
+
+  zx_status_t create_res =
+      zx_sampler_create(debug_resource.get(), 0, &config, sampler.reset_and_get_address());
   if constexpr (!sampler_enabled) {
     ASSERT_EQ(create_res, ZX_ERR_NOT_SUPPORTED);
     return;
@@ -331,8 +371,7 @@
 
   // Reset our sampler
   sampler.reset();
-  create_res = zx_sampler_create(standalone::GetRootResource()->get(), 0, &config,
-                                 sampler.reset_and_get_address());
+  create_res = zx_sampler_create(debug_resource.get(), 0, &config, sampler.reset_and_get_address());
   ASSERT_OK(create_res);
   ASSERT_OK(zx_sampler_start(sampler.get()));
   ASSERT_OK(zx_sampler_stop(sampler.get()));
diff --git a/zircon/system/utest/core/vmo/vmo-clone2.cc b/zircon/system/utest/core/vmo/vmo-clone2.cc
index 4521600..c267ecd 100644
--- a/zircon/system/utest/core/vmo/vmo-clone2.cc
+++ b/zircon/system/utest/core/vmo/vmo-clone2.cc
@@ -33,17 +33,13 @@
 class VmoClone2TestCase : public zxtest::Test {
  public:
   static void SetUpTestSuite() {
-    root_resource_ = maybe_standalone::GetRootResource();
-    if (root_resource_->is_valid()) {
+    zx::unowned_resource system_resource = maybe_standalone::GetSystemResource();
+    if (system_resource->is_valid()) {
       ASSERT_EQ(dl_iterate_phdr(&DlIterpatePhdrCallback, nullptr), 0);
     }
   }
 
-  static const zx::resource& RootResource() { return *root_resource_; }
-
  private:
-  static zx::unowned_resource root_resource_;
-
   // Touch every page in the region to make sure it's been COW'd.
   __attribute__((no_sanitize("all"))) static void PrefaultPages(uintptr_t start, uintptr_t end) {
     while (start < end) {
@@ -94,8 +90,6 @@
   }
 };
 
-zx::unowned_resource VmoClone2TestCase::root_resource_;
-
 // Helper function which checks that the give vmo is contiguous.
 template <size_t N>
 void CheckContigState(const zx::bti& bti, const zx::vmo& vmo) {
@@ -829,9 +823,9 @@
   static void ResizeTest(Contiguity contiguity, ResizeTarget target) {
     bool contiguous = contiguity == Contiguity::Contig;
     bool resize_child = target == ResizeTarget::Child;
-
-    if (contiguous && !RootResource()) {
-      printf("Root resource not available, skipping\n");
+    zx::unowned_resource system_resource = maybe_standalone::GetSystemResource();
+    if (contiguous && !system_resource->is_valid()) {
+      printf("System resource not available, skipping\n");
       return;
     }
 
@@ -843,8 +837,14 @@
 
     if (contiguous) {
       zx_iommu_desc_dummy_t desc;
+
+      zx::result<zx::resource> result =
+          maybe_standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+      ASSERT_OK(result.status_value());
+      zx::resource iommu_resource = std::move(result.value());
+
       ASSERT_OK(
-          zx::iommu::create(RootResource(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
+          zx::iommu::create(iommu_resource, ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
       ASSERT_NO_FAILURES(bti =
                              vmo_test::CreateNamedBti(iommu, 0, 0xdeadbeef, "VmoCloneResizeTests"));
       ASSERT_OK(zx::vmo::create_contiguous(bti, 4 * zx_system_get_page_size(), 0, &vmo));
@@ -1349,8 +1349,9 @@
 }
 
 TEST_F(VmoClone2TestCase, ForbidContiguousVmo) {
-  if (!RootResource()) {
-    printf("Root resource not available, skipping\n");
+  zx::unowned_resource system_resource = maybe_standalone::GetSystemResource();
+  if (!system_resource->is_valid()) {
+    printf("System resource not available, skipping\n");
     return;
   }
 
@@ -1359,7 +1360,12 @@
   zx_iommu_desc_dummy_t desc;
   auto final_bti_check = vmo_test::CreateDeferredBtiCheck(bti);
 
-  ASSERT_OK(zx::iommu::create(RootResource(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
+  zx::result<zx::resource> result =
+      maybe_standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_OK(zx::iommu::create(iommu_resource, ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
   ASSERT_NO_FAILURES(bti = vmo_test::CreateNamedBti(iommu, 0, 0xdeadbeef, "ForbidContiguousVmo"));
 
   zx::vmo vmo;
@@ -1374,8 +1380,9 @@
 }
 
 TEST_F(VmoClone2TestCase, PinBeforeCreateFailure) {
-  if (!RootResource()) {
-    printf("Root resource not available, skipping\n");
+  zx::unowned_resource system_resource = maybe_standalone::GetSystemResource();
+  if (!system_resource->is_valid()) {
+    printf("System resource not available, skipping\n");
     return;
   }
 
@@ -1384,7 +1391,12 @@
   zx_iommu_desc_dummy_t desc;
   auto final_bti_check = vmo_test::CreateDeferredBtiCheck(bti);
 
-  ASSERT_OK(zx::iommu::create(RootResource(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
+  zx::result<zx::resource> result =
+      maybe_standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+
+  ASSERT_OK(zx::iommu::create(iommu_resource, ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
   ASSERT_NO_FAILURES(bti =
                          vmo_test::CreateNamedBti(iommu, 0, 0xdeadbeef, "PinBeforeCreateFailure"));
 
@@ -1407,8 +1419,9 @@
 }
 
 TEST_F(VmoClone2TestCase, PinClonePages) {
-  if (!RootResource()) {
-    printf("Root resource not available, skipping\n");
+  zx::unowned_resource system_resource = maybe_standalone::GetSystemResource();
+  if (!system_resource->is_valid()) {
+    printf("System resource not available, skipping\n");
     return;
   }
 
@@ -1416,7 +1429,12 @@
   zx::iommu iommu;
   zx::bti bti;
   zx_iommu_desc_dummy_t desc;
-  ASSERT_OK(zx::iommu::create(RootResource(), ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
+
+  zx::result<zx::resource> result =
+      maybe_standalone::GetSystemResourceWithBase(system_resource, ZX_RSRC_SYSTEM_IOMMU_BASE);
+  ASSERT_OK(result.status_value());
+  zx::resource iommu_resource = std::move(result.value());
+  ASSERT_OK(zx::iommu::create(iommu_resource, ZX_IOMMU_TYPE_DUMMY, &desc, sizeof(desc), &iommu));
   ASSERT_NO_FAILURES(bti = vmo_test::CreateNamedBti(iommu, 0, 0xdeadbeef, "PinClonePages"));
   auto final_bti_check = vmo_test::CreateDeferredBtiCheck(bti);
 
@@ -1639,8 +1657,9 @@
   } while (0)
 #endif
 
-// This is a regression test for https://fxbug.dev/42133843 and checks that if both children of a hidden parent
-// are dropped 'at the same time', then there are no races with their parallel destruction.
+// This is a regression test for https://fxbug.dev/42133843 and checks that if both children of a
+// hidden parent are dropped 'at the same time', then there are no races with their parallel
+// destruction.
 TEST_F(VmoClone2TestCase, DropChildrenInParallel) {
   // Try some N times and hope that if there is a bug we get the right timing. Prior to fixing
   // https://fxbug.dev/42133843 this was enough iterations to reliably trigger.
@@ -1764,11 +1783,11 @@
   EXPECT_EQ(kNumPages * zx_system_get_page_size(), info.populated_bytes);
 }
 
-// Regression test for https://fxbug.dev/42080199. The hierarchy generation count was previously incremented
-// in the VmObjectPaged destructor, not in the VmCowPages destructor. But the actual changes to the
-// page list take place in the VmCowPages destructor, which would affect attribution counts. We drop
-// the lock between invoking the two destructors, so it was possible for someone to query the
-// attribution count in between and see an old cached count.
+// Regression test for https://fxbug.dev/42080199. The hierarchy generation count was previously
+// incremented in the VmObjectPaged destructor, not in the VmCowPages destructor. But the actual
+// changes to the page list take place in the VmCowPages destructor, which would affect attribution
+// counts. We drop the lock between invoking the two destructors, so it was possible for someone to
+// query the attribution count in between and see an old cached count.
 TEST_F(VmoClone2TestCase, DropParentCommittedBytes) {
   // Try some N times and hope that if there is a bug we get the right timing. Prior to fixing
   // https://fxbug.dev/42080199 this was enough iterations to reliably trigger.
diff --git a/zircon/system/utest/device-enumeration/boards/vim3.cc b/zircon/system/utest/device-enumeration/boards/vim3.cc
index f5270d2..514655d 100644
--- a/zircon/system/utest/device-enumeration/boards/vim3.cc
+++ b/zircon/system/utest/device-enumeration/boards/vim3.cc
@@ -42,8 +42,8 @@
       "sys/platform/05:06:d/display/amlogic-display/display-coordinator",
       "sys/platform/05:06:1d",  // pwm
       "sys/platform/05:06:1d/aml-pwm-device/pwm-4/pwm_init",
-      "sys/platform/05:06:1d/aml-pwm-device/pwm-9/vreg/pwm-0-regulator",
-      "sys/platform/05:06:1d/aml-pwm-device/pwm-9/vreg/pwm-9-regulator",
+      "sys/platform/05:06:1d/aml-pwm-device/pwm-0/vreg-0/pwm-0-regulator",
+      "sys/platform/05:06:1d/aml-pwm-device/pwm-9/vreg-9/pwm-9-regulator",
       "sys/platform/05:06:26/aml-power-impl-composite",
       "sys/platform/05:06:26/aml-power-impl-composite/power-impl/pd_big_core",
       "sys/platform/05:06:26/aml-power-impl-composite/power-impl/pd_little_core",
diff --git a/zircon/system/utest/fpu/fputest.c b/zircon/system/utest/fpu/fputest.c
index 35bc1fa..2d1b267 100644
--- a/zircon/system/utest/fpu/fputest.c
+++ b/zircon/system/utest/fpu/fputest.c
@@ -16,6 +16,8 @@
 #define THREAD_COUNT 8
 #define ITER 1000000
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 /* expected double bit pattern for each thread */
 static const uint64_t expected[THREAD_COUNT] = {
     0x4284755ed4188b3e, 0x4284755ed6cb84c0, 0x4284755ed97e7dd3, 0x4284755edc317770,
@@ -34,18 +36,18 @@
 
   /* do a bunch of work with floating point to test context switching */
   a[0] = *val;
-  for (i = 1; i < countof(a); i++) {
+  for (i = 1; i < ARRAY_SIZE(a); i++) {
     a[i] = a[i - 1] * 1.01;
   }
 
   for (i = 0; i < ITER; i++) {
     a[0] += i;
-    for (j = 1; j < countof(a); j++) {
+    for (j = 1; j < ARRAY_SIZE(a); j++) {
       a[j] += a[j - 1] * 0.00001;
     }
   }
 
-  *val = a[countof(a) - 1];
+  *val = a[ARRAY_SIZE(a) - 1];
   return 0;
 }
 
@@ -54,17 +56,17 @@
 
   /* test lazy fpu load on separate thread */
   thrd_t t[THREAD_COUNT];
-  double val[countof(t)];
+  double val[ARRAY_SIZE(t)];
   char name[ZX_MAX_NAME_LEN];
 
-  printf("creating %zu floating point threads\n", countof(t));
-  for (unsigned int i = 0; i < countof(t); i++) {
+  printf("creating %zu floating point threads\n", ARRAY_SIZE(t));
+  for (unsigned int i = 0; i < ARRAY_SIZE(t); i++) {
     val[i] = i;
     snprintf(name, sizeof(name), "fpu thread %u", i);
     thrd_create_with_name(&t[i], float_thread, &val[i], name);
   }
 
-  for (unsigned int i = 0; i < countof(t); i++) {
+  for (unsigned int i = 0; i < ARRAY_SIZE(t); i++) {
     thrd_join(t[i], NULL);
     void* v = &val[i];
     uint64_t int64_val = *(uint64_t*)v;
diff --git a/zircon/system/utest/stdio/stdio.c b/zircon/system/utest/stdio/stdio.c
index 4027b05..22b8e88 100644
--- a/zircon/system/utest/stdio/stdio.c
+++ b/zircon/system/utest/stdio/stdio.c
@@ -19,6 +19,8 @@
 
 #include "util.h"
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
 TEST(StdioTests, stdio_pipe_test) {
   int fds[2];
   ASSERT_EQ(pipe(fds), 0, "pipe creation failed");
@@ -77,7 +79,7 @@
 
   // Start the process
   zx_handle_t p = tu_launch_process(job_copy, "pipe_stdio_test", 1, &file, 0, NULL,
-                                    countof(handles), handles, handle_ids);
+                                    ARRAY_SIZE(handles), handles, handle_ids);
   ASSERT_NE(p, ZX_HANDLE_INVALID, "process handle != 0");
 
   // Read the stdio
@@ -137,9 +139,9 @@
     ASSERT_NOT_NULL(f, "tmpfile failed");
 
     pthread_t threads[100];
-    ThreadData thread_data[countof(threads)];
+    ThreadData thread_data[ARRAY_SIZE(threads)];
 
-    for (size_t i = 0; i < countof(threads); ++i) {
+    for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
       ThreadData* data = &thread_data[i];
       data->f = f;
       data->index = i;
@@ -148,7 +150,7 @@
       ASSERT_EQ(err, 0, "pthread_create");
     }
 
-    for (size_t i = 0; i < countof(threads); ++i) {
+    for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
       int err = pthread_join(threads[i], NULL);
       ASSERT_EQ(err, 0, "pthread_join");
     }
diff --git a/zircon/third_party/tools/android/gki/generate_gki_certificate.py b/zircon/third_party/tools/android/gki/generate_gki_certificate.py
new file mode 100644
index 0000000..ad695bd
--- /dev/null
+++ b/zircon/third_party/tools/android/gki/generate_gki_certificate.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env fuchsia-vendored-python
+#
+# Copyright 2021, The Android Open Source Project
+#
+# 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.
+#
+"""Generate a Generic Boot Image certificate suitable for VTS verification."""
+from argparse import ArgumentParser
+import shlex
+import subprocess
+def generate_gki_certificate(image, avbtool, name, algorithm, key, salt,
+                             additional_avb_args, output):
+    """Shell out to avbtool to generate a GKI certificate."""
+    # Need to specify a value of --partition_size for avbtool to work.
+    # We use 64 MB below, but avbtool will not resize the boot image to
+    # this size because --do_not_append_vbmeta_image is also specified.
+    avbtool_cmd = [
+        avbtool, 'add_hash_footer',
+        '--partition_name', name,
+        '--partition_size', str(64 * 1024 * 1024),
+        '--image', image,
+        '--algorithm', algorithm,
+        '--key', key,
+        '--do_not_append_vbmeta_image',
+        '--output_vbmeta_image', output,
+    ]
+    if salt is not None:
+        avbtool_cmd += ['--salt', salt]
+    avbtool_cmd += additional_avb_args
+    subprocess.check_call(avbtool_cmd)
+def parse_cmdline():
+    parser = ArgumentParser(add_help=True)
+    # Required args.
+    parser.add_argument('image', help='path to the image')
+    parser.add_argument('-o', '--output', required=True,
+                        help='output certificate file name')
+    parser.add_argument('--name', required=True,
+                        choices=['boot', 'generic_kernel'],
+                        help='name of the image to be certified')
+    parser.add_argument('--algorithm', required=True,
+                        help='AVB signing algorithm')
+    parser.add_argument('--key', required=True,
+                        help='path to the RSA private key')
+    # Optional args.
+    parser.add_argument('--avbtool', default='avbtool',
+                        help='path to the avbtool executable')
+    parser.add_argument('--salt', help='salt to use when computing image hash')
+    parser.add_argument('--additional_avb_args', default=[], action='append',
+                        help='additional arguments to be forwarded to avbtool')
+    args = parser.parse_args()
+    additional_avb_args = []
+    for a in args.additional_avb_args:
+        additional_avb_args.extend(shlex.split(a))
+    args.additional_avb_args = additional_avb_args
+    return args
+def main():
+    args = parse_cmdline()
+    generate_gki_certificate(
+        image=args.image, avbtool=args.avbtool, name=args.name,
+        algorithm=args.algorithm, key=args.key, salt=args.salt,
+        additional_avb_args=args.additional_avb_args,
+        output=args.output,
+    )
+if __name__ == '__main__':
+    main()
diff --git a/zircon/third_party/tools/android/mkbootimg b/zircon/third_party/tools/android/mkbootimg
index 12da888..1f51229 100755
--- a/zircon/third_party/tools/android/mkbootimg
+++ b/zircon/third_party/tools/android/mkbootimg
@@ -1,4 +1,5 @@
 #!/usr/bin/env fuchsia-vendored-python
+#
 # Copyright 2015, The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,13 +13,48 @@
 # 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.
-from __future__ import print_function
-from argparse import ArgumentParser, FileType, Action
+"""Creates the boot image."""
+from argparse import (ArgumentParser, ArgumentTypeError,
+                      FileType, RawDescriptionHelpFormatter)
 from hashlib import sha1
 from os import fstat
-import re
 from struct import pack
+import array
+import collections
+import os
+import re
+import tempfile
+from gki.generate_gki_certificate import generate_gki_certificate
+
+# Constant and structure definition is in
+# system/tools/mkbootimg/include/bootimg/bootimg.h
+BOOT_MAGIC = 'ANDROID!'
+BOOT_MAGIC_SIZE = 8
+BOOT_NAME_SIZE = 16
+BOOT_ARGS_SIZE = 512
+BOOT_EXTRA_ARGS_SIZE = 1024
+BOOT_IMAGE_HEADER_V1_SIZE = 1648
+BOOT_IMAGE_HEADER_V2_SIZE = 1660
+BOOT_IMAGE_HEADER_V3_SIZE = 1580
 BOOT_IMAGE_HEADER_V3_PAGESIZE = 4096
+BOOT_IMAGE_HEADER_V4_SIZE = 1584
+BOOT_IMAGE_V4_SIGNATURE_SIZE = 4096
+VENDOR_BOOT_MAGIC = 'VNDRBOOT'
+VENDOR_BOOT_MAGIC_SIZE = 8
+VENDOR_BOOT_NAME_SIZE = BOOT_NAME_SIZE
+VENDOR_BOOT_ARGS_SIZE = 2048
+VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2112
+VENDOR_BOOT_IMAGE_HEADER_V4_SIZE = 2128
+VENDOR_RAMDISK_TYPE_NONE = 0
+VENDOR_RAMDISK_TYPE_PLATFORM = 1
+VENDOR_RAMDISK_TYPE_RECOVERY = 2
+VENDOR_RAMDISK_TYPE_DLKM = 3
+VENDOR_RAMDISK_NAME_SIZE = 32
+VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE = 16
+VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE = 108
+# Names with special meaning, mustn't be specified in --ramdisk_name.
+VENDOR_RAMDISK_NAME_BLOCKLIST = {b'default'}
+PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT = '--vendor_ramdisk_fragment'
 def filesize(f):
     if f is None:
         return 0
@@ -38,77 +74,124 @@
     f.write(pack(str(pad) + 'x'))
 def get_number_of_pages(image_size, page_size):
     """calculates the number of pages required for the image"""
-    return (image_size + page_size - 1) / page_size
+    return (image_size + page_size - 1) // page_size
 def get_recovery_dtbo_offset(args):
     """calculates the offset of recovery_dtbo image in the boot image"""
     num_header_pages = 1 # header occupies a page
     num_kernel_pages = get_number_of_pages(filesize(args.kernel), args.pagesize)
-    num_ramdisk_pages = get_number_of_pages(filesize(args.ramdisk), args.pagesize)
+    num_ramdisk_pages = get_number_of_pages(filesize(args.ramdisk),
+                                            args.pagesize)
     num_second_pages = get_number_of_pages(filesize(args.second), args.pagesize)
     dtbo_offset = args.pagesize * (num_header_pages + num_kernel_pages +
                                    num_ramdisk_pages + num_second_pages)
     return dtbo_offset
-def write_header_v3(args):
-    BOOT_IMAGE_HEADER_V3_SIZE = 1596
-    BOOT_MAGIC = 'ANDROID!'.encode()
-    args.output.write(pack('8s', BOOT_MAGIC))
-    args.output.write(pack(
-        '4I',
-        filesize(args.kernel),                          # kernel size in bytes
-        filesize(args.ramdisk),                         # ramdisk size in bytes
-        (args.os_version << 11) | args.os_patch_level,  # os version and patch level
-        BOOT_IMAGE_HEADER_V3_SIZE))
-    args.output.write(pack('4I', 0, 0, 0, 0))           # reserved
-    args.output.write(pack('I', args.header_version))   # version of bootimage header
-    args.output.write(pack('1536s', args.cmdline.encode()))
+def should_add_legacy_gki_boot_signature(args):
+    if args.gki_signing_key and args.gki_signing_algorithm:
+        return True
+    return False
+def write_header_v3_and_above(args):
+    if args.header_version > 3:
+        boot_header_size = BOOT_IMAGE_HEADER_V4_SIZE
+    else:
+        boot_header_size = BOOT_IMAGE_HEADER_V3_SIZE
+    args.output.write(pack(f'{BOOT_MAGIC_SIZE}s', BOOT_MAGIC.encode()))
+    # kernel size in bytes
+    args.output.write(pack('I', filesize(args.kernel)))
+    # ramdisk size in bytes
+    args.output.write(pack('I', filesize(args.ramdisk)))
+    # os version and patch level
+    args.output.write(pack('I', (args.os_version << 11) | args.os_patch_level))
+    args.output.write(pack('I', boot_header_size))
+    # reserved
+    args.output.write(pack('4I', 0, 0, 0, 0))
+    # version of boot image header
+    args.output.write(pack('I', args.header_version))
+    args.output.write(pack(f'{BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE}s',
+                           args.cmdline))
+    if args.header_version >= 4:
+        # The signature used to verify boot image v4.
+        boot_signature_size = 0
+        if should_add_legacy_gki_boot_signature(args):
+            boot_signature_size = BOOT_IMAGE_V4_SIGNATURE_SIZE
+        args.output.write(pack('I', boot_signature_size))
     pad_file(args.output, BOOT_IMAGE_HEADER_V3_PAGESIZE)
 def write_vendor_boot_header(args):
-    VENDOR_BOOT_IMAGE_HEADER_V3_SIZE = 2108
-    BOOT_MAGIC = 'VNDRBOOT'.encode()
-    args.vendor_boot.write(pack('8s', BOOT_MAGIC))
-    if filesize(args.vendor_ramdisk) == 0:
-        raise ValueError("Vendor ramdisk image must not be empty.")
-    args.vendor_boot.write(pack(
-        '5I',
-        args.header_version,                            # version of header
-        args.pagesize,                                  # flash page size we assume
-        args.base + args.kernel_offset,                 # kernel physical load addr
-        args.base + args.ramdisk_offset,                # ramdisk physical load addr
-        filesize(args.vendor_ramdisk)))                 # vendor ramdisk size in bytes
-    args.vendor_boot.write(pack('2048s', args.vendor_cmdline.encode()))
-    args.vendor_boot.write(pack('I', args.base + args.tags_offset)) # physical addr for kernel tags
-    args.vendor_boot.write(pack('16s', args.board.encode())) # asciiz product name
-    args.vendor_boot.write(pack('I', VENDOR_BOOT_IMAGE_HEADER_V3_SIZE)) # header size in bytes
-    if filesize(args.dtb) == 0:
-        raise ValueError("DTB image must not be empty.")
-    args.vendor_boot.write(pack('I', filesize(args.dtb)))   # size in bytes
-    args.vendor_boot.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
+    if args.header_version > 3:
+        vendor_ramdisk_size = args.vendor_ramdisk_total_size
+        vendor_boot_header_size = VENDOR_BOOT_IMAGE_HEADER_V4_SIZE
+    else:
+        vendor_ramdisk_size = filesize(args.vendor_ramdisk)
+        vendor_boot_header_size = VENDOR_BOOT_IMAGE_HEADER_V3_SIZE
+    args.vendor_boot.write(pack(f'{VENDOR_BOOT_MAGIC_SIZE}s',
+                                VENDOR_BOOT_MAGIC.encode()))
+    # version of boot image header
+    args.vendor_boot.write(pack('I', args.header_version))
+    # flash page size
+    args.vendor_boot.write(pack('I', args.pagesize))
+    # kernel physical load address
+    args.vendor_boot.write(pack('I', args.base + args.kernel_offset))
+    # ramdisk physical load address
+    args.vendor_boot.write(pack('I', args.base + args.ramdisk_offset))
+    # ramdisk size in bytes
+    args.vendor_boot.write(pack('I', vendor_ramdisk_size))
+    args.vendor_boot.write(pack(f'{VENDOR_BOOT_ARGS_SIZE}s',
+                                args.vendor_cmdline))
+    # kernel tags physical load address
+    args.vendor_boot.write(pack('I', args.base + args.tags_offset))
+    # asciiz product name
+    args.vendor_boot.write(pack(f'{VENDOR_BOOT_NAME_SIZE}s', args.board))
+    # header size in bytes
+    args.vendor_boot.write(pack('I', vendor_boot_header_size))
+    # dtb size in bytes
+    args.vendor_boot.write(pack('I', filesize(args.dtb)))
+    # dtb physical load address
+    args.vendor_boot.write(pack('Q', args.base + args.dtb_offset))
+    if args.header_version > 3:
+        vendor_ramdisk_table_size = (args.vendor_ramdisk_table_entry_num *
+                                     VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE)
+        # vendor ramdisk table size in bytes
+        args.vendor_boot.write(pack('I', vendor_ramdisk_table_size))
+        # number of vendor ramdisk table entries
+        args.vendor_boot.write(pack('I', args.vendor_ramdisk_table_entry_num))
+        # vendor ramdisk table entry size in bytes
+        args.vendor_boot.write(pack('I', VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE))
+        # bootconfig section size in bytes
+        args.vendor_boot.write(pack('I', filesize(args.vendor_bootconfig)))
     pad_file(args.vendor_boot, args.pagesize)
 def write_header(args):
-    BOOT_IMAGE_HEADER_V1_SIZE = 1648
-    BOOT_IMAGE_HEADER_V2_SIZE = 1660
-    BOOT_MAGIC = 'ANDROID!'.encode()
-    if args.header_version > 3:
-        raise ValueError('Boot header version %d not supported' % args.header_version)
-    elif args.header_version == 3:
-        return write_header_v3(args)
-    args.output.write(pack('8s', BOOT_MAGIC))
-    final_ramdisk_offset = (args.base + args.ramdisk_offset) if filesize(args.ramdisk) > 0 else 0
-    final_second_offset = (args.base + args.second_offset) if filesize(args.second) > 0 else 0
-    args.output.write(pack(
-        '10I',
-        filesize(args.kernel),                          # size in bytes
-        args.base + args.kernel_offset,                 # physical load addr
-        filesize(args.ramdisk),                         # size in bytes
-        final_ramdisk_offset,                           # physical load addr
-        filesize(args.second),                          # size in bytes
-        final_second_offset,                            # physical load addr
-        args.base + args.tags_offset,                   # physical addr for kernel tags
-        args.pagesize,                                  # flash page size we assume
-        args.header_version,                            # version of bootimage header
-        (args.os_version << 11) | args.os_patch_level)) # os version and patch level
-    args.output.write(pack('16s', args.board.encode())) # asciiz product name
-    args.output.write(pack('512s', args.cmdline[:512].encode()))
+    if args.header_version > 4:
+        raise ValueError(
+            f'Boot header version {args.header_version} not supported')
+    if args.header_version in {3, 4}:
+        return write_header_v3_and_above(args)
+    ramdisk_load_address = ((args.base + args.ramdisk_offset)
+                            if filesize(args.ramdisk) > 0 else 0)
+    second_load_address = ((args.base + args.second_offset)
+                           if filesize(args.second) > 0 else 0)
+    args.output.write(pack(f'{BOOT_MAGIC_SIZE}s', BOOT_MAGIC.encode()))
+    # kernel size in bytes
+    args.output.write(pack('I', filesize(args.kernel)))
+    # kernel physical load address
+    args.output.write(pack('I', args.base + args.kernel_offset))
+    # ramdisk size in bytes
+    args.output.write(pack('I', filesize(args.ramdisk)))
+    # ramdisk physical load address
+    args.output.write(pack('I', ramdisk_load_address))
+    # second bootloader size in bytes
+    args.output.write(pack('I', filesize(args.second)))
+    # second bootloader physical load address
+    args.output.write(pack('I', second_load_address))
+    # kernel tags physical load address
+    args.output.write(pack('I', args.base + args.tags_offset))
+    # flash page size
+    args.output.write(pack('I', args.pagesize))
+    # version of boot image header
+    args.output.write(pack('I', args.header_version))
+    # os version and patch level
+    args.output.write(pack('I', (args.os_version << 11) | args.os_patch_level))
+    # asciiz product name
+    args.output.write(pack(f'{BOOT_NAME_SIZE}s', args.board))
+    args.output.write(pack(f'{BOOT_ARGS_SIZE}s', args.cmdline))
     sha = sha1()
     update_sha(sha, args.kernel)
     update_sha(sha, args.ramdisk)
@@ -119,13 +202,17 @@
         update_sha(sha, args.dtb)
     img_id = pack('32s', sha.digest())
     args.output.write(img_id)
-    args.output.write(pack('1024s', args.cmdline[512:].encode()))
+    args.output.write(pack(f'{BOOT_EXTRA_ARGS_SIZE}s', args.extra_cmdline))
     if args.header_version > 0:
-        args.output.write(pack('I', filesize(args.recovery_dtbo)))   # size in bytes
         if args.recovery_dtbo:
-            args.output.write(pack('Q', get_recovery_dtbo_offset(args))) # recovery dtbo offset
+            # recovery dtbo size in bytes
+            args.output.write(pack('I', filesize(args.recovery_dtbo)))
+            # recovert dtbo offset in the boot image
+            args.output.write(pack('Q', get_recovery_dtbo_offset(args)))
         else:
-            args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo
+            # Set to zero if no recovery dtbo
+            args.output.write(pack('I', 0))
+            args.output.write(pack('Q', 0))
     # Populate boot image header size for header versions 1 and 2.
     if args.header_version == 1:
         args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE))
@@ -133,23 +220,83 @@
         args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))
     if args.header_version > 1:
         if filesize(args.dtb) == 0:
-            raise ValueError("DTB image must not be empty.")
-        args.output.write(pack('I', filesize(args.dtb)))   # size in bytes
-        args.output.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
+            raise ValueError('DTB image must not be empty.')
+        # dtb size in bytes
+        args.output.write(pack('I', filesize(args.dtb)))
+        # dtb physical load address
+        args.output.write(pack('Q', args.base + args.dtb_offset))
     pad_file(args.output, args.pagesize)
     return img_id
-class ValidateStrLenAction(Action):
-    def __init__(self, option_strings, dest, nargs=None, **kwargs):
-        if 'maxlen' not in kwargs:
-            raise ValueError('maxlen must be set')
-        self.maxlen = int(kwargs['maxlen'])
-        del kwargs['maxlen']
-        super(ValidateStrLenAction, self).__init__(option_strings, dest, **kwargs)
-    def __call__(self, parser, namespace, values, option_string=None):
-        if len(values) > self.maxlen:
+class AsciizBytes:
+    """Parses a string and encodes it as an asciiz bytes object.
+    >>> AsciizBytes(bufsize=4)('foo')
+    b'foo\\x00'
+    >>> AsciizBytes(bufsize=4)('foob')
+    Traceback (most recent call last):
+        ...
+    argparse.ArgumentTypeError: Encoded asciiz length exceeded: max 4, got 5
+    """
+    def __init__(self, bufsize):
+        self.bufsize = bufsize
+    def __call__(self, arg):
+        arg_bytes = arg.encode() + b'\x00'
+        if len(arg_bytes) > self.bufsize:
+            raise ArgumentTypeError(
+                'Encoded asciiz length exceeded: '
+                f'max {self.bufsize}, got {len(arg_bytes)}')
+        return arg_bytes
+class VendorRamdiskTableBuilder:
+    """Vendor ramdisk table builder.
+    Attributes:
+        entries: A list of VendorRamdiskTableEntry namedtuple.
+        ramdisk_total_size: Total size in bytes of all ramdisks in the table.
+    """
+    VendorRamdiskTableEntry = collections.namedtuple(  # pylint: disable=invalid-name
+        'VendorRamdiskTableEntry',
+        ['ramdisk_path', 'ramdisk_size', 'ramdisk_offset', 'ramdisk_type',
+         'ramdisk_name', 'board_id'])
+    def __init__(self):
+        self.entries = []
+        self.ramdisk_total_size = 0
+        self.ramdisk_names = set()
+    def add_entry(self, ramdisk_path, ramdisk_type, ramdisk_name, board_id):
+        # Strip any trailing null for simple comparison.
+        stripped_ramdisk_name = ramdisk_name.rstrip(b'\x00')
+        if stripped_ramdisk_name in VENDOR_RAMDISK_NAME_BLOCKLIST:
             raise ValueError(
-                'String argument too long: max {0:d}, got {1:d}'.format(self.maxlen, len(values)))
-        setattr(namespace, self.dest, values)
+                f'Banned vendor ramdisk name: {stripped_ramdisk_name}')
+        if stripped_ramdisk_name in self.ramdisk_names:
+            raise ValueError(
+                f'Duplicated vendor ramdisk name: {stripped_ramdisk_name}')
+        self.ramdisk_names.add(stripped_ramdisk_name)
+        if board_id is None:
+            board_id = array.array(
+                'I', [0] * VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)
+        else:
+            board_id = array.array('I', board_id)
+        if len(board_id) != VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE:
+            raise ValueError('board_id size must be '
+                             f'{VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE}')
+        with open(ramdisk_path, 'rb') as f:
+            ramdisk_size = filesize(f)
+        self.entries.append(self.VendorRamdiskTableEntry(
+            ramdisk_path, ramdisk_size, self.ramdisk_total_size, ramdisk_type,
+            ramdisk_name, board_id))
+        self.ramdisk_total_size += ramdisk_size
+    def write_ramdisks_padded(self, fout, alignment):
+        for entry in self.entries:
+            with open(entry.ramdisk_path, 'rb') as f:
+                fout.write(f.read())
+        pad_file(fout, alignment)
+    def write_entries_padded(self, fout, alignment):
+        for entry in self.entries:
+            fout.write(pack('I', entry.ramdisk_size))
+            fout.write(pack('I', entry.ramdisk_offset))
+            fout.write(pack('I', entry.ramdisk_type))
+            fout.write(pack(f'{VENDOR_RAMDISK_NAME_SIZE}s',
+                            entry.ramdisk_name))
+            fout.write(entry.board_id)
+        pad_file(fout, alignment)
 def write_padded_file(f_out, f_in, padding):
     if f_in is None:
         return
@@ -173,7 +320,7 @@
         return (a << 14) | (b << 7) | c
     return 0
 def parse_os_patch_level(x):
-    match = re.search(r'^(\d{4})-(\d{2})-(\d{2})', x)
+    match = re.search(r'^(\d{4})-(\d{2})(?:-(\d{2}))?', x)
     if match:
         y = int(match.group(1)) - 2000
         m = int(match.group(2))
@@ -182,47 +329,195 @@
         assert 0 < m <= 12
         return (y << 4) | m
     return 0
+def parse_vendor_ramdisk_type(x):
+    type_dict = {
+        'none': VENDOR_RAMDISK_TYPE_NONE,
+        'platform': VENDOR_RAMDISK_TYPE_PLATFORM,
+        'recovery': VENDOR_RAMDISK_TYPE_RECOVERY,
+        'dlkm': VENDOR_RAMDISK_TYPE_DLKM,
+    }
+    if x.lower() in type_dict:
+        return type_dict[x.lower()]
+    return parse_int(x)
+def get_vendor_boot_v4_usage():
+    return """vendor boot version 4 arguments:
+  --ramdisk_type {none,platform,recovery,dlkm}
+                        specify the type of the ramdisk
+  --ramdisk_name NAME
+                        specify the name of the ramdisk
+  --board_id{0..15} NUMBER
+                        specify the value of the board_id vector, defaults to 0
+  --vendor_ramdisk_fragment VENDOR_RAMDISK_FILE
+                        path to the vendor ramdisk file
+  These options can be specified multiple times, where each vendor ramdisk
+  option group ends with a --vendor_ramdisk_fragment option.
+  Each option group appends an additional ramdisk to the vendor boot image.
+"""
+def parse_vendor_ramdisk_args(args, args_list):
+    """Parses vendor ramdisk specific arguments.
+    Args:
+        args: An argparse.Namespace object. Parsed results are stored into this
+            object.
+        args_list: A list of argument strings to be parsed.
+    Returns:
+        A list argument strings that are not parsed by this method.
+    """
+    parser = ArgumentParser(add_help=False)
+    parser.add_argument('--ramdisk_type', type=parse_vendor_ramdisk_type,
+                        default=VENDOR_RAMDISK_TYPE_NONE)
+    parser.add_argument('--ramdisk_name',
+                        type=AsciizBytes(bufsize=VENDOR_RAMDISK_NAME_SIZE),
+                        required=True)
+    for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE):
+        parser.add_argument(f'--board_id{i}', type=parse_int, default=0)
+    parser.add_argument(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT, required=True)
+    unknown_args = []
+    vendor_ramdisk_table_builder = VendorRamdiskTableBuilder()
+    if args.vendor_ramdisk is not None:
+        vendor_ramdisk_table_builder.add_entry(
+            args.vendor_ramdisk.name, VENDOR_RAMDISK_TYPE_PLATFORM, b'', None)
+    while PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT in args_list:
+        idx = args_list.index(PARSER_ARGUMENT_VENDOR_RAMDISK_FRAGMENT) + 2
+        vendor_ramdisk_args = args_list[:idx]
+        args_list = args_list[idx:]
+        ramdisk_args, extra_args = parser.parse_known_args(vendor_ramdisk_args)
+        ramdisk_args_dict = vars(ramdisk_args)
+        unknown_args.extend(extra_args)
+        ramdisk_path = ramdisk_args.vendor_ramdisk_fragment
+        ramdisk_type = ramdisk_args.ramdisk_type
+        ramdisk_name = ramdisk_args.ramdisk_name
+        board_id = [ramdisk_args_dict[f'board_id{i}']
+                    for i in range(VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE)]
+        vendor_ramdisk_table_builder.add_entry(ramdisk_path, ramdisk_type,
+                                               ramdisk_name, board_id)
+    if len(args_list) > 0:
+        unknown_args.extend(args_list)
+    args.vendor_ramdisk_total_size = (vendor_ramdisk_table_builder
+                                      .ramdisk_total_size)
+    args.vendor_ramdisk_table_entry_num = len(vendor_ramdisk_table_builder
+                                              .entries)
+    args.vendor_ramdisk_table_builder = vendor_ramdisk_table_builder
+    return unknown_args
 def parse_cmdline():
-    parser = ArgumentParser()
-    parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'))
-    parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
-    parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
-    parser.add_argument('--dtb', help='path to dtb', type=FileType('rb'))
-    recovery_dtbo_group = parser.add_mutually_exclusive_group()
-    recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO',
-                                     type=FileType('rb'))
-    recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
-                                     type=FileType('rb'), metavar='RECOVERY_ACPIO',
-                                     dest='recovery_dtbo')
-    parser.add_argument('--cmdline', help='extra arguments to be passed on the '
-                        'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536)
+    version_parser = ArgumentParser(add_help=False)
+    version_parser.add_argument('--header_version', type=parse_int, default=0)
+    if version_parser.parse_known_args()[0].header_version < 3:
+        # For boot header v0 to v2, the kernel commandline field is split into
+        # two fields, cmdline and extra_cmdline. Both fields are asciiz strings,
+        # so we minus one here to ensure the encoded string plus the
+        # null-terminator can fit in the buffer size.
+        cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 1
+    else:
+        cmdline_size = BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE
+    parser = ArgumentParser(formatter_class=RawDescriptionHelpFormatter,
+                            epilog=get_vendor_boot_v4_usage())
+    parser.add_argument('--kernel', type=FileType('rb'),
+                        help='path to the kernel')
+    parser.add_argument('--ramdisk', type=FileType('rb'),
+                        help='path to the ramdisk')
+    parser.add_argument('--second', type=FileType('rb'),
+                        help='path to the second bootloader')
+    parser.add_argument('--dtb', type=FileType('rb'), help='path to the dtb')
+    dtbo_group = parser.add_mutually_exclusive_group()
+    dtbo_group.add_argument('--recovery_dtbo', type=FileType('rb'),
+                            help='path to the recovery DTBO')
+    dtbo_group.add_argument('--recovery_acpio', type=FileType('rb'),
+                            metavar='RECOVERY_ACPIO', dest='recovery_dtbo',
+                            help='path to the recovery ACPIO')
+    parser.add_argument('--cmdline', type=AsciizBytes(bufsize=cmdline_size),
+                        default='', help='kernel command line arguments')
     parser.add_argument('--vendor_cmdline',
-                        help='kernel command line arguments contained in vendor boot',
-                        default='', action=ValidateStrLenAction, maxlen=2048)
-    parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000)
-    parser.add_argument('--kernel_offset', help='kernel offset', type=parse_int, default=0x00008000)
-    parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int,
-                        default=0x01000000)
-    parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
-                        default=0x00f00000)
-    parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000)
-    parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
-                        default=0)
-    parser.add_argument('--os_patch_level', help='operating system patch level',
-                        type=parse_os_patch_level, default=0)
-    parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100)
-    parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction,
-                        maxlen=16)
-    parser.add_argument('--pagesize', help='page size', type=parse_int,
-                        choices=[2**i for i in range(11, 15)], default=2048)
-    parser.add_argument('--id', help='print the image ID on standard output',
-                        action='store_true')
-    parser.add_argument('--header_version', help='boot image header version', type=parse_int,
-                        default=0)
-    parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'))
-    parser.add_argument('--vendor_boot', help='vendor boot output file name', type=FileType('wb'))
-    parser.add_argument('--vendor_ramdisk', help='path to the vendor ramdisk', type=FileType('rb'))
-    return parser.parse_args()
+                        type=AsciizBytes(bufsize=VENDOR_BOOT_ARGS_SIZE),
+                        default='',
+                        help='vendor boot kernel command line arguments')
+    parser.add_argument('--base', type=parse_int, default=0x10000000,
+                        help='base address')
+    parser.add_argument('--kernel_offset', type=parse_int, default=0x00008000,
+                        help='kernel offset')
+    parser.add_argument('--ramdisk_offset', type=parse_int, default=0x01000000,
+                        help='ramdisk offset')
+    parser.add_argument('--second_offset', type=parse_int, default=0x00f00000,
+                        help='second bootloader offset')
+    parser.add_argument('--dtb_offset', type=parse_int, default=0x01f00000,
+                        help='dtb offset')
+    parser.add_argument('--os_version', type=parse_os_version, default=0,
+                        help='operating system version')
+    parser.add_argument('--os_patch_level', type=parse_os_patch_level,
+                        default=0, help='operating system patch level')
+    parser.add_argument('--tags_offset', type=parse_int, default=0x00000100,
+                        help='tags offset')
+    parser.add_argument('--board', type=AsciizBytes(bufsize=BOOT_NAME_SIZE),
+                        default='', help='board name')
+    parser.add_argument('--pagesize', type=parse_int,
+                        choices=[2**i for i in range(11, 15)], default=2048,
+                        help='page size')
+    parser.add_argument('--id', action='store_true',
+                        help='print the image ID on standard output')
+    parser.add_argument('--header_version', type=parse_int, default=0,
+                        help='boot image header version')
+    parser.add_argument('-o', '--output', type=FileType('wb'),
+                        help='output file name')
+    parser.add_argument('--vendor_boot', type=FileType('wb'),
+                        help='vendor boot output file name')
+    parser.add_argument('--vendor_ramdisk', type=FileType('rb'),
+                        help='path to the vendor ramdisk')
+    parser.add_argument('--vendor_bootconfig', type=FileType('rb'),
+                        help='path to the vendor bootconfig file')
+    gki_2_0_signing_args = parser.add_argument_group(
+        '[DEPRECATED] GKI 2.0 signing arguments')
+    gki_2_0_signing_args.add_argument(
+        '--gki_signing_algorithm', help='GKI signing algorithm to use')
+    gki_2_0_signing_args.add_argument(
+        '--gki_signing_key', help='path to RSA private key file')
+    gki_2_0_signing_args.add_argument(
+        '--gki_signing_signature_args', default='',
+        help='other hash arguments passed to avbtool')
+    gki_2_0_signing_args.add_argument(
+        '--gki_signing_avbtool_path', default='avbtool',
+        help='path to avbtool for boot signature generation')
+    args, extra_args = parser.parse_known_args()
+    if args.vendor_boot is not None and args.header_version > 3:
+        extra_args = parse_vendor_ramdisk_args(args, extra_args)
+    if len(extra_args) > 0:
+        raise ValueError(f'Unrecognized arguments: {extra_args}')
+    if args.header_version < 3:
+        args.extra_cmdline = args.cmdline[BOOT_ARGS_SIZE-1:]
+        args.cmdline = args.cmdline[:BOOT_ARGS_SIZE-1] + b'\x00'
+        assert len(args.cmdline) <= BOOT_ARGS_SIZE
+        assert len(args.extra_cmdline) <= BOOT_EXTRA_ARGS_SIZE
+    return args
+def add_boot_image_signature(args, pagesize):
+    """Adds the boot image signature.
+    Note that the signature will only be verified in VTS to ensure a
+    generic boot.img is used. It will not be used by the device
+    bootloader at boot time. The bootloader should only verify
+    the boot vbmeta at the end of the boot partition (or in the top-level
+    vbmeta partition) via the Android Verified Boot process, when the
+    device boots.
+    """
+    # Flush the buffer for signature calculation.
+    args.output.flush()
+    # Outputs the signed vbmeta to a separate file, then append to boot.img
+    # as the boot signature.
+    with tempfile.TemporaryDirectory() as temp_out_dir:
+        boot_signature_output = os.path.join(temp_out_dir, 'boot_signature')
+        generate_gki_certificate(
+            image=args.output.name, avbtool=args.gki_signing_avbtool_path,
+            name='boot', algorithm=args.gki_signing_algorithm,
+            key=args.gki_signing_key, salt='d00df00d',
+            additional_avb_args=args.gki_signing_signature_args.split(),
+            output=boot_signature_output,
+        )
+        with open(boot_signature_output, 'rb') as boot_signature:
+            boot_signature_bytes = boot_signature.read()
+            if len(boot_signature_bytes) > BOOT_IMAGE_V4_SIGNATURE_SIZE:
+                raise ValueError(
+                    f'boot sigature size is > {BOOT_IMAGE_V4_SIGNATURE_SIZE}')
+            boot_signature_bytes += b'\x00' * (
+                BOOT_IMAGE_V4_SIGNATURE_SIZE - len(boot_signature_bytes))
+            assert len(boot_signature_bytes) == BOOT_IMAGE_V4_SIGNATURE_SIZE
+            args.output.write(boot_signature_bytes)
+            pad_file(args.output, pagesize)
 def write_data(args, pagesize):
     write_padded_file(args.output, args.kernel, pagesize)
     write_padded_file(args.output, args.ramdisk, pagesize)
@@ -231,33 +526,39 @@
         write_padded_file(args.output, args.recovery_dtbo, pagesize)
     if args.header_version == 2:
         write_padded_file(args.output, args.dtb, pagesize)
+    if args.header_version >= 4 and should_add_legacy_gki_boot_signature(args):
+        add_boot_image_signature(args, pagesize)
 def write_vendor_boot_data(args):
-    write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
-    write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
+    if args.header_version > 3:
+        builder = args.vendor_ramdisk_table_builder
+        builder.write_ramdisks_padded(args.vendor_boot, args.pagesize)
+        write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
+        builder.write_entries_padded(args.vendor_boot, args.pagesize)
+        write_padded_file(args.vendor_boot, args.vendor_bootconfig,
+            args.pagesize)
+    else:
+        write_padded_file(args.vendor_boot, args.vendor_ramdisk, args.pagesize)
+        write_padded_file(args.vendor_boot, args.dtb, args.pagesize)
 def main():
     args = parse_cmdline()
     if args.vendor_boot is not None:
-        if args.header_version < 3:
-            raise ValueError('--vendor_boot not compatible with given header version')
-        if args.vendor_ramdisk is None:
+        if args.header_version not in {3, 4}:
+            raise ValueError(
+                '--vendor_boot not compatible with given header version')
+        if args.header_version == 3 and args.vendor_ramdisk is None:
             raise ValueError('--vendor_ramdisk missing or invalid')
         write_vendor_boot_header(args)
         write_vendor_boot_data(args)
-        return
     if args.output is not None:
-        if args.kernel is None:
-            raise ValueError('kernel must be supplied when creating a boot image')
         if args.second is not None and args.header_version > 2:
-            raise ValueError('--second not compatible with given header version')
+            raise ValueError(
+                '--second not compatible with given header version')
         img_id = write_header(args)
         if args.header_version > 2:
             write_data(args, BOOT_IMAGE_HEADER_V3_PAGESIZE)
         else:
             write_data(args, args.pagesize)
         if args.id and img_id is not None:
-            # Python 2's struct.pack returns a string, but py3 returns bytes.
-            if isinstance(img_id, str):
-                img_id = [ord(x) for x in img_id]
-            print('0x' + ''.join('{:02x}'.format(c) for c in img_id))
+            print('0x' + ''.join(f'{octet:02x}' for octet in img_id))
 if __name__ == '__main__':
     main()
diff --git a/zircon/vdso/BUILD.gn b/zircon/vdso/BUILD.gn
index a0ea438..55903f2 100644
--- a/zircon/vdso/BUILD.gn
+++ b/zircon/vdso/BUILD.gn
@@ -26,7 +26,7 @@
     "//zircon/tools/zither:tests",
   ]
 
-  platform = "fuchsia"
+  versioned = "fuchsia"
 
   sources = [
     "bti.fidl",
diff --git a/zircon/vdso/debuglog.fidl b/zircon/vdso/debuglog.fidl
index b3af9e1..76fbcdd 100644
--- a/zircon/vdso/debuglog.fidl
+++ b/zircon/vdso/debuglog.fidl
@@ -35,7 +35,7 @@
     ///
     /// ## Rights
     ///
-    /// *resource* must have resource kind `ZX_RSRC_KIND_ROOT`.
+    /// *resource* must have resource kind `ZX_RSRC_KIND_SYSTEM` and base `ZX_RSRC_SYSTEM_DEBUGLOG_BASE`.
     ///
     /// ## Return value
     ///
@@ -48,17 +48,14 @@
     ///
     /// `ZX_ERR_INVALID_ARGS`  *options* contained a value not understood by the kernel
     ///
-    /// `ZX_ERR_WRONG_TYPE`  *resource* was not of the kind `ZX_RSRC_KIND_ROOT`.
+    /// `ZX_ERR_WRONG_TYPE`  *resource* was not of the kind `ZX_RSRC_KIND_SYSTEM` and base `ZX_RSRC_SYSTEM_DEBUGLOG_BASE`.
     ///
     /// `ZX_ERR_NO_MEMORY`  Failure due to lack of memory.
     ///
     /// ## See also
     ///
-    ///  - [`zx_debuglog_read()`]
-    ///  - [`zx_debuglog_write()`]
-    ///
-    /// [`zx_debuglog_read()`]: debuglog_read.md
-    /// [`zx_debuglog_write()`]: debuglog_write.md
+    ///  - [`zx_debuglog_read()`](https://fuchsia.dev/reference/syscalls/debuglog_read)
+    ///  - [`zx_debuglog_write()`](https://fuchsia.dev/reference/syscalls/debuglog_write)
     strict Create(resource struct {
         resource Handle:RESOURCE;
         options uint32;
@@ -119,13 +116,9 @@
     ///
     ///  - [`fuchsia.boot.WriteOnlyLog`](https://fuchsia.dev/reference/fidl/fuchsia.boot#WriteOnlyLog)
     ///
-    ///  - [`zx_debug_write()`]
-    ///  - [`zx_debuglog_create()`]
-    ///  - [`zx_debuglog_read()`]
-    ///
-    /// [`zx_debug_write()`]: debug_write.md
-    /// [`zx_debuglog_create()`]: debuglog_create.md
-    /// [`zx_debuglog_read()`]: debuglog_read.md
+    ///  - [`zx_debug_write()`](https://fuchsia.dev/reference/syscalls/debug_write)
+    ///  - [`zx_debuglog_create()`](https://fuchsia.dev/reference/syscalls/debuglog_create)
+    ///  - [`zx_debuglog_read()`](https://fuchsia.dev/reference/syscalls/debuglog_read)
     strict Write(resource struct {
         handle Handle:LOG;
         options uint32;
@@ -229,11 +222,8 @@
     ///
     ///  - [`fuchsia.boot.ReadOnlyLog`](https://fuchsia.dev/reference/fidl/fuchsia.boot#ReadOnlyLog)
     ///
-    ///  - [`zx_debuglog_create()`]
-    ///  - [`zx_debuglog_write()`]
-    ///
-    /// [`zx_debuglog_create()`]: debuglog_create.md
-    /// [`zx_debuglog_write()`]: debuglog_write.md
+    ///  - [`zx_debuglog_create()`](https://fuchsia.dev/reference/syscalls/debuglog_create)
+    ///  - [`zx_debuglog_write()`](https://fuchsia.dev/reference/syscalls/debuglog_write)
     strict Read(resource struct {
         handle Handle:LOG;
         options uint32;
diff --git a/zircon/vdso/zx/BUILD.gn b/zircon/vdso/zx/BUILD.gn
index ef4e0ba..be3e059 100644
--- a/zircon/vdso/zx/BUILD.gn
+++ b/zircon/vdso/zx/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/fidl/fidl.gni")
 
 fidl("zx") {
-  platform = "fuchsia"
+  versioned = "fuchsia"
 
   sources = [
     "../overview.fidl",