[release] Snap to 552ae29174
Change-Id: Ia7689e5e591bb85e17071ff4e2dae621a1b038ad
diff --git a/build/cpp/BUILD.gn b/build/cpp/BUILD.gn
index f3a37ec..9c86bc3 100644
--- a/build/cpp/BUILD.gn
+++ b/build/cpp/BUILD.gn
@@ -386,6 +386,8 @@
     "//src/ui/input/drivers/gt6853:gt6853-test",
     "//src/ui/input/drivers/hid-input-report:driver-internals",
     "//src/ui/input/drivers/hid-input-report:hid-input-report-test-bin",
+    "//src/ui/input/drivers/pc-ps2:pc-ps2-driver",
+    "//src/ui/input/drivers/pc-ps2:pc-ps2-tests-bin",
     "//src/ui/input/drivers/virtio:virtio-input-test",
     "//src/ui/input/lib/hid-input-report",
     "//src/ui/input/lib/hid-input-report:lib-hid-input-report-test",
diff --git a/build/fidl/BUILD.gn b/build/fidl/BUILD.gn
index 41640b8..fa76c90 100644
--- a/build/fidl/BUILD.gn
+++ b/build/fidl/BUILD.gn
@@ -37,13 +37,16 @@
   script = "//scripts/generate-fidl-project.py"
   deps = [ "//:generated_sources" ]
 
-  inputs = [ "$root_build_dir/generated_sources.json" ]
-  outputs = [ "$root_build_dir/fidl_project.json" ]
+  _input = "$root_build_dir/generated_sources.json"
+  _output = "$root_build_dir/fidl_project.json"
+
+  inputs = [ _input ]
+  outputs = [ _output ]
 
   args = [
-    rebase_path("//"),
-    rebase_path("$root_build_dir/generated_sources.json"),
-    rebase_path("$root_build_dir/fidl_project.json"),
+    rebase_path("//", root_build_dir),
+    rebase_path(_input, root_build_dir),
+    rebase_path(_output, root_build_dir),
   ]
 }
 
diff --git a/build/rust/rustc_binary.gni b/build/rust/rustc_binary.gni
index 0e95b04..d71f0a3 100644
--- a/build/rust/rustc_binary.gni
+++ b/build/rust/rustc_binary.gni
@@ -11,16 +11,11 @@
 #
 #   output_name (optional)
 #     Name of the output file. Also used as the crate name of the binary,
-#     except the crate name has dashes replaced with underscores.
-#
-#     Defaults to an underscore-translated version of target name
-#     (see http://fxbug.dev/64100).
+#     except the crate name has dashes replaced with underscores. If not
+#     specified, it defaults to the target name.
 #
 #   name (optional, deprecated)
-#     Deprecated version of output_name.  If not specified, it is
-#     assumed to be the same as the target name.  Unlike output_name, all
-#     dashes will be replaced with underscores in both the output file name
-#     and the crate name.
+#     Deprecated version of output_name.
 #
 #   output_dir (optional)
 #     Directory that the resulting binary should be placed in.
@@ -73,8 +68,8 @@
 #
 #   with_unit_tests (optional)
 #     Builds unit tests associated with the binary. This will create a
-#     `<name_underscored>_bin_test` test file in the output directory, and a
-#     new GN target called <name>_test.
+#     `<output_name_underscored>_bin_test` test file in the output directory,
+#     and a new GN target called <name>_test.
 #     Equivalent to adding a `rustc_test` target with that name and the same
 #     source_root.
 #
@@ -155,29 +150,21 @@
   # use the target name unless another name is specified
   assert(!(defined(invoker.output_name) && defined(invoker.name)),
          "Only one of output_name and name may be specified.")
-  package_name = target_name
+  _output_name = target_name
   if (defined(invoker.output_name)) {
-    package_name = invoker.output_name
+    _output_name = invoker.output_name
   } else if (defined(invoker.name)) {
-    package_name = invoker.name
+    _output_name = invoker.name
   }
 
   # rustc does not support dashes in crate names
-  _crate_name = string_replace(package_name, "-", "_")
-  if (defined(invoker.output_name)) {
-    _output_name = invoker.output_name
-  } else {
-    assert(
-        _crate_name == package_name,
-        "rustc_binary will soon change to allow binaries with `-` in the name. To disambiguate in the meantime, please set output_name fxbug.dev/64100")
-    _output_name = _crate_name
-  }
+  _crate_name = string_replace(_output_name, "-", "_")
 
   # if "with_unit_tests" is set to true, generate an additional rust test target
   # TODO(https://fxbug.dev/72931): accept a string.
   if (defined(invoker.with_unit_tests) && invoker.with_unit_tests == true) {
     rustc_test_internal("${target_name}_test") {
-      output_name = "${package_name}_bin_test"
+      output_name = "${_output_name}_bin_test"
 
       if (defined(invoker.test_args)) {
         args = invoker.test_args
diff --git a/docs/development/components/structured_config.md b/docs/development/components/structured_config.md
index 8057763..b8b828c 100644
--- a/docs/development/components/structured_config.md
+++ b/docs/development/components/structured_config.md
@@ -1,10 +1,5 @@
 # Structured Configuration
 
-Caution: Structured configuration is an experimental, allowlisted feature. Its behavior and APIs
-are subject to change. The allowlist will be removed when the feature does not require active
-guidance from the Component Framework team. Follow [this bug][remove-allowlist-bug] for updates.
-If you encounter bugs, please file them against our [Monorail component][file-monorail-bug]!
-
 Structured configuration allows C++/Rust components to declare configuration schemas directly in
 their manifest. Benefits of using structured configuration include:
 
@@ -13,6 +8,7 @@
 * Components read their configuration with statically-typed libraries.
 * Component Framework only starts components with valid configuration.
 * Configuration can be viewed at runtime with `ffx` tooling.
+* Values can be set at runtime in tests with RealmBuilder.
 
 To use structured configuration in your component, you must update build rules, declare a schema,
 define values, and generate a client library.
@@ -20,17 +16,13 @@
 ## Update build rules
 
 To prevent cyclic dependencies when generating client libraries, define a
-`fuchsia_component_manifest` rule that compiles the component manifest. Add `structured_config` as
-a restricted feature for this manifest. Pass this compiled manifest GN label into the
-`fuchsia_component` rule.
+`fuchsia_component_manifest` rule that compiles the component manifest. Pass this compiled manifest
+GN label into the `fuchsia_component` rule.
 
 ```gn
 {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/config/cpp/BUILD.gn" region_tag="component" adjust_indentation="auto" %}
 ```
 
-Because structured config is an [experimental feature][restricted-features],
-these GN build rules must be added to the allowlist in [`//tools/cmc/build/restricted_features/BUILD.gn`][restricted-features-build-gn]
-
 ## Declare configuration schema
 
 You must declare a configuration schema in a component's manifest. Structured config supports
@@ -234,9 +226,5 @@
 
 Realm Builder validates the replaced value against the component's configuration schema.
 
-[remove-allowlist-bug]: https://fxbug.dev/95369
-[file-monorail-bug]: https://bugs.fuchsia.dev/p/fuchsia/issues/entry?components=ComponentFramework%3EStructuredConfig&labels=ComponentFeedback
-[restricted-features]: /docs/development/components/build.md#restricted-features
-[restricted-features-build-gn]: https://cs.opensource.google/fuchsia/fuchsia/+/main:/tools/cmc/build/restricted_features/BUILD.gn
 [cml-ref-doc]: https://fuchsia.dev/reference/cml#config
-[rb-feature-matrix]: /docs/development/testing/components/realm_builder.md#language-feature-matrix
\ No newline at end of file
+[rb-feature-matrix]: /docs/development/testing/components/realm_builder.md#language-feature-matrix
diff --git a/examples/assembly/structured_config/configured_by_assembly/BUILD.gn b/examples/assembly/structured_config/configured_by_assembly/BUILD.gn
index 4e36dc2..b3a6f95 100644
--- a/examples/assembly/structured_config/configured_by_assembly/BUILD.gn
+++ b/examples/assembly/structured_config/configured_by_assembly/BUILD.gn
@@ -12,7 +12,6 @@
 
 fuchsia_component("to_configure") {
   manifest = "meta/to_configure.cml"
-  restricted_features = [ "structured_config" ]
   deps = [ ":bin" ]
 }
 
diff --git a/examples/components/config/cpp/BUILD.gn b/examples/components/config/cpp/BUILD.gn
index 4efbe1d..3175c77 100644
--- a/examples/components/config/cpp/BUILD.gn
+++ b/examples/components/config/cpp/BUILD.gn
@@ -39,7 +39,6 @@
 fuchsia_component_manifest("manifest") {
   component_name = "config_example"
   manifest = "meta/config_example.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("component") {
diff --git a/examples/components/config/cpp/main.cc b/examples/components/config/cpp/main.cc
index 099f1f3..c244691 100644
--- a/examples/components/config/cpp/main.cc
+++ b/examples/components/config/cpp/main.cc
@@ -16,7 +16,7 @@
 int main(int argc, const char* argv[], char* envp[]) {
   // [START get_config]
   // Retrieve configuration
-  auto c = example_config::Config::from_args();
+  auto c = example_config::Config::TakeFromStartupHandle();
   // [END get_config]
 
   // Print greeting to the log
@@ -28,7 +28,8 @@
   // Record configuration to inspect
   auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
   sys::ComponentInspector inspector(context.get());
-  c.record_to_inspect(inspector.inspector());
+  inspect::Node config_node = inspector.root().CreateChild("config");
+  c.RecordInspect(&config_node);
   // [END inspect]
 
   loop.Run();
diff --git a/examples/components/config/rust/BUILD.gn b/examples/components/config/rust/BUILD.gn
index 262d01a..969709f 100644
--- a/examples/components/config/rust/BUILD.gn
+++ b/examples/components/config/rust/BUILD.gn
@@ -41,7 +41,6 @@
 fuchsia_component_manifest("manifest") {
   component_name = "config_example"
   manifest = "meta/config_example.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("component") {
diff --git a/scripts/memory/testdata/.gitattributes b/scripts/memory/testdata/.gitattributes
new file mode 100644
index 0000000..587b786
--- /dev/null
+++ b/scripts/memory/testdata/.gitattributes
@@ -0,0 +1 @@
+*.json -diff
diff --git a/sdk/fidl/fuchsia.input.report/device_ids.fidl b/sdk/fidl/fuchsia.input.report/device_ids.fidl
index c80c6d5..1b4766b 100644
--- a/sdk/fidl/fuchsia.input.report/device_ids.fidl
+++ b/sdk/fidl/fuchsia.input.report/device_ids.fidl
@@ -20,6 +20,8 @@
     /// Below are the non-HID VendorIds
     FOCALTECH_TOUCHSCREEN = 0x00010001;
     AMS_LIGHT_SENSOR = 0x00010002;
+    PC_PS2_KEYBOARD = 0x00010003;
+    PC_PS2_MOUSE = 0x00010004;
     GOLDFISH_ACCELERATION_SENSOR = 0x901D0001;
     GOLDFISH_GYROSCOPE_SENSOR = 0x901D0002;
     GOLDFISH_RGBC_LIGHT_SENSOR = 0x901D0003;
diff --git a/sdk/fidl/fuchsia.input.report/fuchsia.input.report.api b/sdk/fidl/fuchsia.input.report/fuchsia.input.report.api
index 9a588d5..a9d20b9 100644
--- a/sdk/fidl/fuchsia.input.report/fuchsia.input.report.api
+++ b/sdk/fidl/fuchsia.input.report/fuchsia.input.report.api
@@ -1,3 +1,3 @@
 {
-  "fidl/fuchsia.input.report": "b8d588c18fba7d16de534263d942f229"
+  "fidl/fuchsia.input.report": "cf37e186a595e877463f2653482b0995"
 }
\ No newline at end of file
diff --git a/sdk/fidl/fuchsia.input.report/fuchsia.input.report.api_summary b/sdk/fidl/fuchsia.input.report/fuchsia.input.report.api_summary
index fa5b168..48e373b 100644
--- a/sdk/fidl/fuchsia.input.report/fuchsia.input.report.api_summary
+++ b/sdk/fidl/fuchsia.input.report/fuchsia.input.report.api_summary
@@ -233,6 +233,8 @@
 enum/member fuchsia.input.report/VendorGoogleProductId.GOLDFISH_ACCELERATION_SENSOR 2417819649
 enum/member fuchsia.input.report/VendorGoogleProductId.GOLDFISH_GYROSCOPE_SENSOR 2417819650
 enum/member fuchsia.input.report/VendorGoogleProductId.GOLDFISH_RGBC_LIGHT_SENSOR 2417819651
+enum/member fuchsia.input.report/VendorGoogleProductId.PC_PS2_KEYBOARD 65539
+enum/member fuchsia.input.report/VendorGoogleProductId.PC_PS2_MOUSE 65540
 strict enum fuchsia.input.report/VendorGoogleProductId uint32
 enum/member fuchsia.input.report/VendorId.GOOGLE 6353
 strict enum fuchsia.input.report/VendorId uint32
diff --git a/sdk/fidl/fuchsia.pkg/repo.fidl b/sdk/fidl/fuchsia.pkg/repo.fidl
index 2db77fa..01ace17 100644
--- a/sdk/fidl/fuchsia.pkg/repo.fidl
+++ b/sdk/fidl/fuchsia.pkg/repo.fidl
@@ -89,10 +89,7 @@
     /// The repository mirrors that serve the package contents. Required.
     3: mirrors vector<MirrorConfig>;
 
-    /// The package URL of the system update package. Optional.
-    ///
-    /// Only used for the fuchsia-pkg://fuchsia.com/ repo.
-    4: update_package_url string;
+    4: reserved; // Formerly update_package_url string;
 
     /// The initial trusted root metadata version. Optional, if absent presumed
     /// to be 1.
diff --git a/sdk/fidl/fuchsia.ui.pointer/touch.fidl b/sdk/fidl/fuchsia.ui.pointer/touch.fidl
index 1f35460..e479bc7 100644
--- a/sdk/fidl/fuchsia.ui.pointer/touch.fidl
+++ b/sdk/fidl/fuchsia.ui.pointer/touch.fidl
@@ -45,7 +45,9 @@
     /// server. Responses for *previous* events are fed to the server on the
     /// *next* call of |Watch| [1]. Each element in the |responses| vector is
     /// interpreted as the pairwise response to the event in the previous
-    /// |events| vector; the vector lengths must match.
+    /// |events| vector; the vector lengths must match. Note that the client's
+    /// contract to respond to events starts as soon as it registers its
+    /// endpoint with scenic, NOT when it first calls `Watch()`.
     ///
     /// Initial response. The first call to |Watch| must be an empty vector.
     ///
diff --git a/sdk/lib/sys/component/cpp/testing/realm_builder.cc b/sdk/lib/sys/component/cpp/testing/realm_builder.cc
index 9b514f0..d8a8797 100644
--- a/sdk/lib/sys/component/cpp/testing/realm_builder.cc
+++ b/sdk/lib/sys/component/cpp/testing/realm_builder.cc
@@ -137,6 +137,20 @@
   return *this;
 }
 
+void Realm::ReplaceComponentDecl(const std::string& child_name,
+                                 fuchsia::component::decl::Component decl) {
+  fuchsia::component::test::Realm_ReplaceComponentDecl_Result result;
+  ZX_COMPONENT_ASSERT_STATUS_AND_RESULT_OK(
+      "Realm/ReplaceComponentDecl",
+      realm_proxy_->ReplaceComponentDecl(child_name, std::move(decl), &result), result);
+}
+
+void Realm::ReplaceRealmDecl(fuchsia::component::decl::Component decl) {
+  fuchsia::component::test::Realm_ReplaceRealmDecl_Result result;
+  ZX_COMPONENT_ASSERT_STATUS_AND_RESULT_OK(
+      "Realm/ReplaceRealmDecl", realm_proxy_->ReplaceRealmDecl(std::move(decl), &result), result);
+}
+
 fuchsia::component::decl::Component Realm::GetComponentDecl(const std::string& child_name) {
   fuchsia::component::test::Realm_GetComponentDecl_Result result;
   ZX_COMPONENT_ASSERT_STATUS_AND_RESULT_OK(
@@ -268,6 +282,15 @@
   return *this;
 }
 
+void RealmBuilder::ReplaceComponentDecl(const std::string& child_name,
+                                        fuchsia::component::decl::Component decl) {
+  root_.ReplaceComponentDecl(child_name, std::move(decl));
+}
+
+void RealmBuilder::ReplaceRealmDecl(fuchsia::component::decl::Component decl) {
+  root_.ReplaceRealmDecl(std::move(decl));
+}
+
 fuchsia::component::decl::Component RealmBuilder::GetComponentDecl(const std::string& child_name) {
   return root_.GetComponentDecl(child_name);
 }
diff --git a/sdk/lib/sys/component/cpp/testing/realm_builder.h b/sdk/lib/sys/component/cpp/testing/realm_builder.h
index 74df96a..dc045be 100644
--- a/sdk/lib/sys/component/cpp/testing/realm_builder.h
+++ b/sdk/lib/sys/component/cpp/testing/realm_builder.h
@@ -153,6 +153,13 @@
   /// Replaces the value of a given configuration field
   Realm& ReplaceConfigValue(const std::string& name, const std::string& key, ConfigValue value);
 
+  /// Updates the Component decl of the given child.
+  void ReplaceComponentDecl(const std::string& child_name,
+                            fuchsia::component::decl::Component decl);
+
+  /// Updates the Component decl of this Realm.
+  void ReplaceRealmDecl(fuchsia::component::decl::Component decl);
+
   /// Fetches the Component decl of the given child.
   fuchsia::component::decl::Component GetComponentDecl(const std::string& child_name);
 
@@ -225,6 +232,13 @@
   RealmBuilder& ReplaceConfigValue(const std::string& name, const std::string& key,
                                    ConfigValue value);
 
+  /// Updates the Component decl of the given child of the root realm.
+  void ReplaceComponentDecl(const std::string& child_name,
+                            fuchsia::component::decl::Component decl);
+
+  /// Updates the Component decl of this root realm.
+  void ReplaceRealmDecl(fuchsia::component::decl::Component decl);
+
   /// Fetches the Component decl of the given child of the root realm.
   fuchsia::component::decl::Component GetComponentDecl(const std::string& child_name);
 
diff --git a/sdk/lib/sys/component/cpp/testing/sys_component_cpp_testing.api b/sdk/lib/sys/component/cpp/testing/sys_component_cpp_testing.api
index 006e2da..aa4871e 100644
--- a/sdk/lib/sys/component/cpp/testing/sys_component_cpp_testing.api
+++ b/sdk/lib/sys/component/cpp/testing/sys_component_cpp_testing.api
@@ -3,7 +3,7 @@
   "pkg/sys_component_cpp_testing/include/lib/sys/component/cpp/testing/internal/errors.h": "462366e266790bf56fc020f5231d59ef",
   "pkg/sys_component_cpp_testing/include/lib/sys/component/cpp/testing/internal/local_component_runner.h": "c64e16d6d13ddec60edc5dfd9c94fdb2",
   "pkg/sys_component_cpp_testing/include/lib/sys/component/cpp/testing/internal/realm.h": "8d8150024af382008ebca0fe86269056",
-  "pkg/sys_component_cpp_testing/include/lib/sys/component/cpp/testing/realm_builder.h": "291d073a5f2e1fa0428f482a68c827e3",
+  "pkg/sys_component_cpp_testing/include/lib/sys/component/cpp/testing/realm_builder.h": "ef351ec83dd243c5ff4c2bb4b3e2b17a",
   "pkg/sys_component_cpp_testing/include/lib/sys/component/cpp/testing/realm_builder_types.h": "48b9496b801a18bdf26939b21e398305",
   "pkg/sys_component_cpp_testing/include/lib/sys/component/cpp/testing/scoped_child.h": "9186348509c271f0e88ba6a288d8aaf1"
 }
\ No newline at end of file
diff --git a/sdk/lib/sys/component/cpp/tests/BUILD.gn b/sdk/lib/sys/component/cpp/tests/BUILD.gn
index 7807811f..e58e64c 100644
--- a/sdk/lib/sys/component/cpp/tests/BUILD.gn
+++ b/sdk/lib/sys/component/cpp/tests/BUILD.gn
@@ -129,7 +129,6 @@
   testonly = true
   component_name = "echo_server_sc"
   manifest = "meta/echo_server_sc.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("echo_server_sc") {
diff --git a/sdk/lib/sys/component/cpp/tests/echo_server.cc b/sdk/lib/sys/component/cpp/tests/echo_server.cc
index 151b6e8..7e3d9f5 100644
--- a/sdk/lib/sys/component/cpp/tests/echo_server.cc
+++ b/sdk/lib/sys/component/cpp/tests/echo_server.cc
@@ -7,17 +7,20 @@
 #include "lib/async-loop/cpp/loop.h"
 #include "lib/async-loop/default.h"
 #include "lib/fidl/cpp/binding_set.h"
+#include "lib/fidl/cpp/string.h"
 #include "lib/sys/cpp/component_context.h"
 #include "src/lib/fxl/command_line.h"
 #include "test/placeholders/cpp/fidl.h"
 
 class EchoServer : public test::placeholders::Echo {
  public:
+  explicit EchoServer(const std::string& default_reply) : default_reply_(default_reply) {}
+
   void EchoString(::fidl::StringPtr value, EchoStringCallback callback) override {
-    std::string intercept = value.value_or("");
-    callback(std::move(value));
+    std::string reply = value.value_or(default_reply_);
+    callback(fidl::StringPtr(reply));
     if (listener_) {
-      listener_(std::move(intercept));
+      listener_(std::move(reply));
     }
   }
 
@@ -28,6 +31,8 @@
   void SetListener(fit::function<void(std::string)> list) { listener_ = std::move(list); }
 
  private:
+  std::string default_reply_;
+
   fidl::BindingSet<test::placeholders::Echo> bindings_;
   fit::function<void(std::string)> listener_;
 };
@@ -35,8 +40,15 @@
 int main(int argc, const char** argv) {
   std::cout << "Starting echo server." << std::endl;
   async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
+
+  std::string default_reply = "UNSET";
+  if (argc > 1) {
+    default_reply = argv[1];
+  }
+  std::cout << "Default reply set to '" << default_reply << "'" << std::endl;
+  std::unique_ptr<EchoServer> echo_server = std::make_unique<EchoServer>(default_reply);
+
   auto startup = sys::ComponentContext::CreateAndServeOutgoingDirectory();
-  std::unique_ptr<EchoServer> echo_server = std::make_unique<EchoServer>();
   startup->outgoing()->AddPublicService(echo_server->GetHandler());
   loop.Run();
 
diff --git a/sdk/lib/sys/component/cpp/tests/echo_server_sc.cc b/sdk/lib/sys/component/cpp/tests/echo_server_sc.cc
index a95aa47..a6a62a5 100644
--- a/sdk/lib/sys/component/cpp/tests/echo_server_sc.cc
+++ b/sdk/lib/sys/component/cpp/tests/echo_server_sc.cc
@@ -93,7 +93,7 @@
 };
 
 int main(int argc, const char** argv) {
-  auto c = echo_server_config_lib::Config::from_args();
+  auto c = echo_server_config_lib::Config::TakeFromStartupHandle();
   std::cout << "Starting echo server." << std::endl;
   async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
   auto startup = sys::ComponentContext::CreateAndServeOutgoingDirectory();
diff --git a/sdk/lib/sys/component/cpp/tests/realm_builder_test.cc b/sdk/lib/sys/component/cpp/tests/realm_builder_test.cc
index 7eb01b0..b5a299d 100644
--- a/sdk/lib/sys/component/cpp/tests/realm_builder_test.cc
+++ b/sdk/lib/sys/component/cpp/tests/realm_builder_test.cc
@@ -6,6 +6,7 @@
 #include <fcntl.h>
 #include <fuchsia/component/cpp/fidl.h>
 #include <fuchsia/component/decl/cpp/fidl.h>
+#include <fuchsia/data/cpp/fidl.h>
 #include <fuchsia/examples/cpp/fidl.h>
 #include <fuchsia/io/cpp/fidl.h>
 #include <fuchsia/logger/cpp/fidl.h>
@@ -17,6 +18,7 @@
 #include <lib/fidl/cpp/string.h>
 #include <lib/fit/function.h>
 #include <lib/gtest/real_loop_fixture.h>
+#include <lib/stdcompat/optional.h>
 #include <lib/sys/component/cpp/testing/realm_builder.h>
 #include <lib/sys/component/cpp/testing/realm_builder_types.h>
 #include <lib/sys/component/cpp/tests/utils.h>
@@ -435,6 +437,55 @@
 }
 
 // This test is similar to RealmBuilderTest.RoutesProtocolFromChild except
+// that its setup is done by mutating the realm's root's decl. This is to
+// assert that invoking |ReplaceRealmDecl| works as expected.
+TEST_F(RealmBuilderTest, RealmDeclCanBeReplaced) {
+  static constexpr char kEchoServer[] = "echo_server";
+
+  auto realm_builder = RealmBuilder::Create();
+  realm_builder.AddChild(kEchoServer, kEchoServerUrl);
+
+  auto decl = realm_builder.GetRealmDecl();
+  fdecl::ExposeProtocol expose_protocol;
+  expose_protocol.set_source(fdecl::Ref::WithChild(fdecl::ChildRef{.name = "echo_server"}));
+  expose_protocol.set_target(fdecl::Ref::WithParent(fdecl::ParentRef{}));
+  expose_protocol.set_source_name("test.placeholders.Echo");
+  expose_protocol.set_target_name("test.placeholders.Echo");
+  decl.mutable_exposes()->emplace_back(fdecl::Expose::WithProtocol(std::move(expose_protocol)));
+  realm_builder.ReplaceRealmDecl(std::move(decl));
+  auto realm = realm_builder.Build(dispatcher());
+
+  auto echo = realm.ConnectSync<test::placeholders::Echo>();
+  fidl::StringPtr response;
+  ASSERT_EQ(echo->EchoString("hello", &response), ZX_OK);
+  EXPECT_EQ(response, fidl::StringPtr("hello"));
+}
+
+TEST_F(RealmBuilderTest, ForwardsArgsToLegacyComponent) {
+  static constexpr char kEchoServer[] = "echo_server";
+  static constexpr char kExpectedReply[] = "test";
+
+  auto realm_builder = RealmBuilder::Create();
+  realm_builder.AddLegacyChild(kEchoServer, kEchoServerLegacyUrl);
+  realm_builder.AddRoute(Route{.capabilities = {Protocol{test::placeholders::Echo::Name_}},
+                               .source = ChildRef{kEchoServer},
+                               .targets = {ParentRef()}});
+  auto decl = realm_builder.GetComponentDecl(kEchoServer);
+  fuchsia::data::DictionaryEntry args;
+  auto value = std::make_unique<fuchsia::data::DictionaryValue>(
+      fuchsia::data::DictionaryValue::WithStrVec({kExpectedReply}));
+  args.key = "args", args.value = std::move(value);
+  decl.mutable_program()->mutable_info()->mutable_entries()->emplace_back(std::move(args));
+  realm_builder.ReplaceComponentDecl(kEchoServer, std::move(decl));
+
+  auto realm = realm_builder.Build(dispatcher());
+  auto echo = realm.ConnectSync<test::placeholders::Echo>();
+  fidl::StringPtr response;
+  ASSERT_EQ(echo->EchoString(cpp17::nullopt, &response), ZX_OK);
+  EXPECT_EQ(response, fidl::StringPtr(kExpectedReply));
+}
+
+// This test is similar to RealmBuilderTest.RoutesProtocolFromChild except
 // that its setup is done statically via a manifest. This is to assert that
 // invoking |CreateFromRelativeUrl| works as expected.
 TEST_F(RealmBuilderTest, BuildsRealmFromRelativeUrl) {
diff --git a/sdk/lib/virtualization/testing/fake_guest_vsock.cc b/sdk/lib/virtualization/testing/fake_guest_vsock.cc
index d530525..2f89fc1 100644
--- a/sdk/lib/virtualization/testing/fake_guest_vsock.cc
+++ b/sdk/lib/virtualization/testing/fake_guest_vsock.cc
@@ -5,6 +5,8 @@
 #include <lib/virtualization/testing/fake_guest_vsock.h>
 #include <lib/virtualization/testing/fake_host_vsock.h>
 
+#include "lib/fpromise/result.h"
+
 namespace guest {
 namespace testing {
 
@@ -36,5 +38,21 @@
   }
 }
 
+void FakeGuestVsock::AcceptConnection2FromHost(
+    uint32_t port, zx::socket client, zx::socket guest,
+    fuchsia::virtualization::HostVsockEndpoint::Connect2Callback callback) {
+  auto it = listeners_.find(port);
+  if (it == listeners_.end()) {
+    callback(fpromise::error(ZX_ERR_CONNECTION_REFUSED));
+  } else {
+    zx_status_t status = it->second(std::move(guest));
+    if (status == ZX_OK) {
+      callback(fpromise::ok(std::move(client)));
+    } else {
+      callback(fpromise::error(status));
+    }
+  }
+}
+
 }  // namespace testing
 }  // namespace guest
diff --git a/sdk/lib/virtualization/testing/fake_guest_vsock.h b/sdk/lib/virtualization/testing/fake_guest_vsock.h
index 465fe8c..36e6654 100644
--- a/sdk/lib/virtualization/testing/fake_guest_vsock.h
+++ b/sdk/lib/virtualization/testing/fake_guest_vsock.h
@@ -41,6 +41,9 @@
   void AcceptConnectionFromHost(
       uint32_t port, zx::handle handle,
       fuchsia::virtualization::HostVsockEndpoint::ConnectCallback callback);
+  void AcceptConnection2FromHost(
+      uint32_t port, zx::socket client, zx::socket guest,
+      fuchsia::virtualization::HostVsockEndpoint::Connect2Callback callback);
 
  private:
   FakeHostVsock* host_vsock_;
diff --git a/sdk/lib/virtualization/testing/fake_host_vsock.cc b/sdk/lib/virtualization/testing/fake_host_vsock.cc
index a3ec6b0..fea82cc 100644
--- a/sdk/lib/virtualization/testing/fake_host_vsock.cc
+++ b/sdk/lib/virtualization/testing/fake_host_vsock.cc
@@ -33,6 +33,17 @@
   guest_vsock_->AcceptConnectionFromHost(port, std::move(socket), std::move(callback));
 }
 
+void FakeHostVsock::Connect2(uint32_t port, Connect2Callback callback) {
+  zx::socket client, guest;
+  zx_status_t status = zx::socket::create(ZX_SOCKET_STREAM, &client, &guest);
+  if (status != ZX_OK) {
+    callback(fpromise::error(status));
+    return;
+  }
+  guest_vsock_->AcceptConnection2FromHost(port, std::move(client), std::move(guest),
+                                          std::move(callback));
+}
+
 zx_status_t FakeHostVsock::AcceptConnectionFromGuest(uint32_t port,
                                                      fit::function<void(zx::handle)> callback) {
   auto it = listeners_.find(port);
diff --git a/sdk/lib/virtualization/testing/fake_host_vsock.h b/sdk/lib/virtualization/testing/fake_host_vsock.h
index 15c9bd3..17fe7c9 100644
--- a/sdk/lib/virtualization/testing/fake_host_vsock.h
+++ b/sdk/lib/virtualization/testing/fake_host_vsock.h
@@ -33,6 +33,7 @@
               fidl::InterfaceHandle<fuchsia::virtualization::HostVsockAcceptor> acceptor,
               ListenCallback callback) override;
   void Connect(uint32_t cid, uint32_t port, zx::socket socket, ConnectCallback callback) override;
+  void Connect2(uint32_t port, Connect2Callback callback) override;
 
   FakeGuestVsock* guest_vsock_;
   fidl::BindingSet<fuchsia::virtualization::HostVsockEndpoint> bindings_;
diff --git a/sdk/lib/virtualization/testing/guest_cid.h b/sdk/lib/virtualization/testing/guest_cid.h
index c8e3793..35220c6 100644
--- a/sdk/lib/virtualization/testing/guest_cid.h
+++ b/sdk/lib/virtualization/testing/guest_cid.h
@@ -5,12 +5,14 @@
 #ifndef LIB_VIRTUALIZATION_TESTING_GUEST_CID_H_
 #define LIB_VIRTUALIZATION_TESTING_GUEST_CID_H_
 
+#include <fuchsia/virtualization/cpp/fidl.h>
+
 namespace guest {
 namespace testing {
 
-// This is typically '3' in production for the first guest. Use some alternate
-// value here to ensure we don't couple too tightly to that behavior.
-static constexpr uint32_t kGuestCid = 1234;
+// Only one guest is supported per (soon to be deprecated, see fxr/97355) host vsock, and it will
+// always use the default guest CID.
+constexpr uint32_t kGuestCid = fuchsia::virtualization::DEFAULT_GUEST_CID;
 
 }  // namespace testing
 }  // namespace guest
diff --git a/src/bringup/bin/console/BUILD.gn b/src/bringup/bin/console/BUILD.gn
index d94cf33..79c8152 100644
--- a/src/bringup/bin/console/BUILD.gn
+++ b/src/bringup/bin/console/BUILD.gn
@@ -8,7 +8,6 @@
 fuchsia_component_manifest("manifest") {
   component_name = "console"
   manifest = "meta/console.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_structured_config_cpp_elf_lib("console_config") {
diff --git a/src/bringup/bin/console/main.cc b/src/bringup/bin/console/main.cc
index 6929079..0fc43fd 100644
--- a/src/bringup/bin/console/main.cc
+++ b/src/bringup/bin/console/main.cc
@@ -79,7 +79,7 @@
   const auto boot_args_client = fidl::BindSyncClient(*std::move(boot_args));
 
   Options opts;
-  status = ParseArgs(console_config::Config::from_args(), boot_args_client, &opts);
+  status = ParseArgs(console_config::Config::TakeFromStartupHandle(), boot_args_client, &opts);
   if (status != ZX_OK) {
     return status;
   }
diff --git a/src/cobalt/bin/system-metrics/BUILD.gn b/src/cobalt/bin/system-metrics/BUILD.gn
index 76e412e..55fd4ba7 100644
--- a/src/cobalt/bin/system-metrics/BUILD.gn
+++ b/src/cobalt/bin/system-metrics/BUILD.gn
@@ -71,13 +71,8 @@
 }
 
 fuchsia_package_with_single_component("cobalt_system_metrics") {
-  manifest = "meta/cobalt_system_metrics.cmx"
-  deps = [
-    ":system-metrics",
-
-    # Configure sysmgr to start cobalt_system_metrics.cmx
-    "//src/sys/sysmgr:cobalt_system_metrics_config",
-  ]
+  manifest = "meta/cobalt_system_metrics.cml"
+  deps = [ ":system-metrics" ]
 }
 
 executable("cobalt_system_metrics_unittests") {
diff --git a/src/cobalt/bin/system-metrics/meta/cobalt_system_metrics.cml b/src/cobalt/bin/system-metrics/meta/cobalt_system_metrics.cml
new file mode 100644
index 0000000..6f8fa5a
--- /dev/null
+++ b/src/cobalt/bin/system-metrics/meta/cobalt_system_metrics.cml
@@ -0,0 +1,44 @@
+// 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/cobalt_system_metrics",
+    },
+    use: [
+        {
+            protocol: [
+                "fuchsia.cobalt.LoggerFactory",
+                "fuchsia.kernel.Stats",
+                "fuchsia.logger.LogSink",
+                "fuchsia.sysinfo.SysInfo",
+                "fuchsia.tracing.provider.Registry",
+                "fuchsia.ui.activity.Provider",
+            ],
+        },
+        {
+            storage: "data",
+            path: "/data",
+        },
+        {
+            directory: "config-data",
+            rights: [ "r*" ],
+            path: "/config/data",
+        },
+        {
+            directory: "dev-thermal",
+            rights: [ "r*" ],
+            path: "/dev/class/thermal",
+        },
+        {
+            directory: "dev-misc",
+            rights: [ "r*" ],
+            path: "/dev/misc",
+        },
+    ],
+}
diff --git a/src/connectivity/lib/internet-checksum/src/lib.rs b/src/connectivity/lib/internet-checksum/src/lib.rs
index 0a0b1b7..d0100ed 100644
--- a/src/connectivity/lib/internet-checksum/src/lib.rs
+++ b/src/connectivity/lib/internet-checksum/src/lib.rs
@@ -161,8 +161,6 @@
 // on other platforms.
 const SMALL_BUF_THRESHOLD: usize = 64;
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 /// The following macro unrolls operations on u16's to wider integers.
 ///
 /// # Arguments
diff --git a/src/connectivity/lib/packet-formats/src/macros.rs b/src/connectivity/lib/packet-formats/src/macros.rs
index ccef766..6af948e 100644
--- a/src/connectivity/lib/packet-formats/src/macros.rs
+++ b/src/connectivity/lib/packet-formats/src/macros.rs
@@ -226,8 +226,6 @@
     };
 }
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 /// Create an enum representing a protocol number (such as IP protocol or
 /// EtherType).
 ///
diff --git a/src/connectivity/lowpan/lib/spinel_pack/src/primitives.rs b/src/connectivity/lowpan/lib/spinel_pack/src/primitives.rs
index cc83508..b0c84d8 100644
--- a/src/connectivity/lowpan/lib/spinel_pack/src/primitives.rs
+++ b/src/connectivity/lowpan/lib/spinel_pack/src/primitives.rs
@@ -27,8 +27,6 @@
     }
 );
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 macro_rules! impl_try_pack_unpack_as_data(
     (u8) => {
         // We skip u8.
diff --git a/src/connectivity/network/netstack3/core/src/ip/gmp/mod.rs b/src/connectivity/network/netstack3/core/src/ip/gmp/mod.rs
index 587d5e7..d5a13fc 100644
--- a/src/connectivity/network/netstack3/core/src/ip/gmp/mod.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/gmp/mod.rs
@@ -17,8 +17,6 @@
 
 // This macro is used by tests in both the `igmp` and `mld` modules.
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 /// Assert that the GMP state machine for `$group` is in the given state.
 ///
 /// `$ctx` is a `context::testutil::DummyCtx` whose state contains a `groups:
@@ -31,9 +29,6 @@
     ($ctx:expr, $group:expr, Delaying) => {
         assert_gmp_state!(@inner $ctx, $group, MemberState::Delaying(_));
     };
-    ($ctx:expr, $group:expr, Idle) => {
-        assert_gmp_state!(@inner $ctx, $group, MemberState::Idle(_));
-    };
     (@inner $ctx:expr, $group:expr, $pattern:pat) => {
         assert!(matches!($ctx.get_ref().groups.get($group).unwrap().0.inner.as_ref().unwrap(), $pattern))
     };
diff --git a/src/connectivity/network/netstack3/core/src/macros.rs b/src/connectivity/network/netstack3/core/src/macros.rs
index 8a04145..d38850f 100644
--- a/src/connectivity/network/netstack3/core/src/macros.rs
+++ b/src/connectivity/network/netstack3/core/src/macros.rs
@@ -4,8 +4,6 @@
 
 //! Macros used in Netstack3.
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 macro_rules! log_unimplemented {
     ($nocrash:expr, $fmt:expr $(,$arg:expr)*) => {{
 
@@ -23,10 +21,6 @@
             $nocrash
         }
     }};
-
-    ($nocrash:expr, $fmt:expr $(,$arg:expr)*,) =>{
-        log_unimplemented!($nocrash, $fmt $(,$arg)*)
-    };
 }
 
 macro_rules! increment_counter {
diff --git a/src/connectivity/network/tests/integration/inspect/src/lib.rs b/src/connectivity/network/tests/integration/inspect/src/lib.rs
index e639663..15d956f 100644
--- a/src/connectivity/network/tests/integration/inspect/src/lib.rs
+++ b/src/connectivity/network/tests/integration/inspect/src/lib.rs
@@ -233,6 +233,7 @@
                    Bytes: 0u64,
                    Packets: 0u64,
                 },
+                TxPacketsDroppedNoBufferSpace: 0u64,
                 Rx: {
                     Bytes: 0u64,
                     Packets: 0u64,
@@ -283,6 +284,7 @@
                    Bytes: AnyProperty,
                    Packets: AnyProperty,
                 },
+                TxPacketsDroppedNoBufferSpace: AnyProperty,
                 Rx: {
                     Bytes: AnyProperty,
                     Packets: AnyProperty,
@@ -354,6 +356,7 @@
                    Bytes: AnyProperty,
                    Packets: AnyProperty,
                 },
+                TxPacketsDroppedNoBufferSpace: AnyProperty,
                 Rx: {
                     Bytes: AnyProperty,
                     Packets: AnyProperty,
@@ -862,6 +865,7 @@
                 Bytes: AnyProperty,
                 Packets: AnyProperty,
             },
+            TxPacketsDroppedNoBufferSpace: AnyProperty,
             UnknownL3ProtocolRcvdPacketCounts: {
                 Total: {
                     Count: "0"
diff --git a/src/connectivity/wlan/lib/inspect/src/wrappers.rs b/src/connectivity/wlan/lib/inspect/src/wrappers.rs
index 24660fc..18aed4c 100644
--- a/src/connectivity/wlan/lib/inspect/src/wrappers.rs
+++ b/src/connectivity/wlan/lib/inspect/src/wrappers.rs
@@ -3,13 +3,13 @@
 // found in the LICENSE file.
 
 use fidl_fuchsia_wlan_common as fidl_common;
-use fuchsia_inspect::Node;
+use fuchsia_inspect::{Node, StringReference};
 use fuchsia_inspect_contrib::{inspect_insert, log::WriteInspect};
 
 pub struct InspectWlanChan<'a>(pub &'a fidl_common::WlanChannel);
 
 impl<'a> WriteInspect for InspectWlanChan<'a> {
-    fn write_inspect(&self, writer: &Node, key: &str) {
+    fn write_inspect<'b>(&self, writer: &Node, key: impl Into<StringReference<'b>>) {
         inspect_insert!(writer, var key: {
             primary: self.0.primary,
             cbw: format!("{:?}", self.0.cbw),
diff --git a/src/connectivity/wlan/wlancfg/src/client/network_selection.rs b/src/connectivity/wlan/wlancfg/src/client/network_selection.rs
index 83d6b98..bfdbd32 100644
--- a/src/connectivity/wlan/wlancfg/src/client/network_selection.rs
+++ b/src/connectivity/wlan/wlancfg/src/client/network_selection.rs
@@ -20,7 +20,7 @@
     fidl_fuchsia_wlan_internal as fidl_internal, fidl_fuchsia_wlan_sme as fidl_sme,
     fuchsia_async as fasync,
     fuchsia_cobalt::CobaltSender,
-    fuchsia_inspect::Node as InspectNode,
+    fuchsia_inspect::{Node as InspectNode, StringReference},
     fuchsia_inspect_contrib::{
         auto_persist::{self, AutoPersist},
         inspect_insert, inspect_log,
@@ -221,7 +221,7 @@
     }
 }
 impl<'a> WriteInspect for InternalBss<'a> {
-    fn write_inspect(&self, writer: &InspectNode, key: &str) {
+    fn write_inspect<'b>(&self, writer: &InspectNode, key: impl Into<StringReference<'b>>) {
         inspect_insert!(writer, var key: {
             ssid_hash: self.hasher.hash_ssid(&self.saved_network_info.network_id.ssid),
             bssid_hash: self.hasher.hash_mac_addr(&self.scanned_bss.bssid.0),
diff --git a/src/connectivity/wlan/wlanstack/BUILD.gn b/src/connectivity/wlan/wlanstack/BUILD.gn
index 5a88ef7..7fb54d8 100644
--- a/src/connectivity/wlan/wlanstack/BUILD.gn
+++ b/src/connectivity/wlan/wlanstack/BUILD.gn
@@ -95,7 +95,6 @@
 fuchsia_component_manifest("wlanstack-manifest") {
   component_name = "wlanstack"
   manifest = "meta/wlanstack.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("wlanstack-comp") {
diff --git a/src/developer/ffx/BUILD.gn b/src/developer/ffx/BUILD.gn
index 956deb6..1bd549d 100644
--- a/src/developer/ffx/BUILD.gn
+++ b/src/developer/ffx/BUILD.gn
@@ -56,12 +56,12 @@
       "//src/developer/ffx/plugins/setui:ffx_setui",
       "//src/developer/ffx/plugins/starnix:ffx_starnix",
       "//src/developer/ffx/plugins/target:ffx_target",
+      "//src/developer/ffx/plugins/test:ffx_test",
       "//src/developer/ffx/plugins/trace:ffx_trace",
       "//src/developer/ffx/plugins/triage:ffx_triage",
       "//src/developer/ffx/plugins/version:ffx_version",
       "//src/developer/ffx/plugins/wlan:ffx_wlan",
       "//src/storage/ffx:ffx_storage",
-      "//src/sys/run_test_suite/ffx/test:ffx_test",
     ]
 
     args_sources = [ "src/args.rs" ]
diff --git a/src/developer/ffx/plugins/log/BUILD.gn b/src/developer/ffx/plugins/log/BUILD.gn
index fcc7685..833e586 100644
--- a/src/developer/ffx/plugins/log/BUILD.gn
+++ b/src/developer/ffx/plugins/log/BUILD.gn
@@ -35,6 +35,7 @@
     "//src/lib/fidl/rust/fidl",
     "//src/lib/fuchsia",
     "//src/lib/fuchsia-async",
+    "//src/sys/lib/moniker",
     "//third_party/rust_crates:assert_matches",
     "//third_party/rust_crates:async-trait",
     "//third_party/rust_crates:blocking",
diff --git a/src/developer/ffx/plugins/log/src/args.rs b/src/developer/ffx/plugins/log/src/args.rs
index 175242a..5284bec 100644
--- a/src/developer/ffx/plugins/log/src/args.rs
+++ b/src/developer/ffx/plugins/log/src/args.rs
@@ -141,6 +141,11 @@
     #[argh(switch)]
     pub show_metadata: bool,
 
+    /// shows the full moniker in log output. By default this is false and only the last segment
+    /// of the moniker is printed.
+    #[argh(switch)]
+    pub show_full_moniker: bool,
+
     /// how to display log timestamps.
     /// Options are "utc", "local", or "monotonic" (i.e. nanos since target boot).
     /// Default is monotonic.
diff --git a/src/developer/ffx/plugins/log/src/lib.rs b/src/developer/ffx/plugins/log/src/lib.rs
index 41649a4..2400c8c 100644
--- a/src/developer/ffx/plugins/log/src/lib.rs
+++ b/src/developer/ffx/plugins/log/src/lib.rs
@@ -19,6 +19,7 @@
     fidl_fuchsia_developer_remotecontrol::{ArchiveIteratorError, RemoteControlProxy},
     fidl_fuchsia_diagnostics::LogSettingsProxy,
     fuchsia_async::futures::{AsyncWrite, AsyncWriteExt},
+    moniker::{AbsoluteMoniker, AbsoluteMonikerBase},
     std::{iter::Iterator, time::SystemTime},
     termion::{color, style},
 };
@@ -178,6 +179,7 @@
     color: bool,
     time_format: TimeFormat,
     show_metadata: bool,
+    show_full_moniker: bool,
     show_tags: bool,
     show_file: bool,
 }
@@ -378,12 +380,21 @@
             String::default()
         };
 
+        let moniker = if options.show_full_moniker {
+            data.moniker
+        } else {
+            AbsoluteMoniker::parse_str(&format!("/{}", data.moniker))
+                .ok()
+                .and_then(|moniker| moniker.path().last().map(|s| s.to_string()))
+                .unwrap_or(data.moniker)
+        };
+
         let severity_str = &format!("{}", data.metadata.severity)[..1];
         format!(
             "[{}]{}[{}]{}[{}{}{}]{} {}{}{}{}",
             ts,
             process_info_str,
-            data.moniker,
+            moniker,
             tags_str,
             color_str,
             severity_str,
@@ -467,6 +478,7 @@
                     color: should_color(config_color, cmd.no_color),
                     time_format: cmd.clock.clone(),
                     show_metadata: cmd.show_metadata,
+                    show_full_moniker: cmd.show_full_moniker,
                 })
             },
         },
@@ -711,24 +723,25 @@
 
     fn empty_log_command() -> LogCommand {
         LogCommand {
-            filter: vec![],
-            exclude: vec![],
-            tags: vec![],
-            exclude_tags: vec![],
-            hide_tags: false,
-            hide_file: false,
             clock: TimeFormat::Monotonic,
-            no_color: false,
+            exclude: vec![],
+            exclude_tags: vec![],
+            filter: vec![],
+            hide_file: false,
+            hide_tags: false,
             kernel: false,
-            severity: Severity::Info,
-            show_metadata: false,
+            no_color: false,
             no_symbols: false,
+            select: vec![],
+            severity: Severity::Info,
+            show_full_moniker: false,
+            show_metadata: false,
             since: None,
             since_monotonic: None,
+            sub_command: None,
+            tags: vec![],
             until: None,
             until_monotonic: None,
-            sub_command: None,
-            select: vec![],
         }
     }
 
@@ -769,10 +782,11 @@
         fn default() -> Self {
             Self {
                 color: Default::default(),
-                time_format: TimeFormat::Monotonic,
+                show_file: Default::default(),
+                show_full_moniker: Default::default(),
                 show_metadata: Default::default(),
                 show_tags: Default::default(),
-                show_file: Default::default(),
+                time_format: TimeFormat::Monotonic,
             }
         }
     }
@@ -1551,7 +1565,7 @@
             DisplayOption::Text(options) => {
                 assert_eq!(
                     formatter.format_target_log_data(&options, logs_data(), None),
-                    "[1615535969.000][some/moniker][W] message"
+                    "[1615535969.000][moniker][W] message"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1597,7 +1611,7 @@
                 // Before setting the boot timestamp, it should use monotonic time.
                 assert_eq!(
                     formatter.format_target_log_data(&options, logs_data(), None),
-                    "[1615535969.000][some/moniker][W] message"
+                    "[1615535969.000][moniker][W] message"
                 );
 
                 formatter.set_boot_timestamp(1);
@@ -1606,7 +1620,7 @@
                 // the output *did* change.
                 assert_ne!(
                     formatter.format_target_log_data(&options, logs_data(), None),
-                    "[1615535969.000][some/moniker][W] message"
+                    "[1615535969.000][moniker][W] message"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1631,13 +1645,13 @@
                 // Before setting the boot timestamp, it should use monotonic time.
                 assert_eq!(
                     formatter.format_target_log_data(&options, logs_data(), None),
-                    "[1615535969.000][some/moniker][W] message"
+                    "[1615535969.000][moniker][W] message"
                 );
 
                 formatter.set_boot_timestamp(1);
                 assert_eq!(
                     formatter.format_target_log_data(&options, logs_data(), None),
-                    "[2021-03-12 07:59:29.000][some/moniker][W] message"
+                    "[2021-03-12 07:59:29.000][moniker][W] message"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1660,7 +1674,7 @@
             DisplayOption::Text(options) => {
                 assert_eq!(
                     formatter.format_target_log_data(&options, logs_data(), None),
-                    "[1615535969.000][some/moniker][\u{1b}[38;5;3mW\u{1b}[m] \u{1b}[38;5;3mmessage\u{1b}[m"
+                    "[1615535969.000][moniker][\u{1b}[38;5;3mW\u{1b}[m] \u{1b}[38;5;3mmessage\u{1b}[m"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1684,7 +1698,7 @@
             DisplayOption::Text(options) => {
                 assert_eq!(
                     formatter.format_target_log_data(&options, logs_data(), None),
-                    "[1615535969.000][1][2][some/moniker][W] message"
+                    "[1615535969.000][1][2][moniker][W] message"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1705,7 +1719,7 @@
                         logs_data(),
                         Some("symbolized".to_string())
                     ),
-                    "[1615535969.000][some/moniker][W] symbolized"
+                    "[1615535969.000][moniker][W] symbolized"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1726,7 +1740,7 @@
                         logs_data(),
                         Some("symbolized".to_string())
                     ),
-                    "[1615535969.000][some/moniker][W] message"
+                    "[1615535969.000][moniker][W] message"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1749,7 +1763,7 @@
             DisplayOption::Text(options) => {
                 assert_eq!(
                     formatter.format_target_log_data(options, logs_data(), None),
-                    "[1615535969.000][some/moniker][tag1,tag2][W] message"
+                    "[1615535969.000][moniker][tag1,tag2][W] message"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1773,7 +1787,7 @@
             DisplayOption::Text(options) => {
                 assert_eq!(
                     formatter.format_target_log_data(&options, logs_data_builder().build(), None),
-                    "[1615535969.000][some/moniker][][W] <missing message>"
+                    "[1615535969.000][moniker][][W] <missing message>"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1800,7 +1814,7 @@
                         logs_data_builder().set_message("multi\nline\nmessage").build(),
                         None
                     ),
-                    "[1615535969.000][some/moniker][][W] multi\nline\nmessage"
+                    "[1615535969.000][moniker][][W] multi\nline\nmessage"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1835,7 +1849,7 @@
                             .build(),
                         None
                     ),
-                    "[1615535969.000][1][2][some/moniker][W] my message bar=baz foo=2"
+                    "[1615535969.000][1][2][moniker][W] my message bar=baz foo=2"
                 );
             }
             DisplayOption::Json => unreachable!("The default display option must be Text"),
@@ -1865,7 +1879,7 @@
                 message_with_file_and_line.clone(),
                 None
             ),
-            "[1615535969.000][some/moniker][W]: [path/to/file.cc:123] my message"
+            "[1615535969.000][moniker][W]: [path/to/file.cc:123] my message"
         );
 
         assert_eq!(
@@ -1877,13 +1891,36 @@
                     .build(),
                 None
             ),
-            "[1615535969.000][some/moniker][W]: [path/to/file.cc] my message"
+            "[1615535969.000][moniker][W]: [path/to/file.cc] my message"
         );
 
         display_options.show_file = false;
         assert_eq!(
             formatter.format_target_log_data(&display_options, message_with_file_and_line, None),
-            "[1615535969.000][some/moniker][W] my message"
+            "[1615535969.000][moniker][W] my message"
         );
     }
+
+    #[fuchsia::test]
+    fn display_full_moniker() {
+        let mut stdout = Unblock::new(std::io::stdout());
+        let options = LogFormatterOptions {
+            display: DisplayOption::Text(TextDisplayOptions {
+                show_full_moniker: true,
+                ..TextDisplayOptions::default()
+            }),
+            no_symbols: false,
+        };
+        let formatter =
+            DefaultLogFormatter::new(LogFilterCriteria::default(), &mut stdout, options.clone());
+        match &options.display {
+            DisplayOption::Text(options) => {
+                assert_eq!(
+                    formatter.format_target_log_data(options, logs_data(), None),
+                    "[1615535969.000][some/moniker][W] message"
+                );
+            }
+            DisplayOption::Json => unreachable!("The default display option must be Text"),
+        }
+    }
 }
diff --git a/src/sys/run_test_suite/ffx/test/BUILD.gn b/src/developer/ffx/plugins/test/BUILD.gn
similarity index 100%
rename from src/sys/run_test_suite/ffx/test/BUILD.gn
rename to src/developer/ffx/plugins/test/BUILD.gn
diff --git a/src/developer/ffx/plugins/test/OWNERS b/src/developer/ffx/plugins/test/OWNERS
new file mode 100644
index 0000000..8effbbe
--- /dev/null
+++ b/src/developer/ffx/plugins/test/OWNERS
@@ -0,0 +1,3 @@
+include /src/sys/run_test_suite/OWNERS
+
+# COMPONENT: TestArchitecture>ffx
diff --git a/src/sys/run_test_suite/ffx/test/data/config.json b/src/developer/ffx/plugins/test/data/config.json
similarity index 100%
rename from src/sys/run_test_suite/ffx/test/data/config.json
rename to src/developer/ffx/plugins/test/data/config.json
diff --git a/src/sys/run_test_suite/ffx/test/src/args.rs b/src/developer/ffx/plugins/test/src/args.rs
similarity index 100%
rename from src/sys/run_test_suite/ffx/test/src/args.rs
rename to src/developer/ffx/plugins/test/src/args.rs
diff --git a/src/sys/run_test_suite/ffx/test/src/lib.rs b/src/developer/ffx/plugins/test/src/lib.rs
similarity index 99%
rename from src/sys/run_test_suite/ffx/test/src/lib.rs
rename to src/developer/ffx/plugins/test/src/lib.rs
index e9b8156..a251799 100644
--- a/src/sys/run_test_suite/ffx/test/src/lib.rs
+++ b/src/developer/ffx/plugins/test/src/lib.rs
@@ -500,7 +500,8 @@
 
     lazy_static! {
         static ref VALID_INPUT_FORMAT: String = serde_json::to_string(&serde_json::json!({
-          "tests": [
+          "schema_id": "experimental",
+          "data": [
             {
                 "name": "{}-test-1",
                 "labels": ["{}-label"],
diff --git a/src/sys/run_test_suite/ffx/test/src/output_directory.rs b/src/developer/ffx/plugins/test/src/output_directory.rs
similarity index 100%
rename from src/sys/run_test_suite/ffx/test/src/output_directory.rs
rename to src/developer/ffx/plugins/test/src/output_directory.rs
diff --git a/src/sys/run_test_suite/ffx/test/src/suite_definition.rs b/src/developer/ffx/plugins/test/src/suite_definition.rs
similarity index 94%
rename from src/sys/run_test_suite/ffx/test/src/suite_definition.rs
rename to src/developer/ffx/plugins/test/src/suite_definition.rs
index ee0d93b..176e13d 100644
--- a/src/sys/run_test_suite/ffx/test/src/suite_definition.rs
+++ b/src/developer/ffx/plugins/test/src/suite_definition.rs
@@ -21,16 +21,14 @@
     options: TestParamsOptions,
 ) -> Result<Vec<TestParams>> {
     let test_list: TestList = serde_json::from_reader(reader).map_err(anyhow::Error::from)?;
+    let TestList::Experimental { data } = test_list;
     if options.ignore_test_without_known_execution {
-        Ok(test_list
-            .tests
+        Ok(data
             .into_iter()
             .filter_map(|entry| maybe_convert_test_list_entry_to_test_params(entry).ok())
             .collect())
     } else {
-        test_list
-            .tests
-            .into_iter()
+        data.into_iter()
             .map(maybe_convert_test_list_entry_to_test_params)
             .collect::<Result<Vec<TestParams>, anyhow::Error>>()
     }
@@ -74,7 +72,8 @@
 
     const VALID_JSON: &'static str = r#"
     {
-        "tests": [
+        "schema_id": "experimental",
+        "data": [
             {
                 "name": "test",
                 "labels": [],
@@ -90,7 +89,8 @@
 
     const CONTAINS_VALID_AND_INVALID: &'static str = r#"
     {
-        "tests": [
+        "schema_id": "experimental",
+        "data": [
             {
                 "name": "test",
                 "labels": [],
diff --git a/src/developer/forensics/crash_reports/BUILD.gn b/src/developer/forensics/crash_reports/BUILD.gn
index ab275b6..984942a 100644
--- a/src/developer/forensics/crash_reports/BUILD.gn
+++ b/src/developer/forensics/crash_reports/BUILD.gn
@@ -62,7 +62,6 @@
 
   deps = [
     "//sdk/lib/syslog/cpp",
-    "//src/developer/forensics/utils/fidl:channel_provider_ptr",
     "//src/lib/files",
     "//src/lib/fostr/fidl/fuchsia.feedback",
   ]
diff --git a/src/developer/forensics/feedback/BUILD.gn b/src/developer/forensics/feedback/BUILD.gn
index 392bea0..bfd7093 100644
--- a/src/developer/forensics/feedback/BUILD.gn
+++ b/src/developer/forensics/feedback/BUILD.gn
@@ -127,6 +127,7 @@
     "//src/developer/forensics/feedback/annotations:current_channel_provider",
     "//src/developer/forensics/feedback/annotations:data_register",
     "//src/developer/forensics/feedback/annotations:product_info_provider",
+    "//src/developer/forensics/feedback/annotations:target_channel_provider",
     "//src/developer/forensics/feedback/annotations:time_provider",
     "//src/developer/forensics/feedback_data:constants",
     "//src/developer/forensics/feedback_data:data_provider",
diff --git a/src/developer/forensics/feedback/annotation_providers.cc b/src/developer/forensics/feedback/annotation_providers.cc
index 48cc939..1707b30 100644
--- a/src/developer/forensics/feedback/annotation_providers.cc
+++ b/src/developer/forensics/feedback/annotation_providers.cc
@@ -33,9 +33,11 @@
       board_info_provider_(dispatcher_, services, AnnotationProviderBackoff()),
       product_info_provider_(dispatcher_, services, AnnotationProviderBackoff()),
       current_channel_provider_(dispatcher_, services, AnnotationProviderBackoff()),
+      target_channel_provider_(dispatcher_, services, AnnotationProviderBackoff()),
       annotation_manager_(
           dispatcher_, allowlist, static_annotations, &data_register_, {&time_provider_},
-          {&board_info_provider_, &product_info_provider_, &current_channel_provider_}) {}
+          {&board_info_provider_, &product_info_provider_, &current_channel_provider_},
+          {&target_channel_provider_}) {}
 
 void AnnotationProviders::Handle(
     ::fidl::InterfaceRequest<fuchsia::feedback::ComponentDataRegister> request,
diff --git a/src/developer/forensics/feedback/annotation_providers.h b/src/developer/forensics/feedback/annotation_providers.h
index e6a7560..127af84 100644
--- a/src/developer/forensics/feedback/annotation_providers.h
+++ b/src/developer/forensics/feedback/annotation_providers.h
@@ -18,6 +18,7 @@
 #include "src/developer/forensics/feedback/annotations/current_channel_provider.h"
 #include "src/developer/forensics/feedback/annotations/data_register.h"
 #include "src/developer/forensics/feedback/annotations/product_info_provider.h"
+#include "src/developer/forensics/feedback/annotations/target_channel_provider.h"
 #include "src/developer/forensics/feedback/annotations/time_provider.h"
 
 namespace forensics::feedback {
@@ -42,6 +43,7 @@
   BoardInfoProvider board_info_provider_;
   ProductInfoProvider product_info_provider_;
   CurrentChannelProvider current_channel_provider_;
+  TargetChannelProvider target_channel_provider_;
 
   AnnotationManager annotation_manager_;
 
diff --git a/src/developer/forensics/feedback/annotations/BUILD.gn b/src/developer/forensics/feedback/annotations/BUILD.gn
index c8af843..3af9f4b 100644
--- a/src/developer/forensics/feedback/annotations/BUILD.gn
+++ b/src/developer/forensics/feedback/annotations/BUILD.gn
@@ -113,6 +113,19 @@
   ]
 }
 
+source_set("target_channel_provider") {
+  sources = [
+    "target_channel_provider.cc",
+    "target_channel_provider.h",
+  ]
+
+  public_deps = [
+    ":fidl_provider",
+    "//sdk/fidl/fuchsia.update.channelcontrol",
+    "//src/developer/forensics/feedback/annotations",
+  ]
+}
+
 source_set("time_provider") {
   sources = [
     "time_provider.cc",
diff --git a/src/developer/forensics/feedback/annotations/fidl_provider.h b/src/developer/forensics/feedback/annotations/fidl_provider.h
index a10b8a5..6715079 100644
--- a/src/developer/forensics/feedback/annotations/fidl_provider.h
+++ b/src/developer/forensics/feedback/annotations/fidl_provider.h
@@ -49,6 +49,34 @@
   fxl::WeakPtrFactory<StaticSingleFidlMethodAnnotationProvider> ptr_factory_{this};
 };
 
+// Dynamic async annotation provider that handles calling a single FIDL method and
+// returning the result of the call as Annotations when the method completes.
+//
+// |Interface| is the FIDL protocol being interacted with.
+// |method| is the method being called on |Interface|.
+// |Convert| is a function object type for converting the results of |method| to Annotations.
+template <typename Interface, auto method, typename Convert>
+class DynamicSingleFidlMethodAnnotationProvider : public DynamicAsyncAnnotationProvider {
+ public:
+  DynamicSingleFidlMethodAnnotationProvider(async_dispatcher_t* dispatcher,
+                                            std::shared_ptr<sys::ServiceDirectory> services,
+                                            std::unique_ptr<backoff::Backoff> backoff);
+
+  void Get(::fit::callback<void(Annotations)> callback) override;
+
+ private:
+  void CleanupCompleted();
+
+  async_dispatcher_t* dispatcher_;
+  std::shared_ptr<sys::ServiceDirectory> services_;
+  std::unique_ptr<backoff::Backoff> backoff_;
+  Convert convert_;
+
+  ::fidl::InterfacePtr<Interface> ptr_;
+  std::vector<::fit::callback<void(Annotations)>> callbacks_;
+  fxl::WeakPtrFactory<DynamicSingleFidlMethodAnnotationProvider> ptr_factory_{this};
+};
+
 template <typename Interface, auto method, typename Convert>
 StaticSingleFidlMethodAnnotationProvider<Interface, method, Convert>::
     StaticSingleFidlMethodAnnotationProvider(async_dispatcher_t* dispatcher,
@@ -87,6 +115,64 @@
   });
 }
 
+template <typename Interface, auto method, typename Convert>
+DynamicSingleFidlMethodAnnotationProvider<Interface, method, Convert>::
+    DynamicSingleFidlMethodAnnotationProvider(async_dispatcher_t* dispatcher,
+                                              std::shared_ptr<sys::ServiceDirectory> services,
+                                              std::unique_ptr<backoff::Backoff> backoff)
+    : dispatcher_(dispatcher), services_(std::move(services)), backoff_(std::move(backoff)) {
+  services_->Connect(ptr_.NewRequest(dispatcher_));
+
+  ptr_.set_error_handler([this](const zx_status_t status) {
+    FX_LOGS(WARNING) << "Lost connection to " << Interface::Name_;
+
+    // Complete any outstanding callbacks with a connection error.
+    for (auto& callback : callbacks_) {
+      if (callback != nullptr) {
+        callback(convert_(Error::kConnectionError));
+      }
+    }
+
+    CleanupCompleted();
+
+    async::PostDelayedTask(
+        dispatcher_,
+        [self = ptr_factory_.GetWeakPtr()] {
+          if (self) {
+            self->services_->Connect(self->ptr_.NewRequest(self->dispatcher_));
+          }
+        },
+        backoff_->GetNext());
+  });
+}
+
+template <typename Interface, auto method, typename Convert>
+void DynamicSingleFidlMethodAnnotationProvider<Interface, method, Convert>::Get(
+    ::fit::callback<void(Annotations)> callback) {
+  // A reconnection is in progress.
+  if (!ptr_.is_bound()) {
+    callback(convert_(Error::kConnectionError));
+    return;
+  }
+
+  callbacks_.push_back(callback.share());
+  ((*ptr_).*method)([this, callback = std::move(callback)](auto&&... result) mutable {
+    if (callback != nullptr) {
+      callback(convert_(result...));
+    }
+    CleanupCompleted();
+  });
+}
+
+template <typename Interface, auto method, typename Convert>
+void DynamicSingleFidlMethodAnnotationProvider<Interface, method, Convert>::CleanupCompleted() {
+  callbacks_.erase(std::remove_if(callbacks_.begin(), callbacks_.end(),
+                                  [](const ::fit::callback<void(Annotations)>& callback) {
+                                    return callback == nullptr;
+                                  }),
+                   callbacks_.end());
+}
+
 }  // namespace forensics::feedback
 
 #endif  // SRC_DEVELOPER_FORENSICS_FEEDBACK_ANNOTATIONS_FIDL_PROVIDER_H_
diff --git a/src/developer/forensics/feedback/annotations/target_channel_provider.cc b/src/developer/forensics/feedback/annotations/target_channel_provider.cc
new file mode 100644
index 0000000..e6716f8
--- /dev/null
+++ b/src/developer/forensics/feedback/annotations/target_channel_provider.cc
@@ -0,0 +1,23 @@
+// 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/developer/forensics/feedback/annotations/target_channel_provider.h"
+
+#include "src/developer/forensics/feedback/annotations/constants.h"
+
+namespace forensics::feedback {
+
+Annotations TargetChannelToAnnotations::operator()(const ErrorOr<std::string>& target_channel) {
+  return Annotations{
+      {kSystemUpdateChannelTargetKey, target_channel},
+  };
+}
+
+std::set<std::string> TargetChannelProvider::GetKeys() const {
+  return {
+      kSystemUpdateChannelTargetKey,
+  };
+}
+
+}  // namespace forensics::feedback
diff --git a/src/developer/forensics/feedback/annotations/target_channel_provider.h b/src/developer/forensics/feedback/annotations/target_channel_provider.h
new file mode 100644
index 0000000..167c7a5
--- /dev/null
+++ b/src/developer/forensics/feedback/annotations/target_channel_provider.h
@@ -0,0 +1,32 @@
+// 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_DEVELOPER_FORENSICS_FEEDBACK_ANNOTATIONS_TARGET_CHANNEL_PROVIDER_H_
+#define SRC_DEVELOPER_FORENSICS_FEEDBACK_ANNOTATIONS_TARGET_CHANNEL_PROVIDER_H_
+
+#include <fuchsia/update/channelcontrol/cpp/fidl.h>
+
+#include "src/developer/forensics/feedback/annotations/fidl_provider.h"
+#include "src/developer/forensics/feedback/annotations/types.h"
+
+namespace forensics::feedback {
+
+struct TargetChannelToAnnotations {
+  Annotations operator()(const ErrorOr<std::string>& target_channel);
+};
+
+// Responsible for collecting annotations for fuchsia.hwinfo/Board.
+class TargetChannelProvider
+    : public DynamicSingleFidlMethodAnnotationProvider<
+          fuchsia::update::channelcontrol::ChannelControl,
+          &fuchsia::update::channelcontrol::ChannelControl::GetTarget, TargetChannelToAnnotations> {
+ public:
+  using DynamicSingleFidlMethodAnnotationProvider::DynamicSingleFidlMethodAnnotationProvider;
+
+  std::set<std::string> GetKeys() const override;
+};
+
+}  // namespace forensics::feedback
+
+#endif  // SRC_DEVELOPER_FORENSICS_FEEDBACK_ANNOTATIONS_TARGET_CHANNEL_PROVIDER_H_
diff --git a/src/developer/forensics/feedback/tests/BUILD.gn b/src/developer/forensics/feedback/tests/BUILD.gn
index b239e17..5c6302b 100644
--- a/src/developer/forensics/feedback/tests/BUILD.gn
+++ b/src/developer/forensics/feedback/tests/BUILD.gn
@@ -136,20 +136,6 @@
   ]
 }
 
-executable("inspect_exe") {
-  testonly = true
-
-  sources = [ "inspect_exe.cc" ]
-
-  deps = [
-    "//sdk/lib/sys/cpp",
-    "//sdk/lib/sys/inspect/cpp",
-    "//src/lib/fxl",
-    "//zircon/system/ulib/async-loop:async-loop-cpp",
-    "//zircon/system/ulib/async-loop:async-loop-default",
-  ]
-}
-
 executable("last_reboot_unittest_exe") {
   testonly = true
 
@@ -285,6 +271,20 @@
   ]
 }
 
+executable("target_channel_provider_unittest_exe") {
+  testonly = true
+
+  sources = [ "target_channel_provider_unittest.cc" ]
+
+  deps = [
+    "//src/developer/forensics/feedback/annotations:target_channel_provider",
+    "//src/developer/forensics/testing:gtest_with_syslog_main",
+    "//src/developer/forensics/testing:unit_test_fixture",
+    "//third_party/googletest:gmock",
+    "//third_party/googletest:gtest",
+  ]
+}
+
 ###############################################################################
 # COMPONENTS
 ###############################################################################
@@ -336,14 +336,6 @@
   deps = [ ":fidl_provider_unittest_exe" ]
 }
 
-fuchsia_component("inspect_test_app") {
-  testonly = true
-
-  manifest = "meta/inspect_test_app.cmx"
-
-  deps = [ ":inspect_exe" ]
-}
-
 fuchsia_unittest_component("last_reboot_unittest") {
   deps = [
     ":last_reboot_unittest_exe",
@@ -385,6 +377,10 @@
   deps = [ ":startup_annotations_unittest_exe" ]
 }
 
+fuchsia_unittest_component("target_channel_provider_unittest") {
+  deps = [ ":target_channel_provider_unittest_exe" ]
+}
+
 ###############################################################################
 # PACKAGES
 ###############################################################################
@@ -393,6 +389,7 @@
     ":annotation_manager_unittest",
     ":board_info_provider_unittest",
     ":config_unittest",
+    ":target_channel_provider_unittest",
     ":current_channel_provider_unittest",
     ":data_register_unittest",
     ":device_id_provider_unittest",
diff --git a/src/developer/forensics/feedback/tests/fidl_provider_unittest.cc b/src/developer/forensics/feedback/tests/fidl_provider_unittest.cc
index 97a77b5..550dbddc 100644
--- a/src/developer/forensics/feedback/tests/fidl_provider_unittest.cc
+++ b/src/developer/forensics/feedback/tests/fidl_provider_unittest.cc
@@ -42,10 +42,10 @@
 using StaticSingleFidlMethodAnnotationProviderTest = UnitTestFixture;
 
 struct ConvertChannel {
-  Annotations operator()(const std::string& channel) { return {{kChannelKey, channel}}; }
+  Annotations operator()(const ErrorOr<std::string>& channel) { return {{kChannelKey, channel}}; }
 };
 
-class CurrentChannelProvider
+class StaticCurrentChannelProvider
     : public StaticSingleFidlMethodAnnotationProvider<
           fuchsia::update::channelcontrol::ChannelControl,
           &fuchsia::update::channelcontrol::ChannelControl::GetCurrent, ConvertChannel> {
@@ -56,7 +56,8 @@
 };
 
 TEST_F(StaticSingleFidlMethodAnnotationProviderTest, GetAll) {
-  CurrentChannelProvider provider(dispatcher(), services(), std::make_unique<MonotonicBackoff>());
+  StaticCurrentChannelProvider provider(dispatcher(), services(),
+                                        std::make_unique<MonotonicBackoff>());
 
   auto channel_server = std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params{
       .current = kChannelValue,
@@ -74,7 +75,8 @@
 }
 
 TEST_F(StaticSingleFidlMethodAnnotationProviderTest, Reconnects) {
-  CurrentChannelProvider provider(dispatcher(), services(), std::make_unique<MonotonicBackoff>());
+  StaticCurrentChannelProvider provider(dispatcher(), services(),
+                                        std::make_unique<MonotonicBackoff>());
 
   auto channel_server = std::make_unique<stubs::ChannelControlClosesFirstConnection>(
       stubs::ChannelControlBase::Params{
@@ -96,5 +98,73 @@
   EXPECT_EQ(channel_server->NumConnections(), 0u);
 }
 
+using DynamicSingleFidlMethodAnnotationProviderTest = UnitTestFixture;
+
+class DynamicCurrentChannelProvider
+    : public DynamicSingleFidlMethodAnnotationProvider<
+          fuchsia::update::channelcontrol::ChannelControl,
+          &fuchsia::update::channelcontrol::ChannelControl::GetCurrent, ConvertChannel> {
+ public:
+  using DynamicSingleFidlMethodAnnotationProvider::DynamicSingleFidlMethodAnnotationProvider;
+
+  std::set<std::string> GetKeys() const override { return {kChannelKey}; }
+};
+
+TEST_F(DynamicSingleFidlMethodAnnotationProviderTest, Get) {
+  DynamicCurrentChannelProvider provider(dispatcher(), services(),
+                                         std::make_unique<MonotonicBackoff>());
+
+  auto channel_server = std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params{
+      .current = kChannelValue,
+  });
+  InjectServiceProvider(channel_server.get());
+
+  RunLoopUntilIdle();
+
+  Annotations annotations;
+  provider.Get([&annotations](Annotations a) { annotations = std::move(a); });
+
+  RunLoopUntilIdle();
+  EXPECT_THAT(annotations, UnorderedElementsAreArray({Pair(kChannelKey, kChannelValue)}));
+  EXPECT_EQ(channel_server->NumConnections(), 1u);
+}
+
+TEST_F(DynamicSingleFidlMethodAnnotationProviderTest, Reconnects) {
+  DynamicCurrentChannelProvider provider(dispatcher(), services(),
+                                         std::make_unique<MonotonicBackoff>());
+
+  auto channel_server = std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params{
+      .current = kChannelValue,
+  });
+  InjectServiceProvider(channel_server.get());
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(channel_server->NumConnections(), 1u);
+
+  channel_server->CloseAllConnections();
+
+  RunLoopUntilIdle();
+  ASSERT_EQ(channel_server->NumConnections(), 0u);
+
+  Annotations annotations;
+  provider.Get([&annotations](Annotations a) { annotations = std::move(a); });
+
+  RunLoopUntilIdle();
+  EXPECT_THAT(annotations, UnorderedElementsAreArray({Pair(kChannelKey, Error::kConnectionError)}));
+
+  RunLoopFor(zx::sec(1));
+  EXPECT_EQ(channel_server->NumConnections(), 1u);
+
+  provider.Get([&annotations](Annotations a) { annotations = std::move(a); });
+
+  RunLoopUntilIdle();
+  EXPECT_THAT(annotations, UnorderedElementsAreArray({Pair(kChannelKey, kChannelValue)}));
+
+  channel_server->CloseAllConnections();
+
+  RunLoopUntilIdle();
+  EXPECT_EQ(channel_server->NumConnections(), 0u);
+}
+
 }  // namespace
 }  // namespace forensics::feedback
diff --git a/src/developer/forensics/feedback/tests/inspect_exe.cc b/src/developer/forensics/feedback/tests/inspect_exe.cc
deleted file mode 100644
index cc2c359..0000000
--- a/src/developer/forensics/feedback/tests/inspect_exe.cc
+++ /dev/null
@@ -1,40 +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/async-loop/cpp/loop.h>
-#include <lib/async-loop/default.h>
-#include <lib/inspect/cpp/vmo/types.h>
-#include <lib/sys/cpp/component_context.h>
-#include <lib/sys/inspect/cpp/component.h>
-#include <lib/syslog/cpp/macros.h>
-
-#include <cstdint>
-#include <cstdlib>
-
-class Object {
- public:
-  Object(inspect::Node node, uint64_t value) : node_(std::move(node)) {
-    version_ = node_.CreateString("version", "1.0");
-    value_ = node_.CreateInt("value", value);
-  }
-
- private:
-  inspect::Node node_;
-  inspect::StringProperty version_;
-  inspect::IntProperty value_;
-};
-
-int main(int argc, const char** argv) {
-  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
-  auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
-  auto inspector = std::make_unique<sys::ComponentInspector>(context.get());
-  auto& root = inspector->root();
-
-  Object o1(root.CreateChild("obj1"), 100);
-  Object o2(root.CreateChild("obj2"), 200);
-
-  loop.Run();
-
-  return EXIT_SUCCESS;
-}
diff --git a/src/developer/forensics/feedback/tests/meta/inspect_test_app.cmx b/src/developer/forensics/feedback/tests/meta/inspect_test_app.cmx
deleted file mode 100644
index 2636cba..0000000
--- a/src/developer/forensics/feedback/tests/meta/inspect_test_app.cmx
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "bin/inspect_exe"
-    }
-}
diff --git a/src/developer/forensics/feedback/tests/target_channel_provider_unittest.cc b/src/developer/forensics/feedback/tests/target_channel_provider_unittest.cc
new file mode 100644
index 0000000..7e12490
--- /dev/null
+++ b/src/developer/forensics/feedback/tests/target_channel_provider_unittest.cc
@@ -0,0 +1,48 @@
+// 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/developer/forensics/feedback/annotations/target_channel_provider.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "src/developer/forensics/feedback/annotations/constants.h"
+#include "src/developer/forensics/feedback/annotations/types.h"
+#include "src/developer/forensics/testing/unit_test_fixture.h"
+
+namespace forensics::feedback {
+namespace {
+
+using ::testing::Pair;
+using ::testing::UnorderedElementsAreArray;
+
+TEST(TargetChannelToAnnotationsTest, Convert) {
+  TargetChannelToAnnotations convert;
+
+  EXPECT_THAT(convert(""), UnorderedElementsAreArray({
+                               Pair(kSystemUpdateChannelTargetKey, ErrorOr<std::string>("")),
+                           }));
+  EXPECT_THAT(convert("channel"),
+              UnorderedElementsAreArray({
+                  Pair(kSystemUpdateChannelTargetKey, ErrorOr<std::string>("channel")),
+              }));
+  EXPECT_THAT(convert(Error::kConnectionError),
+              UnorderedElementsAreArray({
+                  Pair(kSystemUpdateChannelTargetKey, Error::kConnectionError),
+              }));
+}
+
+using TargetChannelProviderTest = UnitTestFixture;
+
+TEST_F(TargetChannelProviderTest, Keys) {
+  // Safe to pass nullptrs b/c objects are never used.
+  TargetChannelProvider provider(dispatcher(), services(), nullptr);
+
+  EXPECT_THAT(provider.GetKeys(), UnorderedElementsAreArray({
+                                      kSystemUpdateChannelTargetKey,
+                                  }));
+}
+
+}  // namespace
+}  // namespace forensics::feedback
diff --git a/src/developer/forensics/feedback_data/annotations/BUILD.gn b/src/developer/forensics/feedback_data/annotations/BUILD.gn
index 1e65e35..3c2b3b2 100644
--- a/src/developer/forensics/feedback_data/annotations/BUILD.gn
+++ b/src/developer/forensics/feedback_data/annotations/BUILD.gn
@@ -22,7 +22,6 @@
   ]
 
   deps = [
-    ":channel_provider",
     ":timezone_provider",
     ":types",
     ":utils",
@@ -39,34 +38,6 @@
   ]
 }
 
-# Exposed separately for unit test purposes.
-source_set("channel_provider") {
-  public = [ "channel_provider.h" ]
-
-  sources = [
-    "annotation_provider.h",
-    "channel_provider.cc",
-    "channel_provider.h",
-  ]
-
-  public_deps = [
-    ":types",
-    "//sdk/fidl/fuchsia.update.channel",
-    "//sdk/lib/sys/cpp",
-    "//src/lib/fxl",
-    "//zircon/system/ulib/async",
-    "//zircon/system/ulib/zx",
-  ]
-
-  deps = [
-    ":utils",
-    "//src/developer/forensics/feedback_data:constants",
-    "//src/developer/forensics/utils:errors",
-    "//src/developer/forensics/utils/fidl:channel_provider_ptr",
-    "//src/developer/forensics/utils/fit",
-  ]
-}
-
 source_set("static_annotations") {
   public = [ "static_annotations.h" ]
 
diff --git a/src/developer/forensics/feedback_data/annotations/annotation_provider_factory.cc b/src/developer/forensics/feedback_data/annotations/annotation_provider_factory.cc
index c30f140..d6faeea 100644
--- a/src/developer/forensics/feedback_data/annotations/annotation_provider_factory.cc
+++ b/src/developer/forensics/feedback_data/annotations/annotation_provider_factory.cc
@@ -9,7 +9,6 @@
 #include <memory>
 #include <vector>
 
-#include "src/developer/forensics/feedback_data/annotations/channel_provider.h"
 #include "src/developer/forensics/feedback_data/annotations/device_id_provider.h"
 #include "src/developer/forensics/feedback_data/annotations/timezone_provider.h"
 #include "src/developer/forensics/feedback_data/constants.h"
@@ -31,14 +30,5 @@
   return providers;
 }
 
-std::vector<std::unique_ptr<AnnotationProvider>> GetSingleUseProviders(
-    async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services) {
-  std::vector<std::unique_ptr<AnnotationProvider>> providers;
-
-  providers.push_back(std::make_unique<ChannelProvider>(dispatcher, services));
-
-  return providers;
-}
-
 }  // namespace feedback_data
 }  // namespace forensics
diff --git a/src/developer/forensics/feedback_data/annotations/annotation_provider_factory.h b/src/developer/forensics/feedback_data/annotations/annotation_provider_factory.h
index 8d8e3c1..66f25062d 100644
--- a/src/developer/forensics/feedback_data/annotations/annotation_provider_factory.h
+++ b/src/developer/forensics/feedback_data/annotations/annotation_provider_factory.h
@@ -24,11 +24,6 @@
     async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services,
     feedback::DeviceIdProvider* device_id_provider);
 
-// Get the annotations providers that can only be used once to collect annotations, typically
-// providers that have a one-shot connection to a service.
-std::vector<std::unique_ptr<AnnotationProvider>> GetSingleUseProviders(
-    async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services);
-
 }  // namespace feedback_data
 }  // namespace forensics
 
diff --git a/src/developer/forensics/feedback_data/annotations/channel_provider.cc b/src/developer/forensics/feedback_data/annotations/channel_provider.cc
deleted file mode 100644
index f697d31..0000000
--- a/src/developer/forensics/feedback_data/annotations/channel_provider.cc
+++ /dev/null
@@ -1,49 +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 "src/developer/forensics/feedback_data/annotations/channel_provider.h"
-
-#include <algorithm>
-
-#include "src/developer/forensics/feedback_data/annotations/types.h"
-#include "src/developer/forensics/feedback_data/annotations/utils.h"
-#include "src/developer/forensics/feedback_data/constants.h"
-#include "src/developer/forensics/utils/errors.h"
-#include "src/developer/forensics/utils/fidl/channel_provider_ptr.h"
-#include "src/developer/forensics/utils/fit/timeout.h"
-
-namespace forensics {
-namespace feedback_data {
-namespace {
-
-const AnnotationKeys kSupportedAnnotations = {
-    kAnnotationSystemUpdateChannelTarget,
-};
-
-}  // namespace
-
-ChannelProvider::ChannelProvider(async_dispatcher_t* dispatcher,
-                                 std::shared_ptr<sys::ServiceDirectory> services)
-    : dispatcher_(dispatcher), services_(services) {}
-
-::fpromise::promise<Annotations> ChannelProvider::GetAnnotations(zx::duration timeout,
-                                                                 const AnnotationKeys& allowlist) {
-  const AnnotationKeys to_get = RestrictAllowlist(allowlist, kSupportedAnnotations);
-  if (to_get.empty()) {
-    return ::fpromise::make_result_promise<Annotations>(::fpromise::ok<Annotations>({}));
-  }
-
-  using Result = ::fpromise::result<std::string, Error>;
-  return fidl::GetTargetChannel(dispatcher_, services_, fit::Timeout(timeout))
-      .then([to_get](Result& result) {
-        Annotations annotations({
-            {kAnnotationSystemUpdateChannelTarget, result},
-        });
-
-        return ::fpromise::ok(ExtractAllowlisted(to_get, annotations));
-      });
-}
-
-}  // namespace feedback_data
-}  // namespace forensics
diff --git a/src/developer/forensics/feedback_data/annotations/channel_provider.h b/src/developer/forensics/feedback_data/annotations/channel_provider.h
deleted file mode 100644
index 45b9e0a..0000000
--- a/src/developer/forensics/feedback_data/annotations/channel_provider.h
+++ /dev/null
@@ -1,39 +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_DEVELOPER_FORENSICS_FEEDBACK_DATA_ANNOTATIONS_CHANNEL_PROVIDER_H_
-#define SRC_DEVELOPER_FORENSICS_FEEDBACK_DATA_ANNOTATIONS_CHANNEL_PROVIDER_H_
-
-#include <lib/async/dispatcher.h>
-#include <lib/sys/cpp/service_directory.h>
-#include <lib/zx/time.h>
-
-#include <memory>
-
-#include "src/developer/forensics/feedback_data/annotations/annotation_provider.h"
-#include "src/developer/forensics/feedback_data/annotations/types.h"
-#include "src/lib/fxl/macros.h"
-
-namespace forensics {
-namespace feedback_data {
-
-class ChannelProvider : public AnnotationProvider {
- public:
-  // fuchsia.update.channelcontrol.ChannelControl is expected to be in |services|.
-  ChannelProvider(async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services);
-
-  ::fpromise::promise<Annotations> GetAnnotations(zx::duration timeout,
-                                                  const AnnotationKeys& allowlist) override;
-
- private:
-  async_dispatcher_t* dispatcher_;
-  const std::shared_ptr<sys::ServiceDirectory> services_;
-
-  FXL_DISALLOW_COPY_AND_ASSIGN(ChannelProvider);
-};
-
-}  // namespace feedback_data
-}  // namespace forensics
-
-#endif  // SRC_DEVELOPER_FORENSICS_FEEDBACK_DATA_ANNOTATIONS_CHANNEL_PROVIDER_H_
diff --git a/src/developer/forensics/feedback_data/datastore.cc b/src/developer/forensics/feedback_data/datastore.cc
index ec3adce..e47fbe2 100644
--- a/src/developer/forensics/feedback_data/datastore.cc
+++ b/src/developer/forensics/feedback_data/datastore.cc
@@ -99,10 +99,6 @@
     annotations.push_back(provider->GetAnnotations(timeout, annotation_allowlist_));
   }
 
-  for (auto& provider : GetSingleUseProviders(dispatcher_, services_)) {
-    annotations.push_back(provider->GetAnnotations(timeout, annotation_allowlist_));
-  }
-
   return ::fpromise::join_promise_vector(std::move(annotations))
       .and_then([this](std::vector<::fpromise::result<Annotations>>& annotations)
                     -> ::fpromise::result<Annotations> {
diff --git a/src/developer/forensics/feedback_data/tests/BUILD.gn b/src/developer/forensics/feedback_data/tests/BUILD.gn
index a7d23ea..55398de 100644
--- a/src/developer/forensics/feedback_data/tests/BUILD.gn
+++ b/src/developer/forensics/feedback_data/tests/BUILD.gn
@@ -30,28 +30,6 @@
   ]
 }
 
-executable("channel_provider_unittest_exe") {
-  testonly = true
-
-  sources = [ "channel_provider_unittest.cc" ]
-
-  deps = [
-    "//sdk/lib/fit-promise",
-    "//sdk/lib/syslog/cpp",
-    "//src/developer/forensics/feedback_data:constants",
-    "//src/developer/forensics/feedback_data/annotations:channel_provider",
-    "//src/developer/forensics/feedback_data/annotations:types",
-    "//src/developer/forensics/testing:gtest_with_syslog_main",
-    "//src/developer/forensics/testing:unit_test_fixture",
-    "//src/developer/forensics/testing/stubs:channel_control",
-    "//src/lib/timekeeper:testing",
-    "//third_party/googletest:gmock",
-    "//third_party/googletest:gtest",
-    "//zircon/system/ulib/async:async-cpp",
-    "//zircon/system/ulib/zx",
-  ]
-}
-
 executable("config_unittest_exe") {
   testonly = true
 
@@ -375,14 +353,6 @@
   deps = [ ":archive_accessor_ptr_unittest_exe" ]
 }
 
-fuchsia_component("channel_provider_unittest") {
-  testonly = true
-
-  manifest = "meta/channel_provider_unittest.cml"
-
-  deps = [ ":channel_provider_unittest_exe" ]
-}
-
 fuchsia_unittest_component("config_unittest") {
   deps = [
     ":config_unittest_exe",
@@ -480,7 +450,6 @@
 fuchsia_test_package("feedback-data-tests") {
   test_components = [
     ":archive_accessor_ptr_unittest",
-    ":channel_provider_unittest",
     ":config_unittest",
     ":data_provider_unittest",
     ":data_provider_controller_unittest",
diff --git a/src/developer/forensics/feedback_data/tests/channel_provider_unittest.cc b/src/developer/forensics/feedback_data/tests/channel_provider_unittest.cc
deleted file mode 100644
index 6ef4f62..0000000
--- a/src/developer/forensics/feedback_data/tests/channel_provider_unittest.cc
+++ /dev/null
@@ -1,142 +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 "src/developer/forensics/feedback_data/annotations/channel_provider.h"
-
-#include <lib/async/cpp/executor.h>
-#include <lib/fpromise/promise.h>
-#include <lib/syslog/cpp/macros.h>
-#include <lib/zx/time.h>
-
-#include <memory>
-#include <optional>
-#include <string>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "src/developer/forensics/feedback_data/annotations/types.h"
-#include "src/developer/forensics/feedback_data/constants.h"
-#include "src/developer/forensics/testing/stubs/channel_control.h"
-#include "src/developer/forensics/testing/unit_test_fixture.h"
-#include "src/developer/forensics/utils/errors.h"
-#include "src/lib/timekeeper/test_clock.h"
-
-namespace forensics {
-namespace feedback_data {
-namespace {
-
-using testing::IsEmpty;
-using testing::Pair;
-using testing::UnorderedElementsAreArray;
-
-class ChannelProviderTest : public UnitTestFixture {
- public:
-  ChannelProviderTest() : executor_(dispatcher()) {}
-
- protected:
-  void SetUpChannelProviderServer(std::unique_ptr<stubs::ChannelControlBase> server) {
-    channel_provider_server_ = std::move(server);
-    if (channel_provider_server_) {
-      InjectServiceProvider(channel_provider_server_.get());
-    }
-  }
-
-  Annotations GetChannels(const AnnotationKeys& allowlist = {kAnnotationSystemUpdateChannelTarget},
-                          const zx::duration timeout = zx::sec(1)) {
-    ChannelProvider provider(dispatcher(), services());
-    auto promise = provider.GetAnnotations(timeout, allowlist);
-
-    bool was_called = false;
-    Annotations channels;
-    executor_.schedule_task(
-        std::move(promise).then([&was_called, &channels](::fpromise::result<Annotations>& res) {
-          was_called = true;
-
-          if (res.is_error()) {
-            return;
-          }
-
-          channels = std::move(res).value();
-        }));
-    RunLoopFor(timeout);
-
-    FX_CHECK(was_called);
-
-    return channels;
-  }
-
-  async::Executor executor_;
-
- private:
-  timekeeper::TestClock clock_;
-  std::unique_ptr<stubs::ChannelControlBase> channel_provider_server_;
-};
-
-TEST_F(ChannelProviderTest, Succeed_TargetChannel) {
-  auto channel_provider_server =
-      std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params{
-          .current = "current-channel",
-          .target = "target-channel",
-      });
-  SetUpChannelProviderServer(std::move(channel_provider_server));
-
-  const auto result = GetChannels({kAnnotationSystemUpdateChannelTarget});
-
-  EXPECT_THAT(result, UnorderedElementsAreArray({
-                          Pair(kAnnotationSystemUpdateChannelTarget, "target-channel"),
-                      }));
-}
-
-TEST_F(ChannelProviderTest, Succeed_EmptyChannel) {
-  SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlReturnsEmptyChannel>());
-
-  const auto result = GetChannels();
-
-  EXPECT_THAT(result, UnorderedElementsAreArray({
-                          Pair(kAnnotationSystemUpdateChannelTarget, ""),
-                      }));
-}
-
-TEST_F(ChannelProviderTest, Succeed_NoRequestedKeysInAllowlist) {
-  SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlReturnsEmptyChannel>());
-
-  const auto result = GetChannels({"not-returned-by-channel-provider"});
-
-  EXPECT_THAT(result, IsEmpty());
-}
-
-TEST_F(ChannelProviderTest, Fail_ChannelProviderServerNotAvailable) {
-  SetUpChannelProviderServer(nullptr);
-
-  const auto result = GetChannels();
-
-  EXPECT_THAT(result, UnorderedElementsAreArray({
-                          Pair(kAnnotationSystemUpdateChannelTarget, Error::kConnectionError),
-                      }));
-}
-
-TEST_F(ChannelProviderTest, Fail_ChannelProviderServerClosesConnection) {
-  SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlClosesConnection>());
-
-  const auto result = GetChannels();
-
-  EXPECT_THAT(result, UnorderedElementsAreArray({
-                          Pair(kAnnotationSystemUpdateChannelTarget, Error::kConnectionError),
-                      }));
-}
-
-TEST_F(ChannelProviderTest, Fail_ChannelProviderServerNeverReturns) {
-  SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlNeverReturns>());
-
-  const auto result = GetChannels();
-
-  EXPECT_THAT(result, UnorderedElementsAreArray({
-                          Pair(kAnnotationSystemUpdateChannelTarget, Error::kTimeout),
-                      }));
-}
-
-}  // namespace
-}  // namespace feedback_data
-}  // namespace forensics
diff --git a/src/developer/forensics/feedback_data/tests/datastore_unittest.cc b/src/developer/forensics/feedback_data/tests/datastore_unittest.cc
index 1ee63ce..f04c268 100644
--- a/src/developer/forensics/feedback_data/tests/datastore_unittest.cc
+++ b/src/developer/forensics/feedback_data/tests/datastore_unittest.cc
@@ -104,13 +104,6 @@
                                              inspect_data_budget_.get());
   }
 
-  void SetUpChannelProviderServer(std::unique_ptr<stubs::ChannelControlBase> server) {
-    channel_provider_server_ = std::move(server);
-    if (channel_provider_server_) {
-      InjectServiceProvider(channel_provider_server_.get());
-    }
-  }
-
   void SetUpDeviceIdProviderServer(std::unique_ptr<stubs::DeviceIdProviderBase> server) {
     device_id_provider_server_ = std::move(server);
     if (device_id_provider_server_) {
@@ -188,7 +181,6 @@
   std::unique_ptr<InspectDataBudget> inspect_data_budget_;
 
   // Stubs servers.
-  std::unique_ptr<stubs::ChannelControlBase> channel_provider_server_;
   std::unique_ptr<stubs::DeviceIdProviderBase> device_id_provider_server_;
   std::unique_ptr<stubs::DiagnosticsArchiveBase> diagnostics_server_;
 };
@@ -251,28 +243,6 @@
   GetAttachments();
 }
 
-TEST_F(DatastoreTest, GetAnnotations_TargetChannel) {
-  SetUpChannelProviderServer(
-      std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params({
-          .current = "current-channel",
-          .target = "target-channel",
-      })));
-  SetUpDatastore(
-      {
-          kAnnotationSystemUpdateChannelTarget,
-      },
-      kDefaultAttachmentsToAvoidSpuriousLogs);
-
-  ::fpromise::result<Annotations> annotations = GetAnnotations();
-  ASSERT_TRUE(annotations.is_ok());
-  EXPECT_THAT(annotations.take_value(),
-              ElementsAreArray({
-                  Pair(kAnnotationSystemUpdateChannelTarget, "target-channel"),
-              }));
-
-  EXPECT_THAT(GetImmediatelyAvailableAnnotations(), IsEmpty());
-}
-
 TEST_F(DatastoreTest, GetAnnotations_DeviceId) {
   SetUpDeviceIdProviderServer(std::make_unique<stubs::DeviceIdProvider>("device-id"));
   SetUpDatastore({kAnnotationDeviceFeedbackId}, kDefaultAttachmentsToAvoidSpuriousLogs);
diff --git a/src/developer/forensics/feedback_data/tests/meta/channel_provider_unittest.cml b/src/developer/forensics/feedback_data/tests/meta/channel_provider_unittest.cml
deleted file mode 100644
index 92deee0..0000000
--- a/src/developer/forensics/feedback_data/tests/meta/channel_provider_unittest.cml
+++ /dev/null
@@ -1,18 +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/gtest/default.shard.cml",
-        "inspect/client.shard.cml",
-        "syslog/client.shard.cml",
-    ],
-    program: {
-        binary: "bin/channel_provider_unittest_exe",
-    },
-    use: [
-        {
-            protocol: [ "fuchsia.process.Launcher" ],
-        },
-    ],
-}
diff --git a/src/developer/forensics/utils/fidl/BUILD.gn b/src/developer/forensics/utils/fidl/BUILD.gn
index 78038b1..2dce5fc 100644
--- a/src/developer/forensics/utils/fidl/BUILD.gn
+++ b/src/developer/forensics/utils/fidl/BUILD.gn
@@ -22,25 +22,6 @@
   ]
 }
 
-source_set("channel_provider_ptr") {
-  sources = [
-    "channel_provider_ptr.cc",
-    "channel_provider_ptr.h",
-  ]
-
-  public_deps = [
-    "//sdk/fidl/fuchsia.update.channelcontrol",
-    "//sdk/lib/fit-promise",
-    "//sdk/lib/sys/cpp",
-    "//src/developer/forensics/utils/fidl:oneshot_ptr",
-    "//src/lib/fxl",
-    "//zircon/system/ulib/async",
-    "//zircon/system/ulib/zx",
-  ]
-
-  deps = [ "//src/developer/forensics/utils:errors" ]
-}
-
 source_set("hanging_get_ptr") {
   sources = [ "hanging_get_ptr.h" ]
 
diff --git a/src/developer/forensics/utils/fidl/channel_provider_ptr.cc b/src/developer/forensics/utils/fidl/channel_provider_ptr.cc
deleted file mode 100644
index ebc9a64..0000000
--- a/src/developer/forensics/utils/fidl/channel_provider_ptr.cc
+++ /dev/null
@@ -1,86 +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.
-
-#include "src/developer/forensics/utils/fidl/channel_provider_ptr.h"
-
-#include <fuchsia/update/channelcontrol/cpp/fidl.h>
-#include <lib/syslog/cpp/macros.h>
-#include <zircon/types.h>
-
-#include <memory>
-
-#include "src/developer/forensics/utils/fidl/oneshot_ptr.h"
-#include "src/developer/forensics/utils/fit/promise.h"
-
-namespace forensics {
-namespace fidl {
-namespace {
-
-// Wraps around fuchsia::update::channelcontrol::ChannelControlPtr to handle establishing the
-// connection, losing the connection, waiting for the callback, enforcing a timeout, etc.
-//
-// Supports only one call to GetCurrentChannel() or GetTargetChannel().
-class ChannelProviderPtr {
- public:
-  // fuchsia.update.channelcontrol.ChannleControl is expected to be in |services|.
-  ChannelProviderPtr(async_dispatcher_t* dispatcher,
-                     std::shared_ptr<sys::ServiceDirectory> services)
-      : channel_ptr_(dispatcher, std::move(services)) {}
-
-  ::fpromise::promise<std::string, Error> GetCurrentChannel(fit::Timeout timeout) {
-    channel_ptr_->GetCurrent([this](std::string channel) {
-      if (channel_ptr_.IsAlreadyDone()) {
-        return;
-      }
-
-      channel_ptr_.CompleteOk(channel);
-    });
-
-    return channel_ptr_.WaitForDone(std::move(timeout));
-  }
-
-  ::fpromise::promise<std::string, Error> GetTargetChannel(fit::Timeout timeout) {
-    channel_ptr_->GetTarget([this](std::string channel) {
-      if (channel_ptr_.IsAlreadyDone()) {
-        return;
-      }
-
-      channel_ptr_.CompleteOk(channel);
-    });
-
-    return channel_ptr_.WaitForDone(std::move(timeout));
-  }
-
- private:
-  OneShotPtr<fuchsia::update::channelcontrol::ChannelControl, std::string> channel_ptr_;
-};
-
-}  // namespace
-
-::fpromise::promise<std::string, Error> GetCurrentChannel(
-    async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services,
-    fit::Timeout timeout) {
-  auto ptr = std::make_unique<fidl::ChannelProviderPtr>(dispatcher, services);
-
-  // We must store the promise in a variable due to the fact that the order of evaluation of
-  // function parameters is undefined.
-  auto channel = ptr->GetCurrentChannel(std::move(timeout));
-  return fit::ExtendArgsLifetimeBeyondPromise(/*promise=*/std::move(channel),
-                                              /*args=*/std::move(ptr));
-}
-
-::fpromise::promise<std::string, Error> GetTargetChannel(
-    async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services,
-    fit::Timeout timeout) {
-  auto ptr = std::make_unique<fidl::ChannelProviderPtr>(dispatcher, services);
-
-  // We must store the promise in a variable due to the fact that the order of evaluation of
-  // function parameters is undefined.
-  auto channel = ptr->GetTargetChannel(std::move(timeout));
-  return fit::ExtendArgsLifetimeBeyondPromise(/*promise=*/std::move(channel),
-                                              /*args=*/std::move(ptr));
-}
-
-}  // namespace fidl
-}  // namespace forensics
diff --git a/src/developer/forensics/utils/fidl/channel_provider_ptr.h b/src/developer/forensics/utils/fidl/channel_provider_ptr.h
deleted file mode 100644
index 9c43094..0000000
--- a/src/developer/forensics/utils/fidl/channel_provider_ptr.h
+++ /dev/null
@@ -1,38 +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.
-
-#ifndef SRC_DEVELOPER_FORENSICS_UTILS_FIDL_CHANNEL_PROVIDER_PTR_H_
-#define SRC_DEVELOPER_FORENSICS_UTILS_FIDL_CHANNEL_PROVIDER_PTR_H_
-
-#include <lib/async/dispatcher.h>
-#include <lib/fpromise/promise.h>
-#include <lib/sys/cpp/service_directory.h>
-
-#include <memory>
-#include <string>
-
-#include "src/developer/forensics/utils/errors.h"
-#include "src/developer/forensics/utils/fit/timeout.h"
-
-namespace forensics {
-namespace fidl {
-
-// Fetches the current update channel.
-//
-// fuchsia.update.channelcontrol.ChannelControl is expected to be in |services|.
-::fpromise::promise<std::string, Error> GetCurrentChannel(
-    async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services,
-    fit::Timeout timeout);
-
-// Fetches the target channel.
-//
-// fuchsia.update.channelcontrol.ChannelControl is expected to be in |services|.
-::fpromise::promise<std::string, Error> GetTargetChannel(
-    async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services,
-    fit::Timeout timeout);
-
-}  // namespace fidl
-}  // namespace forensics
-
-#endif  // SRC_DEVELOPER_FORENSICS_UTILS_FIDL_CHANNEL_PROVIDER_PTR_H_
diff --git a/src/developer/forensics/utils/tests/BUILD.gn b/src/developer/forensics/utils/tests/BUILD.gn
index cf3d025..c2ecf89 100644
--- a/src/developer/forensics/utils/tests/BUILD.gn
+++ b/src/developer/forensics/utils/tests/BUILD.gn
@@ -63,25 +63,6 @@
   ]
 }
 
-executable("channel_provider_ptr_unittest_exe") {
-  testonly = true
-
-  sources = [ "channel_provider_ptr_unittest.cc" ]
-
-  deps = [
-    "//sdk/lib/fit-promise",
-    "//sdk/lib/syslog/cpp",
-    "//src/developer/forensics/testing:gtest_with_syslog_main",
-    "//src/developer/forensics/testing:unit_test_fixture",
-    "//src/developer/forensics/testing/stubs:channel_control",
-    "//src/developer/forensics/utils/fidl:channel_provider_ptr",
-    "//third_party/googletest:gmock",
-    "//third_party/googletest:gtest",
-    "//zircon/system/ulib/async:async-cpp",
-    "//zircon/system/ulib/zx",
-  ]
-}
-
 executable("cobalt_unittest_exe") {
   testonly = true
 
@@ -282,10 +263,6 @@
   deps = [ ":caching_ptr_unittest_exe" ]
 }
 
-fuchsia_unittest_component("channel_provider_ptr_unittest") {
-  deps = [ ":channel_provider_ptr_unittest_exe" ]
-}
-
 fuchsia_unittest_component("cobalt_unittest") {
   deps = [ ":cobalt_unittest_exe" ]
 }
@@ -361,7 +338,6 @@
     ":archive_unittest",
     ":bridge_unittest",
     ":caching_ptr_unittest",
-    ":channel_provider_ptr_unittest",
     ":cobalt_unittest",
     ":component_unittest",
     ":hanging_get_ptr_unittest",
diff --git a/src/developer/forensics/utils/tests/channel_provider_ptr_unittest.cc b/src/developer/forensics/utils/tests/channel_provider_ptr_unittest.cc
deleted file mode 100644
index 8f71c78..0000000
--- a/src/developer/forensics/utils/tests/channel_provider_ptr_unittest.cc
+++ /dev/null
@@ -1,120 +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 "src/developer/forensics/utils/fidl/channel_provider_ptr.h"
-
-#include <lib/async/cpp/executor.h>
-#include <lib/fit/function.h>
-#include <lib/fpromise/promise.h>
-#include <lib/syslog/cpp/macros.h>
-#include <lib/zx/time.h>
-
-#include <memory>
-#include <optional>
-#include <string>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "src/developer/forensics/testing/stubs/channel_control.h"
-#include "src/developer/forensics/testing/unit_test_fixture.h"
-
-namespace forensics {
-namespace fidl {
-namespace {
-
-class ChannelProviderPtrTest : public UnitTestFixture {
- public:
-  ChannelProviderPtrTest() : executor_(dispatcher()) {}
-
- protected:
-  void SetUpChannelProviderServer(
-      std::unique_ptr<stubs::ChannelControlBase> channel_provider_server) {
-    channel_provider_server_ = std::move(channel_provider_server);
-    if (channel_provider_server_) {
-      InjectServiceProvider(channel_provider_server_.get());
-    }
-  }
-
-  std::optional<std::string> GetCurrentChannel(::fit::closure if_timeout = [] {}) {
-    return GetChannel(/*current=*/true, std::move(if_timeout));
-  }
-
-  std::optional<std::string> GetTargetChannel(::fit::closure if_timeout = [] {}) {
-    return GetChannel(/*current=*/false, std::move(if_timeout));
-  }
-
- private:
-  std::optional<std::string> GetChannel(
-      const bool current, ::fit::closure if_timeout = [] {}) {
-    const zx::duration timeout = zx::sec(1);
-    auto promise = (current) ? fidl::GetCurrentChannel(dispatcher(), services(),
-                                                       fit::Timeout(timeout, std::move(if_timeout)))
-                             : fidl::GetTargetChannel(dispatcher(), services(),
-                                                      fit::Timeout(timeout, std::move(if_timeout)));
-
-    bool was_called = false;
-    std::optional<std::string> channel;
-    executor_.schedule_task(std::move(promise).then(
-        [&was_called, &channel](::fpromise::result<std::string, Error>& res) {
-          was_called = true;
-
-          if (res.is_error()) {
-            channel = std::nullopt;
-          } else {
-            channel = res.take_value();
-          }
-        }));
-    RunLoopFor(timeout);
-    FX_CHECK(was_called);
-    return channel;
-  }
-
-  async::Executor executor_;
-  std::unique_ptr<stubs::ChannelControlBase> channel_provider_server_;
-};
-
-TEST_F(ChannelProviderPtrTest, Succeed_SomeChannel) {
-  auto channel_provider = std::make_unique<stubs::ChannelControl>(stubs::ChannelControlBase::Params{
-      .current = "current-channel",
-      .target = "target-channel",
-  });
-  SetUpChannelProviderServer(std::move(channel_provider));
-
-  {
-    const auto result = GetCurrentChannel();
-
-    ASSERT_TRUE(result);
-    EXPECT_EQ(result.value(), "current-channel");
-  }
-
-  {
-    const auto result = GetTargetChannel();
-
-    ASSERT_TRUE(result);
-    EXPECT_EQ(result.value(), "target-channel");
-  }
-}
-
-TEST_F(ChannelProviderPtrTest, Succeed_EmptyChannel) {
-  SetUpChannelProviderServer(std::make_unique<stubs::ChannelControlReturnsEmptyChannel>());
-
-  {
-    const auto result = GetCurrentChannel();
-
-    ASSERT_TRUE(result);
-    EXPECT_EQ(result.value(), "");
-  }
-
-  {
-    const auto result = GetTargetChannel();
-
-    ASSERT_TRUE(result);
-    EXPECT_EQ(result.value(), "");
-  }
-}
-
-}  // namespace
-}  // namespace fidl
-}  // namespace forensics
diff --git a/src/devices/bin/driver_host2/BUILD.gn b/src/devices/bin/driver_host2/BUILD.gn
index 07479fe..453184f 100644
--- a/src/devices/bin/driver_host2/BUILD.gn
+++ b/src/devices/bin/driver_host2/BUILD.gn
@@ -24,7 +24,8 @@
   ]
 
   public_deps = [
-    "//sdk/fidl/fuchsia.driver.framework:fuchsia.driver.framework_llcpp",
+    "//sdk/fidl/fuchsia.driver.framework:fuchsia.driver.framework_cpp",
+    "//sdk/fidl/fuchsia.io:fuchsia.io_cpp",
     "//sdk/lib/driver2:llcpp",
     "//sdk/lib/driver_runtime:driver_runtime_cpp",
     "//sdk/lib/driver_runtime:driver_runtime_internal_cpp",
diff --git a/src/devices/bin/driver_host2/driver_host.cc b/src/devices/bin/driver_host2/driver_host.cc
index c0a5586..4925850 100644
--- a/src/devices/bin/driver_host2/driver_host.cc
+++ b/src/devices/bin/driver_host2/driver_host.cc
@@ -4,7 +4,7 @@
 
 #include "src/devices/bin/driver_host2/driver_host.h"
 
-#include <fidl/fuchsia.io/cpp/wire.h>
+#include <fidl/fuchsia.io/cpp/fidl.h>
 #include <lib/async/cpp/task.h>
 #include <lib/driver2/start_args.h>
 #include <lib/fdf/cpp/dispatcher.h>
@@ -29,7 +29,7 @@
 
 namespace {
 
-class FileEventHandler : public fidl::WireAsyncEventHandler<fio::File> {
+class FileEventHandler : public fidl::AsyncEventHandler<fio::File> {
  public:
   explicit FileEventHandler(std::string url) : url_(std::move(url)) {}
 
@@ -47,6 +47,23 @@
   return i == std::string_view::npos ? url : url.substr(i + 1);
 }
 
+// TODO(fxbug.dev/99679): This logic needs to be kept in sync with |driver::NsValue|.
+// Once we have the ability to produce a const view from FIDL natural types, we can
+// directly use |driver::NsValue| and delete this function.
+zx::status<fidl::UnownedClientEnd<fuchsia_io::Directory>> NsValue(
+    const std::vector<fuchsia_component_runner::ComponentNamespaceEntry>& entries,
+    std::string_view path) {
+  for (auto& entry : entries) {
+    if (!entry.path() || !entry.directory()) {
+      continue;
+    }
+    if (path == *entry.path()) {
+      return zx::ok<fidl::UnownedClientEnd<fuchsia_io::Directory>>(*entry.directory());
+    }
+  }
+  return zx::error(ZX_ERR_NOT_FOUND);
+}
+
 }  // namespace
 
 zx::status<fbl::RefPtr<Driver>> Driver::Load(std::string url, zx::vmo vmo) {
@@ -85,16 +102,34 @@
   binding_.emplace(std::move(binding));
 }
 
-void Driver::Stop(StopRequestView request, StopCompleter::Sync& completer) { binding_->Unbind(); }
+void Driver::Stop(StopRequest& request, StopCompleter::Sync& completer) { binding_->Unbind(); }
 
-zx::status<> Driver::Start(fidl::IncomingMessage& start_args,
-                           fidl_opaque_wire_format_metadata_t wire_format_metadata,
+zx::status<> Driver::Start(fuchsia_driver_framework::DriverStartArgs start_args,
                            fdf::Dispatcher dispatcher) {
   initial_dispatcher_ = std::move(dispatcher);
 
+  fidl::OwnedEncodeResult encoded = fidl::Encode(std::move(start_args));
+  if (!encoded.message().ok()) {
+    LOGF(ERROR, "Failed to start driver, could not encode start args: %s",
+         encoded.message().FormatDescription().data());
+    return zx::error(encoded.message().status());
+  }
+  fidl_opaque_wire_format_metadata_t wire_format_metadata =
+      encoded.wire_format_metadata().ToOpaque();
+
+  // We convert the outgoing message into an incoming message to provide to the
+  // driver on start.
+  fidl::OutgoingToIncomingMessage converted_message{encoded.message()};
+  if (!converted_message.ok()) {
+    LOGF(ERROR, "Failed to start driver, could not convert start args: %s",
+         converted_message.FormatDescription().data());
+    return zx::error(converted_message.status());
+  }
+
   // After calling |record_->start|, we assume it has taken ownership of
   // the handles from |start_args|, and can therefore relinquish ownership.
-  fidl_incoming_msg_t c_msg = std::move(start_args).ReleaseToEncodedCMessage();
+  fidl_incoming_msg_t c_msg =
+      std::move(converted_message.incoming_message()).ReleaseToEncodedCMessage();
   void* opaque = nullptr;
   zx_status_t status =
       record_->start({&c_msg, wire_format_metadata}, initial_dispatcher_.get(), &opaque);
@@ -154,25 +189,29 @@
   return opts;
 }
 
-void DriverHost::Start(StartRequestView request, StartCompleter::Sync& completer) {
-  if (!request->start_args.has_url()) {
+void DriverHost::Start(StartRequest& request, StartCompleter::Sync& completer) {
+  if (!request.start_args().url()) {
     LOGF(ERROR, "Failed to start driver, missing 'url' argument");
     completer.Close(ZX_ERR_INVALID_ARGS);
     return;
   }
-  std::string url(request->start_args.url().get());
-  auto pkg = request->start_args.has_ns() ? driver::NsValue(request->start_args.ns(), "/pkg")
-                                          : zx::error(ZX_ERR_INVALID_ARGS);
+  const std::string& url = *request.start_args().url();
+  const auto& ns = request.start_args().ns();
+  auto pkg = ns ? NsValue(*ns, "/pkg") : zx::error(ZX_ERR_INVALID_ARGS);
   if (pkg.is_error()) {
     LOGF(ERROR, "Failed to start driver, missing '/pkg' directory: %s",
          zx_status_get_string(pkg.error_value()));
     completer.Close(pkg.error_value());
     return;
   }
-  zx::status<std::string> binary =
-      request->start_args.has_program()
-          ? driver::ProgramValue(request->start_args.program(), "binary")
-          : zx::error(ZX_ERR_INVALID_ARGS);
+
+  fidl::Arena arena;
+  zx::status<std::string> binary = zx::error(ZX_ERR_INVALID_ARGS);
+  fuchsia_data::wire::Dictionary wire_program;
+  if (request.start_args().program().has_value()) {
+    wire_program = fidl::ToWire(arena, *request.start_args().program());
+    binary = driver::ProgramValue(wire_program, "binary");
+  }
   if (binary.is_error()) {
     LOGF(ERROR, "Failed to start driver, missing 'binary' argument: %s",
          zx_status_get_string(binary.error_value()));
@@ -185,70 +224,39 @@
     completer.Close(endpoints.error_value());
     return;
   }
-  zx_status_t status = fdio_open_at(pkg->channel()->get(), binary->data(),
-                                    static_cast<uint32_t>(fio::wire::OpenFlags::kRightReadable |
-                                                          fio::wire::OpenFlags::kRightExecutable),
-                                    endpoints->server.TakeChannel().release());
+  zx_status_t status = fdio_open_at(
+      pkg->channel()->get(), binary->data(),
+      static_cast<uint32_t>(fio::OpenFlags::kRightReadable | fio::OpenFlags::kRightExecutable),
+      endpoints->server.TakeChannel().release());
   if (status != ZX_OK) {
     LOGF(ERROR, "Failed to start driver '%s', could not open library: %s", url.data(),
          zx_status_get_string(status));
     completer.Close(status);
     return;
   }
-  // We encode start_args outside of callback in order to access stack-allocated
-  // data before it is destroyed.
-  // TODO(fxbug.dev/45252): Use FIDL at rest.
-  fidl::unstable::OwnedEncodedMessage<fdf::wire::DriverStartArgs> message(
-      fidl::internal::WireFormatVersion::kV2, &request->start_args);
-  if (!message.ok()) {
-    LOGF(ERROR, "Failed to start driver '%s', could not encode start args: %s", url.data(),
-         message.FormatDescription().data());
-    completer.Close(message.status());
-    return;
-  }
-  fidl_opaque_wire_format_metadata_t wire_format_metadata =
-      message.wire_format_metadata().ToOpaque();
 
-  // We convert the outgoing message into an incoming message to provide to the
-  // driver on start.
-  auto converted_message =
-      std::make_unique<fidl::OutgoingToIncomingMessage>(message.GetOutgoingMessage());
-  if (!converted_message->ok()) {
-    LOGF(ERROR, "Failed to start driver '%s', could not convert start args: %s", url.data(),
-         converted_message->FormatDescription().data());
-    completer.Close(converted_message->status());
-    return;
-  }
-
-  uint32_t default_dispatcher_opts = ExtractDefaultDispatcherOpts(request->start_args.program());
+  uint32_t default_dispatcher_opts = ExtractDefaultDispatcherOpts(wire_program);
 
   // Once we receive the VMO from the call to GetBuffer, we can load the driver
   // into this driver host. We move the storage and encoded for start_args into
   // this callback to extend its lifetime.
-  fidl::WireSharedClient file(std::move(endpoints->client), loop_.dispatcher(),
-                              std::make_unique<FileEventHandler>(url));
-  auto callback = [this, request = std::move(request->driver), completer = completer.ToAsync(),
-                   url = std::move(url), converted_message = std::move(converted_message),
-                   wire_format_metadata,
-                   default_dispatcher_opts = std::move(default_dispatcher_opts), _ = file.Clone()](
-                      fidl::WireUnownedResult<fio::File::GetBackingMemory>& result) mutable {
-    if (!result.ok()) {
+  fidl::SharedClient file(std::move(endpoints->client), loop_.dispatcher(),
+                          std::make_unique<FileEventHandler>(url));
+  auto callback = [this, request = std::move(request.driver()), completer = completer.ToAsync(),
+                   start_args = std::move(request.start_args()),
+                   default_dispatcher_opts = default_dispatcher_opts,
+                   _ = file.Clone()](fidl::Result<fio::File::GetBackingMemory>& result) mutable {
+    const std::string& url = *start_args.url();
+    if (!result.is_ok()) {
       LOGF(ERROR, "Failed to start driver '%s', could not get library VMO: %s", url.data(),
-           result.error().FormatDescription().c_str());
-      completer.Close(result.status());
+           result.error_value().FormatDescription().c_str());
+      zx_status_t status = result.error_value().is_application_error()
+                               ? result.error_value().application_error()
+                               : result.error_value().transport_error().status();
+      completer.Close(status);
       return;
     }
-    auto& response = result.value();
-    switch (response.result.Which()) {
-      case fio::wire::File2GetBackingMemoryResult::Tag::kErr:
-        LOGF(ERROR, "Failed to start driver '%s', could not get library VMO: %s", url.data(),
-             zx_status_get_string(response.result.err()));
-        completer.Close(response.result.err());
-        return;
-      case fio::wire::File2GetBackingMemoryResult::Tag::kResponse:
-        break;
-    }
-    zx::vmo& vmo = response.result.response().vmo;
+    zx::vmo vmo = std::move(result->vmo());
     // Give the driver's VMO a name. We can't fit the entire URL in the name, so
     // use the name of the manifest from the URL.
     auto manifest = GetManifest(url);
@@ -307,8 +315,7 @@
 
     // Task to start the driver. Post this to the driver dispatcher thread.
     auto start_task = [this, request = std::move(request), completer = std::move(completer),
-                       converted_message = std::move(converted_message), wire_format_metadata,
-                       driver = std::move(*driver),
+                       start_args = std::move(start_args), driver = std::move(*driver),
                        driver_dispatcher = std::move(driver_dispatcher)]() mutable {
       // We have to add the driver to this list before calling Start in order to have an accurate
       // count of how many drivers exist in this driver host.
@@ -323,8 +330,7 @@
 
       // Save a ptr to the dispatcher so we can shut it down if starting the driver fails.
       fdf::UnownedDispatcher unowned_dispatcher = driver_dispatcher.borrow();
-      auto start = driver->Start(converted_message->incoming_message(), wire_format_metadata,
-                                 std::move(driver_dispatcher));
+      auto start = driver->Start(std::move(start_args), std::move(driver_dispatcher));
       if (start.is_error()) {
         LOGF(ERROR, "Failed to start driver '%s': %s", driver->url().data(), start.status_string());
         completer.Close(start.error_value());
@@ -356,7 +362,7 @@
           // run the destructor and call the driver's Stop hook.
           drivers_.erase(*driver);
 
-          // Send the epitath to the driver runner letting it know we stopped
+          // Send the epitaph to the driver runner letting it know we stopped
           // the driver correctly.
           server.Close(ZX_OK);
 
@@ -376,19 +382,19 @@
     };
     async::PostTask(driver_async_dispatcher, std::move(start_task));
   };
-  file->GetBackingMemory(fio::wire::VmoFlags::kRead | fio::wire::VmoFlags::kExecute |
-                         fio::wire::VmoFlags::kPrivateClone)
+  file->GetBackingMemory(fio::VmoFlags::kRead | fio::VmoFlags::kExecute |
+                         fio::VmoFlags::kPrivateClone)
       .ThenExactlyOnce(std::move(callback));
 }
 
-void DriverHost::GetProcessKoid(GetProcessKoidRequestView request,
+void DriverHost::GetProcessKoid(GetProcessKoidRequest& request,
                                 GetProcessKoidCompleter::Sync& completer) {
   zx_info_handle_basic_t info;
   zx_status_t status =
       zx::process::self()->get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
   if (status != ZX_OK) {
     LOGF(ERROR, "Failed to get info about process handle: %s", zx_status_get_string(status));
-    completer.ReplyError(status);
+    completer.Reply(zx::error(status));
   }
-  completer.ReplySuccess(info.koid);
+  completer.Reply(zx::ok(info.koid));
 }
diff --git a/src/devices/bin/driver_host2/driver_host.h b/src/devices/bin/driver_host2/driver_host.h
index 9264c47..052edf8 100644
--- a/src/devices/bin/driver_host2/driver_host.h
+++ b/src/devices/bin/driver_host2/driver_host.h
@@ -5,7 +5,7 @@
 #ifndef SRC_DEVICES_BIN_DRIVER_HOST2_DRIVER_HOST_H_
 #define SRC_DEVICES_BIN_DRIVER_HOST2_DRIVER_HOST_H_
 
-#include <fidl/fuchsia.driver.framework/cpp/wire.h>
+#include <fidl/fuchsia.driver.framework/cpp/fidl.h>
 #include <lib/async-loop/cpp/loop.h>
 #include <lib/driver2/record.h>
 #include <lib/fdf/cpp/dispatcher.h>
@@ -19,26 +19,23 @@
 
 #include "src/lib/storage/vfs/cpp/pseudo_dir.h"
 
-class Driver : public fidl::WireServer<fuchsia_driver_framework::Driver>,
+class Driver : public fidl::Server<fuchsia_driver_framework::Driver>,
                public fbl::RefCounted<Driver>,
                public fbl::DoublyLinkedListable<fbl::RefPtr<Driver>> {
  public:
   static zx::status<fbl::RefPtr<Driver>> Load(std::string url, zx::vmo vmo);
 
   Driver(std::string url, void* library, const DriverRecordV1* record);
-  ~Driver();
+  ~Driver() override;
 
   const std::string& url() const { return url_; }
   void set_binding(fidl::ServerBindingRef<fuchsia_driver_framework::Driver> binding);
 
-  void Stop(StopRequestView request, StopCompleter::Sync& completer) override;
+  void Stop(StopRequest& request, StopCompleter::Sync& completer) override;
 
   // Starts the driver.
-  //
-  // The handles in `message` will be consumed.
-  zx::status<> Start(fidl::IncomingMessage& message,
-                     fidl_opaque_wire_format_metadata_t wire_format_metadata,
-                     fdf::Dispatcher driver_dispatcher);
+  zx::status<> Start(fuchsia_driver_framework::DriverStartArgs start_args,
+                     fdf::Dispatcher dispatcher);
 
  private:
   std::string url_;
@@ -52,7 +49,7 @@
   fdf::Dispatcher initial_dispatcher_;
 };
 
-class DriverHost : public fidl::WireServer<fuchsia_driver_framework::DriverHost> {
+class DriverHost : public fidl::Server<fuchsia_driver_framework::DriverHost> {
  public:
   // DriverHost does not take ownership of `loop`, and `loop` must outlive
   // DriverHost.
@@ -62,10 +59,10 @@
   zx::status<> PublishDriverHost(component::OutgoingDirectory& outgoing_directory);
 
  private:
-  // fidl::WireServer<fuchsia_driver_framework::DriverHost>
-  void Start(StartRequestView request, StartCompleter::Sync& completer) override;
+  // fidl::Server<fuchsia_driver_framework::DriverHost>
+  void Start(StartRequest& request, StartCompleter::Sync& completer) override;
 
-  void GetProcessKoid(GetProcessKoidRequestView request,
+  void GetProcessKoid(GetProcessKoidRequest& request,
                       GetProcessKoidCompleter::Sync& completer) override;
 
   // Extracts the default_dispatcher_opts from |program| and converts it to
diff --git a/src/devices/bin/driver_host2/driver_host_test.cc b/src/devices/bin/driver_host2/driver_host_test.cc
index a383475..99e17a6 100644
--- a/src/devices/bin/driver_host2/driver_host_test.cc
+++ b/src/devices/bin/driver_host2/driver_host_test.cc
@@ -32,7 +32,7 @@
 namespace frunner = fuchsia_component_runner;
 namespace ftest = fuchsia_driverhost_test;
 
-using Completer = fidl::WireServer<fdf::DriverHost>::StartCompleter::Sync;
+using Completer = fidl::Server<fdf::DriverHost>::StartCompleter::Sync;
 using namespace inspect::testing;
 
 class FakeContext : public fpromise::context {
@@ -132,7 +132,7 @@
  protected:
   async::Loop& loop() { return loop_; }
   async::Loop& second_loop() { return second_loop_; }
-  fidl::WireServer<fdf::DriverHost>& driver_host() { return *driver_host_; }
+  fidl::Server<fdf::DriverHost>& driver_host() { return *driver_host_; }
   void set_driver_host(std::unique_ptr<DriverHost> driver_host) {
     driver_host_ = std::move(driver_host);
   }
@@ -142,25 +142,20 @@
                                         fbl::MakeRefCounted<fs::Service>(std::move(connector))));
   }
 
-  StartDriverResult StartDriver(fidl::VectorView<fdf::wire::NodeSymbol> symbols = {},
+  StartDriverResult StartDriver(std::vector<fdf::NodeSymbol> symbols = {},
                                 fidl::ClientEnd<fuchsia_driver_framework::Node>* node = nullptr,
                                 zx_status_t expected_epitaph = ZX_OK) {
     zx_status_t epitaph = ZX_OK;
     TestTransaction transaction(epitaph);
-    fidl::Arena arena;
 
     auto pkg_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
     EXPECT_TRUE(pkg_endpoints.is_ok());
     auto svc_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
     EXPECT_TRUE(svc_endpoints.is_ok());
 
-    fidl::VectorView<frunner::wire::ComponentNamespaceEntry> ns_entries(arena, 2);
-    ns_entries[0].Allocate(arena);
-    ns_entries[0].set_path(arena, "/pkg");
-    ns_entries[0].set_directory(std::move(pkg_endpoints->client));
-    ns_entries[1].Allocate(arena);
-    ns_entries[1].set_path(arena, "/svc");
-    ns_entries[1].set_directory(std::move(svc_endpoints->client));
+    std::vector<frunner::ComponentNamespaceEntry> ns_entries;
+    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);
@@ -175,31 +170,33 @@
         });
     EXPECT_EQ(ZX_OK, vfs_.ServeDirectory(svc_dir_, std::move(svc_endpoints->server)));
 
-    fidl::VectorView<fdata::wire::DictionaryEntry> program_entries(arena, 1);
-    program_entries[0].key.Set(arena, "binary");
-    program_entries[0].value = fdata::wire::DictionaryValue::WithStr(arena, "driver/library.so");
+    std::vector<fdata::DictionaryEntry> program_entries = {
+        {{
+            .key = "binary",
+            .value = std::make_unique<fdata::DictionaryValue>(
+                fdata::DictionaryValue::WithStr("driver/library.so")),
+        }},
+    };
 
     auto outgoing_dir_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
     EXPECT_TRUE(outgoing_dir_endpoints.is_ok());
     auto driver_endpoints = fidl::CreateEndpoints<fdf::Driver>();
     EXPECT_TRUE(driver_endpoints.is_ok());
     {
-      fdata::wire::Dictionary dictionary(arena);
-      dictionary.set_entries(arena, std::move(program_entries));
+      fdata::Dictionary dictionary = {{.entries = std::move(program_entries)}};
 
-      fdf::wire::DriverStartArgs driver_start_args(arena);
-      if (node != nullptr) {
-        driver_start_args.set_node(std::move(*node));
-      }
-      driver_start_args.set_symbols(arena, std::move(symbols));
-      driver_start_args.set_url(arena, "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm");
-      driver_start_args.set_program(arena, std::move(dictionary));
-      driver_start_args.set_ns(arena, std::move(ns_entries));
-      driver_start_args.set_outgoing_dir(std::move(outgoing_dir_endpoints->server));
+      fdf::DriverStartArgs driver_start_args = {{
+          .node = node != nullptr ? std::optional(std::move(*node)) : std::nullopt,
+          .symbols = std::move(symbols),
+          .url = "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm",
+          .program = std::move(dictionary),
+          .ns = std::move(ns_entries),
+          .outgoing_dir = std::move(std::move(outgoing_dir_endpoints->server)),
+      }};
       Completer completer(&transaction);
-      fidl::WireRequest<fdf::DriverHost::Start> request(driver_start_args,
-                                                        std::move(driver_endpoints->server));
-      driver_host().Start(&request, completer);
+      fidl::Request<fdf::DriverHost::Start> request(std::move(driver_start_args),
+                                                    std::move(driver_endpoints->server));
+      driver_host().Start(request, completer);
     }
     EXPECT_EQ(ZX_OK, loop().RunUntilIdle());
     fdf_internal_wait_until_all_dispatchers_idle();
@@ -318,11 +315,9 @@
 // Start a single driver, and return an error on start.
 TEST_F(DriverHostTest, Start_ReturnError) {
   zx_status_t error = ZX_ERR_STOP;
-  fidl::Arena arena;
-  fidl::VectorView<fdf::wire::NodeSymbol> symbols(arena, 1);
-  symbols[0].Allocate(arena);
-  symbols[0].set_name(arena, "error");
-  symbols[0].set_address(arena, reinterpret_cast<zx_vaddr_t>(&error));
+  std::vector<fdf::NodeSymbol> symbols = {
+      {{.name = "error", .address = reinterpret_cast<zx_vaddr_t>(&error)}},
+  };
   auto [driver, outgoing_dir] = StartDriver(std::move(symbols), nullptr, error);
 
   driver.reset();
@@ -339,11 +334,9 @@
 
 // Start a single driver, and receive a call to a shared function.
 TEST_F(DriverHostTest, Start_NodeSymbols) {
-  fidl::Arena arena;
-  fidl::VectorView<fdf::wire::NodeSymbol> symbols(arena, 1);
-  symbols[0].Allocate(arena);
-  symbols[0].set_name(arena, "func");
-  symbols[0].set_address(arena, reinterpret_cast<zx_vaddr_t>(Func));
+  std::vector<fdf::NodeSymbol> symbols = {
+      {{.name = "func", .address = reinterpret_cast<zx_vaddr_t>(Func)}},
+  };
   auto [driver, outgoing_dir] = StartDriver(std::move(symbols));
   EXPECT_TRUE(called);
 
@@ -357,19 +350,15 @@
 // Start two drivers, and verify that different dispatchers are used.
 TEST_F(DriverHostTest, Start_DifferentDispatcher) {
   fdf_dispatcher_t* dispatcher_1 = nullptr;
-  fidl::Arena arena_1;
-  fidl::VectorView<fdf::wire::NodeSymbol> symbols_1(arena_1, 1);
-  symbols_1[0].Allocate(arena_1);
-  symbols_1[0].set_name(arena_1, "dispatcher");
-  symbols_1[0].set_address(arena_1, reinterpret_cast<zx_vaddr_t>(&dispatcher_1));
+  std::vector<fdf::NodeSymbol> symbols_1 = {
+      {{.name = "dispatcher", .address = reinterpret_cast<zx_vaddr_t>(&dispatcher_1)}},
+  };
   auto [driver_1, outgoing_dir_1] = StartDriver(std::move(symbols_1));
 
   fdf_dispatcher_t* dispatcher_2 = nullptr;
-  fidl::Arena arena_2;
-  fidl::VectorView<fdf::wire::NodeSymbol> symbols_2(arena_2, 1);
-  symbols_2[0].Allocate(arena_2);
-  symbols_2[0].set_name(arena_2, "dispatcher");
-  symbols_2[0].set_address(arena_2, reinterpret_cast<zx_vaddr_t>(&dispatcher_2));
+  std::vector<fdf::NodeSymbol> symbols_2 = {
+      {{.name = "dispatcher", .address = reinterpret_cast<zx_vaddr_t>(&dispatcher_2)}},
+  };
   auto [driver_2, outgoing_dir_2] = StartDriver(std::move(symbols_2));
 
   EXPECT_NE(dispatcher_1, dispatcher_2);
@@ -392,9 +381,9 @@
   ASSERT_TRUE(endpoints.is_ok());
   {
     Completer completer(&transaction);
-    fidl::WireRequest<fdf::DriverHost::Start> request(fdf::wire::DriverStartArgs(),
-                                                      std::move(endpoints->server));
-    driver_host().Start(&request, completer);
+    fidl::Request<fdf::DriverHost::Start> request(fdf::DriverStartArgs(),
+                                                  std::move(endpoints->server));
+    driver_host().Start(request, completer);
   }
   EXPECT_EQ(ZX_ERR_INVALID_ARGS, epitaph);
 
@@ -403,13 +392,12 @@
   ASSERT_TRUE(endpoints.is_ok());
   {
     Completer completer(&transaction);
-    fidl::Arena arena;
-    fdf::wire::DriverStartArgs driver_start_args(arena);
-    driver_start_args.set_url(arena, "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm");
-
-    fidl::WireRequest<fdf::DriverHost::Start> request(std::move(driver_start_args),
-                                                      std::move(endpoints->server));
-    driver_host().Start(&request, completer);
+    fdf::DriverStartArgs driver_start_args{{
+        .url = "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm",
+    }};
+    fidl::Request<fdf::DriverHost::Start> request(std::move(driver_start_args),
+                                                  std::move(endpoints->server));
+    driver_host().Start(request, completer);
   }
   EXPECT_EQ(ZX_ERR_INVALID_ARGS, epitaph);
 
@@ -418,34 +406,32 @@
   ASSERT_TRUE(endpoints.is_ok());
   {
     Completer completer(&transaction);
-    fidl::Arena arena;
-    fdf::wire::DriverStartArgs driver_start_args(arena);
-    driver_start_args.set_url(arena, "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm");
-    driver_start_args.set_ns(arena);
-    fidl::WireRequest<fdf::DriverHost::Start> request(std::move(driver_start_args),
-                                                      std::move(endpoints->server));
-    driver_host().Start(&request, completer);
+    fdf::DriverStartArgs driver_start_args{{
+        .url = "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm",
+    }};
+    driver_start_args.ns().emplace();
+    fidl::Request<fdf::DriverHost::Start> request(std::move(driver_start_args),
+                                                  std::move(endpoints->server));
+    driver_host().Start(request, completer);
   }
   EXPECT_EQ(ZX_ERR_NOT_FOUND, epitaph);
 
   endpoints = fidl::CreateEndpoints<fdf::Driver>();
   ASSERT_TRUE(endpoints.is_ok());
   {
-    fidl::Arena arena;
     // DriverStartArgs::program not set.
-    fidl::VectorView<frunner::wire::ComponentNamespaceEntry> entries1(arena, 1);
-    entries1[0].Allocate(arena);
-    entries1[0].set_path(arena, "/pkg");
-    entries1[0].set_directory(fidl::ClientEnd<fuchsia_io::Directory>());
+    std::vector<frunner::ComponentNamespaceEntry> entries1;
+    entries1.push_back({{.path = "/pkg", .directory = fidl::ClientEnd<fuchsia_io::Directory>()}});
 
-    fdf::wire::DriverStartArgs driver_start_args(arena);
-    driver_start_args.set_url(arena, "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm");
-    driver_start_args.set_ns(arena, std::move(entries1));
+    fdf::DriverStartArgs driver_start_args{{
+        .url = "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm",
+        .ns = std::move(entries1),
+    }};
 
     Completer completer(&transaction);
-    fidl::WireRequest<fdf::DriverHost::Start> request(std::move(driver_start_args),
-                                                      std::move(endpoints->server));
-    driver_host().Start(&request, completer);
+    fidl::Request<fdf::DriverHost::Start> request(std::move(driver_start_args),
+                                                  std::move(endpoints->server));
+    driver_host().Start(request, completer);
   }
   EXPECT_EQ(ZX_ERR_INVALID_ARGS, epitaph);
 
@@ -453,21 +439,19 @@
   ASSERT_TRUE(endpoints.is_ok());
   {
     // DriverStartArgs::program is missing "binary" entry.
-    fidl::Arena arena;
-    fidl::VectorView<frunner::wire::ComponentNamespaceEntry> entries2(arena, 1);
-    entries2[0].Allocate(arena);
-    entries2[0].set_path(arena, "/pkg");
-    entries2[0].set_directory(fidl::ClientEnd<fuchsia_io::Directory>());
+    std::vector<frunner::ComponentNamespaceEntry> entries2;
+    entries2.push_back({{.path = "/pkg", .directory = fidl::ClientEnd<fuchsia_io::Directory>()}});
 
-    fdf::wire::DriverStartArgs driver_start_args(arena);
-    driver_start_args.set_url(arena, "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm");
-    driver_start_args.set_program(arena);
-    driver_start_args.set_ns(arena, std::move(entries2));
+    fdf::DriverStartArgs driver_start_args{{
+        .url = "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm",
+        .program = fdata::Dictionary{},
+        .ns = std::move(entries2),
+    }};
 
     Completer completer(&transaction);
-    fidl::WireRequest<fdf::DriverHost::Start> request(std::move(driver_start_args),
-                                                      std::move(endpoints->server));
-    driver_host().Start(&request, completer);
+    fidl::Request<fdf::DriverHost::Start> request(std::move(driver_start_args),
+                                                  std::move(endpoints->server));
+    driver_host().Start(request, completer);
   }
   EXPECT_EQ(ZX_ERR_NOT_FOUND, epitaph);
 }
@@ -492,14 +476,11 @@
 TEST_F(DriverHostTest, Start_InvalidBinary) {
   zx_status_t epitaph = ZX_OK;
   TestTransaction transaction(epitaph);
-  fidl::Arena arena;
 
   auto pkg_endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
   ASSERT_TRUE(pkg_endpoints.is_ok());
-  fidl::VectorView<frunner::wire::ComponentNamespaceEntry> ns_entries(arena, 1);
-  ns_entries[0].Allocate(arena);
-  ns_entries[0].set_path(arena, "/pkg");
-  ns_entries[0].set_directory(std::move(pkg_endpoints->client));
+  std::vector<frunner::ComponentNamespaceEntry> ns_entries;
+  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;
@@ -511,25 +492,25 @@
         EXPECT_EQ("driver/library.so", path);
         file_binding.Bind(object.TakeChannel(), loop().dispatcher());
       });
-  fidl::VectorView<fdata::wire::DictionaryEntry> program_entries(arena, 1);
-  program_entries[0].key.Set(arena, "binary");
-  program_entries[0].value = fdata::wire::DictionaryValue::WithStr(arena, "driver/library.so");
+  std::vector<fdata::DictionaryEntry> program_entries = {{{
+      .key = "binary",
+      .value = std::make_unique<fdata::DictionaryValue>(
+          fdata::DictionaryValue::WithStr("driver/library.so")),
+  }}};
 
   auto driver_endpoints = fidl::CreateEndpoints<fdf::Driver>();
   ASSERT_TRUE(driver_endpoints.is_ok());
   {
     Completer completer(&transaction);
-    fdata::wire::Dictionary dictionary(arena);
-    dictionary.set_entries(arena, std::move(program_entries));
-
-    fdf::wire::DriverStartArgs driver_start_args(arena);
-    driver_start_args.set_url(arena, "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm");
-    driver_start_args.set_program(arena, std::move(dictionary));
-    driver_start_args.set_ns(arena, std::move(ns_entries));
-
-    fidl::WireRequest<fdf::DriverHost::Start> request(std::move(driver_start_args),
-                                                      std::move(driver_endpoints->server));
-    driver_host().Start(&request, completer);
+    fdata::Dictionary dictionary{{.entries = std::move(program_entries)}};
+    fdf::DriverStartArgs driver_start_args{{
+        .url = "fuchsia-pkg://fuchsia.com/driver#meta/driver.cm",
+        .program = std::move(dictionary),
+        .ns = std::move(ns_entries),
+    }};
+    fidl::Request<fdf::DriverHost::Start> request(std::move(driver_start_args),
+                                                  std::move(driver_endpoints->server));
+    driver_host().Start(request, completer);
   }
   EXPECT_EQ(ZX_OK, loop().RunUntilIdle());
   EXPECT_EQ(ZX_ERR_NOT_FOUND, epitaph);
diff --git a/src/devices/block/drivers/ums-function/ums-function.c b/src/devices/block/drivers/ums-function/ums-function.c
index 6de6147..0997184 100644
--- a/src/devices/block/drivers/ums-function/ums-function.c
+++ b/src/devices/block/drivers/ums-function/ums-function.c
@@ -624,7 +624,8 @@
 
 static int usb_ums_thread(void* ctx) {
   usb_ums_t* ums = (usb_ums_t*)ctx;
-  while (1) {
+  ZX_ASSERT(ums->active);
+  while (ums->active) {
     mtx_lock(&ums->mtx);
     if (!(ums->cbw_req_complete || ums->csw_req_complete || ums->data_req_complete ||
           (!ums->active))) {
diff --git a/src/devices/block/drivers/usb-mass-storage/tests/ums-test.cc b/src/devices/block/drivers/usb-mass-storage/tests/ums-test.cc
index 417916c..7f96a53 100644
--- a/src/devices/block/drivers/usb-mass-storage/tests/ums-test.cc
+++ b/src/devices/block/drivers/usb-mass-storage/tests/ums-test.cc
@@ -316,8 +316,7 @@
   }
 }
 
-// TODO(fxbug.dev/98566) re-enable when the race is resolved.
-TEST_F(UmsTest, DISABLED_BlkdevTest) {
+TEST_F(UmsTest, BlkdevTest) {
   char errmsg[1024];
   fdio_spawn_action_t actions[1];
   actions[0] = {};
diff --git a/src/diagnostics/archivist/BUILD.gn b/src/diagnostics/archivist/BUILD.gn
index 8fefe00..3d58b3e 100644
--- a/src/diagnostics/archivist/BUILD.gn
+++ b/src/diagnostics/archivist/BUILD.gn
@@ -182,13 +182,11 @@
 fuchsia_component_manifest("root-manifest") {
   manifest = "meta/archivist.cml"
   component_name = "archivist"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component_manifest("archivist-for-embedding-v2-manifest") {
   manifest = "meta/archivist-for-embedding.cml"
   component_name = "archivist-for-embedding"
-  restricted_features = [ "structured_config" ]
 }
 
 # fxbug.dev/83213 Retain this component while out of tree tests depend on it
diff --git a/src/diagnostics/archivist/src/events/router.rs b/src/diagnostics/archivist/src/events/router.rs
index 2180782d..cb71ae4 100644
--- a/src/diagnostics/archivist/src/events/router.rs
+++ b/src/diagnostics/archivist/src/events/router.rs
@@ -4,13 +4,14 @@
 
 use crate::{events::types::*, identity::ComponentIdentity};
 use async_trait::async_trait;
-use fuchsia_inspect::{self as inspect, NumericProperty};
+use fuchsia_inspect::{self as inspect, NumericProperty, StringReference};
 use fuchsia_inspect_contrib::{inspect_log, nodes::BoundedListNode};
 use futures::{
     channel::{mpsc, oneshot},
     task::{Context, Poll},
     Future, SinkExt, Stream, StreamExt,
 };
+use lazy_static::lazy_static;
 use pin_project::pin_project;
 use std::{
     collections::{BTreeMap, BTreeSet},
@@ -24,6 +25,11 @@
 const MAX_EVENT_BUS_CAPACITY: usize = 1024;
 const RECENT_EVENT_LIMIT: usize = 200;
 
+lazy_static! {
+    static ref EVENT: StringReference<'static> = "event".into();
+    static ref MONIKER: StringReference<'static> = "moniker".into();
+}
+
 /// Core archivist internal event router that supports multiple event producers and multiple event
 /// consumers.
 pub struct EventRouter {
@@ -409,10 +415,10 @@
     }
 
     fn log_inspect(&mut self, event_name: &str, identity: &ComponentIdentity) {
-        // TODO(fxbug.dev/92374): leverage string references for the keys.
+        // TODO(fxbug.dev/92374): leverage string references for the `event_name`.
         inspect_log!(self.component_log_node,
-            event: event_name,
-            moniker: match &identity.instance_id {
+            &*EVENT => event_name,
+            &*MONIKER => match &identity.instance_id {
                 Some(instance_id) => format!("{}:{}", identity.relative_moniker, instance_id),
                 None => identity.relative_moniker.to_string(),
             }
diff --git a/src/diagnostics/archivist/src/events/source_registry.rs b/src/diagnostics/archivist/src/events/source_registry.rs
index 342e79e..1a65a3c 100644
--- a/src/diagnostics/archivist/src/events/source_registry.rs
+++ b/src/diagnostics/archivist/src/events/source_registry.rs
@@ -7,7 +7,7 @@
         events::{error::EventError, types::*},
         identity::ComponentIdentity,
     },
-    fuchsia_inspect::{self as inspect, NumericProperty},
+    fuchsia_inspect::{self as inspect, NumericProperty, StringReference},
     fuchsia_inspect_contrib::{inspect_log, nodes::BoundedListNode},
     futures::{
         channel::{mpsc, oneshot},
@@ -22,6 +22,11 @@
     },
 };
 
+lazy_static! {
+    pub static ref EVENT: StringReference<'static> = "event".into();
+    pub static ref MONIKER: StringReference<'static> = "moniker".into();
+}
+
 /// Tracks all event sources and listens to events coming from them pushing them into an MPSC
 /// channel.
 pub struct EventSourceRegistry {
@@ -209,8 +214,8 @@
 
     fn log_inspect(&mut self, event_name: &str, identity: &ComponentIdentity) {
         inspect_log!(self.component_log_node,
-            event: event_name,
-            moniker: match &identity.instance_id {
+            &*EVENT => event_name,
+            &*MONIKER => match &identity.instance_id {
                 Some(instance_id) => format!("{}:{}", identity.relative_moniker, instance_id),
                 None => identity.relative_moniker.to_string(),
             }
diff --git a/src/diagnostics/archivist/src/moniker_rewriter.rs b/src/diagnostics/archivist/src/moniker_rewriter.rs
index b39124b..02b6b95 100644
--- a/src/diagnostics/archivist/src/moniker_rewriter.rs
+++ b/src/diagnostics/archivist/src/moniker_rewriter.rs
@@ -25,6 +25,10 @@
             legacy_str: "omaha-client-service.cmx",
             modern_str: "core/omaha-client-service",
         },
+        MonikerRewritePair {
+            legacy_str: "cobalt_system_metrics.cmx",
+            modern_str: "core/cobalt_system_metrics"
+        }
     ];
 }
 
diff --git a/src/diagnostics/archivist/tests/v2/BUILD.gn b/src/diagnostics/archivist/tests/v2/BUILD.gn
index b692946..eb8c8ac 100644
--- a/src/diagnostics/archivist/tests/v2/BUILD.gn
+++ b/src/diagnostics/archivist/tests/v2/BUILD.gn
@@ -86,7 +86,6 @@
 fuchsia_component_manifest("with-log-connector-manifest") {
   manifest = "meta/archivist_for_integration_with_log_connector.cml"
   component_name = "archivist_with_log_connector"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("archivist-for-integration-with-log-connector") {
@@ -98,7 +97,6 @@
 fuchsia_component_manifest("with-klog-manifest") {
   manifest = "meta/archivist_with_klog.cml"
   component_name = "archivist_with_klog"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("archivist-with-klog") {
@@ -110,7 +108,6 @@
 fuchsia_component_manifest("for-integration-manifest") {
   manifest = "meta/archivist_for_integration.cml"
   component_name = "archivist"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("archivist-for-integration") {
@@ -122,7 +119,6 @@
 fuchsia_component_manifest("small-caches-manifest") {
   manifest = "meta/archivist-with-small-caches.cml"
   component_name = "archivist-with-small-caches"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("archivist-with-small-caches") {
@@ -134,7 +130,6 @@
 fuchsia_component_manifest("with-feedback-filtering-manifest") {
   manifest = "meta/archivist_for_integration.cml"
   component_name = "archivist-with-feedback-filtering"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("archivist-with-feedback-filtering") {
@@ -146,7 +141,6 @@
 fuchsia_component_manifest("with-legacy-metrics-filtering-manifest") {
   manifest = "meta/archivist_for_integration.cml"
   component_name = "archivist-with-legacy-metrics-filtering"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("archivist-with-legacy-metrics-filtering") {
@@ -158,7 +152,6 @@
 fuchsia_component_manifest("with-feedback-filtering-disabled-manifest") {
   manifest = "meta/archivist_for_integration.cml"
   component_name = "archivist-with-feedback-filtering-disabled"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("archivist-with-feedback-filtering-disabled") {
diff --git a/src/diagnostics/config/fire/components.json5 b/src/diagnostics/config/fire/components.json5
index c61fd8f..7154f7af 100644
--- a/src/diagnostics/config/fire/components.json5
+++ b/src/diagnostics/config/fire/components.json5
@@ -32,7 +32,7 @@
     {
         id: 107,
         label: "Cobalt Sys Metrics",
-        moniker: "cobalt_system_metrics.cmx",
+        moniker: "core/cobalt_system_metrics",
     },
     {
         id: 108,
diff --git a/src/diagnostics/detect/BUILD.gn b/src/diagnostics/detect/BUILD.gn
index e27d852..94b70ac 100644
--- a/src/diagnostics/detect/BUILD.gn
+++ b/src/diagnostics/detect/BUILD.gn
@@ -69,7 +69,6 @@
 fuchsia_component_manifest("triage-detect-manifest") {
   manifest = "meta/triage-detect.cml"
   component_name = "triage-detect"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_structured_config_values("triage-detect-prod-config") {
diff --git a/src/diagnostics/sampler/BUILD.gn b/src/diagnostics/sampler/BUILD.gn
index c612fbb..876562c 100644
--- a/src/diagnostics/sampler/BUILD.gn
+++ b/src/diagnostics/sampler/BUILD.gn
@@ -71,7 +71,6 @@
 fuchsia_component_manifest("sampler-manifest") {
   component_name = "sampler"
   manifest = "meta/sampler.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("sampler-component") {
diff --git a/src/firmware/lib/fastboot/test/BUILD.gn b/src/firmware/lib/fastboot/test/BUILD.gn
index 13ff944..84cd31b 100644
--- a/src/firmware/lib/fastboot/test/BUILD.gn
+++ b/src/firmware/lib/fastboot/test/BUILD.gn
@@ -7,10 +7,7 @@
 
 group("test") {
   testonly = true
-  if (!is_coverage) {
-    # TODO(https://fxbug.dev/100208): Re-enable this test once it is fixed on coverage bot.
-    deps = [ ":fastboot-test-package" ]
-  }
+  deps = [ ":fastboot-test-package" ]
 }
 
 test("fastboot-test") {
diff --git a/src/fonts/tools/manifest_generator/src/font_catalog.rs b/src/fonts/tools/manifest_generator/src/font_catalog.rs
index 5cf2f49..f10c822 100644
--- a/src/fonts/tools/manifest_generator/src/font_catalog.rs
+++ b/src/fonts/tools/manifest_generator/src/font_catalog.rs
@@ -183,9 +183,8 @@
     /// Ensure that every alias `name` is unique among all the `FontFamilyAliasSet`s.
     fn post_validate(groups: Vec<Self>) -> Result<Vec<Self>, MergeError<Self>> {
         let mut unique = HashSet::new();
-        #[allow(clippy::clone_double_ref)] // TODO(fxbug.dev/95060)
         let first_duplicate =
-            groups.iter().flat_map(|group| group.names()).find(|name| !unique.insert(name.clone()));
+            groups.iter().flat_map(|group| group.names()).find(|&name| !unique.insert(name));
         match first_duplicate {
             Some(name) => {
                 Err(MergeError::PostInvalid(format!("{:?} appeared more than once", name), groups))
diff --git a/src/graphics/display/drivers/intel-i915/dp-display-unittest.cc b/src/graphics/display/drivers/intel-i915/dp-display-unittest.cc
index a1a8f6f..2e0d764 100644
--- a/src/graphics/display/drivers/intel-i915/dp-display-unittest.cc
+++ b/src/graphics/display/drivers/intel-i915/dp-display-unittest.cc
@@ -49,7 +49,7 @@
 
   std::optional<i915::DpllState> LoadState(registers::Ddi ddi) final {
     i915::DpllState state = i915::DpDpllState{
-        .dp_rate = registers::DpllControl1::LinkRate::k2700Mhz,
+        .dp_bit_rate_mhz = 5400,
     };
     return std::make_optional(state);
   }
@@ -202,7 +202,7 @@
   ASSERT_NE(nullptr, display);
 
   i915::DpllState dpll_state = i915::DpDpllState{
-      .dp_rate = registers::DpllControl1::LinkRate::k2160Mhz,
+      .dp_bit_rate_mhz = 4320u,
   };
   display->InitWithDpllState(&dpll_state);
   EXPECT_EQ(4320u, display->link_rate_mhz());
diff --git a/src/graphics/display/drivers/intel-i915/dp-display.cc b/src/graphics/display/drivers/intel-i915/dp-display.cc
index a8fa211..dcf0dc3 100644
--- a/src/graphics/display/drivers/intel-i915/dp-display.cc
+++ b/src/graphics/display/drivers/intel-i915/dp-display.cc
@@ -167,54 +167,6 @@
   DP_REPLY_I2C_DEFER = 8,
 };
 
-// Conversions from DPLL Control register supported link rates and corresponding DisplayPort link
-// clock frequencies. |link_clock| is a numeric value expressed in Mbps/MHz.
-//
-// Only a limited set of discrete |link_lock| values are supported. Returns an error result if the
-// value is not supported.
-
-fpromise::result<registers::DpllControl1::LinkRate> LinkClockToDpllLinkRate(uint32_t link_clock) {
-  using LinkRate = registers::DpllControl1::LinkRate;
-  switch (link_clock) {
-    case 5400:
-      return fpromise::ok(LinkRate::k2700Mhz);
-    case 2700:
-      return fpromise::ok(LinkRate::k1350Mhz);
-    case 1620:
-      return fpromise::ok(LinkRate::k810Mhz);
-    case 3240:
-      return fpromise::ok(LinkRate::k1620Mhz);
-    case 2160:
-      return fpromise::ok(LinkRate::k1080Mhz);
-    case 4320:
-      return fpromise::ok(LinkRate::k2160Mhz);
-    default:
-      break;
-  }
-  return fpromise::error();
-}
-
-fpromise::result<uint32_t> DpllLinkRateToLinkClock(registers::DpllControl1::LinkRate link_rate) {
-  using LinkRate = registers::DpllControl1::LinkRate;
-  switch (link_rate) {
-    case LinkRate::k2700Mhz:
-      return fpromise::ok(5400);
-    case LinkRate::k1350Mhz:
-      return fpromise::ok(2700);
-    case LinkRate::k810Mhz:
-      return fpromise::ok(1620);
-    case LinkRate::k1620Mhz:
-      return fpromise::ok(3240);
-    case LinkRate::k1080Mhz:
-      return fpromise::ok(2160);
-    case LinkRate::k2160Mhz:
-      return fpromise::ok(4320);
-    default:
-      break;
-  }
-  return fpromise::error();
-}
-
 std::string DpcdRevisionToString(dpcd::Revision rev) {
   switch (rev) {
     case dpcd::Revision::k1_0:
@@ -1200,14 +1152,8 @@
     }
   }
 
-  auto dpll_link_rate = LinkClockToDpllLinkRate(dp_link_rate_mhz_);
-  if (dpll_link_rate.is_error()) {
-    zxlogf(ERROR, "Unsupported DP link clock: %u", dp_link_rate_mhz_);
-    return false;
-  }
-
   DpllState state = DpDpllState{
-      .dp_rate = dpll_link_rate.value(),
+      .dp_bit_rate_mhz = dp_link_rate_mhz_,
   };
 
   DisplayPll* dpll = controller()->dpll_manager()->Map(ddi(), is_edp, state);
@@ -1247,26 +1193,17 @@
   // Some display (e.g. eDP) may have already been configured by the bootloader with a
   // link clock. Assign the link rate based on the already enabled DPLL.
   if (dp_link_rate_mhz_ == 0) {
-    fpromise::result<uint32_t> link_rate = DpllLinkRateToLinkClock(dp_state->dp_rate);
-    if (link_rate.is_ok()) {
-      zxlogf(INFO, "Selected pre-configured DisplayPort link rate: %u Mbps/lane",
-             link_rate.value());
-      SetLinkRate(link_rate.value());
-    } else {
-      zxlogf(ERROR, "Invalid DPLL link rate value: %u", static_cast<uint8_t>(dp_state->dp_rate));
-    }
+    // Since the link rate is read from the register directly, we can guarantee
+    // that it is always valid.
+    zxlogf(INFO, "Selected pre-configured DisplayPort link rate: %u Mbps/lane",
+           dp_state->dp_bit_rate_mhz);
+    SetLinkRate(dp_state->dp_bit_rate_mhz);
   }
 }
 
 bool DpDisplay::ComputeDpllState(uint32_t pixel_clock_10khz, DpllState* config) {
-  auto dpll_link_rate = LinkClockToDpllLinkRate(dp_link_rate_mhz_);
-  if (dpll_link_rate.is_error()) {
-    zxlogf(ERROR, "Unsupported DP link clock: %u", dp_link_rate_mhz_);
-    return false;
-  }
-
   *config = DpDpllState{
-      .dp_rate = dpll_link_rate.value(),
+      .dp_bit_rate_mhz = dp_link_rate_mhz_,
   };
   return true;
 }
diff --git a/src/graphics/display/drivers/intel-i915/dpll.cc b/src/graphics/display/drivers/intel-i915/dpll.cc
index 68c4236..657a156 100644
--- a/src/graphics/display/drivers/intel-i915/dpll.cc
+++ b/src/graphics/display/drivers/intel-i915/dpll.cc
@@ -6,6 +6,7 @@
 
 #include <zircon/assert.h>
 
+#include <optional>
 #include <variant>
 
 #include "src/graphics/display/drivers/intel-i915/intel-i915.h"
@@ -40,7 +41,7 @@
 
     const auto& dp_a = std::get<DpDpllState>(a);
     const auto& dp_b = std::get<DpDpllState>(b);
-    return dp_a.dp_rate == dp_b.dp_rate;
+    return dp_a.dp_bit_rate_mhz == dp_b.dp_bit_rate_mhz;
   }
 
   if (std::holds_alternative<HdmiDpllState>(a)) {
@@ -60,6 +61,45 @@
   return false;
 }
 
+std::optional<registers::DpllControl1::LinkRate> DpBitRateMhzToSklLinkRate(
+    uint32_t dp_bit_rate_mhz) {
+  switch (dp_bit_rate_mhz) {
+    case 5400:
+      return registers::DpllControl1::LinkRate::k2700Mhz;
+    case 2700:
+      return registers::DpllControl1::LinkRate::k1350Mhz;
+    case 1620:
+      return registers::DpllControl1::LinkRate::k810Mhz;
+    case 3240:
+      return registers::DpllControl1::LinkRate::k1620Mhz;
+    case 2160:
+      return registers::DpllControl1::LinkRate::k1080Mhz;
+    case 4320:
+      return registers::DpllControl1::LinkRate::k2160Mhz;
+    default:
+      return std::nullopt;
+  }
+}
+
+std::optional<uint32_t> SklLinkRateToDpBitRateMhz(registers::DpllControl1::LinkRate link_rate) {
+  switch (link_rate) {
+    case registers::DpllControl1::LinkRate::k2700Mhz:
+      return 5400;
+    case registers::DpllControl1::LinkRate::k1350Mhz:
+      return 2700;
+    case registers::DpllControl1::LinkRate::k810Mhz:
+      return 1620;
+    case registers::DpllControl1::LinkRate::k1620Mhz:
+      return 3240;
+    case registers::DpllControl1::LinkRate::k1080Mhz:
+      return 2160;
+    case registers::DpllControl1::LinkRate::k2160Mhz:
+      return 4320;
+    default:
+      return std::nullopt;
+  }
+}
+
 }  // namespace
 
 DisplayPll::DisplayPll(registers::Dpll dpll) : dpll_(dpll), name_(GetDpllName(dpll)) {}
@@ -139,7 +179,12 @@
   auto dpll_ctrl1 = registers::DpllControl1::Get().ReadFrom(mmio_space_);
   dpll_ctrl1.dpll_hdmi_mode(dpll()).set(0);
   dpll_ctrl1.dpll_ssc_enable(dpll()).set(0);
-  dpll_ctrl1.SetLinkRate(dpll(), dp_state.dp_rate);
+  auto dp_rate = DpBitRateMhzToSklLinkRate(dp_state.dp_bit_rate_mhz);
+  if (!dp_rate.has_value()) {
+    zxlogf(ERROR, "Invalid DP bit rate: %u MHz", dp_state.dp_bit_rate_mhz);
+    return false;
+  }
+  dpll_ctrl1.SetLinkRate(dpll(), *dp_rate);
   dpll_ctrl1.dpll_override(dpll()).set(1);
   dpll_ctrl1.WriteTo(mmio_space_);
   dpll_ctrl1.ReadFrom(mmio_space_);  // Posting read
@@ -286,8 +331,14 @@
         .cf = static_cast<uint8_t>(dpll_cfg2.central_freq()),
     };
   } else {
+    auto dp_bit_rate_mhz = SklLinkRateToDpBitRateMhz(dpll_ctrl1.GetLinkRate(dpll));
+    if (!dp_bit_rate_mhz.has_value()) {
+      zxlogf(ERROR, "Invalid DPLL link rate from DPLL %d", dpll);
+      return std::nullopt;
+    }
+
     new_state = DpDpllState{
-        dpll_ctrl1.GetLinkRate(dpll),
+        .dp_bit_rate_mhz = *dp_bit_rate_mhz,
     };
   }
 
diff --git a/src/graphics/display/drivers/intel-i915/dpll.h b/src/graphics/display/drivers/intel-i915/dpll.h
index d44a2c5..eac691b 100644
--- a/src/graphics/display/drivers/intel-i915/dpll.h
+++ b/src/graphics/display/drivers/intel-i915/dpll.h
@@ -21,7 +21,8 @@
 namespace i915 {
 
 struct DpDpllState {
-  registers::DpllControl1::LinkRate dp_rate;
+  // Bit rate (Mbps / MHz) of one DP lane.
+  uint32_t dp_bit_rate_mhz;
 };
 
 struct HdmiDpllState {
diff --git a/src/identity/bin/password_authenticator/BUILD.gn b/src/identity/bin/password_authenticator/BUILD.gn
index 6138923..dc72137 100644
--- a/src/identity/bin/password_authenticator/BUILD.gn
+++ b/src/identity/bin/password_authenticator/BUILD.gn
@@ -72,7 +72,6 @@
 fuchsia_component_manifest("manifest") {
   component_name = "password-authenticator"
   manifest = "meta/password-authenticator.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("component") {
diff --git a/src/lib/cobalt/rust/src/sender.rs b/src/lib/cobalt/rust/src/sender.rs
index 1251b07..e965793 100644
--- a/src/lib/cobalt/rust/src/sender.rs
+++ b/src/lib/cobalt/rust/src/sender.rs
@@ -16,8 +16,6 @@
     },
 };
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 macro_rules! gen_comment {
     ($x:expr) => {
         #[doc = $x]
diff --git a/src/lib/component_hub/tests/BUILD.gn b/src/lib/component_hub/tests/BUILD.gn
index 13e921f..aa1397f 100644
--- a/src/lib/component_hub/tests/BUILD.gn
+++ b/src/lib/component_hub/tests/BUILD.gn
@@ -37,7 +37,6 @@
   testonly = true
   component_name = "foo"
   manifest = "meta/foo.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("foo") {
diff --git a/src/lib/diagnostics/inspect/contrib/rust/src/log/impls.rs b/src/lib/diagnostics/inspect/contrib/rust/src/log/impls.rs
index 08c5b49f..946305e 100644
--- a/src/lib/diagnostics/inspect/contrib/rust/src/log/impls.rs
+++ b/src/lib/diagnostics/inspect/contrib/rust/src/log/impls.rs
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 use super::WriteInspect;
-use fuchsia_inspect::Node;
+use fuchsia_inspect::{Node, StringReference};
 
 // --- Utility macros to help with implementing WriteInspect ---
 
@@ -11,7 +11,7 @@
     ($inspect_value_type:ident, $_self:ident => $self_expr:expr, $($ty:ty),+) => {
         $(
             impl WriteInspect for $ty {
-                fn write_inspect(&$_self, writer: &Node, key: &str) {
+                fn write_inspect<'a>(&$_self, writer: &Node, key: impl Into<StringReference<'a>>) {
                     write_inspect_value!($inspect_value_type, writer, key, $self_expr);
                 }
             }
@@ -46,7 +46,7 @@
 impl_write_inspect!(Bool, self => *self, bool);
 
 impl<V: WriteInspect + ?Sized> WriteInspect for &V {
-    fn write_inspect(&self, writer: &Node, key: &str) {
+    fn write_inspect<'a>(&self, writer: &Node, key: impl Into<StringReference<'a>>) {
         (*self).write_inspect(writer, key)
     }
 }
diff --git a/src/lib/diagnostics/inspect/contrib/rust/src/log/mod.rs b/src/lib/diagnostics/inspect/contrib/rust/src/log/mod.rs
index ea8dfa7..1487fc8 100644
--- a/src/lib/diagnostics/inspect/contrib/rust/src/log/mod.rs
+++ b/src/lib/diagnostics/inspect/contrib/rust/src/log/mod.rs
@@ -22,9 +22,10 @@
 mod impls;
 mod wrappers;
 
+pub use fuchsia_inspect::StringReference;
 pub use wrappers::{InspectBytes, InspectList, InspectListClosure};
 
-use fuchsia_inspect::{Node, StringReference};
+use fuchsia_inspect::Node;
 use lazy_static::lazy_static;
 
 lazy_static! {
@@ -36,10 +37,7 @@
     /// Write a *single* value (property or child node) to |node| with the specified |key|.
     /// If multiple properties need to be written, consider creating a single child
     /// node with those properties.
-    ///
-    /// If the same key is used to write values multiple times, then there will be multiple
-    /// values with the same name in the underlying VMO.
-    fn write_inspect(&self, writer: &Node, key: &str);
+    fn write_inspect<'a>(&self, writer: &Node, key: impl Into<StringReference<'a>>);
 }
 
 /// Macro to log a new entry to a bounded list node with the specified key-value pairs. Each value
@@ -148,6 +146,11 @@
         inspect_insert!(@internal $node_writer, var key?: $($rest)+);
     }};
 
+    (@internal $node_writer:expr, $key:expr => $($rest:tt)+) => {{
+        let key: $crate::log::StringReference<'_> = $key.into();
+        inspect_insert!(@internal $node_writer, var key: $($rest)+);
+    }};
+
     // Entry point: from inspect_log! (mainly to allow empty event)
     (@internal_inspect_log $node_writer:expr, { $($args:tt)* }) => {{
         // User may specify an empty event, so `WriteInspect` may not always
@@ -203,14 +206,14 @@
 macro_rules! make_inspect_loggable {
     ($($args:tt)+) => {{
         use $crate::inspect_insert;
-        use fuchsia_inspect::Node;
+        use fuchsia_inspect::{Node, StringReference};
         struct WriteInspectClosure<F>(F);
-        impl<F> WriteInspect for WriteInspectClosure<F> where F: Fn(&Node, &str) {
-            fn write_inspect(&self, writer: &Node, key: &str) {
-                self.0(writer, key);
+        impl<F> WriteInspect for WriteInspectClosure<F> where F: Fn(&Node, StringReference<'_>) {
+            fn write_inspect<'a>(&self, writer: &Node, key: impl Into<StringReference<'a>>) {
+                self.0(writer, key.into());
             }
         }
-        let f = WriteInspectClosure(move |writer: &Node, key: &str| {
+        let f = WriteInspectClosure(move |writer: &Node, key: StringReference<'_>| {
             let child = writer.create_child(key);
             inspect_insert!(child, $($args)+);
             writer.record(child);
@@ -501,6 +504,31 @@
         });
     }
 
+    #[fuchsia::test]
+    fn test_log_inspect_string_reference() {
+        let executor = fasync::TestExecutor::new_with_fake_time().unwrap();
+        executor.set_fake_time(fasync::Time::from_nanos(12345));
+        let (inspector, mut node) = inspector_and_list_node();
+
+        lazy_static! {
+            static ref FOO: StringReference<'static> = "foo".into();
+        };
+
+        inspect_log!(node, &*FOO => "foo_1");
+        inspect_log!(node, &*FOO => "foo_2");
+        inspect_log!(node, &*FOO => "foo_3");
+        inspect_log!(node, &*FOO => "foo_4");
+
+        assert_data_tree!(inspector, root: {
+            list_node: {
+                "0": { "@time": 12345i64, foo: "foo_1" },
+                "1": { "@time": 12345i64, foo: "foo_2" },
+                "2": { "@time": 12345i64, foo: "foo_3" },
+                "3": { "@time": 12345i64, foo: "foo_4" },
+            }
+        });
+    }
+
     fn inspector_and_list_node() -> (Inspector, BoundedListNode) {
         let inspector = Inspector::new();
         let list_node = inspector.root().create_child("list_node");
diff --git a/src/lib/diagnostics/inspect/contrib/rust/src/log/wrappers.rs b/src/lib/diagnostics/inspect/contrib/rust/src/log/wrappers.rs
index a27fa2e..0c0ff92 100644
--- a/src/lib/diagnostics/inspect/contrib/rust/src/log/wrappers.rs
+++ b/src/lib/diagnostics/inspect/contrib/rust/src/log/wrappers.rs
@@ -2,7 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use {super::WriteInspect, fuchsia_inspect::Node, std::convert::AsRef};
+use {
+    super::WriteInspect,
+    fuchsia_inspect::{Node, StringReference},
+    std::convert::AsRef,
+};
 
 /// Wrapper to log bytes in an `inspect_log!` or `inspect_insert!` macro.
 ///
@@ -12,7 +16,7 @@
 pub struct InspectBytes<T: AsRef<[u8]>>(pub T);
 
 impl<T: AsRef<[u8]>> WriteInspect for InspectBytes<T> {
-    fn write_inspect(&self, writer: &Node, key: &str) {
+    fn write_inspect<'a>(&self, writer: &Node, key: impl Into<StringReference<'a>>) {
         writer.record_bytes(key, self.0.as_ref());
     }
 }
@@ -39,7 +43,7 @@
 where
     T: WriteInspect,
 {
-    fn write_inspect(&self, writer: &Node, key: &str) {
+    fn write_inspect<'b>(&self, writer: &Node, key: impl Into<StringReference<'b>>) {
         let child = writer.create_child(key);
         for (i, val) in self.0.iter().enumerate() {
             val.write_inspect(&child, &i.to_string());
@@ -77,7 +81,7 @@
 where
     F: Fn(&Node, &str, &T),
 {
-    fn write_inspect(&self, writer: &Node, key: &str) {
+    fn write_inspect<'b>(&self, writer: &Node, key: impl Into<StringReference<'b>>) {
         let child = writer.create_child(key);
         for (i, val) in self.0.iter().enumerate() {
             self.1(&child, &i.to_string(), val);
diff --git a/src/lib/fdio/rust/src/fdio_sys.rs b/src/lib/fdio/rust/src/fdio_sys.rs
index 064aa26..2ebf226 100644
--- a/src/lib/fdio/rust/src/fdio_sys.rs
+++ b/src/lib/fdio/rust/src/fdio_sys.rs
@@ -5,6 +5,10 @@
 // This file was generated with bindgen, then modified to consume already bound
 // types and remove various bindgen-isms that we don't want.
 
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(non_upper_case_globals)]
 // TODO(https://github.com/rust-lang/rust-bindgen/issues/1651): Remove once bindgen is fixed.
 #![cfg_attr(test, allow(deref_nullptr))]
 
@@ -18,22 +22,18 @@
     pub fn new() -> Self {
         __IncompleteArrayField(::std::marker::PhantomData)
     }
-    #[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99069)
     #[inline]
     pub unsafe fn as_ptr(&self) -> *const T {
         ::std::mem::transmute(self)
     }
-    #[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99069)
     #[inline]
     pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
         ::std::mem::transmute(self)
     }
-    #[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99069)
     #[inline]
     pub unsafe fn as_slice(&self, len: usize) -> &[T] {
         ::std::slice::from_raw_parts(self.as_ptr(), len)
     }
-    #[allow(clippy::missing_safety_doc)] // TODO(fxbug.dev/99069)
     #[inline]
     pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
         ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
diff --git a/src/lib/fdio/rust/src/lib.rs b/src/lib/fdio/rust/src/lib.rs
index 9b21c49..37ad2c6 100644
--- a/src/lib/fdio/rust/src/lib.rs
+++ b/src/lib/fdio/rust/src/lib.rs
@@ -4,14 +4,14 @@
 
 //! Bindings for the Zircon fdio library
 
-#[allow(bad_style)]
-pub mod fdio_sys;
+mod fdio_sys;
 
 mod spawn_builder;
+
 pub use spawn_builder::{Error as SpawnBuilderError, SpawnBuilder};
 
 use {
-    ::bitflags::bitflags,
+    bitflags::bitflags,
     fidl_fuchsia_device::ControllerSynchronousProxy,
     fidl_fuchsia_io as fio,
     fuchsia_zircon::{
@@ -23,6 +23,7 @@
         ffi::{self, CStr, CString},
         fs::File,
         marker::PhantomData,
+        mem::MaybeUninit,
         os::{
             raw,
             unix::{
@@ -160,31 +161,49 @@
     }
 }
 
-pub fn transfer_fd(file: std::fs::File) -> Result<zx::Handle, zx::Status> {
-    unsafe {
-        let mut fd_handle = zx::sys::ZX_HANDLE_INVALID;
-        let status = fdio_sys::fdio_fd_transfer(
-            file.into_raw_fd(),
-            &mut fd_handle as *mut zx::sys::zx_handle_t,
-        );
-        if status != zx::sys::ZX_OK {
-            return Err(zx::Status::from_raw(status));
-        }
-        Ok(zx::Handle::from_raw(fd_handle))
-    }
+/// Clones an object's underlying handle.
+pub fn clone_fd<F: AsRawFd>(f: F) -> Result<zx::Handle, zx::Status> {
+    let fd = f.as_raw_fd();
+    let mut handle = MaybeUninit::uninit();
+    let status = {
+        let handle = handle.as_mut_ptr();
+        unsafe { fdio_sys::fdio_fd_clone(fd, handle) }
+    };
+    let () = zx::Status::ok(status)?;
+    let handle = unsafe { handle.assume_init() };
+    let handle = unsafe { zx::Handle::from_raw(handle) };
+    Ok(handle)
 }
 
-/// Create a open file descriptor from a Handle.
+/// Removes an object from the file descriptor table and returns its underlying handle.
+pub fn transfer_fd<F: AsRawFd>(f: F) -> Result<zx::Handle, zx::Status> {
+    let fd = f.as_raw_fd();
+    let mut handle = MaybeUninit::uninit();
+    let status = {
+        let handle = handle.as_mut_ptr();
+        unsafe { fdio_sys::fdio_fd_transfer(fd, handle) }
+    };
+    let () = zx::Status::ok(status)?;
+    let handle = unsafe { handle.assume_init() };
+    let handle = unsafe { zx::Handle::from_raw(handle) };
+    Ok(handle)
+}
+
+/// Create an object from a handle.
 ///
 /// Afterward, the handle is owned by fdio, and will close with `F`.
 /// See `transfer_fd` for a way to get it back.
 pub fn create_fd<F: FromRawFd>(handle: zx::Handle) -> Result<F, zx::Status> {
-    unsafe {
-        let mut raw_fd = -1;
-        let status = fdio_sys::fdio_fd_create(handle.into_raw(), &mut raw_fd);
-        zx::Status::ok(status)?;
-        Ok(F::from_raw_fd(raw_fd))
-    }
+    let handle = handle.into_raw();
+    let mut fd = MaybeUninit::uninit();
+    let status = {
+        let fd = fd.as_mut_ptr();
+        unsafe { fdio_sys::fdio_fd_create(handle, fd) }
+    };
+    let () = zx::Status::ok(status)?;
+    let fd = unsafe { fd.assume_init() };
+    let f = unsafe { F::from_raw_fd(fd) };
+    Ok(f)
 }
 
 /// Bind a handle to a specific file descriptor.
@@ -328,6 +347,8 @@
 pub struct SpawnAction<'a>(fdio_sys::fdio_spawn_action_t, PhantomData<&'a ()>);
 
 impl<'a> SpawnAction<'a> {
+    pub const USE_FOR_STDIO: i32 = fdio_sys::FDIO_FLAG_USE_FOR_STDIO as i32;
+
     /// Clone a file descriptor into the new process.
     ///
     /// `local_fd`: File descriptor within the current process.
diff --git a/src/lib/fidl/cpp/include/lib/fidl/cpp/channel.h b/src/lib/fidl/cpp/include/lib/fidl/cpp/channel.h
index 43b3a57..66a1e99 100644
--- a/src/lib/fidl/cpp/include/lib/fidl/cpp/channel.h
+++ b/src/lib/fidl/cpp/include/lib/fidl/cpp/channel.h
@@ -17,6 +17,156 @@
 
 namespace fidl {
 
+//
+// Note: when updating the documentation below, please make similar updates to
+// the one in //zircon/system/ulib/fidl/include/lib/fidl/llcpp/channel.h
+//
+// The interface documentation on |fidl::SyncClient| is largely identical to
+// those on |fidl::WireSyncClient|, after removing the "wire" portion from
+// comments.
+//
+
+// |fidl::SyncClient| owns a client endpoint and exposes synchronous FIDL calls
+// taking both natural and wire types. Prefer using this owning class over
+// |fidl::Call| unless one has to interface with very low-level functionality
+// (such as making a call over a raw zx_handle_t).
+//
+// Generated FIDL APIs are accessed by 'dereferencing' the client value:
+//
+//     // Creates a sync client that speaks over |client_end|.
+//     fidl::SyncClient client(std::move(client_end));
+//
+//     // Call the |Foo| method synchronously, obtaining the results from the
+//     // return value.
+//     fidl::Result result = client->Foo(args);
+//
+// |fidl::SyncClient| is suitable for code without access to an async
+// dispatcher.
+//
+// |fidl::SyncClient| includes a superset of the functionality of
+// |fidl::WireSyncClient|, which only exposes synchronous FIDL calls with wire
+// types. Prefer |fidl::SyncClient| over |fidl::WireSyncClient| unless your
+// application needs to statically enforce that only the more performant wire
+// types are used.
+//
+// ## Thread safety
+//
+// |SyncClient| is generally thread-safe with a few caveats:
+//
+// - Client objects can be safely sent between threads.
+// - One may invoke many FIDL methods in parallel on the same client. However,
+//   FIDL method calls must be synchronized with operations that consume or
+//   mutate the client object itself:
+//
+//     - Calling `Bind` or `TakeClientEnd`.
+//     - Assigning a new value to the |SyncClient| variable.
+//     - Moving the |SyncClient| to a different location.
+//     - Destroying the |SyncClient|.
+//
+// - There can be at most one `HandleOneEvent` call going on at the same time.
+template <typename FidlProtocol>
+class SyncClient : private WireSyncClient<FidlProtocol> {
+ private:
+  using Base = WireSyncClient<FidlProtocol>;
+
+ public:
+  // Creates an uninitialized client that is not bound to a client endpoint.
+  //
+  // Prefer using the constructor overload that initializes the client
+  // atomically during construction. Use this default constructor only when the
+  // client must be constructed first before an endpoint could be obtained (for
+  // example, if the client is an instance variable).
+  //
+  // The client may be initialized later via |Bind|.
+  SyncClient() = default;
+
+  // Creates an initialized client. FIDL calls will be made on |client_end|.
+  //
+  // Similar to |fidl::Client|, the client endpoint must be valid.
+  //
+  // To just make a FIDL call uniformly on a client endpoint that may or may not
+  // be valid, use the |fidl::Call(client_end)| helper. We may extend
+  // |fidl::SyncClient<P>| with richer features hinging on having a valid
+  // endpoint in the future.
+  explicit SyncClient(::fidl::ClientEnd<FidlProtocol> client_end) : Base(std::move(client_end)) {}
+
+  ~SyncClient() = default;
+  SyncClient(SyncClient&&) noexcept = default;
+  SyncClient& operator=(SyncClient&&) noexcept = default;
+
+  // Whether the client is initialized.
+  bool is_valid() const { return Base::is_valid(); }
+  explicit operator bool() const { return Base::operator bool(); }
+
+  // Borrows the underlying client endpoint. The client must have been
+  // initialized.
+  const ::fidl::ClientEnd<FidlProtocol>& client_end() const { return Base::client_end(); }
+
+  // Initializes the client with a |client_end|. FIDL calls will be made on this
+  // endpoint.
+  //
+  // It is not allowed to call |Bind| on an initialized client. To rebind a
+  // |SyncClient| to a different endpoint, simply replace the
+  // |SyncClient| variable with a new instance.
+  void Bind(::fidl::ClientEnd<FidlProtocol> client_end) { Base::Bind(std::move(client_end)); }
+
+  // Extracts the underlying endpoint from the client. After this operation, the
+  // client goes back to an uninitialized state.
+  //
+  // It is not safe to invoke this method while there are ongoing FIDL calls.
+  ::fidl::ClientEnd<FidlProtocol> TakeClientEnd() { return Base::TakeClientEnd(); }
+
+  // Returns the interface for making FIDL calls with natural objects.
+  internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>> operator->()
+      const {
+    ZX_ASSERT(is_valid());
+    return internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>>(
+        fidl::internal::MakeAnyUnownedTransport(client_end().handle()));
+  }
+
+  // Returns the interface for making outgoing FIDL calls using wire objects.
+  // The client must be initialized first.
+  const Base& wire() const { return *this; }
+
+  // TODO(fxbug.dev/60240): Implement natural sync event handler.
+  //
+  // Handle all possible events defined in this protocol.
+  //
+  // Blocks to consume exactly one message from the channel, then call the corresponding virtual
+  // method defined in |event_handler|. If the message was unknown or malformed, returns an
+  // error without calling any virtual method.
+  ::fidl::Status HandleOneEvent(fidl::WireSyncEventHandler<FidlProtocol>& event_handler) const {
+    return event_handler.HandleOneEvent(client_end());
+  }
+};
+
+template <typename FidlProtocol>
+SyncClient(fidl::ClientEnd<FidlProtocol>) -> SyncClient<FidlProtocol>;
+
+// |Call| is used to make method calls directly on a |fidl::ClientEnd|
+// without having to set up a client. Call it like:
+//
+//     fidl::Call(client_end)->Method(args...);
+//
+template <typename FidlProtocol>
+internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>> Call(
+    const fidl::ClientEnd<FidlProtocol>& client_end) {
+  return internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>>(
+      fidl::internal::MakeAnyUnownedTransport(client_end.borrow().handle()));
+}
+
+// |Call| is used to make method calls directly on a |fidl::ClientEnd|
+// without having to set up a client. Call it like:
+//
+//     fidl::Call(client_end)->Method(args...);
+//
+template <typename FidlProtocol>
+internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>> Call(
+    const fidl::UnownedClientEnd<FidlProtocol>& client_end) {
+  return internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>>(
+      fidl::internal::MakeAnyUnownedTransport(client_end.handle()));
+}
+
 // Return an interface for sending FIDL events containing natural domain objects
 // over the endpoint managed by |binding_ref|. Call it like:
 //
diff --git a/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/make_response_context.h b/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/make_response_context.h
index 0f34ff7..23f72d7 100644
--- a/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/make_response_context.h
+++ b/src/lib/fidl/cpp/include/lib/fidl/cpp/internal/make_response_context.h
@@ -9,9 +9,83 @@
 #include <lib/fidl/cpp/unified_messaging.h>
 #include <lib/fidl/llcpp/client_base.h>
 
+#include <optional>
+
 namespace fidl {
 namespace internal {
 
+// |DecodeResponseAndFoldError| decodes an incoming message |incoming| returns
+// a transport-specific result type (e.g. |fidl::Result| for Zircon channel
+// transport). In doing so it combines any FIDL application error from the error
+// syntax with transport errors.
+//
+// If a terminal error occurred which warrants unbinding, |out_maybe_unbind|
+// will be populated with a reason if not nullptr.
+template <typename FidlMethod>
+auto DecodeResponseAndFoldError(::fidl::IncomingMessage&& incoming,
+                                ::std::optional<::fidl::UnbindInfo>* out_maybe_unbind) {
+  using ResultType = typename FidlMethod::Protocol::Transport::template Result<FidlMethod>;
+  using NaturalResponse = ::fidl::Response<FidlMethod>;
+  constexpr bool HasApplicationError =
+      ::fidl::internal::NaturalMethodTypes<FidlMethod>::HasApplicationError;
+  constexpr bool IsAbsentBody = ::fidl::internal::NaturalMethodTypes<FidlMethod>::IsAbsentBody;
+
+  // Check error from the underlying transport.
+  if (!incoming.ok()) {
+    ResultType error = ::fitx::error(incoming.error());
+    if (out_maybe_unbind != nullptr) {
+      out_maybe_unbind->emplace(incoming.error());
+    }
+    return error;
+  }
+
+  ::fitx::result decoded = [&] {
+    if constexpr (IsAbsentBody) {
+      return DecodeTransactionalMessage(std::move(incoming));
+    } else {
+      using Body = typename MessageTraits<NaturalResponse>::Payload;
+      return DecodeTransactionalMessage<Body>(std::move(incoming));
+    }
+  }();
+
+  // Check decoding error.
+  if (decoded.is_error()) {
+    ResultType error = ::fitx::error(decoded.error_value());
+    if (out_maybe_unbind != nullptr) {
+      out_maybe_unbind->emplace(decoded.error_value());
+    }
+    return error;
+  }
+
+  if constexpr (IsAbsentBody) {
+    // Absent body.
+    ResultType value = ::fitx::success();
+    return value;
+  } else {
+    NaturalResponse response =
+        NaturalMessageConverter<NaturalResponse>::FromDomainObject(std::move(decoded.value()));
+    if constexpr (HasApplicationError) {
+      // Fold application error.
+      if (response.is_error()) {
+        ResultType error = response.take_error();
+        return error;
+      }
+      ZX_DEBUG_ASSERT(response.is_ok());
+      if constexpr (::fidl::internal::NaturalMethodTypes<FidlMethod>::IsEmptyStructPayload) {
+        // Omit empty structs.
+        ResultType value = ::fitx::success();
+        return value;
+      } else {
+        ResultType value = response.take_value();
+        return value;
+      }
+    } else {
+      ResultType value = ::fitx::ok(std::move(response));
+      return value;
+    }
+  }
+}
+
 // |MakeResponseContext| is a helper to create an adaptor from a |ResponseContext|
 // to a response/result callback. It returns a raw pointer which deletes itself
 // upon the receipt of a response or an error.
@@ -27,73 +101,14 @@
         : ::fidl::internal::ResponseContext(ordinal), callback_(std::move(callback)) {}
 
    private:
-    ::cpp17::optional<::fidl::UnbindInfo> OnRawResult(
+    std::optional<::fidl::UnbindInfo> OnRawResult(
         ::fidl::IncomingMessage&& result,
         ::fidl::internal::IncomingTransportContext transport_context) override {
-      using NaturalResponse = ::fidl::Response<FidlMethod>;
-      constexpr bool HasApplicationError =
-          ::fidl::internal::NaturalMethodTypes<FidlMethod>::HasApplicationError;
-      constexpr bool IsAbsentBody = ::fidl::internal::NaturalMethodTypes<FidlMethod>::IsAbsentBody;
-
-      struct DeleteSelf {
-        ResponseContext* c;
-        ~DeleteSelf() { delete c; }
-      } delete_self{this};
-
-      // Check transport error.
-      if (!result.ok()) {
-        ResultType error = ::fitx::error(result.error());
-        callback_(error);
-        return cpp17::nullopt;
-      }
-
-      ::fitx::result decoded = [&] {
-        if constexpr (IsAbsentBody) {
-          return DecodeTransactionalMessage(std::move(result));
-        } else {
-          using Body = typename MessageTraits<NaturalResponse>::Payload;
-          return DecodeTransactionalMessage<Body>(std::move(result));
-        }
-      }();
-
-      // Check decoding error.
-      if (decoded.is_error()) {
-        ::fidl::UnbindInfo unbind_info = ::fidl::UnbindInfo(decoded.error_value());
-        ResultType error = ::fitx::error(decoded.error_value());
-        callback_(error);
-        return unbind_info;
-      }
-
-      if constexpr (IsAbsentBody) {
-        // Absent body.
-        ResultType value = ::fitx::success();
-        callback_(value);
-      } else {
-        NaturalResponse response =
-            NaturalMessageConverter<NaturalResponse>::FromDomainObject(std::move(decoded.value()));
-        if constexpr (HasApplicationError) {
-          // Fold application error.
-          if (response.is_error()) {
-            ResultType error = response.take_error();
-            callback_(error);
-          } else {
-            ZX_DEBUG_ASSERT(response.is_ok());
-            if constexpr (::fidl::internal::NaturalMethodTypes<FidlMethod>::IsEmptyStructPayload) {
-              // Omit empty structs.
-              ResultType value = ::fitx::success();
-              callback_(value);
-            } else {
-              ResultType value = response.take_value();
-              callback_(value);
-            }
-          }
-        } else {
-          ResultType value = ::fitx::ok(std::move(response));
-          callback_(value);
-        }
-      }
-
-      return cpp17::nullopt;
+      std::optional<fidl::UnbindInfo> maybe_unbind;
+      ResultType value = DecodeResponseAndFoldError<FidlMethod>(std::move(result), &maybe_unbind);
+      callback_(value);
+      delete this;
+      return maybe_unbind;
     }
 
     ::fidl::ClientCallback<FidlMethod> callback_;
diff --git a/src/lib/fidl/cpp/include/lib/fidl/cpp/unified_messaging_declarations.h b/src/lib/fidl/cpp/include/lib/fidl/cpp/unified_messaging_declarations.h
index 1c7c777..4fed509 100644
--- a/src/lib/fidl/cpp/include/lib/fidl/cpp/unified_messaging_declarations.h
+++ b/src/lib/fidl/cpp/include/lib/fidl/cpp/unified_messaging_declarations.h
@@ -111,8 +111,16 @@
 template <typename FidlProtocol>
 class NaturalEventSender;
 
-// |NaturalClientImpl| implements methods for making synchronous and
-// asynchronous FIDL calls with natural types.
+// |NaturalSyncClientImpl| implements methods for making synchronous
+// FIDL calls with natural types.
+//
+// All specializations of |NaturalSyncClientImpl| should inherit from
+// |fidl::internal::SyncEndpointManagedVeneer|.
+template <typename Protocol>
+class NaturalSyncClientImpl;
+
+// |NaturalClientImpl| implements methods for making asynchronous FIDL calls
+// with natural types.
 //
 // All specializations of |NaturalClientImpl| should inherit from
 // |fidl::internal::NaturalClientBase|.
diff --git a/src/lib/fidl/cpp/tests/integration/wire_interop_tests.cc b/src/lib/fidl/cpp/tests/integration/wire_interop_tests.cc
index 2921588..b659d4ee 100644
--- a/src/lib/fidl/cpp/tests/integration/wire_interop_tests.cc
+++ b/src/lib/fidl/cpp/tests/integration/wire_interop_tests.cc
@@ -694,4 +694,204 @@
   }
 }
 
+// Test fixture to simplify creating endpoints and a unified client to talk to
+// a wire domain object server.
+class UnifiedSyncClientToWireServer : public zxtest::Test, public MockData {
+ public:
+  UnifiedSyncClientToWireServer() : loop_(&kAsyncLoopConfigNeverAttachToThread) {}
+
+  void SetUp() final {
+    zx::status client_end =
+        fidl::CreateEndpoints<fidl_cpp_wire_interop_test::Interop>(&server_end_);
+    ASSERT_OK(client_end.status_value());
+    client_.Bind(std::move(*client_end));
+  }
+
+  async::Loop& loop() { return loop_; }
+  fidl::ServerEnd<fidl_cpp_wire_interop_test::Interop>& server_end() { return server_end_; }
+  fidl::SyncClient<fidl_cpp_wire_interop_test::Interop>& client() { return client_; }
+
+ private:
+  async::Loop loop_;
+  fidl::ServerEnd<fidl_cpp_wire_interop_test::Interop> server_end_;
+  fidl::SyncClient<fidl_cpp_wire_interop_test::Interop> client_;
+};
+
+// TODO: more sync client tests
+TEST_F(UnifiedSyncClientToWireServer, RoundTrip) {
+  class Server : public WireTestBase {
+   public:
+    void RoundTrip(RoundTripRequestView request, RoundTripCompleter::Sync& completer) final {
+      CheckWireFile(request->node);
+      num_calls++;
+      completer.Reply(request->node);
+    }
+
+    int num_calls = 0;
+  };
+  Server server;
+  fidl::BindServer(loop().dispatcher(), std::move(server_end()), &server);
+  ASSERT_OK(loop().StartThread());
+
+  {
+    // Test with natural domain objects.
+    auto node = MakeNaturalFile();
+    fidl_cpp_wire_interop_test::InteropRoundTripRequest request{std::move(node)};
+
+    fidl::Result<fidl_cpp_wire_interop_test::Interop::RoundTrip> result =
+        client()->RoundTrip(std::move(request));
+
+    ASSERT_TRUE(result.is_ok());
+    CheckNaturalFile(result->node());
+    EXPECT_EQ(1, server.num_calls);
+
+    // Check that `fidl::Call` works with this one test (since they delegate
+    // to the same implementation, we don't need to test `fidl::Call` everywhere).
+    static_assert(std::is_same_v<cpp20::remove_cvref_t<decltype(fidl::Call(client().client_end()))>,
+                                 cpp20::remove_cvref_t<decltype(client().operator->())>>,
+                  "fidl::Call and fidl::SyncClient exposes the same impl");
+    fidl::Result<fidl_cpp_wire_interop_test::Interop::RoundTrip> call_result =
+        fidl::Call(client().client_end())->RoundTrip({MakeNaturalFile()});
+    ASSERT_TRUE(call_result.is_ok());
+    CheckNaturalFile(call_result->node());
+    EXPECT_EQ(2, server.num_calls);
+  }
+
+  {
+    // Test with wire domain objects.
+    fidl::Arena arena;
+    auto node = MakeWireFile(arena);
+
+    fidl::WireResult<fidl_cpp_wire_interop_test::Interop::RoundTrip> result =
+        client().wire()->RoundTrip(node);
+
+    ASSERT_TRUE(result.ok(), "RoundTrip failed: %s", result.error().FormatDescription().c_str());
+    auto* response = result.Unwrap();
+    CheckWireFile(response->node);
+    EXPECT_EQ(3, server.num_calls);
+
+    // Check that `.wire().buffer()` exists with this one test
+    // (caller-allocating flavors extensively tested elsewhere).
+    fidl::WireUnownedResult<fidl_cpp_wire_interop_test::Interop::RoundTrip>
+        caller_allocating_result = client().wire().buffer(arena)->RoundTrip(node);
+    response = caller_allocating_result.Unwrap();
+    ASSERT_TRUE(caller_allocating_result.ok());
+    CheckWireFile(response->node);
+    ASSERT_OK(loop().RunUntilIdle());
+    EXPECT_EQ(4, server.num_calls);
+  }
+}
+
+TEST_F(UnifiedSyncClientToWireServer, TryRoundTrip) {
+  class Server : public WireTestBase {
+   public:
+    void TryRoundTrip(TryRoundTripRequestView request,
+                      TryRoundTripCompleter::Sync& completer) final {
+      CheckWireDir(request->node);
+      num_calls++;
+      if (reply_with_error.load()) {
+        completer.ReplyError(ZX_ERR_INVALID_ARGS);
+      } else {
+        completer.ReplySuccess(request->node);
+      }
+    }
+
+    std::atomic<bool> reply_with_error = false;
+    int num_calls = 0;
+  };
+  Server server;
+  fidl::BindServer(loop().dispatcher(), std::move(server_end()), &server);
+  ASSERT_OK(loop().StartThread());
+
+  {
+    // Test with natural domain objects, success case.
+    auto node = MakeNaturalDir();
+    fidl_cpp_wire_interop_test::InteropTryRoundTripRequest request{std::move(node)};
+    fidl::Result<fidl_cpp_wire_interop_test::Interop::TryRoundTrip> result =
+        client()->TryRoundTrip(std::move(request));
+    ASSERT_TRUE(result.is_ok());
+    fidl_cpp_wire_interop_test::InteropTryRoundTripResponse payload = std::move(result.value());
+    {
+      fidl_cpp_wire_interop_test::Node node = payload.node();
+      CheckNaturalDir(node);
+      EXPECT_EQ(1, server.num_calls);
+    }
+  }
+
+  {
+    // Test with wire domain objects, success case.
+    fidl::Arena arena;
+    auto node = MakeWireDir(arena);
+    fidl::WireResult<fidl_cpp_wire_interop_test::Interop::TryRoundTrip> result =
+        client().wire()->TryRoundTrip(node);
+    ASSERT_TRUE(result.ok(), "TryRoundTrip failed: %s", result.error().FormatDescription().c_str());
+    auto* response = result.Unwrap();
+    ASSERT_TRUE(response->result.is_response());
+    CheckWireDir(response->result.response().node);
+    EXPECT_EQ(2, server.num_calls);
+  }
+
+  server.reply_with_error.store(true);
+
+  {
+    // Test with natural domain objects, error case.
+    auto node = MakeNaturalDir();
+    fidl_cpp_wire_interop_test::InteropTryRoundTripRequest request{std::move(node)};
+    fidl::Result<fidl_cpp_wire_interop_test::Interop::TryRoundTrip> result =
+        client()->TryRoundTrip(std::move(request));
+    ASSERT_FALSE(result.is_ok());
+    ASSERT_TRUE(result.is_error());
+    fidl::AnyErrorIn<fidl_cpp_wire_interop_test::Interop::TryRoundTrip> error =
+        result.error_value();
+    ASSERT_TRUE(error.is_application_error());
+    EXPECT_STATUS(ZX_ERR_INVALID_ARGS, error.application_error());
+    EXPECT_EQ(3, server.num_calls);
+  }
+
+  {
+    // Test with wire domain objects, error case.
+    fidl::Arena arena;
+    auto node = MakeWireDir(arena);
+    fidl::WireResult<fidl_cpp_wire_interop_test::Interop::TryRoundTrip> result =
+        client().wire()->TryRoundTrip(node);
+    ASSERT_TRUE(result.ok(), "TryRoundTrip failed: %s", result.error().FormatDescription().c_str());
+    auto* response = result.Unwrap();
+    ASSERT_TRUE(response->result.is_err());
+    EXPECT_STATUS(ZX_ERR_INVALID_ARGS, response->result.err());
+    EXPECT_EQ(4, server.num_calls);
+  }
+}
+
+// Test sending a one way call.
+TEST_F(UnifiedSyncClientToWireServer, OneWay) {
+  class Server : public WireTestBase {
+   public:
+    void OneWay(OneWayRequestView request, OneWayCompleter::Sync& completer) override {
+      CheckWireFile(request->node);
+      num_calls++;
+    }
+
+    int num_calls = 0;
+  };
+  Server server;
+  fidl::BindServer(loop().dispatcher(), std::move(server_end()), &server);
+  {
+    // Test with natural domain objects.
+    fitx::result<fidl::Error> result = client()->OneWay({MakeNaturalFile()});
+    ASSERT_TRUE(result.is_ok());
+    ASSERT_OK(loop().RunUntilIdle());
+    EXPECT_EQ(1, server.num_calls);
+  }
+  {
+    // Test with wire domain objects.
+    fidl::Arena arena;
+    fidl::Status status = client().wire()->OneWay(MakeWireFile(arena));
+    ASSERT_TRUE(status.ok());
+    ASSERT_OK(loop().RunUntilIdle());
+    EXPECT_EQ(2, server.num_calls);
+  }
+}
+
+// TODO(fxbug.dev/60240): Synchronous natural events handling.
+
 }  // namespace
diff --git a/src/lib/fidl/llcpp/tests/integration/server_gen_api_test.cc b/src/lib/fidl/llcpp/tests/integration/server_gen_api_test.cc
index 9bd0c49..644cd97 100644
--- a/src/lib/fidl/llcpp/tests/integration/server_gen_api_test.cc
+++ b/src/lib/fidl/llcpp/tests/integration/server_gen_api_test.cc
@@ -1151,14 +1151,22 @@
 template <typename Protocol>
 class UnbindObserver {
  public:
-  UnbindObserver(fidl::Reason expected_reason, zx_status_t expected_status)
-      : expected_reason_(expected_reason), expected_status_(expected_status) {}
+  UnbindObserver(fidl::Reason expected_reason, zx_status_t expected_status,
+                 std::string expected_message_substring = "")
+      : expected_reason_(expected_reason), expected_status_(expected_status) {
+    if (!expected_message_substring.empty()) {
+      expected_message_substring_.emplace(std::move(expected_message_substring));
+    }
+  }
 
   fidl::OnUnboundFn<fidl::WireServer<Protocol>> GetCallback() {
     fidl::OnUnboundFn<fidl::WireServer<Protocol>> on_unbound =
         [this](fidl::WireServer<Protocol>*, fidl::UnbindInfo info, fidl::ServerEnd<Protocol>) {
           EXPECT_EQ(expected_reason_, info.reason());
           EXPECT_EQ(expected_status_, info.status());
+          if (expected_message_substring_.has_value()) {
+            EXPECT_SUBSTR(info.FormatDescription().c_str(), expected_message_substring_->c_str());
+          }
           completion_.Signal();
         };
     return on_unbound;
@@ -1171,9 +1179,48 @@
  private:
   fidl::Reason expected_reason_;
   zx_status_t expected_status_;
+  std::optional<std::string> expected_message_substring_;
   libsync::Completion completion_;
 };
 
+TEST(BindServerTestCase, UnbindInfoDecodeError) {
+  auto server = std::make_unique<NotImplementedServer>();
+  async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
+  ASSERT_OK(loop.StartThread());
+
+  zx::status endpoints = fidl::CreateEndpoints<Example>();
+  ASSERT_OK(endpoints.status_value());
+  auto [local, remote] = std::move(*endpoints);
+
+  // Error message should contain the word "presence", because the presence
+  // marker is invalid. Only checking for "presence" allows the error message to
+  // evolve slightly without breaking tests.
+  UnbindObserver<Example> observer(fidl::Reason::kDecodeError, ZX_ERR_INVALID_ARGS, "presence");
+  fidl::BindServer(loop.dispatcher(), std::move(remote), server.get(), observer.GetCallback());
+
+  // Make a call with an intentionally crafted wrong message.
+  // To trigger a decode error, here we use a string with an invalid presence marker.
+  fidl::internal::TransactionalRequest<Example::TwoWay> request;
+  request.body.in = fidl::StringView::FromExternal(
+      reinterpret_cast<const char*>(0x1234123412341234),  // invalid presence marker
+      0                                                   // size
+  );
+  const zx_channel_call_args_t args{
+      .wr_bytes = &request,
+      .wr_handles = nullptr,
+      .rd_bytes = nullptr,
+      .rd_handles = nullptr,
+      .wr_num_bytes = sizeof(request),
+      .wr_num_handles = 0,
+      .rd_num_bytes = 0,
+      .rd_num_handles = 0,
+  };
+  EXPECT_STATUS(ZX_ERR_PEER_CLOSED,
+                local.channel().call(0, zx::time::infinite(), &args, nullptr, nullptr));
+
+  ASSERT_OK(observer.completion().Wait());
+}
+
 TEST(BindServerTestCase, UnbindInfoDispatcherBeginsShutdownDuringMessageHandling) {
   struct WorkingServer : fidl::WireServer<Example> {
     explicit WorkingServer(std::shared_ptr<async::Loop> loop) : loop_(std::move(loop)) {}
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 12ead38..2487656c 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
@@ -44,6 +44,13 @@
         },);
 }
 
+// The program section of a component decl is not allowed to be mutated
+// for local and legacy components except for one instance. In the event,
+// that an `args` key is added for a legacy component, replacement of the
+// component decl is allowed. This is to enable passing argv to the
+// legacy component runner.
+const ALLOWLISTED_PROGRAM_ARGS_KEY: &'static str = "args";
+
 #[fuchsia::main]
 async fn main() {
     info!("started");
@@ -825,13 +832,7 @@
         let mut state_guard = self.state.lock().await;
         state_guard.validate_with_hypothetical_children(new_decl.clone())?;
         let new_decl = new_decl.fidl_into_native();
-        if state_guard.decl.program.as_ref().and_then(|p| p.runner.as_ref())
-            == Some(&runner::RUNNER_NAME.into())
-        {
-            if state_guard.decl.program != new_decl.program {
-                return Err(RealmBuilderError::ImmutableProgram);
-            }
-        }
+        let () = validate_program_modifications(&state_guard.decl, &new_decl)?;
         state_guard.decl = new_decl;
         Ok(())
     }
@@ -1514,6 +1515,64 @@
     }
 }
 
+// If this realm node is going have its decl replaced, we need to ensure
+// that the program section isn't corrupted. This is only necessary for
+// legacy components, whose program section is generated by
+// realm builder. In that case, we only allow specific modifications to
+// the program section. Specifically, we only allow adding an `args` entry for
+// legacy components.
+fn validate_program_modifications(
+    old_decl: &cm_rust::ComponentDecl,
+    new_decl: &cm_rust::ComponentDecl,
+) -> Result<(), RealmBuilderError> {
+    if old_decl.program.as_ref().and_then(|p| p.runner.as_ref())
+        == Some(&runner::RUNNER_NAME.into())
+    {
+        let new_decl_program = match new_decl.program.as_ref() {
+            Some(program) => {
+                if program_contains_entry(program, runner::LEGACY_URL_KEY)
+                    && program_contains_entry(program, ALLOWLISTED_PROGRAM_ARGS_KEY)
+                {
+                    program_with_entry_removed(program.clone(), ALLOWLISTED_PROGRAM_ARGS_KEY)
+                } else {
+                    program.clone()
+                }
+            }
+            None => {
+                return Err(RealmBuilderError::ImmutableProgram);
+            }
+        };
+
+        // We know that `old_decl.program` is `Some(_)` because we're inside
+        // this `if` clause. Therefore, it's safe to check equality against
+        // `Some(new_decl_program)`.
+        if old_decl.program != Some(new_decl_program) {
+            return Err(RealmBuilderError::ImmutableProgram);
+        }
+    }
+
+    Ok(())
+}
+
+fn program_contains_entry(program: &cm_rust::ProgramDecl, key: &str) -> bool {
+    if let Some(entries) = program.info.entries.as_ref() {
+        return entries.iter().any(|entry| entry.key == key);
+    }
+
+    return false;
+}
+
+fn program_with_entry_removed(
+    mut program: cm_rust::ProgramDecl,
+    key: &str,
+) -> cm_rust::ProgramDecl {
+    if let Some(entries) = program.info.entries.as_mut() {
+        entries.retain(|entry| entry.key != key);
+    }
+
+    return program;
+}
+
 #[allow(unused)]
 #[derive(Debug, Error)]
 enum RealmBuilderError {
@@ -3618,6 +3677,66 @@
     }
 
     #[fuchsia::test]
+    async fn replace_component_decl_immutable_program_not_raised_if_args_changed() {
+        let mut realm_and_builder_task = RealmAndBuilderTask::new();
+        realm_and_builder_task
+            .realm_proxy
+            .add_legacy_child("a", EXAMPLE_LEGACY_URL, ftest::ChildOptions::EMPTY)
+            .await
+            .expect("failed to call add_child")
+            .expect("add_child returned an error");
+        let mut a_decl = realm_and_builder_task
+            .realm_proxy
+            .get_component_decl("a")
+            .await
+            .expect("failed to call get_component_decl")
+            .expect("get_component_decl returned an error")
+            .fidl_into_native();
+        let program = a_decl.program.as_mut().expect("program section is None");
+        let entries = program.info.entries.as_mut().expect("program info is None");
+        let args_entry = fdata::DictionaryEntry {
+            key: crate::ALLOWLISTED_PROGRAM_ARGS_KEY.to_string(),
+            value: Some(Box::new(fdata::DictionaryValue::Str("test".to_string()))),
+        };
+        entries.push(args_entry.clone());
+        realm_and_builder_task
+            .realm_proxy
+            .replace_component_decl("a", a_decl.clone().native_into_fidl())
+            .await
+            .expect("failed to call replace_component_decl")
+            .expect("replace_component_decl returned an error");
+        let tree_from_resolver = realm_and_builder_task.call_build_and_get_tree().await;
+        let expected_a_decl = cm_rust::ComponentDecl {
+            program: Some(cm_rust::ProgramDecl {
+                runner: Some(crate::runner::RUNNER_NAME.try_into().unwrap()),
+                info: fdata::Dictionary {
+                    entries: Some(vec![
+                        fdata::DictionaryEntry {
+                            key: runner::LEGACY_URL_KEY.to_string(),
+                            value: Some(Box::new(fdata::DictionaryValue::Str(
+                                EXAMPLE_LEGACY_URL.to_string(),
+                            ))),
+                        },
+                        args_entry,
+                    ]),
+                    ..fdata::Dictionary::EMPTY
+                },
+            }),
+            ..cm_rust::ComponentDecl::default()
+        };
+        let mut expected_tree = ComponentTree {
+            decl: cm_rust::ComponentDecl::default(),
+            children: vec![(
+                "a".to_string(),
+                ftest::ChildOptions::EMPTY,
+                ComponentTree { decl: expected_a_decl, children: vec![] },
+            )],
+        };
+        expected_tree.add_binder_expose();
+        assert_eq!(expected_tree, tree_from_resolver);
+    }
+
+    #[fuchsia::test]
     async fn replace_component_decl_for_nonexistent_child() {
         let realm_and_builder_task = RealmAndBuilderTask::new();
         let err = realm_and_builder_task
diff --git a/src/lib/fuchsia-component-test/tests/echo_client_sc/BUILD.gn b/src/lib/fuchsia-component-test/tests/echo_client_sc/BUILD.gn
index 57dc395..c090f6e 100644
--- a/src/lib/fuchsia-component-test/tests/echo_client_sc/BUILD.gn
+++ b/src/lib/fuchsia-component-test/tests/echo_client_sc/BUILD.gn
@@ -22,7 +22,6 @@
 fuchsia_component_manifest("manifest") {
   component_name = "echo_client_sc"
   manifest = "meta/echo_client_sc.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("component") {
diff --git a/src/lib/loader_service/loader_service_test.cc b/src/lib/loader_service/loader_service_test.cc
index 525aab2..6d4fc99 100644
--- a/src/lib/loader_service/loader_service_test.cc
+++ b/src/lib/loader_service/loader_service_test.cc
@@ -253,9 +253,8 @@
 void LoadObjectLdmsg(fidl::UnownedClientEnd<fldsvc::Loader> client, const char* object_name,
                      zx::status<> expected) {
   size_t req_len;
-  ldmsg_req_t req = {};
-  req.header.ordinal = LDMSG_OP_LOAD_OBJECT;
-  req.header.magic_number = kFidlWireFormatMagicNumberInitial;
+  ldmsg_req_t req;
+  ldmsg_req_init_txn_header(&req, LDMSG_OP_LOAD_OBJECT);
   zx_status_t status = ldmsg_req_encode(&req, &req_len, object_name, strlen(object_name));
   ASSERT_OK(status);
 
diff --git a/src/lib/mundane/src/boringssl/abort.rs b/src/lib/mundane/src/boringssl/abort.rs
index 9835759..f37f1a9 100644
--- a/src/lib/mundane/src/boringssl/abort.rs
+++ b/src/lib/mundane/src/boringssl/abort.rs
@@ -14,8 +14,6 @@
 
 use std::fmt::Debug;
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 macro_rules! assert_abort {
     ($cond:expr) => ({
         let cond = $cond;
@@ -32,8 +30,6 @@
     });
 }
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 macro_rules! assert_abort_eq {
     ($left:expr, $right:expr) => ({
         match (&$left, &$right) {
@@ -76,8 +72,6 @@
     }};
 }
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 macro_rules! panic_abort {
     () => ({
         panic_abort!("explicit panic")
diff --git a/src/lib/mundane/src/boringssl/mod.rs b/src/lib/mundane/src/boringssl/mod.rs
index 4373f84..8cecb78 100644
--- a/src/lib/mundane/src/boringssl/mod.rs
+++ b/src/lib/mundane/src/boringssl/mod.rs
@@ -798,8 +798,6 @@
     }
 }
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 /// Implements `CStackWrapper` for a hash context type.
 ///
 /// The caller provides doc comments, a public method name, and a private
diff --git a/src/lib/mundane/src/boringssl/wrapper.rs b/src/lib/mundane/src/boringssl/wrapper.rs
index dded5a9..0d41c88 100644
--- a/src/lib/mundane/src/boringssl/wrapper.rs
+++ b/src/lib/mundane/src/boringssl/wrapper.rs
@@ -20,8 +20,6 @@
     };
 }
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 macro_rules! impl_traits {
     (@inner $name:ident, CNew => $fn:tt) => {
         c_new!($name, $fn);
diff --git a/src/lib/pty/src/pty.rs b/src/lib/pty/src/pty.rs
index 781cc69..ba33efb 100644
--- a/src/lib/pty/src/pty.rs
+++ b/src/lib/pty/src/pty.rs
@@ -223,10 +223,7 @@
             command,
             argv,
             environ,
-            &mut [fdio::SpawnAction::transfer_fd(
-                client_pty,
-                fdio::fdio_sys::FDIO_FLAG_USE_FOR_STDIO as i32,
-            )],
+            &mut [fdio::SpawnAction::transfer_fd(client_pty, fdio::SpawnAction::USE_FOR_STDIO)],
         )
         .map_err(|e| format_err!("failed to spawn shell: {:?}", e))?;
 
diff --git a/src/lib/storage/fs_management/cpp/options.cc b/src/lib/storage/fs_management/cpp/options.cc
index 7881b0b..bbb2773 100644
--- a/src/lib/storage/fs_management/cpp/options.cc
+++ b/src/lib/storage/fs_management/cpp/options.cc
@@ -50,6 +50,8 @@
   options.write_compression_level = write_compression_level;
   if (crypt_client)
     options.crypt = fidl::ClientEnd<fuchsia_fxfs::Crypt>(crypt_client());
+  if (migrate_root)
+    options.migrate_root = migrate_root();
 
   if (write_compression_algorithm != nullptr) {
     std::string write_compression_algorithm_string(write_compression_algorithm);
diff --git a/src/lib/storage/fs_management/cpp/options.h b/src/lib/storage/fs_management/cpp/options.h
index 7f1cc62..a602ca7 100644
--- a/src/lib/storage/fs_management/cpp/options.h
+++ b/src/lib/storage/fs_management/cpp/options.h
@@ -6,6 +6,7 @@
 #define SRC_LIB_STORAGE_FS_MANAGEMENT_CPP_OPTIONS_H_
 
 #include <fidl/fuchsia.fs.startup/cpp/wire.h>
+#include <fidl/fuchsia.io/cpp/wire.h>
 #include <lib/zx/status.h>
 #include <zircon/types.h>
 
@@ -60,6 +61,11 @@
   // If set, use the specified component URL rather than a default.
   std::string component_url;
 
+  // If set, provides the caller with the opportunity to migrate data before the mount is finalised.
+  // The mount will be blocked until the channel and any other channels opened via this channel are
+  // closed.
+  std::function<fidl::ServerEnd<fuchsia_io::Directory>()> migrate_root;
+
   // Generate the argv list for launching a process based on this set of options.
   __EXPORT
   std::vector<std::string> as_argv(const char* binary) const;
diff --git a/src/lib/storage/vfs/rust/src/path.rs b/src/lib/storage/vfs/rust/src/path.rs
index 092158d..7d0f37c 100644
--- a/src/lib/storage/vfs/rust/src/path.rs
+++ b/src/lib/storage/vfs/rust/src/path.rs
@@ -182,8 +182,6 @@
 mod tests {
     use super::*;
 
-    #[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-    #[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
     macro_rules! simple_construction_test {
         (path: $str:expr, $path:ident => $body:block) => {
             match Path::validate_and_split($str) {
diff --git a/src/lib/testing/test_list/README.md b/src/lib/testing/test_list/README.md
index 2260d8f..0f448ae 100644
--- a/src/lib/testing/test_list/README.md
+++ b/src/lib/testing/test_list/README.md
@@ -8,8 +8,12 @@
 
 ```json5
 {
+    // Identifier for schema version being used.
+    //
+    // Currently always set to "experimental"
+    "schema_id": "experimental",
     // Array containing all tests in the file.
-    "tests": [
+    "data": [
         {
             // The name of the test.
             //
diff --git a/src/lib/testing/test_list/src/lib.rs b/src/lib/testing/test_list/src/lib.rs
index 30496e6..2b4ffda 100644
--- a/src/lib/testing/test_list/src/lib.rs
+++ b/src/lib/testing/test_list/src/lib.rs
@@ -9,8 +9,10 @@
 };
 
 #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
-pub struct TestList {
-    pub tests: Vec<TestListEntry>,
+#[serde(tag = "schema_id")]
+pub enum TestList {
+    #[serde(rename = "experimental")]
+    Experimental { data: Vec<TestListEntry> },
 }
 
 #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
diff --git a/src/power/power-manager/src/types.rs b/src/power/power-manager/src/types.rs
index 9845fb1..f90b003 100644
--- a/src/power/power-manager/src/types.rs
+++ b/src/power/power-manager/src/types.rs
@@ -50,8 +50,6 @@
     };
 }
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 /// Defines a measurement unit, with an underlying scalar type.
 macro_rules! define_unit {
     ( $unit_type:ident, f32 ) => {
diff --git a/src/proc/bin/galaxies/galaxy.gni b/src/proc/bin/galaxies/galaxy.gni
index 9a05323..8a1f4d6 100644
--- a/src/proc/bin/galaxies/galaxy.gni
+++ b/src/proc/bin/galaxies/galaxy.gni
@@ -30,7 +30,6 @@
   fuchsia_component_manifest(manifest_target) {
     component_name = "starnix_runner"
     manifest = "//src/proc/bin/starnix/meta/starnix_runner.cml"
-    restricted_features = [ "structured_config" ]
   }
 
   fuchsia_component(component_target) {
diff --git a/src/proc/bin/starnix/BUILD.gn b/src/proc/bin/starnix/BUILD.gn
index 7023b18..d13e009 100644
--- a/src/proc/bin/starnix/BUILD.gn
+++ b/src/proc/bin/starnix/BUILD.gn
@@ -243,7 +243,6 @@
   # The starnix runner manifest, used by all galaxies.
   fuchsia_component_manifest("starnix_runner_manifest") {
     manifest = "meta/starnix_runner.cml"
-    restricted_features = [ "structured_config" ]
   }
 
   # The starnix runner configuration library, used by the Rust binary to parse configuration.
diff --git a/src/proc/bin/starnix/device/features.rs b/src/proc/bin/starnix/device/features.rs
index b8794b2..7636e98 100644
--- a/src/proc/bin/starnix/device/features.rs
+++ b/src/proc/bin/starnix/device/features.rs
@@ -9,11 +9,42 @@
 use crate::fs::{devtmpfs::dev_tmp_fs, SpecialNode};
 use crate::task::CurrentTask;
 use crate::types::*;
+use std::collections::HashSet;
 
-/// Parses and runs the features from the provided "program strvec."
+/// Parses and runs the features from the provided "program strvec.". Some features,
+/// such as Wayland, should be enabled on a per-component basis. We run this when we first
+/// make the Galaxy. When we start the component, we run the run_component_features
+/// function.
 pub fn run_features<'a>(entries: &'a Vec<String>, current_task: &CurrentTask) -> Result<(), Errno> {
     for entry in entries {
         match entry.as_str() {
+            // Wayland is enabled on a per-component basis and so skipped here.
+            "wayland" => {}
+            "binder" => {
+                // Creates the various binder drivers (/dev/binder, /dev/hwbinder, /dev/vndbinder).
+                create_binders(current_task.kernel())?;
+            }
+            "logd" => {
+                // Creates a socket at /dev/socket/logdw logs anything written to it.
+                create_socket_and_start_server(current_task.kernel());
+            }
+            "selinux_enabled" => {}
+            feature => {
+                tracing::warn!("Unsupported feature: {:?}", feature);
+            }
+        }
+    }
+    Ok(())
+}
+
+/// Runs features requested by individual components
+pub fn run_component_features<'a>(
+    entries: &'a HashSet<String>,
+    current_task: &CurrentTask,
+    outgoing_dir: &mut Option<fidl::endpoints::ServerEnd<fidl_fuchsia_io::DirectoryMarker>>,
+) -> Result<(), Errno> {
+    for entry in entries {
+        match entry.as_str() {
             "wayland" => {
                 let kernel = current_task.kernel();
                 let dev = kernel.device_registry.write().register_misc_chrdev(MagmaDev::new())?;
@@ -30,16 +61,12 @@
                     current_task,
                     b"/data/tmp/wayland-0".to_vec(),
                     b"/data/tmp/wayland-1".to_vec(),
+                    outgoing_dir,
                 )?;
             }
-            "binder" => {
-                // Creates the various binder drivers (/dev/binder, /dev/hwbinder, /dev/vndbinder).
-                create_binders(current_task.kernel())?;
-            }
-            "logd" => {
-                // Creates a socket at /dev/socket/logdw logs anything written to it.
-                create_socket_and_start_server(current_task.kernel());
-            }
+            "binder" => {}
+            "logd" => {}
+            "selinux_enabled" => {}
             feature => {
                 tracing::warn!("Unsupported feature: {:?}", feature);
             }
diff --git a/src/proc/bin/starnix/device/magma/ffi.rs b/src/proc/bin/starnix/device/magma/ffi.rs
index b97835d..fda8736 100644
--- a/src/proc/bin/starnix/device/magma/ffi.rs
+++ b/src/proc/bin/starnix/device/magma/ffi.rs
@@ -20,7 +20,17 @@
     response: &mut virtio_magma_device_import_resp_t,
 ) -> Result<zx::Channel, Errno> {
     let (client_channel, server_channel) = zx::Channel::create().map_err(|_| errno!(EINVAL))?;
-    fdio::service_connect(&"/dev/class/gpu/000", server_channel).map_err(|_| errno!(EINVAL))?;
+    // TODO(fxbug.dev/100454): This currently picks the first available device, but multiple devices should
+    // probably be exposed to clients.
+    let entry = std::fs::read_dir("/dev/class/gpu")
+        .map_err(|_| errno!(EINVAL))?
+        .next()
+        .ok_or(errno!(EINVAL))?
+        .map_err(|_| errno!(EINVAL))?;
+
+    let path = entry.path().into_os_string().into_string().map_err(|_| errno!(EINVAL))?;
+
+    fdio::service_connect(&path, server_channel).map_err(|_| errno!(EINVAL))?;
 
     // TODO(fxbug.dev/12731): The device import should take ownership of the channel, at which point
     // this can be converted to `into_raw()`, and the return value of this function can be changed
diff --git a/src/proc/bin/starnix/device/magma/file.rs b/src/proc/bin/starnix/device/magma/file.rs
index 68f4925..1fd55fb 100644
--- a/src/proc/bin/starnix/device/magma/file.rs
+++ b/src/proc/bin/starnix/device/magma/file.rs
@@ -147,7 +147,11 @@
                 ) = read_control_and_response(current_task, &command)?;
 
                 let connection = control.connection as magma_connection_t;
-                unsafe { magma_release_connection(connection) };
+                let mut connections = self.connections.lock();
+                if connections.contains_key(&connection) {
+                    unsafe { magma_release_connection(connection) };
+                    connections.remove(&connection);
+                }
 
                 response.hdr.type_ =
                     virtio_magma_ctrl_type_VIRTIO_MAGMA_RESP_RELEASE_CONNECTION as u32;
diff --git a/src/proc/bin/starnix/device/wayland/wayland.rs b/src/proc/bin/starnix/device/wayland/wayland.rs
index a31a763..0b24eb6 100644
--- a/src/proc/bin/starnix/device/wayland/wayland.rs
+++ b/src/proc/bin/starnix/device/wayland/wayland.rs
@@ -49,12 +49,14 @@
     current_task: &CurrentTask,
     display_path: FsString,
     device_path: FsString,
+    outgoing_dir: &mut Option<fidl::endpoints::ServerEnd<fidl_fuchsia_io::DirectoryMarker>>,
 ) -> Result<(), Errno> {
     let display_socket = create_display_socket(current_task, display_path)?;
     create_device_file(current_task, device_path)?;
 
     let kernel = current_task.thread_group.kernel.clone();
-    let outgoing_dir_channel = kernel.outgoing_dir.lock().take().ok_or(errno!(EINVAL))?;
+    let outgoing_dir_channel =
+        outgoing_dir.take().map(|server_end| server_end.into_channel()).ok_or(errno!(EINVAL))?;
 
     // Add `ViewProvider` to the exposed services of the component, and then serve the
     // outgoing directory.
diff --git a/src/proc/bin/starnix/execution/component_runner.rs b/src/proc/bin/starnix/execution/component_runner.rs
index 8885b7b..ec057e0 100644
--- a/src/proc/bin/starnix/execution/component_runner.rs
+++ b/src/proc/bin/starnix/execution/component_runner.rs
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+use crate::device::run_component_features;
 use ::runner::{get_program_string, get_program_strvec};
 use anyhow::{anyhow, format_err, Context, Error};
 use fidl::endpoints::ServerEnd;
@@ -9,8 +10,6 @@
 use fidl_fuchsia_component_decl as fdecl;
 use fidl_fuchsia_component_runner::{ComponentControllerMarker, ComponentStartInfo};
 use fidl_fuchsia_io as fio;
-use fuchsia_async as fasync;
-use fuchsia_async::DurationExt;
 use fuchsia_component::client as fclient;
 use fuchsia_zircon as zx;
 use rand::Rng;
@@ -19,10 +18,9 @@
 
 use crate::auth::Credentials;
 use crate::execution::{
-    create_filesystem_from_spec, execute_task, galaxy::create_galaxy, galaxy::Galaxy,
+    create_filesystem_from_spec, create_galaxy, execute_task, galaxy::Galaxy,
     parse_numbered_handles,
 };
-use crate::fs::*;
 use crate::task::*;
 use crate::types::*;
 
@@ -43,10 +41,11 @@
     mut start_info: ComponentStartInfo,
     controller: ServerEnd<ComponentControllerMarker>,
 ) -> Result<(), Error> {
-    let galaxy = create_galaxy(&mut start_info.outgoing_dir).context("failed to create galaxy")?;
+    let galaxy = create_galaxy().await?;
+    let url = start_info.resolved_url.clone().unwrap_or("<unknown>".to_string());
     info!(
         "start_component: {}\narguments: {:?}\nmanifest: {:?}",
-        start_info.resolved_url.clone().unwrap_or("<unknown>".to_string()),
+        url.clone(),
         start_info.numbered_handles,
         start_info.program,
     );
@@ -108,16 +107,13 @@
 
     current_task.exec(argv[0].clone(), argv.clone(), environ.clone())?;
 
-    if let Some(init_task) = galaxy.init_task {
-        execute_task(init_task, |result| {
-            info!("Finished running init process: {:?}", result);
+    // run per-component features
+    // TODO(fxb/100316) - we should examine start_info to determine which features are needed for this component.
+    run_component_features(&galaxy.kernel.features, &current_task, &mut start_info.outgoing_dir)
+        .unwrap_or_else(|e| {
+            tracing::error!("failed to set component features for {} - {:?}", url, e);
         });
 
-        if let Some(startup_file_path) = galaxy.startup_file_path {
-            wait_for_init_file(&startup_file_path, &current_task).await?;
-        }
-    }
-
     execute_task(current_task, |result| {
         // TODO(fxb/74803): Using the component controller's epitaph may not be the best way to
         // communicate the exit status. The component manager could interpret certain epitaphs as starnix
@@ -160,24 +156,6 @@
     Ok(())
 }
 
-async fn wait_for_init_file(
-    startup_file_path: &str,
-    current_task: &CurrentTask,
-) -> Result<(), Error> {
-    // TODO(fxb/96299): Use inotify machinery to wait for the file.
-    loop {
-        fasync::Timer::new(fasync::Duration::from_millis(100).after_now()).await;
-        let root = current_task.fs.namespace_root();
-        let mut context = LookupContext::default();
-        match current_task.lookup_path(&mut context, root, startup_file_path.as_bytes()) {
-            Ok(_) => break,
-            Err(error) if error == ENOENT => continue,
-            Err(error) => return Err(anyhow::Error::new(error)),
-        }
-    }
-    Ok(())
-}
-
 /// Creates a new child component in the `playground` collection.
 ///
 /// # Parameters
@@ -211,70 +189,3 @@
     // deleted when it exits.
     Ok(())
 }
-
-#[cfg(test)]
-mod test {
-    use super::wait_for_init_file;
-    use crate::fs::FdNumber;
-    use crate::testing::create_kernel_and_task;
-    use crate::types::*;
-    use fuchsia_async as fasync;
-    use futures::{SinkExt, StreamExt};
-
-    #[fuchsia::test]
-    async fn test_init_file_already_exists() {
-        let (_kernel, current_task) = create_kernel_and_task();
-        let (mut sender, mut receiver) = futures::channel::mpsc::unbounded();
-
-        let path = "/path";
-        current_task
-            .open_file_at(
-                FdNumber::AT_FDCWD,
-                &path.as_bytes(),
-                OpenFlags::CREAT,
-                FileMode::default(),
-            )
-            .expect("Failed to create file");
-
-        fasync::Task::local(async move {
-            wait_for_init_file(&path, &current_task).await.expect("failed to wait for file");
-            sender.send(()).await.expect("failed to send message");
-        })
-        .detach();
-
-        // Wait for the file creation to have been detected.
-        assert!(receiver.next().await.is_some());
-    }
-
-    #[fuchsia::test]
-    async fn test_init_file_wait_required() {
-        let (_kernel, current_task) = create_kernel_and_task();
-        let (mut sender, mut receiver) = futures::channel::mpsc::unbounded();
-
-        let init_task = current_task.clone_task_for_test(CLONE_FS as u64);
-        let path = "/path";
-
-        fasync::Task::local(async move {
-            sender.send(()).await.expect("failed to send message");
-            wait_for_init_file(&path, &init_task).await.expect("failed to wait for file");
-            sender.send(()).await.expect("failed to send message");
-        })
-        .detach();
-
-        // Wait for message that file check has started.
-        assert!(receiver.next().await.is_some());
-
-        // Create the file that is being waited on.
-        current_task
-            .open_file_at(
-                FdNumber::AT_FDCWD,
-                &path.as_bytes(),
-                OpenFlags::CREAT,
-                FileMode::default(),
-            )
-            .expect("Failed to create file");
-
-        // Wait for the file creation to be detected.
-        assert!(receiver.next().await.is_some());
-    }
-}
diff --git a/src/proc/bin/starnix/execution/galaxy.rs b/src/proc/bin/starnix/execution/galaxy.rs
index 5545138..7adf00a 100644
--- a/src/proc/bin/starnix/execution/galaxy.rs
+++ b/src/proc/bin/starnix/execution/galaxy.rs
@@ -4,6 +4,8 @@
 
 use anyhow::{anyhow, Context, Error};
 use fidl_fuchsia_io as fio;
+use fuchsia_async as fasync;
+use fuchsia_async::DurationExt;
 use fuchsia_zircon as zx;
 use starnix_runner_config::Config;
 use std::ffi::CString;
@@ -29,16 +31,6 @@
 }
 
 pub struct Galaxy {
-    /// The initial task in the galaxy, if one was specified in the galaxy's CONFIGuration file.
-    ///
-    /// This task is executed prior to running any other tasks in the galaxy.
-    pub init_task: Option<CurrentTask>,
-
-    /// A path to a file in the `init_task`'s filesystem. If this file is `Some`, then the runner
-    /// machinery will wait for the file to exist before executing any other tasks in the galaxy
-    /// (`init_task` is started, since it is expected to create this file).
-    pub startup_file_path: Option<String>,
-
     /// The `Kernel` object that is associated with the galaxy.
     pub kernel: Arc<Kernel>,
 
@@ -53,13 +45,7 @@
 ///
 /// If a `startup_file_path` is also returned, the caller should wait to start any other tasks
 /// until the file at `startup_file_path` exists.
-///
-/// # Parameters
-/// - `outgoing_dir`: The outgoing directory of the component to run in the galaxy. This is used
-///                   to serve protocols on behalf of the component.
-pub fn create_galaxy(
-    outgoing_dir: &mut Option<fidl::endpoints::ServerEnd<fidl_fuchsia_io::DirectoryMarker>>,
-) -> Result<Galaxy, Error> {
+pub async fn create_galaxy() -> Result<Galaxy, Error> {
     const COMPONENT_PKG_PATH: &'static str = "/pkg";
 
     let (server, client) = zx::Channel::create().context("failed to create channel pair")?;
@@ -72,7 +58,6 @@
     let pkg_dir_proxy = fio::DirectorySynchronousProxy::new(client);
     let mut kernel = Kernel::new(&to_cstr(&CONFIG.name), &CONFIG.features)?;
     kernel.cmdline = CONFIG.kernel_cmdline.as_bytes().to_vec();
-    *kernel.outgoing_dir.lock() = outgoing_dir.take().map(|server_end| server_end.into_channel());
     let kernel = Arc::new(kernel);
 
     let fs_context = create_fs_context(&kernel, &pkg_dir_proxy)?;
@@ -84,32 +69,41 @@
     // TODO(tbodt): Remove once apexd works.
     mount_apexes(&init_task)?;
 
-    // Run all the features (e.g., wayland) that were specified in the .cml.
+    // Run all common features that were specified in the .cml.
     run_features(&CONFIG.features, &init_task)
         .map_err(|e| anyhow!("Failed to initialize features: {:?}", e))?;
     // TODO: This should probably be part of the "feature" CONFIGuration.
     let kernel = init_task.kernel().clone();
 
     let root_fs = init_task.fs.clone();
-    // Only return an init task if there was an init binary path. The task struct is still used
-    // to initialize the system up until this point, regardless of whether or not there is an
-    // actual init to be run.
-    let init_task = if CONFIG.init.is_empty() {
-        // A task must have an exit status, so set it here to simulate the init task having run.
-        init_task.write().exit_status = Some(ExitStatus::Exit(0));
-        None
-    } else {
-        let argv: Vec<_> = CONFIG.init.iter().map(to_cstr).collect();
-        init_task.exec(argv[0].clone(), argv.clone(), vec![])?;
-        Some(init_task)
-    };
 
     let startup_file_path = if CONFIG.startup_file_path.is_empty() {
         None
     } else {
         Some(CONFIG.startup_file_path.clone())
     };
-    Ok(Galaxy { init_task, startup_file_path, kernel, root_fs })
+
+    // If there is an init binary path, run it, optionally waiting for the
+    // startup_file_path to be created. The task struct is still used
+    // to initialize the system up until this point, regardless of whether
+    // or not there is an actual init to be run.
+    if CONFIG.init.is_empty() {
+        // A task must have an exit status, so set it here to simulate the init task having run.
+        init_task.write().exit_status = Some(ExitStatus::Exit(0));
+    } else {
+        let argv: Vec<_> = CONFIG.init.iter().map(to_cstr).collect();
+        init_task.exec(argv[0].clone(), argv.clone(), vec![])?;
+        execute_task(init_task, |result| {
+            tracing::info!("Finished running init process: {:?}", result);
+        });
+        if let Some(startup_file_path) = startup_file_path {
+            let init_wait_task = create_init_task(&kernel, &fs_context)?;
+            wait_for_init_file(&startup_file_path, &init_wait_task).await?;
+            init_wait_task.write().exit_status = Some(ExitStatus::Exit(0));
+        }
+    };
+
+    Ok(Galaxy { kernel, root_fs })
 }
 
 fn create_fs_context(
@@ -186,3 +180,88 @@
     }
     Ok(())
 }
+
+async fn wait_for_init_file(
+    startup_file_path: &str,
+    current_task: &CurrentTask,
+) -> Result<(), Error> {
+    // TODO(fxb/96299): Use inotify machinery to wait for the file.
+    loop {
+        fasync::Timer::new(fasync::Duration::from_millis(100).after_now()).await;
+        let root = current_task.fs.namespace_root();
+        let mut context = LookupContext::default();
+        match current_task.lookup_path(&mut context, root, startup_file_path.as_bytes()) {
+            Ok(_) => break,
+            Err(error) if error == ENOENT => continue,
+            Err(error) => return Err(anyhow::Error::new(error)),
+        }
+    }
+    Ok(())
+}
+
+#[cfg(test)]
+mod test {
+    use super::wait_for_init_file;
+    use crate::fs::FdNumber;
+    use crate::testing::create_kernel_and_task;
+    use crate::types::*;
+    use fuchsia_async as fasync;
+    use futures::{SinkExt, StreamExt};
+
+    #[fuchsia::test]
+    async fn test_init_file_already_exists() {
+        let (_kernel, current_task) = create_kernel_and_task();
+        let (mut sender, mut receiver) = futures::channel::mpsc::unbounded();
+
+        let path = "/path";
+        current_task
+            .open_file_at(
+                FdNumber::AT_FDCWD,
+                &path.as_bytes(),
+                OpenFlags::CREAT,
+                FileMode::default(),
+            )
+            .expect("Failed to create file");
+
+        fasync::Task::local(async move {
+            wait_for_init_file(&path, &current_task).await.expect("failed to wait for file");
+            sender.send(()).await.expect("failed to send message");
+        })
+        .detach();
+
+        // Wait for the file creation to have been detected.
+        assert!(receiver.next().await.is_some());
+    }
+
+    #[fuchsia::test]
+    async fn test_init_file_wait_required() {
+        let (_kernel, current_task) = create_kernel_and_task();
+        let (mut sender, mut receiver) = futures::channel::mpsc::unbounded();
+
+        let init_task = current_task.clone_task_for_test(CLONE_FS as u64);
+        let path = "/path";
+
+        fasync::Task::local(async move {
+            sender.send(()).await.expect("failed to send message");
+            wait_for_init_file(&path, &init_task).await.expect("failed to wait for file");
+            sender.send(()).await.expect("failed to send message");
+        })
+        .detach();
+
+        // Wait for message that file check has started.
+        assert!(receiver.next().await.is_some());
+
+        // Create the file that is being waited on.
+        current_task
+            .open_file_at(
+                FdNumber::AT_FDCWD,
+                &path.as_bytes(),
+                OpenFlags::CREAT,
+                FileMode::default(),
+            )
+            .expect("Failed to create file");
+
+        // Wait for the file creation to be detected.
+        assert!(receiver.next().await.is_some());
+    }
+}
diff --git a/src/proc/bin/starnix/execution/mod.rs b/src/proc/bin/starnix/execution/mod.rs
index 9941735..8e1c205 100644
--- a/src/proc/bin/starnix/execution/mod.rs
+++ b/src/proc/bin/starnix/execution/mod.rs
@@ -11,5 +11,6 @@
 pub use component_runner::*;
 #[cfg(not(feature = "restricted_mode"))]
 pub use exception_executor::*;
+pub use galaxy::*;
 pub use serve_protocols::*;
 pub use shared::*;
diff --git a/src/proc/bin/starnix/fs/fs_node.rs b/src/proc/bin/starnix/fs/fs_node.rs
index 3a6d234..fc32d15 100644
--- a/src/proc/bin/starnix/fs/fs_node.rs
+++ b/src/proc/bin/starnix/fs/fs_node.rs
@@ -234,8 +234,6 @@
     };
 }
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 /// Implements [`FsNodeOps::set_xattr`] by delegating to another [`FsNodeOps`]
 /// object.
 macro_rules! fs_node_impl_xattr_delegate {
diff --git a/src/proc/bin/starnix/mutable_state.rs b/src/proc/bin/starnix/mutable_state.rs
index 9705db8..d054d15 100644
--- a/src/proc/bin/starnix/mutable_state.rs
+++ b/src/proc/bin/starnix/mutable_state.rs
@@ -275,8 +275,6 @@
     }
 }
 
-#[allow(unknown_lints)] // TODO(fxbug.dev/99424): remove this after toolchain roll when lint is known
-#[allow(unused_macro_rules)] // TODO(fxbug.dev/100318): remove unused macro rules and re-enable
 /// This macro matches the methods inside a `state_implementation!` macro depending on their
 /// visibility and mutability so that the `state_implementation!` might dispatch these to the right
 /// trait or implementation.
diff --git a/src/proc/bin/starnix/task/kernel.rs b/src/proc/bin/starnix/task/kernel.rs
index 259c325..5a67622 100644
--- a/src/proc/bin/starnix/task/kernel.rs
+++ b/src/proc/bin/starnix/task/kernel.rs
@@ -12,7 +12,7 @@
 use crate::device::{DeviceMode, DeviceRegistry};
 use crate::fs::socket::SocketAddress;
 use crate::fs::{FileOps, FileSystemHandle, FsNode};
-use crate::lock::{Mutex, RwLock};
+use crate::lock::RwLock;
 use crate::task::*;
 use crate::types::{DeviceType, Errno, OpenFlags};
 
@@ -59,12 +59,6 @@
     /// The registry of device drivers.
     pub device_registry: RwLock<DeviceRegistry>,
 
-    /// The outgoing directory for the component that is being run. This is used to serve a
-    /// `ViewProvider` on behalf of the component, if the component displays graphics.
-    ///
-    /// Note: This assumes there is only one component running in the Kernel.
-    pub outgoing_dir: Mutex<Option<fidl::Channel>>,
-
     // The features enabled for the galaxy this kernel is associated with, as specified in
     // the galaxy's configuration file.
     pub features: HashSet<String>,
@@ -94,7 +88,6 @@
             sys_fs: OnceCell::new(),
             selinux_fs: OnceCell::new(),
             device_registry: RwLock::new(DeviceRegistry::new_with_common_devices()),
-            outgoing_dir: Mutex::new(None),
             features: HashSet::from_iter(features.iter().cloned()),
         })
     }
diff --git a/src/proc/tests/chromiumos/BUILD.gn b/src/proc/tests/chromiumos/BUILD.gn
index e713499..d238194 100644
--- a/src/proc/tests/chromiumos/BUILD.gn
+++ b/src/proc/tests/chromiumos/BUILD.gn
@@ -3,11 +3,9 @@
 # found in the LICENSE file.
 
 import("//build/components.gni")
+import("//build/testing/environments.gni")
 import("build/starnix_host_test_component.gni")
-
-group("chromiumos") {
-  deps = [ ":chromiumos_system_image" ]
-}
+import("build/starnix_linux_test_component.gni")
 
 group("tests") {
   testonly = true
@@ -15,43 +13,34 @@
 
   if (target_cpu == "x64") {
     deps += [ ":test_chromiumos_distro" ]
-  }
-}
 
-resource("chromiumos_system_image") {
-  sources = [ "//prebuilt/starnix/chromiumos-image-amd64/system.img" ]
-  outputs = [ "data/system.img" ]
+    # TODO(lindkvist): Remove !is_asan check when Starnix can run binaries built for
+    # ASAN.
+    if (!is_asan) {
+      deps += [ ":test_starnix_magma" ]
+    }
+  }
 }
 
 fuchsia_component("sh_test") {
   testonly = true
   check_references = false
-  deps = [ ":chromiumos_system_image" ]
   manifest = "meta/sh_test.cml"
 }
 
 if (host_os == "linux" && host_cpu == "x64") {
-  starnix_host_test_component("syscalls_test") {
-    test_label = "syscalls:syscalls_test"
-  }
-
   starnix_host_test_component("fdio-test") {
     test_label = "//sdk/lib/fdio/tests:fdio-test"
   }
 }
 
 fuchsia_test_package("test_chromiumos_distro") {
-  deps = [ ":chromiumos_system_image" ]
-
   test_components = [ ":sh_test" ]
 
   # TODO(abarth): Remove !is_asan check when Starnix can run binaries built for
   # ASAN.
   if (host_os == "linux" && host_cpu == "x64" && !is_asan) {
-    test_components += [
-      ":syscalls_test",
-      ":fdio-test",
-    ]
+    test_components += [ ":fdio-test" ]
   }
 
   # This package intentionally contains many non-Fuchia ELF binaries that
@@ -59,3 +48,18 @@
   # theses checks to build successfully.
   disable_elf_binaries_checks = true
 }
+
+starnix_linux_test_component("virtmagma_conformance_tests") {
+  test_label =
+      "//src/graphics/lib/magma/tests/integration:virtmagma_conformance_tests"
+}
+
+fuchsia_test_package("test_starnix_magma") {
+  test_components = [ ":virtmagma_conformance_tests" ]
+  test_specs = {
+    environments = [
+      atlas_env,
+      nuc_env,
+    ]
+  }
+}
diff --git a/src/proc/tests/chromiumos/build/starnix_host_test_component.gni b/src/proc/tests/chromiumos/build/starnix_host_test_component.gni
index e505141..9f6ed0f 100644
--- a/src/proc/tests/chromiumos/build/starnix_host_test_component.gni
+++ b/src/proc/tests/chromiumos/build/starnix_host_test_component.gni
@@ -2,7 +2,7 @@
 # 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("starnix_toolchain_test_component.gni")
 
 # Defines a Fuchsia component that contains a host test.
 #
@@ -18,32 +18,12 @@
 #     Type: GN label
 #
 #   The remaining parameters are forwarded to the fuchsia_component template.
+# TODO(fxbug.dev/100002): This should be removed once all our tests can be built
+#                         using the explicit linux toolchain
 template("starnix_host_test_component") {
   assert(host_os == "linux")
-  assert(defined(invoker.test_label))
-
-  test_name = target_name
-  test_label = "${invoker.test_label}($host_toolchain)"
-
-  resource("${test_name}_resource") {
-    testonly = true
-    out_dir = get_label_info(test_label, "root_out_dir")
-    sources = [ "${out_dir}/${test_name}" ]
-    outputs = [ "data/tests/${test_name}" ]
-    deps = [ test_label ]
-  }
-
-  fuchsia_component(test_name) {
-    forward_variables_from(invoker, "*", [ "test_label" ])
-
-    testonly = true
-    check_references = false
-    manifest = "meta/${test_name}.cml"
-
-    if (!defined(deps)) {
-      deps = []
-    }
-
-    deps += [ ":${test_name}_resource" ]
+  test_toolchain = "$host_toolchain"
+  starnix_toolchain_test_component(target_name) {
+    forward_variables_from(invoker, "*")
   }
 }
diff --git a/src/proc/tests/chromiumos/build/starnix_linux_test_component.gni b/src/proc/tests/chromiumos/build/starnix_linux_test_component.gni
new file mode 100644
index 0000000..b51dafd
--- /dev/null
+++ b/src/proc/tests/chromiumos/build/starnix_linux_test_component.gni
@@ -0,0 +1,27 @@
+# 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.
+
+import("//build/components.gni")
+import("starnix_toolchain_test_component.gni")
+
+# Defines a Fuchsia component that contains a test binary built for linux_x64.
+#
+# This template expects to find a CML file named "meta/${test_name}.cml" where
+# "test_name" is the name of this target. This file is used as the component
+# manifest for the test.
+#
+# Parameters
+#
+#   test_label (required)
+#     The label of the host test. The template will add the "($host_toolchain)"
+#     parameter.
+#     Type: GN label
+#
+#   The remaining parameters are forwarded to the fuchsia_component template.
+template("starnix_linux_test_component") {
+  test_toolchain = "//build/toolchain:linux_x64"
+  starnix_toolchain_test_component(target_name) {
+    forward_variables_from(invoker, "*")
+  }
+}
diff --git a/src/proc/tests/chromiumos/build/starnix_toolchain_test_component.gni b/src/proc/tests/chromiumos/build/starnix_toolchain_test_component.gni
new file mode 100644
index 0000000..973ca92
--- /dev/null
+++ b/src/proc/tests/chromiumos/build/starnix_toolchain_test_component.gni
@@ -0,0 +1,58 @@
+# 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.
+
+import("//build/components.gni")
+
+# Defines a Fuchsia component that contains a test binary built with a specific toolchain.
+#
+# This template expects to find a CML file named "meta/${test_name}.cml" where
+# "test_name" is the name of this target. This file is used as the component
+# manifest for the test.
+#
+# Parameters
+#
+#   test_label (required)
+#     The label of the test.
+#     Type: GN label
+#   test_toolchain (required)
+#     The toolchain to use to build the test, e.g. //build/toolchain:linux_x64.
+#     parameter.
+#     Type: string
+#   test_binary (optional)
+#     The name of the binary produced by test_label. Defaults to target_name.
+#     Type: string
+#
+#   The remaining parameters are forwarded to the fuchsia_component template.
+template("starnix_toolchain_test_component") {
+  assert(defined(invoker.test_label))
+  assert(defined(invoker.test_toolchain))
+
+  if (defined(invoker.test_binary)) {
+    test_binary = invoker.test_binary
+  } else {
+    test_binary = target_name
+  }
+  test_label = "${invoker.test_label}(${invoker.test_toolchain})"
+
+  resource("${target_name}_resource") {
+    testonly = true
+    out_dir = get_label_info(test_label, "root_out_dir")
+    sources = [ "${out_dir}/${test_binary}" ]
+    outputs = [ "data/tests/${test_binary}" ]
+    deps = [ test_label ]
+  }
+
+  fuchsia_test_component(target_name) {
+    forward_variables_from(invoker, "*", [ "test_label" ])
+
+    testonly = true
+    check_references = false
+    manifest = "meta/${target_name}.cml"
+
+    if (!defined(deps)) {
+      deps = []
+    }
+    deps += [ ":${target_name}_resource" ]
+  }
+}
diff --git a/src/proc/tests/chromiumos/meta/virtmagma_conformance_tests.cml b/src/proc/tests/chromiumos/meta/virtmagma_conformance_tests.cml
new file mode 100644
index 0000000..571b173
--- /dev/null
+++ b/src/proc/tests/chromiumos/meta/virtmagma_conformance_tests.cml
@@ -0,0 +1,7 @@
+{
+    include: [ "//src/proc/tests/chromiumos/starmium_test.shard.cml" ],
+    program: {
+        binary: "data/tests/virtmagma_conformance_tests",
+        args: [ "--gtest_filter=-*.DeviceId:*.VendorId:*.QueryReturnsBuffer:*.QueryReturnsBufferLeaky:*.QueryReturnsBufferCalibratedTimestamps:*.QueryTestRestartSupported:*.BufferMap:*.FromC:*ExecuteCommand*" ],
+    },
+}
diff --git a/src/proc/tests/chromiumos/syscalls/BUILD.gn b/src/proc/tests/chromiumos/syscalls/BUILD.gn
index efffd0e..0127980 100644
--- a/src/proc/tests/chromiumos/syscalls/BUILD.gn
+++ b/src/proc/tests/chromiumos/syscalls/BUILD.gn
@@ -2,27 +2,40 @@
 # 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")
+import("//src/proc/tests/chromiumos/build/starnix_linux_test_component.gni")
 
 group("tests") {
   testonly = true
   deps = []
 
-  if (host_os == "linux") {
-    deps += [ ":syscalls_test($host_toolchain)" ]
+  if (target_cpu == "x64" && !is_asan) {
+    deps += [ ":test_chromiumos_syscalls" ]
   }
 }
 
-if (host_os == "linux") {
-  test("syscalls_test") {
-    sources = [
-      "restart_read_test.cc",
-      "terminal_test.cc",
-      "trivial_test.cc",
-    ]
-    deps = [
-      "//src/lib/fxl/test:gtest_main",
-      "//third_party/googletest:gtest",
-    ]
-  }
+test("syscalls_test_bin") {
+  sources = [
+    "restart_read_test.cc",
+    "trivial_test.cc",
+  ]
+  deps = [
+    "//src/lib/fxl/test:gtest_main",
+    "//third_party/googletest:gtest",
+  ]
+}
+
+starnix_linux_test_component("syscalls_test") {
+  test_label = ":syscalls_test_bin"
+  test_binary = "syscalls_test_bin"
+}
+
+fuchsia_test_package("test_chromiumos_syscalls") {
+  test_components = [ ":syscalls_test" ]
+
+  # This package intentionally contains many non-Fuchia ELF binaries that
+  # are not under /data/, and some of them are even unstripped, so disable
+  # theses checks to build successfully.
+  disable_elf_binaries_checks = true
 }
diff --git a/src/proc/tests/chromiumos/meta/syscalls_test.cml b/src/proc/tests/chromiumos/syscalls/meta/syscalls_test.cml
similarity index 67%
rename from src/proc/tests/chromiumos/meta/syscalls_test.cml
rename to src/proc/tests/chromiumos/syscalls/meta/syscalls_test.cml
index 310c64e..2e8dc59 100644
--- a/src/proc/tests/chromiumos/meta/syscalls_test.cml
+++ b/src/proc/tests/chromiumos/syscalls/meta/syscalls_test.cml
@@ -1,6 +1,6 @@
 {
     include: [ "//src/proc/tests/chromiumos/starmium_test.shard.cml" ],
     program: {
-        binary: "data/tests/syscalls_test",
+        binary: "data/tests/syscalls_test_bin",
     },
 }
diff --git a/src/security/policy/build_info_allowlist_eng.txt b/src/security/policy/build_info_allowlist_eng.txt
index 36b702a..3d2793d 100644
--- a/src/security/policy/build_info_allowlist_eng.txt
+++ b/src/security/policy/build_info_allowlist_eng.txt
@@ -1,8 +1,5 @@
 fuchsia-pkg://fuchsia.com/amber#meta/system_updater.cmx
 fuchsia-pkg://fuchsia.com/build-info-service#meta/build-info.cmx
-fuchsia-pkg://fuchsia.com/copy-forensics#meta/feedback.cmx
-fuchsia-pkg://fuchsia.com/feedback-data-tests#meta/datastore_unittest.cmx
-fuchsia-pkg://fuchsia.com/feedback-data-tests#meta/main_service_unittest.cmx
 fuchsia-pkg://fuchsia.com/has-build-info#meta/has-build-info.cmx
 fuchsia-pkg://fuchsia.com/settings#meta/settings.cmx
 fuchsia-pkg://fuchsia.com/sl4f#meta/sl4f.cmx
diff --git a/src/session/bin/session_manager/BUILD.gn b/src/session/bin/session_manager/BUILD.gn
index ac853b8..273b6a1 100644
--- a/src/session/bin/session_manager/BUILD.gn
+++ b/src/session/bin/session_manager/BUILD.gn
@@ -77,7 +77,6 @@
 fuchsia_component_manifest("manifest") {
   component_name = "session_manager"
   manifest = "meta/session_manager.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_structured_config_rust_lib("session_manager_config") {
diff --git a/src/session/build/session_manager.gni b/src/session/build/session_manager.gni
index cdbccaf..6a6ddfd 100644
--- a/src/session/build/session_manager.gni
+++ b/src/session/build/session_manager.gni
@@ -27,7 +27,6 @@
 
   fuchsia_component_manifest(manifest_target) {
     manifest = "//src/session/bin/session_manager/meta/session_manager.cml"
-    restricted_features = [ "structured_config" ]
     component_name = "session_manager"
   }
 
diff --git a/src/settings/BUILD.gn b/src/settings/BUILD.gn
index 8d04918..b0f30a2 100644
--- a/src/settings/BUILD.gn
+++ b/src/settings/BUILD.gn
@@ -5,6 +5,7 @@
 group("settings") {
   testonly = true
   deps = [
+    ":tests",
     "config",
     "service",
   ]
diff --git a/src/settings/service/BUILD.gn b/src/settings/service/BUILD.gn
index 681f906..5ae271d 100644
--- a/src/settings/service/BUILD.gn
+++ b/src/settings/service/BUILD.gn
@@ -14,6 +14,7 @@
     ":bin",
     ":lib",
     ":setui_service",
+    ":tests",
   ]
 }
 
diff --git a/src/storage/fidl/fuchsia.fs.startup/BUILD.gn b/src/storage/fidl/fuchsia.fs.startup/BUILD.gn
index 24e6ab0..c89d210 100644
--- a/src/storage/fidl/fuchsia.fs.startup/BUILD.gn
+++ b/src/storage/fidl/fuchsia.fs.startup/BUILD.gn
@@ -8,6 +8,7 @@
   sources = [ "startup.fidl" ]
   public_deps = [
     "//sdk/fidl/fuchsia.hardware.block",
+    "//sdk/fidl/fuchsia.io",
     "//src/storage/fxfs:fuchsia.fxfs",
   ]
 }
diff --git a/src/storage/fidl/fuchsia.fs.startup/startup.fidl b/src/storage/fidl/fuchsia.fs.startup/startup.fidl
index e6cdfc2..c3cf84b 100644
--- a/src/storage/fidl/fuchsia.fs.startup/startup.fidl
+++ b/src/storage/fidl/fuchsia.fs.startup/startup.fidl
@@ -6,6 +6,7 @@
 
 using fuchsia.fxfs;
 using fuchsia.hardware.block;
+using fuchsia.io;
 using zx;
 
 /// Compression algorithm specifier.
@@ -47,6 +48,10 @@
 
     /// An optional connection to a crypt client (for encrypted filesystems).
     crypt client_end:<fuchsia.fxfs.Crypt, optional>;
+
+    // If set, provides the caller with the opportunity to migrate data before the mount is
+    // finalised.  The mount will be blocked until the channel is closed.
+    migrate_root server_end:<fuchsia.io.Directory, optional>;
 };
 
 /// Options for how to format filesystems.
diff --git a/src/storage/fshost/BUILD.gn b/src/storage/fshost/BUILD.gn
index df8bee8..d6f730d 100644
--- a/src/storage/fshost/BUILD.gn
+++ b/src/storage/fshost/BUILD.gn
@@ -421,7 +421,6 @@
   manifest_outputs = get_target_outputs(":test-fshost.cml")
   manifest = manifest_outputs[0]
   deps = [ ":test-fshost.cml" ]
-  restricted_features = [ "structured_config" ]
 }
 
 # This is a test version of fshost, not a component with fshost tests.
@@ -460,7 +459,6 @@
   manifest_outputs = get_target_outputs(":test-fshost-no-watcher.cml")
   manifest = manifest_outputs[0]
   deps = [ ":test-fshost-no-watcher.cml" ]
-  restricted_features = [ "structured_config" ]
 }
 
 # This is a test version of fshost with no block watcher.
@@ -556,7 +554,6 @@
   manifest = get_target_outputs(":fshost.cml")
   manifest = manifest[0]
   deps = [ ":fshost.cml" ]
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_structured_config_cpp_elf_lib("fshost_config") {
diff --git a/src/storage/fshost/block-device-manager.cc b/src/storage/fshost/block-device-manager.cc
index dcb1163..f895eb3 100644
--- a/src/storage/fshost/block-device-manager.cc
+++ b/src/storage/fshost/block-device-manager.cc
@@ -314,7 +314,7 @@
         reformat_ = true;
       }
     } else if (reformat_) {
-      // We formatted zxcrypt, so skip straight to formatting minfs.
+      // We formatted zxcrypt, so skip straight to formatting the filesystem.
       zx_status_t status = device.FormatFilesystem();
       if (status != ZX_OK) {
         return status;
diff --git a/src/storage/fshost/block-device.cc b/src/storage/fshost/block-device.cc
index 787e34f..43d3adc 100644
--- a/src/storage/fshost/block-device.cc
+++ b/src/storage/fshost/block-device.cc
@@ -55,7 +55,6 @@
 #include "src/lib/storage/fs_management/cpp/mount.h"
 #include "src/lib/uuid/uuid.h"
 #include "src/storage/fshost/block-device-interface.h"
-#include "src/storage/fshost/copier.h"
 #include "src/storage/fshost/fshost-fs-provider.h"
 #include "src/storage/fvm/format.h"
 #include "src/storage/minfs/fsck.h"
@@ -113,15 +112,14 @@
 // binary to terminate and returns the status.
 zx_status_t RunBinary(const fbl::Vector<const char*>& argv,
                       fidl::ClientEnd<fuchsia_io::Node> device,
-                      fidl::ServerEnd<fuchsia_io::Directory> export_root = {},
-                      fidl::ClientEnd<fuchsia_fxfs::Crypt> crypt_client = {}) {
+                      fidl::ServerEnd<fuchsia_io::Directory> export_root = {}) {
   FX_CHECK(argv[argv.size() - 1] == nullptr);
   FshostFsProvider fs_provider;
   DevmgrLauncher launcher(&fs_provider);
   zx::process proc;
   int handle_count = 1;
-  zx_handle_t handles[3] = {device.TakeChannel().release()};
-  uint32_t handle_ids[3] = {FS_HANDLE_BLOCK_DEVICE_ID};
+  zx_handle_t handles[2] = {device.TakeChannel().release()};
+  uint32_t handle_ids[2] = {FS_HANDLE_BLOCK_DEVICE_ID};
   bool async = false;
   if (export_root) {
     handles[handle_count] = export_root.TakeChannel().release();
@@ -129,11 +127,6 @@
     ++handle_count;
     async = true;
   }
-  if (crypt_client) {
-    handles[handle_count] = crypt_client.TakeChannel().release();
-    handle_ids[handle_count] = PA_HND(PA_USER0, 2);
-    ++handle_count;
-  }
   if (zx_status_t status = launcher.Launch(
           *zx::job::default_job(), argv[0], argv.data(), nullptr, -1,
           /* TODO(fxbug.dev/32044) */ zx::resource(), handles, handle_ids, handle_count, &proc, 0);
@@ -707,13 +700,59 @@
     case fs_management::kDiskFormatF2fs:
     case fs_management::kDiskFormatMinfs: {
       fs_management::MountOptions options;
+
+      // Fxfs supports the migrate_root mount option which allows us to copy source data before the
+      // mount is finalised.
+      std::thread copy_thread;
+      std::optional<Copier> copier = std::move(source_data_);
+      source_data_.reset();
+
+      if (copier) {
+        if (format_ == fs_management::kDiskFormatFxfs) {
+          options.migrate_root = [&copier,
+                                  &copy_thread]() -> fidl::ServerEnd<fuchsia_io::Directory> {
+            FX_CHECK(copier);
+
+            auto migrate_root_or = fidl::CreateEndpoints<fuchsia_io::Directory>();
+            if (migrate_root_or.is_error())
+              return {};
+
+            zx::channel client = migrate_root_or->client.TakeChannel();
+            copy_thread = std::thread([&copier, client = std::move(client)]() mutable {
+              FX_LOGS(INFO) << "Copying data...";
+              fbl::unique_fd fd;
+              if (zx_status_t status = fdio_fd_create(client.release(), fd.reset_and_get_address());
+                  status != ZX_OK) {
+                FX_PLOGS(ERROR, status) << "Unable to create fd";
+                return;
+              }
+              if (zx_status_t status = copier->Write(std::move(fd)); status != ZX_OK) {
+                FX_PLOGS(ERROR, status) << "Failed to copy data";
+                return;
+              }
+              FX_LOGS(INFO) << "Successfully copied data";
+            });
+
+            return std::move(migrate_root_or->server);
+          };
+        } else {
+          // Treat errors here as non-fatal.
+          [[maybe_unused]] zx_status_t status = CopySourceData(*copier);
+        }
+      }
+
       FX_LOGS(INFO) << "BlockDevice::MountFilesystem(data partition)";
       zx_status_t status = MountData(&options, std::move(block_device));
+
+      if (copy_thread.joinable())
+        copy_thread.join();
+
       if (status != ZX_OK) {
         FX_LOGS(ERROR) << "Failed to mount data partition: " << zx_status_get_string(status) << ".";
         MaybeDumpMetadata(fd_.duplicate(), {.disk_format = format_});
         return status;
       }
+
       return ZX_OK;
     }
     default:
@@ -735,7 +774,7 @@
   if (gpt_is_sys_guid(guid, GPT_GUID_LEN)) {
     return ZX_ERR_NOT_SUPPORTED;
   } else if (gpt_is_data_guid(guid, GPT_GUID_LEN)) {
-    return mounter_->MountData(std::move(block_device), *options, content_format());
+    return mounter_->MountData(std::move(block_device), *options, format_);
   } else if (gpt_is_durable_guid(guid, GPT_GUID_LEN)) {
     return mounter_->MountDurable(std::move(block_device), *options);
   }
@@ -854,54 +893,66 @@
 }
 
 zx_status_t BlockDevice::CheckCustomFilesystem(fs_management::DiskFormat format) const {
-  const std::string binary_path(BinaryPathForFormat(format));
-  if (binary_path.empty()) {
-    FX_LOGS(ERROR) << "Unsupported data format";
-    return ZX_ERR_INVALID_ARGS;
-  }
-
-  FX_LOGS(INFO) << "Starting fsck with format " << DiskFormatString(format);
-
-  fbl::Vector<const char*> argv;
-  argv.push_back(binary_path.c_str());
-  argv.push_back("fsck");
-  argv.push_back(nullptr);
   auto device_or = GetDeviceEndPoint();
   if (device_or.is_error()) {
     return device_or.error_value();
   }
-  auto crypt_client_or = service::Connect<fuchsia_fxfs::Crypt>();
-  if (crypt_client_or.is_error())
-    return crypt_client_or.error_value();
-  return RunBinary(argv, std::move(device_or).value(), {}, std::move(crypt_client_or).value());
+
+  if (format == fs_management::kDiskFormatFxfs) {
+    // Fxfs runs as a component.
+    constexpr char startup_service_path[] = "/fxfs/fuchsia.fs.startup.Startup";
+    auto startup_client_end = service::Connect<fuchsia_fs_startup::Startup>(startup_service_path);
+    if (startup_client_end.is_error()) {
+      FX_PLOGS(ERROR, startup_client_end.error_value())
+          << "Failed to connect to startup service at " << startup_service_path;
+      return startup_client_end.error_value();
+    }
+    auto startup_client = fidl::BindSyncClient(std::move(*startup_client_end));
+    fidl::ClientEnd<fuchsia_hardware_block::Block> block_client_end(device_or->TakeChannel());
+    fs_management::FsckOptions options;
+    options.crypt_client = [] {
+      auto crypt_client_or = service::Connect<fuchsia_fxfs::Crypt>();
+      if (crypt_client_or.is_error())
+        return zx::channel();
+      else
+        return crypt_client_or->TakeChannel();
+    };
+    auto res = startup_client->Check(std::move(block_client_end), options.as_check_options());
+    if (!res.ok()) {
+      FX_PLOGS(ERROR, res.status()) << "Failed to fsck (FIDL error)";
+      return res.status();
+    }
+    if (res->result.is_err()) {
+      FX_PLOGS(ERROR, res->result.err()) << "Fsck failed";
+      return res->result.err();
+    }
+    return ZX_OK;
+  } else {
+    const std::string binary_path(BinaryPathForFormat(format));
+    if (binary_path.empty()) {
+      FX_LOGS(ERROR) << "Unsupported data format";
+      return ZX_ERR_INVALID_ARGS;
+    }
+
+    return RunBinary({binary_path.c_str(), "fsck", nullptr}, std::move(device_or).value());
+  }
 }
 
 // This is a destructive operation and isn't atomic (i.e. not resilient to power interruption).
-zx_status_t BlockDevice::FormatCustomFilesystem(fs_management::DiskFormat format) const {
-  const std::string binary_path(BinaryPathForFormat(format));
-  if (binary_path.empty()) {
-    FX_LOGS(ERROR) << "Unsupported data format";
-    return ZX_ERR_INVALID_ARGS;
-  }
-
-  FX_LOGS(INFO) << "Formatting " << DiskFormatString(format);
-
+zx_status_t BlockDevice::FormatCustomFilesystem(fs_management::DiskFormat format) {
   // Try mounting minfs and slurp all existing data off.
-  zx_handle_t handle;
-  if (zx_status_t status = fdio_fd_clone(fd_.get(), &handle); status != ZX_OK)
-    return status;
-  fbl::unique_fd fd;
-  if (zx_status_t status = fdio_fd_create(handle, fd.reset_and_get_address()); status != ZX_OK)
-    return status;
-
-  Copier copier;
-  {
+  if (content_format() == fs_management::kDiskFormatMinfs) {
+    FX_LOGS(INFO) << "Attempting to read existing Minfs data";
     auto device_or = GetDeviceEndPoint();
     if (device_or.is_error())
       return device_or.error_value();
-    copier = TryReadingMinfs(std::move(device_or).value());
+    if (Copier copier = TryReadingMinfs(std::move(device_or).value()); !copier.empty()) {
+      FX_LOGS(INFO) << "Successfully read Minfs data";
+      source_data_.emplace(std::move(copier));
+    }
   }
 
+  FX_LOGS(INFO) << "Formatting " << DiskFormatString(format);
   fidl::ClientEnd<fuchsia_io::Node> device;
   if (auto device_or = GetDeviceEndPoint(); device_or.is_error()) {
     return device_or.error_value();
@@ -994,7 +1045,7 @@
     if (format == fs_management::kDiskFormatF2fs) {
       slice_target = kDefaultF2fsMinBytes;
     }
-    if (slices_available < slice_target) {
+    if (slices_available * slice_size < slice_target) {
       FX_LOGS(WARNING) << "Only " << slices_available << " slices available for "
                        << DiskFormatString(format)
                        << " partition; some functionality may be missing.";
@@ -1020,91 +1071,97 @@
     return status;
   }
 
-  fbl::Vector<const char*> argv = {binary_path.c_str(), "mkfs", nullptr};
+  if (format == fs_management::kDiskFormatFxfs) {
+    // Fxfs runs as a component.
+    constexpr char startup_service_path[] = "/fxfs/fuchsia.fs.startup.Startup";
+    auto startup_client_end = service::Connect<fuchsia_fs_startup::Startup>(startup_service_path);
+    if (startup_client_end.is_error()) {
+      FX_PLOGS(ERROR, startup_client_end.error_value())
+          << "Failed to connect to startup service at " << startup_service_path;
+      return startup_client_end.error_value();
+    }
+    auto startup_client = fidl::BindSyncClient(std::move(*startup_client_end));
+    auto device_or = GetDeviceEndPoint();
+    if (device_or.is_error()) {
+      FX_PLOGS(ERROR, device_or.error_value()) << "Unable to get device";
+      return device_or.error_value();
+    }
+    fidl::ClientEnd<fuchsia_hardware_block::Block> block_client_end(device_or->TakeChannel());
+    fs_management::MkfsOptions options;
+    options.crypt_client = [] {
+      auto crypt_client_or = service::Connect<fuchsia_fxfs::Crypt>();
+      if (crypt_client_or.is_error())
+        return zx::channel();
+      else
+        return crypt_client_or->TakeChannel();
+    };
+    auto res = startup_client->Format(std::move(block_client_end), options.as_format_options());
+    if (!res.ok()) {
+      FX_PLOGS(ERROR, res.status()) << "Failed to format (FIDL error)";
+      return res.status();
+    }
+    if (res->result.is_err()) {
+      FX_PLOGS(ERROR, res->result.err()) << "Format failed";
+      return res->result.err();
+    }
+  } else {
+    const std::string binary_path(BinaryPathForFormat(format));
+    if (binary_path.empty()) {
+      FX_LOGS(ERROR) << "Unsupported data format";
+      return ZX_ERR_INVALID_ARGS;
+    }
 
-  {
-    auto crypt_client_or = service::Connect<fuchsia_fxfs::Crypt>();
-    if (crypt_client_or.is_error())
-      return crypt_client_or.error_value();
-    if (zx_status_t status =
-            RunBinary(argv, std::move(device), {}, std::move(crypt_client_or).value());
+    if (zx_status_t status = RunBinary({binary_path.c_str(), "mkfs", nullptr}, std::move(device));
         status != ZX_OK) {
       return status;
     }
   }
+  content_format_ = format_;
 
-  // If there's any data to copy, mount and then copy all the data back.
-  if (copier.empty()) {
-    content_format_ = format_;
-    return ZX_OK;
-  }
-  FX_LOGS(INFO) << "Copying data from old partition...";
+  return ZX_OK;
+}
 
-  if (zx_status_t status = fdio_fd_clone(fd_.get(), &handle); status != ZX_OK) {
-    FX_LOGS(ERROR) << "fdio_fd_clone failed";
-    return status;
-  }
-  if (zx_status_t status = fdio_fd_create(handle, fd.reset_and_get_address()); status != ZX_OK)
-    return status;
-
+// This copies source data for filesystems that aren't components and don't support the migrate_root
+// mount option.
+zx_status_t BlockDevice::CopySourceData(const Copier& copier) const {
+  FX_LOGS(INFO) << "Copying data...";
   auto export_root_or = fidl::CreateEndpoints<fuchsia_io::Directory>();
   if (export_root_or.is_error())
     return export_root_or.error_value();
 
-  argv[1] = "mount";
+  const std::string binary_path(BinaryPathForFormat(format_));
   auto device_or = GetDeviceEndPoint();
   if (device_or.is_error()) {
     return device_or.error_value();
   }
-  {
-    auto crypt_client_or = service::Connect<fuchsia_fxfs::Crypt>();
-    if (crypt_client_or.is_error())
-      return crypt_client_or.error_value();
-    if (zx_status_t status =
-            RunBinary(argv, std::move(device_or).value(), std::move(export_root_or->server),
-                      std::move(crypt_client_or).value());
-        status != ZX_OK) {
-      FX_LOGS(ERROR) << "Unable to mount after format";
-      return status;
-    }
-  }
-
-  zx::status create_root = fidl::CreateEndpoints<fuchsia_io::Node>();
-  if (create_root.is_error()) {
-    return create_root.status_value();
-  }
-  auto [root_client, root_server] = std::move(create_root).value();
-
-  if (auto resp = fidl::WireCall(export_root_or->client)
-                      ->Open(fuchsia_io::wire::OpenFlags::kRightReadable |
-                                 fuchsia_io::wire::OpenFlags::kPosixWritable |
-                                 fuchsia_io::wire::OpenFlags::kPosixExecutable,
-                             0, fidl::StringView("root"), std::move(root_server));
-      !resp.ok()) {
-    FX_LOGS(ERROR) << "Failed to open export root: " << resp.status_string();
-    return resp.status();
-  }
-
   if (zx_status_t status =
-          fdio_fd_create(root_client.TakeChannel().release(), fd.reset_and_get_address());
+          RunBinary({binary_path.c_str(), "mount", nullptr}, std::move(device_or).value(),
+                    std::move(export_root_or->server));
+      status != ZX_OK) {
+    FX_LOGS(ERROR) << "Unable to mount after format";
+    return status;
+  }
+  auto root_or = fs_management::FsRootHandle(export_root_or->client);
+  if (root_or.is_error()) {
+    FX_PLOGS(ERROR, root_or.error_value()) << "Unable to get root";
+    return root_or.error_value();
+  }
+  fbl::unique_fd fd;
+  if (zx_status_t status =
+          fdio_fd_create(root_or->TakeChannel().release(), fd.reset_and_get_address());
       status != ZX_OK) {
     FX_LOGS(ERROR) << "fdio_fd_create failed";
     return status;
   }
-
   if (zx_status_t status = copier.Write(std::move(fd)); status != ZX_OK) {
     FX_LOGS(ERROR) << "Failed to copy data: " << zx_status_get_string(status);
     return status;
   }
-
   if (auto status = fs_management::Shutdown(export_root_or->client); status.is_error()) {
     // Ignore errors; there's nothing we can do.
     FX_LOGS(WARNING) << "Unmount failed: " << status.status_string();
   }
-
-  FX_LOGS(INFO) << "Copying data complete.";
-  content_format_ = format_;
-
+  FX_LOGS(INFO) << "Successfully copied data";
   return ZX_OK;
 }
 
diff --git a/src/storage/fshost/block-device.h b/src/storage/fshost/block-device.h
index 81e9f5c..9e04676 100644
--- a/src/storage/fshost/block-device.h
+++ b/src/storage/fshost/block-device.h
@@ -19,6 +19,7 @@
 
 #include "src/lib/storage/fs_management/cpp/mount.h"
 #include "src/storage/fshost/block-device-interface.h"
+#include "src/storage/fshost/copier.h"
 #include "src/storage/fshost/filesystem-mounter.h"
 #include "src/storage/fshost/fshost_config.h"
 
@@ -65,11 +66,14 @@
   const std::string& partition_name() const override;
   zx::status<fidl::ClientEnd<fuchsia_io::Node>> GetDeviceEndPoint() const;
   zx_status_t CheckCustomFilesystem(fs_management::DiskFormat format) const;
-  zx_status_t FormatCustomFilesystem(fs_management::DiskFormat format) const;
+  zx_status_t FormatCustomFilesystem(fs_management::DiskFormat format);
 
  private:
   zx_status_t MountData(fs_management::MountOptions* options, zx::channel block_device);
 
+  // Copies source data for filesystems that aren't components.
+  zx_status_t CopySourceData(const Copier& copier) const;
+
   FilesystemMounter* mounter_ = nullptr;
   fbl::unique_fd fd_;
   const fshost_config::Config* device_config_;
@@ -80,6 +84,9 @@
   mutable std::string partition_name_;
   mutable std::optional<fuchsia_hardware_block_partition::wire::Guid> instance_guid_;
   mutable std::optional<fuchsia_hardware_block_partition::wire::Guid> type_guid_;
+
+  // Data that should be written to the partition once mounted.
+  std::optional<Copier> source_data_;
 };
 
 }  // namespace fshost
diff --git a/src/storage/fshost/config.h b/src/storage/fshost/config.h
index 2d176f6..07d2ba4 100644
--- a/src/storage/fshost/config.h
+++ b/src/storage/fshost/config.h
@@ -9,6 +9,7 @@
 #include "src/storage/fshost/fshost_config.h"
 
 namespace fshost {
+
 // Returns the default/base configuration for fshost when run without configuration from the
 // component framework.
 fshost_config::Config DefaultConfig();
diff --git a/src/storage/fshost/generated_fshost_config.gni b/src/storage/fshost/generated_fshost_config.gni
index a8dbc0e..8725de7 100644
--- a/src/storage/fshost/generated_fshost_config.gni
+++ b/src/storage/fshost/generated_fshost_config.gni
@@ -97,7 +97,6 @@
   fuchsia_component_manifest(_manifest_target) {
     component_name = _component_name
     manifest = "//src/storage/fshost/meta/config.cml"
-    restricted_features = [ "structured_config" ]
     metadata = {
       # we don't want this in the packaged output, it's just to give cmc something to work with
       distribution_entries_barrier = []
diff --git a/src/storage/fshost/main.cc b/src/storage/fshost/main.cc
index d7818ff..6487fba4 100644
--- a/src/storage/fshost/main.cc
+++ b/src/storage/fshost/main.cc
@@ -160,7 +160,7 @@
   auto boot_args = FshostBootArgs::Create();
   auto config = DefaultConfig();
   if (!ignore_component_config) {
-    config = fshost_config::Config::from_args();
+    config = fshost_config::Config::TakeFromStartupHandle();
   }
   ApplyBootArgsToConfig(config, *boot_args);
 
diff --git a/src/storage/fshost/meta/fxfs_fshost.cml b/src/storage/fshost/meta/fxfs_fshost.cml
index ee98b9a..c1c6774 100644
--- a/src/storage/fshost/meta/fxfs_fshost.cml
+++ b/src/storage/fshost/meta/fxfs_fshost.cml
@@ -27,11 +27,11 @@
             path: "/fxfs/fuchsia.fs.startup.Startup",
         },
 
-        // Required for inspect data.
+        // Required for inspect data and to migrate data.
         {
             directory: "root",
             from: "#fxfs",
-            rights: [ "r*" ],
+            rights: [ "rw*" ],
             path: "/data_root",
         },
     ],
diff --git a/src/storage/fxfs/BUILD.gn b/src/storage/fxfs/BUILD.gn
index d2948ff..119f63f 100644
--- a/src/storage/fxfs/BUILD.gn
+++ b/src/storage/fxfs/BUILD.gn
@@ -10,10 +10,7 @@
 import("//build/rust/rustc_macro.gni")
 import("//src/storage/fs_test/suite.gni")
 
-# Set to true to enable tracing.  For now this cannot be enabled by default due to
-# https://fxbug.dev/66819#c88.  Enabling it trips an LSAN bug that is triggered by the
-# implementation of trace_provider_create_with_fdio.
-tracing_enabled = false
+tracing_enabled = true
 
 fxfs_deps = [
   ":fxfs_macros",
diff --git a/src/storage/fxfs/src/object_store/journal.rs b/src/storage/fxfs/src/object_store/journal.rs
index c361141..0a7e871 100644
--- a/src/storage/fxfs/src/object_store/journal.rs
+++ b/src/storage/fxfs/src/object_store/journal.rs
@@ -775,7 +775,7 @@
         const INIT_ROOT_STORE_OBJECT_ID: u64 = 4;
         const INIT_ALLOCATOR_OBJECT_ID: u64 = 5;
 
-        log::info!("Formatting fxfs device-size: {})", filesystem.device().size());
+        log::info!("Formatting fxfs (device size: {})", filesystem.device().size());
 
         let checkpoint = JournalCheckpoint {
             version: LATEST_VERSION,
diff --git a/src/storage/fxfs/src/platform/fuchsia/component.rs b/src/storage/fxfs/src/platform/fuchsia/component.rs
index a4fa839..505c9df 100644
--- a/src/storage/fxfs/src/platform/fuchsia/component.rs
+++ b/src/storage/fxfs/src/platform/fuchsia/component.rs
@@ -233,6 +233,18 @@
         let volume = volumes
             .open_or_create_volume(DEFAULT_VOLUME_NAME, Some(crypt), /* create_only: */ false)
             .await?;
+        let root = volume.root();
+        if let Some(migrate_root) = options.migrate_root {
+            let scope = volume.volume().scope();
+            root.clone().open(
+                scope.clone(),
+                fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_WRITABLE,
+                0,
+                Path::dot(),
+                migrate_root.into_channel().into(),
+            );
+            scope.wait().await;
+        }
         self.start_serving(&volume).await?;
         if let State::PreStart { queued } = std::mem::replace(
             &mut *self.state.lock().unwrap(),
@@ -245,7 +257,6 @@
                 ),
             }),
         ) {
-            let root = volume.root();
             let scope = volume.volume().scope();
             for (open_flags, mode, path, channel) in queued {
                 root.clone().open(scope.clone(), open_flags, mode, path, channel);
diff --git a/src/sys/appmgr/config/core_component_id_index.json5 b/src/sys/appmgr/config/core_component_id_index.json5
index 1bdc924..528fafa 100644
--- a/src/sys/appmgr/config/core_component_id_index.json5
+++ b/src/sys/appmgr/config/core_component_id_index.json5
@@ -194,13 +194,7 @@
         },
         {
             instance_id: "76777fb21aa060c86680f0fbd7cbd4734ef6b239b429ac4d9cb2a9d08792033d",
-            appmgr_moniker: {
-                url: "fuchsia-pkg://fuchsia.com/cobalt_system_metrics#meta/cobalt_system_metrics.cmx",
-                realm_path: [
-                    "app",
-                    "sys",
-                ],
-            },
+            moniker: "/core/cobalt_system_metrics",
         },
 
         // An entry for `memory_monitor` is needed to preserve /cache across the v2 migration.
diff --git a/src/sys/component_manager/lib/logger/src/klog.rs b/src/sys/component_manager/lib/logger/src/klog.rs
index 750f2bf..9345359 100644
--- a/src/sys/component_manager/lib/logger/src/klog.rs
+++ b/src/sys/component_manager/lib/logger/src/klog.rs
@@ -3,14 +3,12 @@
 // found in the LICENSE file.
 
 use {
-    fdio::fdio_sys,
     fuchsia_zircon::{self as zx, AsHandleRef, ObjectType},
     lazy_static::lazy_static,
     std::fmt,
     std::{panic, sync::Once},
 };
 
-const STDOUT_FD: i32 = 1;
 const MAX_LOG_LEVEL: log::Level = log::Level::Info;
 
 lazy_static! {
@@ -25,15 +23,7 @@
 
 impl KernelLogger {
     fn new() -> KernelLogger {
-        let debuglog = unsafe {
-            let mut raw_debuglog = zx::sys::ZX_HANDLE_INVALID;
-            let status = fdio_sys::fdio_fd_clone(STDOUT_FD, &mut raw_debuglog);
-            if let Err(s) = zx::Status::ok(status) {
-                // Panic as this failure means that there's no logger initialized.
-                panic!("Unable to get debuglog handle from stdout fd: {}", s);
-            }
-            fuchsia_zircon::Handle::from_raw(raw_debuglog)
-        };
+        let debuglog = fdio::clone_fd(std::io::stdout()).expect("get handle from stdout");
 
         assert_eq!(debuglog.basic_info().unwrap().object_type, ObjectType::LOG);
         KernelLogger { debuglog: debuglog.into() }
@@ -158,6 +148,8 @@
     // manager now uses to retrieve the debuglog handle. To simulate that, we need to bind
     // a handle before calling KernelLogger::init().
     fn init() {
+        const STDOUT_FD: i32 = 1;
+
         let resource = zx::Resource::from(zx::Handle::invalid());
         let debuglog = zx::DebugLog::create(&resource, zx::DebugLogOpts::empty())
             .context("Failed to create debuglog object")
diff --git a/src/sys/component_manager/src/diagnostics/component_tree_stats.rs b/src/sys/component_manager/src/diagnostics/component_tree_stats.rs
index 5574885..143ea84 100644
--- a/src/sys/component_manager/src/diagnostics/component_tree_stats.rs
+++ b/src/sys/component_manager/src/diagnostics/component_tree_stats.rs
@@ -402,12 +402,12 @@
     }
 
     fn update(&mut self, measurement: Measurement) {
-        // TODO(fxbug.dev/66596): use atomic updates here. We can't use inspect_log since it sets
-        // automatically a timestamp for the entry.
         let child = self.node.create_entry();
-        child.record_int("timestamp", measurement.timestamp().into_nanos());
-        child.record_int("cpu_time", measurement.cpu_time().into_nanos());
-        child.record_int("queue_time", measurement.queue_time().into_nanos());
+        child.atomic_update(|node| {
+            node.record_int("timestamp", measurement.timestamp().into_nanos());
+            node.record_int("cpu_time", measurement.cpu_time().into_nanos());
+            node.record_int("queue_time", measurement.queue_time().into_nanos());
+        });
         self.previous_measurement = self.recent_measurement.take();
         self.recent_measurement = Some(measurement);
     }
diff --git a/src/sys/component_manager/testing/echo_server/src/main.rs b/src/sys/component_manager/testing/echo_server/src/main.rs
index 4211f0b..cbf8bbb 100644
--- a/src/sys/component_manager/testing/echo_server/src/main.rs
+++ b/src/sys/component_manager/testing/echo_server/src/main.rs
@@ -34,8 +34,15 @@
 
 // Handler for incoming service requests
 async fn handle_echo_request(mut stream: EchoRequestStream) {
+    let default_reply = match std::env::args().skip(1).next() {
+        Some(user_specified_reply) => user_specified_reply,
+        None => "UNSET".to_string(),
+    };
+
     while let Some(event) = stream.try_next().await.expect("failed to serve echo service") {
         let EchoRequest::EchoString { value, responder } = event;
-        responder.send(value.as_ref().map(|s| &**s)).expect("failed to send echo response");
+        responder
+            .send(Some(value.unwrap_or(default_reply.to_string())).as_ref().map(|s| &**s))
+            .expect("failed to send echo response");
     }
 }
diff --git a/src/sys/component_manager/tests/hub/BUILD.gn b/src/sys/component_manager/tests/hub/BUILD.gn
index 01765d7..09d5b47 100644
--- a/src/sys/component_manager/tests/hub/BUILD.gn
+++ b/src/sys/component_manager/tests/hub/BUILD.gn
@@ -74,7 +74,6 @@
   testonly = true
   component_name = "structured_config_reporter"
   manifest = "components/structured_config/meta/reporter.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("structured_config_reporter") {
diff --git a/src/sys/component_manager/tests/structured_config/client_integration/cpp_driver/BUILD.gn b/src/sys/component_manager/tests/structured_config/client_integration/cpp_driver/BUILD.gn
index 50a006d..3f8b73e 100644
--- a/src/sys/component_manager/tests/structured_config/client_integration/cpp_driver/BUILD.gn
+++ b/src/sys/component_manager/tests/structured_config/client_integration/cpp_driver/BUILD.gn
@@ -40,10 +40,7 @@
   testonly = true
   component_name = "cpp_driver_receiver"
   manifest = "meta/receiver.cml"
-  restricted_features = [
-    "structured_config",
-    "services",
-  ]
+  restricted_features = [ "services" ]
 }
 
 fuchsia_driver_component("receiver_component") {
diff --git a/src/sys/component_manager/tests/structured_config/client_integration/cpp_driver/receiver.cc b/src/sys/component_manager/tests/structured_config/client_integration/cpp_driver/receiver.cc
index 818abcc1..2a8dde3 100644
--- a/src/sys/component_manager/tests/structured_config/client_integration/cpp_driver/receiver.cc
+++ b/src/sys/component_manager/tests/structured_config/client_integration/cpp_driver/receiver.cc
@@ -82,7 +82,7 @@
                                                            fidl::WireSharedClient<fdf::Node> node,
                                                            driver::Namespace ns,
                                                            driver::Logger logger) {
-    auto config = receiver_config::Config::from_args(start_args);
+    auto config = receiver_config::Config::TakeFromStartArgs(start_args);
     auto driver =
         std::make_unique<ReceiverDriver>(dispatcher->async_dispatcher(), std::move(node),
                                          std::move(ns), std::move(logger), std::move(config));
@@ -110,7 +110,9 @@
     ZX_ASSERT(result.is_ok());
 
     // Serve the inspect data
-    config_.record_to_inspect(&inspector_);
+    auto config_node = inspector_.GetRoot().CreateChild("config");
+    config_.RecordInspect(&config_node);
+    inspector_.emplace(std::move(config_node));
     auto exposed_inspector = driver::ExposedInspector::Create(dispatcher_, inspector_, outgoing_);
     ZX_ASSERT(exposed_inspector.is_ok());
     exposed_inspector_ = std::move(exposed_inspector.value());
diff --git a/src/sys/component_manager/tests/structured_config/client_integration/cpp_elf/BUILD.gn b/src/sys/component_manager/tests/structured_config/client_integration/cpp_elf/BUILD.gn
index 7a8a26b..fda78c0 100644
--- a/src/sys/component_manager/tests/structured_config/client_integration/cpp_elf/BUILD.gn
+++ b/src/sys/component_manager/tests/structured_config/client_integration/cpp_elf/BUILD.gn
@@ -24,7 +24,6 @@
   testonly = true
   component_name = "cpp_elf_receiver"
   manifest = "meta/receiver.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_structured_config_cpp_elf_lib("config_lib") {
diff --git a/src/sys/component_manager/tests/structured_config/client_integration/cpp_elf/src/main.cc b/src/sys/component_manager/tests/structured_config/client_integration/cpp_elf/src/main.cc
index 66322c3..a90b4c7 100644
--- a/src/sys/component_manager/tests/structured_config/client_integration/cpp_elf/src/main.cc
+++ b/src/sys/component_manager/tests/structured_config/client_integration/cpp_elf/src/main.cc
@@ -47,13 +47,14 @@
 };
 
 int main(int argc, const char** argv) {
-  auto c = receiver_config::Config::from_args();
+  auto c = receiver_config::Config::TakeFromStartupHandle();
   async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
 
   auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
 
   sys::ComponentInspector inspector(context.get());
-  c.record_to_inspect(inspector.inspector());
+  inspect::Node inspect_config = inspector.root().CreateChild("config");
+  c.RecordInspect(&inspect_config);
 
   PuppetImpl impl(c);
   fidl::Binding<test::structuredconfig::receiver::ConfigReceiverPuppet> binding(&impl);
diff --git a/src/sys/component_manager/tests/structured_config/different_values/BUILD.gn b/src/sys/component_manager/tests/structured_config/different_values/BUILD.gn
index a5d919f..2475652 100644
--- a/src/sys/component_manager/tests/structured_config/different_values/BUILD.gn
+++ b/src/sys/component_manager/tests/structured_config/different_values/BUILD.gn
@@ -33,7 +33,6 @@
   testonly = true
   component_name = "receiver"
   manifest = "//src/sys/component_manager/tests/structured_config/client_integration/rust/meta/receiver.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("receiver_component") {
diff --git a/src/sys/core/meta/core.cml b/src/sys/core/meta/core.cml
index 3eef8f8..cfa6253 100644
--- a/src/sys/core/meta/core.cml
+++ b/src/sys/core/meta/core.cml
@@ -56,6 +56,11 @@
             name: "text_manager",
             url: "fuchsia-pkg://fuchsia.com/text_manager#meta/text_manager.cm",
         },
+        {
+            name: "cobalt_system_metrics",
+            url: "fuchsia-pkg://fuchsia.com/cobalt_system_metrics#meta/cobalt_system_metrics.cm",
+            startup: "eager",
+        },
 
         // Children below this line may be present on some but not all product configurations.
         // Children above this line are expected to be present on all configs that include
@@ -226,7 +231,10 @@
                 "fuchsia.ui.activity.Tracker",
             ],
             from: "#activity",
-            to: [ "#cobalt" ],
+            to: [
+                "#cobalt",
+                "#cobalt_system_metrics",
+            ],
         },
         {
             directory: "dev",
@@ -238,7 +246,10 @@
         {
             protocol: "fuchsia.tracing.provider.Registry",
             from: "self",
-            to: "#sysmem_connector",
+            to: [
+                "#cobalt_system_metrics",
+                "#sysmem_connector",
+            ],
             dependency: "weak_for_migration",
         },
         {
@@ -419,6 +430,7 @@
                 "#bluetooth-core",
                 "#brightness_manager",
                 "#cobalt",
+                "#cobalt_system_metrics",
                 "#debug_serial",
                 "#detect",
                 "#device_settings",
@@ -605,7 +617,10 @@
         {
             protocol: "fuchsia.kernel.Stats",
             from: "parent",
-            to: "#system-metrics-logger",
+            to: [
+                "#cobalt_system_metrics",
+                "#system-metrics-logger",
+            ],
         },
         {
             protocol: "fuchsia.process.Launcher",
@@ -688,6 +703,20 @@
             subdir: "class/power-sensor",
         },
         {
+            directory: "dev",
+            from: "parent",
+            as: "dev-thermal",
+            to: "#cobalt_system_metrics",
+            subdir: "class/thermal",
+        },
+        {
+            directory: "dev",
+            from: "parent",
+            as: "dev-misc",
+            to: [ "#cobalt_system_metrics" ],
+            subdir: "misc",
+        },
+        {
             directory: "root-ssl-certificates",
             from: "parent",
             to: [
@@ -734,6 +763,12 @@
             subdir: "cobalt",
         },
         {
+            directory: "config-data",
+            from: "parent",
+            to: "#cobalt_system_metrics",
+            subdir: "cobalt_system_metrics",
+        },
+        {
             protocol: [
                 "fuchsia.device.Controller",
                 "fuchsia.hardware.temperature.Device",
@@ -953,6 +988,7 @@
             protocol: "fuchsia.cobalt.LoggerFactory",
             from: "#cobalt",
             to: [
+                "#cobalt_system_metrics",
                 "#pkg-resolver",
                 "#sampler",
 
@@ -987,12 +1023,18 @@
                 "fuchsia.sysinfo.SysInfo",
             ],
             from: "parent",
-            to: "#cobalt",
+            to: [
+                "#cobalt",
+                "#cobalt_system_metrics",
+            ],
         },
         {
             storage: "data",
             from: "self",
-            to: "#cobalt",
+            to: [
+                "#cobalt",
+                "#cobalt_system_metrics",
+            ],
         },
         {
             protocol: [
diff --git a/src/sys/lib/fidl-fuchsia-pkg-ext/src/repo.rs b/src/sys/lib/fidl-fuchsia-pkg-ext/src/repo.rs
index b0817c7..fd04272 100644
--- a/src/sys/lib/fidl-fuchsia-pkg-ext/src/repo.rs
+++ b/src/sys/lib/fidl-fuchsia-pkg-ext/src/repo.rs
@@ -5,7 +5,7 @@
 use {
     crate::errors::{MirrorConfigError, RepositoryParseError, RepositoryUrlParseError},
     fidl_fuchsia_pkg as fidl,
-    fuchsia_url::pkg_url::{PkgUrl, RepoUrl},
+    fuchsia_url::pkg_url::RepoUrl,
     http::Uri,
     http_uri_ext::HttpUriExt as _,
     serde::{Deserialize, Serialize},
@@ -272,7 +272,6 @@
     root_threshold: u32,
     root_keys: Vec<RepositoryKey>,
     mirrors: Vec<MirrorConfig>,
-    update_package_url: Option<PkgUrl>,
     #[serde(default = "default_use_local_mirror")]
     use_local_mirror: bool,
     #[serde(default = "default_storage_type")]
@@ -341,10 +340,6 @@
         &self.root_keys
     }
 
-    pub fn update_package_url(&self) -> Option<&PkgUrl> {
-        self.update_package_url.as_ref()
-    }
-
     pub fn use_local_mirror(&self) -> bool {
         self.use_local_mirror
     }
@@ -365,14 +360,6 @@
             .parse()
             .map_err(|err| RepositoryParseError::InvalidRepoUrl(err))?;
 
-        let update_package_url = if let Some(url) = other.update_package_url {
-            let url =
-                url.parse().map_err(|err| RepositoryParseError::InvalidUpdatePackageUrl(err))?;
-            Some(url)
-        } else {
-            None
-        };
-
         let root_version = if let Some(root_version) = other.root_version {
             if root_version < 1 {
                 return Err(RepositoryParseError::InvalidRootVersion(root_version));
@@ -410,7 +397,6 @@
                 .into_iter()
                 .map(MirrorConfig::try_from)
                 .collect::<Result<_, _>>()?,
-            update_package_url: update_package_url,
             use_local_mirror: other.use_local_mirror.unwrap_or(false),
             repo_storage_type: storage_type.into(),
         })
@@ -425,7 +411,6 @@
             root_threshold: Some(config.root_threshold),
             root_keys: Some(config.root_keys.into_iter().map(RepositoryKey::into).collect()),
             mirrors: Some(config.mirrors.into_iter().map(MirrorConfig::into).collect()),
-            update_package_url: config.update_package_url.map(|url| url.to_string()),
             use_local_mirror: Some(config.use_local_mirror),
             storage_type: Some(RepositoryStorageType::into(config.repo_storage_type)),
             ..Self::EMPTY
@@ -454,7 +439,6 @@
                 root_threshold: 1,
                 root_keys: vec![],
                 mirrors: vec![],
-                update_package_url: None,
                 use_local_mirror: false,
                 repo_storage_type: RepositoryStorageType::Ephemeral,
             },
@@ -486,11 +470,6 @@
         self
     }
 
-    pub fn update_package_url(mut self, url: PkgUrl) -> Self {
-        self.config.update_package_url = Some(url);
-        self
-    }
-
     pub fn use_local_mirror(mut self, use_local_mirror: bool) -> Self {
         self.config.use_local_mirror = use_local_mirror;
         self
@@ -977,7 +956,6 @@
                 root_threshold: 1,
                 root_keys: vec![],
                 mirrors: vec![],
-                update_package_url: None,
                 use_local_mirror: false,
                 repo_storage_type: RepositoryStorageType::Ephemeral,
             }
@@ -991,7 +969,6 @@
                 root_threshold: 1,
                 root_keys: vec![],
                 mirrors: vec![],
-                update_package_url: None,
                 use_local_mirror: false,
                 repo_storage_type: RepositoryStorageType::Persistent,
             }
@@ -1010,7 +987,6 @@
                 subscribe: true,
                 blob_mirror_url: "http://example.com/tuf/repo/blobs".parse::<Uri>().unwrap(),
             }],
-            update_package_url: Some("fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()),
             use_local_mirror: true,
             repo_storage_type: RepositoryStorageType::Ephemeral,
         };
@@ -1028,9 +1004,6 @@
                     blob_mirror_url: None,
                     ..fidl::MirrorConfig::EMPTY
                 }]),
-                update_package_url: Some(
-                    "fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()
-                ),
                 use_local_mirror: Some(true),
                 storage_type: Some(fidl::RepositoryStorageType::Ephemeral),
                 ..fidl::RepositoryConfig::EMPTY
@@ -1051,7 +1024,6 @@
                 blob_mirror_url: None,
                 ..fidl::MirrorConfig::EMPTY
             }]),
-            update_package_url: Some("fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()),
             use_local_mirror: None,
             storage_type: None,
             ..fidl::RepositoryConfig::EMPTY
@@ -1068,9 +1040,6 @@
                     subscribe: true,
                     blob_mirror_url: "http://example.com/tuf/repo/blobs".parse::<Uri>().unwrap(),
                 },],
-                update_package_url: Some(
-                    "fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()
-                ),
                 use_local_mirror: false,
                 repo_storage_type: RepositoryStorageType::Ephemeral,
             }
@@ -1090,7 +1059,6 @@
                 blob_mirror_url: None,
                 ..fidl::MirrorConfig::EMPTY
             }]),
-            update_package_url: Some("fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()),
             use_local_mirror: None,
             storage_type: Some(fidl::RepositoryStorageType::Persistent),
             ..fidl::RepositoryConfig::EMPTY
@@ -1107,9 +1075,6 @@
                     subscribe: true,
                     blob_mirror_url: "http://example.com/tuf/repo/blobs".parse::<Uri>().unwrap(),
                 },],
-                update_package_url: Some(
-                    "fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()
-                ),
                 use_local_mirror: false,
                 repo_storage_type: RepositoryStorageType::Persistent,
             }
@@ -1129,7 +1094,6 @@
                 blob_mirror_url: None,
                 ..fidl::MirrorConfig::EMPTY
             }]),
-            update_package_url: Some("fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()),
             use_local_mirror: None,
             storage_type: None,
             ..fidl::RepositoryConfig::EMPTY
@@ -1146,9 +1110,6 @@
                     subscribe: true,
                     blob_mirror_url: "http://example.com/tuf/repo/blobs".parse::<Uri>().unwrap(),
                 },],
-                update_package_url: Some(
-                    "fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()
-                ),
                 use_local_mirror: false,
                 repo_storage_type: RepositoryStorageType::Ephemeral,
             }
@@ -1168,7 +1129,6 @@
                 blob_mirror_url: None,
                 ..fidl::MirrorConfig::EMPTY
             }]),
-            update_package_url: Some("fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()),
             use_local_mirror: Some(true),
             storage_type: None,
             ..fidl::RepositoryConfig::EMPTY
@@ -1185,9 +1145,6 @@
                     subscribe: true,
                     blob_mirror_url: "http://example.com/tuf/repo/blobs".parse::<Uri>().unwrap(),
                 },],
-                update_package_url: Some(
-                    "fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()
-                ),
                 use_local_mirror: true,
                 repo_storage_type: RepositoryStorageType::Ephemeral,
             }
@@ -1202,7 +1159,6 @@
             root_threshold: None,
             root_keys: Some(vec![]),
             mirrors: Some(vec![]),
-            update_package_url: Some("fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()),
             use_local_mirror: None,
             storage_type: None,
             ..fidl::RepositoryConfig::EMPTY
@@ -1225,7 +1181,6 @@
                 subscribe: true,
                 blob_mirror_url: "http://example.com/tuf/repo/blobs".parse::<Uri>().unwrap(),
             }],
-            update_package_url: Some("fuchsia-pkg://fuchsia.com/systemupdate".try_into().unwrap()),
             use_local_mirror: true,
             repo_storage_type: RepositoryStorageType::Ephemeral,
         };
@@ -1240,7 +1195,6 @@
             "repo_url": "fuchsia-pkg://fuchsia.com",
             "root_keys": [],
             "mirrors": [],
-            "update_package_url": null,
         });
         let actual_config: RepositoryConfig = serde_json::from_value(json_value).unwrap();
 
@@ -1252,7 +1206,32 @@
                 root_threshold: 1,
                 root_keys: vec![],
                 mirrors: vec![],
-                update_package_url: None,
+                use_local_mirror: false,
+                repo_storage_type: RepositoryStorageType::Ephemeral,
+            },
+        );
+    }
+
+    // Validate we can still deserialize old configs that have the now-removed
+    // "update_package_url" field.
+    #[test]
+    fn test_repository_config_deserialize_ignores_update_package_url() {
+        let json_value = json!({
+            "repo_url": "fuchsia-pkg://fuchsia.com",
+            "root_keys": [],
+            "mirrors": [],
+            "update_package_url": "ignored-value",
+        });
+        let actual_config: RepositoryConfig = serde_json::from_value(json_value).unwrap();
+
+        assert_eq!(
+            actual_config,
+            RepositoryConfig {
+                repo_url: "fuchsia-pkg://fuchsia.com".try_into().unwrap(),
+                root_version: 1,
+                root_threshold: 1,
+                root_keys: vec![],
+                mirrors: vec![],
                 use_local_mirror: false,
                 repo_storage_type: RepositoryStorageType::Ephemeral,
             },
@@ -1268,7 +1247,6 @@
                 root_threshold: 1,
                 root_keys: vec![],
                 mirrors: vec![],
-                update_package_url: None,
                 use_local_mirror: true,
                 repo_storage_type: RepositoryStorageType::Ephemeral,
             }]),
@@ -1280,7 +1258,6 @@
                     "root_threshold": 1,
                     "root_keys": [],
                     "mirrors": [],
-                    "update_package_url": null,
                     "use_local_mirror": true,
                     "repo_storage_type": "ephemeral",
                 }],
diff --git a/src/sys/lib/legacy_component/BUILD.gn b/src/sys/lib/legacy_component/BUILD.gn
index 8e39156..0bf8efa 100644
--- a/src/sys/lib/legacy_component/BUILD.gn
+++ b/src/sys/lib/legacy_component/BUILD.gn
@@ -16,6 +16,7 @@
     "//src/lib/fuchsia-async",
     "//src/lib/storage/vfs/rust:vfs",
     "//src/lib/zircon/rust:fuchsia-zircon",
+    "//src/sys/lib/runner",
     "//third_party/rust_crates:anyhow",
     "//third_party/rust_crates:futures",
     "//third_party/rust_crates:log",
diff --git a/src/sys/lib/legacy_component/src/legacy_component.rs b/src/sys/lib/legacy_component/src/legacy_component.rs
index a8fe46d..f670c4c 100644
--- a/src/sys/lib/legacy_component/src/legacy_component.rs
+++ b/src/sys/lib/legacy_component/src/legacy_component.rs
@@ -32,6 +32,11 @@
         realm_label: String,
         execution_scope: ExecutionScope,
     ) -> Result<Self, Error> {
+        // We get the args here because |start_info| is partially moved below,
+        // and the rust compiler doesn't allow accessing the program section
+        // by reference after that.
+        let args = runner::get_program_args(&start_info).map(|args| Some(args)).unwrap_or(None);
+
         // We are going to create a new v1 nested environment that holds the component's incoming
         // svc contents along with fuchsia.sys.Loader. This is because fuchsia.sys.Loader must be
         // in the environment for us to be able to launch components within it.
@@ -207,7 +212,7 @@
 
         let mut launch_info = fsysv1::LaunchInfo {
             url: legacy_url.clone(),
-            arguments: None,
+            arguments: args,
             out: None,
             err: None,
             directory_request: Some(outgoing_svc_dir_server_end.into_channel()),
diff --git a/src/sys/lib/legacy_component/tests/BUILD.gn b/src/sys/lib/legacy_component/tests/BUILD.gn
index 47dbe71..7ecb437 100644
--- a/src/sys/lib/legacy_component/tests/BUILD.gn
+++ b/src/sys/lib/legacy_component/tests/BUILD.gn
@@ -12,6 +12,7 @@
   deps = [
     "//examples/components/routing/fidl:echo-rustc",
     "//sdk/fidl/fuchsia.component.runner:fuchsia.component.runner-rustc",
+    "//sdk/fidl/fuchsia.data:fuchsia.data-rustc",
     "//sdk/fidl/fuchsia.io:fuchsia.io-rustc",
     "//sdk/fidl/fuchsia.sys:fuchsia.sys-rustc",
     "//src/lib/fidl/rust/fidl",
diff --git a/src/sys/lib/legacy_component/tests/legacy_component_lib_tests.rs b/src/sys/lib/legacy_component/tests/legacy_component_lib_tests.rs
index cb14a0ad..ca24b61 100644
--- a/src/sys/lib/legacy_component/tests/legacy_component_lib_tests.rs
+++ b/src/sys/lib/legacy_component/tests/legacy_component_lib_tests.rs
@@ -4,8 +4,8 @@
 
 use {
     anyhow::Error, fidl::endpoints::ProtocolMarker, fidl_fidl_examples_routing_echo as fecho,
-    fidl_fuchsia_component_runner as fcrunner, fidl_fuchsia_io as fio, fidl_fuchsia_sys as fsys,
-    fuchsia_component::client::connect_to_protocol, futures::StreamExt,
+    fidl_fuchsia_component_runner as fcrunner, fidl_fuchsia_data as fdata, fidl_fuchsia_io as fio,
+    fidl_fuchsia_sys as fsys, fuchsia_component::client::connect_to_protocol, futures::StreamExt,
     vfs::execution_scope::ExecutionScope,
 };
 
@@ -27,14 +27,14 @@
 }
 
 async fn call_echo(
-    echo_str: &str,
+    echo_str: Option<&str>,
     dir_proxy: &fio::DirectoryProxy,
 ) -> Result<Option<String>, Error> {
     let echo = fuchsia_component::client::connect_to_named_protocol_at_dir_root::<fecho::EchoMarker>(
         &dir_proxy,
         format!("svc/{}", fecho::EchoMarker::DEBUG_NAME).as_str(),
     )?;
-    echo.echo_string(Some(echo_str)).await.map_err(|e| e.into())
+    echo.echo_string(echo_str).await.map_err(|e| e.into())
 }
 
 #[fuchsia::test]
@@ -49,7 +49,7 @@
     let _component =
         launch_echo_component(start_info, "test_legacy_echo", execution_scope).await.unwrap();
     const ECHO_STRING: &str = "Hello, world!";
-    let out = call_echo(ECHO_STRING, &dir_proxy).await.expect("echo failed");
+    let out = call_echo(Some(ECHO_STRING), &dir_proxy).await.expect("echo failed");
     assert_eq!(ECHO_STRING, out.unwrap());
 }
 
@@ -73,7 +73,7 @@
 
     // make sure echo is running
     const ECHO_STRING: &str = "Hello, world!";
-    let out = call_echo(ECHO_STRING, &dir_proxy).await.expect("echo failed");
+    let out = call_echo(Some(ECHO_STRING), &dir_proxy).await.expect("echo failed");
     assert_eq!(ECHO_STRING, out.unwrap());
 
     proxy.stop().unwrap();
@@ -83,7 +83,7 @@
     while let Some(_) = stream.next().await {}
 
     // make sure echo fails
-    call_echo(ECHO_STRING, &dir_proxy).await.expect_err("echo should fail");
+    call_echo(Some(ECHO_STRING), &dir_proxy).await.expect_err("echo should fail");
 }
 
 #[fuchsia::test]
@@ -106,7 +106,7 @@
 
     // make sure echo is running
     const ECHO_STRING: &str = "Hello, world!";
-    let out = call_echo(ECHO_STRING, &dir_proxy).await.expect("echo failed");
+    let out = call_echo(Some(ECHO_STRING), &dir_proxy).await.expect("echo failed");
     assert_eq!(ECHO_STRING, out.unwrap());
 
     proxy.kill().unwrap();
@@ -116,5 +116,29 @@
     while let Some(_) = stream.next().await {}
 
     // make sure echo fails
-    call_echo(ECHO_STRING, &dir_proxy).await.expect_err("echo should fail");
+    call_echo(Some(ECHO_STRING), &dir_proxy).await.expect_err("echo should fail");
+}
+
+#[fuchsia::test]
+async fn test_legacy_echo_with_args() {
+    const TEST_VALUE: &str = "TEST";
+
+    let execution_scope = ExecutionScope::new();
+    let mut start_info = fcrunner::ComponentStartInfo::EMPTY;
+    start_info.ns = Some(vec![]);
+    start_info.program = Some(fdata::Dictionary {
+        entries: Some(vec![fdata::DictionaryEntry {
+            key: "args".to_string(),
+            value: Some(Box::new(fdata::DictionaryValue::StrVec(vec![TEST_VALUE.to_string()]))),
+        }]),
+        ..fdata::Dictionary::EMPTY
+    });
+
+    let (dir_proxy, dir_end) = fidl::endpoints::create_proxy().unwrap();
+    start_info.outgoing_dir = Some(dir_end);
+
+    let _component =
+        launch_echo_component(start_info, "test_legacy_echo_args", execution_scope).await.unwrap();
+    let out = call_echo(None, &dir_proxy).await.expect("echo failed");
+    assert_eq!(TEST_VALUE.to_string(), out.unwrap());
 }
diff --git a/src/sys/lib/moniker/BUILD.gn b/src/sys/lib/moniker/BUILD.gn
index ee9e19e..51be386 100644
--- a/src/sys/lib/moniker/BUILD.gn
+++ b/src/sys/lib/moniker/BUILD.gn
@@ -12,6 +12,7 @@
 
   visibility = [
     "//src/developer/ffx/plugins/component/*",
+    "//src/developer/ffx/plugins/log/*",
     "//src/lib/component_hub/*",
     "//src/security/scrutiny/*",
     "//src/sys/component_manager/*",
diff --git a/src/sys/pkg/bin/omaha-client/BUILD.gn b/src/sys/pkg/bin/omaha-client/BUILD.gn
index a4d351b8..7ce55cd 100644
--- a/src/sys/pkg/bin/omaha-client/BUILD.gn
+++ b/src/sys/pkg/bin/omaha-client/BUILD.gn
@@ -121,7 +121,6 @@
 fuchsia_component_manifest("manifest") {
   component_name = "omaha-client-service"
   manifest = "meta/omaha-client-service.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("component") {
diff --git a/src/sys/pkg/bin/pkg-resolver/src/inspect_util.rs b/src/sys/pkg/bin/pkg-resolver/src/inspect_util.rs
index a4b0a77..5c90cdf 100644
--- a/src/sys/pkg/bin/pkg-resolver/src/inspect_util.rs
+++ b/src/sys/pkg/bin/pkg-resolver/src/inspect_util.rs
@@ -4,7 +4,7 @@
 
 use {
     fidl_fuchsia_pkg_ext::{MirrorConfig, RepositoryConfig},
-    fuchsia_inspect::{self as inspect, NumericProperty, Property, StringReference},
+    fuchsia_inspect::{self as inspect, NumericProperty, StringReference},
     fuchsia_inspect_contrib::inspectable::{Inspectable, Watch},
     std::sync::Arc,
 };
@@ -17,7 +17,6 @@
     _mirror_configs_states: Vec<MirrorConfigInspectState>,
     root_keys_node: inspect::Node,
     _root_keys_properties: Vec<inspect::StringProperty>,
-    update_package_url_property: inspect::StringProperty,
     _node: inspect::Node,
 }
 
@@ -33,8 +32,6 @@
             _root_keys_properties: vec![],
             mirror_configs_node: repo_config_node.create_child("mirrors"),
             _mirror_configs_states: vec![],
-            update_package_url_property: repo_config_node
-                .create_string("update_package_url", format!("{:?}", config.update_package_url())),
             _node: repo_config_node,
         };
         ret.watch(config);
@@ -42,7 +39,6 @@
     }
 
     fn watch(&mut self, config: &Arc<RepositoryConfig>) {
-        self.update_package_url_property.set(&format!("{:?}", config.update_package_url()));
         self._root_keys_properties = config
             .root_keys()
             .iter()
@@ -142,7 +138,6 @@
                         blob_mirror_url: format!("{:?}", mirror_config.blob_mirror_url())
                     }
                   },
-                  update_package_url: format!("{:?}", inspectable.update_package_url()),
                 }
             }
         );
@@ -182,7 +177,6 @@
                         blob_mirror_url: format!("{:?}", mirror_config.blob_mirror_url())
                     }
                   },
-                  update_package_url: format!("{:?}", inspectable.update_package_url()),
                 }
             }
         );
diff --git a/src/sys/pkg/bin/pkg-resolver/src/repository_manager.rs b/src/sys/pkg/bin/pkg-resolver/src/repository_manager.rs
index 24c3787..4d5b14d0 100644
--- a/src/sys/pkg/bin/pkg-resolver/src/repository_manager.rs
+++ b/src/sys/pkg/bin/pkg-resolver/src/repository_manager.rs
@@ -1726,7 +1726,6 @@
                                     blob_mirror_url: format!("{:?}", mirror_config.blob_mirror_url())
                                 }
                             },
-                            update_package_url: format!("{:?}", fuchsia_config.update_package_url()),
                         }
                     },
                     stats: {
@@ -1824,7 +1823,6 @@
                                     blob_mirror_url: format!("{:?}", mirror_config.blob_mirror_url())
                                 }
                             },
-                            update_package_url: format!("{:?}", config.update_package_url()),
                         }
                     },
                 }
diff --git a/src/sys/pkg/tests/pkg-resolver/src/pkg_resolve_inspect.rs b/src/sys/pkg/tests/pkg-resolver/src/pkg_resolve_inspect.rs
index e6ad2d3..202c642 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/pkg_resolve_inspect.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/pkg_resolve_inspect.rs
@@ -87,7 +87,6 @@
                     "example.com": {
                         root_keys: {},
                         mirrors: {},
-                        update_package_url: format!("{:?}", config.update_package_url()),
                     },
                 },
             },
@@ -133,7 +132,6 @@
                             blob_mirror_url: format!("{:?}", config.mirrors()[0].blob_mirror_url())
                           }
                         },
-                        update_package_url: format!("{:?}", config.update_package_url()),
                     }
                 },
                 repos: {
diff --git a/src/sys/pkg/tests/pkgctl/src/lib.rs b/src/sys/pkg/tests/pkgctl/src/lib.rs
index 358dce3..96b5ffa 100644
--- a/src/sys/pkg/tests/pkgctl/src/lib.rs
+++ b/src/sys/pkg/tests/pkgctl/src/lib.rs
@@ -29,7 +29,7 @@
         server::{NestedEnvironment, ServiceFs},
     },
     fuchsia_hyper_test_support::{handler::StaticResponse, TestServer},
-    fuchsia_url::pkg_url::{PkgUrl, RepoUrl},
+    fuchsia_url::pkg_url::RepoUrl,
     fuchsia_zircon::Status,
     futures::prelude::*,
     http::Uri,
@@ -511,9 +511,6 @@
         .add_mirror(
             MirrorConfigBuilder::new("http://example.org".parse::<Uri>().unwrap()).unwrap().build(),
         )
-        .update_package_url(
-            PkgUrl::parse("fuchsia-pkg://update.example.com/update").expect("valid PkgUrl"),
-        )
         .build()
 }
 
diff --git a/src/sys/run_test_suite/BUILD.gn b/src/sys/run_test_suite/BUILD.gn
index bf45cbd..9e926a5 100644
--- a/src/sys/run_test_suite/BUILD.gn
+++ b/src/sys/run_test_suite/BUILD.gn
@@ -14,9 +14,8 @@
   # Only to be used by internal bin and tests.
   visibility = [
     ":*",
-    "ffx/component_test/*",
-    "ffx/test/*",
     "tests/*",
+    "//src/developer/ffx/plugins/test/*",
     "//src/sys/test_runners/rust/tests/*",
   ]
 
diff --git a/src/sys/run_test_suite/OWNERS b/src/sys/run_test_suite/OWNERS
index c6315a3..da8dccb 100644
--- a/src/sys/run_test_suite/OWNERS
+++ b/src/sys/run_test_suite/OWNERS
@@ -1,3 +1,3 @@
 include /src/sys/test_manager/OWNERS
 
-# COMPONENT: TestRunnerFramework
+# COMPONENT: TestArchitecture>ffx
diff --git a/src/sys/run_test_suite/README.md b/src/sys/run_test_suite/README.md
index d3b293b..5bb5a9c 100644
--- a/src/sys/run_test_suite/README.md
+++ b/src/sys/run_test_suite/README.md
@@ -2,13 +2,13 @@
 
 Reviewed on: 2022-01-05
 
-This folder contains the run_test_suite *library*, run-test-suite *binary*, and
-`ffx test` plugin.
+This folder contains the run_test_suite *library* and run-test-suite *binary*.
 
 * The run-test-suite *binary* is a command line tool run on a Fuchsia device that runs
 tests which implement `fuchsia.test.Suite`.
 * `ffx test` is a plugin for [ffx][ffx] that runs tests which implement
-`fuchsia.test.Suite`.
+`fuchsia.test.Suite`. It is located in the [ffx plugins][ffx-plugins] folder. See the
+[ffx plugin development guide][ffx-dev-guide] for details on how to develop ffx test.
 * The run_test_suite *library* contains common code used for both the run-test-suite
 *library* and `ffx test`.
 
@@ -21,10 +21,6 @@
 can be added to builds by including `--with //src/sys/run_test_suite` to the
 `fx set` invocation.
 
-`ffx test` should also be included in a test build of Fuchsia, but can be added
-explicitly by including `--with //src/developer/ffx` to the `fx set`
-invocation.
-
 ## Running
 
 ### run-test-suite
@@ -33,14 +29,6 @@
 $ fx shell run run-test-suite <v2_test_component_url>
 ```
 
-### ffx test
-
-```
-$ ffx test run <v2_test_component_url>
-```
-
-See [ffx documentation][ffx] for more details on how to run `ffx`.
-
 ## Testing
 
 Tests for the run-test-suite *library* and *binary* can be added to builds by
@@ -59,13 +47,6 @@
 $ fx test run_test_suite_integration_tests
 ```
 
-Unit tests for `ffx test` are included via the `//src/developer/ffx` target,
-and can be run with
-
-```
-$ fx test ffx_test_lib_test
-```
-
 ## Source layout
 
 The run-test-suite *library* is located in the `src` directory. The top entry
@@ -82,7 +63,7 @@
 
 The entry point for the run-test-suite *binary* is located in `src/main.rs`.
 
-The source for the `ffx test` plugin is located in `ffx/test`.
-
 [ffx]: /docs/development/tools/ffx/overview.md
+[ffx-dev-guide]: /docs/development/tools/development/plugins.md
+[ffx-plugins]: /src/developer/ffx/plugins/test
 [structured-output]: /src/sys/run_test_suite/directory/README.md
diff --git a/src/sys/run_test_suite/directory/src/testing.rs b/src/sys/run_test_suite/directory/src/testing.rs
index 0a913fd..c259ba2 100644
--- a/src/sys/run_test_suite/directory/src/testing.rs
+++ b/src/sys/run_test_suite/directory/src/testing.rs
@@ -221,7 +221,7 @@
     expected_artifacts: &ArtifactMetadataToAssertionMap,
     entity_context: EntityContext<'_>,
 ) {
-    // TODO(satsukiu): add options so that the test author can explicitly declare whether
+    // TODO(fxbug.dev/100463): add options so that the test author can explicitly declare whether
     // artifacts should be an exact match, should contain (and may contain more) artifacts,
     // or any number of artifacts is accesptable.
     // This skips artifact assertion for the typical case where verifying artifacts isn't
diff --git a/src/sys/sysmgr/BUILD.gn b/src/sys/sysmgr/BUILD.gn
index bf10d04..790c710 100644
--- a/src/sys/sysmgr/BUILD.gn
+++ b/src/sys/sysmgr/BUILD.gn
@@ -83,10 +83,6 @@
   }
 }
 
-cfg("cobalt_system_metrics_config") {
-  name = "cobalt_system_metrics.config"
-}
-
 cfg("services_config") {
   name = "services.config"
 }
diff --git a/src/sys/sysmgr/config/cobalt_system_metrics.config b/src/sys/sysmgr/config/cobalt_system_metrics.config
deleted file mode 100644
index 64ea509..0000000
--- a/src/sys/sysmgr/config/cobalt_system_metrics.config
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "apps": [
-        "fuchsia-pkg://fuchsia.com/cobalt_system_metrics#meta/cobalt_system_metrics.cmx"
-    ]
-}
diff --git a/src/sys/test_manager/debug_data/src/data_processor.rs b/src/sys/test_manager/debug_data/src/data_processor.rs
index 3f85441..dc9e0d9 100644
--- a/src/sys/test_manager/debug_data/src/data_processor.rs
+++ b/src/sys/test_manager/debug_data/src/data_processor.rs
@@ -11,7 +11,7 @@
 
 /// Max VMOs to send at once. This is limited primarily by the max handles in a channel
 /// write, although we may encounter the max byte limit too.
-/// TODO(satsukiu): Use tape measure instead
+/// TODO(fxbug.dev/100462): Use tape measure instead
 const VMO_CHUNK_SIZE: usize = 32;
 
 /// Processes a stream of |DebugData| VMOs and places the results in |dir_path|.
diff --git a/src/sys/test_manager/src/test_suite.rs b/src/sys/test_manager/src/test_suite.rs
index 38c61da..e58b1a1 100644
--- a/src/sys/test_manager/src/test_suite.rs
+++ b/src/sys/test_manager/src/test_suite.rs
@@ -216,7 +216,7 @@
 }
 
 // max events to send so that we don't cross fidl limits.
-// TODO(anmittal): Use tape measure to calculate limit.
+// TODO(fxbug.dev/100462): Use tape measure to calculate limit.
 const EVENTS_THRESHOLD: usize = 50;
 
 impl Suite {
diff --git a/src/ui/bin/brightness_manager/BUILD.gn b/src/ui/bin/brightness_manager/BUILD.gn
index cb5f8f2..6f45ade 100644
--- a/src/ui/bin/brightness_manager/BUILD.gn
+++ b/src/ui/bin/brightness_manager/BUILD.gn
@@ -172,7 +172,6 @@
 fuchsia_component_manifest("brightness_manager_manifest") {
   component_name = "brightness_manager"
   manifest = "meta/brightness_manager.cml"
-  restricted_features = [ "structured_config" ]
 }
 
 fuchsia_component("brightness_manager_component") {
diff --git a/src/ui/bin/hardware_display_controller_provider/fake/tests/BUILD.gn b/src/ui/bin/hardware_display_controller_provider/fake/tests/BUILD.gn
index 93f4bb4..1519269 100644
--- a/src/ui/bin/hardware_display_controller_provider/fake/tests/BUILD.gn
+++ b/src/ui/bin/hardware_display_controller_provider/fake/tests/BUILD.gn
@@ -31,6 +31,6 @@
 }
 
 fuchsia_unittest_package("fake_hdcp_tests") {
-  manifest = "meta/fake_hdcp_unittests.cmx"
+  manifest = "meta/fake_hdcp_unittests.cml"
   deps = [ ":unittests" ]
 }
diff --git a/src/ui/bin/hardware_display_controller_provider/fake/tests/meta/fake_hdcp_unittests.cml b/src/ui/bin/hardware_display_controller_provider/fake/tests/meta/fake_hdcp_unittests.cml
new file mode 100644
index 0000000..feaeff0
--- /dev/null
+++ b/src/ui/bin/hardware_display_controller_provider/fake/tests/meta/fake_hdcp_unittests.cml
@@ -0,0 +1,12 @@
+{
+    include: [
+        "//src/lib/vulkan/vulkan-test.shard.cml",
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "inspect/client.shard.cml",
+        "syslog/client.shard.cml",
+        "vulkan/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/fake_hdcp_unittests",
+    },
+}
diff --git a/src/ui/bin/hardware_display_controller_provider/fake/tests/meta/fake_hdcp_unittests.cmx b/src/ui/bin/hardware_display_controller_provider/fake/tests/meta/fake_hdcp_unittests.cmx
deleted file mode 100644
index 1655ee0..0000000
--- a/src/ui/bin/hardware_display_controller_provider/fake/tests/meta/fake_hdcp_unittests.cmx
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-    "facets": {
-        "fuchsia.test": {
-            "injected-services": {
-                "fuchsia.tracing.provider.Registry": "fuchsia-pkg://fuchsia.com/trace_manager#meta/trace_manager.cmx"
-            },
-            "system-services": [
-                "fuchsia.sysmem.Allocator"
-            ]
-        }
-    },
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "bin/fake_hdcp_unittests"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.sysmem.Allocator",
-            "fuchsia.tracing.provider.Registry"
-        ]
-    }
-}
diff --git a/src/ui/bin/root_presenter/tests/BUILD.gn b/src/ui/bin/root_presenter/tests/BUILD.gn
index ea97e93..034bc83 100644
--- a/src/ui/bin/root_presenter/tests/BUILD.gn
+++ b/src/ui/bin/root_presenter/tests/BUILD.gn
@@ -13,15 +13,18 @@
   ]
 }
 
-fuchsia_component("focus_dispatcher_unittests") {
-  testonly = true
+fuchsia_unittest_component("focus_dispatcher_unittests") {
   deps = [ ":focus_dispatcher_unittests_bin" ]
-  manifest = "meta/focus_dispatcher_unittests.cmx"
 }
 
 fuchsia_unittest_component("root_presenter_unittests") {
-  deps = [ ":root_presenter_unittests_bin" ]
-  manifest = "meta/root_presenter_unittests.cmx"
+  deps = [
+    ":root_presenter_unittests_bin",
+    "//src/cobalt/bin/testing/mock_cobalt:component_v2",
+    "//src/ui/bin/hardware_display_controller_provider:fake-hardware-display-controller-provider-cmv2-component",
+    "//src/ui/scenic:component_v2",
+  ]
+  manifest = "meta/root_presenter_unittests.cml"
 }
 
 fuchsia_test_package("root_presenter_tests") {
diff --git a/src/ui/bin/root_presenter/tests/README b/src/ui/bin/root_presenter/tests/README
index d131dbc..5417c69 100644
--- a/src/ui/bin/root_presenter/tests/README
+++ b/src/ui/bin/root_presenter/tests/README
@@ -2,5 +2,5 @@
 //src/ui/bin/root_presenter:tests
 
 After building, presenter tests can be run as follows:
-fx test root_presenter_apptests
-fx test root_presenter_unittests
+fx test run "fuchsia-pkg://fuchsia.com/root_presenter_tests#meta/focus_dispatcher_unittests.cm"
+fx test run "fuchsia-pkg://fuchsia.com/root_presenter_tests#meta/root_presenter_unittests.cm"
diff --git a/src/ui/bin/root_presenter/tests/meta/focus_dispatcher_unittests.cmx b/src/ui/bin/root_presenter/tests/meta/focus_dispatcher_unittests.cmx
deleted file mode 100644
index aae1166..0000000
--- a/src/ui/bin/root_presenter/tests/meta/focus_dispatcher_unittests.cmx
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "bin/focus_dispatcher_unittests"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.recovery.FactoryReset",
-            "fuchsia.sys.Environment",
-            "fuchsia.sys.Loader"
-        ]
-    }
-}
diff --git a/src/ui/bin/root_presenter/tests/meta/root_presenter_apptests.cmx b/src/ui/bin/root_presenter/tests/meta/root_presenter_apptests.cmx
deleted file mode 100644
index 5dde992..0000000
--- a/src/ui/bin/root_presenter/tests/meta/root_presenter_apptests.cmx
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "bin/root_presenter_apptests"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.recovery.FactoryReset",
-            "fuchsia.sys.Environment",
-            "fuchsia.sys.Loader"
-        ]
-    }
-}
diff --git a/src/ui/bin/root_presenter/tests/meta/root_presenter_unittests.cml b/src/ui/bin/root_presenter/tests/meta/root_presenter_unittests.cml
new file mode 100644
index 0000000..dbdb190
--- /dev/null
+++ b/src/ui/bin/root_presenter/tests/meta/root_presenter_unittests.cml
@@ -0,0 +1,104 @@
+// 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.
+// TDOO(fxb.dev/98336): Replace with use of scenic_only shard
+{
+    include: [
+        "//src/lib/vulkan/vulkan-test.shard.cml",
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "inspect/client.shard.cml",
+        "syslog/client.shard.cml",
+        "vulkan/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/root_presenter_unittests",
+    },
+    children: [
+        {
+            name: "fake_display_provider",
+            url: "#meta/hdcp.cm",
+        },
+        {
+            name: "mock_cobalt",
+            url: "#meta/mock_cobalt.cm",
+        },
+        {
+            name: "scenic",
+            url: "#meta/scenic.cm",
+        },
+    ],
+    use: [
+        {
+            // Isolated persistent storage, used by FactoryResetManager tests.
+            storage: "data",
+            path: "/data",
+        },
+        {
+            // Scenic protocols used from the parent - these are not offered to
+            // RealmBuilder by default, and they are not required for correct
+            // Scenic operation.  If a test wishes to provide these protocols,
+            // it can fake them and explicitly route the fake(s) to the Scenic
+            // realm.
+            //
+            // fuchsia.scheduler.ProfileProvider: Required to change the scheduling
+            // profile used by scenic's main thread (e.g. deadline scheduling).
+            //
+            // fuchsia.stash.Store: Required to inject stash configuration for
+            // flags like `i_can_haz_display` and `i_can_haz_flatland`.
+            protocol: [
+                "fuchsia.scheduler.ProfileProvider",
+                "fuchsia.stash.Store",
+            ],
+        },
+        {
+            protocol: [
+                "fuchsia.ui.focus.FocusChainListenerRegistry",
+                "fuchsia.ui.input.InputDeviceRegistry",
+                "fuchsia.ui.keyboard.focus.Controller",
+                "fuchsia.ui.pointerinjector.Registry",
+                "fuchsia.ui.scenic.Scenic",
+            ],
+            from: "#scenic",
+        },
+    ],
+    offer: [
+        {
+            protocol: "fuchsia.logger.LogSink",
+            from: "parent",
+            to: [
+                "#fake_display_provider",
+                "#mock_cobalt",
+                "#scenic",
+            ],
+        },
+        {
+            protocol: [
+                "fuchsia.scheduler.ProfileProvider",
+                "fuchsia.stash.Store",
+                "fuchsia.sysmem.Allocator",
+                "fuchsia.tracing.provider.Registry",
+                "fuchsia.vulkan.loader.Loader",
+            ],
+            from: "parent",
+            to: [ "#scenic" ],
+        },
+        {
+            protocol: [
+                "fuchsia.sysmem.Allocator",
+                "fuchsia.tracing.provider.Registry",
+            ],
+            from: "parent",
+            to: [ "#fake_display_provider" ],
+        },
+        {
+            protocol: [ "fuchsia.hardware.display.Provider" ],
+            from: "#fake_display_provider",
+            to: [ "#scenic" ],
+        },
+        {
+            protocol: [ "fuchsia.cobalt.LoggerFactory" ],
+            from: "#mock_cobalt",
+            to: [ "#scenic" ],
+        },
+    ],
+}
diff --git a/src/ui/bin/root_presenter/tests/meta/root_presenter_unittests.cmx b/src/ui/bin/root_presenter/tests/meta/root_presenter_unittests.cmx
deleted file mode 100644
index ef9f4d2..0000000
--- a/src/ui/bin/root_presenter/tests/meta/root_presenter_unittests.cmx
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-    "facets": {
-        "fuchsia.test": {
-            "injected-services": {
-                "fuchsia.hardware.display.Provider": "fuchsia-pkg://fuchsia.com/fake-hardware-display-controller-provider#meta/hdcp.cmx",
-                "fuchsia.tracing.provider.Registry": "fuchsia-pkg://fuchsia.com/trace_manager#meta/trace_manager.cmx",
-                "fuchsia.ui.focus.FocusChainListenerRegistry": "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx",
-                "fuchsia.ui.keyboard.focus.Controller": "fuchsia-pkg://fuchsia.com/text_manager#meta/text_manager.cmx",
-                "fuchsia.ui.pointerinjector.Registry": "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx",
-                "fuchsia.ui.scenic.Scenic": "fuchsia-pkg://fuchsia.com/scenic#meta/scenic.cmx"
-            }
-        }
-    },
-    "include": [
-        "//src/lib/vulkan/test-application.shard.cmx",
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "bin/root_presenter_unittests"
-    },
-    "sandbox": {
-        "dev": [
-            "class/input"
-        ],
-        "features": [
-            "config-data",
-            "isolated-persistent-storage"
-        ],
-        "services": [
-            "fuchsia.sys.Environment",
-            "fuchsia.sys.Launcher",
-            "fuchsia.ui.focus.FocusChainListenerRegistry",
-            "fuchsia.ui.input.InputDeviceRegistry",
-            "fuchsia.ui.keyboard.focus.Controller",
-            "fuchsia.ui.pointerinjector.Registry",
-            "fuchsia.ui.scenic.Scenic"
-        ]
-    }
-}
diff --git a/src/ui/input/drivers/pc-ps2/BUILD.gn b/src/ui/input/drivers/pc-ps2/BUILD.gn
index 2b512b8..5e8cefa 100644
--- a/src/ui/input/drivers/pc-ps2/BUILD.gn
+++ b/src/ui/input/drivers/pc-ps2/BUILD.gn
@@ -27,13 +27,17 @@
 
 common_deps = [
   ":i8042_bind_header",
-  "//sdk/banjo/fuchsia.hardware.hidbus:fuchsia.hardware.hidbus_banjo_cpp",
   "//sdk/fidl/fuchsia.hardware.input:fuchsia.hardware.input_llcpp",
+  "//sdk/fidl/fuchsia.input.report:fuchsia.input.report_llcpp",
   "//src/devices/lib/driver",
   "//src/lib/ddk",
   "//src/lib/ddktl",
+  "//zircon/system/ulib/async-loop:async-loop-cpp",
+  "//zircon/system/ulib/async-loop:async-loop-default",
+  "//zircon/system/ulib/fbl",
   "//zircon/system/ulib/hid",
   "//zircon/system/ulib/hwreg",
+  "//zircon/system/ulib/zircon-internal",
 ]
 
 fuchsia_driver("pc-ps2-driver") {
@@ -50,6 +54,10 @@
 
   # TODO(fxbug.dev/58162): delete the below and fix compiler warnings
   configs += [ "//build/config:Wno-conversion" ]
+
+  # TODO(fxbug.dev/94768): This target uses mutable tables which are deprecated,
+  # rather than builders.
+  configs += [ "//build/cpp:fidl-wire-deprecated-mutable-tables" ]
 }
 
 fuchsia_driver_component("pc-ps2") {
@@ -77,6 +85,10 @@
 
   # TODO(fxbug.dev/99745): remove this
   defines = [ "PS2_TEST" ]
+
+  # TODO(fxbug.dev/94768): This target uses mutable tables which are deprecated,
+  # rather than builders.
+  configs += [ "//build/cpp:fidl-wire-deprecated-mutable-tables" ]
 }
 
 fuchsia_unittest_package("pc-ps2-tests") {
diff --git a/src/ui/input/drivers/pc-ps2/descriptors.h b/src/ui/input/drivers/pc-ps2/descriptors.h
deleted file mode 100644
index d7d12e0..0000000
--- a/src/ui/input/drivers/pc-ps2/descriptors.h
+++ /dev/null
@@ -1,80 +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_UI_INPUT_DRIVERS_PC_PS2_DESCRIPTORS_H_
-#define SRC_UI_INPUT_DRIVERS_PC_PS2_DESCRIPTORS_H_
-
-#include <stdint.h>
-
-namespace i8042 {
-inline constexpr uint8_t kKeyboardHidDescriptor[] = {
-    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
-    0x09, 0x06,  // Usage (Keyboard)
-    0xA1, 0x01,  // Collection (Application)
-    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
-    0x19, 0xE0,  //   Usage Minimum (0xE0)
-    0x29, 0xE7,  //   Usage Maximum (0xE7)
-    0x15, 0x00,  //   Logical Minimum (0)
-    0x25, 0x01,  //   Logical Maximum (1)
-    0x75, 0x01,  //   Report Size (1)
-    0x95, 0x08,  //   Report Count (8)
-    0x81, 0x02,  //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
-    0x95, 0x01,  //   Report Count (1)
-    0x75, 0x08,  //   Report Size (8)
-    0x81, 0x01,  //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
-    0x95, 0x05,  //   Report Count (5)
-    0x75, 0x01,  //   Report Size (1)
-    0x05, 0x08,  //   Usage Page (LEDs)
-    0x19, 0x01,  //   Usage Minimum (Num Lock)
-    0x29, 0x05,  //   Usage Maximum (Kana)
-    0x91, 0x02,  //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,
-                 // Non-volatile)
-    0x95, 0x01,  //   Report Count (1)
-    0x75, 0x03,  //   Report Size (3)
-    0x91, 0x01,  //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null
-                 //   Position,Non-volatile)
-    0x95, 0x06,  //   Report Count (6)
-    0x75, 0x08,  //   Report Size (8)
-    0x15, 0x00,  //   Logical Minimum (0)
-    0x25, 0x65,  //   Logical Maximum (101)
-    0x05, 0x07,  //   Usage Page (Kbrd/Keypad)
-    0x19, 0x00,  //   Usage Minimum (0x00)
-    0x29, 0x65,  //   Usage Maximum (0x65)
-    0x81, 0x00,  //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
-    0xC0,        // End Collection
-};
-
-inline constexpr uint8_t kMouseHidDescriptor[] = {
-    0x05, 0x01,  // Usage Page (Generic Desktop Ctrls)
-    0x09, 0x02,  // Usage (Mouse)
-    0xA1, 0x01,  // Collection (Application)
-    0x09, 0x01,  //   Usage (Pointer)
-    0xA1, 0x00,  //   Collection (Physical)
-    0x05, 0x09,  //     Usage Page (Button)
-    0x19, 0x01,  //     Usage Minimum (0x01)
-    0x29, 0x03,  //     Usage Maximum (0x03)
-    0x15, 0x00,  //     Logical Minimum (0)
-    0x25, 0x01,  //     Logical Maximum (1)
-    0x95, 0x03,  //     Report Count (3)
-    0x75, 0x01,  //     Report Size (1)
-    0x81, 0x02,  //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
-    0x95, 0x01,  //     Report Count (1)
-    0x75, 0x05,  //     Report Size (5)
-    0x81, 0x01,  //     Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
-    0x05, 0x01,  //     Usage Page (Generic Desktop Ctrls)
-    0x09, 0x30,  //     Usage (X)
-    0x09, 0x31,  //     Usage (Y)
-    0x15, 0x81,  //     Logical Minimum (129)
-    0x25, 0x7F,  //     Logical Maximum (127)
-    0x75, 0x08,  //     Report Size (8)
-    0x95, 0x02,  //     Report Count (2)
-    0x81, 0x06,  //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
-    0xC0,        //   End Collection
-    0xC0,        // End Collection
-};
-
-}  // namespace i8042
-
-#endif  // SRC_UI_INPUT_DRIVERS_PC_PS2_DESCRIPTORS_H_
diff --git a/src/ui/input/drivers/pc-ps2/device.cc b/src/ui/input/drivers/pc-ps2/device.cc
index adfa652..19a22eb 100644
--- a/src/ui/input/drivers/pc-ps2/device.cc
+++ b/src/ui/input/drivers/pc-ps2/device.cc
@@ -6,7 +6,6 @@
 
 #include <fidl/fuchsia.hardware.input/cpp/wire.h>
 #include <fidl/fuchsia.hardware.input/cpp/wire_types.h>
-#include <fuchsia/hardware/hidbus/cpp/banjo.h>
 #include <lib/ddk/driver.h>
 #include <zircon/syscalls.h>
 
@@ -17,7 +16,6 @@
 
 #include "src/ui/input/drivers/pc-ps2/commands.h"
 #include "src/ui/input/drivers/pc-ps2/controller.h"
-#include "src/ui/input/drivers/pc-ps2/descriptors.h"
 #include "src/ui/input/drivers/pc-ps2/keymap.h"
 
 #ifdef PS2_TEST
@@ -33,6 +31,7 @@
 constexpr uint16_t kIrqPort1 = 0x1;
 constexpr uint16_t kIrqPort2 = 0xc;
 
+constexpr uint8_t kMouseButtonCount = 3;
 constexpr uint8_t kMouseAlwaysOne = (1 << 3);
 constexpr uint8_t kMouseButtonMask = 0x7;
 
@@ -60,13 +59,49 @@
     },
 };
 
-constexpr hid_boot_kbd_report_t kRolloverReport = {.modifier = 1, .usage = {1, 1, 1, 1, 1, 1}};
-bool IsKeyboardModifier(uint8_t usage) {
-  return (usage >= HID_USAGE_KEY_LEFT_CTRL && usage <= HID_USAGE_KEY_RIGHT_GUI);
-}
-
 }  // namespace
 
+void PS2InputReport::ToFidlInputReport(fuchsia_input_report::wire::InputReport& input_report,
+                                       fidl::AnyArena& allocator) {
+  if (type == fuchsia_hardware_input::BootProtocol::kKbd) {
+    ZX_ASSERT(std::holds_alternative<PS2KbdInputReport>(report));
+    auto kbd = std::get<PS2KbdInputReport>(report);
+    fidl::VectorView<fuchsia_input::wire::Key> keys3(allocator, kbd.num_pressed_keys_3);
+    size_t idx = 0;
+    for (const auto& key : kbd.pressed_keys_3) {
+      keys3[idx++] = key;
+    }
+
+    auto kbd_input_rpt = fuchsia_input_report::wire::KeyboardInputReport(allocator);
+    kbd_input_rpt.set_pressed_keys3(allocator, keys3);
+
+    input_report.set_keyboard(allocator, kbd_input_rpt);
+  } else if (type == fuchsia_hardware_input::BootProtocol::kMouse) {
+    ZX_ASSERT(std::holds_alternative<PS2MouseInputReport>(report));
+    auto mouse = std::get<PS2MouseInputReport>(report);
+    std::vector<uint8_t> pressed_buttons;
+    for (uint8_t i = 0; i < kMouseButtonCount; i++) {
+      if (mouse.buttons & (1 << i)) {
+        pressed_buttons.push_back(i + 1);
+      }
+    }
+    fidl::VectorView<uint8_t> buttons(allocator, pressed_buttons.size());
+    size_t idx = 0;
+    for (const auto& button : pressed_buttons) {
+      buttons[idx++] = button;
+    }
+
+    auto mouse_input_rpt = fuchsia_input_report::wire::MouseInputReport(allocator);
+    mouse_input_rpt.set_pressed_buttons(allocator, buttons);
+    mouse_input_rpt.set_movement_x(allocator, mouse.rel_x);
+    mouse_input_rpt.set_movement_y(allocator, mouse.rel_y);
+
+    input_report.set_mouse(allocator, mouse_input_rpt);
+  }
+
+  input_report.set_event_time(allocator, event_time.get());
+}
+
 zx_status_t I8042Device::Bind(Controller* parent, Port port) {
   auto dev = std::make_unique<I8042Device>(parent, port);
   zx_status_t status = dev->Bind();
@@ -86,6 +121,12 @@
   }
 
   protocol_ = *identity;
+  if (protocol_ == fuchsia_hardware_input::BootProtocol::kKbd) {
+    report_.report = PS2KbdInputReport{};
+  } else if (protocol_ == fuchsia_hardware_input::BootProtocol::kMouse) {
+    report_.report = PS2MouseInputReport{};
+  }
+
 #ifndef PS2_TEST
   // Map interrupt. We should get this from ACPI eventually.
   // Please do not use get_root_resource() in new code. See fxbug.dev/31358.
@@ -99,6 +140,11 @@
   zx_status_t status;
 #endif
 
+  status = loop_.StartThread("i8042-reader-thread");
+  if (status != ZX_OK) {
+    return status;
+  }
+
   status = DdkAdd(ddk::DeviceAddArgs(kPortInfo[port_].devname));
   if (status != ZX_OK) {
     return status;
@@ -181,61 +227,111 @@
   return zx::ok(proto);
 }
 
-zx_status_t I8042Device::HidbusQuery(uint32_t options, hid_info_t* out_info) {
-  out_info->dev_num = static_cast<uint8_t>(protocol_);
-  out_info->device_class = static_cast<hid_device_class_t>(protocol_);
-  out_info->boot_device = true;
-  return ZX_OK;
-}
-
-zx_status_t I8042Device::HidbusStart(const hidbus_ifc_protocol_t* ifc) {
+void I8042Device::GetInputReportsReader(GetInputReportsReaderRequestView request,
+                                        GetInputReportsReaderCompleter::Sync& completer) {
   std::scoped_lock lock(hid_lock_);
-  if (ifc_.is_valid()) {
-    return ZX_ERR_ALREADY_BOUND;
+  zx_status_t status =
+      input_report_readers_.CreateReader(loop_.dispatcher(), std::move(request->reader));
+  if (status == ZX_OK) {
+#ifdef PS2_TEST
+    sync_completion_signal(&next_reader_wait_);
+#endif
   }
-  ifc_ = ddk::HidbusIfcProtocolClient(ifc);
-  return ZX_OK;
 }
 
-void I8042Device::HidbusStop() {
-  std::scoped_lock lock(hid_lock_);
-  ifc_.clear();
-}
+void I8042Device::GetDescriptor(GetDescriptorRequestView request,
+                                GetDescriptorCompleter::Sync& completer) {
+  fidl::Arena allocator;
+  auto descriptor = fuchsia_input_report::wire::DeviceDescriptor(allocator);
 
-zx_status_t I8042Device::HidbusGetDescriptor(hid_description_type_t desc_type,
-                                             uint8_t* out_data_buffer, size_t data_size,
-                                             size_t* out_data_actual) {
-  if (out_data_buffer == NULL || out_data_actual == NULL) {
-    return ZX_ERR_INVALID_ARGS;
-  }
+  fuchsia_input_report::wire::DeviceInfo device_info;
+  device_info.vendor_id = static_cast<uint32_t>(fuchsia_input_report::wire::VendorId::kGoogle);
 
-  if (desc_type != HID_DESCRIPTION_TYPE_REPORT) {
-    return ZX_ERR_NOT_FOUND;
-  }
+  if (protocol_ == fuchsia_hardware_input::BootProtocol::kKbd) {
+    device_info.product_id =
+        static_cast<uint32_t>(fuchsia_input_report::wire::VendorGoogleProductId::kPcPs2Keyboard);
+    std::vector<fuchsia_input::wire::Key> keys3;
+    // Add usual HID keys
+    for (const auto& key : kSet1UsageMap) {
+      if (key) {
+        keys3.push_back(key.value());
+      }
 
-  const uint8_t* buf;
-  size_t buflen = 0;
-  if (protocol_ == finput::BootProtocol::kKbd) {
-    buf = kKeyboardHidDescriptor;
-    buflen = sizeof(kKeyboardHidDescriptor);
-  } else if (protocol_ == finput::BootProtocol::kMouse) {
-    buf = kMouseHidDescriptor;
-    buflen = sizeof(kMouseHidDescriptor);
-  } else {
-    return ZX_ERR_NOT_SUPPORTED;
-  }
+      if (keys3.size() >= fuchsia_input_report::wire::kKeyboardMaxNumKeys) {
+        zxlogf(ERROR, "Too many keys!");
+        completer.Reply({});
+        return;
+      }
+    }
+    for (const auto& key : kSet1ExtendedUsageMap) {
+      if (key) {
+        keys3.push_back(key.value());
+      }
 
-  *out_data_actual = buflen;
-  if (data_size < buflen) {
-    return ZX_ERR_BUFFER_TOO_SMALL;
+      if (keys3.size() >= fuchsia_input_report::wire::kKeyboardMaxNumKeys) {
+        zxlogf(ERROR, "Too many keys!");
+        completer.Reply({});
+        return;
+      }
+    }
+
+    fidl::VectorView<fuchsia_input::wire::Key> fidl_keys3(allocator, keys3.size());
+    size_t idx = 0;
+    for (const auto& key : keys3) {
+      fidl_keys3[idx++] = key;
+    }
+
+    auto kbd_in_desc = fuchsia_input_report::wire::KeyboardInputDescriptor(allocator);
+    kbd_in_desc.set_keys3(allocator, fidl_keys3);
+
+    fidl::VectorView<fuchsia_input_report::wire::LedType> leds(allocator, 5);
+    leds[0] = fuchsia_input_report::wire::LedType::kNumLock;
+    leds[1] = fuchsia_input_report::wire::LedType::kCapsLock;
+    leds[2] = fuchsia_input_report::wire::LedType::kScrollLock;
+    leds[3] = fuchsia_input_report::wire::LedType::kCompose;
+    leds[4] = fuchsia_input_report::wire::LedType::kKana;
+    auto kbd_out_desc = fuchsia_input_report::wire::KeyboardOutputDescriptor(allocator);
+    kbd_out_desc.set_leds(allocator, leds);
+
+    auto kbd_descriptor = fuchsia_input_report::wire::KeyboardDescriptor(allocator);
+    kbd_descriptor.set_input(allocator, kbd_in_desc);
+    kbd_descriptor.set_output(allocator, kbd_out_desc);
+    descriptor.set_keyboard(allocator, kbd_descriptor);
+  } else if (protocol_ == fuchsia_hardware_input::BootProtocol::kMouse) {
+    device_info.product_id =
+        static_cast<uint32_t>(fuchsia_input_report::wire::VendorGoogleProductId::kPcPs2Mouse);
+    fidl::VectorView<uint8_t> buttons(allocator, kMouseButtonCount);
+    buttons[0] = 0x01;
+    buttons[1] = 0x02;
+    buttons[2] = 0x03;
+
+    constexpr fuchsia_input_report::wire::Axis movement_x{
+        .range = {.min = -127, .max = 127},
+        .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0},
+    };
+    constexpr fuchsia_input_report::wire::Axis movement_y{
+        .range = {.min = -127, .max = 127},
+        .unit = {.type = fuchsia_input_report::wire::UnitType::kNone, .exponent = 0},
+    };
+
+    auto mouse_in_desc = fuchsia_input_report::wire::MouseInputDescriptor(allocator);
+    mouse_in_desc.set_buttons(allocator, buttons);
+    mouse_in_desc.set_movement_x(allocator, movement_x);
+    mouse_in_desc.set_movement_y(allocator, movement_y);
+
+    auto mouse_descriptor = fuchsia_input_report::wire::MouseDescriptor(allocator);
+    mouse_descriptor.set_input(allocator, mouse_in_desc);
+    descriptor.set_mouse(allocator, mouse_descriptor);
   }
-  memcpy(out_data_buffer, buf, buflen);
-  return ZX_OK;
+  descriptor.set_device_info(allocator, device_info);
+
+  completer.Reply(descriptor);
 }
 
 void I8042Device::IrqThread() {
   while (true) {
-    zx_status_t status = irq_.wait(nullptr);
+    zx::time timestamp;
+    zx_status_t status = irq_.wait(&timestamp);
     if (status != ZX_OK) {
       break;
     }
@@ -249,9 +345,9 @@
         retry = true;
         uint8_t data = controller_->ReadData();
         if (protocol_ == finput::BootProtocol::kKbd) {
-          ProcessScancode(data);
+          ProcessScancode(timestamp, data);
         } else if (protocol_ == finput::BootProtocol::kMouse) {
-          ProcessMouse(data);
+          ProcessMouse(timestamp, data);
         }
       }
     } while (retry);
@@ -263,99 +359,70 @@
   unbind_->Reply();
 }
 
-void I8042Device::ProcessScancode(uint8_t code) {
+void I8042Device::ProcessScancode(zx::time timestamp, uint8_t code) {
+  report_.event_time = timestamp;
+  report_.type = fuchsia_hardware_input::wire::BootProtocol::kKbd;
+
   bool multi = (last_code_ == kExtendedScancode);
   last_code_ = code;
 
   bool key_up = !!(code & kKeyUp);
   code &= kScancodeMask;
 
-  uint8_t usage;
+  std::optional<fuchsia_input::wire::Key> key;
   if (multi) {
-    usage = kSet1ExtendedUsageMap[code];
+    key = kSet1ExtendedUsageMap[code];
   } else {
-    usage = kSet1UsageMap[code];
+    key = kSet1UsageMap[code];
   }
+  if (!key)
+    return;
 
-  bool rollover = false;
-  if (IsKeyboardModifier(usage)) {
-    switch (ModifierKey(usage, !key_up)) {
-      case ModStatus::kExists:
-        return;
-      case ModStatus::kRollover:
-        rollover = true;
-        break;
-      case ModStatus::kSet:
-      default:
-        break;
-    }
-  } else if (key_up) {
-    RemoveKey(usage);
+  if (key_up) {
+    RemoveKey(*key);
   } else {
-    AddKey(usage);
+    AddKey(*key);
   }
 
-  const hid_boot_kbd_report_t* report = rollover ? &kRolloverReport : &keyboard_report();
-
   {
     std::scoped_lock lock(hid_lock_);
-    if (ifc_.is_valid()) {
-      ifc_.IoQueue(reinterpret_cast<const uint8_t*>(report), sizeof(*report),
-                   zx_clock_get_monotonic());
-    }
+    input_report_readers_.SendReportToAllReaders(report_);
   }
 }
 
-ModStatus I8042Device::ModifierKey(uint8_t usage, bool down) {
-  int bit = usage - HID_USAGE_KEY_LEFT_CTRL;
-  if (bit < 0 || bit > 7)
-    return ModStatus::kRollover;
-  if (down) {
-    if (keyboard_report().modifier & 1 << bit) {
-      return ModStatus::kExists;
-    }
-    keyboard_report().modifier |= 1 << bit;
-
-  } else {
-    keyboard_report().modifier &= ~(1 << bit);
-  }
-  return ModStatus::kSet;
-}
-
-KeyStatus I8042Device::AddKey(uint8_t usage) {
-  for (unsigned char& key : keyboard_report().usage) {
-    if (key == usage) {
+KeyStatus I8042Device::AddKey(fuchsia_input::wire::Key key) {
+  for (size_t i = 0; i < keyboard_report().num_pressed_keys_3; i++) {
+    if (keyboard_report().pressed_keys_3[i] == key) {
       return KeyStatus::kKeyExists;
     }
-    if (key == 0) {
-      key = usage;
-      return KeyStatus::kKeyAdded;
-    }
   }
-  return KeyStatus::kKeyRollover;
+  keyboard_report().pressed_keys_3[keyboard_report().num_pressed_keys_3++] = key;
+  return KeyStatus::kKeyAdded;
 }
 
-KeyStatus I8042Device::RemoveKey(uint8_t usage) {
-  ssize_t idx = -1;
-  for (size_t i = 0; i < sizeof(keyboard_report().usage); i++) {
-    if (keyboard_report().usage[i] == usage) {
+KeyStatus I8042Device::RemoveKey(fuchsia_input::wire::Key key) {
+  size_t idx = -1;
+  for (size_t i = 0; i < keyboard_report().num_pressed_keys_3; i++) {
+    if (keyboard_report().pressed_keys_3[i] == key) {
       idx = i;
       break;
     }
   }
 
-  if (idx == -1) {
+  if (idx == -1UL) {
     return KeyStatus::kKeyNotFound;
   }
 
-  for (size_t i = idx; i < sizeof(keyboard_report().usage) - 1; i++) {
-    keyboard_report().usage[i] = keyboard_report().usage[i + 1];
+  for (size_t i = idx; i < keyboard_report().num_pressed_keys_3 - 1; i++) {
+    keyboard_report().pressed_keys_3[i] = keyboard_report().pressed_keys_3[i + 1];
   }
-  keyboard_report().usage[sizeof(keyboard_report().usage) - 1] = 0;
+  keyboard_report().num_pressed_keys_3--;
   return KeyStatus::kKeyRemoved;
 }
 
-void I8042Device::ProcessMouse(uint8_t code) {
+void I8042Device::ProcessMouse(zx::time timestamp, uint8_t code) {
+  report_.type = fuchsia_hardware_input::wire::BootProtocol::kMouse;
+  report_.event_time = timestamp;
   // PS/2 mouse reports span 3 bytes. last_code_ tracks which byte we're up to.
   switch (last_code_) {
     case 0:
@@ -379,12 +446,8 @@
       mouse_report().buttons &= kMouseButtonMask;
 
       std::scoped_lock lock(hid_lock_);
-      if (ifc_.is_valid()) {
-        ifc_.IoQueue(reinterpret_cast<const uint8_t*>(&mouse_report()), sizeof(mouse_report()),
-                     zx_clock_get_monotonic());
-      }
-
-      memset(&mouse_report(), 0, sizeof(mouse_report()));
+      input_report_readers_.SendReportToAllReaders(report_);
+      report_.Reset();
       break;
     }
   }
diff --git a/src/ui/input/drivers/pc-ps2/device.h b/src/ui/input/drivers/pc-ps2/device.h
index f0f6fc6..e62d9c4 100644
--- a/src/ui/input/drivers/pc-ps2/device.h
+++ b/src/ui/input/drivers/pc-ps2/device.h
@@ -6,18 +6,60 @@
 #define SRC_UI_INPUT_DRIVERS_PC_PS2_DEVICE_H_
 
 #include <fidl/fuchsia.hardware.input/cpp/wire.h>
-#include <fuchsia/hardware/hidbus/cpp/banjo.h>
+#include <fidl/fuchsia.input.report/cpp/wire.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/async-loop/default.h>
 #include <lib/zx/interrupt.h>
 
 #include <condition_variable>
 
 #include <ddktl/device.h>
+#include <ddktl/protocol/empty-protocol.h>
 #include <ddktl/unbind-txn.h>
 #include <hid/boot.h>
 
 #include "src/ui/input/drivers/pc-ps2/controller.h"
+#include "src/ui/input/lib/input-report-reader/reader.h"
 
 namespace i8042 {
+
+struct PS2KbdInputReport {
+  size_t num_pressed_keys_3 = 0;
+  fuchsia_input::wire::Key pressed_keys_3[fuchsia_input_report::wire::kKeyboardMaxNumKeys];
+
+  void Reset() { num_pressed_keys_3 = 0; }
+};
+
+struct PS2MouseInputReport {
+  uint8_t buttons;
+  int8_t rel_x;
+  int8_t rel_y;
+
+  void Reset() {
+    buttons = 0;
+    rel_x = 0;
+    rel_y = 0;
+  }
+};
+
+struct PS2InputReport {
+  zx::time event_time;
+  fuchsia_hardware_input::BootProtocol type;
+  std::variant<PS2KbdInputReport, PS2MouseInputReport> report;
+
+  void ToFidlInputReport(fuchsia_input_report::wire::InputReport& input_report,
+                         fidl::AnyArena& allocator);
+  void Reset() {
+    event_time = {};
+    type = fuchsia_hardware_input::BootProtocol::kNone;
+    if (std::holds_alternative<PS2KbdInputReport>(report)) {
+      std::get<PS2KbdInputReport>(report).Reset();
+    } else if (std::holds_alternative<PS2MouseInputReport>(report)) {
+      std::get<PS2MouseInputReport>(report).Reset();
+    }
+  }
+};
+
 enum ModStatus {
   kSet = 1,
   kExists = 2,
@@ -34,13 +76,19 @@
 constexpr uint8_t kAck = 0xfa;
 
 class I8042Device;
-using DeviceType = ddk::Device<I8042Device, ddk::Unbindable>;
-class I8042Device : public DeviceType, public ddk::HidbusProtocol<I8042Device, ddk::base_protocol> {
+using DeviceType = ddk::Device<I8042Device, ddk::Unbindable,
+                               ddk::Messageable<fuchsia_input_report::InputDevice>::Mixin>;
+class I8042Device : public DeviceType, public ddk::EmptyProtocol<ZX_PROTOCOL_INPUTREPORT> {
  public:
   explicit I8042Device(Controller* parent, Port port)
-      : DeviceType(parent->zxdev()), controller_(parent), port_(port) {
-    memset(&reports_, 0, sizeof(reports_));
-  }
+      : DeviceType(parent->zxdev()),
+        controller_(parent),
+        port_(port),
+        loop_(&kAsyncLoopConfigNoAttachToCurrentThread),
+        report_({
+            .event_time = {},
+            .type = fuchsia_hardware_input::BootProtocol::kNone,
+        }) {}
 
   static zx_status_t Bind(Controller* parent, Port port);
   zx_status_t Bind();
@@ -51,23 +99,36 @@
   }
   void DdkUnbind(ddk::UnbindTxn txn);
 
-  // Hid bus ops
-  zx_status_t HidbusQuery(uint32_t options, hid_info_t* out_info);
-  zx_status_t HidbusStart(const hidbus_ifc_protocol_t* ifc);
-  void HidbusStop();
-  zx_status_t HidbusGetDescriptor(hid_description_type_t desc_type, uint8_t* out_data_buffer,
-                                  size_t data_size, size_t* out_data_actual);
-  zx_status_t HidbusGetReport(uint8_t rpt_type, uint8_t rpt_id, uint8_t* data, size_t len,
-                              size_t* out_len) {
-    return ZX_ERR_NOT_SUPPORTED;
+  void GetInputReportsReader(GetInputReportsReaderRequestView request,
+                             GetInputReportsReaderCompleter::Sync& completer) override;
+  void GetDescriptor(GetDescriptorRequestView request,
+                     GetDescriptorCompleter::Sync& completer) override;
+  void SendOutputReport(SendOutputReportRequestView request,
+                        SendOutputReportCompleter::Sync& completer) override {
+    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
   }
-  zx_status_t HidbusSetReport(uint8_t rpt_type, uint8_t rpt_id, const uint8_t* data, size_t len) {
-    return ZX_ERR_NOT_SUPPORTED;
+  void GetFeatureReport(GetFeatureReportRequestView request,
+                        GetFeatureReportCompleter::Sync& completer) override {
+    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
   }
-  zx_status_t HidbusGetIdle(uint8_t rpt_id, uint8_t* duration) { return ZX_ERR_NOT_SUPPORTED; }
-  zx_status_t HidbusSetIdle(uint8_t rpt_id, uint8_t duration) { return ZX_OK; }
-  zx_status_t HidbusGetProtocol(uint8_t* protocol) { return ZX_ERR_NOT_SUPPORTED; }
-  zx_status_t HidbusSetProtocol(uint8_t protocol) { return ZX_OK; }
+  void SetFeatureReport(SetFeatureReportRequestView request,
+                        SetFeatureReportCompleter::Sync& completer) override {
+    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
+  }
+  void GetInputReport(GetInputReportRequestView request,
+                      GetInputReportCompleter::Sync& completer) override {
+    completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
+  }
+
+#ifdef PS2_TEST
+  zx_status_t WaitForNextReader(zx::duration timeout) {
+    zx_status_t status = sync_completion_wait(&next_reader_wait_, timeout.get());
+    if (status == ZX_OK) {
+      sync_completion_reset(&next_reader_wait_);
+    }
+    return status;
+  }
+#endif
 
  private:
   Controller* controller_;
@@ -80,25 +141,31 @@
   std::optional<ddk::UnbindTxn> unbind_ __TA_GUARDED(unbind_lock_);
 
   std::mutex hid_lock_;
-  ddk::HidbusIfcProtocolClient ifc_ __TA_GUARDED(hid_lock_);
+  input::InputReportReaderManager<PS2InputReport> input_report_readers_ __TA_GUARDED(hid_lock_);
+#ifdef PS2_TEST
+  sync_completion_t next_reader_wait_;
+#endif
+  async::Loop loop_;
 
   uint8_t last_code_ = 0;
-  union {
-    hid_boot_kbd_report_t keyboard_report;
-    hid_boot_mouse_report_t mouse_report;
-  } reports_;
-  hid_boot_kbd_report_t& keyboard_report() { return reports_.keyboard_report; }
-  hid_boot_mouse_report_t& mouse_report() { return reports_.mouse_report; }
+  PS2InputReport report_;
+  PS2KbdInputReport& keyboard_report() {
+    ZX_ASSERT(std::holds_alternative<PS2KbdInputReport>(report_.report));
+    return std::get<PS2KbdInputReport>(report_.report);
+  }
+  PS2MouseInputReport& mouse_report() {
+    ZX_ASSERT(std::holds_alternative<PS2MouseInputReport>(report_.report));
+    return std::get<PS2MouseInputReport>(report_.report);
+  }
 
   zx::status<fuchsia_hardware_input::wire::BootProtocol> Identify();
   void IrqThread();
   // Keyboard input
-  void ProcessScancode(uint8_t code);
-  ModStatus ModifierKey(uint8_t usage, bool down);
-  KeyStatus AddKey(uint8_t usage);
-  KeyStatus RemoveKey(uint8_t usage);
+  void ProcessScancode(zx::time timestamp, uint8_t code);
+  KeyStatus AddKey(fuchsia_input::wire::Key key);
+  KeyStatus RemoveKey(fuchsia_input::wire::Key key);
   // Mouse input
-  void ProcessMouse(uint8_t code);
+  void ProcessMouse(zx::time timestamp, uint8_t code);
 };
 
 }  // namespace i8042
diff --git a/src/ui/input/drivers/pc-ps2/keymap.h b/src/ui/input/drivers/pc-ps2/keymap.h
index 4eda70b..dc9893d 100644
--- a/src/ui/input/drivers/pc-ps2/keymap.h
+++ b/src/ui/input/drivers/pc-ps2/keymap.h
@@ -5,9 +5,9 @@
 #ifndef SRC_UI_INPUT_DRIVERS_PC_PS2_KEYMAP_H_
 #define SRC_UI_INPUT_DRIVERS_PC_PS2_KEYMAP_H_
 
+#include <fidl/fuchsia.input/cpp/wire.h>
 #include <stdint.h>
 
-#include <hid/usages.h>
 namespace i8042 {
 
 constexpr uint8_t kKeyUp = 0x80;
@@ -15,198 +15,198 @@
 
 constexpr uint8_t kExtendedScancode = 0xe0;
 
-inline constexpr uint8_t kSet1UsageMap[128] = {
-    /* 0x00 */ 0,
-    HID_USAGE_KEY_ESC,
-    HID_USAGE_KEY_1,
-    HID_USAGE_KEY_2,
-    /* 0x04 */ HID_USAGE_KEY_3,
-    HID_USAGE_KEY_4,
-    HID_USAGE_KEY_5,
-    HID_USAGE_KEY_6,
-    /* 0x08 */ HID_USAGE_KEY_7,
-    HID_USAGE_KEY_8,
-    HID_USAGE_KEY_9,
-    HID_USAGE_KEY_0,
-    /* 0x0c */ HID_USAGE_KEY_MINUS,
-    HID_USAGE_KEY_EQUAL,
-    HID_USAGE_KEY_BACKSPACE,
-    HID_USAGE_KEY_TAB,
-    /* 0x10 */ HID_USAGE_KEY_Q,
-    HID_USAGE_KEY_W,
-    HID_USAGE_KEY_E,
-    HID_USAGE_KEY_R,
-    /* 0x14 */ HID_USAGE_KEY_T,
-    HID_USAGE_KEY_Y,
-    HID_USAGE_KEY_U,
-    HID_USAGE_KEY_I,
-    /* 0x18 */ HID_USAGE_KEY_O,
-    HID_USAGE_KEY_P,
-    HID_USAGE_KEY_LEFTBRACE,
-    HID_USAGE_KEY_RIGHTBRACE,
-    /* 0x1c */ HID_USAGE_KEY_ENTER,
-    HID_USAGE_KEY_LEFT_CTRL,
-    HID_USAGE_KEY_A,
-    HID_USAGE_KEY_S,
-    /* 0x20 */ HID_USAGE_KEY_D,
-    HID_USAGE_KEY_F,
-    HID_USAGE_KEY_G,
-    HID_USAGE_KEY_H,
-    /* 0x24 */ HID_USAGE_KEY_J,
-    HID_USAGE_KEY_K,
-    HID_USAGE_KEY_L,
-    HID_USAGE_KEY_SEMICOLON,
-    /* 0x28 */ HID_USAGE_KEY_APOSTROPHE,
-    HID_USAGE_KEY_GRAVE,
-    HID_USAGE_KEY_LEFT_SHIFT,
-    HID_USAGE_KEY_BACKSLASH,
-    /* 0x2c */ HID_USAGE_KEY_Z,
-    HID_USAGE_KEY_X,
-    HID_USAGE_KEY_C,
-    HID_USAGE_KEY_V,
-    /* 0x30 */ HID_USAGE_KEY_B,
-    HID_USAGE_KEY_N,
-    HID_USAGE_KEY_M,
-    HID_USAGE_KEY_COMMA,
-    /* 0x34 */ HID_USAGE_KEY_DOT,
-    HID_USAGE_KEY_SLASH,
-    HID_USAGE_KEY_RIGHT_SHIFT,
-    HID_USAGE_KEY_KP_ASTERISK,
-    /* 0x38 */ HID_USAGE_KEY_LEFT_ALT,
-    HID_USAGE_KEY_SPACE,
-    HID_USAGE_KEY_CAPSLOCK,
-    HID_USAGE_KEY_F1,
-    /* 0x3c */ HID_USAGE_KEY_F2,
-    HID_USAGE_KEY_F3,
-    HID_USAGE_KEY_F4,
-    HID_USAGE_KEY_F5,
-    /* 0x40 */ HID_USAGE_KEY_F6,
-    HID_USAGE_KEY_F7,
-    HID_USAGE_KEY_F8,
-    HID_USAGE_KEY_F9,
-    /* 0x44 */ HID_USAGE_KEY_F10,
-    HID_USAGE_KEY_NUMLOCK,
-    HID_USAGE_KEY_SCROLLLOCK,
-    HID_USAGE_KEY_KP_7,
-    /* 0x48 */ HID_USAGE_KEY_KP_8,
-    HID_USAGE_KEY_KP_9,
-    HID_USAGE_KEY_KP_MINUS,
-    HID_USAGE_KEY_KP_4,
-    /* 0x4c */ HID_USAGE_KEY_KP_5,
-    HID_USAGE_KEY_KP_6,
-    HID_USAGE_KEY_KP_PLUS,
-    HID_USAGE_KEY_KP_1,
-    /* 0x50 */ HID_USAGE_KEY_KP_2,
-    HID_USAGE_KEY_KP_3,
-    HID_USAGE_KEY_KP_0,
-    HID_USAGE_KEY_KP_DOT,
-    /* 0x54 */ 0,
-    0,
-    0,
-    HID_USAGE_KEY_F11,
-    /* 0x58 */ HID_USAGE_KEY_F12,
-    0,
-    0,
-    0,
+inline constexpr std::optional<fuchsia_input::wire::Key> kSet1UsageMap[128] = {
+    /* 0x00 */ std::nullopt,
+    fuchsia_input::wire::Key::kEscape,
+    fuchsia_input::wire::Key::kKey1,
+    fuchsia_input::wire::Key::kKey2,
+    /* 0x04 */ fuchsia_input::wire::Key::kKey3,
+    fuchsia_input::wire::Key::kKey4,
+    fuchsia_input::wire::Key::kKey5,
+    fuchsia_input::wire::Key::kKey6,
+    /* 0x08 */ fuchsia_input::wire::Key::kKey7,
+    fuchsia_input::wire::Key::kKey8,
+    fuchsia_input::wire::Key::kKey9,
+    fuchsia_input::wire::Key::kKey0,
+    /* 0x0c */ fuchsia_input::wire::Key::kMinus,
+    fuchsia_input::wire::Key::kEquals,
+    fuchsia_input::wire::Key::kBackspace,
+    fuchsia_input::wire::Key::kTab,
+    /* 0x10 */ fuchsia_input::wire::Key::kQ,
+    fuchsia_input::wire::Key::kW,
+    fuchsia_input::wire::Key::kE,
+    fuchsia_input::wire::Key::kR,
+    /* 0x14 */ fuchsia_input::wire::Key::kT,
+    fuchsia_input::wire::Key::kY,
+    fuchsia_input::wire::Key::kU,
+    fuchsia_input::wire::Key::kI,
+    /* 0x18 */ fuchsia_input::wire::Key::kO,
+    fuchsia_input::wire::Key::kP,
+    fuchsia_input::wire::Key::kLeftBrace,
+    fuchsia_input::wire::Key::kRightBrace,
+    /* 0x1c */ fuchsia_input::wire::Key::kEnter,
+    fuchsia_input::wire::Key::kLeftCtrl,
+    fuchsia_input::wire::Key::kA,
+    fuchsia_input::wire::Key::kS,
+    /* 0x20 */ fuchsia_input::wire::Key::kD,
+    fuchsia_input::wire::Key::kF,
+    fuchsia_input::wire::Key::kG,
+    fuchsia_input::wire::Key::kH,
+    /* 0x24 */ fuchsia_input::wire::Key::kJ,
+    fuchsia_input::wire::Key::kK,
+    fuchsia_input::wire::Key::kL,
+    fuchsia_input::wire::Key::kSemicolon,
+    /* 0x28 */ fuchsia_input::wire::Key::kApostrophe,
+    fuchsia_input::wire::Key::kGraveAccent,
+    fuchsia_input::wire::Key::kLeftShift,
+    fuchsia_input::wire::Key::kBackslash,
+    /* 0x2c */ fuchsia_input::wire::Key::kZ,
+    fuchsia_input::wire::Key::kX,
+    fuchsia_input::wire::Key::kC,
+    fuchsia_input::wire::Key::kV,
+    /* 0x30 */ fuchsia_input::wire::Key::kB,
+    fuchsia_input::wire::Key::kN,
+    fuchsia_input::wire::Key::kM,
+    fuchsia_input::wire::Key::kComma,
+    /* 0x34 */ fuchsia_input::wire::Key::kDot,
+    fuchsia_input::wire::Key::kSlash,
+    fuchsia_input::wire::Key::kRightShift,
+    fuchsia_input::wire::Key::kKeypadAsterisk,
+    /* 0x38 */ fuchsia_input::wire::Key::kLeftShift,
+    fuchsia_input::wire::Key::kSpace,
+    fuchsia_input::wire::Key::kCapsLock,
+    fuchsia_input::wire::Key::kF1,
+    /* 0x3c */ fuchsia_input::wire::Key::kF2,
+    fuchsia_input::wire::Key::kF3,
+    fuchsia_input::wire::Key::kF4,
+    fuchsia_input::wire::Key::kF5,
+    /* 0x40 */ fuchsia_input::wire::Key::kF6,
+    fuchsia_input::wire::Key::kF7,
+    fuchsia_input::wire::Key::kF8,
+    fuchsia_input::wire::Key::kF9,
+    /* 0x44 */ fuchsia_input::wire::Key::kF10,
+    fuchsia_input::wire::Key::kNumLock,
+    fuchsia_input::wire::Key::kScrollLock,
+    fuchsia_input::wire::Key::kKeypad7,
+    /* 0x48 */ fuchsia_input::wire::Key::kKeypad8,
+    fuchsia_input::wire::Key::kKeypad9,
+    fuchsia_input::wire::Key::kKeypadMinus,
+    fuchsia_input::wire::Key::kKeypad4,
+    /* 0x4c */ fuchsia_input::wire::Key::kKeypad5,
+    fuchsia_input::wire::Key::kKeypad6,
+    fuchsia_input::wire::Key::kKeypadPlus,
+    fuchsia_input::wire::Key::kKeypad1,
+    /* 0x50 */ fuchsia_input::wire::Key::kKeypad2,
+    fuchsia_input::wire::Key::kKeypad3,
+    fuchsia_input::wire::Key::kKeypad0,
+    fuchsia_input::wire::Key::kKeypadDot,
+    /* 0x54 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    fuchsia_input::wire::Key::kF11,
+    /* 0x58 */ fuchsia_input::wire::Key::kF12,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
 };
 
-inline constexpr uint8_t kSet1ExtendedUsageMap[128] = {
-    /* 0x00 */ 0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    /* 0x08 */ 0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    /* 0x10 */ 0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    /* 0x18 */ 0,
-    0,
-    0,
-    0,
-    HID_USAGE_KEY_KP_ENTER,
-    HID_USAGE_KEY_RIGHT_CTRL,
-    0,
-    0,
-    /* 0x20 */ 0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    /* 0x28 */ 0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    HID_USAGE_KEY_VOL_DOWN,
-    0,
-    /* 0x30 */ HID_USAGE_KEY_VOL_UP,
-    0,
-    0,
-    0,
-    0,
-    HID_USAGE_KEY_KP_SLASH,
-    0,
-    HID_USAGE_KEY_PRINTSCREEN,
-    /* 0x38 */ HID_USAGE_KEY_RIGHT_ALT,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    /* 0x40 */ 0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    HID_USAGE_KEY_HOME,
-    /* 0x48 */ HID_USAGE_KEY_UP,
-    HID_USAGE_KEY_PAGEUP,
-    0,
-    HID_USAGE_KEY_LEFT,
-    0,
-    HID_USAGE_KEY_RIGHT,
-    0,
-    HID_USAGE_KEY_END,
-    /* 0x50 */ HID_USAGE_KEY_DOWN,
-    HID_USAGE_KEY_PAGEDOWN,
-    HID_USAGE_KEY_INSERT,
-    HID_USAGE_KEY_DELETE,
-    0,
-    0,
-    0,
-    0,
-    /* 0x58 */ 0,
-    0,
-    0,
-    HID_USAGE_KEY_LEFT_GUI,
-    HID_USAGE_KEY_RIGHT_GUI,
-    0 /* MENU */,
-    0,
-    0,
+inline constexpr std::optional<fuchsia_input::wire::Key> kSet1ExtendedUsageMap[128] = {
+    /* 0x00 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    /* 0x08 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    /* 0x10 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    /* 0x18 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    fuchsia_input::wire::Key::kKeypadEnter,
+    fuchsia_input::wire::Key::kRightCtrl,
+    std::nullopt,
+    std::nullopt,
+    /* 0x20 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    /* 0x28 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    fuchsia_input::wire::Key::kMediaVolumeDecrement,
+    std::nullopt,
+    /* 0x30 */ fuchsia_input::wire::Key::kMediaVolumeIncrement,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    fuchsia_input::wire::Key::kKeypadSlash,
+    std::nullopt,
+    fuchsia_input::wire::Key::kPrintScreen,
+    /* 0x38 */ fuchsia_input::wire::Key::kRightAlt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    /* 0x40 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    fuchsia_input::wire::Key::kHome,
+    /* 0x48 */ fuchsia_input::wire::Key::kUp,
+    fuchsia_input::wire::Key::kPageUp,
+    std::nullopt,
+    fuchsia_input::wire::Key::kLeft,
+    std::nullopt,
+    fuchsia_input::wire::Key::kRight,
+    std::nullopt,
+    fuchsia_input::wire::Key::kEnd,
+    /* 0x50 */ fuchsia_input::wire::Key::kDown,
+    fuchsia_input::wire::Key::kPageDown,
+    fuchsia_input::wire::Key::kInsert,
+    fuchsia_input::wire::Key::kDelete,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    /* 0x58 */ std::nullopt,
+    std::nullopt,
+    std::nullopt,
+    fuchsia_input::wire::Key::kLeftMeta,
+    fuchsia_input::wire::Key::kRightMeta,
+    std::nullopt /* MENU */,
+    std::nullopt,
+    std::nullopt,
 };
 
 }  // namespace i8042
diff --git a/src/ui/input/drivers/pc-ps2/unit-tests.cc b/src/ui/input/drivers/pc-ps2/unit-tests.cc
index 00429d4d..1aebed7 100644
--- a/src/ui/input/drivers/pc-ps2/unit-tests.cc
+++ b/src/ui/input/drivers/pc-ps2/unit-tests.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 <fuchsia/hardware/hidbus/cpp/banjo.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/async-loop/default.h>
 #include <lib/sync/completion.h>
 #include <lib/zx/clock.h>
 #include <lib/zx/interrupt.h>
@@ -11,7 +12,6 @@
 #include <condition_variable>
 
 #include <hid/boot.h>
-#include <hid/usages.h>
 #include <zxtest/zxtest.h>
 
 #include "src/devices/testing/mock-ddk/mock-device.h"
@@ -179,7 +179,7 @@
   return clone;
 }
 
-class ControllerTest : public zxtest::Test, public ddk::HidbusIfcProtocol<ControllerTest> {
+class ControllerTest : public zxtest::Test {
  public:
   void SetUp() override {
     root_ = MockDevice::FakeRootParent();
@@ -187,6 +187,8 @@
     ASSERT_OK(status);
 
     controller_dev_ = root_->GetLatestChild();
+
+    loop_.StartThread("pc-ps2-test-thread");
   }
 
   void TearDown() override {
@@ -200,73 +202,185 @@
     ASSERT_OK(controller_dev_->InitReplyCallStatus());
     sync_completion_wait(&controller_dev_->GetDeviceContext<i8042::Controller>()->added_children(),
                          ZX_TIME_INFINITE);
-  }
 
-  void HidbusIfcIoQueue(const uint8_t* buf_buffer, size_t buf_size, zx_time_t timestamp) {
-    std::scoped_lock lock(buf_lock_);
-    last_buffer_.resize(buf_size);
-    memcpy(last_buffer_.data(), buf_buffer, buf_size);
-    received_ = true;
-    received_event_.notify_all();
-  }
+    auto endpoints = fidl::CreateEndpoints<fuchsia_input_report::InputDevice>();
+    ASSERT_OK(endpoints.status_value());
 
-  std::vector<uint8_t> WaitForIo() {
-    std::scoped_lock lock(buf_lock_);
-    received_event_.wait(buf_lock_, [this]() { return received_; });
-    received_ = false;
-    auto ret = std::move(last_buffer_);
-    last_buffer_ = {};
-    return ret;
+    binding_ =
+        fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server),
+                         controller_dev_->GetLatestChild()->GetDeviceContext<i8042::I8042Device>());
+    client_.Bind(std::move(endpoints->client));
   }
 
  protected:
   Fake8042 i8042_;
   std::shared_ptr<MockDevice> root_;
   zx_device* controller_dev_;
-  std::mutex buf_lock_;
-  std::condition_variable_any received_event_;
-  std::vector<uint8_t> last_buffer_ __TA_GUARDED(buf_lock_);
-  bool received_ = false;
 
-  const hidbus_ifc_protocol_t proto_{
-      .ops = &hidbus_ifc_protocol_ops_,
-      .ctx = this,
-  };
+  fidl::WireSyncClient<fuchsia_input_report::InputDevice> client_;
+
+ private:
+  async::Loop loop_{&kAsyncLoopConfigNoAttachToCurrentThread};
+  std::optional<fidl::ServerBindingRef<fuchsia_input_report::InputDevice>> binding_;
 };
 
+TEST_F(ControllerTest, GetKbdDescriptorTest) {
+  InitDevices();
+
+  auto response = client_->GetDescriptor();
+
+  ASSERT_TRUE(response.ok());
+  ASSERT_TRUE(response->descriptor.has_device_info());
+  EXPECT_EQ(response->descriptor.device_info().vendor_id,
+            static_cast<uint32_t>(fuchsia_input_report::wire::VendorId::kGoogle));
+  EXPECT_EQ(
+      response->descriptor.device_info().product_id,
+      static_cast<uint32_t>(fuchsia_input_report::wire::VendorGoogleProductId::kPcPs2Keyboard));
+
+  ASSERT_TRUE(response->descriptor.has_keyboard());
+  ASSERT_TRUE(response->descriptor.keyboard().has_input());
+  ASSERT_TRUE(response->descriptor.keyboard().input().has_keys3());
+  ASSERT_EQ(response->descriptor.keyboard().input().keys3().count(), 104);
+
+  ASSERT_TRUE(response->descriptor.keyboard().has_output());
+  ASSERT_TRUE(response->descriptor.keyboard().output().has_leds());
+  ASSERT_EQ(response->descriptor.keyboard().output().leds().count(), 5);
+  const auto& leds = response->descriptor.keyboard().output().leds();
+  EXPECT_EQ(leds[0], fuchsia_input_report::wire::LedType::kNumLock);
+  EXPECT_EQ(leds[1], fuchsia_input_report::wire::LedType::kCapsLock);
+  EXPECT_EQ(leds[2], fuchsia_input_report::wire::LedType::kScrollLock);
+  EXPECT_EQ(leds[3], fuchsia_input_report::wire::LedType::kCompose);
+  EXPECT_EQ(leds[4], fuchsia_input_report::wire::LedType::kKana);
+}
+
 TEST_F(ControllerTest, KeyboardPressTest) {
   InitDevices();
   zx_device* dev = controller_dev_->GetLatestChild();
   auto keyboard = dev->GetDeviceContext<i8042::I8042Device>();
-  ASSERT_OK(keyboard->HidbusStart(&proto_));
-  i8042_.SendDataAndIrq(false, 0x2);
 
-  hid_boot_kbd_report_t report;
-  auto buf = WaitForIo();
-  memcpy(&report, buf.data(), sizeof(report));
-  ASSERT_EQ(report.usage[0], HID_USAGE_KEY_1);
+  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));
+    ASSERT_OK(result.status());
+    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
+        std::move(endpoints->client));
+    ASSERT_OK(keyboard->WaitForNextReader(zx::duration::infinite()));
+  }
+  {
+    i8042_.SendDataAndIrq(false, 0x2);
 
-  i8042_.SendDataAndIrq(false, i8042::kKeyUp | 0x2);
-  buf = WaitForIo();
-  memcpy(&report, buf.data(), sizeof(report));
-  ASSERT_EQ(report.usage[0], 0);
+    auto result = reader->ReadInputReports();
+    ASSERT_OK(result.status());
+    ASSERT_FALSE(result->result.is_err());
+    auto& reports = result->result.response().reports;
+
+    ASSERT_EQ(1, reports.count());
+
+    auto& report = reports[0];
+    ASSERT_TRUE(report.has_event_time());
+    ASSERT_TRUE(report.has_keyboard());
+    auto& keyboard_report = report.keyboard();
+
+    ASSERT_TRUE(keyboard_report.has_pressed_keys3());
+    ASSERT_EQ(keyboard_report.pressed_keys3().count(), 1);
+    EXPECT_EQ(keyboard_report.pressed_keys3()[0], fuchsia_input::wire::Key::kKey1);
+  }
+  {
+    i8042_.SendDataAndIrq(false, i8042::kKeyUp | 0x2);
+
+    auto result = reader->ReadInputReports();
+    ASSERT_OK(result.status());
+    ASSERT_FALSE(result->result.is_err());
+    auto& reports = result->result.response().reports;
+
+    ASSERT_EQ(1, reports.count());
+
+    auto& report = reports[0];
+    ASSERT_TRUE(report.has_event_time());
+    ASSERT_TRUE(report.has_keyboard());
+    auto& keyboard_report = report.keyboard();
+
+    ASSERT_TRUE(keyboard_report.has_pressed_keys3());
+    EXPECT_EQ(keyboard_report.pressed_keys3().count(), 0);
+  }
+}
+
+TEST_F(ControllerTest, GetMouseDescriptorTest) {
+  i8042_.EnablePort2();
+  InitDevices();
+
+  auto response = client_->GetDescriptor();
+
+  ASSERT_TRUE(response.ok());
+  ASSERT_TRUE(response->descriptor.has_device_info());
+  EXPECT_EQ(response->descriptor.device_info().vendor_id,
+            static_cast<uint32_t>(fuchsia_input_report::wire::VendorId::kGoogle));
+  EXPECT_EQ(response->descriptor.device_info().product_id,
+            static_cast<uint32_t>(fuchsia_input_report::wire::VendorGoogleProductId::kPcPs2Mouse));
+
+  ASSERT_TRUE(response->descriptor.has_mouse());
+  ASSERT_TRUE(response->descriptor.mouse().has_input());
+  ASSERT_TRUE(response->descriptor.mouse().input().has_buttons());
+  ASSERT_EQ(response->descriptor.mouse().input().buttons().count(), 3);
+  EXPECT_EQ(response->descriptor.mouse().input().buttons()[0], 0x01);
+  EXPECT_EQ(response->descriptor.mouse().input().buttons()[1], 0x02);
+  EXPECT_EQ(response->descriptor.mouse().input().buttons()[2], 0x03);
+
+  ASSERT_TRUE(response->descriptor.mouse().input().has_movement_x());
+  EXPECT_EQ(response->descriptor.mouse().input().movement_x().range.min, -127);
+  EXPECT_EQ(response->descriptor.mouse().input().movement_x().range.max, 127);
+  EXPECT_EQ(response->descriptor.mouse().input().movement_x().unit.type,
+            fuchsia_input_report::wire::UnitType::kNone);
+  EXPECT_EQ(response->descriptor.mouse().input().movement_x().unit.exponent, 0);
+
+  ASSERT_TRUE(response->descriptor.mouse().input().has_movement_y());
+  EXPECT_EQ(response->descriptor.mouse().input().movement_y().range.min, -127);
+  EXPECT_EQ(response->descriptor.mouse().input().movement_y().range.max, 127);
+  EXPECT_EQ(response->descriptor.mouse().input().movement_y().unit.type,
+            fuchsia_input_report::wire::UnitType::kNone);
+  EXPECT_EQ(response->descriptor.mouse().input().movement_y().unit.exponent, 0);
 }
 
 TEST_F(ControllerTest, MouseMoveTest) {
   i8042_.EnablePort2();
   InitDevices();
-
   zx_device* dev = controller_dev_->GetLatestChild();
   auto mouse = dev->GetDeviceContext<i8042::I8042Device>();
-  ASSERT_OK(mouse->HidbusStart(&proto_));
+
+  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));
+    ASSERT_OK(result.status());
+    reader = fidl::WireSyncClient<fuchsia_input_report::InputReportsReader>(
+        std::move(endpoints->client));
+    ASSERT_OK(mouse->WaitForNextReader(zx::duration::infinite()));
+  }
+
   i8042_.SendData(0x09 /* button_left | always_one */);
   i8042_.SendData(0x70) /* rel_x */;
   i8042_.SendDataAndIrq(true, 0x10 /* rel_y */);
 
-  hid_boot_mouse_report_t report;
-  auto buf = WaitForIo();
-  memcpy(&report, buf.data(), sizeof(report));
-  ASSERT_EQ(report.buttons, 0x1);
-  ASSERT_EQ(report.rel_x, 0x70);
-  ASSERT_EQ(report.rel_y, -16);
+  auto result = reader->ReadInputReports();
+  ASSERT_OK(result.status());
+  ASSERT_FALSE(result->result.is_err());
+  auto& reports = result->result.response().reports;
+
+  ASSERT_EQ(1, reports.count());
+
+  auto& report = reports[0];
+  ASSERT_TRUE(report.has_event_time());
+  ASSERT_TRUE(report.has_mouse());
+  auto& mouse_report = report.mouse();
+
+  ASSERT_TRUE(mouse_report.has_pressed_buttons());
+  ASSERT_EQ(mouse_report.pressed_buttons().count(), 1);
+  EXPECT_EQ(mouse_report.pressed_buttons()[0], 0x1);
+  ASSERT_TRUE(mouse_report.has_movement_x());
+  EXPECT_EQ(mouse_report.movement_x(), 0x70);
+  ASSERT_TRUE(mouse_report.has_movement_y());
+  EXPECT_EQ(mouse_report.movement_y(), -16);
 }
diff --git a/src/ui/lib/display/BUILD.gn b/src/ui/lib/display/BUILD.gn
index b2e5487..526f9fc 100644
--- a/src/ui/lib/display/BUILD.gn
+++ b/src/ui/lib/display/BUILD.gn
@@ -74,7 +74,7 @@
 fuchsia_unittest_package("test") {
   package_name = "get_hardware_display_controller_test"
   deps = [ ":get_hardware_display_controller_test" ]
-  manifest = "tests/meta/get_hardware_display_controller_test.cmx"
+  manifest = "tests/meta/get_hardware_display_controller_test.cml"
   test_specs = {
     log_settings = {
       max_severity = "ERROR"
@@ -97,9 +97,12 @@
 
 fuchsia_unittest_package("inject_service_test") {
   package_name = "get_hardware_display_controller_inject_services_test"
-  deps = [ ":get_hardware_display_controller_inject_services_test" ]
+  deps = [
+    ":get_hardware_display_controller_inject_services_test",
+    "//src/ui/bin/hardware_display_controller_provider:fake-hardware-display-controller-provider-cmv2-component",
+  ]
   manifest =
-      "tests/meta/get_hardware_display_controller_inject_services_test.cmx"
+      "tests/meta/get_hardware_display_controller_inject_services_test.cml"
   test_specs = {
     log_settings = {
       max_severity = "ERROR"
diff --git a/src/ui/lib/display/tests/meta/get_hardware_display_controller_inject_services_test.cml b/src/ui/lib/display/tests/meta/get_hardware_display_controller_inject_services_test.cml
new file mode 100644
index 0000000..a90fff4
--- /dev/null
+++ b/src/ui/lib/display/tests/meta/get_hardware_display_controller_inject_services_test.cml
@@ -0,0 +1,34 @@
+{
+    include: [
+        "//src/lib/vulkan/vulkan-test.shard.cml",
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "syslog/client.shard.cml",
+        "vulkan/client.shard.cml",
+    ],
+    program: {
+        binary: "test/get_hardware_display_controller_inject_services_test",
+    },
+    children: [
+        {
+            name: "fake_display_provider",
+            url: "#meta/hdcp.cm",
+        },
+    ],
+    use: [
+        {
+            protocol: [ "fuchsia.hardware.display.Provider" ],
+            from: "#fake_display_provider",
+        },
+    ],
+    offer: [
+        {
+            protocol: [
+                "fuchsia.logger.LogSink",
+                "fuchsia.sysmem.Allocator",
+                "fuchsia.tracing.provider.Registry",
+            ],
+            from: "parent",
+            to: [ "#fake_display_provider" ],
+        },
+    ],
+}
diff --git a/src/ui/lib/display/tests/meta/get_hardware_display_controller_inject_services_test.cmx b/src/ui/lib/display/tests/meta/get_hardware_display_controller_inject_services_test.cmx
deleted file mode 100644
index 43afd34..0000000
--- a/src/ui/lib/display/tests/meta/get_hardware_display_controller_inject_services_test.cmx
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    "facets": {
-        "fuchsia.test": {
-            "injected-services": {
-                "fuchsia.hardware.display.Provider": "fuchsia-pkg://fuchsia.com/fake-hardware-display-controller-provider#meta/hdcp.cmx"
-            }
-        }
-    },
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "test/get_hardware_display_controller_inject_services_test"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.hardware.display.Provider"
-        ]
-    }
-}
diff --git a/src/ui/lib/display/tests/meta/get_hardware_display_controller_test.cml b/src/ui/lib/display/tests/meta/get_hardware_display_controller_test.cml
new file mode 100644
index 0000000..71124238
--- /dev/null
+++ b/src/ui/lib/display/tests/meta/get_hardware_display_controller_test.cml
@@ -0,0 +1,9 @@
+{
+    include: [
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "test/get_hardware_display_controller_test",
+    },
+}
diff --git a/src/ui/lib/display/tests/meta/get_hardware_display_controller_test.cmx b/src/ui/lib/display/tests/meta/get_hardware_display_controller_test.cmx
deleted file mode 100644
index f32f356..0000000
--- a/src/ui/lib/display/tests/meta/get_hardware_display_controller_test.cmx
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "test/get_hardware_display_controller_test"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.hardware.display.Provider"
-        ]
-    }
-}
diff --git a/src/ui/lib/escher/BUILD.gn b/src/ui/lib/escher/BUILD.gn
index d1417fc..4305c43 100644
--- a/src/ui/lib/escher/BUILD.gn
+++ b/src/ui/lib/escher/BUILD.gn
@@ -16,22 +16,22 @@
 }
 
 fuchsia_test_component("escher_unittests") {
-  manifest = "meta/escher_unittests.cmx"
+  manifest = "meta/escher_unittests.cml"
   deps = [ "test:escher_unittests" ]
 }
 
 fuchsia_test_component("escher_unittests_expected_failure") {
-  manifest = "meta/escher_unittests_expected_failure.cmx"
+  manifest = "meta/escher_unittests_expected_failure.cml"
   deps = [ "test:escher_unittests_expected_failure" ]
 }
 
 fuchsia_test_component("escher_renderer_tests") {
-  manifest = "meta/escher_renderer_tests.cmx"
+  manifest = "meta/escher_renderer_tests.cml"
   deps = [ "test:escher_renderer_tests" ]
 }
 
 fuchsia_test_component("escher_examples_test") {
-  manifest = "meta/escher_examples_test.cmx"
+  manifest = "meta/escher_examples_test.cml"
   deps = [ "//src/ui/examples/escher/test:escher_examples_test" ]
 }
 
diff --git a/src/ui/lib/escher/meta/escher_examples_test.cml b/src/ui/lib/escher/meta/escher_examples_test.cml
new file mode 100644
index 0000000..b037090
--- /dev/null
+++ b/src/ui/lib/escher/meta/escher_examples_test.cml
@@ -0,0 +1,12 @@
+{
+    include: [
+        "//src/lib/vulkan/vulkan-test.shard.cml",
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "//src/sys/test_runners/tmp_storage.shard.cml",
+        "syslog/client.shard.cml",
+        "vulkan/client.shard.cml",
+    ],
+    program: {
+        binary: "test/escher_examples_test",
+    },
+}
diff --git a/src/ui/lib/escher/meta/escher_examples_test.cmx b/src/ui/lib/escher/meta/escher_examples_test.cmx
deleted file mode 100644
index 907a6ba..0000000
--- a/src/ui/lib/escher/meta/escher_examples_test.cmx
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx",
-        "//src/lib/vulkan/test-application.shard.cmx"
-    ],
-    "program": {
-        "binary": "test/escher_examples_test"
-    },
-    "sandbox": {
-        "features": [
-            "isolated-temp"
-        ],
-        "services": [
-            "fuchsia.process.Launcher"
-        ]
-    }
-}
diff --git a/src/ui/lib/escher/meta/escher_renderer_tests.cml b/src/ui/lib/escher/meta/escher_renderer_tests.cml
new file mode 100644
index 0000000..83eb36f
--- /dev/null
+++ b/src/ui/lib/escher/meta/escher_renderer_tests.cml
@@ -0,0 +1,11 @@
+{
+    include: [
+        "//src/lib/vulkan/vulkan-test.shard.cml",
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "syslog/client.shard.cml",
+        "vulkan/client.shard.cml",
+    ],
+    program: {
+        binary: "test/escher_renderer_tests",
+    },
+}
diff --git a/src/ui/lib/escher/meta/escher_renderer_tests.cmx b/src/ui/lib/escher/meta/escher_renderer_tests.cmx
deleted file mode 100644
index 59334d9..0000000
--- a/src/ui/lib/escher/meta/escher_renderer_tests.cmx
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx",
-        "//src/lib/vulkan/test-application.shard.cmx"
-    ],
-    "program": {
-        "binary": "test/escher_renderer_tests"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.process.Launcher"
-        ]
-    }
-}
diff --git a/src/ui/lib/escher/meta/escher_unittests.cml b/src/ui/lib/escher/meta/escher_unittests.cml
new file mode 100644
index 0000000..bd0270b
--- /dev/null
+++ b/src/ui/lib/escher/meta/escher_unittests.cml
@@ -0,0 +1,11 @@
+{
+    include: [
+        "//src/lib/vulkan/vulkan-test.shard.cml",
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "syslog/client.shard.cml",
+        "vulkan/client.shard.cml",
+    ],
+    program: {
+        binary: "test/escher_unittests",
+    },
+}
diff --git a/src/ui/lib/escher/meta/escher_unittests.cmx b/src/ui/lib/escher/meta/escher_unittests.cmx
deleted file mode 100644
index 55c0e82..0000000
--- a/src/ui/lib/escher/meta/escher_unittests.cmx
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx",
-        "//src/lib/vulkan/test-application.shard.cmx"
-    ],
-    "program": {
-        "binary": "test/escher_unittests"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.process.Launcher"
-        ]
-    }
-}
diff --git a/src/ui/lib/escher/meta/escher_unittests_expected_failure.cml b/src/ui/lib/escher/meta/escher_unittests_expected_failure.cml
new file mode 100644
index 0000000..482453e
--- /dev/null
+++ b/src/ui/lib/escher/meta/escher_unittests_expected_failure.cml
@@ -0,0 +1,12 @@
+{
+    include: [
+        "//src/lib/vulkan/vulkan-test.shard.cml",
+        "//src/sys/test_runners/gtest/death_test.shard.cml",
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "syslog/client.shard.cml",
+        "vulkan/client.shard.cml",
+    ],
+    program: {
+        binary: "test/escher_unittests_expected_failure",
+    },
+}
diff --git a/src/ui/lib/escher/meta/escher_unittests_expected_failure.cmx b/src/ui/lib/escher/meta/escher_unittests_expected_failure.cmx
deleted file mode 100644
index cfc26a6..0000000
--- a/src/ui/lib/escher/meta/escher_unittests_expected_failure.cmx
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx",
-        "//src/lib/vulkan/test-application.shard.cmx"
-    ],
-    "program": {
-        "binary": "test/escher_unittests_expected_failure"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.process.Launcher"
-        ]
-    }
-}
diff --git a/src/ui/lib/input_pipeline/BUILD.gn b/src/ui/lib/input_pipeline/BUILD.gn
index 63ae4e3..0768c6d 100644
--- a/src/ui/lib/input_pipeline/BUILD.gn
+++ b/src/ui/lib/input_pipeline/BUILD.gn
@@ -108,7 +108,6 @@
 }
 
 fuchsia_unittest_package("input_pipeline_lib_tests") {
-  manifest = "meta/input_pipeline_lib_test.cmx"
   deps = [ ":input_pipeline_test" ]
   test_specs = {
     log_settings = {
diff --git a/src/ui/lib/input_pipeline/meta/input_keymap_configuration.shard.cml b/src/ui/lib/input_pipeline/meta/input_keymap_configuration.shard.cml
deleted file mode 100644
index 4958f322..0000000
--- a/src/ui/lib/input_pipeline/meta/input_keymap_configuration.shard.cml
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    use: [
-        {
-            protocol: [ "fuchsia.settings.Keyboard" ],
-        },
-    ],
-}
diff --git a/src/ui/lib/input_pipeline/meta/input_pipeline_lib_test.cmx b/src/ui/lib/input_pipeline/meta/input_pipeline_lib_test.cmx
deleted file mode 100644
index 673b6c9..0000000
--- a/src/ui/lib/input_pipeline/meta/input_pipeline_lib_test.cmx
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "bin/input_pipeline_lib_test"
-    }
-}
diff --git a/src/ui/lib/scene_management/BUILD.gn b/src/ui/lib/scene_management/BUILD.gn
index 875266d..54fc9221 100644
--- a/src/ui/lib/scene_management/BUILD.gn
+++ b/src/ui/lib/scene_management/BUILD.gn
@@ -51,6 +51,5 @@
 }
 
 fuchsia_unittest_package("scene_management_tests") {
-  manifest = "meta/scene_management_lib_test.cmx"
   deps = [ ":scene_management_test" ]
 }
diff --git a/src/ui/lib/scene_management/meta/scene_management_lib_test.cmx b/src/ui/lib/scene_management/meta/scene_management_lib_test.cmx
deleted file mode 100644
index 633f0a8..0000000
--- a/src/ui/lib/scene_management/meta/scene_management_lib_test.cmx
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "bin/scene_management_lib_test"
-    }
-}
diff --git a/src/ui/scenic/BUILD.gn b/src/ui/scenic/BUILD.gn
index 5303b95..970eba5 100644
--- a/src/ui/scenic/BUILD.gn
+++ b/src/ui/scenic/BUILD.gn
@@ -47,27 +47,20 @@
     ":flatland_engine_unittests",
     ":flatland_renderer_unittests",
     ":flatland_unittests",
+    ":focus_unittests",
     ":fuzzers",
+    ":geometry_provider_unittests",
     ":gfx_apptests",
     ":gfx_swapchain_tests",
     ":gfx_unittests",
     ":gfx_util_unittests",
     ":input_unittests",
     ":scenic_unittests",
+    ":scenic_util_tests",
     ":scheduling_unittests",
     ":screen_capture_unittests",
-    "lib/focus/tests",
-    "lib/gfx/tests",
-    "lib/scenic/util/tests",
-    "lib/view_tree:geometry_provider",
-    "lib/view_tree:observer_registry",
-    "lib/view_tree/tests",
+    ":view_tree_unittests",
     "tests",
-
-    # These are included in //src/ui/bin:tests, but I don't see that included anywhere.
-    # If these tests fail, then other Scenic tests are likely to fail, so we want to guarantee that
-    # they are always run whenever Scenic tests are.
-    "//src/ui/bin/hardware_display_controller_provider:tests",
   ]
 }
 
@@ -235,6 +228,10 @@
   deps = [ "lib/gfx/util/tests:unittests" ] + scenic_test_deps
 }
 
+fuchsia_unittest_package("focus_unittests") {
+  deps = [ "lib/focus/tests:unittests" ]
+}
+
 fuchsia_unittest_package("input_unittests") {
   manifest = "meta/input_unittests.cml"
   deps = [ "lib/input/tests:unittests" ] + scenic_test_deps
@@ -258,6 +255,11 @@
   }
 }
 
+fuchsia_unittest_package("scenic_util_tests") {
+  manifest = "meta/scenic_util_tests.cml"
+  deps = [ "lib/scenic/util/tests:unittests" ]
+}
+
 fuchsia_unittest_package("scheduling_unittests") {
   deps = [ "lib/scheduling/tests:unittests" ] + scenic_test_deps
 }
@@ -272,6 +274,14 @@
   }
 }
 
+fuchsia_unittest_package("geometry_provider_unittests") {
+  deps = [ "lib/view_tree/tests:geometry_provider_test_bin" ]
+}
+
+fuchsia_unittest_package("view_tree_unittests") {
+  deps = [ "lib/view_tree/tests:view_tree_test_bin" ]
+}
+
 # For migration purposes only.  To be moved to src/ui/scenic/bin:scenic
 #
 # TODO(fxbug.dev/83213) Retain v1 component while out of tree tests need it.
diff --git a/src/ui/scenic/lib/flatland/link_system.cc b/src/ui/scenic/lib/flatland/link_system.cc
index f833bde..23f6157 100644
--- a/src/ui/scenic/lib/flatland/link_system.cc
+++ b/src/ui/scenic/lib/flatland/link_system.cc
@@ -20,10 +20,20 @@
 
 namespace {
 
+// Scale can be extracted from a matrix by finding the length of the
+// column the scale is located in:
+//
+//   a b c
+//   e f g
+//   i j k
+//
+// If |a| is the x scale and rotation, and |f| is the y scale and rotation, then
+// we can calculate the x scale with length(vector(a,e,i)) and y scale with
+// length(vector(b,f,j)).
 glm::vec2 ComputeScale(const glm::mat3& matrix) {
-  const glm::vec3 x_row = glm::row(matrix, 0);
-  const glm::vec3 y_row = glm::row(matrix, 1);
-  return {std::fabs(glm::length(x_row)), std::fabs(glm::length(y_row))};
+  const glm::vec3 x_column = glm::column(matrix, 0);
+  const glm::vec3 y_column = glm::column(matrix, 1);
+  return {glm::length(x_column), glm::length(y_column)};
 }
 
 }  // namespace
diff --git a/src/ui/scenic/lib/focus/tests/BUILD.gn b/src/ui/scenic/lib/focus/tests/BUILD.gn
index c9fb66d..c82a916 100644
--- a/src/ui/scenic/lib/focus/tests/BUILD.gn
+++ b/src/ui/scenic/lib/focus/tests/BUILD.gn
@@ -2,16 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/components.gni")
-
-group("tests") {
+executable("unittests") {
   testonly = true
-
-  deps = [ ":focus_unittests" ]
-}
-
-executable("focus_test_bin") {
-  testonly = true
+  output_name = "focus_unittests"
   sources = [
     "focus_manager_unittest.cc",
     "view_focuser_registry_unittest.cc",
@@ -29,7 +22,3 @@
     "//third_party/googletest:gtest",
   ]
 }
-
-fuchsia_unittest_package("focus_unittests") {
-  deps = [ ":focus_test_bin" ]
-}
diff --git a/src/ui/scenic/lib/input/tests/BUILD.gn b/src/ui/scenic/lib/input/tests/BUILD.gn
index 2e1f878..4f0232d 100644
--- a/src/ui/scenic/lib/input/tests/BUILD.gn
+++ b/src/ui/scenic/lib/input/tests/BUILD.gn
@@ -2,12 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-group("tests") {
-  testonly = true
-  public_deps = [ ":unittests" ]
-  deps = [ "fuzzers" ]
-}
-
 executable("unittests") {
   testonly = true
   output_name = "input_unittests"
diff --git a/src/ui/scenic/lib/scenic/util/tests/BUILD.gn b/src/ui/scenic/lib/scenic/util/tests/BUILD.gn
index 1f67337..b4af9e5 100644
--- a/src/ui/scenic/lib/scenic/util/tests/BUILD.gn
+++ b/src/ui/scenic/lib/scenic/util/tests/BUILD.gn
@@ -2,14 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/components.gni")
-
-group("tests") {
-  testonly = true
-  public_deps = [ ":scenic_util_tests_pkg" ]
-}
-
-executable("scenic_util_tests_bin") {
+executable("unittests") {
   testonly = true
   output_name = "scenic_util_tests"
   sources = [ "util_tests.cc" ]
@@ -19,9 +12,3 @@
     "//third_party/googletest:gtest",
   ]
 }
-
-fuchsia_unittest_package("scenic_util_tests_pkg") {
-  package_name = "scenic_util_tests"
-  manifest = "meta/scenic_util_tests.cmx"
-  deps = [ ":scenic_util_tests_bin" ]
-}
diff --git a/src/ui/scenic/lib/scenic/util/tests/meta/scenic_util_tests.cmx b/src/ui/scenic/lib/scenic/util/tests/meta/scenic_util_tests.cmx
deleted file mode 100644
index 19ebd2d..0000000
--- a/src/ui/scenic/lib/scenic/util/tests/meta/scenic_util_tests.cmx
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    "facets": {
-        "fuchsia.test": {
-            "system-services": [
-                "fuchsia.scheduler.ProfileProvider"
-            ]
-        }
-    },
-    "include": [
-        "syslog/client.shard.cmx"
-    ],
-    "program": {
-        "binary": "bin/scenic_util_tests"
-    },
-    "sandbox": {
-        "services": [
-            "fuchsia.scheduler.ProfileProvider"
-        ]
-    }
-}
diff --git a/src/ui/scenic/lib/view_tree/tests/BUILD.gn b/src/ui/scenic/lib/view_tree/tests/BUILD.gn
index 85b26d4..50c1c9c 100644
--- a/src/ui/scenic/lib/view_tree/tests/BUILD.gn
+++ b/src/ui/scenic/lib/view_tree/tests/BUILD.gn
@@ -2,17 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/components.gni")
-
-group("tests") {
-  testonly = true
-
-  deps = [
-    ":geometry_provider_unittests",
-    ":view_tree_unittests",
-  ]
-}
-
 source_set("common_deps") {
   testonly = true
   sources = [
@@ -61,11 +50,3 @@
     "//zircon/system/ulib/async-testing",
   ]
 }
-
-fuchsia_unittest_package("view_tree_unittests") {
-  deps = [ ":view_tree_test_bin" ]
-}
-
-fuchsia_unittest_package("geometry_provider_unittests") {
-  deps = [ ":geometry_provider_test_bin" ]
-}
diff --git a/src/ui/scenic/meta/scenic_util_tests.cml b/src/ui/scenic/meta/scenic_util_tests.cml
new file mode 100644
index 0000000..d958a05
--- /dev/null
+++ b/src/ui/scenic/meta/scenic_util_tests.cml
@@ -0,0 +1,15 @@
+{
+    include: [
+        "//src/sys/test_manager/system-test.shard.cml",
+        "//src/sys/test_runners/gtest/default.shard.cml",
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/scenic_util_tests",
+    },
+    use: [
+        {
+            protocol: [ "fuchsia.scheduler.ProfileProvider" ],
+        },
+    ],
+}
diff --git a/src/ui/tests/integration_input_tests/touch/touch-gfx-client/touch-gfx-client.cc b/src/ui/tests/integration_input_tests/touch/touch-gfx-client/touch-gfx-client.cc
index 46fc018..e45433f 100644
--- a/src/ui/tests/integration_input_tests/touch/touch-gfx-client/touch-gfx-client.cc
+++ b/src/ui/tests/integration_input_tests/touch/touch-gfx-client/touch-gfx-client.cc
@@ -125,27 +125,23 @@
       } else if (event.is_input()) {
         switch (event.input().Which()) {
           case fuchsia::ui::input::InputEvent::Tag::kPointer: {
-            if (event.input().pointer().phase == fuchsia::ui::input::PointerEventPhase::DOWN &&
-                material_) {
-              {
-                // Cycle to next color.
-                color_index_ = (color_index_ + 1) % kColorsRgba.size();
-                std::array<uint8_t, 4> color = kColorsRgba[color_index_];
-                material_->SetColor(color[0], color[1], color[2], color[3]);
-                session_->Present2(/*when*/ zx_clock_get_monotonic(), /*span*/ 0, [](auto) {});
-              }
-
-              if (response_listener_) {
-                test::touch::PointerData data;
-                // The raw pointer event's coordinates are in pips (logical pixels). The test
-                // expects coordinates in physical pixels. The former is transformed into the latter
-                // with the scale factor provided in the metrics event.
-                data.set_local_x(event.input().pointer().x * metrics_.scale_x)
-                    .set_local_y(event.input().pointer().y * metrics_.scale_y)
-                    .set_time_received(zx_clock_get_monotonic())
-                    .set_component_name("touch-gfx-client");
-                response_listener_->Respond(std::move(data));
-              }
+            const auto& phase = event.input().pointer().phase;
+            if (phase == fuchsia::ui::input::PointerEventPhase::DOWN && material_) {
+              color_index_ = (color_index_ + 1) % kColorsRgba.size();
+              std::array<uint8_t, 4> color = kColorsRgba[color_index_];
+              material_->SetColor(color[0], color[1], color[2], color[3]);
+              session_->Present2(/*when*/ zx_clock_get_monotonic(), /*span*/ 0, [](auto) {});
+            }
+            if (response_listener_) {
+              test::touch::PointerData data;
+              // The raw pointer event's coordinates are in pips (logical pixels). The test
+              // expects coordinates in physical pixels. The former is transformed into the latter
+              // with the scale factor provided in the metrics event.
+              data.set_local_x(event.input().pointer().x * metrics_.scale_x)
+                  .set_local_y(event.input().pointer().y * metrics_.scale_y)
+                  .set_time_received(zx_clock_get_monotonic())
+                  .set_component_name("touch-gfx-client");
+              response_listener_->Respond(std::move(data));
             }
             break;
           }
diff --git a/src/ui/tests/integration_input_tests/touch/touch-input-test-ip.cc b/src/ui/tests/integration_input_tests/touch/touch-input-test-ip.cc
index 7f97178..cbc5822 100644
--- a/src/ui/tests/integration_input_tests/touch/touch-input-test-ip.cc
+++ b/src/ui/tests/integration_input_tests/touch/touch-input-test-ip.cc
@@ -135,6 +135,12 @@
 // Set this as low as you can that still works across all test platforms.
 constexpr zx::duration kTimeout = zx::min(5);
 
+// Maximum distance between two physical pixel coordinates so that they are considered equal.
+constexpr float kEpsilon = 0.5f;
+
+constexpr auto kTouchScreenMaxDim = 1000;
+constexpr auto kTouchScreenMinDim = -1000;
+
 // The type used to measure UTC time. The integer value here does not matter so
 // long as it differs from the ZX_CLOCK_MONOTONIC=0 defined by Zircon.
 using time_utc = zx::basic_time<1>;
@@ -143,6 +149,18 @@
 
 enum class TapLocation { kTopLeft, kTopRight };
 
+enum class SwipeGesture {
+  UP = 1,
+  DOWN,
+  LEFT,
+  RIGHT,
+};
+
+struct ExpectedSwipeEvent {
+  double x = 0, y = 0;
+  zx::time injection_time;
+};
+
 // Combines all vectors in `vecs` into one.
 template <typename T>
 std::vector<T> merge(std::initializer_list<std::vector<T>> vecs) {
@@ -153,6 +171,26 @@
   return result;
 }
 
+// Checks whether all the coordinates in |expected_events| are contained in |actual_events|.
+void AssertSwipeEvents(const std::vector<test::touch::PointerData>& actual_events,
+                       const std::vector<ExpectedSwipeEvent>& expected_events) {
+  FX_DCHECK(actual_events.size() == expected_events.size());
+  for (size_t i = 0; i < actual_events.size(); i++) {
+    const auto& actual_x = actual_events[i].local_x();
+    const auto& actual_y = actual_events[i].local_y();
+    const auto& actual_time_received = actual_events[i].time_received();
+
+    const auto& [expected_x, expected_y, expected_time_received] = expected_events[i];
+
+    auto elapsed_time =
+        zx::basic_time<ZX_CLOCK_MONOTONIC>(actual_time_received) - expected_time_received;
+
+    EXPECT_NEAR(actual_x, expected_x, kEpsilon);
+    EXPECT_NEAR(actual_y, expected_y, kEpsilon);
+    EXPECT_TRUE(elapsed_time.get() > 0 && elapsed_time.get() != ZX_TIME_INFINITE);
+  }
+}
+
 // This component implements the test.touch.ResponseListener protocol
 // and the interface for a RealmBuilder LocalComponent. A LocalComponent
 // is a component that is implemented here in the test, as opposed to elsewhere
@@ -324,8 +362,8 @@
     fuchsia::input::report::Axis axis;
     axis.unit.type = fuchsia::input::report::UnitType::NONE;
     axis.unit.exponent = 0;
-    axis.range.min = -1000;
-    axis.range.max = 1000;
+    axis.range.min = kTouchScreenMinDim;
+    axis.range.max = kTouchScreenMaxDim;
 
     fuchsia::input::report::ContactInputDescriptor contact;
     contact.set_position_x(axis);
@@ -397,6 +435,77 @@
     return RealNow<TimeT>();
   }
 
+  // Inject directly into Input Pipeline, using fuchsia.input.injection FIDLs. A swipe gesture is
+  // mimicked by injecting |swipe_length| touch events across the length of the display, with a
+  // delay of 10 msec. For the fake display used in this test, and swipe_length=N, this results in
+  // events separated by 50 pixels.
+  template <typename TimeT>
+  std::vector<TimeT> InjectSwipe(SwipeGesture direction, int swipe_length, int begin_x,
+                                 int begin_y) {
+    int x_dir = 0, y_dir = 0;
+    switch (direction) {
+      case SwipeGesture::UP:
+        y_dir = -1;
+        break;
+      case SwipeGesture::DOWN:
+        y_dir = 1;
+        break;
+      case SwipeGesture::LEFT:
+        x_dir = -1;
+        break;
+      case SwipeGesture::RIGHT:
+        x_dir = 1;
+        break;
+      default:
+        FX_NOTREACHED();
+    }
+
+    std::vector<TimeT> injection_times;
+
+    // Inject a series of input reports.
+    //
+    // The /config/data/display_rotation (90) specifies how many degrees to rotate the
+    // presentation child view, counter-clockwise, in a right-handed coordinate system. Thus,
+    // the user observes the child view to rotate *clockwise* by that amount (90).
+    //
+    // Hence an upward swipe on the display is observed by the child view as a left swipe in its
+    // coordinate system.
+    std::vector<fuchsia::input::report::InputReport> input_reports;
+    auto touchscreen_width = kTouchScreenMaxDim - kTouchScreenMinDim;
+
+    // Note: The display start and end edges must be included.
+    for (auto i = 0; i <= swipe_length; i++) {
+      auto x = begin_x + x_dir * (touchscreen_width / swipe_length) * i;
+      auto y = begin_y + y_dir * (touchscreen_width / swipe_length) * i;
+
+      fuchsia::input::report::ContactInputReport contact_input_report;
+      contact_input_report.set_contact_id(1);
+      contact_input_report.set_position_x(x);
+      contact_input_report.set_position_y(y);
+
+      fuchsia::input::report::TouchInputReport touch_input_report;
+      auto contacts = touch_input_report.mutable_contacts();
+      contacts->push_back(std::move(contact_input_report));
+
+      fuchsia::input::report::InputReport input_report;
+      input_report.set_touch(std::move(touch_input_report));
+
+      input_reports.push_back(std::move(input_report));
+      injection_times.push_back(RealNow<TimeT>());
+
+      zx::nanosleep(zx::deadline_after(zx::msec(10)));
+      injection_count_++;
+    }
+
+    fuchsia::input::report::TouchInputReport remove_touch_input_report;
+    fuchsia::input::report::InputReport remove_input_report;
+    remove_input_report.set_touch(std::move(remove_touch_input_report));
+    input_reports.push_back(std::move(remove_input_report));
+    fake_input_device_->SetReports(std::move(input_reports));
+
+    return injection_times;
+  }
+
   // Guaranteed to be initialized after SetUp().
   uint32_t display_width() const { return display_width_; }
   uint32_t display_height() const { return display_height_; }
@@ -577,6 +686,174 @@
   RunLoopUntil([&injection_complete] { return injection_complete; });
 }
 
+TEST_F(GfxInputTestIp, CppGFXClientSwipeTest) {
+  // Inject a right swipe on the display. As the child view is rotated by 90 degrees, an upward
+  // swipe is observed by the child view.
+  {
+    const int swipe_length = 40, begin_x = kTouchScreenMinDim, begin_y = 0;
+    std::vector<test::touch::PointerData> actual_events;
+    response_listener()->SetRespondCallback(
+        [&actual_events](auto touch) { actual_events.push_back(std::move(touch)); });
+    auto injection_times = InjectSwipe<zx::basic_time<ZX_CLOCK_MONOTONIC>>(
+        SwipeGesture::RIGHT, swipe_length, begin_x, begin_y);
+
+    //  Client sends a response for every PointerEventPhase event which includes 1 Add, 1 Down,
+    // |swipe_length| Move, 1 Up, 1 Remove.
+    RunLoopUntil([&actual_events] {
+      return actual_events.size() >= static_cast<uint32_t>(swipe_length + 4);
+    });
+
+    std::vector<ExpectedSwipeEvent> expected_events;
+    auto tap_distance = static_cast<double>(display_width()) / static_cast<double>(swipe_length);
+
+    // As the child view is rotated by 90 degrees, a swipe in the middle of the display from
+    // the left edge to the right edge should appear as a swipe in the middle of the screen from the
+    // bottom edge to the top edge.
+    for (double i = static_cast<double>(swipe_length); i >= 0; i--) {
+      expected_events.push_back(
+          {.x = static_cast<double>(display_height()) / 2,
+           .y = i * tap_distance,
+           .injection_time = injection_times[swipe_length - static_cast<int>(i)]});
+    }
+
+    // The |ExpectedSwipeEvent| for Up and Remove PointerEventPhase will be the same as the last
+    // Move event.
+    auto last_touch_event = expected_events.back();
+    expected_events.push_back(last_touch_event);
+    expected_events.push_back(last_touch_event);
+
+    // Remove the first event received as it is a response sent for an Add event.
+    actual_events.erase(actual_events.begin());
+
+    ASSERT_EQ(actual_events.size(), expected_events.size());
+    AssertSwipeEvents(actual_events, expected_events);
+  }
+
+  // Inject a downward swipe on the display. As the child view is rotated by 90 degrees, a right
+  // swipe is observed by the child view.
+  {
+    const int swipe_length = 40, begin_x = 0, begin_y = kTouchScreenMinDim;
+    std::vector<test::touch::PointerData> actual_events;
+    response_listener()->SetRespondCallback(
+        [&actual_events](auto touch) { actual_events.push_back(std::move(touch)); });
+    auto injection_times = InjectSwipe<zx::basic_time<ZX_CLOCK_MONOTONIC>>(
+        SwipeGesture::DOWN, swipe_length, begin_x, begin_y);
+
+    //  Client sends a response for every PointerEventPhase event which includes 1 Add, 1 Down,
+    // |swipe_length| Move, 1 Up, 1 Remove.
+    RunLoopUntil([&actual_events] {
+      return actual_events.size() >= static_cast<uint32_t>(swipe_length + 4);
+    });
+
+    std::vector<ExpectedSwipeEvent> expected_events;
+    auto tap_distance = static_cast<double>(display_height()) / static_cast<double>(swipe_length);
+
+    // As the child view is rotated by 90 degrees, a swipe in the middle of the display from the
+    // top edge to the bottom edge should appear as a swipe in the middle of the screen from the
+    // left edge to the right edge.
+    for (double i = 0; i <= static_cast<double>(swipe_length); i++) {
+      expected_events.push_back({.x = i * tap_distance,
+                                 .y = static_cast<double>(display_width()) / 2,
+                                 .injection_time = injection_times[static_cast<int>(i)]});
+    }
+
+    // The |ExpectedSwipeEvent| for Up and Remove PointerEventPhase will be the same as the last
+    // Move event.
+    auto last_touch_event = expected_events.back();
+    expected_events.push_back(last_touch_event);
+    expected_events.push_back(last_touch_event);
+
+    // Remove the first event received as it is a response sent for an Add event.
+    actual_events.erase(actual_events.begin());
+
+    ASSERT_EQ(actual_events.size(), expected_events.size());
+    AssertSwipeEvents(actual_events, expected_events);
+  }
+
+  // Inject a left swipe on the display. As the child view is rotated by 90 degrees, a downward
+  // swipe is observed by the child view.
+  {
+    const int swipe_length = 40, begin_x = kTouchScreenMaxDim, begin_y = 0;
+    std::vector<test::touch::PointerData> actual_events;
+    response_listener()->SetRespondCallback(
+        [&actual_events](auto touch) { actual_events.push_back(std::move(touch)); });
+    auto injection_times = InjectSwipe<zx::basic_time<ZX_CLOCK_MONOTONIC>>(
+        SwipeGesture::LEFT, swipe_length, begin_x, begin_y);
+
+    //  Client sends a response for every PointerEventPhase event which includes 1 Add, 1 Down,
+    // |swipe_length| Move, 1 Up, 1 Remove.
+    RunLoopUntil([&actual_events] {
+      return actual_events.size() >= static_cast<uint32_t>(swipe_length + 4);
+    });
+
+    std::vector<ExpectedSwipeEvent> expected_events;
+    auto tap_distance = static_cast<double>(display_width()) / static_cast<double>(swipe_length);
+
+    // As the child view is rotated by 90 degrees, a swipe in the middle of the display from the
+    // right edge to the left edge should appear as a swipe in the middle of the screen from the top
+    // edge to the the bottom edge.
+    for (double i = 0; i <= static_cast<double>(swipe_length); i++) {
+      expected_events.push_back({.x = static_cast<double>(display_height()) / 2,
+                                 .y = i * tap_distance,
+                                 .injection_time = injection_times[static_cast<int>(i)]});
+    }
+
+    // The |ExpectedSwipeEvent| for Up and Remove PointerEventPhase will be the same as the last
+    // Move event.
+    auto last_touch_event = expected_events.back();
+    expected_events.push_back(last_touch_event);
+    expected_events.push_back(last_touch_event);
+
+    // Remove the first event received as it is a response sent for an Add event.
+    actual_events.erase(actual_events.begin());
+
+    ASSERT_EQ(actual_events.size(), expected_events.size());
+    AssertSwipeEvents(actual_events, expected_events);
+  }
+
+  // Inject an upward swipe on the display. As the child view is rotated by 90 degrees, a left
+  // swipe is observed by the child view.
+  {
+    const int swipe_length = 40, begin_x = 0, begin_y = kTouchScreenMaxDim;
+    std::vector<test::touch::PointerData> actual_events;
+    response_listener()->SetRespondCallback(
+        [&actual_events](auto touch) { actual_events.push_back(std::move(touch)); });
+    auto injection_times = InjectSwipe<zx::basic_time<ZX_CLOCK_MONOTONIC>>(
+        SwipeGesture::UP, swipe_length, begin_x, begin_y);
+
+    //  Client sends a response for every PointerEventPhase event which includes 1 Add, 1 Down,
+    // |swipe_length| Move, 1 Up, 1 Remove.
+    RunLoopUntil([&actual_events] {
+      return actual_events.size() >= static_cast<uint32_t>(swipe_length + 4);
+    });
+
+    std::vector<ExpectedSwipeEvent> expected_events;
+    auto tap_distance = static_cast<double>(display_height()) / static_cast<double>(swipe_length);
+
+    // As the child view is rotated by 90 degrees, a swipe in the middle of the display from the
+    // bottom edge to the top edge should appear as a swipe in the middle of the screen from the
+    // right edge to the left edge.
+    for (double i = static_cast<double>(swipe_length); i >= 0; i--) {
+      expected_events.push_back(
+          {.x = i * tap_distance,
+           .y = static_cast<double>(display_width()) / 2,
+           .injection_time = injection_times[swipe_length - static_cast<int>(i)]});
+    }
+
+    // The |ExpectedSwipeEvent| for Up and Remove PointerEventPhase will be the same as the last
+    // Move event.
+    auto last_touch_event = expected_events.back();
+    expected_events.push_back(last_touch_event);
+    expected_events.push_back(last_touch_event);
+
+    // Remove the first event received as it is a response sent for an Add event.
+    actual_events.erase(actual_events.begin());
+
+    ASSERT_EQ(actual_events.size(), expected_events.size());
+    AssertSwipeEvents(actual_events, expected_events);
+  }
+}
+
 class WebEngineTestIp : public TouchInputBase {
  protected:
   std::vector<std::pair<ChildName, LegacyUrl>> GetTestComponents() override {
diff --git a/src/virtualization/bin/host_vsock/host_vsock_endpoint.cc b/src/virtualization/bin/host_vsock/host_vsock_endpoint.cc
index 2e3158e..1e44478 100644
--- a/src/virtualization/bin/host_vsock/host_vsock_endpoint.cc
+++ b/src/virtualization/bin/host_vsock/host_vsock_endpoint.cc
@@ -135,6 +135,42 @@
   }
 }
 
+void HostVsockEndpoint::Connect2(
+    uint32_t port, fuchsia::virtualization::HostVsockEndpoint::Connect2Callback callback) {
+  fuchsia::virtualization::GuestVsockAcceptor* acceptor =
+      acceptor_provider_(fuchsia::virtualization::DEFAULT_GUEST_CID);
+  if (acceptor == nullptr) {
+    callback(fpromise::error(ZX_ERR_CONNECTION_REFUSED));
+    return;
+  }
+
+  uint32_t src_port;
+  zx_status_t status = AllocEphemeralPort(&src_port);
+  if (status != ZX_OK) {
+    callback(fpromise::error(status));
+    return;
+  }
+
+  zx::socket client, guest;
+  status = zx::socket::create(ZX_SOCKET_STREAM, &client, &guest);
+  if (status != ZX_OK) {
+    callback(fpromise::error(status));
+    return;
+  }
+
+  auto callback2 = [this, src_port, client = std::move(client), callback = std::move(callback)](
+                       fuchsia::virtualization::GuestVsockAcceptor_Accept_Result result) mutable {
+    if (result.is_response()) {
+      callback(fpromise::ok(std::move(client)));
+    } else {
+      FreeEphemeralPort(src_port);
+      callback(fpromise::error(result.err()));
+    }
+  };
+  acceptor->Accept(fuchsia::virtualization::HOST_CID, src_port, port, std::move(guest),
+                   std::move(callback2));
+}
+
 void HostVsockEndpoint::OnShutdown(uint32_t port) {
   // If there are no listeners for this port then it was ephemeral and should
   // free it.
diff --git a/src/virtualization/bin/host_vsock/host_vsock_endpoint.h b/src/virtualization/bin/host_vsock/host_vsock_endpoint.h
index fab6276..1462585 100644
--- a/src/virtualization/bin/host_vsock/host_vsock_endpoint.h
+++ b/src/virtualization/bin/host_vsock/host_vsock_endpoint.h
@@ -50,6 +50,8 @@
               ListenCallback callback) override;
   void Connect(uint32_t cid, uint32_t port, zx::socket socket,
                fuchsia::virtualization::HostVsockEndpoint::ConnectCallback callback) override;
+  void Connect2(uint32_t port,
+                fuchsia::virtualization::HostVsockEndpoint::Connect2Callback callback) override;
 
   void OnShutdown(uint32_t port);
 
diff --git a/src/virtualization/bin/host_vsock/host_vsock_endpoint_unittest.cc b/src/virtualization/bin/host_vsock/host_vsock_endpoint_unittest.cc
index 9fa4f05..1aa6def 100644
--- a/src/virtualization/bin/host_vsock/host_vsock_endpoint_unittest.cc
+++ b/src/virtualization/bin/host_vsock/host_vsock_endpoint_unittest.cc
@@ -18,6 +18,7 @@
 using ::fuchsia::virtualization::HostVsockAcceptor_Accept_Response;
 using ::fuchsia::virtualization::HostVsockAcceptor_Accept_Result;
 using ::fuchsia::virtualization::HostVsockConnector_Connect_Result;
+using ::fuchsia::virtualization::HostVsockEndpoint_Connect2_Result;
 using ::fuchsia::virtualization::HostVsockEndpoint_Connect_Result;
 using ::fuchsia::virtualization::HostVsockEndpoint_Listen_Result;
 
@@ -85,6 +86,7 @@
 
 struct TestEndpointConnection {
   zx_status_t status = ZX_ERR_BAD_STATE;
+  zx::socket socket;
 
   fuchsia::virtualization::HostVsockEndpoint::ConnectCallback connect_callback() {
     return [this](HostVsockEndpoint_Connect_Result result) {
@@ -92,6 +94,17 @@
     };
   }
 
+  fuchsia::virtualization::HostVsockEndpoint::Connect2Callback connect2_callback() {
+    return [this](HostVsockEndpoint_Connect2_Result result) {
+      if (result.is_response()) {
+        this->status = ZX_OK;
+        this->socket = std::move(result.response().socket);
+      } else {
+        this->status = result.err();
+      }
+    };
+  }
+
   fuchsia::virtualization::HostVsockEndpoint::ListenCallback listen_callback() {
     return [this](HostVsockEndpoint_Listen_Result result) {
       this->status = result.is_response() ? ZX_OK : result.err();
@@ -178,6 +191,23 @@
   EXPECT_EQ(ZX_OK, connection.status);
 }
 
+TEST_F(HostVsockEndpointTest, Connect2HostToGuest) {
+  TestEndpointConnection connection;
+  host_endpoint_.Connect2(22, connection.connect2_callback());
+
+  auto requests = guest_acceptor_.TakeRequests();
+  ASSERT_EQ(1u, requests.size());
+  EXPECT_EQ(fuchsia::virtualization::HOST_CID, requests[0].src_cid);
+  EXPECT_EQ(kFirstEphemeralPort, requests[0].src_port);
+  EXPECT_EQ(22u, requests[0].port);
+  EXPECT_TRUE(requests[0].socket.is_valid());
+
+  requests[0].callback(fpromise::ok());
+
+  EXPECT_EQ(ZX_OK, connection.status);
+  EXPECT_TRUE(connection.socket.is_valid());
+}
+
 TEST_F(HostVsockEndpointTest, ConnectHostToHost) {
   zx::socket h1, h2;
   ASSERT_EQ(ZX_OK, zx::socket::create(ZX_SOCKET_STREAM, &h1, &h2));
@@ -257,8 +287,6 @@
   }
 }
 
-namespace {
-
 // Open a connection from the host to the given guest on the given port.
 zx::socket OpenConnectionToGuest(HostVsockEndpoint* host_endpoint, uint32_t cid, uint32_t port) {
   // Create a socket.
@@ -271,8 +299,6 @@
   return host_end;
 }
 
-}  // namespace
-
 TEST_F(HostVsockEndpointTest, ConnectHostToGuestFreeEphemeralPort) {
   // Open two connections.
   zx::socket first = OpenConnectionToGuest(&host_endpoint_, /*cid=*/kGuestCid, /*port=*/22);
diff --git a/third_party/golibs/go.mod b/third_party/golibs/go.mod
index 9fc23bc..918602d 100644
--- a/third_party/golibs/go.mod
+++ b/third_party/golibs/go.mod
@@ -36,5 +36,5 @@
 	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
 	google.golang.org/protobuf v1.27.1
 	gopkg.in/yaml.v2 v2.4.0
-	gvisor.dev/gvisor v0.0.0-20220509173753-e2136489dfb7
+	gvisor.dev/gvisor v0.0.0-20220513212916-a23dc0715d38
 )
diff --git a/third_party/golibs/go.sum b/third_party/golibs/go.sum
index e9aa4947..974dd15 100644
--- a/third_party/golibs/go.sum
+++ b/third_party/golibs/go.sum
@@ -930,8 +930,8 @@
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
-gvisor.dev/gvisor v0.0.0-20220509173753-e2136489dfb7 h1:OkTbtUFPjlyZh4IUNJzuxBSx8HZmElZ9p8EUVjiKEn4=
-gvisor.dev/gvisor v0.0.0-20220509173753-e2136489dfb7/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI=
+gvisor.dev/gvisor v0.0.0-20220513212916-a23dc0715d38 h1:a4PsEqiJG7UmtAMcEtxgLcscq49mqpjZgBAi82+2Y1c=
+gvisor.dev/gvisor v0.0.0-20220513212916-a23dc0715d38/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/loopback/loopback.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/loopback/loopback.go
index 72e6dc1..fcebdc8 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/loopback/loopback.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/loopback/loopback.go
@@ -22,7 +22,6 @@
 
 import (
 	"gvisor.dev/gvisor/pkg/tcpip"
-	"gvisor.dev/gvisor/pkg/tcpip/buffer"
 	"gvisor.dev/gvisor/pkg/tcpip/header"
 	"gvisor.dev/gvisor/pkg/tcpip/stack"
 )
@@ -77,8 +76,11 @@
 // WritePackets implements stack.LinkEndpoint.WritePackets.
 func (e *endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) {
 	for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
+		// In order to properly loop back to the inbound side we must create a
+		// fresh packet that only contains the underlying payload with no headers
+		// or struct fields set.
 		newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
-			Data: buffer.NewVectorisedView(pkt.Size(), pkt.Views()),
+			Payload: pkt.Buffer(),
 		})
 		e.dispatcher.DeliverNetworkPacket(pkt.NetworkProtocolNumber, newPkt)
 		newPkt.DecRef()
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/pipe/pipe.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/pipe/pipe.go
index e95f8b9..cb98797 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/pipe/pipe.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/pipe/pipe.go
@@ -18,7 +18,6 @@
 
 import (
 	"gvisor.dev/gvisor/pkg/tcpip"
-	"gvisor.dev/gvisor/pkg/tcpip/buffer"
 	"gvisor.dev/gvisor/pkg/tcpip/header"
 	"gvisor.dev/gvisor/pkg/tcpip/stack"
 )
@@ -54,8 +53,11 @@
 	}
 
 	for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() {
+		// Create a fresh packet with pkt's payload but without struct fields
+		// or headers set so the next link protocol can properly set the link
+		// header.
 		newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
-			Data: buffer.NewVectorisedView(pkt.Size(), pkt.Views()),
+			Payload: pkt.Buffer(),
 		})
 		e.linked.dispatcher.DeliverNetworkPacket(pkt.NetworkProtocolNumber, newPkt)
 		newPkt.DecRef()
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/sniffer.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/sniffer.go
index 36c0ac9..cd72c9ba5 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/sniffer.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/link/sniffer/sniffer.go
@@ -29,7 +29,6 @@
 	"gvisor.dev/gvisor/pkg/atomicbitops"
 	"gvisor.dev/gvisor/pkg/log"
 	"gvisor.dev/gvisor/pkg/tcpip"
-	"gvisor.dev/gvisor/pkg/tcpip/buffer"
 	"gvisor.dev/gvisor/pkg/tcpip/header"
 	"gvisor.dev/gvisor/pkg/tcpip/header/parse"
 	"gvisor.dev/gvisor/pkg/tcpip/link/nested"
@@ -194,10 +193,10 @@
 	//
 	// We trim the link headers from the cloned buffer as the sniffer doesn't
 	// handle link headers.
-	vv := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
-	vv.TrimFront(len(pkt.VirtioNetHeader().View()))
-	vv.TrimFront(len(pkt.LinkHeader().View()))
-	pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{Data: vv})
+	buf := pkt.Buffer()
+	buf.TrimFront(int64(len(pkt.VirtioNetHeader().View())))
+	buf.TrimFront(int64(len(pkt.LinkHeader().View())))
+	pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: buf})
 	defer pkt.DecRef()
 	switch protocol {
 	case header.IPv4ProtocolNumber:
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables.go
index a5f9049..9860acb 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables.go
@@ -273,6 +273,13 @@
 //
 // If IPTables should not be skipped, tables will be updated with the
 // specified table.
+//
+// This is called in the hot path even when iptables are disabled, so we ensure
+// it does not allocate. We check recursively for heap allocations, but not for:
+//   - Stack splitting, which can allocate.
+//   - Calls to interfaces, which can allocate.
+//   - Calls to dynamic functions, which can allocate.
+// +checkescape:hard
 func (it *IPTables) shouldSkipOrPopulateTables(tables []checkTable, pkt *PacketBuffer) bool {
 	switch pkt.NetworkProtocolNumber {
 	case header.IPv4ProtocolNumber, header.IPv6ProtocolNumber:
@@ -303,14 +310,19 @@
 // must be dropped if false is returned.
 //
 // Precondition: The packet's network and transport header must be set.
+//
+// This is called in the hot path even when iptables are disabled, so we ensure
+// that it does not allocate. Note that called functions (e.g.
+// getConnAndUpdate) can allocate.
+// +checkescape
 func (it *IPTables) CheckPrerouting(pkt *PacketBuffer, addressEP AddressableEndpoint, inNicName string) bool {
 	tables := [...]checkTable{
 		{
-			fn:      it.check,
+			fn:      check,
 			tableID: MangleID,
 		},
 		{
-			fn:      it.checkNAT,
+			fn:      checkNAT,
 			tableID: NATID,
 		},
 	}
@@ -322,7 +334,7 @@
 	pkt.tuple = it.connections.getConnAndUpdate(pkt)
 
 	for _, table := range tables {
-		if !table.fn(table.table, Prerouting, pkt, nil /* route */, addressEP, inNicName, "" /* outNicName */) {
+		if !table.fn(it, table.table, Prerouting, pkt, nil /* route */, addressEP, inNicName, "" /* outNicName */) {
 			return false
 		}
 	}
@@ -336,14 +348,19 @@
 // must be dropped if false is returned.
 //
 // Precondition: The packet's network and transport header must be set.
+//
+// This is called in the hot path even when iptables are disabled, so we ensure
+// that it does not allocate. Note that called functions (e.g.
+// getConnAndUpdate) can allocate.
+// +checkescape
 func (it *IPTables) CheckInput(pkt *PacketBuffer, inNicName string) bool {
 	tables := [...]checkTable{
 		{
-			fn:      it.checkNAT,
+			fn:      checkNAT,
 			tableID: NATID,
 		},
 		{
-			fn:      it.check,
+			fn:      check,
 			tableID: FilterID,
 		},
 	}
@@ -353,7 +370,7 @@
 	}
 
 	for _, table := range tables {
-		if !table.fn(table.table, Input, pkt, nil /* route */, nil /* addressEP */, inNicName, "" /* outNicName */) {
+		if !table.fn(it, table.table, Input, pkt, nil /* route */, nil /* addressEP */, inNicName, "" /* outNicName */) {
 			return false
 		}
 	}
@@ -371,10 +388,15 @@
 // must be dropped if false is returned.
 //
 // Precondition: The packet's network and transport header must be set.
+//
+// This is called in the hot path even when iptables are disabled, so we ensure
+// that it does not allocate. Note that called functions (e.g.
+// getConnAndUpdate) can allocate.
+// +checkescape
 func (it *IPTables) CheckForward(pkt *PacketBuffer, inNicName, outNicName string) bool {
 	tables := [...]checkTable{
 		{
-			fn:      it.check,
+			fn:      check,
 			tableID: FilterID,
 		},
 	}
@@ -384,7 +406,7 @@
 	}
 
 	for _, table := range tables {
-		if !table.fn(table.table, Forward, pkt, nil /* route */, nil /* addressEP */, inNicName, outNicName) {
+		if !table.fn(it, table.table, Forward, pkt, nil /* route */, nil /* addressEP */, inNicName, outNicName) {
 			return false
 		}
 	}
@@ -398,18 +420,23 @@
 // must be dropped if false is returned.
 //
 // Precondition: The packet's network and transport header must be set.
+//
+// This is called in the hot path even when iptables are disabled, so we ensure
+// that it does not allocate. Note that called functions (e.g.
+// getConnAndUpdate) can allocate.
+// +checkescape
 func (it *IPTables) CheckOutput(pkt *PacketBuffer, r *Route, outNicName string) bool {
 	tables := [...]checkTable{
 		{
-			fn:      it.check,
+			fn:      check,
 			tableID: MangleID,
 		},
 		{
-			fn:      it.checkNAT,
+			fn:      checkNAT,
 			tableID: NATID,
 		},
 		{
-			fn:      it.check,
+			fn:      check,
 			tableID: FilterID,
 		},
 	}
@@ -421,7 +448,7 @@
 	pkt.tuple = it.connections.getConnAndUpdate(pkt)
 
 	for _, table := range tables {
-		if !table.fn(table.table, Output, pkt, r, nil /* addressEP */, "" /* inNicName */, outNicName) {
+		if !table.fn(it, table.table, Output, pkt, r, nil /* addressEP */, "" /* inNicName */, outNicName) {
 			return false
 		}
 	}
@@ -435,14 +462,19 @@
 // must be dropped if false is returned.
 //
 // Precondition: The packet's network and transport header must be set.
+//
+// This is called in the hot path even when iptables are disabled, so we ensure
+// that it does not allocate. Note that called functions (e.g.
+// getConnAndUpdate) can allocate.
+// +checkescape
 func (it *IPTables) CheckPostrouting(pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, outNicName string) bool {
 	tables := [...]checkTable{
 		{
-			fn:      it.check,
+			fn:      check,
 			tableID: MangleID,
 		},
 		{
-			fn:      it.checkNAT,
+			fn:      checkNAT,
 			tableID: NATID,
 		},
 	}
@@ -452,7 +484,7 @@
 	}
 
 	for _, table := range tables {
-		if !table.fn(table.table, Postrouting, pkt, r, addressEP, "" /* inNicName */, outNicName) {
+		if !table.fn(it, table.table, Postrouting, pkt, r, addressEP, "" /* inNicName */, outNicName) {
 			return false
 		}
 	}
@@ -464,7 +496,13 @@
 	return true
 }
 
-type checkTableFn func(table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool
+// Note: this used to omit the *IPTables parameter, but doing so caused
+// unnecessary allocations.
+type checkTableFn func(it *IPTables, table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool
+
+func checkNAT(it *IPTables, table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool {
+	return it.checkNAT(table, hook, pkt, r, addressEP, inNicName, outNicName)
+}
 
 // checkNAT runs the packet through the NAT table.
 //
@@ -507,6 +545,10 @@
 	return true
 }
 
+func check(it *IPTables, table Table, hook Hook, pkt *PacketBuffer, r *Route, addressEP AddressableEndpoint, inNicName, outNicName string) bool {
+	return it.check(table, hook, pkt, r, addressEP, inNicName, outNicName)
+}
+
 // check runs the packet through the rules in the specified table for the
 // hook. It returns true if the packet should continue to traverse through the
 // network stack or tables, or false when it must be dropped.
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_types.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_types.go
index d77ed1c..97f9e1f 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_types.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/iptables_types.go
@@ -17,8 +17,8 @@
 import (
 	"fmt"
 	"strings"
-	"sync"
 
+	"gvisor.dev/gvisor/pkg/sync"
 	"gvisor.dev/gvisor/pkg/tcpip"
 	"gvisor.dev/gvisor/pkg/tcpip/header"
 )
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic.go
index 7f70294..c805f74 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic.go
@@ -394,6 +394,9 @@
 
 func (n *nic) writeRawPacket(pkt *PacketBuffer) tcpip.Error {
 	if err := n.qDisc.WritePacket(pkt); err != nil {
+		if _, ok := err.(*tcpip.ErrNoBufferSpace); ok {
+			n.stats.txPacketsDroppedNoBufferSpace.Increment()
+		}
 		return err
 	}
 
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_stats.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_stats.go
index 89aa951..e94ea57 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_stats.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/nic_stats.go
@@ -56,6 +56,7 @@
 	unknownL4ProtocolRcvdPacketCounts tcpip.MultiIntegralStatCounterMap
 	malformedL4RcvdPackets            tcpip.MultiCounterStat
 	tx                                multiCounterNICPacketStats
+	txPacketsDroppedNoBufferSpace     tcpip.MultiCounterStat
 	rx                                multiCounterNICPacketStats
 	disabledRx                        multiCounterNICPacketStats
 	neighbor                          multiCounterNICNeighborStats
@@ -66,6 +67,7 @@
 	m.unknownL4ProtocolRcvdPacketCounts.Init(a.UnknownL4ProtocolRcvdPacketCounts, b.UnknownL4ProtocolRcvdPacketCounts)
 	m.malformedL4RcvdPackets.Init(a.MalformedL4RcvdPackets, b.MalformedL4RcvdPackets)
 	m.tx.init(&a.Tx, &b.Tx)
+	m.txPacketsDroppedNoBufferSpace.Init(a.TxPacketsDroppedNoBufferSpace, b.TxPacketsDroppedNoBufferSpace)
 	m.rx.init(&a.Rx, &b.Rx)
 	m.disabledRx.init(&a.DisabledRx, &b.DisabledRx)
 	m.neighbor.init(&a.Neighbor, &b.Neighbor)
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer.go
index 6a037f8..c127771 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/stack/packet_buffer.go
@@ -286,6 +286,7 @@
 }
 
 // Views returns the underlying storage of the whole packet.
+// TODO(b/230896518): Remove this.
 func (pk *PacketBuffer) Views() []tcpipbuffer.View {
 	var views []tcpipbuffer.View
 	offset := pk.headerOffset()
@@ -295,6 +296,23 @@
 	return views
 }
 
+// Slices returns the underlying storage of the whole packet.
+func (pk *PacketBuffer) Slices() [][]byte {
+	var views [][]byte
+	offset := pk.headerOffset()
+	pk.buf.SubApply(offset, int(pk.buf.Size())-offset, func(v []byte) {
+		views = append(views, v)
+	})
+	return views
+}
+
+// Buffer returns the underlying storage of the whole packet.
+func (pk *PacketBuffer) Buffer() buffer.Buffer {
+	b := pk.buf.Clone()
+	b.TrimFront(int64(pk.headerOffset()))
+	return b
+}
+
 func (pk *PacketBuffer) headerOffset() int {
 	return pk.reserved - pk.pushed
 }
@@ -565,6 +583,15 @@
 	return views
 }
 
+// AsBuffer returns the underlying storage of d in a buffer.Buffer. Caller
+// should not modify the returned buffer.
+func (d PacketData) AsBuffer() buffer.Buffer {
+	buf := d.pk.buf.Clone()
+	offset := d.pk.dataOffset()
+	buf.TrimFront(int64(offset))
+	return buf
+}
+
 // AppendView appends v into d, taking the ownership of v.
 func (d PacketData) AppendView(v tcpipbuffer.View) {
 	d.pk.buf.AppendOwned(v)
diff --git a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go
index 11dae0c..f125c7f 100644
--- a/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go
+++ b/third_party/golibs/vendor/gvisor.dev/gvisor/pkg/tcpip/tcpip.go
@@ -71,9 +71,9 @@
 	nanoseconds int64
 }
 
-// Nanoseconds returns the monotonic time in nanoseconds.
-func (mt MonotonicTime) Nanoseconds() int64 {
-	return mt.nanoseconds
+// String implements Stringer.
+func (mt MonotonicTime) String() string {
+	return strconv.FormatInt(mt.nanoseconds, 10)
 }
 
 // Before reports whether the monotonic clock reading mt is before u.
@@ -2103,6 +2103,13 @@
 	// Tx contains statistics about transmitted packets.
 	Tx NICPacketStats
 
+	// TxPacketsDroppedNoBufferSpace is the number of packets dropepd due to the
+	// NIC not having enough buffer space to send the packet.
+	//
+	// Packets may be dropped with a no buffer space error when the device TX
+	// queue is full.
+	TxPacketsDroppedNoBufferSpace *StatCounter
+
 	// Rx contains statistics about received packets.
 	Rx NICPacketStats
 
diff --git a/third_party/golibs/vendor/modules.txt b/third_party/golibs/vendor/modules.txt
index d96cd6d..60a60a3 100644
--- a/third_party/golibs/vendor/modules.txt
+++ b/third_party/golibs/vendor/modules.txt
@@ -356,7 +356,7 @@
 # gopkg.in/yaml.v2 v2.4.0
 ## explicit
 gopkg.in/yaml.v2
-# gvisor.dev/gvisor v0.0.0-20220509173753-e2136489dfb7
+# gvisor.dev/gvisor v0.0.0-20220513212916-a23dc0715d38
 ## explicit
 gvisor.dev/gvisor/pkg/atomicbitops
 gvisor.dev/gvisor/pkg/buffer
diff --git a/tools/build/test_list.go b/tools/build/test_list.go
index 7c1a82e..da1cc14 100644
--- a/tools/build/test_list.go
+++ b/tools/build/test_list.go
@@ -5,6 +5,7 @@
 package build
 
 import (
+	"fmt"
 	"os"
 
 	"go.fuchsia.dev/fuchsia/tools/lib/jsonutil"
@@ -13,9 +14,12 @@
 // TestList contains the list of tests in the build along with
 // arbitrary test metadata.
 type TestList struct {
-	Tests []TestListEntry `json:"tests,omitempty"`
+	Data     []TestListEntry `json:"data,omitempty"`
+	SchemaID string          `json:"schema_id"`
 }
 
+const TestListSchemaIDExperimental string = "experimental"
+
 // TestListEntry is an entry in the test-list.json.
 // See //src/lib/testing/test_list/src/lib.rs.
 type TestListEntry struct {
@@ -58,8 +62,12 @@
 		return nil, err
 	}
 
+	if testList.SchemaID != TestListSchemaIDExperimental {
+		return nil, fmt.Errorf(`"schema_id" must be %q, found %q`, TestListSchemaIDExperimental, testList.SchemaID)
+	}
+
 	m := make(map[string]TestListEntry)
-	for _, entry := range testList.Tests {
+	for _, entry := range testList.Data {
 		m[entry.Name] = entry
 	}
 	return m, nil
diff --git a/tools/build/test_list_test.go b/tools/build/test_list_test.go
index d9f957a..b23268d 100644
--- a/tools/build/test_list_test.go
+++ b/tools/build/test_list_test.go
@@ -14,7 +14,8 @@
 
 func TestLoadTestList(t *testing.T) {
 	manifest := `{
-	  "tests": [
+	  "schema_id": "experimental",
+	  "data": [
 	    {
 	      "name": "fuchsia-pkg://fuchsia.com/fuchsia_pkg#meta/component1.cmx",
 	      "labels": [
@@ -77,3 +78,62 @@
 		t.Fatalf("got test list: %#v\n\nexpected: %#v", testListEntries, expected)
 	}
 }
+
+func TestLoadTestListVersionMismatch(t *testing.T) {
+	manifest := `{
+	  "schema_id": "1234",
+	  "data": [
+	    {
+	      "name": "fuchsia-pkg://fuchsia.com/fuchsia_pkg#meta/component1.cmx",
+	      "labels": [
+	        "//garnet/bin/fuchsia:fuchsia_pkg_test_component1(//build/toolchain/fuchsia:x64)"
+	      ],
+	      "tags": [
+	        {
+	          "key": "key",
+	          "value": "value"
+	        }
+	      ]
+	    }
+	  ]
+	}`
+	testListPath := filepath.Join(t.TempDir(), "test-list.json")
+	ioutil.WriteFile(testListPath, []byte(manifest), os.ModePerm)
+	_, err := LoadTestList(testListPath)
+	if err == nil {
+		t.Fatalf("expected an error loading an unknown schema_id")
+	}
+	expected := `"schema_id" must be "experimental", found "1234"`
+	if err.Error() != expected {
+		t.Fatalf("got error '%s', expected '%s'", err, expected)
+	}
+}
+
+func TestLoadTestListVersionMissing(t *testing.T) {
+	manifest := `{
+	  "data": [
+	    {
+	      "name": "fuchsia-pkg://fuchsia.com/fuchsia_pkg#meta/component1.cmx",
+	      "labels": [
+	        "//garnet/bin/fuchsia:fuchsia_pkg_test_component1(//build/toolchain/fuchsia:x64)"
+	      ],
+	      "tags": [
+	        {
+	          "key": "key",
+	          "value": "value"
+	        }
+	      ]
+	    }
+	  ]
+	}`
+	testListPath := filepath.Join(t.TempDir(), "test-list.json")
+	ioutil.WriteFile(testListPath, []byte(manifest), os.ModePerm)
+	_, err := LoadTestList(testListPath)
+	if err == nil {
+		t.Fatalf("expected an error loading a missing schema_id")
+	}
+	expected := `"schema_id" must be "experimental", found ""`
+	if err.Error() != expected {
+		t.Fatalf(`got error %q, expected %q`, err, expected)
+	}
+}
diff --git a/tools/check-licenses/license/patterns/approved/Copyright/mit.lic b/tools/check-licenses/license/patterns/approved/Copyright/mit.lic
new file mode 100644
index 0000000..7e55956
--- /dev/null
+++ b/tools/check-licenses/license/patterns/approved/Copyright/mit.lic
@@ -0,0 +1 @@
+\A Copyright [\d]{4} by the Massachusetts Institute of Technology $
diff --git a/tools/cmc/BUILD.gn b/tools/cmc/BUILD.gn
index c252770..8ef35ed 100644
--- a/tools/cmc/BUILD.gn
+++ b/tools/cmc/BUILD.gn
@@ -99,7 +99,6 @@
   restricted_features = [
     "services",
     "dynamic_offers",
-    "structured_config",
     "allow_long_names",
   ]
   component_name = "example"
diff --git a/tools/cmc/build/cml.gni b/tools/cmc/build/cml.gni
index 331a07c..804ff4b 100644
--- a/tools/cmc/build/cml.gni
+++ b/tools/cmc/build/cml.gni
@@ -125,7 +125,10 @@
     #
     # Useful for features which we want to allow globally in tree but
     # restrict out of tree.
-    restricted_features += [ "hub" ]
+    restricted_features += [
+      "hub",
+      "structured_config",
+    ]
 
     # Opt-in to the requested restricted_features.
     args += [ "--features" ] + restricted_features
diff --git a/tools/cmc/build/restricted_features/BUILD.gn b/tools/cmc/build/restricted_features/BUILD.gn
index 1d54429..7042ec1 100644
--- a/tools/cmc/build/restricted_features/BUILD.gn
+++ b/tools/cmc/build/restricted_features/BUILD.gn
@@ -30,63 +30,8 @@
 }
 
 # The allowlist of components that can use the "structured_config" feature in CML.
-# This allowlist is temporary and will be removed once the interfaces between structured
-# configuration clients and the framework is mature. Clients in this list may need some
-# refactoring as structured configuration is fully productionized.
 group("structured_config") {
-  visibility = [
-    # components
-    "//examples/assembly/structured_config/*",
-    "//examples/components/config/cpp:*",
-    "//examples/components/config/rust:*",
-    "//sdk/lib/sys/component/cpp/tests:*",
-    "//src/bringup/bin/console:*",
-    "//src/connectivity/wlan/wlanstack:*",
-    "//src/diagnostics/archivist:*",
-    "//src/diagnostics/archivist/tests/v2:*",
-    "//src/diagnostics/detect:*",
-    "//src/diagnostics/sampler:*",
-    "//src/identity/bin/password_authenticator:*",
-    "//src/proc/bin/galaxies/stardroid:*",
-    "//src/proc/bin/galaxies/stardroid_test:*",
-    "//src/proc/bin/galaxies/starless:*",
-    "//src/proc/bin/galaxies/starmium:*",
-    "//src/proc/bin/galaxies/starmium_test:*",
-    "//src/proc/bin/starnix:*",
-    "//src/session/bin/session_manager:*",
-    "//src/storage/fshost:*",
-    "//src/ui/bin/brightness_manager:*",
-
-    # locations where assemble_system() (transitively) invokes generated_fshost_config()
-    # (generating an fshost configuration file requires access to a compiled manifest, which
-    # must be defined in the same file as the generated values)
-    "//build/images/*",
-    "//src/security/ffx_test:*",
-    "//src/security/pkg_test/tests:*",
-    "//third_party/network-conformance/images:*",
-    "//vendor/google/build/pre_migration:*",
-    "//vendor/google/build/recovery:*",
-    "//vendor/google/build/reverse_migration:*",
-
-    # locations where session_manager_package() is invoked:
-    "//src/experiences/session_shells/ermine/session:*",
-    "//src/session/examples/hello-world-session:*",
-    "//vendor/google/sessions:*",
-
-    # tests
-    "//src/lib/assembly/structured_config/tests/*:*",
-    "//src/lib/component_hub/tests:*",
-    "//src/lib/fuchsia-component-test/tests/echo_client_sc:*",
-    "//src/sys/component_manager/tests/hub:*",
-    "//src/sys/component_manager/tests/structured_config/client_integration/cpp_driver:*",
-    "//src/sys/component_manager/tests/structured_config/client_integration/cpp_elf:*",
-    "//src/sys/component_manager/tests/structured_config/client_integration/rust:*",
-    "//src/sys/component_manager/tests/structured_config/different_values:*",
-    "//src/sys/pkg/bin/omaha-client:*",
-    "//src/tests/assembly/structured_config/*",
-    "//tools/cmc:*",
-    "//tools/configc:*",
-  ]
+  # Available to all components in fuchsia.git
 }
 
 # The allowlist of components that can use the "hub" feature in CML.
diff --git a/tools/configc/BUILD.gn b/tools/configc/BUILD.gn
index 02acfce..99d7ae4 100644
--- a/tools/configc/BUILD.gn
+++ b/tools/configc/BUILD.gn
@@ -48,7 +48,6 @@
 cm("config_manifest") {
   manifest = "goldens/config_manifest.cml"
   output_name = "config_manifest.cm"
-  restricted_features = [ "structured_config" ]
   config_values_package_path = "goldens/config_values.json5"
 }
 
diff --git a/tools/configc/goldens/config.cc.driver.golden b/tools/configc/goldens/config.cc.driver.golden
index 1b96cdf..b913478 100644
--- a/tools/configc/goldens/config.cc.driver.golden
+++ b/tools/configc/goldens/config.cc.driver.golden
@@ -18,100 +18,78 @@
 
 namespace cpp_driver_config_lib {
 
-void Config::record_to_inspect(inspect::Inspector* inspector) {
-  inspect::Node inspect_config = inspector->GetRoot().CreateChild("config");
-  inspect_config.CreateBool("my_flag", this->my_flag(), inspector);
-
-  inspect_config.CreateInt("my_int16", this->my_int16(), inspector);
-
-  inspect_config.CreateInt("my_int32", this->my_int32(), inspector);
-
-  inspect_config.CreateInt("my_int64", this->my_int64(), inspector);
-
-  inspect_config.CreateInt("my_int8", this->my_int8(), inspector);
-
-  inspect_config.CreateString("my_string", this->my_string(), inspector);
-
-  inspect_config.CreateUint("my_uint16", this->my_uint16(), inspector);
-
-  inspect_config.CreateUint("my_uint32", this->my_uint32(), inspector);
-
-  inspect_config.CreateUint("my_uint64", this->my_uint64(), inspector);
-
-  inspect_config.CreateUint("my_uint8", this->my_uint8(), inspector);
-
-  auto my_vector_of_flag = inspect_config.CreateUintArray(
+void Config::RecordInspect(inspect::Node* node) {
+  node->RecordBool("my_flag", this->my_flag());
+  node->RecordInt("my_int16", this->my_int16());
+  node->RecordInt("my_int32", this->my_int32());
+  node->RecordInt("my_int64", this->my_int64());
+  node->RecordInt("my_int8", this->my_int8());
+  node->RecordString("my_string", this->my_string());
+  node->RecordUint("my_uint16", this->my_uint16());
+  node->RecordUint("my_uint32", this->my_uint32());
+  node->RecordUint("my_uint64", this->my_uint64());
+  node->RecordUint("my_uint8", this->my_uint8());
+  auto my_vector_of_flag_array_ = node->CreateUintArray(
       "my_vector_of_flag", this->my_vector_of_flag().size());
   for (size_t i = 0; i < this->my_vector_of_flag().size(); i++) {
-    my_vector_of_flag.Set(i, this->my_vector_of_flag()[i]);
+    my_vector_of_flag_array_.Set(i, this->my_vector_of_flag()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_flag));
-
-  auto my_vector_of_int16 = inspect_config.CreateIntArray(
+  node->Record(std::move(my_vector_of_flag_array_));
+  auto my_vector_of_int16_array_ = node->CreateIntArray(
       "my_vector_of_int16", this->my_vector_of_int16().size());
   for (size_t i = 0; i < this->my_vector_of_int16().size(); i++) {
-    my_vector_of_int16.Set(i, this->my_vector_of_int16()[i]);
+    my_vector_of_int16_array_.Set(i, this->my_vector_of_int16()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_int16));
-
-  auto my_vector_of_int32 = inspect_config.CreateIntArray(
+  node->Record(std::move(my_vector_of_int16_array_));
+  auto my_vector_of_int32_array_ = node->CreateIntArray(
       "my_vector_of_int32", this->my_vector_of_int32().size());
   for (size_t i = 0; i < this->my_vector_of_int32().size(); i++) {
-    my_vector_of_int32.Set(i, this->my_vector_of_int32()[i]);
+    my_vector_of_int32_array_.Set(i, this->my_vector_of_int32()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_int32));
-
-  auto my_vector_of_int64 = inspect_config.CreateIntArray(
+  node->Record(std::move(my_vector_of_int32_array_));
+  auto my_vector_of_int64_array_ = node->CreateIntArray(
       "my_vector_of_int64", this->my_vector_of_int64().size());
   for (size_t i = 0; i < this->my_vector_of_int64().size(); i++) {
-    my_vector_of_int64.Set(i, this->my_vector_of_int64()[i]);
+    my_vector_of_int64_array_.Set(i, this->my_vector_of_int64()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_int64));
-
-  auto my_vector_of_int8 = inspect_config.CreateIntArray(
+  node->Record(std::move(my_vector_of_int64_array_));
+  auto my_vector_of_int8_array_ = node->CreateIntArray(
       "my_vector_of_int8", this->my_vector_of_int8().size());
   for (size_t i = 0; i < this->my_vector_of_int8().size(); i++) {
-    my_vector_of_int8.Set(i, this->my_vector_of_int8()[i]);
+    my_vector_of_int8_array_.Set(i, this->my_vector_of_int8()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_int8));
-
-  auto my_vector_of_string = inspect_config.CreateStringArray(
+  node->Record(std::move(my_vector_of_int8_array_));
+  auto my_vector_of_string_array_ = node->CreateStringArray(
       "my_vector_of_string", this->my_vector_of_string().size());
   for (size_t i = 0; i < this->my_vector_of_string().size(); i++) {
     auto ref = std::string_view(this->my_vector_of_string()[i].data());
-    my_vector_of_string.Set(i, ref);
+    my_vector_of_string_array_.Set(i, ref);
   }
-  inspector->emplace(std::move(my_vector_of_string));
-
-  auto my_vector_of_uint16 = inspect_config.CreateUintArray(
+  node->Record(std::move(my_vector_of_string_array_));
+  auto my_vector_of_uint16_array_ = node->CreateUintArray(
       "my_vector_of_uint16", this->my_vector_of_uint16().size());
   for (size_t i = 0; i < this->my_vector_of_uint16().size(); i++) {
-    my_vector_of_uint16.Set(i, this->my_vector_of_uint16()[i]);
+    my_vector_of_uint16_array_.Set(i, this->my_vector_of_uint16()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_uint16));
-
-  auto my_vector_of_uint32 = inspect_config.CreateUintArray(
+  node->Record(std::move(my_vector_of_uint16_array_));
+  auto my_vector_of_uint32_array_ = node->CreateUintArray(
       "my_vector_of_uint32", this->my_vector_of_uint32().size());
   for (size_t i = 0; i < this->my_vector_of_uint32().size(); i++) {
-    my_vector_of_uint32.Set(i, this->my_vector_of_uint32()[i]);
+    my_vector_of_uint32_array_.Set(i, this->my_vector_of_uint32()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_uint32));
-
-  auto my_vector_of_uint64 = inspect_config.CreateUintArray(
+  node->Record(std::move(my_vector_of_uint32_array_));
+  auto my_vector_of_uint64_array_ = node->CreateUintArray(
       "my_vector_of_uint64", this->my_vector_of_uint64().size());
   for (size_t i = 0; i < this->my_vector_of_uint64().size(); i++) {
-    my_vector_of_uint64.Set(i, this->my_vector_of_uint64()[i]);
+    my_vector_of_uint64_array_.Set(i, this->my_vector_of_uint64()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_uint64));
-
-  auto my_vector_of_uint8 = inspect_config.CreateUintArray(
+  node->Record(std::move(my_vector_of_uint64_array_));
+  auto my_vector_of_uint8_array_ = node->CreateUintArray(
       "my_vector_of_uint8", this->my_vector_of_uint8().size());
   for (size_t i = 0; i < this->my_vector_of_uint8().size(); i++) {
-    my_vector_of_uint8.Set(i, this->my_vector_of_uint8()[i]);
+    my_vector_of_uint8_array_.Set(i, this->my_vector_of_uint8()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_uint8));
-
-  inspector->emplace(std::move(inspect_config));
+  node->Record(std::move(my_vector_of_uint8_array_));
 }
 
 std::ostream& operator<<(std::ostream& os, const Config& c) {
@@ -198,7 +176,7 @@
   return data;
 }
 
-Config Config::from_args(
+Config Config::TakeFromStartArgs(
     fuchsia_driver_framework::wire::DriverStartArgs& start_args) noexcept {
   // Get the VMO containing FIDL config
   ZX_ASSERT_MSG(start_args.has_config(),
diff --git a/tools/configc/goldens/config.cc.elf.golden b/tools/configc/goldens/config.cc.elf.golden
index 28c68a8..71354d6 100644
--- a/tools/configc/goldens/config.cc.elf.golden
+++ b/tools/configc/goldens/config.cc.elf.golden
@@ -18,100 +18,78 @@
 
 namespace cpp_elf_config_lib {
 
-void Config::record_to_inspect(inspect::Inspector* inspector) {
-  inspect::Node inspect_config = inspector->GetRoot().CreateChild("config");
-  inspect_config.CreateBool("my_flag", this->my_flag(), inspector);
-
-  inspect_config.CreateInt("my_int16", this->my_int16(), inspector);
-
-  inspect_config.CreateInt("my_int32", this->my_int32(), inspector);
-
-  inspect_config.CreateInt("my_int64", this->my_int64(), inspector);
-
-  inspect_config.CreateInt("my_int8", this->my_int8(), inspector);
-
-  inspect_config.CreateString("my_string", this->my_string(), inspector);
-
-  inspect_config.CreateUint("my_uint16", this->my_uint16(), inspector);
-
-  inspect_config.CreateUint("my_uint32", this->my_uint32(), inspector);
-
-  inspect_config.CreateUint("my_uint64", this->my_uint64(), inspector);
-
-  inspect_config.CreateUint("my_uint8", this->my_uint8(), inspector);
-
-  auto my_vector_of_flag = inspect_config.CreateUintArray(
+void Config::RecordInspect(inspect::Node* node) {
+  node->RecordBool("my_flag", this->my_flag());
+  node->RecordInt("my_int16", this->my_int16());
+  node->RecordInt("my_int32", this->my_int32());
+  node->RecordInt("my_int64", this->my_int64());
+  node->RecordInt("my_int8", this->my_int8());
+  node->RecordString("my_string", this->my_string());
+  node->RecordUint("my_uint16", this->my_uint16());
+  node->RecordUint("my_uint32", this->my_uint32());
+  node->RecordUint("my_uint64", this->my_uint64());
+  node->RecordUint("my_uint8", this->my_uint8());
+  auto my_vector_of_flag_array_ = node->CreateUintArray(
       "my_vector_of_flag", this->my_vector_of_flag().size());
   for (size_t i = 0; i < this->my_vector_of_flag().size(); i++) {
-    my_vector_of_flag.Set(i, this->my_vector_of_flag()[i]);
+    my_vector_of_flag_array_.Set(i, this->my_vector_of_flag()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_flag));
-
-  auto my_vector_of_int16 = inspect_config.CreateIntArray(
+  node->Record(std::move(my_vector_of_flag_array_));
+  auto my_vector_of_int16_array_ = node->CreateIntArray(
       "my_vector_of_int16", this->my_vector_of_int16().size());
   for (size_t i = 0; i < this->my_vector_of_int16().size(); i++) {
-    my_vector_of_int16.Set(i, this->my_vector_of_int16()[i]);
+    my_vector_of_int16_array_.Set(i, this->my_vector_of_int16()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_int16));
-
-  auto my_vector_of_int32 = inspect_config.CreateIntArray(
+  node->Record(std::move(my_vector_of_int16_array_));
+  auto my_vector_of_int32_array_ = node->CreateIntArray(
       "my_vector_of_int32", this->my_vector_of_int32().size());
   for (size_t i = 0; i < this->my_vector_of_int32().size(); i++) {
-    my_vector_of_int32.Set(i, this->my_vector_of_int32()[i]);
+    my_vector_of_int32_array_.Set(i, this->my_vector_of_int32()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_int32));
-
-  auto my_vector_of_int64 = inspect_config.CreateIntArray(
+  node->Record(std::move(my_vector_of_int32_array_));
+  auto my_vector_of_int64_array_ = node->CreateIntArray(
       "my_vector_of_int64", this->my_vector_of_int64().size());
   for (size_t i = 0; i < this->my_vector_of_int64().size(); i++) {
-    my_vector_of_int64.Set(i, this->my_vector_of_int64()[i]);
+    my_vector_of_int64_array_.Set(i, this->my_vector_of_int64()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_int64));
-
-  auto my_vector_of_int8 = inspect_config.CreateIntArray(
+  node->Record(std::move(my_vector_of_int64_array_));
+  auto my_vector_of_int8_array_ = node->CreateIntArray(
       "my_vector_of_int8", this->my_vector_of_int8().size());
   for (size_t i = 0; i < this->my_vector_of_int8().size(); i++) {
-    my_vector_of_int8.Set(i, this->my_vector_of_int8()[i]);
+    my_vector_of_int8_array_.Set(i, this->my_vector_of_int8()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_int8));
-
-  auto my_vector_of_string = inspect_config.CreateStringArray(
+  node->Record(std::move(my_vector_of_int8_array_));
+  auto my_vector_of_string_array_ = node->CreateStringArray(
       "my_vector_of_string", this->my_vector_of_string().size());
   for (size_t i = 0; i < this->my_vector_of_string().size(); i++) {
     auto ref = std::string_view(this->my_vector_of_string()[i].data());
-    my_vector_of_string.Set(i, ref);
+    my_vector_of_string_array_.Set(i, ref);
   }
-  inspector->emplace(std::move(my_vector_of_string));
-
-  auto my_vector_of_uint16 = inspect_config.CreateUintArray(
+  node->Record(std::move(my_vector_of_string_array_));
+  auto my_vector_of_uint16_array_ = node->CreateUintArray(
       "my_vector_of_uint16", this->my_vector_of_uint16().size());
   for (size_t i = 0; i < this->my_vector_of_uint16().size(); i++) {
-    my_vector_of_uint16.Set(i, this->my_vector_of_uint16()[i]);
+    my_vector_of_uint16_array_.Set(i, this->my_vector_of_uint16()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_uint16));
-
-  auto my_vector_of_uint32 = inspect_config.CreateUintArray(
+  node->Record(std::move(my_vector_of_uint16_array_));
+  auto my_vector_of_uint32_array_ = node->CreateUintArray(
       "my_vector_of_uint32", this->my_vector_of_uint32().size());
   for (size_t i = 0; i < this->my_vector_of_uint32().size(); i++) {
-    my_vector_of_uint32.Set(i, this->my_vector_of_uint32()[i]);
+    my_vector_of_uint32_array_.Set(i, this->my_vector_of_uint32()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_uint32));
-
-  auto my_vector_of_uint64 = inspect_config.CreateUintArray(
+  node->Record(std::move(my_vector_of_uint32_array_));
+  auto my_vector_of_uint64_array_ = node->CreateUintArray(
       "my_vector_of_uint64", this->my_vector_of_uint64().size());
   for (size_t i = 0; i < this->my_vector_of_uint64().size(); i++) {
-    my_vector_of_uint64.Set(i, this->my_vector_of_uint64()[i]);
+    my_vector_of_uint64_array_.Set(i, this->my_vector_of_uint64()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_uint64));
-
-  auto my_vector_of_uint8 = inspect_config.CreateUintArray(
+  node->Record(std::move(my_vector_of_uint64_array_));
+  auto my_vector_of_uint8_array_ = node->CreateUintArray(
       "my_vector_of_uint8", this->my_vector_of_uint8().size());
   for (size_t i = 0; i < this->my_vector_of_uint8().size(); i++) {
-    my_vector_of_uint8.Set(i, this->my_vector_of_uint8()[i]);
+    my_vector_of_uint8_array_.Set(i, this->my_vector_of_uint8()[i]);
   }
-  inspector->emplace(std::move(my_vector_of_uint8));
-
-  inspector->emplace(std::move(inspect_config));
+  node->Record(std::move(my_vector_of_uint8_array_));
 }
 
 std::ostream& operator<<(std::ostream& os, const Config& c) {
@@ -198,7 +176,7 @@
   return data;
 }
 
-Config Config::from_args() noexcept {
+Config Config::TakeFromStartupHandle() noexcept {
   // Get the VMO containing FIDL config
   zx_handle_t config_vmo_handle = zx_take_startup_handle(PA_CONFIG_VMO);
   ZX_ASSERT_MSG(config_vmo_handle != ZX_HANDLE_INVALID,
diff --git a/tools/configc/goldens/config.h.driver.golden b/tools/configc/goldens/config.h.driver.golden
index 1f8bc39..1ded4e9 100644
--- a/tools/configc/goldens/config.h.driver.golden
+++ b/tools/configc/goldens/config.h.driver.golden
@@ -11,7 +11,7 @@
 namespace cpp_driver_config_lib {
 struct Config {
  public:
-  static Config from_args(
+  static Config TakeFromStartArgs(
       fuchsia_driver_framework::wire::DriverStartArgs& start_args) noexcept;
 
  private:
@@ -24,7 +24,7 @@
   Config() = default;
 #pragma clang diagnostic pop
 
-  void record_to_inspect(inspect::Inspector* inspector);
+  void RecordInspect(inspect::Node* node);
 
   const bool& my_flag() const { return storage_.my_flag; }
   bool& my_flag() { return storage_.my_flag; }
diff --git a/tools/configc/goldens/config.h.elf.golden b/tools/configc/goldens/config.h.elf.golden
index 84ea40d..9cb91ef 100644
--- a/tools/configc/goldens/config.h.elf.golden
+++ b/tools/configc/goldens/config.h.elf.golden
@@ -10,7 +10,7 @@
 namespace cpp_elf_config_lib {
 struct Config {
  public:
-  static Config from_args() noexcept;
+  static Config TakeFromStartupHandle() noexcept;
 
  private:
   struct Storage_;
@@ -22,7 +22,7 @@
   Config() = default;
 #pragma clang diagnostic pop
 
-  void record_to_inspect(inspect::Inspector* inspector);
+  void RecordInspect(inspect::Node* node);
 
   const bool& my_flag() const { return storage_.my_flag; }
   bool& my_flag() { return storage_.my_flag; }
diff --git a/tools/fidl/fidlgen_llcpp/codegen/file_natural_messaging_header.tmpl b/tools/fidl/fidlgen_llcpp/codegen/file_natural_messaging_header.tmpl
index d7cdd9c..46fd621 100644
--- a/tools/fidl/fidlgen_llcpp/codegen/file_natural_messaging_header.tmpl
+++ b/tools/fidl/fidlgen_llcpp/codegen/file_natural_messaging_header.tmpl
@@ -51,6 +51,8 @@
 {{ "" }}
   {{- template "Protocol:Client:NaturalMessagingHeader" $protocol }}
 {{ "" }}
+  {{- template "Protocol:Caller:NaturalMessagingHeader" $protocol }}
+{{ "" }}
   {{- template "Protocol:EventHandler:NaturalMessagingHeader" $protocol }}
 {{ "" }}
   {{- template "Protocol:EventSender:NaturalMessagingHeader" $protocol }}
diff --git a/tools/fidl/fidlgen_llcpp/codegen/file_natural_messaging_source.tmpl b/tools/fidl/fidlgen_llcpp/codegen/file_natural_messaging_source.tmpl
index 73ec78c..5325518 100644
--- a/tools/fidl/fidlgen_llcpp/codegen/file_natural_messaging_source.tmpl
+++ b/tools/fidl/fidlgen_llcpp/codegen/file_natural_messaging_source.tmpl
@@ -31,6 +31,8 @@
 {{ "" }}
   {{- template "Protocol:Client:NaturalMessagingSource" $protocol }}
 {{ "" }}
+  {{- template "Protocol:Caller:NaturalMessagingSource" $protocol }}
+{{ "" }}
   {{- template "Protocol:EventHandler:NaturalMessagingSource" $protocol }}
 {{ "" }}
   {{- template "Protocol:EventSender:NaturalMessagingSource" $protocol }}
diff --git a/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol.tmpl b/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol.tmpl
index c2f5ad6..56fe9ee 100644
--- a/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol.tmpl
+++ b/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol.tmpl
@@ -74,9 +74,30 @@
 {{ EnsureNamespace "fidl" }}
 {{ template "Protocol:Traits:WireMessagingHeader" . }}
 
-{{ EnsureNamespace . }}
-
 {{- IfdefFuchsia -}}
+
+{{- EnsureNamespace "" }}
+{{- range .TwoWayMethods -}}
+{{/* TODO(fxbug.dev/60240): Syncronous wire messaging should use this storage
+     when receiving a response to be decoded. */}}
+{{/* TODO(fxbug.dev/60240): Add a specialization for driver transport,
+     containing an arena which backs both the bytes and handles. */}}
+{{- if eq .Transport.Name "Channel" }}
+template<>
+struct {{ .IncomingMessageStorageForResponse }} final
+    : public ::fidl::internal::ChannelMessageStorageBase<{{ .IncomingMessageStorageForResponse }}> {
+  static constexpr uint32_t kNumHandles =
+      fidl::internal::ClampedHandleCount<{{ .WireResponse }}, fidl::MessageDirection::kReceiving>();
+
+  {{ .Response.ClientAllocationV1.BackingBufferType }} bytes_;
+  ::std::array<zx_handle_t, kNumHandles> handles_;
+  ::std::array<fidl_channel_handle_metadata_t, kNumHandles> handle_metadata_;
+};
+{{- end }}
+{{- end }}
+
+
+{{- EnsureNamespace "" }}
 {{- range .ClientMethods -}}
   {{- if .Transport.HasSyncClient }}
   {{- if eq .Transport.Name "Channel" }}
diff --git a/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol_caller.tmpl b/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol_caller.tmpl
index e1be7f7..205bf66 100644
--- a/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol_caller.tmpl
+++ b/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol_caller.tmpl
@@ -55,3 +55,76 @@
 };
 {{- end }}
 
+
+
+{{- define "Protocol:Caller:NaturalMessagingHeader" }}
+{{- EnsureNamespace "" }}
+{{- IfdefFuchsia }}
+
+template <>
+class {{ .NaturalSyncClientImpl }} final
+    : public ::fidl::internal::SyncEndpointManagedVeneer<{{ .NaturalSyncClientImpl }}> {
+ public:
+  {{ range .TwoWayMethods }}
+    {{ .Docs }}
+    {{ .NaturalResult }} {{ .Name }}({{ .NaturalRequestArg "request" }});
+
+  {{ end }}
+
+  {{ range .OneWayMethods }}
+    {{ .Docs }}
+    ::fitx::result<::fidl::Error> {{ .Name }}({{ .NaturalRequestArg "request" }});
+
+  {{ end }}
+
+ private:
+  ::{{ .Transport.Namespace }}::UnownedClientEnd<{{ . }}> _client_end() const {
+    return ::{{ .Transport.Namespace }}::UnownedClientEnd<{{ . }}>(
+      _transport().get<{{ .Transport.Type }}>());
+  }
+};
+
+{{- EndifFuchsia }}
+{{- end }}
+
+
+
+{{- define "Protocol:Caller:NaturalMessagingSource" }}
+{{- EnsureNamespace "" }}
+{{- IfdefFuchsia }}
+
+{{ range .TwoWayMethods }}
+  {{ .NaturalResult }}
+  {{ $.NaturalSyncClientImpl.NoLeading }}::{{ .Name }}({{ .NaturalRequestArg "request" }}) {
+    ::fidl::internal::NaturalMessageEncoder encoder{
+        &::fidl::internal::ChannelTransport::VTable, {{ .OrdinalName }}, {{ .DynamicFlagsName }} };
+    {{- if .HasRequestPayload }}
+    encoder.EncodeBody(
+        {{ .NaturalRequestConverter }}::IntoDomainObject(std::move(request)));
+    {{- end }}
+    ::fidl::OutgoingMessage msg = encoder.GetMessage();
+    {{ .IncomingMessageStorageForResponse }} response_storage;
+    return ::fidl::internal::DecodeResponseAndFoldError<{{ .Marker }}>(
+        msg.Call(_client_end().handle(), response_storage.view()), nullptr);
+  }
+
+{{ end }}
+
+{{ range .OneWayMethods }}
+  ::fitx::result<::fidl::Error>
+  {{ $.NaturalSyncClientImpl.NoLeading }}::{{ .Name }}({{ .NaturalRequestArg "request" }}) {
+    ::fidl::internal::NaturalMessageEncoder encoder{
+        &::fidl::internal::ChannelTransport::VTable, {{ .OrdinalName }}, {{ .DynamicFlagsName }} };
+    {{- if .HasRequestPayload }}
+    encoder.EncodeBody(
+        {{ .NaturalRequestConverter }}::IntoDomainObject(std::move(request)));
+    {{- end }}
+    ::fidl::OutgoingMessage msg = encoder.GetMessage();
+    msg.Write(_client_end().handle());
+    return ::fidl::internal::ToFitxResult(::fidl::Status{msg});
+  }
+
+{{ end }}
+
+{{- EndifFuchsia }}
+{{- end }}
diff --git a/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol_dispatcher.tmpl b/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol_dispatcher.tmpl
index 3b85992..d0a8c8e 100644
--- a/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol_dispatcher.tmpl
+++ b/tools/fidl/fidlgen_llcpp/codegen/fragment_protocol_dispatcher.tmpl
@@ -38,7 +38,7 @@
         {{- if .RequestArgs }}
         ::fidl::unstable::DecodedMessage<{{ .WireTransactionalRequest }}> decoded{std::move(msg)};
         if (unlikely(!decoded.ok())) {
-          return decoded.status();
+          return ::fidl::Status{decoded};
         }
         auto* primary = &decoded.PrimaryObject()->body;
         {{- else }}
@@ -54,7 +54,7 @@
         reinterpret_cast<{{ $.WireServer }}*>(interface)->{{ .Name }}(
             primary, completer);
           {{- end }}
-        return ZX_OK;
+        return ::fidl::Status::Ok();
       },
     },
   {{- end }}
@@ -120,7 +120,7 @@
         ::fitx::result decoded = ::fidl::internal::DecodeTransactionalMessage
             {{- if .HasRequestPayload }}<{{ .RequestPayload }}>{{ end }}(std::move(msg));
         if (decoded.is_error()) {
-          return decoded.error_value().status();
+          return decoded.error_value();
         }
         {{ .NaturalRequest }} request
         {{- if .HasRequestPayload }}
@@ -129,7 +129,7 @@
         {{ .NaturalCompleter }}::Sync completer(txn);
         static_cast<{{ $.NaturalServer }}*>(interface)->{{ .Name }}(
             request, completer);
-        return ZX_OK;
+        return ::fidl::Status::Ok();
       },
     },
   {{- end }}
diff --git a/tools/fidl/fidlgen_llcpp/goldens/anonymous_natural_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/anonymous_natural_messaging.cc.golden
index 90a94e8..026d05a 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/anonymous_natural_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/anonymous_natural_messaging.cc.golden
@@ -40,6 +40,31 @@
 }  // namespace test_anonymous
 #ifdef __Fuchsia__
 
+::fidl::Result<::test_anonymous::SomeProtocol::SomeMethod> fidl::internal::
+    NaturalSyncClientImpl<::test_anonymous::SomeProtocol>::SomeMethod(
+        ::fidl::Request<::test_anonymous::SomeProtocol::SomeMethod> request) {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_anonymous::kSomeProtocol_SomeMethod_Ordinal,
+      ::test_anonymous::kSomeProtocol_SomeMethod_DynamicFlags};
+  encoder.EncodeBody(
+      ::fidl::internal::NaturalMessageConverter<
+          ::fidl::Request<::test_anonymous::SomeProtocol::SomeMethod>>::
+          IntoDomainObject(std::move(request)));
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  ::fidl::internal::IncomingMessageStorage<
+      ::fidl::internal::TransactionalResponse<
+          ::test_anonymous::SomeProtocol::SomeMethod>>
+      response_storage;
+  return ::fidl::internal::DecodeResponseAndFoldError<
+      ::test_anonymous::SomeProtocol::SomeMethod>(
+      msg.Call(_client_end().handle(), response_storage.view()), nullptr);
+}
+
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
 std::optional<::fidl::UnbindInfo> fidl::internal::
     NaturalEventDispatcher<::test_anonymous::SomeProtocol>::DispatchEvent(
         ::fidl::IncomingMessage& msg,
@@ -80,7 +105,7 @@
           ::fitx::result decoded = ::fidl::internal::DecodeTransactionalMessage<
               ::test_anonymous::SomeProtocolSomeMethodRequest>(std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<::test_anonymous::SomeProtocol::SomeMethod> request =
               ::fidl::internal::NaturalMessageConverter<
@@ -91,7 +116,7 @@
           static_cast<::fidl::Server<::test_anonymous::SomeProtocol>*>(
               interface)
               ->SomeMethod(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/anonymous_natural_messaging.h.golden b/tools/fidl/fidlgen_llcpp/goldens/anonymous_natural_messaging.h.golden
index 8ab3ff17..b7d99e5 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/anonymous_natural_messaging.h.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/anonymous_natural_messaging.h.golden
@@ -120,6 +120,25 @@
 #ifdef __Fuchsia__
 
 template <>
+class ::fidl::internal::NaturalSyncClientImpl<::test_anonymous::SomeProtocol>
+    final : public ::fidl::internal::SyncEndpointManagedVeneer<
+                ::fidl::internal::NaturalSyncClientImpl<
+                    ::test_anonymous::SomeProtocol>> {
+ public:
+  ::fidl::Result<::test_anonymous::SomeProtocol::SomeMethod> SomeMethod(
+      ::fidl::Request<::test_anonymous::SomeProtocol::SomeMethod> request);
+
+ private:
+  ::fidl::UnownedClientEnd<::test_anonymous::SomeProtocol> _client_end() const {
+    return ::fidl::UnownedClientEnd<::test_anonymous::SomeProtocol>(
+        _transport().get<::fidl::internal::ChannelTransport>());
+  }
+};
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
+template <>
 class ::fidl::internal::NaturalEventHandlerInterface<
     ::test_anonymous::SomeProtocol> {
  public:
diff --git a/tools/fidl/fidlgen_llcpp/goldens/anonymous_wire_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/anonymous_wire_messaging.cc.golden
index ed6d119..5ef6012 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/anonymous_wire_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/anonymous_wire_messaging.cc.golden
@@ -249,7 +249,7 @@
                   ::test_anonymous::SomeProtocol::SomeMethod>>
               decoded{std::move(msg)};
           if (unlikely(!decoded.ok())) {
-            return decoded.status();
+            return ::fidl::Status{decoded};
           }
           auto* primary = &decoded.PrimaryObject()->body;
           ::fidl::internal::WireCompleter<
@@ -257,7 +257,7 @@
           reinterpret_cast<::fidl::WireServer<::test_anonymous::SomeProtocol>*>(
               interface)
               ->SomeMethod(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/anonymous_wire_messaging.h.golden b/tools/fidl/fidlgen_llcpp/goldens/anonymous_wire_messaging.h.golden
index 459201c..07092e9 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/anonymous_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/anonymous_wire_messaging.h.golden
@@ -303,11 +303,25 @@
 static_assert(
     offsetof(::fidl::WireResponse<::test_anonymous::SomeProtocol::SomeMethod>,
              result) == 0);
-
-}  // namespace fidl
-namespace test_anonymous {
 #ifdef __Fuchsia__
-}  // namespace test_anonymous
+}  // namespace fidl
+
+template <>
+struct ::fidl::internal::IncomingMessageStorage<
+    ::fidl::internal::TransactionalResponse<
+        ::test_anonymous::SomeProtocol::SomeMethod>>
+    final : public ::fidl::internal::ChannelMessageStorageBase<
+                ::fidl::internal::IncomingMessageStorage<
+                    ::fidl::internal::TransactionalResponse<
+                        ::test_anonymous::SomeProtocol::SomeMethod>>> {
+  static constexpr uint32_t kNumHandles = fidl::internal::ClampedHandleCount<
+      ::fidl::WireResponse<::test_anonymous::SomeProtocol::SomeMethod>,
+      fidl::MessageDirection::kReceiving>();
+
+  ::fidl::internal::InlineMessageBuffer<48> bytes_;
+  ::std::array<zx_handle_t, kNumHandles> handles_;
+  ::std::array<fidl_channel_handle_metadata_t, kNumHandles> handle_metadata_;
+};
 template <>
 class [[nodiscard]] ::fidl::WireResult<
     ::test_anonymous::SomeProtocol::SomeMethod>
@@ -689,11 +703,8 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_anonymous {
-#endif  // __Fuchsia__
-
-}  // namespace test_anonymous
 namespace fidl {
+#endif  // __Fuchsia__
 
 #ifdef __Fuchsia__
 }  // namespace fidl
diff --git a/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_natural_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_natural_messaging.cc.golden
index 64926c5..833ab3e 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_natural_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_natural_messaging.cc.golden
@@ -8,6 +8,10 @@
 
 #ifdef __Fuchsia__
 
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
 std::optional<::fidl::UnbindInfo> fidl::internal::
     NaturalEventDispatcher<::test_bindingsdenylist::Allowed>::DispatchEvent(
         ::fidl::IncomingMessage& msg,
@@ -87,6 +91,33 @@
 }  // namespace test_bindingsdenylist
 #ifdef __Fuchsia__
 
+::fidl::Result<::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
+                   LibfuzzerNeedsNonemptyProtocol>
+fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::OnlyLibfuzzerAndDeps>::
+    LibfuzzerNeedsNonemptyProtocol() {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_bindingsdenylist::
+          kOnlyLibfuzzerAndDeps_LibfuzzerNeedsNonemptyProtocol_Ordinal,
+      ::test_bindingsdenylist::
+          kOnlyLibfuzzerAndDeps_LibfuzzerNeedsNonemptyProtocol_DynamicFlags};
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  ::fidl::internal::IncomingMessageStorage<
+      ::fidl::internal::TransactionalResponse<
+          ::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
+              LibfuzzerNeedsNonemptyProtocol>>
+      response_storage;
+  return ::fidl::internal::DecodeResponseAndFoldError<
+      ::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
+          LibfuzzerNeedsNonemptyProtocol>(
+      msg.Call(_client_end().handle(), response_storage.view()), nullptr);
+}
+
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
 std::optional<::fidl::UnbindInfo> fidl::internal::NaturalEventDispatcher<
     ::test_bindingsdenylist::OnlyLibfuzzerAndDeps>::
     DispatchEvent(
@@ -126,7 +157,7 @@
           ::fitx::result decoded =
               ::fidl::internal::DecodeTransactionalMessage(std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
                               LibfuzzerNeedsNonemptyProtocol>
@@ -138,7 +169,7 @@
               ::fidl::Server<::test_bindingsdenylist::OnlyLibfuzzerAndDeps>*>(
               interface)
               ->LibfuzzerNeedsNonemptyProtocol(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
@@ -172,6 +203,10 @@
 
 #ifdef __Fuchsia__
 
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
 std::optional<::fidl::UnbindInfo> fidl::internal::NaturalEventDispatcher<
     ::test_bindingsdenylist::OnlyCppAndDeps>::
     DispatchEvent(
@@ -262,6 +297,36 @@
 }  // namespace test_bindingsdenylist
 #ifdef __Fuchsia__
 
+::fitx::result<::fidl::Error> fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::ImportsSameNameContext>::Unattributed() {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_bindingsdenylist::kImportsSameNameContext_Unattributed_Ordinal,
+      ::test_bindingsdenylist::
+          kImportsSameNameContext_Unattributed_DynamicFlags};
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  msg.Write(_client_end().handle());
+  return ::fidl::internal::ToFitxResult(::fidl::Status{msg});
+}
+
+::fitx::result<::fidl::Error> fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::ImportsSameNameContext>::
+    AlwaysAppearsInImportingLibrary() {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_bindingsdenylist::
+          kImportsSameNameContext_AlwaysAppearsInImportingLibrary_Ordinal,
+      ::test_bindingsdenylist::
+          kImportsSameNameContext_AlwaysAppearsInImportingLibrary_DynamicFlags};
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  msg.Write(_client_end().handle());
+  return ::fidl::internal::ToFitxResult(::fidl::Status{msg});
+}
+
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
 std::optional<::fidl::UnbindInfo> fidl::internal::NaturalEventDispatcher<
     ::test_bindingsdenylist::ImportsSameNameContext>::
     DispatchEvent(
@@ -287,7 +352,7 @@
           ::fitx::result decoded =
               ::fidl::internal::DecodeTransactionalMessage(std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<
               ::test_bindingsdenylist::ImportsSameNameContext::Unattributed>
@@ -299,7 +364,7 @@
               ::fidl::Server<::test_bindingsdenylist::ImportsSameNameContext>*>(
               interface)
               ->Unattributed(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -311,7 +376,7 @@
           ::fitx::result decoded =
               ::fidl::internal::DecodeTransactionalMessage(std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<::test_bindingsdenylist::ImportsSameNameContext::
                               AlwaysAppearsInImportingLibrary>
@@ -323,7 +388,7 @@
               ::fidl::Server<::test_bindingsdenylist::ImportsSameNameContext>*>(
               interface)
               ->AlwaysAppearsInImportingLibrary(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
@@ -523,6 +588,131 @@
 }  // namespace test_bindingsdenylist
 #ifdef __Fuchsia__
 
+::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>
+fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::DenyEachBinding>::
+    OnlyDenyDart(
+        ::fidl::Request<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>
+            request) {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenyDart_Ordinal,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenyDart_DynamicFlags};
+  encoder.EncodeBody(
+      ::fidl::internal::NaturalMessageConverter<::fidl::Request<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>>::
+          IntoDomainObject(std::move(request)));
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  ::fidl::internal::IncomingMessageStorage<
+      ::fidl::internal::TransactionalResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>>
+      response_storage;
+  return ::fidl::internal::DecodeResponseAndFoldError<
+      ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>(
+      msg.Call(_client_end().handle(), response_storage.view()), nullptr);
+}
+
+::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>
+fidl::internal::
+    NaturalSyncClientImpl<::test_bindingsdenylist::DenyEachBinding>::OnlyDenyGo(
+        ::fidl::Request<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>
+            request) {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenyGo_Ordinal,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenyGo_DynamicFlags};
+  encoder.EncodeBody(
+      ::fidl::internal::NaturalMessageConverter<::fidl::Request<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>>::
+          IntoDomainObject(std::move(request)));
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  ::fidl::internal::IncomingMessageStorage<
+      ::fidl::internal::TransactionalResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>>
+      response_storage;
+  return ::fidl::internal::DecodeResponseAndFoldError<
+      ::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>(
+      msg.Call(_client_end().handle(), response_storage.view()), nullptr);
+}
+
+::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>
+fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::DenyEachBinding>::
+    OnlyDenyLibfuzzer(
+        ::fidl::Request<
+            ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>
+            request) {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenyLibfuzzer_Ordinal,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenyLibfuzzer_DynamicFlags};
+  encoder.EncodeBody(
+      ::fidl::internal::NaturalMessageConverter<::fidl::Request<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>>::
+          IntoDomainObject(std::move(request)));
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  ::fidl::internal::IncomingMessageStorage<
+      ::fidl::internal::TransactionalResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>>
+      response_storage;
+  return ::fidl::internal::DecodeResponseAndFoldError<
+      ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>(
+      msg.Call(_client_end().handle(), response_storage.view()), nullptr);
+}
+
+::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>
+fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::DenyEachBinding>::
+    OnlyDenyRust(
+        ::fidl::Request<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>
+            request) {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenyRust_Ordinal,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenyRust_DynamicFlags};
+  encoder.EncodeBody(
+      ::fidl::internal::NaturalMessageConverter<::fidl::Request<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>>::
+          IntoDomainObject(std::move(request)));
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  ::fidl::internal::IncomingMessageStorage<
+      ::fidl::internal::TransactionalResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>>
+      response_storage;
+  return ::fidl::internal::DecodeResponseAndFoldError<
+      ::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>(
+      msg.Call(_client_end().handle(), response_storage.view()), nullptr);
+}
+
+::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>
+fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::DenyEachBinding>::
+    OnlyDenySyzkaller(
+        ::fidl::Request<
+            ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>
+            request) {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenySyzkaller_Ordinal,
+      ::test_bindingsdenylist::kDenyEachBinding_OnlyDenySyzkaller_DynamicFlags};
+  encoder.EncodeBody(
+      ::fidl::internal::NaturalMessageConverter<::fidl::Request<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>>::
+          IntoDomainObject(std::move(request)));
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  ::fidl::internal::IncomingMessageStorage<
+      ::fidl::internal::TransactionalResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>>
+      response_storage;
+  return ::fidl::internal::DecodeResponseAndFoldError<
+      ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>(
+      msg.Call(_client_end().handle(), response_storage.view()), nullptr);
+}
+
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
 std::optional<::fidl::UnbindInfo> fidl::internal::NaturalEventDispatcher<
     ::test_bindingsdenylist::DenyEachBinding>::
     DispatchEvent(
@@ -632,7 +822,7 @@
               ::test_bindingsdenylist::DenyEachBindingOnlyDenyDartRequest>(
               std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<
               ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>
@@ -647,7 +837,7 @@
               ::fidl::Server<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenyDart(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -659,7 +849,7 @@
               ::test_bindingsdenylist::DenyEachBindingOnlyDenyGoRequest>(
               std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>
               request =
@@ -673,7 +863,7 @@
               ::fidl::Server<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenyGo(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -685,7 +875,7 @@
               ::test_bindingsdenylist::DenyEachBindingOnlyDenyLibfuzzerRequest>(
               std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<
               ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>
@@ -700,7 +890,7 @@
               ::fidl::Server<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenyLibfuzzer(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -712,7 +902,7 @@
               ::test_bindingsdenylist::DenyEachBindingOnlyDenyRustRequest>(
               std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<
               ::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>
@@ -727,7 +917,7 @@
               ::fidl::Server<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenyRust(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -739,7 +929,7 @@
               ::test_bindingsdenylist::DenyEachBindingOnlyDenySyzkallerRequest>(
               std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<
               ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>
@@ -754,7 +944,7 @@
               ::fidl::Server<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenySyzkaller(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_natural_messaging.h.golden b/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_natural_messaging.h.golden
index a4c26f2..63a6216 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_natural_messaging.h.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_natural_messaging.h.golden
@@ -29,6 +29,23 @@
 #ifdef __Fuchsia__
 
 template <>
+class ::fidl::internal::NaturalSyncClientImpl<::test_bindingsdenylist::Allowed>
+    final : public ::fidl::internal::SyncEndpointManagedVeneer<
+                ::fidl::internal::NaturalSyncClientImpl<
+                    ::test_bindingsdenylist::Allowed>> {
+ public:
+ private:
+  ::fidl::UnownedClientEnd<::test_bindingsdenylist::Allowed> _client_end()
+      const {
+    return ::fidl::UnownedClientEnd<::test_bindingsdenylist::Allowed>(
+        _transport().get<::fidl::internal::ChannelTransport>());
+  }
+};
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
+template <>
 class ::fidl::internal::NaturalEventHandlerInterface<
     ::test_bindingsdenylist::Allowed> {
  public:
@@ -175,6 +192,29 @@
 #ifdef __Fuchsia__
 
 template <>
+class ::fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::OnlyLibfuzzerAndDeps>
+    final : public ::fidl::internal::SyncEndpointManagedVeneer<
+                ::fidl::internal::NaturalSyncClientImpl<
+                    ::test_bindingsdenylist::OnlyLibfuzzerAndDeps>> {
+ public:
+  ::fidl::Result<::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
+                     LibfuzzerNeedsNonemptyProtocol>
+  LibfuzzerNeedsNonemptyProtocol();
+
+ private:
+  ::fidl::UnownedClientEnd<::test_bindingsdenylist::OnlyLibfuzzerAndDeps>
+  _client_end() const {
+    return ::fidl::UnownedClientEnd<
+        ::test_bindingsdenylist::OnlyLibfuzzerAndDeps>(
+        _transport().get<::fidl::internal::ChannelTransport>());
+  }
+};
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
+template <>
 class ::fidl::internal::NaturalEventHandlerInterface<
     ::test_bindingsdenylist::OnlyLibfuzzerAndDeps> {
  public:
@@ -321,6 +361,24 @@
 #ifdef __Fuchsia__
 
 template <>
+class ::fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::OnlyCppAndDeps>
+    final : public ::fidl::internal::SyncEndpointManagedVeneer<
+                ::fidl::internal::NaturalSyncClientImpl<
+                    ::test_bindingsdenylist::OnlyCppAndDeps>> {
+ public:
+ private:
+  ::fidl::UnownedClientEnd<::test_bindingsdenylist::OnlyCppAndDeps>
+  _client_end() const {
+    return ::fidl::UnownedClientEnd<::test_bindingsdenylist::OnlyCppAndDeps>(
+        _transport().get<::fidl::internal::ChannelTransport>());
+  }
+};
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
+template <>
 class ::fidl::internal::NaturalEventHandlerInterface<
     ::test_bindingsdenylist::OnlyCppAndDeps> {
  public:
@@ -428,6 +486,29 @@
 #ifdef __Fuchsia__
 
 template <>
+class ::fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::ImportsSameNameContext>
+    final : public ::fidl::internal::SyncEndpointManagedVeneer<
+                ::fidl::internal::NaturalSyncClientImpl<
+                    ::test_bindingsdenylist::ImportsSameNameContext>> {
+ public:
+  ::fitx::result<::fidl::Error> Unattributed();
+
+  ::fitx::result<::fidl::Error> AlwaysAppearsInImportingLibrary();
+
+ private:
+  ::fidl::UnownedClientEnd<::test_bindingsdenylist::ImportsSameNameContext>
+  _client_end() const {
+    return ::fidl::UnownedClientEnd<
+        ::test_bindingsdenylist::ImportsSameNameContext>(
+        _transport().get<::fidl::internal::ChannelTransport>());
+  }
+};
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
+template <>
 class ::fidl::internal::NaturalEventHandlerInterface<
     ::test_bindingsdenylist::ImportsSameNameContext> {
  public:
@@ -1103,6 +1184,49 @@
 #ifdef __Fuchsia__
 
 template <>
+class ::fidl::internal::NaturalSyncClientImpl<
+    ::test_bindingsdenylist::DenyEachBinding>
+    final : public ::fidl::internal::SyncEndpointManagedVeneer<
+                ::fidl::internal::NaturalSyncClientImpl<
+                    ::test_bindingsdenylist::DenyEachBinding>> {
+ public:
+  ::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>
+  OnlyDenyDart(
+      ::fidl::Request<::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>
+          request);
+
+  ::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>
+  OnlyDenyGo(
+      ::fidl::Request<::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>
+          request);
+
+  ::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>
+  OnlyDenyLibfuzzer(::fidl::Request<
+                    ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>
+                        request);
+
+  ::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>
+  OnlyDenyRust(
+      ::fidl::Request<::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>
+          request);
+
+  ::fidl::Result<::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>
+  OnlyDenySyzkaller(::fidl::Request<
+                    ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>
+                        request);
+
+ private:
+  ::fidl::UnownedClientEnd<::test_bindingsdenylist::DenyEachBinding>
+  _client_end() const {
+    return ::fidl::UnownedClientEnd<::test_bindingsdenylist::DenyEachBinding>(
+        _transport().get<::fidl::internal::ChannelTransport>());
+  }
+};
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
+template <>
 class ::fidl::internal::NaturalEventHandlerInterface<
     ::test_bindingsdenylist::DenyEachBinding> {
  public:
diff --git a/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_wire_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_wire_messaging.cc.golden
index 4441830c..c6250d6 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_wire_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_wire_messaging.cc.golden
@@ -360,7 +360,7 @@
           reinterpret_cast<::fidl::WireServer<
               ::test_bindingsdenylist::OnlyLibfuzzerAndDeps>*>(interface)
               ->LibfuzzerNeedsNonemptyProtocol(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
@@ -879,7 +879,7 @@
           reinterpret_cast<::fidl::WireServer<
               ::test_bindingsdenylist::ImportsSameNameContext>*>(interface)
               ->Unattributed(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -898,7 +898,7 @@
           reinterpret_cast<::fidl::WireServer<
               ::test_bindingsdenylist::ImportsSameNameContext>*>(interface)
               ->AlwaysAppearsInImportingLibrary(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
@@ -1920,7 +1920,7 @@
                   ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>>
               decoded{std::move(msg)};
           if (unlikely(!decoded.ok())) {
-            return decoded.status();
+            return ::fidl::Status{decoded};
           }
           auto* primary = &decoded.PrimaryObject()->body;
           ::fidl::internal::WireCompleter<
@@ -1930,7 +1930,7 @@
               ::fidl::WireServer<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenyDart(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -1943,7 +1943,7 @@
                   ::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>>
               decoded{std::move(msg)};
           if (unlikely(!decoded.ok())) {
-            return decoded.status();
+            return ::fidl::Status{decoded};
           }
           auto* primary = &decoded.PrimaryObject()->body;
           ::fidl::internal::WireCompleter<
@@ -1953,7 +1953,7 @@
               ::fidl::WireServer<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenyGo(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -1966,7 +1966,7 @@
                   ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>>
               decoded{std::move(msg)};
           if (unlikely(!decoded.ok())) {
-            return decoded.status();
+            return ::fidl::Status{decoded};
           }
           auto* primary = &decoded.PrimaryObject()->body;
           ::fidl::internal::WireCompleter<
@@ -1976,7 +1976,7 @@
               ::fidl::WireServer<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenyLibfuzzer(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -1989,7 +1989,7 @@
                   ::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>>
               decoded{std::move(msg)};
           if (unlikely(!decoded.ok())) {
-            return decoded.status();
+            return ::fidl::Status{decoded};
           }
           auto* primary = &decoded.PrimaryObject()->body;
           ::fidl::internal::WireCompleter<
@@ -1999,7 +1999,7 @@
               ::fidl::WireServer<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenyRust(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
     {
@@ -2012,7 +2012,7 @@
                   ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>>
               decoded{std::move(msg)};
           if (unlikely(!decoded.ok())) {
-            return decoded.status();
+            return ::fidl::Status{decoded};
           }
           auto* primary = &decoded.PrimaryObject()->body;
           ::fidl::internal::WireCompleter<
@@ -2022,7 +2022,7 @@
               ::fidl::WireServer<::test_bindingsdenylist::DenyEachBinding>*>(
               interface)
               ->OnlyDenySyzkaller(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_wire_messaging.h.golden b/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_wire_messaging.h.golden
index ca91609..1252e6a 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/bindings_denylist_wire_messaging.h.golden
@@ -59,10 +59,10 @@
 };
 #endif  // __Fuchsia__
 
-namespace fidl {}  // namespace fidl
-namespace test_bindingsdenylist {
+namespace fidl {
+
 #ifdef __Fuchsia__
-}  // namespace test_bindingsdenylist
+}  // namespace fidl
 template <>
 class ::fidl::internal::WireEventHandlerInterface<
     ::test_bindingsdenylist::Allowed> {
@@ -164,10 +164,10 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_bindingsdenylist {
+namespace fidl {
 #endif  // __Fuchsia__
 
-}  // namespace test_bindingsdenylist
+}  // namespace fidl
 template <>
 struct ::fidl::internal::WireOrdinal<
     ::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
@@ -410,11 +410,28 @@
   static constexpr ::fidl::internal::TransactionalMessageKind kMessageKind =
       ::fidl::internal::TransactionalMessageKind::kResponse;
 };
-
-}  // namespace fidl
-namespace test_bindingsdenylist {
 #ifdef __Fuchsia__
-}  // namespace test_bindingsdenylist
+}  // namespace fidl
+
+template <>
+struct ::fidl::internal::IncomingMessageStorage<
+    ::fidl::internal::TransactionalResponse<
+        ::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
+            LibfuzzerNeedsNonemptyProtocol>>
+    final : public ::fidl::internal::ChannelMessageStorageBase<
+                ::fidl::internal::IncomingMessageStorage<
+                    ::fidl::internal::TransactionalResponse<
+                        ::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
+                            LibfuzzerNeedsNonemptyProtocol>>> {
+  static constexpr uint32_t kNumHandles = fidl::internal::ClampedHandleCount<
+      ::fidl::WireResponse<::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
+                               LibfuzzerNeedsNonemptyProtocol>,
+      fidl::MessageDirection::kReceiving>();
+
+  ::fidl::internal::InlineMessageBuffer<16> bytes_;
+  ::std::array<zx_handle_t, kNumHandles> handles_;
+  ::std::array<fidl_channel_handle_metadata_t, kNumHandles> handle_metadata_;
+};
 template <>
 class [[nodiscard]] ::fidl::WireResult<
     ::test_bindingsdenylist::OnlyLibfuzzerAndDeps::
@@ -682,10 +699,11 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_bindingsdenylist {
+namespace fidl {
 #endif  // __Fuchsia__
 
-}  // namespace test_bindingsdenylist
+}  // namespace fidl
+namespace test_bindingsdenylist {}  // namespace test_bindingsdenylist
 #ifdef __Fuchsia__
 
 template <>
@@ -717,10 +735,10 @@
 };
 #endif  // __Fuchsia__
 
-namespace fidl {}  // namespace fidl
-namespace test_bindingsdenylist {
+namespace fidl {
+
 #ifdef __Fuchsia__
-}  // namespace test_bindingsdenylist
+}  // namespace fidl
 template <>
 class ::fidl::internal::WireEventHandlerInterface<
     ::test_bindingsdenylist::OnlyCppAndDeps> {
@@ -826,10 +844,10 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_bindingsdenylist {
+namespace fidl {
 #endif  // __Fuchsia__
 
-}  // namespace test_bindingsdenylist
+}  // namespace fidl
 template <>
 struct ::fidl::internal::WireOrdinal<
     ::test_bindingsdenylist::ImportsSameNameContext::Unattributed>
@@ -1042,11 +1060,8 @@
   static constexpr ::fidl::internal::TransactionalMessageKind kMessageKind =
       ::fidl::internal::TransactionalMessageKind::kRequest;
 };
-
-}  // namespace fidl
-namespace test_bindingsdenylist {
 #ifdef __Fuchsia__
-}  // namespace test_bindingsdenylist
+}  // namespace fidl
 template <>
 class [[nodiscard]] ::fidl::WireResult<
     ::test_bindingsdenylist::ImportsSameNameContext::Unattributed>
@@ -1314,9 +1329,11 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_bindingsdenylist {
+namespace fidl {
 #endif  // __Fuchsia__
 
+}  // namespace fidl
+namespace test_bindingsdenylist {
 __LOCAL extern "C" const fidl_type_t
     test_bindingsdenylist_DenyEachBindingOnlyDenyDartRequestTable;
 __LOCAL extern "C" const fidl_type_t
@@ -2712,11 +2729,103 @@
     offsetof(::fidl::WireResponse<
                  ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>,
              result) == 0);
-
-}  // namespace fidl
-namespace test_bindingsdenylist {
 #ifdef __Fuchsia__
-}  // namespace test_bindingsdenylist
+}  // namespace fidl
+
+template <>
+struct ::fidl::internal::IncomingMessageStorage<
+    ::fidl::internal::TransactionalResponse<
+        ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>>
+    final
+    : public ::fidl::internal::ChannelMessageStorageBase<
+          ::fidl::internal::IncomingMessageStorage<
+              ::fidl::internal::TransactionalResponse<
+                  ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>>> {
+  static constexpr uint32_t kNumHandles = fidl::internal::ClampedHandleCount<
+      ::fidl::WireResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>,
+      fidl::MessageDirection::kReceiving>();
+
+  ::fidl::internal::InlineMessageBuffer<48> bytes_;
+  ::std::array<zx_handle_t, kNumHandles> handles_;
+  ::std::array<fidl_channel_handle_metadata_t, kNumHandles> handle_metadata_;
+};
+
+template <>
+struct ::fidl::internal::IncomingMessageStorage<
+    ::fidl::internal::TransactionalResponse<
+        ::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>>
+    final
+    : public ::fidl::internal::ChannelMessageStorageBase<
+          ::fidl::internal::IncomingMessageStorage<
+              ::fidl::internal::TransactionalResponse<
+                  ::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>>> {
+  static constexpr uint32_t kNumHandles = fidl::internal::ClampedHandleCount<
+      ::fidl::WireResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyGo>,
+      fidl::MessageDirection::kReceiving>();
+
+  ::fidl::internal::InlineMessageBuffer<48> bytes_;
+  ::std::array<zx_handle_t, kNumHandles> handles_;
+  ::std::array<fidl_channel_handle_metadata_t, kNumHandles> handle_metadata_;
+};
+
+template <>
+struct ::fidl::internal::IncomingMessageStorage<
+    ::fidl::internal::TransactionalResponse<
+        ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>>
+    final : public ::fidl::internal::ChannelMessageStorageBase<
+                ::fidl::internal::IncomingMessageStorage<
+                    ::fidl::internal::TransactionalResponse<
+                        ::test_bindingsdenylist::DenyEachBinding::
+                            OnlyDenyLibfuzzer>>> {
+  static constexpr uint32_t kNumHandles = fidl::internal::ClampedHandleCount<
+      ::fidl::WireResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyLibfuzzer>,
+      fidl::MessageDirection::kReceiving>();
+
+  ::fidl::internal::InlineMessageBuffer<48> bytes_;
+  ::std::array<zx_handle_t, kNumHandles> handles_;
+  ::std::array<fidl_channel_handle_metadata_t, kNumHandles> handle_metadata_;
+};
+
+template <>
+struct ::fidl::internal::IncomingMessageStorage<
+    ::fidl::internal::TransactionalResponse<
+        ::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>>
+    final
+    : public ::fidl::internal::ChannelMessageStorageBase<
+          ::fidl::internal::IncomingMessageStorage<
+              ::fidl::internal::TransactionalResponse<
+                  ::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>>> {
+  static constexpr uint32_t kNumHandles = fidl::internal::ClampedHandleCount<
+      ::fidl::WireResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenyRust>,
+      fidl::MessageDirection::kReceiving>();
+
+  ::fidl::internal::InlineMessageBuffer<48> bytes_;
+  ::std::array<zx_handle_t, kNumHandles> handles_;
+  ::std::array<fidl_channel_handle_metadata_t, kNumHandles> handle_metadata_;
+};
+
+template <>
+struct ::fidl::internal::IncomingMessageStorage<
+    ::fidl::internal::TransactionalResponse<
+        ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>>
+    final : public ::fidl::internal::ChannelMessageStorageBase<
+                ::fidl::internal::IncomingMessageStorage<
+                    ::fidl::internal::TransactionalResponse<
+                        ::test_bindingsdenylist::DenyEachBinding::
+                            OnlyDenySyzkaller>>> {
+  static constexpr uint32_t kNumHandles = fidl::internal::ClampedHandleCount<
+      ::fidl::WireResponse<
+          ::test_bindingsdenylist::DenyEachBinding::OnlyDenySyzkaller>,
+      fidl::MessageDirection::kReceiving>();
+
+  ::fidl::internal::InlineMessageBuffer<48> bytes_;
+  ::std::array<zx_handle_t, kNumHandles> handles_;
+  ::std::array<fidl_channel_handle_metadata_t, kNumHandles> handle_metadata_;
+};
 template <>
 class [[nodiscard]] ::fidl::WireResult<
     ::test_bindingsdenylist::DenyEachBinding::OnlyDenyDart>
@@ -4407,11 +4516,8 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_bindingsdenylist {
-#endif  // __Fuchsia__
-
-}  // namespace test_bindingsdenylist
 namespace fidl {
+#endif  // __Fuchsia__
 
 #ifdef __Fuchsia__
 }  // namespace fidl
diff --git a/tools/fidl/fidlgen_llcpp/goldens/doc_comments_natural_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/doc_comments_natural_messaging.cc.golden
index 4d256cd..c4e92be 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/doc_comments_natural_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/doc_comments_natural_messaging.cc.golden
@@ -34,6 +34,21 @@
 }  // namespace test_doccomments
 #ifdef __Fuchsia__
 
+::fitx::result<::fidl::Error>
+fidl::internal::NaturalSyncClientImpl<::test_doccomments::Interface>::Method() {
+  ::fidl::internal::NaturalMessageEncoder encoder{
+      &::fidl::internal::ChannelTransport::VTable,
+      ::test_doccomments::kInterface_Method_Ordinal,
+      ::test_doccomments::kInterface_Method_DynamicFlags};
+  ::fidl::OutgoingMessage msg = encoder.GetMessage();
+  msg.Write(_client_end().handle());
+  return ::fidl::internal::ToFitxResult(::fidl::Status{msg});
+}
+
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
 std::optional<::fidl::UnbindInfo> fidl::internal::
     NaturalEventDispatcher<::test_doccomments::Interface>::DispatchEvent(
         ::fidl::IncomingMessage& msg,
@@ -96,14 +111,14 @@
           ::fitx::result decoded =
               ::fidl::internal::DecodeTransactionalMessage(std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<::test_doccomments::Interface::Method> request;
           ::fidl::internal::NaturalCompleter<
               ::test_doccomments::Interface::Method>::Sync completer(txn);
           static_cast<::fidl::Server<::test_doccomments::Interface>*>(interface)
               ->Method(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/doc_comments_natural_messaging.h.golden b/tools/fidl/fidlgen_llcpp/goldens/doc_comments_natural_messaging.h.golden
index 233d768..91a4ef5 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/doc_comments_natural_messaging.h.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/doc_comments_natural_messaging.h.golden
@@ -46,6 +46,27 @@
 #ifdef __Fuchsia__
 
 template <>
+class ::fidl::internal::NaturalSyncClientImpl<::test_doccomments::Interface>
+    final : public ::fidl::internal::SyncEndpointManagedVeneer<
+                ::fidl::internal::NaturalSyncClientImpl<
+                    ::test_doccomments::Interface>> {
+ public:
+  /// method comment #1
+  ///
+  /// method comment #3
+  ::fitx::result<::fidl::Error> Method();
+
+ private:
+  ::fidl::UnownedClientEnd<::test_doccomments::Interface> _client_end() const {
+    return ::fidl::UnownedClientEnd<::test_doccomments::Interface>(
+        _transport().get<::fidl::internal::ChannelTransport>());
+  }
+};
+#endif  // __Fuchsia__
+
+#ifdef __Fuchsia__
+
+template <>
 class ::fidl::internal::NaturalEventHandlerInterface<
     ::test_doccomments::Interface> {
  public:
diff --git a/tools/fidl/fidlgen_llcpp/goldens/doc_comments_wire_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/doc_comments_wire_messaging.cc.golden
index eda11de..ac64a65 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/doc_comments_wire_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/doc_comments_wire_messaging.cc.golden
@@ -219,7 +219,7 @@
           reinterpret_cast<::fidl::WireServer<::test_doccomments::Interface>*>(
               interface)
               ->Method(primary, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/doc_comments_wire_messaging.h.golden b/tools/fidl/fidlgen_llcpp/goldens/doc_comments_wire_messaging.h.golden
index f651c5d..872330c 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/doc_comments_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/doc_comments_wire_messaging.h.golden
@@ -205,11 +205,8 @@
   static constexpr ::fidl::internal::TransactionalMessageKind kMessageKind =
       ::fidl::internal::TransactionalMessageKind::kResponse;
 };
-
-}  // namespace fidl
-namespace test_doccomments {
 #ifdef __Fuchsia__
-}  // namespace test_doccomments
+}  // namespace fidl
 template <>
 class [[nodiscard]] ::fidl::WireResult<::test_doccomments::Interface::Method>
     final : public ::fidl::Status {
@@ -387,9 +384,12 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_doccomments {
+namespace fidl {
 #endif  // __Fuchsia__
 
+}  // namespace fidl
+namespace test_doccomments {
+
 /// service comment #1
 ///
 /// service comment #3
diff --git a/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_natural_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_natural_messaging.cc.golden
index 5594e84..85d900c 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_natural_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_natural_messaging.cc.golden
@@ -66,7 +66,7 @@
               ::test_driverhandle::HandlesInProtocolSendHandlesRequest>(
               std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<::test_driverhandle::HandlesInProtocol::SendHandles>
               request =
@@ -79,7 +79,7 @@
           static_cast<::fdf::Server<::test_driverhandle::HandlesInProtocol>*>(
               interface)
               ->SendHandles(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_wire_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_wire_messaging.cc.golden
index adc789e..90e93d1 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_wire_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_wire_messaging.cc.golden
@@ -132,7 +132,7 @@
                   ::test_driverhandle::HandlesInProtocol::SendHandles>>
               decoded{std::move(msg)};
           if (unlikely(!decoded.ok())) {
-            return decoded.status();
+            return ::fidl::Status{decoded};
           }
           auto* primary = &decoded.PrimaryObject()->body;
           ::fidl::internal::WireCompleter<
@@ -144,7 +144,7 @@
               ::fdf::WireServer<::test_driverhandle::HandlesInProtocol>*>(
               interface)
               ->SendHandles(primary, arena, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_wire_messaging.h.golden b/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_wire_messaging.h.golden
index fece29c..96e4fbb 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/driver_handle_driver_wire_messaging.h.golden
@@ -189,10 +189,8 @@
                        t) == 0);
 #endif  // __Fuchsia__
 
-}  // namespace fidl
-namespace test_driverhandle {
 #ifdef __Fuchsia__
-}  // namespace test_driverhandle
+}  // namespace fidl
 template <>
 class [[nodiscard]] ::fdf::WireUnownedResult<
     ::test_driverhandle::HandlesInProtocol::SendHandles>
@@ -318,10 +316,11 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_driverhandle {
+namespace fidl {
 #endif  // __Fuchsia__
 
-}  // namespace test_driverhandle
+}  // namespace fidl
+namespace test_driverhandle {}  // namespace test_driverhandle
 #ifdef __Fuchsia__
 
 template <>
@@ -353,10 +352,10 @@
 };
 #endif  // __Fuchsia__
 
-namespace fidl {}  // namespace fidl
-namespace test_driverhandle {
+namespace fidl {
+
 #ifdef __Fuchsia__
-}  // namespace test_driverhandle
+}  // namespace fidl
 template <>
 class ::fidl::internal::WireEventHandlerInterface<
     ::test_driverhandle::DriverProtocol> {
@@ -441,11 +440,8 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_driverhandle {
-#endif  // __Fuchsia__
-
-}  // namespace test_driverhandle
 namespace fidl {
+#endif  // __Fuchsia__
 
 #ifdef __Fuchsia__
 }  // namespace fidl
diff --git a/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_natural_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_natural_messaging.cc.golden
index 7f14055..1341e6a 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_natural_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_natural_messaging.cc.golden
@@ -61,7 +61,7 @@
           ::fitx::result decoded = ::fidl::internal::DecodeTransactionalMessage<
               ::test_driveroneway::OneWaySendRequest>(std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<::test_driveroneway::OneWay::Send> request =
               ::fidl::internal::NaturalMessageConverter<
@@ -71,7 +71,7 @@
               ::test_driveroneway::OneWay::Send>::Sync completer(txn);
           static_cast<::fdf::Server<::test_driveroneway::OneWay>*>(interface)
               ->Send(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_wire_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_wire_messaging.cc.golden
index 34d6477..1d50fa7 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_wire_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_wire_messaging.cc.golden
@@ -120,7 +120,7 @@
                   ::test_driveroneway::OneWay::Send>>
               decoded{std::move(msg)};
           if (unlikely(!decoded.ok())) {
-            return decoded.status();
+            return ::fidl::Status{decoded};
           }
           auto* primary = &decoded.PrimaryObject()->body;
           ::fidl::internal::WireCompleter<
@@ -130,7 +130,7 @@
           reinterpret_cast<::fdf::WireServer<::test_driveroneway::OneWay>*>(
               interface)
               ->Send(primary, arena, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();
         },
     },
 };
diff --git a/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_wire_messaging.h.golden b/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_wire_messaging.h.golden
index 832c7e8..b896623 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_wire_messaging.h.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/driver_one_way_driver_wire_messaging.h.golden
@@ -153,11 +153,8 @@
         ::fidl::WireRequest<::test_driveroneway::OneWay::Send>>::kPrimarySize);
 static_assert(offsetof(::fidl::WireRequest<::test_driveroneway::OneWay::Send>,
                        payload) == 0);
-
-}  // namespace fidl
-namespace test_driveroneway {
 #ifdef __Fuchsia__
-}  // namespace test_driveroneway
+}  // namespace fidl
 template <>
 class [[nodiscard]] ::fdf::WireUnownedResult<::test_driveroneway::OneWay::Send>
     final : public ::fidl::Status {
@@ -272,11 +269,8 @@
       ::fidl::IncomingMessage&& msg, ::fidl::Transaction* txn,
       ::fidl::internal::IncomingTransportContext transport_context) final;
 };
-namespace test_driveroneway {
-#endif  // __Fuchsia__
-
-}  // namespace test_driveroneway
 namespace fidl {
+#endif  // __Fuchsia__
 
 #ifdef __Fuchsia__
 }  // namespace fidl
diff --git a/tools/fidl/fidlgen_llcpp/goldens/driver_two_way_driver_natural_messaging.cc.golden b/tools/fidl/fidlgen_llcpp/goldens/driver_two_way_driver_natural_messaging.cc.golden
index 5dac580..a24957f9 100644
--- a/tools/fidl/fidlgen_llcpp/goldens/driver_two_way_driver_natural_messaging.cc.golden
+++ b/tools/fidl/fidlgen_llcpp/goldens/driver_two_way_driver_natural_messaging.cc.golden
@@ -101,7 +101,7 @@
           ::fitx::result decoded = ::fidl::internal::DecodeTransactionalMessage<
               ::test_drivertwoway::TwoWayAddRequest>(std::move(msg));
           if (decoded.is_error()) {
-            return decoded.error_value().status();
+            return decoded.error_value();
           }
           ::fidl::Request<::test_drivertwoway::TwoWay::Add> request =
               ::fidl::internal::NaturalMessageConverter<
@@ -111,7 +111,7 @@
               ::test_drivertwoway::TwoWay::Add>::Sync completer(txn);
           static_cast<::fdf::Server<::test_drivertwoway::TwoWay>*>(interface)
               ->Add(request, completer);
-          return ZX_OK;
+          return ::fidl::Status::Ok();