[release] Snap to f887291593
Change-Id: Icd8c228113314f5bce7d806ea018d63587733aac
diff --git a/bundles/fidl/BUILD.gn b/bundles/fidl/BUILD.gn
index e97c509..ad9a8ac 100644
--- a/bundles/fidl/BUILD.gn
+++ b/bundles/fidl/BUILD.gn
@@ -19,6 +19,7 @@
     "//src/lib/fidl_table_validation/fidl_table_validation_tests",
     "//src/tests/fidl/dyn_suite",
     "//src/tests/fidl/go_bindings_test",
+    "//src/tests/fidl/server_suite",
     "//third_party/go:fidl-tests",
     "//tools/fidl:tests",
     "//zircon/system/ulib/fidl-async-2/test",
diff --git a/docs/contribute/_toc.yaml b/docs/contribute/_toc.yaml
index e92a0d8..b60917b 100644
--- a/docs/contribute/_toc.yaml
+++ b/docs/contribute/_toc.yaml
@@ -39,3 +39,5 @@
 - heading: Issues
 - title: "Report an issue"
   path: /docs/contribute/report-issue.md
+- title: "Report a security issue"
+  path: /docs/contribute/report-security-issue.md
diff --git a/docs/contribute/report-security-issue.md b/docs/contribute/report-security-issue.md
new file mode 100644
index 0000000..a436801
--- /dev/null
+++ b/docs/contribute/report-security-issue.md
@@ -0,0 +1,82 @@
+# Report a security issue
+
+Filing a security issue is a great way to contribute to the Fuchsia project.
+You can file a security issue using Monorail, Google's issue tracking tool for
+open source projects.
+
+Security issue reports that relate to Fuchsia may be eligible for reward
+payments under the Android and Google Devices Security Reward Program.
+
+Note: You need a Google account to file an issue in Monorail.
+
+## File a new security issue
+To file a security issue in Fuchsia, use the [Fuchsia security bug report](https://bugs.fuchsia.dev/p/fuchsia/issues/entry?template=Fuchsia+security+bug+report) template
+in the [Fuchsia issue tracker](https://bugs.fuchsia.dev) and provide
+the details of your issue.
+
+### Android and Google Devices Security Reward Program
+
+Security issue reports that relate to Fuchsia may be eligible for reward
+payments under the Android and Google Devices Security Reward Program.
+
+For more information on the program's details and eligibility, see
+[Android and Google Devices Security Reward Program](https://bughunters.google.com/about/rules/6171833274204160/android-and-google-devices-security-reward-program-rules) and
+[Google Bug Hunters - Fuchsia](https://bughunters.google.com/report/targets/189296641).
+
+###  Complete the issue template
+
+Include the following information in your issue description:
+
+* **Bug or vulnerability details**
+
+    Provide a brief explanation of the security issue, including any of
+    the following:
+
+    * The location of that issue in the code or in the user interface.
+    * The category of the security issue. Categories include buffer overflow,
+    phishing, broken cryptography, authorization bypass, etc.
+    * The types of assets affected. Asset types include browser
+    cookies, control of a device, personally-identifiable information, etc.
+
+* **Version information**
+
+    Provide any version information associated with your security issue, for example:
+
+    * fuchsia.git revision number
+    * Fuchsia version number
+    * Product name (for example, Nest Hub)
+
+*  **Steps to reproduce / proof-of-concept**
+
+    Provide a demonstration or list of steps needed to reproduce the security
+    issue.
+
+    Demonstration information can include the following:
+
+    * Source code
+    * Address Sanitizer dumps
+    * Debugger output
+    * Example inputs, for example, a JPEG file that crashes the JPEG handler
+
+    Minimize the proof-of-concept files
+    and attach them directly to the issue in Monorail, not within zip or other
+    archive formats.
+
+    Be sure to remove any content not required to demonstrate the
+    issue, including any personal or confidential information.
+
+*  **Credit information for Common Vulnerabilities and Exposures (CVE) and/or Release Notes**
+
+    Published security issues are publicly visible. For example, a
+    security issue can be published as a CVE or as a part of the
+    release notes. If you'd like to be credited for your discovery,
+    provide a one-line description stating how you'd like to be publicly
+    credited. You can use your name, a pseudonym, or you can remain anonymous.
+
+## Issue resolution
+
+The Fuchsia Security team triages incoming issues and assigns those issues
+to the appropriate team. The assigned team can then prioritize, assign, and
+respond to the issue with guidance from the Fuchsia Security team. The
+assigned team may be indicated within the issue
+through the **Components** section in Monorail.
diff --git a/sdk/fidl/fuchsia.component.resolution/component.fidl b/sdk/fidl/fuchsia.component.resolution/component.fidl
index e907183..e8e8c6d 100644
--- a/sdk/fidl/fuchsia.component.resolution/component.fidl
+++ b/sdk/fidl/fuchsia.component.resolution/component.fidl
@@ -58,6 +58,9 @@
 // fuchsia.pkg implements subpackages, assuming fuchsia.pkg implements the
 // package context value as a much smaller lookup key (such as a package hash to
 // the package containing the subpackage map).
+//
+// ALSO, change the constant name's suffix from LENGTH to SIZE per FIDL style
+// guidelines.
 
 // Note the context length, in bytes, must be at least the size of
 // fuchsia.pkg.MAX_RESOLUTION_CONTEXT_LENGTH, plus the size required to
diff --git a/sdk/fidl/fuchsia.pkg/common.fidl b/sdk/fidl/fuchsia.pkg/common.fidl
index a200e49..2c884e1 100644
--- a/sdk/fidl/fuchsia.pkg/common.fidl
+++ b/sdk/fidl/fuchsia.pkg/common.fidl
@@ -33,3 +33,25 @@
     package_url PackageUrl;
     meta_far_blob_id BlobId;
 };
+
+/// A package resolution context, used when resolving package URLs relative to
+/// another package.
+type ResolutionContext = struct {
+    bytes bytes:MAX_RESOLUTION_CONTEXT_SIZE;
+};
+
+// TODO(fxbug.dev/100050): Change this length to something smaller once
+// fuchsia.pkg implements subpackages, assuming fuchsia.pkg implements the
+// package context value as a much smaller lookup key (such as a package hash to
+// the package containing the subpackage map). Make a related change to
+// the component's MAX_RESOLUTION_CONTEXT_LENGTH (to be
+// renamed MAX_RESOLUTION_CONTEXT_SIZE) in
+// //sdk/fidl/fuchsia.component.resolution/resolver.fidl
+
+/// The maximum number of bytes for a `ResolutionContext`.
+///
+/// Note that this value must be less than or equal to
+/// `fuchsia.component.resolution::MAX_RESOLUTION_CONTEXT_LENGTH`, since the
+/// component resolver is expected to copy or contain the context provided by
+/// the package resolver.
+const MAX_RESOLUTION_CONTEXT_SIZE uint32 = 8192;
diff --git a/sdk/fidl/fuchsia.pkg/resolver.fidl b/sdk/fidl/fuchsia.pkg/resolver.fidl
index 543aa13..fa2c7d7 100644
--- a/sdk/fidl/fuchsia.pkg/resolver.fidl
+++ b/sdk/fidl/fuchsia.pkg/resolver.fidl
@@ -46,21 +46,58 @@
 /// repository administration tools.
 @discoverable
 protocol PackageResolver {
-    /// Populates or updates the cache of a package.
+    /// Populates or updates the cache of a package using an absolute package
+    /// URL.
     ///
-    /// Ensures that a package is on the local filesystem.
+    /// Ensures that a package, and any transitive subpackages, are on the local
+    /// filesystem.
     ///
-    /// + request `package_url` the package URL for a package. The following link describes
-    ///   the format, resource paths are not allowed:
+    /// + request `package_url` the absolute package URL for a package.  The
+    ///   following link describes the format:
     ///   https://fuchsia.dev/fuchsia-src/concepts/packages/package_url.
-    /// + request `dir` a request for a directory that will be resolved when the package has
-    ///   been successfully cached.
-    /// * error indicates failure. See `ResolveError` for values and error scenarios.
+    ///   Resource paths are not allowed.
+    /// + request `dir` a request for a directory that will be resolved when the
+    ///   package has been successfully cached.
+    /// + returns a `resolved_context`, which can be passed to
+    ///   `ResolveWithContext`, with a relative URL, to resolve a subpackage of
+    ///   this package.
+    /// * error indicates failure. See `ResolveError` for values and error
+    ///   scenarios.
     // TODO(fxbug.dev/45811) change `package_url` from string to PackageUrl
     Resolve(resource struct {
         package_url string;
         dir server_end:fuchsia.io.Directory;
-    }) -> (struct {}) error ResolveError;
+    }) -> (struct {
+        resolved_context ResolutionContext;
+    }) error ResolveError;
+
+    /// Populates or updates the cache of a package using either an absolute or
+    /// a relative package URL. If relative, the package will be resolved
+    /// relative to the supplied `context`.
+    ///
+    /// Ensures that a package is on the local filesystem.
+    ///
+    /// + request `package_url` the absolute or relative package URL for a
+    ///   package. If absolute, the `context` is ignored, and the behavior is
+    ///   identical to calling `Resolve()`. A relative `package_url` is a
+    ///   subpackage name.
+    /// + request `context` a `ResolutionContext` associated with a previously
+    ///   resolved package, for resolving subpackages relative to that package.
+    /// + request `dir` a request for a directory that will be resolved when the
+    ///   package has been successfully cached.
+    /// + returns a `resolved_context`, which can be passed to a subsequent call
+    ///   to `ResolveWithContext`, with a relative URL, to resolve a subpackage
+    ///   of this package or subpackage.
+    /// * error indicates failure. See `ResolveError` for values and error
+    ///   scenarios.
+    // TODO(fxbug.dev/45811) change `package_url` from string to PackageUrl
+    ResolveWithContext(resource struct {
+        package_url string;
+        context ResolutionContext;
+        dir server_end:fuchsia.io.Directory;
+    }) -> (struct {
+        resolved_context ResolutionContext;
+    }) error ResolveError;
 
     /// Determines the hash of a package.
     ///
diff --git a/sdk/lib/device-watcher/cpp/device-watcher.cc b/sdk/lib/device-watcher/cpp/device-watcher.cc
index 69c59e1..2b07043 100644
--- a/sdk/lib/device-watcher/cpp/device-watcher.cc
+++ b/sdk/lib/device-watcher/cpp/device-watcher.cc
@@ -4,6 +4,7 @@
 
 #include "device-watcher.h"
 
+#include <dirent.h>
 #include <fcntl.h>
 #include <fidl/fuchsia.device/cpp/wire.h>
 #include <fidl/fuchsia.io/cpp/wire.h>
@@ -32,11 +33,15 @@
   if (endpoints.is_error()) {
     return endpoints.status_value();
   }
+
   fdio_t* io = fdio_unsafe_fd_to_io(dir_fd.get());
   zx::unowned_channel channel{fdio_unsafe_borrow_channel(io)};
 
+  // Make a one-off call to fuchsia.io.Directory.Watch to open a channel from
+  // which watch events can be read.
   auto result = fidl::WireCall(fidl::UnownedClientEnd<fio::Directory>(channel))
                     ->Watch(fio::wire::WatchMask::kRemoved, 0, std::move(endpoints->server));
+
   fdio_unsafe_release(io);
   if (!result.ok()) {
     return result.status();
@@ -84,6 +89,51 @@
   return ZX_ERR_NOT_FOUND;
 }
 
+__EXPORT
+zx_status_t IterateDirectory(fbl::unique_fd fd, FileCallback callback) {
+  struct dirent* entry;
+
+  DIR* dir = fdopendir(fd.get());
+  if (dir == nullptr) {
+    return ZX_ERR_IO;
+  }
+
+  fdio_t* io = fdio_unsafe_fd_to_io(fd.get());
+  zx::unowned_channel dir_channel{fdio_unsafe_borrow_channel(io)};
+
+  zx_status_t status = ZX_OK;
+  while ((entry = readdir(dir)) != nullptr) {
+    std::string filename(entry->d_name);
+    if (filename == "." || filename == "..") {
+      continue;
+    }
+
+    auto endpoints = fidl::CreateEndpoints<fio::Node>();
+    if (endpoints.is_error()) {
+      status = endpoints.status_value();
+      goto finish;
+    }
+
+    // Open a channel to the file.
+    status = fdio_open_at(dir_channel->get(), entry->d_name, 0,
+                          endpoints->server.TakeChannel().release());
+    if (status != ZX_OK) {
+      goto finish;
+    }
+
+    // Invoke the user-provided callback.
+    status = callback(filename, endpoints->client.TakeChannel());
+    if (status != ZX_OK) {
+      goto finish;
+    }
+  }
+
+finish:
+  fdio_unsafe_release(io);
+  closedir(dir);
+  return status;
+}
+
 // Waits for |file| to appear in |dir|, and opens it when it does.  Times out if
 // the deadline passes.
 __EXPORT
diff --git a/sdk/lib/device-watcher/cpp/device-watcher.h b/sdk/lib/device-watcher/cpp/device-watcher.h
index 23374b2..50aef97 100644
--- a/sdk/lib/device-watcher/cpp/device-watcher.h
+++ b/sdk/lib/device-watcher/cpp/device-watcher.h
@@ -5,6 +5,7 @@
 #ifndef LIB_DEVICE_WATCHER_CPP_DEVICE_WATCHER_H_
 #define LIB_DEVICE_WATCHER_CPP_DEVICE_WATCHER_H_
 
+#include <lib/fit/function.h>
 #include <lib/zx/channel.h>
 #include <lib/zx/status.h>
 
@@ -41,6 +42,14 @@
 // otherwise it will return ZX_ERR_NOT_SUPPORTED.
 zx_status_t RecursiveWaitForFileReadOnly(const char* path, fbl::unique_fd* out);
 
+// Invokes |callback| on each entry in the directory, returning immediately after all entries have
+// been processed. |callback| is passed the file name and a channel for the file's fuchsia.io.Node
+// protocol. If |callback| returns a status other than ZX_OK, iteration terminates immediately, and
+// the error status is returned. This function does not continue to watch the directory for newly
+// created files.
+using FileCallback = fit::function<zx_status_t(std::string_view, zx::channel)>;
+zx_status_t IterateDirectory(fbl::unique_fd fd, FileCallback callback);
+
 // DirWatcher can be used to detect when a file has been removed from the filesystem.
 //
 // Example usage:
@@ -66,6 +75,8 @@
   zx_status_t WaitForRemoval(std::string_view filename, zx::duration timeout);
 
  private:
+  // A channel opened by a call to fuchsia.io.Directory.Watch, from which watch
+  // events can be read.
   zx::channel client_;
 };
 
diff --git a/sdk/lib/device-watcher/cpp/test.cc b/sdk/lib/device-watcher/cpp/test.cc
index b421b71..6aaddba 100644
--- a/sdk/lib/device-watcher/cpp/test.cc
+++ b/sdk/lib/device-watcher/cpp/test.cc
@@ -16,6 +16,7 @@
 #include <sdk/lib/device-watcher/cpp/device-watcher.h>
 #include <zxtest/zxtest.h>
 
+#include "lib/async-loop/loop.h"
 #include "src/lib/storage/vfs/cpp/managed_vfs.h"
 #include "src/lib/storage/vfs/cpp/pseudo_dir.h"
 #include "src/lib/storage/vfs/cpp/pseudo_file.h"
@@ -142,3 +143,99 @@
   });
   ASSERT_EQ(sync_completion_wait(&shutdown, zx::duration::infinite().get()), ZX_OK);
 }
+
+class IterateDirectoryTest : public zxtest::Test {
+ public:
+  IterateDirectoryTest()
+      : loop_(&kAsyncLoopConfigNoAttachToCurrentThread), vfs_(loop_.dispatcher()) {}
+
+  void SetUp() override {
+    // Set up the fake filesystem.
+    auto file1 = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(
+        [](fbl::String* output) { return ZX_OK; }, [](std::string_view input) { return ZX_OK; });
+    auto file2 = fbl::MakeRefCounted<fs::UnbufferedPseudoFile>(
+        [](fbl::String* output) { return ZX_OK; }, [](std::string_view input) { return ZX_OK; });
+
+    auto first = fbl::MakeRefCounted<fs::PseudoDir>();
+    first->AddEntry("file1", file1);
+    first->AddEntry("file2", file2);
+
+    auto endpoints = fidl::CreateEndpoints<fuchsia_io::Directory>();
+    ASSERT_EQ(ZX_OK, endpoints.status_value());
+
+    loop_.StartThread();
+    vfs_.ServeDirectory(first, std::move(endpoints->server));
+
+    ASSERT_EQ(ZX_OK, fdio_fd_create(endpoints->client.TakeChannel().release(),
+                                    dir_.reset_and_get_address()));
+  }
+
+  void TearDown() override {
+    sync_completion_t shutdown;
+    vfs_.Shutdown([&shutdown](zx_status_t status) {
+      sync_completion_signal(&shutdown);
+      ASSERT_EQ(status, ZX_OK);
+    });
+    ASSERT_EQ(ZX_OK, sync_completion_wait(&shutdown, zx::duration::infinite().get()));
+    loop_.Shutdown();
+  }
+
+ protected:
+  async::Loop loop_;
+  fs::ManagedVfs vfs_;
+  fbl::unique_fd dir_;
+};
+
+TEST_F(IterateDirectoryTest, IterateDirectory) {
+  std::vector<std::string> seen;
+  zx_status_t status = device_watcher::IterateDirectory(
+      std::move(dir_), [&seen](std::string_view filename, zx::channel channel) {
+        // Collect the file names into the vector.
+        seen.emplace_back(filename);
+        return ZX_OK;
+      });
+  ASSERT_EQ(ZX_OK, status);
+
+  // Make sure the file names seen were as expected.
+  ASSERT_EQ(2, seen.size());
+  std::sort(seen.begin(), seen.end());
+  ASSERT_EQ("file1", seen[0]);
+  ASSERT_EQ("file2", seen[1]);
+}
+
+TEST_F(IterateDirectoryTest, IterateDirectoryCancelled) {
+  // Test that iteration is cancelled when the callback returns an error
+  std::vector<std::string> seen;
+  zx_status_t status = device_watcher::IterateDirectory(
+      std::move(dir_), [&seen](std::string_view filename, zx::channel channel) {
+        seen.emplace_back(filename);
+        return ZX_ERR_INTERNAL;
+      });
+  ASSERT_EQ(ZX_ERR_INTERNAL, status);
+
+  // Should only have seen a single file before exiting.
+  ASSERT_EQ(1, seen.size());
+}
+
+TEST_F(IterateDirectoryTest, IterateDirectoryChannel) {
+  // Test that we can use the channel passed to the callback function to make
+  // fuchsia.io.Node calls.
+  std::vector<uint64_t> content_sizes;
+  zx_status_t status = device_watcher::IterateDirectory(
+      std::move(dir_), [&content_sizes](std::string_view filename, zx::channel channel) {
+        auto result =
+            fidl::WireCall(fidl::UnownedClientEnd<fuchsia_io::Node>(channel.borrow()))->GetAttr();
+        if (!result.ok()) {
+          return result.status();
+        }
+        content_sizes.push_back(result.value().attributes.content_size);
+        return ZX_OK;
+      });
+  ASSERT_EQ(ZX_OK, status);
+
+  ASSERT_EQ(2, content_sizes.size());
+
+  // Files are empty.
+  ASSERT_EQ(0, content_sizes[0]);
+  ASSERT_EQ(0, content_sizes[1]);
+}
diff --git a/sdk/lib/driver_test_realm/support.cc b/sdk/lib/driver_test_realm/support.cc
index 7d7b241..fa6c73f 100644
--- a/sdk/lib/driver_test_realm/support.cc
+++ b/sdk/lib/driver_test_realm/support.cc
@@ -42,6 +42,7 @@
 #include <fbl/string_printf.h>
 #include <mock-boot-arguments/server.h>
 
+#include "lib/fidl/llcpp/vector_view.h"
 #include "lib/vfs/cpp/pseudo_dir.h"
 #include "src/lib/fxl/strings/join_strings.h"
 #include "src/lib/storage/vfs/cpp/pseudo_dir.h"
@@ -325,7 +326,14 @@
       return;
     }
 
-    completer.ReplySuccess();
+    auto resolution_context = fuchsia_pkg::wire::ResolutionContext({});
+    completer.ReplySuccess(resolution_context);
+  }
+
+  void ResolveWithContext(ResolveWithContextRequestView request,
+                          ResolveWithContextCompleter::Sync& completer) override {
+    FX_LOGF(ERROR, nullptr, "ResolveWithContext is not yet implemented in FakePackageResolver");
+    completer.ReplyError(fuchsia_pkg::wire::ResolveError::kInternal);
   }
 
   void GetHash(GetHashRequestView request, GetHashCompleter::Sync& completer) override {
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/integration.rs b/src/connectivity/network/netstack3/core/src/ip/device/integration.rs
index aa332a7..6489aba 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/integration.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/integration.rs
@@ -374,26 +374,29 @@
         SC: ip::BufferIpDeviceContext<Ipv6, C, EmptyBuf> + device::Ipv6DeviceContext<C>,
     > Ipv6LayerRsContext<C> for SC
 {
-    fn send_rs_packet<S: Serializer<Buffer = EmptyBuf>>(
+    fn send_rs_packet<
+        S: Serializer<Buffer = EmptyBuf>,
+        F: FnOnce(Option<UnicastAddr<Ipv6Addr>>) -> S,
+    >(
         &mut self,
         ctx: &mut C,
         device_id: Self::DeviceId,
         message: RouterSolicitation,
-        body: S,
+        body: F,
     ) -> Result<(), S> {
         let dst_ip = Ipv6::ALL_ROUTERS_LINK_LOCAL_MULTICAST_ADDRESS.into_specified();
+        let src_ip = crate::ip::socket::ipv6_source_address_selection::select_ipv6_source_address(
+            dst_ip,
+            device_id,
+            get_ipv6_device_state(self, device_id).iter_addrs().map(move |a| (a, device_id)),
+        );
         send_ndp_packet(
             self,
             ctx,
             device_id,
-            crate::ip::socket::ipv6_source_address_selection::select_ipv6_source_address(
-                dst_ip,
-                device_id,
-                get_ipv6_device_state(self, device_id).iter_addrs().map(move |a| (a, device_id)),
-            )
-            .map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
+            src_ip.map_or(Ipv6::UNSPECIFIED_ADDRESS, |a| a.get()),
             dst_ip,
-            body,
+            body(src_ip),
             IcmpUnusedCode,
             message,
         )
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/router_solicitation.rs b/src/connectivity/network/netstack3/core/src/ip/device/router_solicitation.rs
index e22e8a8b..dbe002c 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/router_solicitation.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/router_solicitation.rs
@@ -8,8 +8,11 @@
 
 use core::{num::NonZeroU8, time::Duration};
 
-use net_types::ip::Ipv6;
-use packet::{EmptyBuf, InnerPacketBuilder as _, Serializer};
+use net_types::{
+    ip::{Ipv6, Ipv6Addr},
+    UnicastAddr,
+};
+use packet::{EitherSerializer, EmptyBuf, InnerPacketBuilder as _, Serializer};
 use packet_formats::icmp::ndp::{
     options::NdpOptionBuilder, OptionSequenceBuilder, RouterSolicitation,
 };
@@ -68,12 +71,18 @@
 /// The IP layer context provided to RS.
 pub(super) trait Ipv6LayerRsContext<C>: IpDeviceIdContext<Ipv6> {
     /// Sends an NDP Router Solicitation to the local-link.
-    fn send_rs_packet<S: Serializer<Buffer = EmptyBuf>>(
+    ///
+    /// The callback is called with a source address suitable for an outgoing
+    /// router solicitation message and returns the message body.
+    fn send_rs_packet<
+        S: Serializer<Buffer = EmptyBuf>,
+        F: FnOnce(Option<UnicastAddr<Ipv6Addr>>) -> S,
+    >(
         &mut self,
         ctx: &mut C,
         device_id: Self::DeviceId,
         message: RouterSolicitation,
-        body: S,
+        body: F,
     ) -> Result<(), S>;
 }
 
@@ -148,15 +157,30 @@
 
     // TODO(https://fxbug.dev/85055): Either panic or guarantee that this error
     // can't happen statically.
-    let _: Result<(), _> = sync_ctx.send_rs_packet(
-        ctx,
-        device_id,
-        RouterSolicitation::default(),
-        OptionSequenceBuilder::new(
-            src_ll.as_ref().map(AsRef::as_ref).map(NdpOptionBuilder::SourceLinkLayerAddress).iter(),
-        )
-        .into_serializer(),
-    );
+    let _: Result<(), _> =
+        sync_ctx.send_rs_packet(ctx, device_id, RouterSolicitation::default(), |src_ip| {
+            // As per RFC 4861 section 4.1,
+            //
+            //   Valid Options:
+            //
+            //      Source link-layer address The link-layer address of the
+            //                     sender, if known. MUST NOT be included if the
+            //                     Source Address is the unspecified address.
+            //                     Otherwise, it SHOULD be included on link
+            //                     layers that have addresses.
+            src_ip.map_or(EitherSerializer::A(EmptyBuf), |UnicastAddr { .. }| {
+                EitherSerializer::B(
+                    OptionSequenceBuilder::new(
+                        src_ll
+                            .as_ref()
+                            .map(AsRef::as_ref)
+                            .into_iter()
+                            .map(NdpOptionBuilder::SourceLinkLayerAddress),
+                    )
+                    .into_serializer(),
+                )
+            })
+        });
 
     let remaining = sync_ctx.get_router_soliciations_remaining_mut(device_id);
     *remaining = NonZeroU8::new(
@@ -178,7 +202,7 @@
 
 #[cfg(test)]
 mod tests {
-    use alloc::vec;
+    use net_declare::net_ip_v6;
     use packet_formats::icmp::ndp::{options::NdpOption, Options};
     use test_case::test_case;
 
@@ -194,6 +218,7 @@
     struct MockRsContext<'a> {
         max_router_solicitations: Option<NonZeroU8>,
         router_soliciations_remaining: Option<NonZeroU8>,
+        source_address: Option<UnicastAddr<Ipv6Addr>>,
         link_layer_bytes: Option<&'a [u8]>,
     }
 
@@ -210,6 +235,7 @@
             let MockRsContext {
                 max_router_solicitations,
                 router_soliciations_remaining: _,
+                source_address: _,
                 link_layer_bytes: _,
             } = self.get_ref();
             *max_router_solicitations
@@ -222,6 +248,7 @@
             let MockRsContext {
                 max_router_solicitations: _,
                 router_soliciations_remaining,
+                source_address: _,
                 link_layer_bytes: _,
             } = self.get_mut();
             router_soliciations_remaining
@@ -231,6 +258,7 @@
             let MockRsContext {
                 max_router_solicitations: _,
                 router_soliciations_remaining: _,
+                source_address: _,
                 link_layer_bytes,
             } = self.get_ref();
             *link_layer_bytes
@@ -238,14 +266,23 @@
     }
 
     impl<'a> Ipv6LayerRsContext<MockNonSyncCtx> for MockCtx<'a> {
-        fn send_rs_packet<S: Serializer<Buffer = EmptyBuf>>(
+        fn send_rs_packet<
+            S: Serializer<Buffer = EmptyBuf>,
+            F: FnOnce(Option<UnicastAddr<Ipv6Addr>>) -> S,
+        >(
             &mut self,
             ctx: &mut MockNonSyncCtx,
             DummyDeviceId: DummyDeviceId,
             message: RouterSolicitation,
-            body: S,
+            body: F,
         ) -> Result<(), S> {
-            self.send_frame(ctx, RsMessageMeta { message }, body)
+            let MockRsContext {
+                max_router_solicitations: _,
+                router_soliciations_remaining: _,
+                source_address,
+                link_layer_bytes: _,
+            } = self.get_ref();
+            self.send_frame(ctx, RsMessageMeta { message }, body(*source_address))
         }
     }
 
@@ -257,6 +294,7 @@
             DummyCtx::with_sync_ctx(MockCtx::with_state(MockRsContext {
                 max_router_solicitations: NonZeroU8::new(1),
                 router_soliciations_remaining: None,
+                source_address: None,
                 link_layer_bytes: None,
             }));
         RsHandler::start_router_solicitation(&mut sync_ctx, &mut non_sync_ctx, DummyDeviceId);
@@ -272,24 +310,50 @@
         assert_eq!(sync_ctx.frames(), &[][..]);
     }
 
-    #[test_case(0, None; "disabled")]
-    #[test_case(1, None; "once_without_source_link_layer_option")]
-    #[test_case(1, Some((&[1, 2, 3, 4, 5, 6], 0)); "once_with_mac_address_source_link_layer_option")]
-    #[test_case(1, Some((&[1, 2, 3, 4, 5], 1)); "once_with_short_address_source_link_layer_option")]
-    #[test_case(1, Some((&[1, 2, 3, 4, 5, 6, 7], 7)); "once_with_long_address_source_link_layer_option")]
+    const SOURCE_ADDRESS: UnicastAddr<Ipv6Addr> =
+        unsafe { UnicastAddr::new_unchecked(net_ip_v6!("fe80::1")) };
+
+    #[test_case(0, None, None, None; "disabled")]
+    #[test_case(1, None, None, None; "once_without_source_address_or_link_layer_option")]
+    #[test_case(
+        1,
+        Some(SOURCE_ADDRESS),
+        None,
+        None; "once_with_source_address_and_without_link_layer_option")]
+    #[test_case(
+        1,
+        None,
+        Some(&[1, 2, 3, 4, 5, 6]),
+        None; "once_without_source_address_and_with_mac_address_source_link_layer_option")]
+    #[test_case(
+        1,
+        Some(SOURCE_ADDRESS),
+        Some(&[1, 2, 3, 4, 5, 6]),
+        Some(&[1, 2, 3, 4, 5, 6]); "once_with_source_address_and_mac_address_source_link_layer_option")]
+    #[test_case(
+        1,
+        Some(SOURCE_ADDRESS),
+        Some(&[1, 2, 3, 4, 5]),
+        Some(&[1, 2, 3, 4, 5, 0]); "once_with_source_address_and_short_address_source_link_layer_option")]
+    #[test_case(
+        1,
+        Some(SOURCE_ADDRESS),
+        Some(&[1, 2, 3, 4, 5, 6, 7]),
+        Some(&[
+            1, 2, 3, 4, 5, 6, 7,
+            0, 0, 0, 0, 0, 0, 0,
+        ]); "once_with_source_address_and_long_address_source_link_layer_option")]
     fn perform_router_solicitation(
         max_router_solicitations: u8,
-        link_layer_bytes: Option<(&[u8], u8)>,
+        source_address: Option<UnicastAddr<Ipv6Addr>>,
+        link_layer_bytes: Option<&[u8]>,
+        expected_sll_bytes: Option<&[u8]>,
     ) {
-        // NDP options have lengths in 8 byte increments so the option may be
-        // padded if the address does not fit cleanly in the option.
-        let (link_layer_bytes, expected_pad_bytes) =
-            link_layer_bytes.map_or((None, 0), |(a, b)| (Some(a), b));
-
         let DummyCtx { mut sync_ctx, mut non_sync_ctx } =
             DummyCtx::with_sync_ctx(MockCtx::with_state(MockRsContext {
                 max_router_solicitations: NonZeroU8::new(max_router_solicitations),
                 router_soliciations_remaining: None,
+                source_address,
                 link_layer_bytes,
             }));
         RsHandler::start_router_solicitation(&mut sync_ctx, &mut non_sync_ctx, DummyDeviceId);
@@ -320,21 +384,7 @@
                 o => panic!("unexpected NDP option = {:?}", o),
             });
 
-            match (sll_bytes, link_layer_bytes) {
-                (Some(sll_bytes), Some(link_layer_bytes)) => {
-                    assert_eq!(&sll_bytes[..link_layer_bytes.len()], link_layer_bytes);
-                    assert_eq!(
-                        sll_bytes[link_layer_bytes.len()..],
-                        vec![0; expected_pad_bytes.into()]
-                    );
-                }
-                (None, None) => {}
-                (sll_bytes, link_layer_bytes) => panic!(
-                    "got sll_bytes = {:?}, want = {:?} with {} padding bytes",
-                    sll_bytes, link_layer_bytes, expected_pad_bytes
-                ),
-            }
-
+            assert_eq!(sll_bytes, expected_sll_bytes);
             duration = RTR_SOLICITATION_INTERVAL;
         }
 
diff --git a/src/connectivity/network/netstack3/core/src/ip/device/slaac.rs b/src/connectivity/network/netstack3/core/src/ip/device/slaac.rs
index 4af0012..27866f8 100644
--- a/src/connectivity/network/netstack3/core/src/ip/device/slaac.rs
+++ b/src/connectivity/network/netstack3/core/src/ip/device/slaac.rs
@@ -172,18 +172,10 @@
 ///
 /// May panic if `addr` is not an address configured via SLAAC on
 /// `device_id`.
-fn update_slaac_addr_valid_until<C: SlaacNonSyncContext<SC::DeviceId>, SC: SlaacStateContext<C>>(
-    sync_ctx: &mut SC,
-    device_id: SC::DeviceId,
-    addr: &UnicastAddr<Ipv6Addr>,
-    valid_until: Lifetime<C::Instant>,
+fn update_slaac_addr_valid_until<I: Instant>(
+    slaac_config: &mut SlaacConfig<I>,
+    valid_until: Lifetime<I>,
 ) {
-    let slaac_config = sync_ctx
-        .iter_slaac_addrs_mut(device_id)
-        .find_map(|SlaacAddressEntryMut { addr_sub, config, deprecated: _ }| {
-            (addr_sub.addr() == *addr).then(|| config)
-        })
-        .expect("address is not configured via SLAAC on this device");
     match slaac_config {
         SlaacConfig::Static { valid_until: v } => *v = valid_until,
         SlaacConfig::Temporary(TemporarySlaacConfig {
@@ -274,23 +266,40 @@
             return;
         }
 
+        let mut seen_static = false;
+        let mut seen_temporary = false;
+
         let now = ctx.now();
-        let existing_subnet_slaac_addrs: Vec<_> =
-            self.iter_slaac_addrs(device_id).filter(|a| a.addr_sub.subnet() == subnet).collect();
+        let config = self.get_config(device_id);
+        let dad_transmits = self.dad_transmits(device_id);
+        let retrans_timer = self.retrans_timer(device_id);
 
         // Apply the update to each existing address, static or temporary, for the
         // prefix.
-        for entry in existing_subnet_slaac_addrs.iter() {
+        for entry in self.iter_slaac_addrs_mut(device_id).filter(|a| a.addr_sub.subnet() == subnet)
+        {
             let addr_sub = entry.addr_sub;
             let addr = addr_sub.addr();
             let slaac_config = &entry.config;
+            let slaac_type = SlaacType::from(&**slaac_config);
 
             trace!(
-            "receive_ndp_packet: already have a {:?} SLAAC address {:?} configured on device {:?}",
-            SlaacType::from(slaac_config),
-            addr_sub,
-            device_id
-        );
+                "receive_ndp_packet: already have a {:?} SLAAC address {:?} configured on device {:?}",
+                slaac_type,
+                addr_sub,
+                device_id
+            );
+
+            // Mark the SLAAC address type as existing so we know not to
+            // generate an address for the type later.
+            //
+            // Note that SLAAC addresses are never invalidated/removed in
+            // response to a prefix update and addresses types never change
+            // after the address is added.
+            match slaac_type {
+                SlaacType::Static => seen_static = true,
+                SlaacType::Temporary => seen_temporary = true,
+            }
 
             /// Encapsulates a lifetime bound and where it came from.
             #[derive(Copy, Clone)]
@@ -328,7 +337,7 @@
                     let SlaacConfiguration {
                         enable_stable_addresses: _,
                         temporary_address_configuration,
-                    } = self.get_config(device_id);
+                    } = config;
                     let (valid_for, preferred_for, entry_valid_until) =
                         match temporary_address_configuration {
                             // Since it's possible to change NDP configuration for a
@@ -397,11 +406,10 @@
                         };
 
                     let preferred_for_and_regen_at = preferred_for.map(|preferred_for| {
-                        let dad_transmits = self.dad_transmits(device_id);
                         let SlaacConfiguration {
                             enable_stable_addresses: _,
                             temporary_address_configuration,
-                        } = self.get_config(device_id);
+                        } = config;
 
                         let regen_at = temporary_address_configuration.and_then(
                             |TemporarySlaacAddressConfiguration {
@@ -412,7 +420,7 @@
                              }| {
                                 let regen_advance = regen_advance(
                                     temp_idgen_retries,
-                                    self.retrans_timer(device_id),
+                                    retrans_timer,
                                     dad_transmits.map_or(0, NonZeroU8::get),
                                 )
                                 .get();
@@ -455,13 +463,6 @@
             // Preferred Lifetime in the received advertisement.
 
             // Update the preferred lifetime for this address.
-            //
-            // Must not have reached this point if the address was not already
-            // assigned to a device.
-            let entry = self
-                .iter_slaac_addrs_mut(device_id)
-                .find(|a| a.addr_sub == entry.addr_sub)
-                .unwrap();
             match preferred_for_and_regen_at {
                 None => {
                     if !*entry.deprecated {
@@ -576,12 +577,8 @@
                         trace!("receive_ndp_packet: updating valid lifetime to {:?} for SLAAC address {:?} on device {:?}", valid_until, addr, device_id);
 
                         // Set the valid lifetime for this address.
-                        update_slaac_addr_valid_until(
-                            self,
-                            device_id,
-                            &addr,
-                            Lifetime::Finite(valid_until),
-                        );
+
+                        update_slaac_addr_valid_until(entry.config, Lifetime::Finite(valid_until));
 
                         let _: Option<C::Instant> = ctx.schedule_timer_instant(
                             valid_until,
@@ -590,7 +587,7 @@
                     }
                     NonZeroNdpLifetime::Infinite => {
                         // Set the valid lifetime for this address.
-                        update_slaac_addr_valid_until(self, device_id, &addr, Lifetime::Infinite);
+                        update_slaac_addr_valid_until(entry.config, Lifetime::Infinite);
 
                         let _: Option<C::Instant> = ctx.cancel_timer(
                             SlaacTimerId::new_invalidate_slaac_address(device_id, addr).into(),
@@ -621,33 +618,34 @@
                 return;
             }
         };
-        let address_types_to_add =
-            IntoIterator::into_iter([SlaacType::Static, SlaacType::Temporary]).filter(
-                |slaac_type| {
-                    let mut of_same_slaac_type = existing_subnet_slaac_addrs.iter().filter(|a| {
-                        match a.config {
-                            SlaacConfig::Static { valid_until: _ } => {
-                                // From RFC 4862 Section 5.5.3.d: "If the prefix advertised
-                                // is not equal to the prefix of an address configured by
-                                // stateless autoconfiguration already in the list of
-                                // addresses associated with the interface (where 'equal'
-                                // means the two prefix lengths are the same and the first
-                                // prefix- length bits of the prefixes are identical), and
-                                // if the Valid Lifetime is not 0, form an address [...]"
-                                *slaac_type == SlaacType::Static
-                            }
-                            SlaacConfig::Temporary(_) => {
-                                // From RFC 8981 Section 3.4.3: "If the host has not
-                                // configured any temporary address for the corresponding
-                                // prefix, the host SHOULD create a new temporary address
-                                // for such prefix."
-                                *slaac_type == SlaacType::Temporary
-                            }
-                        }
-                    });
-                    // Add addresses only if there are none already present.
-                    of_same_slaac_type.next() == None
-                },
+
+        let address_types_to_add = (!seen_static)
+            .then(|| {
+                // As per RFC 4862 Section 5.5.3.d,
+                //
+                //
+                //   If the prefix advertised is not equal to the prefix of an
+                //   address configured by stateless autoconfiguration already
+                //   in the list of addresses associated with the interface
+                //   (where 'equal' means the two prefix lengths are the same
+                //   and the first prefix- length bits of the prefixes are
+                //   identical), and if the Valid Lifetime is not 0, form an
+                //   address [...].
+                SlaacType::Static
+            })
+            .into_iter()
+            .chain(
+                (!seen_temporary)
+                    .then(|| {
+                        // As per RFC 8981 Section 3.4.3,
+                        //
+                        //   If the host has not configured any temporary
+                        //   address for the corresponding prefix, the host
+                        //   SHOULD create a new temporary address for such
+                        //   prefix.
+                        SlaacType::Temporary
+                    })
+                    .into_iter(),
             );
 
         for slaac_type in address_types_to_add {
diff --git a/src/developer/ffx/plugins/scrutiny/verify/args/bootfs.rs b/src/developer/ffx/plugins/scrutiny/verify/args/bootfs.rs
index 80520d9..5c87b8f 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/args/bootfs.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/args/bootfs.rs
@@ -10,16 +10,19 @@
     subcommand,
     name = "bootfs",
     description = "Verifies list of files in bootfs embedded in ZBI image against a golden file",
-    example = "To verify bootfs on your current build:
+    example = r#"To verify bootfs on your current build:
 
-        $ ffx scrutiny verify bootfs --zbi path/to/image.zbi --golden path/to/bootfs_golden",
+    $ ffx scrutiny verify bootfs \
+        --zbi $(fx get-build-dir)/obj/build/images/fuchsia/fuchsia/fuchsia.zbi \
+        --golden /path/to/goldens/product.txt \
+        --golden /path/to/goldens/board.txt"#,
     note = "Verifies all file paths in bootfs."
 )]
 pub struct Command {
-    /// path to ZBI image file that contains bootfs.
+    /// absolute or working directory-relative path to ZBI image file that contains bootfs.
     #[argh(option)]
     pub zbi: PathBuf,
-    /// path(s) to golden file(s) for verifying bootfs paths.
+    /// absolute or working directory-relative path(s) to golden file(s) for verifying bootfs paths.
     #[argh(option)]
     pub golden: Vec<PathBuf>,
 }
diff --git a/src/developer/ffx/plugins/scrutiny/verify/args/component_resolvers.rs b/src/developer/ffx/plugins/scrutiny/verify/args/component_resolvers.rs
index 6d858dd..5c71bd1 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/args/component_resolvers.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/args/component_resolvers.rs
@@ -15,25 +15,27 @@
     description = "Verifies that component configured to use custom component resolvers are permitted by an allowlist.",
     example = "To verify component resolvers on your current eng build:
 
-        $ ffx scrutiny verify component-resolvers \
-            --build-path $(fx get-build-dir) \
-            --repository-path $(fx get-build-dir)/amber-files/repository \
-            --allowlist path/to/allowlist.json5",
+    $ ffx scrutiny verify component-resolvers \
+        --build-path $(fx get-build-dir) \
+        --update obj/build/images/fuchsia/update/update.far \
+        --blobfs obj/build/images/fuchsia/fuchsia/blob.blk \
+        --blobfs obj/build/images/fuchsia/update/gen/update.blob.blk \
+        --allowlist ../../src/security/policy/component_resolvers_policy.json5",
     note = "Verifies all components that use a custom component resolver."
 )]
 pub struct Command {
-    /// path to fuchsia build directory.
+    /// absolute or working directory-relative path to fuchsia build directory.
     #[argh(option)]
     pub build_path: PathBuf,
-    /// path to fuchsia update package.
+    /// absolute or build path-relative path to fuchsia update package.
     #[argh(option)]
     pub update: PathBuf,
-    /// path to one or more blobfs archives that contain fuchsia packages and
-    /// their packages.
+    /// absolute or build path-relative path to one or more blobfs archives that contain fuchsia
+    /// packages and their packages.
     #[argh(option)]
     pub blobfs: Vec<PathBuf>,
-    /// path to allowlist file that specifies which components may use
-    /// particular custom component resolvers.
+    /// absolute or build path-relative path to allowlist file that specifies which components may
+    /// use particular custom component resolvers.
     #[argh(option)]
     pub allowlist: PathBuf,
 }
diff --git a/src/developer/ffx/plugins/scrutiny/verify/args/kernel_cmdline.rs b/src/developer/ffx/plugins/scrutiny/verify/args/kernel_cmdline.rs
index 544a981..4b7793f 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/args/kernel_cmdline.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/args/kernel_cmdline.rs
@@ -12,18 +12,19 @@
 #[argh(
     subcommand,
     name = "kernel-cmdline",
-    description = "Verifies that kernel commandline arguments match golden files.",
-    example = "To verify kernel cmdline arguments on your current build:
+    description = "Verifies that kernel cmdline arguments match golden files.",
+    example = r#"To verify kernel cmdline arguments on your current build:
 
-        $ ffx scrutiny verify kernel-cmdline \
-            --zbi path/to/image.zbi \
-            --golden path/to/golden"
+    $ ffx scrutiny verify kernel-cmdline \
+        --zbi $(fx get-build-dir)/obj/build/images/fuchsia/fuchsia/fuchsia.zbi \
+        --golden path/to/golden"#
 )]
 pub struct Command {
-    /// path to ZBI image file that contains bootfs.
+    /// absolute or working directory-relative path to ZBI image file that contains bootfs.
     #[argh(option)]
     pub zbi: PathBuf,
-    /// path(s) to golden files to compare against during verification.
+    /// absolute or working directory-relative path(s) to golden files to compare against during
+    /// verification.
     #[argh(option)]
     pub golden: Vec<PathBuf>,
 }
diff --git a/src/developer/ffx/plugins/scrutiny/verify/args/route_sources.rs b/src/developer/ffx/plugins/scrutiny/verify/args/route_sources.rs
index 688413b..e6e6c72 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/args/route_sources.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/args/route_sources.rs
@@ -13,27 +13,28 @@
     subcommand,
     name = "route-sources",
     description = "Verifies that routes to designated components are routed from designated sources.",
-    example = "To verify route sources according to a configuration file on your current build:
+    example = r#"To verify route sources according to a configuration file on your current build:
 
-        $ ffx scrutiny verify route-sources
-            --build-path $(fx get-build-dir) \
-            --update path/to/update.far \
-            --blobfs path/to/blob.blk \
-            --config path/to/verify_route_sources_config.json"
+    $ ffx scrutiny verify route-sources
+        --build-path $(fx get-build-dir) \
+        --update obj/build/images/fuchsia/update/update.far \
+        --blobfs obj/build/images/fuchsia/fuchsia/blob.blk \
+        --blobfs obj/build/images/fuchsia/update/gen/update.blob.blk \
+        --config path/to/verify_route_sources/product.board.json5"#
 )]
 pub struct Command {
-    /// path to root output directory of build.
+    /// absolute or working directory-relative path to root output directory of build.
     #[argh(option)]
     pub build_path: PathBuf,
-    /// path to fuchsia update package.
+    /// absolute or build path-relative path to fuchsia update package.
     #[argh(option)]
     pub update: PathBuf,
-    /// path to one or more blobfs archives that contain fuchsia packages and
-    /// their packages.
+    /// absolute or build path-relative path to one or more blobfs archives that contain fuchsia
+    /// packages and their packages.
     #[argh(option)]
     pub blobfs: Vec<PathBuf>,
-    /// path to configuration file that specifies components and their expected
-    /// route sources.
+    /// absolute or build path-relative path to configuration file that specifies components and
+    /// their expected route sources.
     #[argh(option)]
     pub config: PathBuf,
 }
diff --git a/src/developer/ffx/plugins/scrutiny/verify/args/routes.rs b/src/developer/ffx/plugins/scrutiny/verify/args/routes.rs
index 2bb5600..c039cd3 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/args/routes.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/args/routes.rs
@@ -8,7 +8,7 @@
     std::path::PathBuf,
 };
 
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum CapabilityType {
     Directory,
     Protocol,
@@ -33,7 +33,7 @@
     }
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum ResponseLevel {
     Verbose,
     All,
@@ -74,11 +74,14 @@
     subcommand,
     name = "routes",
     description = "Verifies capability routes in the component tree",
-    example = "To verify routes on your current build:
+    example = r#"To verify routes on your current build:
 
-        $ ffx scrutiny verify routes \
-            --build-path $(fx get-build-dir) \
-            --repository-path $(fx get-build-dir)/amber-files/repository"
+    $ ffx scrutiny verify routes \
+        --build-path $(fx get-build-dir) \
+        --update obj/build/images/fuchsia/update/update.far \
+        --blobfs obj/build/images/fuchsia/fuchsia/blob.blk \
+        --blobfs obj/build/images/fuchsia/update/gen/update.blob.blk \
+        --allowlist ../../src/security/policy/build/verify_routes_exceptions_allowlist.json5"#
 )]
 pub struct Command {
     /// capability types to verify.
@@ -87,21 +90,22 @@
     /// response level to report from routes scrutiny plugin.
     #[argh(option, default = "ResponseLevel::Error")]
     pub response_level: ResponseLevel,
-    /// path to root output directory of build.
+    /// absolute or working directory-relative path to root output directory of build.
     #[argh(option)]
     pub build_path: PathBuf,
-    /// path to fuchsia update package.
+    /// absolute or build path-relative path to fuchsia update package.
     #[argh(option)]
     pub update: PathBuf,
-    /// path to one or more blobfs archives that contain fuchsia packages and
-    /// their packages.
+    /// absolute or build path-relative path to one or more blobfs archives that contain
+    /// fuchsia packages and their packages, typically repeated for a system blobfs archive and a
+    /// blobfs archive of blobs in the update package.
     #[argh(option)]
     pub blobfs: Vec<PathBuf>,
-    /// path(s) to allowlist(s) used to verify routes.
+    /// absolute or build path-relative path(s) to allowlist(s) used to verify routes.
     #[argh(option)]
     pub allowlist: Vec<PathBuf>,
-    /// path to component tree configuration file that affects how component
-    /// tree data is gathered.
+    /// absolute or build path-relative path to component tree configuration file that affects how
+    /// component tree data is gathered.
     #[argh(option)]
     pub component_tree_config: Option<PathBuf>,
 }
diff --git a/src/developer/ffx/plugins/scrutiny/verify/src/bootfs.rs b/src/developer/ffx/plugins/scrutiny/verify/src/bootfs.rs
index 0edeb12..0ead700 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/src/bootfs.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/src/bootfs.rs
@@ -21,7 +21,7 @@
 5: For each existing line you modified in 2, remove the line.
 ";
 
-pub async fn verify(cmd: Command) -> Result<HashSet<PathBuf>> {
+pub async fn verify(cmd: &Command) -> Result<HashSet<PathBuf>> {
     if cmd.golden.len() == 0 {
         bail!("Must specify at least one --golden");
     }
@@ -44,9 +44,9 @@
         launcher::launch_from_config(config).context("Failed to launch scrutiny")?;
     let bootfs_files: Vec<String> = serde_json::from_str(&scrutiny_output)
         .context(format!("Failed to deserialize scrutiny output: {}", scrutiny_output))?;
-    for golden_file_path in cmd.golden.into_iter() {
+    for golden_file_path in cmd.golden.iter() {
         let golden_file =
-            GoldenFile::open(&golden_file_path).context("Failed to open the golden file")?;
+            GoldenFile::open(golden_file_path).context("Failed to open the golden file")?;
         match golden_file.compare(bootfs_files.clone()) {
             CompareResult::Matches => Ok(()),
             CompareResult::Mismatch { errors } => {
@@ -65,7 +65,7 @@
             }
         }?;
 
-        deps.insert(golden_file_path);
+        deps.insert(golden_file_path.clone());
     }
 
     Ok(deps)
diff --git a/src/developer/ffx/plugins/scrutiny/verify/src/component_resolvers.rs b/src/developer/ffx/plugins/scrutiny/verify/src/component_resolvers.rs
index a709a7b..44c2efd 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/src/component_resolvers.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/src/component_resolvers.rs
@@ -7,6 +7,7 @@
     ffx_scrutiny_verify_args::component_resolvers::Command,
     scrutiny_config::Config,
     scrutiny_frontend::{command_builder::CommandBuilder, launcher},
+    scrutiny_utils::path::join_and_canonicalize,
     serde::{Deserialize, Serialize},
     std::{collections::HashSet, fs, path::PathBuf},
 };
@@ -139,16 +140,19 @@
     }
 }
 
-pub async fn verify(cmd: Command) -> Result<HashSet<PathBuf>> {
-    let allowlist_path = cmd.allowlist.clone();
+pub async fn verify(cmd: &Command) -> Result<HashSet<PathBuf>> {
+    let allowlist_path = join_and_canonicalize(&cmd.build_path, &cmd.allowlist);
+    let update_package_path = join_and_canonicalize(&cmd.build_path, &cmd.update);
+    let blobfs_paths =
+        cmd.blobfs.iter().map(|blobfs| join_and_canonicalize(&cmd.build_path, blobfs)).collect();
     let scrutiny = ScrutinyQueryComponentResolvers {
-        build_path: cmd.build_path,
-        update_package_path: cmd.update,
-        blobfs_paths: cmd.blobfs,
+        build_path: cmd.build_path.clone(),
+        update_package_path,
+        blobfs_paths,
     };
 
     let allowlist: AllowList = serde_json5::from_str(
-        &fs::read_to_string(&cmd.allowlist).context("Failed to read allowlist")?,
+        &fs::read_to_string(&allowlist_path).context("Failed to read allowlist")?,
     )
     .context("Failed to deserialize allowlist")?;
 
diff --git a/src/developer/ffx/plugins/scrutiny/verify/src/kernel_cmdline.rs b/src/developer/ffx/plugins/scrutiny/verify/src/kernel_cmdline.rs
index 11dc7d8..2247c18 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/src/kernel_cmdline.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/src/kernel_cmdline.rs
@@ -74,18 +74,18 @@
     }
 }
 
-pub async fn verify(cmd: Command) -> Result<HashSet<PathBuf>> {
+pub async fn verify(cmd: &Command) -> Result<HashSet<PathBuf>> {
     if cmd.golden.len() == 0 {
         bail!("Must specify at least one --golden");
     }
     let mut deps = HashSet::new();
     deps.insert(cmd.zbi.clone());
 
-    let query = Query { zbi_path: cmd.zbi };
-    for golden_file_path in cmd.golden.into_iter() {
-        verify_kernel_cmdline(&query, &golden_file_path)?;
+    let query = Query { zbi_path: cmd.zbi.clone() };
+    for golden_file_path in cmd.golden.iter() {
+        verify_kernel_cmdline(&query, golden_file_path)?;
 
-        deps.insert(golden_file_path);
+        deps.insert(golden_file_path.clone());
     }
 
     Ok(deps)
diff --git a/src/developer/ffx/plugins/scrutiny/verify/src/lib.rs b/src/developer/ffx/plugins/scrutiny/verify/src/lib.rs
index 77e7106..7e20d63 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/src/lib.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/src/lib.rs
@@ -6,7 +6,8 @@
     anyhow::{anyhow, bail, Context, Result},
     ffx_core::ffx_plugin,
     ffx_scrutiny_verify_args::{Command, SubCommand},
-    std::{fs, io::Write},
+    scrutiny_utils::path::relativize_path,
+    std::{fs, io::Write, path::PathBuf},
 };
 
 mod bootfs;
@@ -22,7 +23,7 @@
         bail!("Cannot specify --depfile without --stamp");
     }
 
-    let deps_set = match cmd.subcommand {
+    let deps_set = match &cmd.subcommand {
         SubCommand::Bootfs(cmd) => bootfs::verify(cmd).await,
         SubCommand::ComponentResolvers(cmd) => component_resolvers::verify(cmd).await,
         SubCommand::KernelCmdline(cmd) => kernel_cmdline::verify(cmd).await,
@@ -44,11 +45,24 @@
         })?;
         let mut depfile = fs::File::create(depfile_path).context("failed to create depfile")?;
 
-        let deps = deps_set
+        // Convert any absolute paths into paths relative to `build_path` to satisfy depfile format
+        // requirements.
+        let default_build_path = PathBuf::from(String::from("."));
+        let build_path = match &cmd.subcommand {
+            SubCommand::Bootfs(_) | SubCommand::KernelCmdline(_) => &default_build_path,
+            SubCommand::ComponentResolvers(subcommand) => &subcommand.build_path,
+            SubCommand::RouteSources(subcommand) => &subcommand.build_path,
+            SubCommand::Routes(subcommand) => &subcommand.build_path,
+            SubCommand::StaticPkgs(subcommand) => &subcommand.build_path,
+        };
+        let relative_dep_paths: Vec<PathBuf> =
+            deps_set.into_iter().map(|dep_path| relativize_path(build_path, dep_path)).collect();
+
+        let deps = relative_dep_paths
             .iter()
-            .map(|path_buf| {
-                path_buf.to_str().ok_or_else(|| {
-                    anyhow!("Failed to convert path for depfile to string: {:?}", path_buf)
+            .map(|dep_path| {
+                dep_path.to_str().ok_or_else(|| {
+                    anyhow!("Failed to convert path for depfile to string: {:?}", dep_path)
                 })
             })
             .collect::<Result<Vec<&str>>>()?;
diff --git a/src/developer/ffx/plugins/scrutiny/verify/src/route_sources.rs b/src/developer/ffx/plugins/scrutiny/verify/src/route_sources.rs
index 49acbf5..9554f88 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/src/route_sources.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/src/route_sources.rs
@@ -8,6 +8,7 @@
     scrutiny_config::{Config, LoggingConfig, ModelConfig, PluginConfig, RuntimeConfig},
     scrutiny_frontend::{command_builder::CommandBuilder, launcher},
     scrutiny_plugins::verify::{RouteSourceError, VerifyRouteSourcesResults},
+    scrutiny_utils::path::join_and_canonicalize,
     serde_json,
     std::{
         collections::{HashMap, HashSet},
@@ -23,20 +24,28 @@
     config_path: String,
 }
 
-impl TryFrom<Command> for Query {
+impl TryFrom<&Command> for Query {
     type Error = Error;
-    fn try_from(cmd: Command) -> Result<Self, Self::Error> {
-        let config_path = cmd.config.to_str().ok_or_else(|| {
+    fn try_from(cmd: &Command) -> Result<Self, Self::Error> {
+        let config_path_buf = join_and_canonicalize(&cmd.build_path, &cmd.config);
+        let config_path = config_path_buf.to_str().ok_or_else(|| {
             anyhow!(
                 "Route sources configuration file path {:?} cannot be converted to string for passing to scrutiny",
                 cmd.config
             )
         })?;
+        let update_package_path = join_and_canonicalize(&cmd.build_path, &cmd.update);
+        let blobfs_paths = cmd
+            .blobfs
+            .iter()
+            .map(|blobfs| join_and_canonicalize(&cmd.build_path, blobfs))
+            .collect();
+        let config_path = config_path.to_string();
         Ok(Query {
-            build_path: cmd.build_path,
-            update_package_path: cmd.update,
-            blobfs_paths: cmd.blobfs,
-            config_path: config_path.to_string(),
+            build_path: cmd.build_path.clone(),
+            update_package_path,
+            blobfs_paths,
+            config_path,
         })
     }
 }
@@ -93,7 +102,7 @@
     Ok(route_sources_results.deps)
 }
 
-pub async fn verify(cmd: Command) -> Result<HashSet<PathBuf>> {
+pub async fn verify(cmd: &Command) -> Result<HashSet<PathBuf>> {
     let query = cmd.try_into()?;
     let deps = verify_route_sources(query)?;
     Ok(deps)
diff --git a/src/developer/ffx/plugins/scrutiny/verify/src/routes/mod.rs b/src/developer/ffx/plugins/scrutiny/verify/src/routes/mod.rs
index 5df770a..0d2778d 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/src/routes/mod.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/src/routes/mod.rs
@@ -11,6 +11,7 @@
     scrutiny_config::Config,
     scrutiny_frontend::{command_builder::CommandBuilder, launcher},
     scrutiny_plugins::verify::CapabilityRouteResults,
+    scrutiny_utils::path::join_and_canonicalize,
     serde_json,
     std::{collections::HashSet, fs, io::Read, path::PathBuf},
 };
@@ -25,26 +26,41 @@
     component_tree_config_path: Option<PathBuf>,
 }
 
-impl From<Command> for Query {
-    fn from(cmd: Command) -> Self {
+impl From<&Command> for Query {
+    fn from(cmd: &Command) -> Self {
         // argh(default = "vec![...]") does not work due to failed trait bound:
         // FromStr on Vec<_>. Apply default when vec is empty.
         let capability_types = if cmd.capability_type.len() > 0 {
-            cmd.capability_type
+            cmd.capability_type.clone()
         } else {
             default_capability_types()
         }
         .into_iter()
         .map(|capability_type| capability_type.into())
         .collect();
+        let update_package_path = join_and_canonicalize(&cmd.build_path, &cmd.update);
+        let blobfs_paths = cmd
+            .blobfs
+            .iter()
+            .map(|blobfs| join_and_canonicalize(&cmd.build_path, blobfs))
+            .collect();
+        let allowlist_paths = cmd
+            .allowlist
+            .iter()
+            .map(|allowlist| join_and_canonicalize(&cmd.build_path, allowlist))
+            .collect();
+        let component_tree_config_path =
+            cmd.component_tree_config.as_ref().map(|component_tree_config| {
+                join_and_canonicalize(&cmd.build_path, &component_tree_config)
+            });
         Query {
             capability_types,
-            response_level: cmd.response_level.into(),
-            build_path: cmd.build_path,
-            update_package_path: cmd.update,
-            blobfs_paths: cmd.blobfs,
-            allowlist_paths: cmd.allowlist,
-            component_tree_config_path: cmd.component_tree_config,
+            response_level: cmd.response_level.clone().into(),
+            build_path: cmd.build_path.clone(),
+            update_package_path,
+            blobfs_paths,
+            allowlist_paths,
+            component_tree_config_path,
         }
     }
 }
@@ -70,7 +86,7 @@
     Err(err.unwrap())
 }
 
-pub async fn verify(cmd: Command) -> Result<HashSet<PathBuf>> {
+pub async fn verify(cmd: &Command) -> Result<HashSet<PathBuf>> {
     let query: Query = cmd.into();
     let mut config = Config::run_command_with_plugins(
         CommandBuilder::new("verify.capability_routes")
diff --git a/src/developer/ffx/plugins/scrutiny/verify/src/static_pkgs.rs b/src/developer/ffx/plugins/scrutiny/verify/src/static_pkgs.rs
index a396999..41d19b5 100644
--- a/src/developer/ffx/plugins/scrutiny/verify/src/static_pkgs.rs
+++ b/src/developer/ffx/plugins/scrutiny/verify/src/static_pkgs.rs
@@ -11,6 +11,7 @@
     scrutiny_utils::{
         artifact::{ArtifactReader, FileArtifactReader},
         golden::{CompareResult, GoldenFile},
+        path::join_and_canonicalize,
     },
     std::{collections::HashSet, path::PathBuf},
 };
@@ -96,16 +97,19 @@
     }
 }
 
-pub async fn verify(cmd: Command) -> Result<HashSet<PathBuf>> {
-    let query = Query {
-        build_path: cmd.build_path,
-        update_package_path: cmd.update,
-        blobfs_paths: cmd.blobfs,
-    };
+pub async fn verify(cmd: &Command) -> Result<HashSet<PathBuf>> {
+    let build_path = cmd.build_path.clone();
+    let update_package_path = join_and_canonicalize(&cmd.build_path, &cmd.update);
+    let blobfs_paths =
+        cmd.blobfs.iter().map(|blobfs| join_and_canonicalize(&cmd.build_path, blobfs)).collect();
+    let query = Query { build_path, update_package_path, blobfs_paths };
     let mut deps = HashSet::new();
 
-    for golden_file_path in cmd.golden.into_iter() {
-        deps.extend(verify_static_pkgs(&query, golden_file_path)?);
+    for golden_file_path in cmd.golden.iter() {
+        deps.extend(verify_static_pkgs(
+            &query,
+            join_and_canonicalize(&cmd.build_path, golden_file_path),
+        )?);
     }
 
     Ok(deps)
diff --git a/src/devices/bin/driver-index/src/main.rs b/src/devices/bin/driver-index/src/main.rs
index 24a192e..58baa45 100644
--- a/src/devices/bin/driver-index/src/main.rs
+++ b/src/devices/bin/driver-index/src/main.rs
@@ -740,7 +740,22 @@
                         let flags = fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::DIRECTORY;
                         fuchsia_fs::node::connect_in_namespace("/pkg", flags, dir.into_channel())
                             .unwrap();
-                        responder.send(&mut Ok(())).context("error sending response")?;
+                        responder
+                            .send(&mut Ok(fidl_fuchsia_pkg::ResolutionContext { bytes: vec![] }))
+                            .context("error sending response")?;
+                    }
+                    fidl_fuchsia_pkg::PackageResolverRequest::ResolveWithContext {
+                        package_url: _,
+                        context: _,
+                        dir: _,
+                        responder,
+                    } => {
+                        log::error!(
+                            "ResolveWithContext is not currently implemented in driver-index"
+                        );
+                        responder
+                            .send(&mut Err(fidl_fuchsia_pkg::ResolveError::Internal))
+                            .context("error sending response")?;
                     }
                     fidl_fuchsia_pkg::PackageResolverRequest::GetHash {
                         package_url: _,
diff --git a/src/devices/bin/driver-index/src/package_resolver.rs b/src/devices/bin/driver-index/src/package_resolver.rs
index 18f776a..475bd45 100644
--- a/src/devices/bin/driver-index/src/package_resolver.rs
+++ b/src/devices/bin/driver-index/src/package_resolver.rs
@@ -6,7 +6,7 @@
 use futures::TryStreamExt;
 use {
     fidl_fuchsia_io as fio,
-    fidl_fuchsia_pkg::PackageResolverRequestStream,
+    fidl_fuchsia_pkg::{self as fpkg, PackageResolverRequestStream},
     fuchsia_url::{PackageVariant, UnpinnedAbsolutePackageUrl},
     futures::StreamExt,
 };
@@ -34,7 +34,20 @@
                         flags,
                         dir.into_channel(),
                     )?;
-                    responder.send(&mut Ok(())).context("error sending response")?;
+                    responder
+                        .send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] }))
+                        .context("error sending response")?;
+                }
+                fidl_fuchsia_pkg::PackageResolverRequest::ResolveWithContext {
+                    package_url: _,
+                    context: _,
+                    dir: _,
+                    responder,
+                } => {
+                    // Not implemented for driver-index PackageResolver
+                    responder
+                        .send(&mut Err(fidl_fuchsia_pkg::ResolveError::Internal))
+                        .context("error sending response")?;
                 }
                 fidl_fuchsia_pkg::PackageResolverRequest::GetHash { package_url: _, responder } => {
                     responder
diff --git a/src/devices/i2c/lib/device-protocol-i2c-channel/BUILD.gn b/src/devices/i2c/lib/device-protocol-i2c-channel/BUILD.gn
index 0765862..3de26f2 100644
--- a/src/devices/i2c/lib/device-protocol-i2c-channel/BUILD.gn
+++ b/src/devices/i2c/lib/device-protocol-i2c-channel/BUILD.gn
@@ -10,8 +10,8 @@
   sdk_headers = [ "lib/device-protocol/i2c-channel.h" ]
   sources = []
   public_deps = [
-    # <lib/device-protocol-i2c-channel/i2c-channel.h> has #include <fuchsia/hardware/i2c/cpp/banjo.h>
-    "//sdk/banjo/fuchsia.hardware.i2c:fuchsia.hardware.i2c_banjo_cpp",
+    # <lib/device-protocol-i2c-channel/i2c-channel.h> has
+    # #includes <fidl/fuchsia.hardware.i2c/cpp/wire.h>
     "//sdk/fidl/fuchsia.hardware.i2c:fuchsia.hardware.i2c_llcpp",
 
     # <lib/device-protocol-i2c-channel/i2c-channel.h> include <lib/device-protocol/i2c.h>
@@ -32,13 +32,10 @@
   sources = [ "test.cc" ]
   deps = [
     "//sdk/fidl/fuchsia.hardware.i2c:fuchsia.hardware.i2c_llcpp",
-    "//sdk/fidl/fuchsia.hardware.i2c:fuchsia.hardware.i2c_llcpp",
-    "//src/devices/i2c/lib/device-protocol-i2c",
     "//src/devices/i2c/lib/device-protocol-i2c-channel",
     "//src/devices/i2c/testing/fake-i2c",
     "//src/devices/testing/mock-ddk",
     "//zircon/system/ulib/async-loop:async-loop-cpp",
-    "//zircon/system/ulib/async-loop:async-loop-default",
     "//zircon/system/ulib/zxtest",
   ]
 }
diff --git a/src/devices/i2c/lib/device-protocol-i2c-channel/include/lib/device-protocol/i2c-channel.h b/src/devices/i2c/lib/device-protocol-i2c-channel/include/lib/device-protocol/i2c-channel.h
index 04d6e22..e99f5d1 100644
--- a/src/devices/i2c/lib/device-protocol-i2c-channel/include/lib/device-protocol/i2c-channel.h
+++ b/src/devices/i2c/lib/device-protocol-i2c-channel/include/lib/device-protocol/i2c-channel.h
@@ -7,7 +7,6 @@
 
 #include <fidl/fuchsia.hardware.i2c/cpp/wire.h>
 #include <fuchsia/hardware/i2c/cpp/banjo.h>
-#include <lib/device-protocol/i2c.h>
 #include <lib/sync/completion.h>
 #include <zircon/types.h>
 
@@ -16,16 +15,29 @@
 
 namespace ddk {
 
-// TODO(fxbug.dev/96293): Merge I2cFidlChannel back into I2cChannel and delete I2cChannelBase once
-// all clients are using FIDL.
-class I2cChannelBase {
+class I2cChannel {
  public:
   struct StatusRetries {
     zx_status_t status;
     uint8_t retries;
   };
 
-  virtual ~I2cChannelBase() = default;
+  I2cChannel() = default;
+
+  I2cChannel(fidl::ClientEnd<fuchsia_hardware_i2c::Device> client)
+      : fidl_client_(std::move(client)) {}
+
+  I2cChannel(zx_device_t* parent) { ConnectFidl(parent, nullptr); }
+
+  I2cChannel(zx_device_t* parent, const char* fragment_name) { ConnectFidl(parent, fragment_name); }
+
+  I2cChannel(I2cChannel&& other) noexcept = default;
+  I2cChannel& operator=(I2cChannel&& other) noexcept = default;
+
+  I2cChannel(const I2cChannel& other) = delete;
+  I2cChannel& operator=(const I2cChannel& other) = delete;
+
+  ~I2cChannel() = default;
 
   // Performs typical i2c Read: writes device register address (1 byte) followed
   // by len reads into buf.
@@ -38,9 +50,6 @@
     return WriteReadSync(buf, len, nullptr, 0);
   }
 
-  virtual zx_status_t WriteReadSync(const uint8_t* tx_buf, size_t tx_len, uint8_t* rx_buf,
-                                    size_t rx_len) = 0;
-
   // ReadSync with retries, returns status and retry attempts.
   StatusRetries ReadSyncRetries(uint8_t addr, uint8_t* buf, size_t len, uint8_t retries,
                                 zx::duration delay) {
@@ -65,25 +74,8 @@
     }
     return {status, attempt};
   }
-};
 
-class I2cFidlChannel : public I2cChannelBase {
- public:
-  explicit I2cFidlChannel(fidl::ClientEnd<fuchsia_hardware_i2c::Device> client_end)
-      : fidl_client_(std::move(client_end)) {}
-
-  I2cFidlChannel(I2cFidlChannel&& other) noexcept = default;
-  I2cFidlChannel& operator=(I2cFidlChannel&& other) noexcept = default;
-
-  ~I2cFidlChannel() override = default;
-
-  fidl::WireResult<fuchsia_hardware_i2c::Device::Transfer> Transfer(
-      fidl::VectorView<fuchsia_hardware_i2c::wire::Transaction> transactions) {
-    return fidl_client_->Transfer(transactions);
-  }
-
-  zx_status_t WriteReadSync(const uint8_t* tx_buf, size_t tx_len, uint8_t* rx_buf,
-                            size_t rx_len) override {
+  zx_status_t WriteReadSync(const uint8_t* tx_buf, size_t tx_len, uint8_t* rx_buf, size_t rx_len) {
     if (tx_len > fuchsia_hardware_i2c::wire::kMaxTransferSize ||
         rx_len > fuchsia_hardware_i2c::wire::kMaxTransferSize) {
       return ZX_ERR_OUT_OF_RANGE;
@@ -207,80 +199,10 @@
     callback(cookie, ZX_OK, read_ops, read_count);
   }
 
- private:
-  fidl::WireSyncClient<fuchsia_hardware_i2c::Device> fidl_client_;
-};
-
-// TODO(fxbug.dev/96293): Remove Banjo support once all clients have been switched to FIDL.
-class I2cChannel : public I2cChannelBase {
- public:
-  I2cChannel() = default;
-
-  I2cChannel(const i2c_protocol_t* proto) : banjo_client_(proto) {}
-
-  I2cChannel(fidl::ClientEnd<fuchsia_hardware_i2c::Device> client)
-      : fidl_client_(std::move(client)) {}
-
-  I2cChannel(zx_device_t* parent) : banjo_client_(parent) { ConnectFidlIfNeeded(parent, nullptr); }
-
-  I2cChannel(zx_device_t* parent, const char* fragment_name)
-      : banjo_client_(parent, fragment_name) {
-    ConnectFidlIfNeeded(parent, fragment_name);
-  }
-
-  I2cChannel(I2cChannel&& other) noexcept = default;
-  I2cChannel& operator=(I2cChannel&& other) noexcept = default;
-
-  I2cChannel(const I2cChannel& other) = delete;
-  I2cChannel& operator=(const I2cChannel& other) = delete;
-
-  ~I2cChannel() override = default;
-
-  zx_status_t WriteReadSync(const uint8_t* tx_buf, size_t tx_len, uint8_t* rx_buf,
-                            size_t rx_len) override {
-    if (banjo_client_.is_valid()) {
-      i2c_protocol_t proto;
-      banjo_client_.GetProto(&proto);
-      return i2c_write_read_sync(&proto, tx_buf, tx_len, rx_buf, rx_len);
-    }
-    if (fidl_client_.has_value()) {
-      return fidl_client_->WriteReadSync(tx_buf, tx_len, rx_buf, rx_len);
-    }
-    ZX_ASSERT_MSG(false, "No Banjo or FIDL client is available");
-  }
-
-  void GetProto(i2c_protocol_t* proto) const {
-    ZX_ASSERT_MSG(banjo_client_.is_valid(), "No Banjo client is available");
-    banjo_client_.GetProto(proto);
-  }
-
-  bool is_valid() const { return banjo_client_.is_valid() || fidl_client_.has_value(); }
-
-  // Note: Currently Transact() calls to FIDL clients are synchronous.
-  // TODO(fxbug.dev/96293): Add support for async FIDL calls if needed.
-  void Transact(const i2c_op_t* op_list, size_t op_count, i2c_transact_callback callback,
-                void* cookie) {
-    if (banjo_client_.is_valid()) {
-      banjo_client_.Transact(op_list, op_count, callback, cookie);
-    } else if (fidl_client_.has_value()) {
-      fidl_client_->Transact(op_list, op_count, callback, cookie);
-    } else {
-      ZX_ASSERT_MSG(false, "No Banjo or FIDL client is available");
-    }
-  }
-
-  zx_status_t GetMaxTransferSize(uint64_t* out_size) const {
-    ZX_ASSERT_MSG(!fidl_client_.has_value(),
-                  "GetMaxTransferSize() is not implemented for FIDL clients");
-    return banjo_client_.GetMaxTransferSize(out_size);
-  }
+  bool is_valid() const { return fidl_client_.is_valid(); }
 
  private:
-  void ConnectFidlIfNeeded(zx_device_t* parent, const char* fragment_name) {
-    if (banjo_client_.is_valid()) {
-      return;
-    }
-
+  void ConnectFidl(zx_device_t* parent, const char* fragment_name) {
     auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
     if (endpoints.is_error()) {
       return;
@@ -301,11 +223,10 @@
       return;
     }
 
-    fidl_client_.emplace(std::move(endpoints->client));
+    fidl_client_ = fidl::WireSyncClient(std::move(endpoints->client));
   }
 
-  I2cProtocolClient banjo_client_;
-  std::optional<I2cFidlChannel> fidl_client_;
+  fidl::WireSyncClient<fuchsia_hardware_i2c::Device> fidl_client_;
 };
 
 }  // namespace ddk
diff --git a/src/devices/i2c/lib/device-protocol-i2c-channel/test.cc b/src/devices/i2c/lib/device-protocol-i2c-channel/test.cc
index b69e533..3069c5b 100644
--- a/src/devices/i2c/lib/device-protocol-i2c-channel/test.cc
+++ b/src/devices/i2c/lib/device-protocol-i2c-channel/test.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <lib/async-loop/cpp/loop.h>
-#include <lib/async-loop/default.h>
 #include <lib/device-protocol/i2c-channel.h>
 #include <lib/fake-i2c/fake-i2c.h>
 #include <zircon/errors.h>
@@ -40,14 +39,9 @@
   size_t count_ = 0;
 };
 
-class I2cDevice : public fake_i2c::FakeI2c {
+class I2cDevice : public fidl::WireServer<fuchsia_hardware_i2c::Device> {
  public:
-  size_t banjo_count() const { return banjo_count_; }
-  size_t fidl_count() const { return fidl_count_; }
-
   void Transfer(TransferRequestView request, TransferCompleter::Sync& completer) override {
-    fidl_count_++;
-
     const fidl::VectorView<fuchsia_hardware_i2c::wire::Transaction> transactions =
         request->transactions;
 
@@ -117,20 +111,7 @@
   void set_rx_data(std::vector<uint8_t> rx_data) { rx_data_ = std::move(rx_data); }
   const std::vector<bool>& stop() const { return stop_; }
 
- protected:
-  zx_status_t Transact(const uint8_t* write_buffer, size_t write_buffer_size, uint8_t* read_buffer,
-                       size_t* read_buffer_size) override {
-    banjo_count_++;
-
-    *read_buffer_size = rx_data_.size();
-    memcpy(read_buffer, rx_data_.data(), rx_data_.size());
-    tx_data_ = {write_buffer, write_buffer + write_buffer_size};
-    return ZX_OK;
-  }
-
  private:
-  size_t banjo_count_ = 0;
-  size_t fidl_count_ = 0;
   std::vector<uint8_t> tx_data_;
   std::vector<uint8_t> rx_data_;
   std::vector<bool> stop_;
@@ -138,7 +119,7 @@
 
 class I2cChannelTest : public zxtest::Test {
  public:
-  I2cChannelTest() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {}
+  I2cChannelTest() : loop_(&kAsyncLoopConfigNeverAttachToThread) {}
 
   void SetUp() override { loop_.StartThread(); }
 
@@ -221,7 +202,7 @@
 
   const std::array<uint8_t, 4> expected_rx_data{0x12, 0x34, 0xab, 0xcd};
 
-  ddk::I2cFidlChannel client(std::move(endpoints->client));
+  ddk::I2cChannel client(std::move(endpoints->client));
   i2c_dev.set_rx_data({expected_rx_data.data(), expected_rx_data.data() + expected_rx_data.size()});
 
   uint8_t buf[4];
@@ -254,7 +235,7 @@
 
   const std::array<uint8_t, 4> expected_tx_data{0x0f, 0x1e, 0x2d, 0x3c};
 
-  ddk::I2cFidlChannel client(std::move(endpoints->client));
+  ddk::I2cChannel client(std::move(endpoints->client));
 
   EXPECT_OK(client.WriteSync(expected_tx_data.data(), expected_tx_data.size()));
   ASSERT_EQ(i2c_dev.tx_data().size(), expected_tx_data.size());
@@ -271,7 +252,7 @@
   const std::array<uint8_t, 4> expected_rx_data{0x12, 0x34, 0xab, 0xcd};
   const std::array<uint8_t, 4> expected_tx_data{0x0f, 0x1e, 0x2d, 0x3c};
 
-  ddk::I2cFidlChannel client(std::move(endpoints->client));
+  ddk::I2cChannel client(std::move(endpoints->client));
   i2c_dev.set_rx_data({expected_rx_data.data(), expected_rx_data.data() + expected_rx_data.size()});
 
   uint8_t buf[4];
@@ -400,9 +381,6 @@
   EXPECT_EQ(i2c_dev.tx_data()[0], 0x89);
   EXPECT_EQ(rx, 0xab);
 
-  EXPECT_EQ(i2c_dev.banjo_count(), 0);
-  EXPECT_EQ(i2c_dev.fidl_count(), 1);
-
   // Move the client and verify that the new one is functional.
   ddk::I2cChannel new_client = std::move(client);
 
@@ -411,9 +389,6 @@
   ASSERT_EQ(i2c_dev.tx_data().size(), 1);
   EXPECT_EQ(i2c_dev.tx_data()[0], 0x34);
   EXPECT_EQ(rx, 0x12);
-
-  EXPECT_EQ(i2c_dev.banjo_count(), 0);
-  EXPECT_EQ(i2c_dev.fidl_count(), 2);
 }
 
 TEST_F(I2cChannelTest, GetFidlProtocolFromFragment) {
@@ -445,78 +420,4 @@
   ASSERT_EQ(i2c_dev.tx_data().size(), 1);
   EXPECT_EQ(i2c_dev.tx_data()[0], 0x78);
   EXPECT_EQ(rx, 0x56);
-
-  EXPECT_EQ(i2c_dev.banjo_count(), 0);
-  EXPECT_EQ(i2c_dev.fidl_count(), 1);
-}
-
-TEST_F(I2cChannelTest, BanjoClientMethods) {
-  auto endpoints = fidl::CreateEndpoints<fuchsia_hardware_i2c::Device>();
-  ASSERT_TRUE(endpoints.is_ok());
-
-  I2cDevice i2c_dev;
-  auto binding = fidl::BindServer(loop_.dispatcher(), std::move(endpoints->server), &i2c_dev);
-
-  auto parent = MockDevice::FakeRootParent();
-
-  parent->AddFidlProtocol(fidl::DiscoverableProtocolName<fuchsia_hardware_i2c::Device>,
-                          [this, &i2c_dev](zx::channel channel) {
-                            fidl::BindServer(
-                                loop_.dispatcher(),
-                                fidl::ServerEnd<fuchsia_hardware_i2c::Device>(std::move(channel)),
-                                &i2c_dev);
-                            return ZX_OK;
-                          });
-
-  ddk::I2cChannel client(parent.get());
-  ASSERT_TRUE(client.is_valid());
-
-  const std::array<uint8_t, 4> expected_rx_data{0x12, 0x34, 0xab, 0xcd};
-  const std::array<uint8_t, 1> expected_tx_data{0xa5};
-
-  i2c_op_t ops[2] = {
-      {
-          .data_buffer = expected_tx_data.data(),
-          .data_size = expected_tx_data.size(),
-          .is_read = false,
-          .stop = false,
-      },
-      {
-          .data_buffer = nullptr,
-          .data_size = expected_rx_data.size(),
-          .is_read = true,
-          .stop = true,
-      },
-  };
-
-  i2c_dev.set_rx_data({expected_rx_data.data(), expected_rx_data.data() + expected_rx_data.size()});
-
-  struct I2cContext {
-    sync_completion_t completion = {};
-    zx_status_t status = ZX_ERR_INTERNAL;
-    uint8_t rx_data[4];
-  } context;
-
-  client.Transact(
-      ops, std::size(ops),
-      [](void* ctx, zx_status_t status, const i2c_op_t* op_list, size_t op_count) {
-        auto* i2c_context = reinterpret_cast<I2cContext*>(ctx);
-
-        ASSERT_EQ(op_count, 1);
-        ASSERT_TRUE(op_list[0].is_read);
-        ASSERT_EQ(op_list[0].data_size, 4);
-        memcpy(i2c_context->rx_data, op_list[0].data_buffer, 4);
-
-        i2c_context->status = status;
-        sync_completion_signal(&i2c_context->completion);
-      },
-      &context);
-
-  ASSERT_OK(sync_completion_wait(&context.completion, ZX_TIME_INFINITE));
-  EXPECT_OK(context.status);
-
-  ASSERT_EQ(i2c_dev.tx_data().size(), 1);
-  EXPECT_EQ(i2c_dev.tx_data()[0], 0xa5);
-
-  EXPECT_BYTES_EQ(context.rx_data, expected_rx_data.data(), sizeof(context.rx_data));
 }
diff --git a/src/lib/network/packet/src/serialize.rs b/src/lib/network/packet/src/serialize.rs
index beb2f84..6cd4aba9 100644
--- a/src/lib/network/packet/src/serialize.rs
+++ b/src/lib/network/packet/src/serialize.rs
@@ -1648,6 +1648,33 @@
     }
 }
 
+/// Either of two serializers.
+///
+/// An `EitherSerializer` wraps one of two different serializer types.
+pub enum EitherSerializer<A, B> {
+    A(A),
+    B(B),
+}
+
+impl<A: Serializer, B: Serializer<Buffer = A::Buffer>> Serializer for EitherSerializer<A, B> {
+    type Buffer = A::Buffer;
+
+    fn serialize<TB: TargetBuffer, PB: NestedPacketBuilder, P: BufferProvider<Self::Buffer, TB>>(
+        self,
+        outer: PB,
+        provider: P,
+    ) -> Result<TB, (SerializeError<P::Error>, Self)> {
+        match self {
+            EitherSerializer::A(s) => {
+                s.serialize(outer, provider).map_err(|(err, s)| (err, EitherSerializer::A(s)))
+            }
+            EitherSerializer::B(s) => {
+                s.serialize(outer, provider).map_err(|(err, s)| (err, EitherSerializer::B(s)))
+            }
+        }
+    }
+}
+
 /// The direction a buffer's body should be truncated from to force
 /// it to fit within a MTU.
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
diff --git a/src/proc/bin/starnix/auth.rs b/src/proc/bin/starnix/auth.rs
index d33e5b5..0037b67 100644
--- a/src/proc/bin/starnix/auth.rs
+++ b/src/proc/bin/starnix/auth.rs
@@ -156,6 +156,12 @@
     pub fn has_capability(&self, capability: Capabilities) -> bool {
         self.cap_effective.contains(capability)
     }
+
+    pub fn exec(&mut self) {
+        self.cap_permitted = self.cap_inheritable;
+        self.cap_effective = self.cap_permitted;
+        self.securebits.remove(SecureBits::KEEP_CAPS);
+    }
 }
 
 /// The owner and group of a file. Used as a parameter for functions that create files.
diff --git a/src/proc/bin/starnix/task/task.rs b/src/proc/bin/starnix/task/task.rs
index 719772b..f62067c 100644
--- a/src/proc/bin/starnix/task/task.rs
+++ b/src/proc/bin/starnix/task/task.rs
@@ -849,8 +849,7 @@
 
             // TODO(tbodt): Check whether capability xattrs are set on the file, and grant/limit
             // capabilities accordingly.
-            state.creds.cap_permitted = state.creds.cap_inheritable;
-            state.creds.cap_effective = state.creds.cap_permitted;
+            state.creds.exec();
         }
 
         self.thread_group.signal_actions.reset_for_exec();
diff --git a/src/security/scrutiny/utils/BUILD.gn b/src/security/scrutiny/utils/BUILD.gn
index 1c894f7..63507a4 100644
--- a/src/security/scrutiny/utils/BUILD.gn
+++ b/src/security/scrutiny/utils/BUILD.gn
@@ -91,13 +91,13 @@
     ]
 
     test_deps = [
+      "//src/lib/fuchsia",
       "//third_party/rust_crates:maplit",
       "//third_party/rust_crates:tempfile",
     ]
 
     non_rust_deps = [
       "//src/lib/chunked-compression",
-      "//src/lib/fuchsia",
       "//src/security/scrutiny/utils/ffi",
       "//third_party/zstd",
     ]
@@ -112,6 +112,7 @@
       "src/key_value.rs",
       "src/lib.rs",
       "src/package.rs",
+      "src/path.rs",
       "src/url.rs",
       "src/usage.rs",
       "src/zbi.rs",
diff --git a/src/security/scrutiny/utils/src/lib.rs b/src/security/scrutiny/utils/src/lib.rs
index a513804..4d74ed3 100644
--- a/src/security/scrutiny/utils/src/lib.rs
+++ b/src/security/scrutiny/utils/src/lib.rs
@@ -9,6 +9,7 @@
 pub mod golden;
 pub mod key_value;
 pub mod package;
+pub mod path;
 pub mod url;
 pub mod usage;
 pub mod zbi;
diff --git a/src/security/scrutiny/utils/src/path.rs b/src/security/scrutiny/utils/src/path.rs
new file mode 100644
index 0000000..a9bcc9d
--- /dev/null
+++ b/src/security/scrutiny/utils/src/path.rs
@@ -0,0 +1,191 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {
+    log::warn,
+    pathdiff::diff_paths,
+    std::path::{Path, PathBuf},
+};
+
+/// Attempt to build a canonical path of the form `base`/`path`. If `path` is absolute,
+/// then `base` is ignored. If paths do not actually exist on the filesystem, the resulting path
+/// may not be canonicalized; e.g., may contain `a/../b` instead of simply `b`. This limitation
+/// stems from delegating to `std::path::Path::canonicalize` which conflates resolving
+/// intermediate path elements and resolving symbolic links (yielding a failure if the no file
+/// with the given path exists on the filesystem).
+pub fn join_and_canonicalize<P1: AsRef<Path>, P2: AsRef<Path>>(base: P1, path: P2) -> PathBuf {
+    let base_ref = base.as_ref();
+    let path_ref = path.as_ref();
+    if path_ref.is_relative() {
+        canonicalize(base_ref.join(path_ref), "joined path for join_and_canonicalize")
+    } else {
+        canonicalize(path_ref, "absolute path for join_and_canonicalize")
+    }
+}
+
+/// Attempt to construct a relative path for `path` relative to `base`. If `path` is relative, then
+/// `base` is ignored. Limitations of the underlying algorithm cause this function to fallback on
+/// returning `path` unchanged when either:
+/// 1. `path` is relative, or
+/// 2. `base` contains a relative parent component, `..`, that cannot be canonicalized.
+pub fn relativize_path<P1: AsRef<Path>, P2: AsRef<Path>>(base: P1, path: P2) -> PathBuf {
+    let path_ref = path.as_ref();
+    if path_ref.is_relative() {
+        return path_ref.to_path_buf();
+    }
+
+    let base_ref = base.as_ref();
+    let base_path = canonicalize(base_ref, "base path for relativize");
+    diff_paths(path_ref, &base_path).unwrap_or_else(|| {
+        warn!(
+            "Failed to relativize path {:?} relative to base path {:?} (canonicalized as {:?}); returning path unchanged",
+            path_ref, base_ref, base_path
+        );
+        path_ref.to_path_buf()
+    })
+}
+
+fn canonicalize<P: AsRef<Path>>(path: P, path_name: &str) -> PathBuf {
+    let path_ref = path.as_ref();
+    match path_ref.canonicalize() {
+        Ok(path) => path,
+        Err(err) => {
+            warn!("Failed to canonicalize {}: {:?}: {}", path_name, path_ref, err.to_string());
+            path_ref.to_path_buf()
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use {
+        super::{join_and_canonicalize, relativize_path},
+        std::{
+            fs::{create_dir_all, File},
+            path::PathBuf,
+        },
+        tempfile::tempdir,
+    };
+
+    fn path_buf(path_str: &str) -> PathBuf {
+        PathBuf::from(String::from(path_str))
+    }
+
+    #[fuchsia::test]
+    fn resolve_absolute_base_absolute_path() {
+        let base = path_buf("/base");
+        let path = path_buf("/path");
+        let expected = path_buf("/path");
+
+        assert_eq!(join_and_canonicalize(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn resolve_absolute_base_relative_path() {
+        let base = path_buf("/base");
+        let path = path_buf("path");
+        let expected = path_buf("/base/path");
+
+        assert_eq!(join_and_canonicalize(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn resolve_absolute_base_unresolved_relative_parent_path() {
+        let base = path_buf("/path/does/not/exist/on/test/machine/out/product.board");
+        let path = path_buf("../../path");
+        let expected =
+            path_buf("/path/does/not/exist/on/test/machine/out/product.board/../../path");
+
+        assert_eq!(join_and_canonicalize(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn resolve_absolute_base_resolved_relative_parent_path() {
+        let base_root = tempdir().unwrap().into_path();
+        let base = base_root.join("out/product.board");
+        let path = path_buf("../../path");
+        // `join_and_canonicalize("/tmp-dir/out/product.board", "../../path") == "/tmp-dir/path"`.
+        let expected = base_root.join("path");
+
+        // Ensure canonicalization by creating all directories and files involved in canonicalized
+        // paths.
+        create_dir_all(&base).unwrap();
+        File::create(&expected).unwrap();
+
+        assert_eq!(join_and_canonicalize(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn resolve_absolute_base_resolved_absolute_path_resolved() {
+        let base = tempdir().unwrap().into_path();
+        let path = tempdir().unwrap().into_path();
+        // `join_and_canonicalize("/tmp-dir-1", "/tmp-dir-2") == "/tmp-dir-2"`.
+        let expected = path.clone();
+
+        assert_eq!(join_and_canonicalize(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn relativize_absolute_base_absolute_path() {
+        let base = path_buf("/root/build/dir");
+        let path = path_buf("/root/build/dir/file");
+        let expected = path_buf("file");
+
+        assert_eq!(relativize_path(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn relativize_absolute_base_relative_path() {
+        let base = path_buf("/root/build/dir");
+        let path = path_buf("root/build/dir/file");
+        // Relative `path` => return `path` unchanged.
+        let expected = path_buf("root/build/dir/file");
+
+        assert_eq!(relativize_path(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn relativize_relative_base_relative_path() {
+        let base = path_buf("root/build/dir");
+        let path = path_buf("root/build/dir/file");
+        // Relative `path` => return `path` unchanged.
+        let expected = path_buf("root/build/dir/file");
+
+        assert_eq!(relativize_path(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn relativize_non_canonicalized_base_absolute_path() {
+        let base = PathBuf::from(String::from(
+            "/path/does/not/exist/on/test/machine/out/product.board/../product.board",
+        ));
+        let path = PathBuf::from(String::from(
+            "/path/does/not/exist/on/test/machine/out/product.board/file",
+        ));
+        // Non-canonicalized `..` in `base` => return `path` unchanged.
+        let expected = PathBuf::from(String::from(
+            "/path/does/not/exist/on/test/machine/out/product.board/file",
+        ));
+
+        assert_eq!(relativize_path(&base, &path), expected);
+    }
+
+    #[fuchsia::test]
+    fn relativize_canonicalized_base_absolute_path() {
+        let base_root = tempdir().unwrap().into_path();
+        let canonical_base = base_root.join("out/product.board");
+        create_dir_all(&canonical_base).unwrap();
+        let non_canonical_base = base_root.join("out/product.board/../../out/product.board");
+        let path = base_root.join("out/product.board/../../file");
+        // ```
+        // relativize_path(
+        //     ".../out/board.product/../../out/board.product",
+        //     ".../out/board.product/../../file"
+        // ) == "../../file"
+        // ```
+        let expected = path_buf("../../file");
+
+        assert_eq!(relativize_path(&non_canonical_base, &path), expected);
+    }
+}
diff --git a/src/sys/fuzzing/BUILD.gn b/src/sys/fuzzing/BUILD.gn
index e04832c..0b08cc7 100644
--- a/src/sys/fuzzing/BUILD.gn
+++ b/src/sys/fuzzing/BUILD.gn
@@ -14,9 +14,9 @@
   testonly = true
   deps = [
     "common:tests",
-    "framework:tests",
     "libfuzzer:tests",
     "manager:tests",
+    "realmfuzzer:tests",
     "registry:tests",
   ]
 }
diff --git a/src/sys/fuzzing/common/BUILD.gn b/src/sys/fuzzing/common/BUILD.gn
index 1b050f4..ab8dfee 100644
--- a/src/sys/fuzzing/common/BUILD.gn
+++ b/src/sys/fuzzing/common/BUILD.gn
@@ -84,7 +84,7 @@
 }
 
 test("unittests_bin") {
-  output_name = "component_fuzzing_common_unittests"
+  output_name = "fuzzing_common_unittests"
   visibility = [ ":*" ]
   testonly = true
   sources = [
@@ -115,6 +115,6 @@
 }
 
 fuchsia_test_package("tests") {
-  package_name = "component-fuzzing-common-tests"
+  package_name = "fuzzing-common-tests"
   test_components = [ ":unittests" ]
 }
diff --git a/src/sys/fuzzing/common/meta/unittests.cml b/src/sys/fuzzing/common/meta/unittests.cml
index b2a87c3..eab2010 100644
--- a/src/sys/fuzzing/common/meta/unittests.cml
+++ b/src/sys/fuzzing/common/meta/unittests.cml
@@ -8,6 +8,6 @@
         "syslog/client.shard.cml",
     ],
     program: {
-        binary: "test/component_fuzzing_common_unittests",
+        binary: "test/fuzzing_common_unittests",
     },
 }
diff --git a/src/sys/fuzzing/common/testing/BUILD.gn b/src/sys/fuzzing/common/testing/BUILD.gn
index dd35aa4..8cec85a 100644
--- a/src/sys/fuzzing/common/testing/BUILD.gn
+++ b/src/sys/fuzzing/common/testing/BUILD.gn
@@ -51,7 +51,7 @@
 
 # A standalone fuzzer that uses a fake runner.
 executable("fuzzer") {
-  output_name = "component_fuzzing_test_fuzzer"
+  output_name = "fake_fuzzer_for_testing"
   testonly = true
   sources = [ "engine-main.cc" ]
   deps = [
diff --git a/src/sys/fuzzing/libfuzzer/BUILD.gn b/src/sys/fuzzing/libfuzzer/BUILD.gn
index 10c80f7..2113d81 100644
--- a/src/sys/fuzzing/libfuzzer/BUILD.gn
+++ b/src/sys/fuzzing/libfuzzer/BUILD.gn
@@ -38,7 +38,7 @@
 }
 
 test("unittests_bin") {
-  output_name = "component_fuzzing_libfuzzer_unittests"
+  output_name = "libfuzzer_unittests"
   visibility = [ ":*" ]
   testonly = true
   sources = [ "runner-unittest.cc" ]
@@ -55,7 +55,7 @@
 }
 
 test("error_unittests_bin") {
-  output_name = "component_fuzzing_libfuzzer_error_unittests"
+  output_name = "libfuzzer_error_unittests"
   visibility = [ ":*" ]
   testonly = true
   sources = [ "process-unittest.cc" ]
@@ -106,12 +106,12 @@
 }
 
 fuchsia_test_package("default-tests") {
-  package_name = "component-fuzzing-libfuzzer-tests"
+  package_name = "libfuzzer-tests"
   test_components = [ ":test-realm" ]
 }
 
 fuchsia_test_package("error-tests") {
-  package_name = "component-fuzzing-libfuzzer-error-tests"
+  package_name = "libfuzzer-error-tests"
 
   # Some tests involve handling intentional crashes.
   test_specs = {
diff --git a/src/sys/fuzzing/libfuzzer/meta/error-unittests.cml b/src/sys/fuzzing/libfuzzer/meta/error-unittests.cml
index 4b1db2e..ee43c3b 100644
--- a/src/sys/fuzzing/libfuzzer/meta/error-unittests.cml
+++ b/src/sys/fuzzing/libfuzzer/meta/error-unittests.cml
@@ -9,7 +9,7 @@
         "syslog/client.shard.cml",
     ],
     program: {
-        binary: "test/component_fuzzing_libfuzzer_error_unittests",
+        binary: "test/libfuzzer_error_unittests",
     },
     use: [
         { protocol: "test.fuzzer.Relay" },
diff --git a/src/sys/fuzzing/libfuzzer/meta/test-realm.cml b/src/sys/fuzzing/libfuzzer/meta/test-realm.cml
index a9a6584..f1f775d 100644
--- a/src/sys/fuzzing/libfuzzer/meta/test-realm.cml
+++ b/src/sys/fuzzing/libfuzzer/meta/test-realm.cml
@@ -5,11 +5,11 @@
     children: [
         {
             name: "unittests",
-            url: "fuchsia-pkg://fuchsia.com/component-fuzzing-libfuzzer-tests#meta/unittests.cm",
+            url: "#meta/unittests.cm",
         },
         {
             name: "relay",
-            url: "fuchsia-pkg://fuchsia.com/component-fuzzing-libfuzzer-tests#meta/test-relay.cm",
+            url: "#meta/test-relay.cm",
         },
     ],
     offer: [
diff --git a/src/sys/fuzzing/libfuzzer/meta/unittests.cml b/src/sys/fuzzing/libfuzzer/meta/unittests.cml
index 17b14ba..e48fb41 100644
--- a/src/sys/fuzzing/libfuzzer/meta/unittests.cml
+++ b/src/sys/fuzzing/libfuzzer/meta/unittests.cml
@@ -9,7 +9,7 @@
         "syslog/client.shard.cml",
     ],
     program: {
-        binary: "test/component_fuzzing_libfuzzer_unittests",
+        binary: "test/libfuzzer_unittests",
     },
     use: [
         { protocol: "test.fuzzer.Relay" },
diff --git a/src/sys/fuzzing/framework/BUILD.gn b/src/sys/fuzzing/realmfuzzer/BUILD.gn
similarity index 85%
rename from src/sys/fuzzing/framework/BUILD.gn
rename to src/sys/fuzzing/realmfuzzer/BUILD.gn
index 05139cc..cf4217c 100644
--- a/src/sys/fuzzing/framework/BUILD.gn
+++ b/src/sys/fuzzing/realmfuzzer/BUILD.gn
@@ -17,7 +17,7 @@
 # This package contains "normal" unit tests.
 
 test("unittests-bin") {
-  output_name = "component_fuzzing_framework_unittests"
+  output_name = "realmfuzzer_unittests"
   visibility = [ ":*" ]
   testonly = true
   deps = [
@@ -37,14 +37,14 @@
 }
 
 fuchsia_test_package("unittests-pkg") {
-  package_name = "component-fuzzing-framework-tests"
+  package_name = "realmfuzzer-unittests"
   test_components = [ ":unittests" ]
 }
 
 # This package contains unit tests that produce fatal error messages.
 
 test("fatal-unittests-bin") {
-  output_name = "component_fuzzing_framework_fatal_unittests"
+  output_name = "realmfuzzer_fatal_unittests"
   visibility = [ "../*" ]
   testonly = true
   deps = [
@@ -59,7 +59,7 @@
 }
 
 fuchsia_test_package("fatal-unittests-pkg") {
-  package_name = "component-fuzzing-framework-fatal-tests"
+  package_name = "realmfuzzer-fatal-unittests"
 
   # Some tests involve handling intentional crashes.
   test_specs = {
diff --git a/src/sys/fuzzing/framework/adapters/BUILD.gn b/src/sys/fuzzing/realmfuzzer/adapters/BUILD.gn
similarity index 100%
rename from src/sys/fuzzing/framework/adapters/BUILD.gn
rename to src/sys/fuzzing/realmfuzzer/adapters/BUILD.gn
diff --git a/src/sys/fuzzing/framework/adapters/llvm-main.cc b/src/sys/fuzzing/realmfuzzer/adapters/llvm-main.cc
similarity index 94%
rename from src/sys/fuzzing/framework/adapters/llvm-main.cc
rename to src/sys/fuzzing/realmfuzzer/adapters/llvm-main.cc
index a2c5606..7de5e31b 100644
--- a/src/sys/fuzzing/framework/adapters/llvm-main.cc
+++ b/src/sys/fuzzing/realmfuzzer/adapters/llvm-main.cc
@@ -6,7 +6,7 @@
 #include <zircon/status.h>
 
 #include "src/sys/fuzzing/common/component-context.h"
-#include "src/sys/fuzzing/framework/adapters/llvm.h"
+#include "src/sys/fuzzing/realmfuzzer/adapters/llvm.h"
 
 namespace fuzzing {
 
diff --git a/src/sys/fuzzing/framework/adapters/llvm-unittest.cc b/src/sys/fuzzing/realmfuzzer/adapters/llvm-unittest.cc
similarity index 98%
rename from src/sys/fuzzing/framework/adapters/llvm-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/adapters/llvm-unittest.cc
index 3f0bc6c..8a436249 100644
--- a/src/sys/fuzzing/framework/adapters/llvm-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/adapters/llvm-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/adapters/llvm.h"
+#include "src/sys/fuzzing/realmfuzzer/adapters/llvm.h"
 
 #include <gtest/gtest.h>
 
diff --git a/src/sys/fuzzing/framework/adapters/llvm.cc b/src/sys/fuzzing/realmfuzzer/adapters/llvm.cc
similarity index 97%
rename from src/sys/fuzzing/framework/adapters/llvm.cc
rename to src/sys/fuzzing/realmfuzzer/adapters/llvm.cc
index b75a4e9..f8651bf 100644
--- a/src/sys/fuzzing/framework/adapters/llvm.cc
+++ b/src/sys/fuzzing/realmfuzzer/adapters/llvm.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/adapters/llvm.h"
+#include "src/sys/fuzzing/realmfuzzer/adapters/llvm.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <zircon/errors.h>
diff --git a/src/sys/fuzzing/framework/adapters/llvm.h b/src/sys/fuzzing/realmfuzzer/adapters/llvm.h
similarity index 92%
rename from src/sys/fuzzing/framework/adapters/llvm.h
rename to src/sys/fuzzing/realmfuzzer/adapters/llvm.h
index 28cf4e0..617df15 100644
--- a/src/sys/fuzzing/framework/adapters/llvm.h
+++ b/src/sys/fuzzing/realmfuzzer/adapters/llvm.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ADAPTERS_LLVM_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ADAPTERS_LLVM_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ADAPTERS_LLVM_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ADAPTERS_LLVM_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <fuchsia/mem/cpp/fidl.h>
@@ -63,4 +63,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ADAPTERS_LLVM_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ADAPTERS_LLVM_H_
diff --git a/src/sys/fuzzing/framework/adapters/llvm.shard.cml b/src/sys/fuzzing/realmfuzzer/adapters/llvm.shard.cml
similarity index 100%
rename from src/sys/fuzzing/framework/adapters/llvm.shard.cml
rename to src/sys/fuzzing/realmfuzzer/adapters/llvm.shard.cml
diff --git a/src/sys/fuzzing/framework/engine/BUILD.gn b/src/sys/fuzzing/realmfuzzer/engine/BUILD.gn
similarity index 91%
rename from src/sys/fuzzing/framework/engine/BUILD.gn
rename to src/sys/fuzzing/realmfuzzer/engine/BUILD.gn
index c0b671e..62f88a8 100644
--- a/src/sys/fuzzing/framework/engine/BUILD.gn
+++ b/src/sys/fuzzing/realmfuzzer/engine/BUILD.gn
@@ -59,7 +59,7 @@
     "//src/lib/fxl",
     "//src/sys/fuzzing/common",
     "//src/sys/fuzzing/fidl:fuchsia.fuzzer",
-    "//src/sys/fuzzing/framework/target:no_hooks",
+    "//src/sys/fuzzing/realmfuzzer/target:no_hooks",
     "//zircon/system/ulib/sync",
   ]
   deps = [
@@ -71,7 +71,7 @@
 }
 
 executable("engine-bin") {
-  output_name = "component_fuzzing_engine"
+  output_name = "realmfuzzer_engine"
   testonly = true
   sources = [ "engine-main.cc" ]
   deps = [ ":engine-lib" ]
@@ -99,8 +99,8 @@
     "//src/sys/fuzzing/common:runner-unittests",
     "//src/sys/fuzzing/common/testing",
     "//src/sys/fuzzing/fidl:fuchsia.fuzzer",
-    "//src/sys/fuzzing/framework/target:no_hooks",
-    "//src/sys/fuzzing/framework/testing",
+    "//src/sys/fuzzing/realmfuzzer/target:no_hooks",
+    "//src/sys/fuzzing/realmfuzzer/testing",
     "//third_party/googletest:gtest",
   ]
 }
@@ -124,7 +124,7 @@
     ":testing",
     "//src/lib/files",
     "//src/sys/fuzzing/common:runner-unittests",
-    "//src/sys/fuzzing/framework/testing:test-target",
+    "//src/sys/fuzzing/realmfuzzer/testing:test-target",
   ]
 }
 
@@ -139,6 +139,6 @@
   deps = [
     ":testing",
     "//src/sys/fuzzing/common:runner-fatal-unittests",
-    "//src/sys/fuzzing/framework/testing:test-target",
+    "//src/sys/fuzzing/realmfuzzer/testing:test-target",
   ]
 }
diff --git a/src/sys/fuzzing/framework/engine/adapter-client-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/adapter-client-unittest.cc
similarity index 96%
rename from src/sys/fuzzing/framework/engine/adapter-client-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/adapter-client-unittest.cc
index 3b210e1..38da652 100644
--- a/src/sys/fuzzing/framework/engine/adapter-client-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/adapter-client-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/adapter-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/adapter-client.h"
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 
@@ -14,7 +14,7 @@
 #include "src/sys/fuzzing/common/input.h"
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/testing/async-test.h"
-#include "src/sys/fuzzing/framework/testing/adapter.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/adapter.h"
 
 namespace fuzzing {
 
diff --git a/src/sys/fuzzing/framework/engine/adapter-client.cc b/src/sys/fuzzing/realmfuzzer/engine/adapter-client.cc
similarity index 98%
rename from src/sys/fuzzing/framework/engine/adapter-client.cc
rename to src/sys/fuzzing/realmfuzzer/engine/adapter-client.cc
index 9a5a63d..5f4aee3 100644
--- a/src/sys/fuzzing/framework/engine/adapter-client.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/adapter-client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/adapter-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/adapter-client.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <zircon/status.h>
diff --git a/src/sys/fuzzing/framework/engine/adapter-client.h b/src/sys/fuzzing/realmfuzzer/engine/adapter-client.h
similarity index 90%
rename from src/sys/fuzzing/framework/engine/adapter-client.h
rename to src/sys/fuzzing/realmfuzzer/engine/adapter-client.h
index 8607b18..288429a 100644
--- a/src/sys/fuzzing/framework/engine/adapter-client.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/adapter-client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_ADAPTER_CLIENT_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_ADAPTER_CLIENT_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_ADAPTER_CLIENT_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_ADAPTER_CLIENT_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <lib/fidl/cpp/interface_request.h>
@@ -17,7 +17,7 @@
 #include "src/sys/fuzzing/common/input.h"
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/shared-memory.h"
-#include "src/sys/fuzzing/framework/engine/corpus.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/corpus.h"
 
 namespace fuzzing {
 
@@ -72,4 +72,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_ADAPTER_CLIENT_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_ADAPTER_CLIENT_H_
diff --git a/src/sys/fuzzing/framework/engine/corpus-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/corpus-unittest.cc
similarity index 98%
rename from src/sys/fuzzing/framework/engine/corpus-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/corpus-unittest.cc
index a26aa00..9ac7ccc 100644
--- a/src/sys/fuzzing/framework/engine/corpus-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/corpus-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/corpus.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/corpus.h"
 
 #include <unordered_set>
 
diff --git a/src/sys/fuzzing/framework/engine/corpus.cc b/src/sys/fuzzing/realmfuzzer/engine/corpus.cc
similarity index 98%
rename from src/sys/fuzzing/framework/engine/corpus.cc
rename to src/sys/fuzzing/realmfuzzer/engine/corpus.cc
index 18ed503..8e63dbb 100644
--- a/src/sys/fuzzing/framework/engine/corpus.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/corpus.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/corpus.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/corpus.h"
 
 #include <lib/async/dispatcher.h>
 #include <lib/syslog/cpp/macros.h>
diff --git a/src/sys/fuzzing/framework/engine/corpus.h b/src/sys/fuzzing/realmfuzzer/engine/corpus.h
similarity index 95%
rename from src/sys/fuzzing/framework/engine/corpus.h
rename to src/sys/fuzzing/realmfuzzer/engine/corpus.h
index 655743b..8d4e05c 100644
--- a/src/sys/fuzzing/framework/engine/corpus.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/corpus.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_CORPUS_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_CORPUS_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_CORPUS_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_CORPUS_H_
 
 #include <stddef.h>
 #include <zircon/compiler.h>
@@ -90,4 +90,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_CORPUS_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_CORPUS_H_
diff --git a/src/sys/fuzzing/framework/engine/coverage-client-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/coverage-client-unittest.cc
similarity index 93%
rename from src/sys/fuzzing/framework/engine/coverage-client-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-client-unittest.cc
index db27b07..937a1af 100644
--- a/src/sys/fuzzing/framework/engine/coverage-client-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-client-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/coverage-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-client.h"
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 
@@ -13,7 +13,7 @@
 #include "src/sys/fuzzing/common/async-deque.h"
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/testing/async-test.h"
-#include "src/sys/fuzzing/framework/coverage/provider.h"
+#include "src/sys/fuzzing/realmfuzzer/coverage/provider.h"
 
 namespace fuzzing {
 
diff --git a/src/sys/fuzzing/framework/engine/coverage-client.cc b/src/sys/fuzzing/realmfuzzer/engine/coverage-client.cc
similarity index 95%
rename from src/sys/fuzzing/framework/engine/coverage-client.cc
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-client.cc
index 7cfb76b..36d6ba3 100644
--- a/src/sys/fuzzing/framework/engine/coverage-client.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/coverage-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-client.h"
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <lib/sync/completion.h>
diff --git a/src/sys/fuzzing/framework/engine/coverage-client.h b/src/sys/fuzzing/realmfuzzer/engine/coverage-client.h
similarity index 87%
rename from src/sys/fuzzing/framework/engine/coverage-client.h
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-client.h
index 58cdb72..9c0f558 100644
--- a/src/sys/fuzzing/framework/engine/coverage-client.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_CLIENT_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_CLIENT_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_CLIENT_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_CLIENT_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 
@@ -45,4 +45,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_CLIENT_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_CLIENT_H_
diff --git a/src/sys/fuzzing/framework/engine/coverage-data-provider-client-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client-unittest.cc
similarity index 94%
rename from src/sys/fuzzing/framework/engine/coverage-data-provider-client-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client-unittest.cc
index 86669f4..7dd23a4 100644
--- a/src/sys/fuzzing/framework/engine/coverage-data-provider-client-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/coverage-data-provider-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.h"
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <lib/fidl/cpp/binding.h>
@@ -17,8 +17,8 @@
 #include "src/sys/fuzzing/common/async-types.h"
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/testing/async-test.h"
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
-#include "src/sys/fuzzing/framework/testing/module.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/module.h"
 
 namespace fuzzing {
 
@@ -144,11 +144,11 @@
   char name[ZX_MAX_NAME_LEN];
 
   // Send multiple, and verify they arrive in order.
-  FakeFrameworkModule module1(1);
+  FakeRealmFuzzerModule module1(1);
   EXPECT_EQ(module1.Share(0x1111, &counters), ZX_OK);
   Pend(CoverageData::WithInline8bitCounters(std::move(counters)));
 
-  FakeFrameworkModule module2(1);
+  FakeRealmFuzzerModule module2(1);
   EXPECT_EQ(module2.Share(0x2222, &counters), ZX_OK);
   Pend(CoverageData::WithInline8bitCounters(std::move(counters)));
 
@@ -169,7 +169,7 @@
   EXPECT_EQ(GetModuleId(name), module2.id());
 
   // Intentionally drop a |GetCoverageData| future and ensure no data is lost.
-  FakeFrameworkModule module3(3);
+  FakeRealmFuzzerModule module3(3);
   {
     auto dropped = provider_client->GetCoverageData();
     RunOnce();
diff --git a/src/sys/fuzzing/framework/engine/coverage-data-provider-client.cc b/src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.cc
similarity index 96%
rename from src/sys/fuzzing/framework/engine/coverage-data-provider-client.cc
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.cc
index 7227ff1..fe9cdda 100644
--- a/src/sys/fuzzing/framework/engine/coverage-data-provider-client.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/coverage-data-provider-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.h"
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <lib/sync/completion.h>
diff --git a/src/sys/fuzzing/framework/engine/coverage-data-provider-client.h b/src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.h
similarity index 80%
rename from src/sys/fuzzing/framework/engine/coverage-data-provider-client.h
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.h
index 1d12afe..83fe073 100644
--- a/src/sys/fuzzing/framework/engine/coverage-data-provider-client.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_DATA_PROVIDER_CLIENT_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_DATA_PROVIDER_CLIENT_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_DATA_PROVIDER_CLIENT_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_DATA_PROVIDER_CLIENT_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <stdint.h>
@@ -13,7 +13,7 @@
 #include "src/sys/fuzzing/common/async-deque.h"
 #include "src/sys/fuzzing/common/async-types.h"
 #include "src/sys/fuzzing/common/options.h"
-#include "src/sys/fuzzing/framework/engine/module-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-proxy.h"
 
 namespace fuzzing {
 
@@ -44,4 +44,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_DATA_PROVIDER_CLIENT_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_DATA_PROVIDER_CLIENT_H_
diff --git a/src/sys/fuzzing/framework/engine/coverage-data-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/coverage-data-unittest.cc
similarity index 93%
rename from src/sys/fuzzing/framework/engine/coverage-data-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-data-unittest.cc
index d1b7b9f..a8e4c8d 100644
--- a/src/sys/fuzzing/framework/engine/coverage-data-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-data-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
 
 #include <gtest/gtest.h>
 
diff --git a/src/sys/fuzzing/framework/engine/coverage-data.cc b/src/sys/fuzzing/realmfuzzer/engine/coverage-data.cc
similarity index 96%
rename from src/sys/fuzzing/framework/engine/coverage-data.cc
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-data.cc
index b0e6f9c..8e63a60 100644
--- a/src/sys/fuzzing/framework/engine/coverage-data.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-data.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <zircon/status.h>
diff --git a/src/sys/fuzzing/framework/engine/coverage-data.h b/src/sys/fuzzing/realmfuzzer/engine/coverage-data.h
similarity index 83%
rename from src/sys/fuzzing/framework/engine/coverage-data.h
rename to src/sys/fuzzing/realmfuzzer/engine/coverage-data.h
index 135e16e..3252352 100644
--- a/src/sys/fuzzing/framework/engine/coverage-data.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/coverage-data.h
@@ -4,8 +4,8 @@
 
 // This file contains routines to consume |fuchsia.fuzzer.CoverageData| FIDL structures.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_DATA_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_DATA_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_DATA_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_DATA_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <lib/zx/process.h>
@@ -13,7 +13,7 @@
 
 #include <string>
 
-#include "src/sys/fuzzing/framework/target/process.h"
+#include "src/sys/fuzzing/realmfuzzer/target/process.h"
 
 namespace fuzzing {
 
@@ -38,4 +38,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_COVERAGE_DATA_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_COVERAGE_DATA_H_
diff --git a/src/sys/fuzzing/framework/engine/default.shard.cml b/src/sys/fuzzing/realmfuzzer/engine/default.shard.cml
similarity index 100%
rename from src/sys/fuzzing/framework/engine/default.shard.cml
rename to src/sys/fuzzing/realmfuzzer/engine/default.shard.cml
diff --git a/src/sys/fuzzing/framework/engine/dictionary-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/dictionary-unittest.cc
similarity index 98%
rename from src/sys/fuzzing/framework/engine/dictionary-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/dictionary-unittest.cc
index dca29c4..746f00f 100644
--- a/src/sys/fuzzing/framework/engine/dictionary-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/dictionary-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/dictionary.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/dictionary.h"
 
 #include <unordered_set>
 
diff --git a/src/sys/fuzzing/framework/engine/dictionary.cc b/src/sys/fuzzing/realmfuzzer/engine/dictionary.cc
similarity index 98%
rename from src/sys/fuzzing/framework/engine/dictionary.cc
rename to src/sys/fuzzing/realmfuzzer/engine/dictionary.cc
index 2df6dd2..e19fde3 100644
--- a/src/sys/fuzzing/framework/engine/dictionary.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/dictionary.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/dictionary.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/dictionary.h"
 
 #include <lib/syslog/cpp/macros.h>
 
diff --git a/src/sys/fuzzing/framework/engine/dictionary.h b/src/sys/fuzzing/realmfuzzer/engine/dictionary.h
similarity index 94%
rename from src/sys/fuzzing/framework/engine/dictionary.h
rename to src/sys/fuzzing/realmfuzzer/engine/dictionary.h
index 99b7dac..adf5e0c 100644
--- a/src/sys/fuzzing/framework/engine/dictionary.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/dictionary.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_DICTIONARY_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_DICTIONARY_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_DICTIONARY_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_DICTIONARY_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -91,4 +91,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_DICTIONARY_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_DICTIONARY_H_
diff --git a/src/sys/fuzzing/framework/engine/engine-main.cc b/src/sys/fuzzing/realmfuzzer/engine/engine-main.cc
similarity index 80%
rename from src/sys/fuzzing/framework/engine/engine-main.cc
rename to src/sys/fuzzing/realmfuzzer/engine/engine-main.cc
index 85586f0..983b6b3 100644
--- a/src/sys/fuzzing/framework/engine/engine-main.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/engine-main.cc
@@ -7,19 +7,19 @@
 
 #include "src/sys/fuzzing/common/component-context.h"
 #include "src/sys/fuzzing/common/controller-provider.h"
-#include "src/sys/fuzzing/framework/engine/runner.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/runner.h"
 
 namespace fuzzing {
 
-zx_status_t RunFrameworkEngine() {
+zx_status_t RunRealmFuzzer() {
   // Take start up handles.
   auto context = ComponentContext::Create();
   zx::channel fuzz_registry_channel{zx_take_startup_handle(PA_HND(PA_USER0, 0))};
   zx::channel fuzz_coverage_channel{zx_take_startup_handle(PA_HND(PA_USER0, 1))};
 
   // Create the runner.
-  auto runner = RunnerImpl::MakePtr(context->executor());
-  auto runner_impl = std::static_pointer_cast<RunnerImpl>(runner);
+  auto runner = RealmFuzzerRunner::MakePtr(context->executor());
+  auto runner_impl = std::static_pointer_cast<RealmFuzzerRunner>(runner);
   runner_impl->SetTargetAdapterHandler(context->MakeRequestHandler<TargetAdapter>());
   if (auto status = runner_impl->BindCoverageDataProvider(std::move(fuzz_coverage_channel));
       status != ZX_OK) {
@@ -37,4 +37,4 @@
 
 }  // namespace fuzzing
 
-int main() { return fuzzing::RunFrameworkEngine(); }
+int main() { return fuzzing::RunRealmFuzzer(); }
diff --git a/src/sys/fuzzing/framework/engine/meta/engine.cml b/src/sys/fuzzing/realmfuzzer/engine/meta/engine.cml
similarity index 84%
rename from src/sys/fuzzing/framework/engine/meta/engine.cml
rename to src/sys/fuzzing/realmfuzzer/engine/meta/engine.cml
index 5c4728a..56074ec 100644
--- a/src/sys/fuzzing/framework/engine/meta/engine.cml
+++ b/src/sys/fuzzing/realmfuzzer/engine/meta/engine.cml
@@ -5,11 +5,11 @@
 // This manifest corresponds to the "real" engine used by fuzzers.
 {
     include: [
-        "//src/sys/fuzzing/framework/engine/default.shard.cml",
+        "//src/sys/fuzzing/realmfuzzer/engine/default.shard.cml",
         "//src/sys/test_runners/fuzz/default.shard.cml",
     ],
     program: {
-        binary: "bin/component_fuzzing_engine",
+        binary: "bin/realmfuzzer_engine",
     },
     use: [
         { protocol: "fuchsia.fuzzer.CoverageProvider" },
diff --git a/src/sys/fuzzing/framework/engine/module-pool-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/module-pool-unittest.cc
similarity index 95%
rename from src/sys/fuzzing/framework/engine/module-pool-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/module-pool-unittest.cc
index 27bfb0d..c2c0654 100644
--- a/src/sys/fuzzing/framework/engine/module-pool-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/module-pool-unittest.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/module-pool.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-pool.h"
 
 #include <gtest/gtest.h>
 
-#include "src/sys/fuzzing/framework/engine/module-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-proxy.h"
 
 namespace fuzzing {
 namespace {
diff --git a/src/sys/fuzzing/framework/engine/module-pool.cc b/src/sys/fuzzing/realmfuzzer/engine/module-pool.cc
similarity index 95%
rename from src/sys/fuzzing/framework/engine/module-pool.cc
rename to src/sys/fuzzing/realmfuzzer/engine/module-pool.cc
index b25b994..aa25591 100644
--- a/src/sys/fuzzing/framework/engine/module-pool.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/module-pool.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/module-pool.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-pool.h"
 
 #include <iomanip>
 #include <sstream>
diff --git a/src/sys/fuzzing/framework/engine/module-pool.h b/src/sys/fuzzing/realmfuzzer/engine/module-pool.h
similarity index 84%
rename from src/sys/fuzzing/framework/engine/module-pool.h
rename to src/sys/fuzzing/realmfuzzer/engine/module-pool.h
index f33baae..35ab92f 100644
--- a/src/sys/fuzzing/framework/engine/module-pool.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/module-pool.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MODULE_POOL_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MODULE_POOL_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MODULE_POOL_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MODULE_POOL_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <stddef.h>
@@ -12,7 +12,7 @@
 #include <unordered_map>
 
 #include "src/lib/fxl/macros.h"
-#include "src/sys/fuzzing/framework/engine/module-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-proxy.h"
 
 namespace fuzzing {
 
@@ -49,4 +49,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MODULE_POOL_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MODULE_POOL_H_
diff --git a/src/sys/fuzzing/framework/engine/module-proxy-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/module-proxy-unittest.cc
similarity index 96%
rename from src/sys/fuzzing/framework/engine/module-proxy-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/module-proxy-unittest.cc
index ab3da07..4552a61 100644
--- a/src/sys/fuzzing/framework/engine/module-proxy-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/module-proxy-unittest.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/module-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-proxy.h"
 
 #include <random>
 
 #include <gtest/gtest.h>
 
 #include "src/sys/fuzzing/common/shared-memory.h"
-#include "src/sys/fuzzing/framework/target/module.h"
-#include "src/sys/fuzzing/framework/testing/module.h"
+#include "src/sys/fuzzing/realmfuzzer/target/module.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/module.h"
 
 namespace fuzzing {
 namespace {
diff --git a/src/sys/fuzzing/framework/engine/module-proxy.cc b/src/sys/fuzzing/realmfuzzer/engine/module-proxy.cc
similarity index 98%
rename from src/sys/fuzzing/framework/engine/module-proxy.cc
rename to src/sys/fuzzing/realmfuzzer/engine/module-proxy.cc
index 9996a8e..4932b5c 100644
--- a/src/sys/fuzzing/framework/engine/module-proxy.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/module-proxy.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/module-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-proxy.h"
 
 #include <lib/syslog/cpp/macros.h>
 
diff --git a/src/sys/fuzzing/framework/engine/module-proxy.h b/src/sys/fuzzing/realmfuzzer/engine/module-proxy.h
similarity index 93%
rename from src/sys/fuzzing/framework/engine/module-proxy.h
rename to src/sys/fuzzing/realmfuzzer/engine/module-proxy.h
index 01aa0e8..6a016c9 100644
--- a/src/sys/fuzzing/framework/engine/module-proxy.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/module-proxy.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MODULE_PROXY_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MODULE_PROXY_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MODULE_PROXY_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MODULE_PROXY_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <fuchsia/mem/cpp/fidl.h>
@@ -75,4 +75,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MODULE_PROXY_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MODULE_PROXY_H_
diff --git a/src/sys/fuzzing/framework/engine/mutagen-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/mutagen-unittest.cc
similarity index 99%
rename from src/sys/fuzzing/framework/engine/mutagen-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/mutagen-unittest.cc
index 14b139d..8e5849d 100644
--- a/src/sys/fuzzing/framework/engine/mutagen-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/mutagen-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/mutagen.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/mutagen.h"
 
 #include <unordered_set>
 
diff --git a/src/sys/fuzzing/framework/engine/mutagen.cc b/src/sys/fuzzing/realmfuzzer/engine/mutagen.cc
similarity index 99%
rename from src/sys/fuzzing/framework/engine/mutagen.cc
rename to src/sys/fuzzing/realmfuzzer/engine/mutagen.cc
index 81c487b..e69a023 100644
--- a/src/sys/fuzzing/framework/engine/mutagen.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/mutagen.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/mutagen.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/mutagen.h"
 
 #include <lib/syslog/cpp/macros.h>
 
diff --git a/src/sys/fuzzing/framework/engine/mutagen.h b/src/sys/fuzzing/realmfuzzer/engine/mutagen.h
similarity index 94%
rename from src/sys/fuzzing/framework/engine/mutagen.h
rename to src/sys/fuzzing/realmfuzzer/engine/mutagen.h
index dc6ee72..d42ff88 100644
--- a/src/sys/fuzzing/framework/engine/mutagen.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/mutagen.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MUTAGEN_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MUTAGEN_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MUTAGEN_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MUTAGEN_H_
 
 #include <stddef.h>
 
@@ -12,7 +12,7 @@
 #include "src/lib/fxl/macros.h"
 #include "src/sys/fuzzing/common/input.h"
 #include "src/sys/fuzzing/common/options.h"
-#include "src/sys/fuzzing/framework/engine/dictionary.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/dictionary.h"
 
 namespace fuzzing {
 
@@ -53,7 +53,7 @@
 // MutationDispatcher, here:
 //   https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/fuzzer/FuzzerMutate.cpp
 //
-// During fuzzing, the framework will pick an input from the corpus, and pass it to this object. It
+// During fuzzing, the runner will pick an input from the corpus, and pass it to this object. It
 // will then use this object to generate a sequence of mutated inputs that it can send to the
 // target adapter.
 class Mutagen final {
@@ -172,4 +172,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_MUTAGEN_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_MUTAGEN_H_
diff --git a/src/sys/fuzzing/framework/engine/process-proxy-fatal-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/process-proxy-fatal-unittest.cc
similarity index 84%
rename from src/sys/fuzzing/framework/engine/process-proxy-fatal-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/process-proxy-fatal-unittest.cc
index a6736e7..e3beea6 100644
--- a/src/sys/fuzzing/framework/engine/process-proxy-fatal-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/process-proxy-fatal-unittest.cc
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "src/sys/fuzzing/common/options.h"
-#include "src/sys/fuzzing/framework/engine/process-proxy-test.h"
-#include "src/sys/fuzzing/framework/engine/process-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/process-proxy.h"
 
 namespace fuzzing {
 namespace {
diff --git a/src/sys/fuzzing/framework/engine/process-proxy-test.cc b/src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.cc
similarity index 93%
rename from src/sys/fuzzing/framework/engine/process-proxy-test.cc
rename to src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.cc
index d6024aa..5b9d63d 100644
--- a/src/sys/fuzzing/framework/engine/process-proxy-test.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/process-proxy-test.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.h"
 
 #include <zircon/status.h>
 
 #include "src/sys/fuzzing/common/async-eventpair.h"
-#include "src/sys/fuzzing/framework/target/process.h"
+#include "src/sys/fuzzing/realmfuzzer/target/process.h"
 
 namespace fuzzing {
 
diff --git a/src/sys/fuzzing/framework/engine/process-proxy-test.h b/src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.h
similarity index 83%
rename from src/sys/fuzzing/framework/engine/process-proxy-test.h
rename to src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.h
index 961bdb5..874c172 100644
--- a/src/sys/fuzzing/framework/engine/process-proxy-test.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_PROCESS_PROXY_TEST_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_PROCESS_PROXY_TEST_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_PROCESS_PROXY_TEST_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_PROCESS_PROXY_TEST_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <stdint.h>
@@ -15,9 +15,9 @@
 #include "src/sys/fuzzing/common/async-eventpair.h"
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/testing/async-test.h"
-#include "src/sys/fuzzing/framework/engine/module-pool.h"
-#include "src/sys/fuzzing/framework/engine/process-proxy.h"
-#include "src/sys/fuzzing/framework/testing/target.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-pool.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/process-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/target.h"
 
 namespace fuzzing {
 
@@ -55,4 +55,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_PROCESS_PROXY_TEST_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_PROCESS_PROXY_TEST_H_
diff --git a/src/sys/fuzzing/framework/engine/process-proxy-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/process-proxy-unittest.cc
similarity index 95%
rename from src/sys/fuzzing/framework/engine/process-proxy-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/process-proxy-unittest.cc
index e94f5d0..12b82cd 100644
--- a/src/sys/fuzzing/framework/engine/process-proxy-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/process-proxy-unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/process-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/process-proxy.h"
 
 #include <lib/sync/completion.h>
 
@@ -11,10 +11,10 @@
 #include <gtest/gtest.h>
 
 #include "src/sys/fuzzing/common/options.h"
-#include "src/sys/fuzzing/framework/engine/process-proxy-test.h"
-#include "src/sys/fuzzing/framework/target/module.h"
-#include "src/sys/fuzzing/framework/testing/module.h"
-#include "src/sys/fuzzing/framework/testing/target.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/process-proxy-test.h"
+#include "src/sys/fuzzing/realmfuzzer/target/module.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/module.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/target.h"
 
 namespace fuzzing {
 namespace {
@@ -44,9 +44,10 @@
   AsyncEventPair eventpair(executor());
   auto process_proxy = CreateAndConnectProxy(target.Launch(), eventpair.Create());
 
-  FakeFrameworkModule module;
-  // Invalid id.
+  FakeRealmFuzzerModule module;
   zx::vmo inline_8bit_counters;
+
+  // Invalid id.
   EXPECT_EQ(module.Share(0x1234, &inline_8bit_counters), ZX_OK);
   const char* invalid_name = "invalid";
   EXPECT_EQ(inline_8bit_counters.set_property(ZX_PROP_NAME, invalid_name, strlen(invalid_name)),
diff --git a/src/sys/fuzzing/framework/engine/process-proxy.cc b/src/sys/fuzzing/realmfuzzer/engine/process-proxy.cc
similarity index 98%
rename from src/sys/fuzzing/framework/engine/process-proxy.cc
rename to src/sys/fuzzing/realmfuzzer/engine/process-proxy.cc
index 646a3b2..b298c15 100644
--- a/src/sys/fuzzing/framework/engine/process-proxy.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/process-proxy.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/process-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/process-proxy.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <lib/zx/job.h>
@@ -11,7 +11,7 @@
 #include <inspector/inspector.h>
 
 #include "src/sys/fuzzing/common/status.h"
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
 
 namespace fuzzing {
 
diff --git a/src/sys/fuzzing/framework/engine/process-proxy.h b/src/sys/fuzzing/realmfuzzer/engine/process-proxy.h
similarity index 90%
rename from src/sys/fuzzing/framework/engine/process-proxy.h
rename to src/sys/fuzzing/realmfuzzer/engine/process-proxy.h
index ec5fd70..8ea60b6 100644
--- a/src/sys/fuzzing/framework/engine/process-proxy.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/process-proxy.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_PROCESS_PROXY_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_PROCESS_PROXY_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_PROCESS_PROXY_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_PROCESS_PROXY_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <fuchsia/mem/cpp/fidl.h>
@@ -23,9 +23,9 @@
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/result.h"
 #include "src/sys/fuzzing/common/shared-memory.h"
-#include "src/sys/fuzzing/framework/engine/module-pool.h"
-#include "src/sys/fuzzing/framework/engine/module-proxy.h"
-#include "src/sys/fuzzing/framework/target/process.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-pool.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/target/process.h"
 
 namespace fuzzing {
 
@@ -103,4 +103,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_PROCESS_PROXY_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_PROCESS_PROXY_H_
diff --git a/src/sys/fuzzing/framework/engine/runner-fatal-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/runner-fatal-unittest.cc
similarity index 63%
rename from src/sys/fuzzing/framework/engine/runner-fatal-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/runner-fatal-unittest.cc
index ea20979..4d76b73 100644
--- a/src/sys/fuzzing/framework/engine/runner-fatal-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/runner-fatal-unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/runner-test.h"
-#include "src/sys/fuzzing/framework/engine/runner.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/runner-test.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/runner.h"
 
 namespace fuzzing {
 namespace {
 
-#define RUNNER_TYPE RunnerImpl
-#define RUNNER_TEST RunnerImplTest
+#define RUNNER_TYPE RealmFuzzerRunner
+#define RUNNER_TEST RealmFuzzerRunnerTest
 #include "src/sys/fuzzing/common/runner-fatal-unittest.inc"
 #undef RUNNER_TYPE
 #undef RUNNER_TEST
diff --git a/src/sys/fuzzing/framework/engine/runner-test.cc b/src/sys/fuzzing/realmfuzzer/engine/runner-test.cc
similarity index 89%
rename from src/sys/fuzzing/framework/engine/runner-test.cc
rename to src/sys/fuzzing/realmfuzzer/engine/runner-test.cc
index a9d70e6..8f38992 100644
--- a/src/sys/fuzzing/framework/engine/runner-test.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/runner-test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/runner-test.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/runner-test.h"
 
 #include <lib/fidl/cpp/interface_handle.h>
 #include <lib/syslog/cpp/macros.h>
@@ -12,14 +12,14 @@
 #include <gtest/gtest.h>
 
 #include "src/sys/fuzzing/common/options.h"
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
 
 namespace fuzzing {
 
-void RunnerImplTest::SetUp() {
+void RealmFuzzerRunnerTest::SetUp() {
   RunnerTest::SetUp();
-  runner_ = RunnerImpl::MakePtr(executor());
-  auto runner_impl = std::static_pointer_cast<RunnerImpl>(runner_);
+  runner_ = RealmFuzzerRunner::MakePtr(executor());
+  auto runner_impl = std::static_pointer_cast<RealmFuzzerRunner>(runner_);
   target_adapter_ = std::make_unique<FakeTargetAdapter>(executor());
   runner_impl->SetTargetAdapterHandler(target_adapter_->GetHandler());
 
@@ -33,11 +33,11 @@
   target_ = std::make_unique<TestTarget>(executor());
 }
 
-void RunnerImplTest::SetAdapterParameters(const std::vector<std::string>& parameters) {
+void RealmFuzzerRunnerTest::SetAdapterParameters(const std::vector<std::string>& parameters) {
   target_adapter_->SetParameters(parameters);
 }
 
-ZxPromise<Input> RunnerImplTest::GetTestInput() {
+ZxPromise<Input> RealmFuzzerRunnerTest::GetTestInput() {
   auto stash = std::make_shared<Input>();
   return target_adapter_->AwaitStart()
       .and_then([this, stash](Input& input) -> ZxResult<> {
@@ -60,7 +60,7 @@
       .wrap_with(scope_);
 }
 
-ZxPromise<> RunnerImplTest::PublishProcess() {
+ZxPromise<> RealmFuzzerRunnerTest::PublishProcess() {
   Bridge<Options> bridge;
   return fpromise::make_promise(
              [this, completer = std::move(bridge.completer)]() mutable -> ZxResult<> {
@@ -86,7 +86,7 @@
       });
 }
 
-ZxPromise<> RunnerImplTest::PublishModule() {
+ZxPromise<> RealmFuzzerRunnerTest::PublishModule() {
   Bridge<> bridge;
   return fpromise::make_promise([this,
                                  completer = std::move(bridge.completer)]() mutable -> ZxResult<> {
@@ -111,7 +111,8 @@
       });
 }
 
-ZxPromise<> RunnerImplTest::SetFeedback(Coverage coverage, FuzzResult fuzz_result, bool leak) {
+ZxPromise<> RealmFuzzerRunnerTest::SetFeedback(Coverage coverage, FuzzResult fuzz_result,
+                                               bool leak) {
   return fpromise::make_promise(
              [this, coverage = std::move(coverage), leak, fuzz_result]() mutable -> ZxResult<> {
                if (fuzz_result != FuzzResult::NO_ERRORS) {
@@ -183,7 +184,7 @@
       .wrap_with(scope_);
 }
 
-ZxPromise<> RunnerImplTest::AwaitStart() {
+ZxPromise<> RealmFuzzerRunnerTest::AwaitStart() {
   return fpromise::make_promise(
              [this, start = ZxFuture<zx_signals_t>()](Context& context) mutable -> ZxResult<> {
                while (true) {
@@ -212,7 +213,7 @@
       .wrap_with(scope_);
 }
 
-ZxPromise<> RunnerImplTest::AwaitFinish() {
+ZxPromise<> RealmFuzzerRunnerTest::AwaitFinish() {
   return eventpair_->WaitFor(kFinish)
       .and_then([this](const zx_signals_t& observed) -> ZxResult<> {
         module_.Update();
@@ -229,7 +230,7 @@
       .wrap_with(scope_);
 }
 
-ZxPromise<> RunnerImplTest::ExitAsync(int32_t exitcode) {
+ZxPromise<> RealmFuzzerRunnerTest::ExitAsync(int32_t exitcode) {
   return target_->Exit(exitcode)
       .and_then([this] {
         eventpair_->Reset();
@@ -239,7 +240,7 @@
       .wrap_with(scope_);
 }
 
-ZxPromise<> RunnerImplTest::CrashAsync() {
+ZxPromise<> RealmFuzzerRunnerTest::CrashAsync() {
   return target_->Crash()
       .and_then([this] {
         eventpair_->Reset();
diff --git a/src/sys/fuzzing/framework/engine/runner-test.h b/src/sys/fuzzing/realmfuzzer/engine/runner-test.h
similarity index 76%
rename from src/sys/fuzzing/framework/engine/runner-test.h
rename to src/sys/fuzzing/realmfuzzer/engine/runner-test.h
index 5042c37..7e3b355 100644
--- a/src/sys/fuzzing/framework/engine/runner-test.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/runner-test.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_RUNNER_TEST_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_RUNNER_TEST_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_RUNNER_TEST_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_RUNNER_TEST_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <lib/fidl/cpp/interface_request.h>
@@ -20,18 +20,18 @@
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/runner-unittest.h"
 #include "src/sys/fuzzing/common/testing/module.h"
-#include "src/sys/fuzzing/framework/engine/runner.h"
-#include "src/sys/fuzzing/framework/target/module.h"
-#include "src/sys/fuzzing/framework/testing/adapter.h"
-#include "src/sys/fuzzing/framework/testing/coverage.h"
-#include "src/sys/fuzzing/framework/testing/module.h"
-#include "src/sys/fuzzing/framework/testing/target.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/runner.h"
+#include "src/sys/fuzzing/realmfuzzer/target/module.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/adapter.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/coverage.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/module.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/target.h"
 
 namespace fuzzing {
 
-// Specializes the generic |RunnerTest| for |RunnerImpl|. Encapsulates a fake target adapter,
+// Specializes the generic |RunnerTest| for |RealmFuzzerRunner|. Encapsulates a fake target adapter,
 // fake target process, and fake coverage component.
-class RunnerImplTest : public RunnerTest {
+class RealmFuzzerRunnerTest : public RunnerTest {
  protected:
   void SetUp() override;
 
@@ -71,7 +71,7 @@
   std::unique_ptr<FakeCoverage> coverage_;
   CoverageDataCollectorPtr collector_;
   std::unique_ptr<AsyncEventPair> eventpair_;
-  FakeFrameworkModule module_;
+  FakeRealmFuzzerModule module_;
   std::unique_ptr<TestTarget> target_;
   bool running_ = false;
   bool leak_suspected_ = false;
@@ -80,4 +80,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_RUNNER_TEST_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_RUNNER_TEST_H_
diff --git a/src/sys/fuzzing/framework/engine/runner-unittest.cc b/src/sys/fuzzing/realmfuzzer/engine/runner-unittest.cc
similarity index 76%
rename from src/sys/fuzzing/framework/engine/runner-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/engine/runner-unittest.cc
index e0cc405..1158be7 100644
--- a/src/sys/fuzzing/framework/engine/runner-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/runner-unittest.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/runner.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/runner.h"
 
 #include "src/sys/fuzzing/common/options.h"
-#include "src/sys/fuzzing/framework/engine/runner-test.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/runner-test.h"
 
 namespace fuzzing {
 namespace {
 
-TEST_F(RunnerImplTest, AddDefaults) {
+TEST_F(RealmFuzzerRunnerTest, AddDefaults) {
   Options options;
   runner()->AddDefaults(&options);
   EXPECT_EQ(options.runs(), kDefaultRuns);
@@ -29,12 +29,12 @@
   EXPECT_EQ(options.pulse_interval(), kDefaultPulseInterval);
 }
 
-TEST_F(RunnerImplTest, LoadCorpus) {
+TEST_F(RealmFuzzerRunnerTest, LoadCorpus) {
   // In a real fuzzer, the parameters would be supplied by the 'program.args' from the adapter's
   // component manifest.
   //
   // See also:
-  //   //src/sys/fuzzing/framework/testing/data/BUILD.gn
+  //   //src/sys/fuzzing/realmfuzzer/testing/data/BUILD.gn
   SetAdapterParameters(std::vector<std::string>({"data/corpus", "--ignored"}));
   Configure(RunnerTest::DefaultOptions());
   // Results are sorted.
@@ -42,15 +42,17 @@
   EXPECT_EQ(runner()->ReadFromCorpus(CorpusType::SEED, 2), Input("foo"));
 }
 
-#define RUNNER_TYPE RunnerImpl
-#define RUNNER_TEST RunnerImplTest
+#define RUNNER_TYPE RealmFuzzerRunner
+#define RUNNER_TEST RealmFuzzerRunnerTest
 #include "src/sys/fuzzing/common/runner-unittest.inc"
 #undef RUNNER_TYPE
 #undef RUNNER_TEST
 
-TEST_F(RunnerImplTest, MergeSeedError) { MergeSeedError(/* expected */ ZX_ERR_INVALID_ARGS); }
+TEST_F(RealmFuzzerRunnerTest, MergeSeedError) {
+  MergeSeedError(/* expected */ ZX_ERR_INVALID_ARGS);
+}
 
-TEST_F(RunnerImplTest, Merge) { Merge(/* keep_errors= */ true); }
+TEST_F(RealmFuzzerRunnerTest, Merge) { Merge(/* keep_errors= */ true); }
 
 }  // namespace
 }  // namespace fuzzing
diff --git a/src/sys/fuzzing/framework/engine/runner.cc b/src/sys/fuzzing/realmfuzzer/engine/runner.cc
similarity index 92%
rename from src/sys/fuzzing/framework/engine/runner.cc
rename to src/sys/fuzzing/realmfuzzer/engine/runner.cc
index cf04697..ad2c6d4 100644
--- a/src/sys/fuzzing/framework/engine/runner.cc
+++ b/src/sys/fuzzing/realmfuzzer/engine/runner.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/engine/runner.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/runner.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <lib/zx/clock.h>
@@ -13,18 +13,18 @@
 #include <deque>
 
 #include "src/lib/fxl/macros.h"
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
-#include "src/sys/fuzzing/framework/target/process.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/target/process.h"
 
 namespace fuzzing {
 
 using ::fuchsia::fuzzer::MAX_PROCESS_STATS;
 
-RunnerPtr RunnerImpl::MakePtr(ExecutorPtr executor) {
-  return RunnerPtr(new RunnerImpl(std::move(executor)));
+RunnerPtr RealmFuzzerRunner::MakePtr(ExecutorPtr executor) {
+  return RunnerPtr(new RealmFuzzerRunner(std::move(executor)));
 }
 
-RunnerImpl::RunnerImpl(ExecutorPtr executor)
+RealmFuzzerRunner::RealmFuzzerRunner(ExecutorPtr executor)
     : Runner(executor), adapter_(executor), provider_(executor), workflow_(this) {
   generated_.Close();
   processed_.Close();
@@ -33,15 +33,15 @@
   pool_ = std::make_shared<ModulePool>();
 }
 
-void RunnerImpl::SetTargetAdapterHandler(TargetAdapterClient::RequestHandler handler) {
+void RealmFuzzerRunner::SetTargetAdapterHandler(TargetAdapterClient::RequestHandler handler) {
   adapter_.set_handler(std::move(handler));
 }
 
-zx_status_t RunnerImpl::BindCoverageDataProvider(zx::channel provider) {
+zx_status_t RealmFuzzerRunner::BindCoverageDataProvider(zx::channel provider) {
   return provider_.Bind(std::move(provider));
 }
 
-void RunnerImpl::AddDefaults(Options* options) {
+void RealmFuzzerRunner::AddDefaults(Options* options) {
   Corpus::AddDefaults(options);
   Mutagen::AddDefaults(options);
   ProcessProxy::AddDefaults(options);
@@ -72,7 +72,7 @@
   }
 }
 
-ZxPromise<> RunnerImpl::Configure(const OptionsPtr& options) {
+ZxPromise<> RealmFuzzerRunner::Configure(const OptionsPtr& options) {
   return fpromise::make_promise([this, options]() -> ZxResult<> {
            options_ = options;
            seed_corpus_->Configure(options_);
@@ -94,7 +94,7 @@
       .wrap_with(workflow_);
 }
 
-zx_status_t RunnerImpl::AddToCorpus(CorpusType corpus_type, Input input) {
+zx_status_t RealmFuzzerRunner::AddToCorpus(CorpusType corpus_type, Input input) {
   switch (corpus_type) {
     case CorpusType::SEED:
       return seed_corpus_->Add(std::move(input));
@@ -105,7 +105,7 @@
   }
 }
 
-Input RunnerImpl::ReadFromCorpus(CorpusType corpus_type, size_t offset) {
+Input RealmFuzzerRunner::ReadFromCorpus(CorpusType corpus_type, size_t offset) {
   Input input;
   switch (corpus_type) {
     case CorpusType::SEED:
@@ -120,7 +120,7 @@
   return input;
 }
 
-zx_status_t RunnerImpl::ParseDictionary(const Input& input) {
+zx_status_t RealmFuzzerRunner::ParseDictionary(const Input& input) {
   Dictionary dict;
   dict.Configure(options_);
   if (!dict.Parse(input)) {
@@ -130,12 +130,12 @@
   return ZX_OK;
 }
 
-Input RunnerImpl::GetDictionaryAsInput() const { return mutagen_.dictionary().AsInput(); }
+Input RealmFuzzerRunner::GetDictionaryAsInput() const { return mutagen_.dictionary().AsInput(); }
 
 ///////////////////////////////////////////////////////////////
 // Asynchronous workflows.
 
-ZxPromise<FuzzResult> RunnerImpl::Execute(Input input) {
+ZxPromise<FuzzResult> RealmFuzzerRunner::Execute(Input input) {
   return TestOneAsync(std::move(input), kNoPostProcessing)
       .and_then([](const Artifact& artifact) -> ZxResult<FuzzResult> {
         return fpromise::ok(artifact.fuzz_result());
@@ -149,7 +149,7 @@
       .wrap_with(workflow_);
 }
 
-ZxPromise<Input> RunnerImpl::Minimize(Input input) {
+ZxPromise<Input> RealmFuzzerRunner::Minimize(Input input) {
   auto corpus = live_corpus_;
   auto options = CopyOptions(*options_);
   // Check that the input can be minimized, and that minimizationis bounded.
@@ -230,7 +230,7 @@
       .wrap_with(workflow_);
 }
 
-ZxPromise<Input> RunnerImpl::Cleanse(Input input) {
+ZxPromise<Input> RealmFuzzerRunner::Cleanse(Input input) {
   // The general approach of this loop is to take tested inputs and their fuzzing results and return
   // them to |GenerateCleanInputs| as |Artifacts|.
   return fpromise::make_promise([this, generate = Future<>(),
@@ -294,11 +294,11 @@
       .wrap_with(workflow_);
 }
 
-ZxPromise<Artifact> RunnerImpl::Fuzz() {
+ZxPromise<Artifact> RealmFuzzerRunner::Fuzz() {
   return FuzzInputs(/* backlog= */ options_->mutation_depth()).wrap_with(workflow_);
 }
 
-ZxPromise<> RunnerImpl::Merge() {
+ZxPromise<> RealmFuzzerRunner::Merge() {
   // First, accumulate the coverage from testing all the elements of the seed corpus.
   auto collect_errors = std::make_shared<std::vector<Input>>();
   return TestOneAsync(Input(), kAccumulateCoverage)
@@ -358,12 +358,12 @@
       .wrap_with(workflow_);
 }
 
-ZxPromise<> RunnerImpl::Stop() {
+ZxPromise<> RealmFuzzerRunner::Stop() {
   stopped_ = true;
   return workflow_.Stop();
 }
 
-Status RunnerImpl::CollectStatus() {
+Status RealmFuzzerRunner::CollectStatus() {
   Status status;
   status.set_running(!stopped_);
   status.set_runs(run_);
@@ -401,7 +401,7 @@
 ///////////////////////////////////////////////////////////////
 // Workflow-related methods.
 
-void RunnerImpl::StartWorkflow(Scope& scope) {
+void RealmFuzzerRunner::StartWorkflow(Scope& scope) {
   Reset();
   run_ = 0;
   pool_->Clear();
@@ -440,7 +440,7 @@
   UpdateMonitors(UpdateReason::INIT);
 }
 
-void RunnerImpl::FinishWorkflow() {
+void RealmFuzzerRunner::FinishWorkflow() {
   generated_.Clear();
   processed_.Clear();
   stopped_ = true;
@@ -450,7 +450,7 @@
 ///////////////////////////////////////////////////////////////
 // Methods to generate fuzzing inputs.
 
-ZxPromise<> RunnerImpl::GenerateInputs(size_t num_inputs, size_t backlog) {
+ZxPromise<> RealmFuzzerRunner::GenerateInputs(size_t num_inputs, size_t backlog) {
   // Set up parameters for determining what inputs to generate and for how long.
   auto max_size = options_->max_input_size();
   auto max_time = zx::duration(options_->max_total_time());
@@ -519,8 +519,8 @@
       });
 }
 
-Promise<> RunnerImpl::GenerateCleanInputs(const Input& input,
-                                          std::shared_ptr<AsyncDeque<Artifact>> recycler) {
+Promise<> RealmFuzzerRunner::GenerateCleanInputs(const Input& input,
+                                                 std::shared_ptr<AsyncDeque<Artifact>> recycler) {
   // To set up initial conditions, simulate having just completed an "extra" attempt.
   constexpr size_t kMaxCleanseAttempts = 5;
   auto attempts_left = kMaxCleanseAttempts + 1;
@@ -605,7 +605,7 @@
 ///////////////////////////////////////////////////////////////
 // Methods to perform a sequence of fuzzing runs.
 
-ZxPromise<Artifact> RunnerImpl::FuzzInputs(size_t backlog) {
+ZxPromise<Artifact> RealmFuzzerRunner::FuzzInputs(size_t backlog) {
   auto num_inputs = options_->runs();
   if (num_inputs != 0) {
     // Adjust for fixed inputs tested first. Be careful not to double count the empty input.
@@ -643,7 +643,7 @@
       });
 }
 
-ZxPromise<Artifact> RunnerImpl::TestOneAsync(Input input, PostProcessing mode) {
+ZxPromise<Artifact> RealmFuzzerRunner::TestOneAsync(Input input, PostProcessing mode) {
   return fpromise::make_promise([this, input = std::move(input)]() mutable -> ZxResult<> {
            return AsZxResult(generated_.Send(std::move(input)));
          })
@@ -654,8 +654,8 @@
       .and_then([this, mode] { return TestInputs(mode); });
 }
 
-ZxPromise<Artifact> RunnerImpl::TestCorpusAsync(CorpusPtr corpus, PostProcessing mode,
-                                                InputsPtr collect_errors) {
+ZxPromise<Artifact> RealmFuzzerRunner::TestCorpusAsync(CorpusPtr corpus, PostProcessing mode,
+                                                       InputsPtr collect_errors) {
   return fpromise::make_promise([this]() -> ZxResult<> {
            // Prime the output queue.
            Reset();
@@ -698,7 +698,7 @@
       });
 }
 
-ZxPromise<Artifact> RunnerImpl::TestInputs(PostProcessing mode, InputsPtr collect_errors) {
+ZxPromise<Artifact> RealmFuzzerRunner::TestInputs(PostProcessing mode, InputsPtr collect_errors) {
   constexpr size_t kMaxLeakDetectionAttempts = 1000;
   auto leak_detections = options_->detect_leaks() ? kMaxLeakDetectionAttempts : 0;
   return fpromise::make_promise(
@@ -751,7 +751,7 @@
 ///////////////////////////////////////////////////////////////
 // Methods to perform individual steps of a single fuzzing run.
 
-ZxPromise<> RunnerImpl::CheckPrevious(zx_status_t status) {
+ZxPromise<> RealmFuzzerRunner::CheckPrevious(zx_status_t status) {
   return fpromise::make_promise([status]() -> ZxResult<> {
     if (status != ZX_ERR_STOP) {
       return fpromise::error(status);
@@ -760,7 +760,7 @@
   });
 }
 
-ZxPromise<Input> RunnerImpl::Prepare(bool detect_leaks) {
+ZxPromise<Input> RealmFuzzerRunner::Prepare(bool detect_leaks) {
   return fpromise::make_promise([this, detect_leaks]() {
            // Send start signals.
            std::vector<ZxPromise<>> starts;
@@ -799,7 +799,7 @@
       });
 }
 
-Promise<bool, FuzzResult> RunnerImpl::RunOne(const Input& input) {
+Promise<bool, FuzzResult> RealmFuzzerRunner::RunOne(const Input& input) {
   return fpromise::make_promise([this, &input, run_limit = options_->run_limit(),
                                  timeout = Future<>(),
                                  first = true](Context& context) mutable -> Result<bool, uint64_t> {
@@ -851,7 +851,7 @@
       .or_else([this](const uint64_t& target_id) { return GetFuzzResult(target_id); });
 }
 
-void RunnerImpl::ConnectProcess(InstrumentedProcess& instrumented) {
+void RealmFuzzerRunner::ConnectProcess(InstrumentedProcess& instrumented) {
   auto process_proxy = std::make_unique<ProcessProxy>(executor(), pool_);
   process_proxy->Configure(options_);
   if (auto status = process_proxy->Connect(instrumented); status != ZX_OK) {
@@ -865,7 +865,7 @@
   suspended_.resume_task();
 }
 
-void RunnerImpl::AddLlvmModule(zx::vmo& inline_8bit_counters) {
+void RealmFuzzerRunner::AddLlvmModule(zx::vmo& inline_8bit_counters) {
   auto target_id = GetTargetId(inline_8bit_counters);
   auto iter = process_proxies_.find(target_id);
   if (iter == process_proxies_.end()) {
@@ -879,7 +879,7 @@
   }
 }
 
-Promise<bool, FuzzResult> RunnerImpl::GetFuzzResult(uint64_t target_id) {
+Promise<bool, FuzzResult> RealmFuzzerRunner::GetFuzzResult(uint64_t target_id) {
   return fpromise::make_promise(
              [this, target_id, process_proxy = std::unique_ptr<ProcessProxy>(),
               result = ZxFuture<FuzzResult>()](Context& context) mutable -> ZxResult<FuzzResult> {
@@ -930,7 +930,7 @@
       });
 }
 
-void RunnerImpl::Analyze(Input& input, PostProcessing mode) {
+void RealmFuzzerRunner::Analyze(Input& input, PostProcessing mode) {
   bool updated = false;
   switch (mode) {
     case kNoPostProcessing: {
@@ -968,7 +968,8 @@
   }
 }
 
-bool RunnerImpl::Recycle(Input&& input, size_t& attempts_left, bool suspected, bool detecting) {
+bool RealmFuzzerRunner::Recycle(Input&& input, size_t& attempts_left, bool suspected,
+                                bool detecting) {
   // Determine if leak detection is needed and thereby where to send the input. Leak detection is
   // expensive, so the strategy is as follows:
   // 1. Try inputs once without leak detection.
@@ -1006,12 +1007,12 @@
 ///////////////////////////////////////////////////////////////
 // Clean-up methods.
 
-void RunnerImpl::Disconnect() {
+void RealmFuzzerRunner::Disconnect() {
   adapter_.Disconnect();
   process_proxies_.clear();
 }
 
-void RunnerImpl::Reset() {
+void RealmFuzzerRunner::Reset() {
   generated_.Clear();
   processed_.Clear();
   generated_.Reset();
diff --git a/src/sys/fuzzing/framework/engine/runner.h b/src/sys/fuzzing/realmfuzzer/engine/runner.h
similarity index 92%
rename from src/sys/fuzzing/framework/engine/runner.h
rename to src/sys/fuzzing/realmfuzzer/engine/runner.h
index 35f8833..0001c47 100644
--- a/src/sys/fuzzing/framework/engine/runner.h
+++ b/src/sys/fuzzing/realmfuzzer/engine/runner.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_ENGINE_RUNNER_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_ENGINE_RUNNER_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_ENGINE_RUNNER_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_ENGINE_RUNNER_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <lib/fidl/cpp/interface_request.h>
@@ -19,19 +19,19 @@
 #include "src/sys/fuzzing/common/async-types.h"
 #include "src/sys/fuzzing/common/input.h"
 #include "src/sys/fuzzing/common/runner.h"
-#include "src/sys/fuzzing/framework/engine/adapter-client.h"
-#include "src/sys/fuzzing/framework/engine/corpus.h"
-#include "src/sys/fuzzing/framework/engine/coverage-data-provider-client.h"
-#include "src/sys/fuzzing/framework/engine/module-pool.h"
-#include "src/sys/fuzzing/framework/engine/mutagen.h"
-#include "src/sys/fuzzing/framework/engine/process-proxy.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/adapter-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/corpus.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data-provider-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-pool.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/mutagen.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/process-proxy.h"
 
 namespace fuzzing {
 
-// The concrete implementation of |Runner|.
-class RunnerImpl final : public Runner {
+// The concrete implementation of |Runner| for the realmfuzzer engine.
+class RealmFuzzerRunner final : public Runner {
  public:
-  ~RunnerImpl() override = default;
+  ~RealmFuzzerRunner() override = default;
 
   // Factory method.
   static RunnerPtr MakePtr(ExecutorPtr executor);
@@ -88,7 +88,7 @@
     kAccumulateCoverageAndKeepInputs,
   };
 
-  explicit RunnerImpl(ExecutorPtr executor);
+  explicit RealmFuzzerRunner(ExecutorPtr executor);
 
   // Returns a promise to generate |num_inputs| inputs for testing by taking them from the
   // |processed| queue, mutating corpus elements, and sending them to the |generated| queue. If
@@ -228,9 +228,9 @@
 
   Workflow workflow_;
 
-  FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(RunnerImpl);
+  FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(RealmFuzzerRunner);
 };
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_ENGINE_RUNNER_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_ENGINE_RUNNER_H_
diff --git a/src/sys/fuzzing/framework/meta/fatal-unittests.cml b/src/sys/fuzzing/realmfuzzer/meta/fatal-unittests.cml
similarity index 85%
rename from src/sys/fuzzing/framework/meta/fatal-unittests.cml
rename to src/sys/fuzzing/realmfuzzer/meta/fatal-unittests.cml
index 74feddb..5156a42 100644
--- a/src/sys/fuzzing/framework/meta/fatal-unittests.cml
+++ b/src/sys/fuzzing/realmfuzzer/meta/fatal-unittests.cml
@@ -8,7 +8,7 @@
         "syslog/client.shard.cml",
     ],
     program: {
-        binary: "test/component_fuzzing_framework_fatal_unittests",
+        binary: "test/realmfuzzer_fatal_unittests",
     },
     use: [
         { protocol: "fuchsia.process.Launcher" },
diff --git a/src/sys/fuzzing/framework/meta/unittests.cml b/src/sys/fuzzing/realmfuzzer/meta/unittests.cml
similarity index 88%
rename from src/sys/fuzzing/framework/meta/unittests.cml
rename to src/sys/fuzzing/realmfuzzer/meta/unittests.cml
index ded3bd1..e1a4b63 100644
--- a/src/sys/fuzzing/framework/meta/unittests.cml
+++ b/src/sys/fuzzing/realmfuzzer/meta/unittests.cml
@@ -9,7 +9,7 @@
         "syslog/client.shard.cml",
     ],
     program: {
-        binary: "test/component_fuzzing_framework_unittests",
+        binary: "test/realmfuzzer_unittests",
         args: [ "data/corpus" ],
     },
     use: [
diff --git a/src/sys/fuzzing/framework/target/BUILD.gn b/src/sys/fuzzing/realmfuzzer/target/BUILD.gn
similarity index 100%
rename from src/sys/fuzzing/framework/target/BUILD.gn
rename to src/sys/fuzzing/realmfuzzer/target/BUILD.gn
diff --git a/src/sys/fuzzing/framework/target/default.shard.cml b/src/sys/fuzzing/realmfuzzer/target/default.shard.cml
similarity index 100%
rename from src/sys/fuzzing/framework/target/default.shard.cml
rename to src/sys/fuzzing/realmfuzzer/target/default.shard.cml
diff --git a/src/sys/fuzzing/framework/target/instrumented-process.cc b/src/sys/fuzzing/realmfuzzer/target/instrumented-process.cc
similarity index 98%
rename from src/sys/fuzzing/framework/target/instrumented-process.cc
rename to src/sys/fuzzing/realmfuzzer/target/instrumented-process.cc
index 9e40050..694b658 100644
--- a/src/sys/fuzzing/framework/target/instrumented-process.cc
+++ b/src/sys/fuzzing/realmfuzzer/target/instrumented-process.cc
@@ -10,7 +10,7 @@
 
 #include "src/lib/fxl/macros.h"
 #include "src/sys/fuzzing/common/component-context.h"
-#include "src/sys/fuzzing/framework/target/process.h"
+#include "src/sys/fuzzing/realmfuzzer/target/process.h"
 
 namespace fuzzing {
 
diff --git a/src/sys/fuzzing/framework/target/main-wrapper.cc b/src/sys/fuzzing/realmfuzzer/target/main-wrapper.cc
similarity index 100%
rename from src/sys/fuzzing/framework/target/main-wrapper.cc
rename to src/sys/fuzzing/realmfuzzer/target/main-wrapper.cc
diff --git a/src/sys/fuzzing/framework/target/module-unittest.cc b/src/sys/fuzzing/realmfuzzer/target/module-unittest.cc
similarity index 86%
rename from src/sys/fuzzing/framework/target/module-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/target/module-unittest.cc
index 5853715..bd31aea 100644
--- a/src/sys/fuzzing/framework/target/module-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/target/module-unittest.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/target/module.h"
+#include "src/sys/fuzzing/realmfuzzer/target/module.h"
 
 #include <random>
 
 #include <gtest/gtest.h>
 
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
-#include "src/sys/fuzzing/framework/testing/module.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/module.h"
 
 namespace fuzzing {
 namespace {
@@ -19,10 +19,10 @@
 TEST(ModuleTest, Identifier) {
   // Prepare a fixed module.
   std::vector<ModulePC> pc_table1;
-  for (size_t i = 0; i < FakeFrameworkModule::kNumPCs; ++i) {
+  for (size_t i = 0; i < FakeRealmFuzzerModule::kNumPCs; ++i) {
     pc_table1.emplace_back(0x1000 + i * 0x10, (i % 8) == 0);
   }
-  FakeFrameworkModule module1(std::move(pc_table1));
+  FakeRealmFuzzerModule module1(std::move(pc_table1));
   Identifier legacy_expected = {0x942bcbf83d06e325ULL, 0x9e6b80d9266e0505ULL};
   // Compare with `echo $x | xxd -r -p | xxd -e -g8 | xxd -r | base64`, where $x is one of the hex
   // values above. The multiple `xxd` are needed to perform the byte swap for endianness.
@@ -33,10 +33,10 @@
   // Shifting all the PCs by a random basis does not affect the source ID, i.e., the ID is
   // independent of where it is mapped in memory.
   std::vector<ModulePC> pc_table2;
-  for (size_t i = 0; i < FakeFrameworkModule::kNumPCs; ++i) {
+  for (size_t i = 0; i < FakeRealmFuzzerModule::kNumPCs; ++i) {
     pc_table2.emplace_back(0xdeadbeef + i * 0x10, (i % 8) == 0);
   }
-  FakeFrameworkModule module2(std::move(pc_table2));
+  FakeRealmFuzzerModule module2(std::move(pc_table2));
   EXPECT_EQ(module1.id(), module2.id());
 
   // Changing the counters has no effect on identifiers.
@@ -46,7 +46,7 @@
   // Check for collisions. This isn't exhaustive; it is simply a smoke test to check if things are
   // very broken.
   for (uint32_t i = 0; i < 100; ++i) {
-    FakeFrameworkModule moduleN(/* seed */ i);
+    FakeRealmFuzzerModule moduleN(/* seed */ i);
     EXPECT_NE(moduleN.id(), expected);
   }
 
@@ -61,7 +61,7 @@
 }
 
 TEST(ModuleTest, UpdateAndClear) {
-  FakeFrameworkModule module;
+  FakeRealmFuzzerModule module;
   std::minstd_rand prng(1);
 
   // Initial contents are shared.
diff --git a/src/sys/fuzzing/framework/target/module.cc b/src/sys/fuzzing/realmfuzzer/target/module.cc
similarity index 97%
rename from src/sys/fuzzing/framework/target/module.cc
rename to src/sys/fuzzing/realmfuzzer/target/module.cc
index eb63573c..528c0b3 100644
--- a/src/sys/fuzzing/framework/target/module.cc
+++ b/src/sys/fuzzing/realmfuzzer/target/module.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/target/module.h"
+#include "src/sys/fuzzing/realmfuzzer/target/module.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <zircon/status.h>
diff --git a/src/sys/fuzzing/framework/target/module.h b/src/sys/fuzzing/realmfuzzer/target/module.h
similarity index 93%
rename from src/sys/fuzzing/framework/target/module.h
rename to src/sys/fuzzing/realmfuzzer/target/module.h
index 0e80c5b..54fe7d5 100644
--- a/src/sys/fuzzing/framework/target/module.h
+++ b/src/sys/fuzzing/realmfuzzer/target/module.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_TARGET_MODULE_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_TARGET_MODULE_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_TARGET_MODULE_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_TARGET_MODULE_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <lib/zx/eventpair.h>
@@ -64,4 +64,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_TARGET_MODULE_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_TARGET_MODULE_H_
diff --git a/src/sys/fuzzing/framework/target/process-unittest.cc b/src/sys/fuzzing/realmfuzzer/target/process-unittest.cc
similarity index 96%
rename from src/sys/fuzzing/framework/target/process-unittest.cc
rename to src/sys/fuzzing/realmfuzzer/target/process-unittest.cc
index e73b145..bbcff6b 100644
--- a/src/sys/fuzzing/framework/target/process-unittest.cc
+++ b/src/sys/fuzzing/realmfuzzer/target/process-unittest.cc
@@ -7,7 +7,7 @@
 // configurations (i.e. link against ASan or LSan) and more complex process lifecycle management. As
 // a result, this functionality is tested using integration rather than unit tests.
 
-#include "src/sys/fuzzing/framework/target/process.h"
+#include "src/sys/fuzzing/realmfuzzer/target/process.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -24,10 +24,10 @@
 #include "src/sys/fuzzing/common/async-eventpair.h"
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/testing/async-test.h"
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
-#include "src/sys/fuzzing/framework/engine/module-pool.h"
-#include "src/sys/fuzzing/framework/testing/coverage.h"
-#include "src/sys/fuzzing/framework/testing/module.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/module-pool.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/coverage.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/module.h"
 
 namespace fuzzing {
 
@@ -101,7 +101,7 @@
   // Creates a fake module for the current process, but defers adding its coverage. Returns the
   // unique module ID.
   std::string CreateModule() {
-    FakeFrameworkModule module(static_cast<uint32_t>(modules_.size() + 1));
+    FakeRealmFuzzerModule module(static_cast<uint32_t>(modules_.size() + 1));
     auto id = module.id();
     auto result = modules_.emplace(id, std::move(module));
     FX_CHECK(result.second);
@@ -119,7 +119,7 @@
   }
 
   // The returned pointer may be invalidated by calls to |AddModule|.
-  FakeFrameworkModule* GetModule(const std::string& id) {
+  FakeRealmFuzzerModule* GetModule(const std::string& id) {
     auto i = modules_.find(id);
     return i == modules_.end() ? nullptr : &i->second;
   }
@@ -172,7 +172,7 @@
   ModulePoolPtr pool_;
   CoverageDataProviderPtr provider_;
   uint64_t target_id_ = kInvalidTargetId;
-  std::unordered_map<std::string, FakeFrameworkModule> modules_;
+  std::unordered_map<std::string, FakeRealmFuzzerModule> modules_;
   std::vector<SharedMemory> added_;
   Completer<zx_signals_t> completer_;
   Scope scope_;
diff --git a/src/sys/fuzzing/framework/target/process.cc b/src/sys/fuzzing/realmfuzzer/target/process.cc
similarity index 97%
rename from src/sys/fuzzing/framework/target/process.cc
rename to src/sys/fuzzing/realmfuzzer/target/process.cc
index 77667e8e..0e31616 100644
--- a/src/sys/fuzzing/framework/target/process.cc
+++ b/src/sys/fuzzing/realmfuzzer/target/process.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/target/process.h"
+#include "src/sys/fuzzing/realmfuzzer/target/process.h"
 
 #include <lib/backtrace-request/backtrace-request.h>
 #include <lib/syslog/cpp/macros.h>
@@ -15,7 +15,7 @@
 
 #include "src/sys/fuzzing/common/module.h"
 #include "src/sys/fuzzing/common/options.h"
-#include "src/sys/fuzzing/framework/target/weak-symbols.h"
+#include "src/sys/fuzzing/realmfuzzer/target/weak-symbols.h"
 
 namespace fuzzing {
 namespace {
@@ -207,8 +207,8 @@
 void Process::OnDeath() { _Exit(options_.death_exitcode()); }
 
 void Process::OnExit() {
-  // Exits may not be fatal, e.g. if detect_exits=false. May sure the process publishes all its
-  // coverage before it ends as the framework will keep fuzzing.
+  // Exits may not be fatal, e.g. if detect_exits=false. Make sure the process publishes all its
+  // coverage before it ends as the engine will keep fuzzing.
   for (auto& module : modules_) {
     module.Update();
   }
@@ -522,13 +522,13 @@
 }
 
 bool Process::DetectLeak() {
-  // As described in the header, full leak detection is expensive. This framework imitates libFuzzer
+  // As described in the header, full leak detection is expensive. Realmfuzzer imitates libfuzzer
   // and performs a two-pass process:
   //   1a. Upon starting a fuzzing iteration,i.e. |OnSignal(kStart)|, it tracks |num_mallocs| and
   //       |num_frees|.
   //   1b. Upon finishing an iteration, i.e. |OnSignal(kFinish)|, it checks if |num_mallocs| equals
   //       |num_frees| and returns |kFinish| or |kFinishWithLeaks|, as appropriate.
-  //   2a. Returning |kFinishWithLeaks| will cause the framework to repeat the input with leak
+  //   2a. Returning |kFinishWithLeaks| will cause the engine to repeat the input with leak
   //       detection, i.e. |OnSignal(kStartLeakCheck)|. It will disable LSan for this run to avoid
   //       eventually reporting the same error twice.
   //   2b. Upon finishing the second iteration, i.e. |OnSignal(kFinish)| again, it re-enables LSan.
diff --git a/src/sys/fuzzing/framework/target/process.h b/src/sys/fuzzing/realmfuzzer/target/process.h
similarity index 96%
rename from src/sys/fuzzing/framework/target/process.h
rename to src/sys/fuzzing/realmfuzzer/target/process.h
index 48e5fd64..17858d7 100644
--- a/src/sys/fuzzing/framework/target/process.h
+++ b/src/sys/fuzzing/realmfuzzer/target/process.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_TARGET_PROCESS_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_TARGET_PROCESS_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_TARGET_PROCESS_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_TARGET_PROCESS_H_
 
 #include <fuchsia/debugdata/cpp/fidl.h>
 #include <fuchsia/fuzzer/cpp/fidl.h>
@@ -22,7 +22,7 @@
 #include "src/sys/fuzzing/common/async-types.h"
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/sancov.h"
-#include "src/sys/fuzzing/framework/target/module.h"
+#include "src/sys/fuzzing/realmfuzzer/target/module.h"
 
 namespace fuzzing {
 
@@ -177,4 +177,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_TARGET_PROCESS_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_TARGET_PROCESS_H_
diff --git a/src/sys/fuzzing/framework/target/weak-symbols.h b/src/sys/fuzzing/realmfuzzer/target/weak-symbols.h
similarity index 89%
rename from src/sys/fuzzing/framework/target/weak-symbols.h
rename to src/sys/fuzzing/realmfuzzer/target/weak-symbols.h
index 07f0fac..dbe6f66 100644
--- a/src/sys/fuzzing/framework/target/weak-symbols.h
+++ b/src/sys/fuzzing/realmfuzzer/target/weak-symbols.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_TARGET_WEAK_SYMBOLS_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_TARGET_WEAK_SYMBOLS_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_TARGET_WEAK_SYMBOLS_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_TARGET_WEAK_SYMBOLS_H_
 
 #include <stddef.h>
 
@@ -38,4 +38,4 @@
 
 #undef WEAK_EXPORT
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_TARGET_WEAK_SYMBOLS_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_TARGET_WEAK_SYMBOLS_H_
diff --git a/src/sys/fuzzing/framework/testing/BUILD.gn b/src/sys/fuzzing/realmfuzzer/testing/BUILD.gn
similarity index 87%
rename from src/sys/fuzzing/framework/testing/BUILD.gn
rename to src/sys/fuzzing/realmfuzzer/testing/BUILD.gn
index 6519aa4..2a84c59 100644
--- a/src/sys/fuzzing/framework/testing/BUILD.gn
+++ b/src/sys/fuzzing/realmfuzzer/testing/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//build/components/fuchsia_test_component.gni")
 
-# This source set contains various fakes used in framework unit tests.
+# This source set contains various fakes used in realmfuzzer unit tests.
 source_set("testing") {
   visibility = [ "../*" ]
   testonly = true
@@ -31,7 +31,7 @@
 
 # This executable is used for unit tests that manipulate processes.
 executable("test-target") {
-  output_name = "component_fuzzing_framework_test_target"
+  output_name = "realmfuzzer_test_target"
   visibility = [ "//src/sys/fuzzing/*" ]
   testonly = true
   sources = [ "target-main.cc" ]
@@ -45,7 +45,7 @@
 # The test engine is used to drive the target adapter with fixed inputs from the seed corpus. This
 # is used to create fuzzer tests that can be run as part of CQ.
 executable("engine-bin") {
-  output_name = "component_fuzzing_test_engine"
+  output_name = "realmfuzzer_test_engine"
   testonly = true
   sources = [ "engine.cc" ]
   deps = [
@@ -54,7 +54,7 @@
     "//src/lib/fxl/test:gtest_main",
     "//src/sys/fuzzing/common",
     "//src/sys/fuzzing/common/testing",
-    "//src/sys/fuzzing/framework/engine:adapter-client",
+    "//src/sys/fuzzing/realmfuzzer/engine:adapter-client",
     "//third_party/googletest:gtest",
   ]
 }
@@ -68,7 +68,7 @@
 # can handle a single watcher, and doesn't need |fuchsia.sys2.EventStream|, making it suitable for
 # use in integration tests.
 executable("coverage-bin") {
-  output_name = "component_fuzzing_test_coverage"
+  output_name = "realmfuzzer_test_coverage"
   testonly = true
   sources = [ "coverage-main.cc" ]
   deps = [
diff --git a/src/sys/fuzzing/framework/testing/adapter.cc b/src/sys/fuzzing/realmfuzzer/testing/adapter.cc
similarity index 97%
rename from src/sys/fuzzing/framework/testing/adapter.cc
rename to src/sys/fuzzing/realmfuzzer/testing/adapter.cc
index b895e2d..b38655f 100644
--- a/src/sys/fuzzing/framework/testing/adapter.cc
+++ b/src/sys/fuzzing/realmfuzzer/testing/adapter.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/testing/adapter.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/adapter.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <zircon/status.h>
diff --git a/src/sys/fuzzing/framework/testing/adapter.h b/src/sys/fuzzing/realmfuzzer/testing/adapter.h
similarity index 92%
rename from src/sys/fuzzing/framework/testing/adapter.h
rename to src/sys/fuzzing/realmfuzzer/testing/adapter.h
index 52fc5c0..1aae781 100644
--- a/src/sys/fuzzing/framework/testing/adapter.h
+++ b/src/sys/fuzzing/realmfuzzer/testing/adapter.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_TESTING_ADAPTER_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_TESTING_ADAPTER_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_TESTING_ADAPTER_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_TESTING_ADAPTER_H_
 
 #include <fuchsia/fuzzer/cpp/fidl.h>
 #include <fuchsia/mem/cpp/fidl.h>
@@ -69,4 +69,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_TESTING_ADAPTER_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_TESTING_ADAPTER_H_
diff --git a/src/sys/fuzzing/framework/testing/coverage-main.cc b/src/sys/fuzzing/realmfuzzer/testing/coverage-main.cc
similarity index 95%
rename from src/sys/fuzzing/framework/testing/coverage-main.cc
rename to src/sys/fuzzing/realmfuzzer/testing/coverage-main.cc
index 32a892c..44bf8c2 100644
--- a/src/sys/fuzzing/framework/testing/coverage-main.cc
+++ b/src/sys/fuzzing/realmfuzzer/testing/coverage-main.cc
@@ -6,7 +6,7 @@
 #include <zircon/status.h>
 
 #include "src/sys/fuzzing/common/component-context.h"
-#include "src/sys/fuzzing/framework/testing/coverage.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/coverage.h"
 
 namespace fuzzing {
 zx_status_t RunCoverage() {
diff --git a/src/sys/fuzzing/framework/testing/coverage.cc b/src/sys/fuzzing/realmfuzzer/testing/coverage.cc
similarity index 97%
rename from src/sys/fuzzing/framework/testing/coverage.cc
rename to src/sys/fuzzing/realmfuzzer/testing/coverage.cc
index 4660789..95d260b 100644
--- a/src/sys/fuzzing/framework/testing/coverage.cc
+++ b/src/sys/fuzzing/realmfuzzer/testing/coverage.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/testing/coverage.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/coverage.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <zircon/status.h>
diff --git a/src/sys/fuzzing/framework/testing/coverage.h b/src/sys/fuzzing/realmfuzzer/testing/coverage.h
similarity index 89%
rename from src/sys/fuzzing/framework/testing/coverage.h
rename to src/sys/fuzzing/realmfuzzer/testing/coverage.h
index 5c0556e..8fa01df 100644
--- a/src/sys/fuzzing/framework/testing/coverage.h
+++ b/src/sys/fuzzing/realmfuzzer/testing/coverage.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_TESTING_COVERAGE_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_TESTING_COVERAGE_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_TESTING_COVERAGE_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_TESTING_COVERAGE_H_
 
 #include <fuchsia/debugdata/cpp/fidl.h>
 #include <fuchsia/fuzzer/cpp/fidl.h>
@@ -18,7 +18,7 @@
 #include "src/sys/fuzzing/common/async-deque.h"
 #include "src/sys/fuzzing/common/async-types.h"
 #include "src/sys/fuzzing/common/options.h"
-#include "src/sys/fuzzing/framework/engine/coverage-data.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/coverage-data.h"
 
 namespace fuzzing {
 
@@ -61,4 +61,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_TESTING_COVERAGE_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_TESTING_COVERAGE_H_
diff --git a/src/sys/fuzzing/framework/testing/data/BUILD.gn b/src/sys/fuzzing/realmfuzzer/testing/data/BUILD.gn
similarity index 100%
rename from src/sys/fuzzing/framework/testing/data/BUILD.gn
rename to src/sys/fuzzing/realmfuzzer/testing/data/BUILD.gn
diff --git a/src/sys/fuzzing/framework/testing/data/input-1 b/src/sys/fuzzing/realmfuzzer/testing/data/input-1
similarity index 100%
rename from src/sys/fuzzing/framework/testing/data/input-1
rename to src/sys/fuzzing/realmfuzzer/testing/data/input-1
diff --git a/src/sys/fuzzing/framework/testing/data/input-2 b/src/sys/fuzzing/realmfuzzer/testing/data/input-2
similarity index 100%
rename from src/sys/fuzzing/framework/testing/data/input-2
rename to src/sys/fuzzing/realmfuzzer/testing/data/input-2
diff --git a/src/sys/fuzzing/framework/testing/engine.cc b/src/sys/fuzzing/realmfuzzer/testing/engine.cc
similarity index 95%
rename from src/sys/fuzzing/framework/testing/engine.cc
rename to src/sys/fuzzing/realmfuzzer/testing/engine.cc
index b803c73..1becc48 100644
--- a/src/sys/fuzzing/framework/testing/engine.cc
+++ b/src/sys/fuzzing/realmfuzzer/testing/engine.cc
@@ -12,8 +12,8 @@
 #include "src/sys/fuzzing/common/input.h"
 #include "src/sys/fuzzing/common/options.h"
 #include "src/sys/fuzzing/common/testing/async-test.h"
-#include "src/sys/fuzzing/framework/engine/adapter-client.h"
-#include "src/sys/fuzzing/framework/engine/corpus.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/adapter-client.h"
+#include "src/sys/fuzzing/realmfuzzer/engine/corpus.h"
 
 // These tests replaces the engine when building a fuzzer test instead of a fuzzer.
 
diff --git a/src/sys/fuzzing/framework/testing/meta/coverage.cml b/src/sys/fuzzing/realmfuzzer/testing/meta/coverage.cml
similarity index 91%
rename from src/sys/fuzzing/framework/testing/meta/coverage.cml
rename to src/sys/fuzzing/realmfuzzer/testing/meta/coverage.cml
index 9ece390..ff0aa2a 100644
--- a/src/sys/fuzzing/framework/testing/meta/coverage.cml
+++ b/src/sys/fuzzing/realmfuzzer/testing/meta/coverage.cml
@@ -5,7 +5,7 @@
     include: [ "syslog/client.shard.cml" ],
     program: {
         runner: "elf",
-        binary: "bin/component_fuzzing_test_coverage",
+        binary: "bin/realmfuzzer_test_coverage",
     },
     capabilities: [
         { protocol: "fuchsia.debugdata.Publisher" },
diff --git a/src/sys/fuzzing/framework/testing/meta/engine.cml b/src/sys/fuzzing/realmfuzzer/testing/meta/engine.cml
similarity index 74%
rename from src/sys/fuzzing/framework/testing/meta/engine.cml
rename to src/sys/fuzzing/realmfuzzer/testing/meta/engine.cml
index ff426d1..3150877 100644
--- a/src/sys/fuzzing/framework/testing/meta/engine.cml
+++ b/src/sys/fuzzing/realmfuzzer/testing/meta/engine.cml
@@ -5,10 +5,10 @@
 // This manifest corresponds to the "test" engine used in fuzzer tests.
 {
     include: [
-        "//src/sys/fuzzing/framework/engine/default.shard.cml",
+        "//src/sys/fuzzing/realmfuzzer/engine/default.shard.cml",
         "//src/sys/test_runners/gtest/default.shard.cml",
     ],
     program: {
-        binary: "bin/component_fuzzing_test_engine",
+        binary: "bin/realmfuzzer_test_engine",
     },
 }
diff --git a/src/sys/fuzzing/framework/testing/module.cc b/src/sys/fuzzing/realmfuzzer/testing/module.cc
similarity index 66%
rename from src/sys/fuzzing/framework/testing/module.cc
rename to src/sys/fuzzing/realmfuzzer/testing/module.cc
index dc5fd9cf..cabdc6c 100644
--- a/src/sys/fuzzing/framework/testing/module.cc
+++ b/src/sys/fuzzing/realmfuzzer/testing/module.cc
@@ -2,33 +2,33 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/testing/module.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/module.h"
 
 #include <lib/syslog/cpp/macros.h>
 #include <zircon/status.h>
 
 namespace fuzzing {
 
-FakeFrameworkModule::FakeFrameworkModule(uint32_t seed) : FakeModule(seed) {
+FakeRealmFuzzerModule::FakeRealmFuzzerModule(uint32_t seed) : FakeModule(seed) {
   module_ = std::make_unique<Module>();
   auto status = module_->Import(counters(), pcs(), num_pcs());
   FX_CHECK(status == ZX_OK) << zx_status_get_string(status);
 }
 
-FakeFrameworkModule::FakeFrameworkModule(std::vector<ModulePC>&& pc_table) noexcept
+FakeRealmFuzzerModule::FakeRealmFuzzerModule(std::vector<ModulePC>&& pc_table) noexcept
     : FakeModule(std::move(pc_table)) {
   module_ = std::make_unique<Module>();
   auto status = module_->Import(counters(), pcs(), num_pcs());
   FX_CHECK(status == ZX_OK) << zx_status_get_string(status);
 }
 
-FakeFrameworkModule& FakeFrameworkModule::operator=(FakeFrameworkModule&& other) noexcept {
+FakeRealmFuzzerModule& FakeRealmFuzzerModule::operator=(FakeRealmFuzzerModule&& other) noexcept {
   module_ = std::move(other.module_);
   FakeModule::operator=(std::move(other));
   return *this;
 }
 
-zx_status_t FakeFrameworkModule::Share(uint64_t target_id, zx::vmo* out) const {
+zx_status_t FakeRealmFuzzerModule::Share(uint64_t target_id, zx::vmo* out) const {
   return module_->Share(target_id, out);
 }
 
diff --git a/src/sys/fuzzing/framework/testing/module.h b/src/sys/fuzzing/realmfuzzer/testing/module.h
similarity index 60%
rename from src/sys/fuzzing/framework/testing/module.h
rename to src/sys/fuzzing/realmfuzzer/testing/module.h
index 60d0988..87df9d6 100644
--- a/src/sys/fuzzing/framework/testing/module.h
+++ b/src/sys/fuzzing/realmfuzzer/testing/module.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_TESTING_MODULE_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_TESTING_MODULE_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_TESTING_MODULE_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_TESTING_MODULE_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -13,23 +13,23 @@
 
 #include "src/lib/fxl/macros.h"
 #include "src/sys/fuzzing/common/testing/module.h"
-#include "src/sys/fuzzing/framework/target/module.h"
+#include "src/sys/fuzzing/realmfuzzer/target/module.h"
 
 namespace fuzzing {
 
 // Wraps a |Module| and automatically provides fake counters and PC tables based on a seed value.
-class FakeFrameworkModule final : public FakeModule {
+class FakeRealmFuzzerModule final : public FakeModule {
  public:
   // Make a fake module with randomized PCs.
-  explicit FakeFrameworkModule(uint32_t seed = 1);
+  explicit FakeRealmFuzzerModule(uint32_t seed = 1);
 
   // Make a fake module with the given PCs.
-  explicit FakeFrameworkModule(std::vector<ModulePC>&& pc_table) noexcept;
+  explicit FakeRealmFuzzerModule(std::vector<ModulePC>&& pc_table) noexcept;
 
-  FakeFrameworkModule(FakeFrameworkModule&& other) { *this = std::move(other); }
-  ~FakeFrameworkModule() override = default;
+  FakeRealmFuzzerModule(FakeRealmFuzzerModule&& other) { *this = std::move(other); }
+  ~FakeRealmFuzzerModule() override = default;
 
-  FakeFrameworkModule& operator=(FakeFrameworkModule&& other) noexcept;
+  FakeRealmFuzzerModule& operator=(FakeRealmFuzzerModule&& other) noexcept;
 
   const Module& module() const { return *module_; }
 
@@ -43,9 +43,9 @@
  private:
   std::unique_ptr<Module> module_;
 
-  FXL_DISALLOW_COPY_AND_ASSIGN(FakeFrameworkModule);
+  FXL_DISALLOW_COPY_AND_ASSIGN(FakeRealmFuzzerModule);
 };
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_TESTING_MODULE_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_TESTING_MODULE_H_
diff --git a/src/sys/fuzzing/framework/testing/target-main.cc b/src/sys/fuzzing/realmfuzzer/testing/target-main.cc
similarity index 100%
rename from src/sys/fuzzing/framework/testing/target-main.cc
rename to src/sys/fuzzing/realmfuzzer/testing/target-main.cc
diff --git a/src/sys/fuzzing/framework/testing/target.cc b/src/sys/fuzzing/realmfuzzer/testing/target.cc
similarity index 97%
rename from src/sys/fuzzing/framework/testing/target.cc
rename to src/sys/fuzzing/realmfuzzer/testing/target.cc
index 1f877b8..2800269 100644
--- a/src/sys/fuzzing/framework/testing/target.cc
+++ b/src/sys/fuzzing/realmfuzzer/testing/target.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/sys/fuzzing/framework/testing/target.h"
+#include "src/sys/fuzzing/realmfuzzer/testing/target.h"
 
 #include <lib/fdio/spawn.h>
 #include <lib/syslog/cpp/macros.h>
@@ -28,7 +28,7 @@
   FX_DCHECK(status == ZX_OK) << zx_status_get_string(status);
 
   // Spawn the new process in the new job.
-  const char* argv[2] = {"/pkg/bin/component_fuzzing_framework_test_target", nullptr};
+  const char* argv[2] = {"/pkg/bin/realmfuzzer_test_target", nullptr};
   fdio_spawn_action_t actions[] = {
       {
           .action = FDIO_SPAWN_ACTION_ADD_HANDLE,
diff --git a/src/sys/fuzzing/framework/testing/target.h b/src/sys/fuzzing/realmfuzzer/testing/target.h
similarity index 85%
rename from src/sys/fuzzing/framework/testing/target.h
rename to src/sys/fuzzing/realmfuzzer/testing/target.h
index 99c41b5..b21e06a 100644
--- a/src/sys/fuzzing/framework/testing/target.h
+++ b/src/sys/fuzzing/realmfuzzer/testing/target.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef SRC_SYS_FUZZING_FRAMEWORK_TESTING_TARGET_H_
-#define SRC_SYS_FUZZING_FRAMEWORK_TESTING_TARGET_H_
+#ifndef SRC_SYS_FUZZING_REALMFUZZER_TESTING_TARGET_H_
+#define SRC_SYS_FUZZING_REALMFUZZER_TESTING_TARGET_H_
 
 #include <lib/zx/channel.h>
 #include <lib/zx/process.h>
@@ -11,7 +11,7 @@
 
 #include "src/lib/fxl/macros.h"
 #include "src/sys/fuzzing/common/async-types.h"
-#include "src/sys/fuzzing/framework/target/process.h"
+#include "src/sys/fuzzing/realmfuzzer/target/process.h"
 
 namespace fuzzing {
 
@@ -51,4 +51,4 @@
 
 }  // namespace fuzzing
 
-#endif  // SRC_SYS_FUZZING_FRAMEWORK_TESTING_TARGET_H_
+#endif  // SRC_SYS_FUZZING_REALMFUZZER_TESTING_TARGET_H_
diff --git a/src/sys/fuzzing/framework/tests/BUILD.gn b/src/sys/fuzzing/realmfuzzer/tests/BUILD.gn
similarity index 74%
rename from src/sys/fuzzing/framework/tests/BUILD.gn
rename to src/sys/fuzzing/realmfuzzer/tests/BUILD.gn
index 77c4d03..efb5626 100644
--- a/src/sys/fuzzing/framework/tests/BUILD.gn
+++ b/src/sys/fuzzing/realmfuzzer/tests/BUILD.gn
@@ -19,12 +19,12 @@
 
 executable("fuzzer-bin") {
   testonly = true
-  output_name = "component_fuzzing_framework_test_fuzzer"
+  output_name = "realmfuzzer_test_fuzzer"
   sources = [ "fuzzer.cc" ]
   deps = [
     "//src/sys/fuzzing/common/testing:sanitizer",
-    "//src/sys/fuzzing/framework/adapters:llvm",
-    "//src/sys/fuzzing/framework/target",
+    "//src/sys/fuzzing/realmfuzzer/adapters:llvm",
+    "//src/sys/fuzzing/realmfuzzer/target",
   ]
   exclude_toolchain_tags = [ "instrumented" ]
 }
@@ -37,13 +37,13 @@
   }
   deps = [
     ":fuzzer-bin",
-    "//src/sys/fuzzing/framework/testing/data:corpus",
+    "//src/sys/fuzzing/realmfuzzer/testing/data:corpus",
   ]
 }
 
 test("integration-test-bin") {
-  output_name = "component_fuzzing_framework_tests"
-  sources = [ "framework-integration-test.cc" ]
+  output_name = "realmfuzzer_integration_tests"
+  sources = [ "integration-tests.cc" ]
   deps = [
     "//sdk/lib/fdio",
     "//sdk/lib/sys/cpp",
@@ -52,7 +52,7 @@
     "//src/sys/fuzzing/common",
     "//src/sys/fuzzing/common/testing",
     "//src/sys/fuzzing/fidl:fuchsia.fuzzer",
-    "//src/sys/fuzzing/framework/engine:engine-lib",
+    "//src/sys/fuzzing/realmfuzzer/engine:engine-lib",
     "//third_party/googletest:gtest",
   ]
 }
@@ -61,7 +61,7 @@
   manifest = "meta/engine.cml"
   deps = [
     ":integration-test-bin",
-    "//src/sys/fuzzing/framework/engine:engine-bin",
+    "//src/sys/fuzzing/realmfuzzer/engine:engine-bin",
   ]
 }
 
@@ -70,12 +70,12 @@
   deps = [
     ":engine",
     ":fuzzer",
-    "//src/sys/fuzzing/framework/testing:coverage",
+    "//src/sys/fuzzing/realmfuzzer/testing:coverage",
   ]
 }
 
 fuchsia_test_package("fuzzer-integration-tests-pkg") {
-  package_name = "component-fuzzer-integration-tests"
+  package_name = "realmfuzzer-integration-tests"
   test_components = [ ":fuzzer-integration-tests" ]
 }
 
@@ -84,7 +84,7 @@
 
 executable("fuzzer-uninstrumented-bin") {
   testonly = true
-  output_name = "component_fuzzing_framework_test_fuzzer_uninstrumented"
+  output_name = "realmfuzzer_test_fuzzer_uninstrumented"
   sources = [ "fuzzer.cc" ]
   deps = [ "../adapters:llvm" ]
   exclude_toolchain_tags = [ "instrumented" ]
@@ -92,9 +92,8 @@
 
 renamed_binary("fuzzer-uninstrumented-renamed") {
   testonly = true
-  dest = "bin/component_fuzzing_framework_test_fuzzer"
-  source =
-      "$root_out_dir/component_fuzzing_framework_test_fuzzer_uninstrumented"
+  dest = "bin/realmfuzzer_test_fuzzer"
+  source = "$root_out_dir/realmfuzzer_test_fuzzer_uninstrumented"
   source_deps = [ ":fuzzer-uninstrumented-bin" ]
 }
 
@@ -107,7 +106,7 @@
   }
   deps = [
     ":fuzzer-uninstrumented-renamed",
-    "//src/sys/fuzzing/framework/testing/data:corpus",
+    "//src/sys/fuzzing/realmfuzzer/testing/data:corpus",
   ]
 }
 
@@ -115,11 +114,11 @@
   manifest = "../testing/meta/engine.cml"
   deps = [
     ":fuzzer-uninstrumented",
-    "//src/sys/fuzzing/framework/testing:engine",
+    "//src/sys/fuzzing/realmfuzzer/testing:engine",
   ]
 }
 
 fuchsia_test_package("fuzzer-test-integration-tests-pkg") {
-  package_name = "component-fuzzer-test-integration-test"
+  package_name = "realmfuzzer-test-integration-test"
   test_components = [ ":fuzzer-test-integration-test" ]
 }
diff --git a/src/sys/fuzzing/framework/tests/fuzzer.cc b/src/sys/fuzzing/realmfuzzer/tests/fuzzer.cc
similarity index 100%
rename from src/sys/fuzzing/framework/tests/fuzzer.cc
rename to src/sys/fuzzing/realmfuzzer/tests/fuzzer.cc
diff --git a/src/sys/fuzzing/framework/tests/framework-integration-test.cc b/src/sys/fuzzing/realmfuzzer/tests/integration-tests.cc
similarity index 93%
rename from src/sys/fuzzing/framework/tests/framework-integration-test.cc
rename to src/sys/fuzzing/realmfuzzer/tests/integration-tests.cc
index 3edf9e6..c0f27f2 100644
--- a/src/sys/fuzzing/framework/tests/framework-integration-test.cc
+++ b/src/sys/fuzzing/realmfuzzer/tests/integration-tests.cc
@@ -25,13 +25,13 @@
 
 // Test fixtures.
 
-// The |FrameworkIntegrationTest| fakes the registrar but uses the real framework/engine.
+// The |RealmFuzzerTest| fakes the registrar but uses the real realmfuzzer engine.
 //
 // TODO(fxbug.dev/71912): This could be converted to use RealmBuilder, at which point specific tests
 // could provide individual components for the target adapter capability to be routed to. This would
 // facilitate writing tests for the engine under specific scenarios, analogous to libFuzzer's tests
 // under https://github.com/llvm/llvm-project/tree/main/compiler-rt/test/fuzzer.
-class FrameworkIntegrationTest : public AsyncTest {
+class RealmFuzzerTest : public AsyncTest {
  protected:
   void SetUp() override {
     AsyncTest::SetUp();
@@ -52,8 +52,7 @@
              }
              channels.emplace_back(registrar_handle.TakeChannel());
              channels.emplace_back(provider_handle.TakeChannel());
-             if (auto status =
-                     StartProcess("component_fuzzing_engine", std::move(channels), &engine_);
+             if (auto status = StartProcess("realmfuzzer_engine", std::move(channels), &engine_);
                  status != ZX_OK) {
                FX_LOGS(ERROR) << "Failed to start engine process: " << zx_status_get_string(status);
                return fpromise::error(status);
@@ -100,7 +99,7 @@
 
 // Integration tests.
 
-TEST_F(FrameworkIntegrationTest, Crash) {
+TEST_F(RealmFuzzerTest, Crash) {
   ControllerPtr controller;
   FUZZING_EXPECT_OK(Start(), &controller);
   RunUntilIdle();
diff --git a/src/sys/fuzzing/framework/tests/meta/engine.cml b/src/sys/fuzzing/realmfuzzer/tests/meta/engine.cml
similarity index 83%
rename from src/sys/fuzzing/framework/tests/meta/engine.cml
rename to src/sys/fuzzing/realmfuzzer/tests/meta/engine.cml
index 021c75b..6befd0e 100644
--- a/src/sys/fuzzing/framework/tests/meta/engine.cml
+++ b/src/sys/fuzzing/realmfuzzer/tests/meta/engine.cml
@@ -5,11 +5,11 @@
 // This manifest corresponds to the "real" engine used by the integration tests.
 {
     include: [
-        "//src/sys/fuzzing/framework/engine/default.shard.cml",
+        "//src/sys/fuzzing/realmfuzzer/engine/default.shard.cml",
         "//src/sys/test_runners/gtest/default.shard.cml",
     ],
     program: {
-        binary: "test/component_fuzzing_framework_tests",
+        binary: "test/realmfuzzer_integration_tests",
     },
     use: [
         { protocol: "fuchsia.fuzzer.CoverageDataProvider" },
diff --git a/src/sys/fuzzing/framework/tests/meta/fuzzer-coverage.cml b/src/sys/fuzzing/realmfuzzer/tests/meta/fuzzer-coverage.cml
similarity index 80%
rename from src/sys/fuzzing/framework/tests/meta/fuzzer-coverage.cml
rename to src/sys/fuzzing/realmfuzzer/tests/meta/fuzzer-coverage.cml
index 4be9fef..a879ab9 100644
--- a/src/sys/fuzzing/framework/tests/meta/fuzzer-coverage.cml
+++ b/src/sys/fuzzing/realmfuzzer/tests/meta/fuzzer-coverage.cml
@@ -7,10 +7,10 @@
 // configuration, //tools/cmc/build/cml.gni will add a `use` declaration for
 // `fuchsia.debugdata.Publisher`, so that declaration is omitted from this file.
 {
-    include: [ "//src/sys/fuzzing/framework/adapters/llvm.shard.cml" ],
+    include: [ "//src/sys/fuzzing/realmfuzzer/adapters/llvm.shard.cml" ],
     program: {
         runner: "elf",
-        binary: "bin/component_fuzzing_framework_test_fuzzer",
+        binary: "bin/realmfuzzer_test_fuzzer",
         args: [ "data/corpus" ],
     },
 }
diff --git a/src/sys/fuzzing/framework/tests/meta/fuzzer.cml b/src/sys/fuzzing/realmfuzzer/tests/meta/fuzzer.cml
similarity index 74%
rename from src/sys/fuzzing/framework/tests/meta/fuzzer.cml
rename to src/sys/fuzzing/realmfuzzer/tests/meta/fuzzer.cml
index c58a11c..196d2a8 100644
--- a/src/sys/fuzzing/framework/tests/meta/fuzzer.cml
+++ b/src/sys/fuzzing/realmfuzzer/tests/meta/fuzzer.cml
@@ -4,10 +4,10 @@
 
 // This manifest corresponds to the fuzzer used by the integration tests.
 {
-    include: [ "//src/sys/fuzzing/framework/adapters/llvm.shard.cml" ],
+    include: [ "//src/sys/fuzzing/realmfuzzer/adapters/llvm.shard.cml" ],
     program: {
         runner: "elf",
-        binary: "bin/component_fuzzing_framework_test_fuzzer",
+        binary: "bin/realmfuzzer_test_fuzzer",
         args: [ "data/corpus" ],
     },
     use: [
diff --git a/src/sys/fuzzing/framework/tests/meta/integration-tests.cml b/src/sys/fuzzing/realmfuzzer/tests/meta/integration-tests.cml
similarity index 100%
rename from src/sys/fuzzing/framework/tests/meta/integration-tests.cml
rename to src/sys/fuzzing/realmfuzzer/tests/meta/integration-tests.cml
diff --git a/src/sys/fuzzing/registry/tests/integration-tests.cc b/src/sys/fuzzing/registry/tests/integration-tests.cc
index 4cde245e..935bbe6 100644
--- a/src/sys/fuzzing/registry/tests/integration-tests.cc
+++ b/src/sys/fuzzing/registry/tests/integration-tests.cc
@@ -44,7 +44,7 @@
     ASSERT_EQ(context_->Connect(handle.NewRequest()), ZX_OK);
     std::vector<zx::channel> channels;
     channels.emplace_back(handle.TakeChannel());
-    ASSERT_EQ(StartProcess("component_fuzzing_test_fuzzer", std::move(channels), &process_), ZX_OK);
+    ASSERT_EQ(StartProcess("fake_fuzzer_for_testing", std::move(channels), &process_), ZX_OK);
   }
 
   // Promises to connect the |controller| once a fuzzer is registered.
diff --git a/src/sys/lib/fidl-fuchsia-pkg-ext/src/lib.rs b/src/sys/lib/fidl-fuchsia-pkg-ext/src/lib.rs
index 9fc92e5..deb0f7d 100644
--- a/src/sys/lib/fidl-fuchsia-pkg-ext/src/lib.rs
+++ b/src/sys/lib/fidl-fuchsia-pkg-ext/src/lib.rs
@@ -6,7 +6,7 @@
 //! bindings.
 
 mod types;
-pub use crate::types::{BlobId, BlobInfo, CupData};
+pub use crate::types::{BlobId, BlobInfo, CupData, ResolutionContext};
 
 mod repo;
 pub use crate::repo::{
diff --git a/src/sys/lib/fidl-fuchsia-pkg-ext/src/types.rs b/src/sys/lib/fidl-fuchsia-pkg-ext/src/types.rs
index 8d35825..4af5955 100644
--- a/src/sys/lib/fidl-fuchsia-pkg-ext/src/types.rs
+++ b/src/sys/lib/fidl-fuchsia-pkg-ext/src/types.rs
@@ -121,6 +121,30 @@
     }
 }
 
+/// Convenience wrapper type for the autogenerated FIDL `ResolutionContext`.
+#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub struct ResolutionContext {
+    pub bytes: Vec<u8>,
+}
+
+impl ResolutionContext {
+    pub fn new(bytes: Vec<u8>) -> Self {
+        ResolutionContext { bytes }
+    }
+}
+
+impl From<fidl::ResolutionContext> for ResolutionContext {
+    fn from(context: fidl::ResolutionContext) -> Self {
+        ResolutionContext { bytes: context.bytes }
+    }
+}
+
+impl From<ResolutionContext> for fidl::ResolutionContext {
+    fn from(context: ResolutionContext) -> Self {
+        Self { bytes: context.bytes }
+    }
+}
+
 mod hex_serde {
     use {super::BLOB_ID_SIZE, hex::FromHex, serde::Deserialize};
 
diff --git a/src/sys/pkg/bin/pkg-resolver/src/eager_package_manager.rs b/src/sys/pkg/bin/pkg-resolver/src/eager_package_manager.rs
index 2f9b543..0703d28 100644
--- a/src/sys/pkg/bin/pkg-resolver/src/eager_package_manager.rs
+++ b/src/sys/pkg/bin/pkg-resolver/src/eager_package_manager.rs
@@ -9,7 +9,7 @@
     eager_package_config::pkg_resolver::{EagerPackageConfig, EagerPackageConfigs},
     fidl_fuchsia_io as fio,
     fidl_fuchsia_pkg::{self as fpkg, CupRequest, CupRequestStream, GetInfoError, WriteError},
-    fidl_fuchsia_pkg_ext::{cache, BlobInfo, CupData, CupMissingField},
+    fidl_fuchsia_pkg_ext::{cache, BlobInfo, CupData, CupMissingField, ResolutionContext},
     fidl_fuchsia_pkg_internal::{PersistentEagerPackage, PersistentEagerPackages},
     fuchsia_pkg::PackageDirectory,
     fuchsia_syslog::fx_log_err,
@@ -195,14 +195,14 @@
     async fn resolve_pinned(
         package_resolver: &T,
         url: PinnedAbsolutePackageUrl,
-    ) -> Result<PackageDirectory, ResolvePinnedError> {
+    ) -> Result<(PackageDirectory, ResolutionContext), ResolvePinnedError> {
         let expected_hash = url.hash();
-        let pkg_dir = package_resolver.resolve(url.into(), None).await?;
+        let (pkg_dir, resolution_context) = package_resolver.resolve(url.into(), None).await?;
         let hash = pkg_dir.merkle_root().await?;
         if hash != expected_hash {
             return Err(ResolvePinnedError::HashMismatch(hash));
         }
-        Ok(pkg_dir)
+        Ok((pkg_dir, resolution_context))
     }
 
     async fn resolve_pinned_from_cache(
@@ -279,7 +279,8 @@
         let package = packages
             .get_mut(pinned_url.as_unpinned())
             .ok_or_else(|| CupWriteError::UnknownURL(pinned_url.as_unpinned().clone()))?;
-        let pkg_dir = Self::resolve_pinned(&self.package_resolver, pinned_url).await?;
+        let (pkg_dir, _resolution_context) =
+            Self::resolve_pinned(&self.package_resolver, pinned_url).await?;
         package.package_directory = Some(pkg_dir);
 
         let cup_handler = StandardCupv2Handler::new(&package.public_keys);
@@ -461,7 +462,7 @@
             BlobInfoIteratorRequest, NeededBlobsRequest, PackageCacheMarker, PackageCacheRequest,
             PackageCacheRequestStream,
         },
-        fuchsia_async as fasync, fuchsia_zircon as zx,
+        fidl_fuchsia_pkg_ext as pkg, fuchsia_async as fasync, fuchsia_zircon as zx,
         omaha_client::{
             cup_ecdsa::{
                 test_support::{
@@ -484,7 +485,7 @@
         let pkg_dir = PackageDirectory::open_from_namespace().unwrap();
         MockResolver::new(move |_url| {
             let pkg_dir = pkg_dir.clone();
-            async move { Ok(pkg_dir) }
+            async move { Ok((pkg_dir, pkg::ResolutionContext::new(vec![]))) }
         })
     }
 
@@ -537,7 +538,7 @@
         let pkg_dir = PackageDirectory::from_proxy(proxy);
         let package_resolver = MockResolver::new(move |_url| {
             let pkg_dir = pkg_dir.clone();
-            async move { Ok(pkg_dir) }
+            async move { Ok((pkg_dir, pkg::ResolutionContext::new(vec![]))) }
         });
         (package_resolver, dir)
     }
diff --git a/src/sys/pkg/bin/pkg-resolver/src/resolver_service.rs b/src/sys/pkg/bin/pkg-resolver/src/resolver_service.rs
index ad0661f..eff1ec1f 100644
--- a/src/sys/pkg/bin/pkg-resolver/src/resolver_service.rs
+++ b/src/sys/pkg/bin/pkg-resolver/src/resolver_service.rs
@@ -21,8 +21,8 @@
     fidl::endpoints::ServerEnd,
     fidl_fuchsia_io as fio,
     fidl_fuchsia_pkg::{
-        FontResolverRequest, FontResolverRequestStream, PackageResolverRequest,
-        PackageResolverRequestStream,
+        self as fpkg, FontResolverRequest, FontResolverRequestStream, PackageResolverRequest,
+        PackageResolverRequestStream, ResolveError,
     },
     fidl_fuchsia_pkg_ext::{self as pkg, BlobId},
     fuchsia_cobalt::CobaltSender,
@@ -82,11 +82,13 @@
 /// repository if necessary and possible.
 #[async_trait]
 pub trait Resolver: std::fmt::Debug + Sync + Sized {
+    /// Resolves the given absolute package URL and returns the package
+    /// directory and a resolution context for resolving subpackages.
     async fn resolve(
         &self,
         url: AbsolutePackageUrl,
         eager_package_manager: Option<&AsyncRwLock<EagerPackageManager<Self>>>,
-    ) -> Result<PackageDirectory, pkg::ResolveError>;
+    ) -> Result<(PackageDirectory, pkg::ResolutionContext), pkg::ResolveError>;
 }
 
 // How the package directory was resolved.
@@ -125,7 +127,7 @@
         &self,
         pkg_url: AbsolutePackageUrl,
         eager_package_manager: Option<&AsyncRwLock<EagerPackageManager<Self>>>,
-    ) -> Result<PackageDirectory, pkg::ResolveError> {
+    ) -> Result<(PackageDirectory, pkg::ResolutionContext), pkg::ResolveError> {
         let trace_id = ftrace::Id::random();
         let guard = ftrace::async_enter!(
             trace_id, "app", "resolve",
@@ -156,7 +158,9 @@
                 },
             ),
         ]);
-        resolve_res.map(|pkg_with_source| pkg_with_source.into_package())
+        resolve_res.map(|pkg_with_source| {
+            (pkg_with_source.into_package(), pkg::ResolutionContext::new(vec![]))
+        })
     }
 }
 
@@ -357,7 +361,7 @@
     queue: work_queue::WorkSender<
         AbsolutePackageUrl,
         (),
-        Result<PackageDirectory, Arc<GetPackageError>>,
+        Result<(PackageDirectory, pkg::ResolutionContext), Arc<GetPackageError>>,
     >,
 }
 
@@ -366,7 +370,9 @@
     pub fn new<W, F>(callback: W) -> Self
     where
         W: Fn(AbsolutePackageUrl) -> F + Send + 'static,
-        F: Future<Output = Result<PackageDirectory, Arc<GetPackageError>>> + Send,
+        F: Future<
+                Output = Result<(PackageDirectory, pkg::ResolutionContext), Arc<GetPackageError>>,
+            > + Send,
     {
         let (package_fetch_queue, queue) =
             work_queue::work_queue(1, move |url, _: ()| callback(url));
@@ -382,7 +388,7 @@
         &self,
         url: AbsolutePackageUrl,
         _eager_package_manager: Option<&AsyncRwLock<EagerPackageManager<Self>>>,
-    ) -> Result<PackageDirectory, pkg::ResolveError> {
+    ) -> Result<(PackageDirectory, pkg::ResolutionContext), pkg::ResolveError> {
         let queued_fetch = self.queue.push(url, ());
         queued_fetch.await.expect("expected queue to be open").map_err(|e| e.to_resolve_error())
     }
@@ -440,6 +446,28 @@
                     Ok(())
                 }
 
+                PackageResolverRequest::ResolveWithContext {
+                    package_url,
+                    context,
+                    dir: _,
+                    responder,
+                } => {
+                    fx_log_err!(
+                        "ResolveWithContext is not currently implemented by the resolver_service.
+                         Could not resolve {} with context {:?}",
+                        package_url,
+                        context,
+                    );
+                    responder.send(&mut Err(ResolveError::Internal)).with_context(|| {
+                        format!(
+                            "sending fuchsia.pkg/PackageResolver.ResolveWithContext response
+                                 for {} with context {:?}",
+                            package_url, context
+                        )
+                    })?;
+                    Ok(())
+                }
+
                 PackageResolverRequest::GetHash { package_url, responder } => {
                     match get_hash(
                         &rewriter,
@@ -706,14 +734,16 @@
     url: String,
     dir_request: ServerEnd<fio::DirectoryMarker>,
     eager_package_manager: Option<&AsyncRwLock<EagerPackageManager<QueuedResolver>>>,
-) -> Result<(), pkg::ResolveError> {
+) -> Result<fpkg::ResolutionContext, pkg::ResolveError> {
     let pkg_url =
         AbsolutePackageUrl::parse(&url).map_err(|e| handle_bad_package_url_error(e, &url))?;
-    let pkg = package_resolver.resolve(pkg_url, eager_package_manager).await?;
-    pkg.reopen(dir_request).map_err(|e| {
+    let (pkg, resolution_context) =
+        package_resolver.resolve(pkg_url, eager_package_manager).await?;
+    let () = pkg.reopen(dir_request).map_err(|e| {
         fx_log_err!("failed to re-open directory for package url {}: {:#}", url, anyhow!(e));
         pkg::ResolveError::Internal
-    })
+    })?;
+    Ok(resolution_context.into())
 }
 
 /// Run a service that only resolves registered font packages.
@@ -738,7 +768,8 @@
             )
             .await;
 
-            let response_legacy = response.clone().map_err(|s| s.to_resolve_status());
+            let response_legacy =
+                response.clone().map(|_resolution_context| ()).map_err(|s| s.to_resolve_status());
             cobalt_sender.log_event_count(
                 metrics::RESOLVE_METRIC_ID,
                 (
@@ -769,7 +800,7 @@
     package_url: String,
     directory_request: ServerEnd<fio::DirectoryMarker>,
     mut cobalt_sender: CobaltSender,
-) -> Result<(), pkg::ResolveError> {
+) -> Result<fpkg::ResolutionContext, pkg::ResolveError> {
     let parsed_package_url = AbsolutePackageUrl::parse(&package_url)
         .map_err(|e| handle_bad_package_url_error(e, &package_url))?;
     let is_font_package = match &parsed_package_url {
@@ -787,7 +818,9 @@
         1,
     );
     if is_font_package {
-        resolve_and_reopen(&package_resolver, package_url, directory_request, None).await
+        let _resolution_context =
+            resolve_and_reopen(&package_resolver, package_url, directory_request, None).await?;
+        Ok(fpkg::ResolutionContext { bytes: vec![] })
     } else {
         fx_log_err!("font resolver asked to resolve non-font package: {}", package_url);
         Err(pkg::ResolveError::PackageNotFound)
@@ -805,7 +838,7 @@
 }
 
 fn resolve_result_to_resolve_duration_code<T>(
-    res: &Result<(), T>,
+    res: &Result<fpkg::ResolutionContext, T>,
 ) -> metrics::ResolveDurationMetricDimensionResult {
     match res {
         Ok(_) => metrics::ResolveDurationMetricDimensionResult::Success,
@@ -814,10 +847,10 @@
 }
 
 fn resolve_result_to_resolve_status_code(
-    result: &Result<(), pkg::ResolveError>,
+    result: &Result<fpkg::ResolutionContext, pkg::ResolveError>,
 ) -> metrics::ResolveStatusMetricDimensionResult {
     match *result {
-        Ok(()) => metrics::ResolveStatusMetricDimensionResult::Success,
+        Ok(_) => metrics::ResolveStatusMetricDimensionResult::Success,
         Err(pkg::ResolveError::Internal) => metrics::ResolveStatusMetricDimensionResult::Internal,
         Err(pkg::ResolveError::AccessDenied) => {
             metrics::ResolveStatusMetricDimensionResult::AccessDenied
diff --git a/src/sys/pkg/bin/pkgctl/src/main.rs b/src/sys/pkg/bin/pkgctl/src/main.rs
index 1bbdc57..78f7a86 100644
--- a/src/sys/pkg/bin/pkgctl/src/main.rs
+++ b/src/sys/pkg/bin/pkgctl/src/main.rs
@@ -15,8 +15,8 @@
     anyhow::{bail, format_err, Context as _},
     fidl_fuchsia_net_http::{self as http},
     fidl_fuchsia_pkg::{
-        PackageCacheMarker, PackageResolverAdminMarker, PackageResolverMarker, PackageUrl,
-        RepositoryManagerMarker, RepositoryManagerProxy,
+        self as fpkg, PackageCacheMarker, PackageResolverAdminMarker, PackageResolverMarker,
+        PackageUrl, RepositoryManagerMarker, RepositoryManagerProxy,
     },
     fidl_fuchsia_pkg_ext::{
         BlobId, RepositoryConfig, RepositoryConfigBuilder, RepositoryStorageType,
@@ -57,7 +57,7 @@
 
             let (dir, dir_server_end) = fidl::endpoints::create_proxy()?;
 
-            let () = resolver
+            let _: fpkg::ResolutionContext = resolver
                 .resolve(&pkg_url, dir_server_end)
                 .await?
                 .map_err(fidl_fuchsia_pkg_ext::ResolveError::from)
diff --git a/src/sys/pkg/bin/system-update-checker/src/check.rs b/src/sys/pkg/bin/system-update-checker/src/check.rs
index 74385c6..c502b2a 100644
--- a/src/sys/pkg/bin/system-update-checker/src/check.rs
+++ b/src/sys/pkg/bin/system-update-checker/src/check.rs
@@ -11,7 +11,7 @@
     fidl_fuchsia_paver::{
         Asset, BootManagerMarker, Configuration, DataSinkMarker, PaverMarker, PaverProxy,
     },
-    fidl_fuchsia_pkg::{PackageResolverMarker, PackageResolverProxyInterface},
+    fidl_fuchsia_pkg::{self as fpkg, PackageResolverMarker, PackageResolverProxyInterface},
     fidl_fuchsia_space as fidl_space,
     fuchsia_component::client::connect_to_protocol,
     fuchsia_hash::Hash,
@@ -188,7 +188,7 @@
     let update_package =
         channel_manager.get_target_channel_update_url().unwrap_or(UPDATE_PACKAGE_URL.to_owned());
     let fut = package_resolver.resolve(&update_package, dir_server_end);
-    let () = fut
+    let _: fpkg::ResolutionContext = fut
         .await
         .map_err(errors::UpdatePackage::ResolveFidl)?
         .map_err(|raw| errors::UpdatePackage::Resolve(raw.into()))?;
@@ -277,7 +277,8 @@
         fidl_fuchsia_io as fio,
         fidl_fuchsia_paver::Configuration,
         fidl_fuchsia_pkg::{
-            PackageResolverGetHashResult, PackageResolverResolveResult, PackageUrl,
+            PackageResolverGetHashResult, PackageResolverResolveResult,
+            PackageResolverResolveWithContextResult, PackageUrl,
         },
         fuchsia_async as fasync,
         futures::{future, TryFutureExt, TryStreamExt},
@@ -452,7 +453,18 @@
                 dir.into_channel(),
             )
             .unwrap();
-            future::ok(Ok(()))
+            future::ok(Ok(fpkg::ResolutionContext { bytes: vec![] }))
+        }
+
+        type ResolveWithContextResponseFut =
+            future::Ready<Result<PackageResolverResolveWithContextResult, fidl::Error>>;
+        fn resolve_with_context(
+            &self,
+            _package_url: &str,
+            _context: &mut fpkg::ResolutionContext,
+            _dir: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
+        ) -> Self::ResolveWithContextResponseFut {
+            panic!("resolve_with_context not implemented");
         }
 
         type GetHashResponseFut = future::Ready<Result<PackageResolverGetHashResult, fidl::Error>>;
@@ -562,6 +574,18 @@
             ) -> Self::ResolveResponseFut {
                 future::err(fidl::Error::Invalid)
             }
+
+            type ResolveWithContextResponseFut =
+                future::Ready<Result<PackageResolverResolveWithContextResult, fidl::Error>>;
+            fn resolve_with_context(
+                &self,
+                _package_url: &str,
+                _context: &mut fpkg::ResolutionContext,
+                _dir: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
+            ) -> Self::ResolveWithContextResponseFut {
+                future::err(fidl::Error::Invalid)
+            }
+
             type GetHashResponseFut =
                 future::Ready<Result<PackageResolverGetHashResult, fidl::Error>>;
             fn get_hash(&self, _package_url: &mut PackageUrl) -> Self::GetHashResponseFut {
@@ -631,8 +655,20 @@
                     dir.into_channel(),
                 )
                 .unwrap();
-                future::ok(Ok(()))
+                future::ok(Ok(fpkg::ResolutionContext { bytes: vec![] }))
             }
+
+            type ResolveWithContextResponseFut =
+                future::Ready<Result<PackageResolverResolveWithContextResult, fidl::Error>>;
+            fn resolve_with_context(
+                &self,
+                _package_url: &str,
+                _context: &mut fpkg::ResolutionContext,
+                _dir: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
+            ) -> Self::ResolveWithContextResponseFut {
+                panic!("resolve_with_context not implemented");
+            }
+
             type GetHashResponseFut =
                 future::Ready<Result<PackageResolverGetHashResult, fidl::Error>>;
             fn get_hash(&self, _package_url: &mut PackageUrl) -> Self::GetHashResponseFut {
@@ -679,6 +715,18 @@
             ) -> Self::ResolveResponseFut {
                 future::ok(Err(fidl_fuchsia_pkg::ResolveError::NoSpace))
             }
+
+            type ResolveWithContextResponseFut =
+                future::Ready<Result<PackageResolverResolveWithContextResult, fidl::Error>>;
+            fn resolve_with_context(
+                &self,
+                _package_url: &str,
+                _context: &mut fpkg::ResolutionContext,
+                _dir: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
+            ) -> Self::ResolveWithContextResponseFut {
+                panic!("resolve_with_context not implemented");
+            }
+
             type GetHashResponseFut =
                 future::Ready<Result<PackageResolverGetHashResult, fidl::Error>>;
             fn get_hash(&self, _package_url: &mut PackageUrl) -> Self::GetHashResponseFut {
@@ -725,6 +773,18 @@
             ) -> Self::ResolveResponseFut {
                 future::ok(Err(fidl_fuchsia_pkg::ResolveError::Internal))
             }
+
+            type ResolveWithContextResponseFut =
+                future::Ready<Result<PackageResolverResolveWithContextResult, fidl::Error>>;
+            fn resolve_with_context(
+                &self,
+                _package_url: &str,
+                _context: &mut fpkg::ResolutionContext,
+                _dir: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
+            ) -> Self::ResolveWithContextResponseFut {
+                panic!("resolve_with_context not implemented");
+            }
+
             type GetHashResponseFut =
                 future::Ready<Result<PackageResolverGetHashResult, fidl::Error>>;
             fn get_hash(&self, _package_url: &mut PackageUrl) -> Self::GetHashResponseFut {
@@ -763,8 +823,20 @@
                 _package_url: &str,
                 _dir: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
             ) -> Self::ResolveResponseFut {
-                future::ok(Ok(()))
+                future::ok(Ok(fpkg::ResolutionContext { bytes: vec![] }))
             }
+
+            type ResolveWithContextResponseFut =
+                future::Ready<Result<PackageResolverResolveWithContextResult, fidl::Error>>;
+            fn resolve_with_context(
+                &self,
+                _package_url: &str,
+                _context: &mut fpkg::ResolutionContext,
+                _dir: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
+            ) -> Self::ResolveWithContextResponseFut {
+                panic!("resolve_with_context not implemented");
+            }
+
             type GetHashResponseFut =
                 future::Ready<Result<PackageResolverGetHashResult, fidl::Error>>;
             fn get_hash(&self, _package_url: &mut PackageUrl) -> Self::GetHashResponseFut {
diff --git a/src/sys/pkg/bin/system-updater/src/update/resolver.rs b/src/sys/pkg/bin/system-updater/src/update/resolver.rs
index f51d3f2..f58f2c8 100644
--- a/src/sys/pkg/bin/system-updater/src/update/resolver.rs
+++ b/src/sys/pkg/bin/system-updater/src/update/resolver.rs
@@ -3,8 +3,11 @@
 // found in the LICENSE file.
 
 use {
-    fidl_fuchsia_io as fio, fidl_fuchsia_pkg::PackageResolverProxy,
-    fuchsia_url::AbsolutePackageUrl, futures::prelude::*, thiserror::Error,
+    fidl_fuchsia_io as fio,
+    fidl_fuchsia_pkg::{self as fpkg, PackageResolverProxy},
+    fuchsia_url::AbsolutePackageUrl,
+    futures::prelude::*,
+    thiserror::Error,
     update_package::UpdatePackage,
 };
 
@@ -56,7 +59,8 @@
     let res = pkg_resolver.resolve(&url.to_string(), dir_server_end);
     let res = res.await.map_err(|e| ResolveError::Fidl(e, url.clone()))?;
 
-    let () = res.map_err(|raw| ResolveError::Error(raw.into(), url.clone()))?;
+    let _: fpkg::ResolutionContext =
+        res.map_err(|raw| ResolveError::Error(raw.into(), url.clone()))?;
 
     Ok(dir)
 }
diff --git a/src/sys/pkg/lib/isolated-swd/src/resolver.rs b/src/sys/pkg/lib/isolated-swd/src/resolver.rs
index b63ce6e..082b4d0 100644
--- a/src/sys/pkg/lib/isolated-swd/src/resolver.rs
+++ b/src/sys/pkg/lib/isolated-swd/src/resolver.rs
@@ -7,7 +7,7 @@
     anyhow::{Context, Error},
     fidl_fuchsia_boot::{ArgumentsRequest, ArgumentsRequestStream},
     fidl_fuchsia_pkg::PackageCacheMarker,
-    fuchsia_async as fasync,
+    fidl_fuchsia_pkg_ext as pkg, fuchsia_async as fasync,
     fuchsia_component::{
         client::{App, AppBuilder},
         server::{NestedEnvironment, ServiceFs, ServiceObj},
@@ -209,8 +209,12 @@
             Ok(ResolverForTest { cache, resolver: Arc::new(resolver), _served_repo: served_repo })
         }
 
-        /// Resolve a package using the resolver, returning the root directory of the package.
-        pub async fn resolve_package(&self, url: &str) -> Result<fio::DirectoryProxy, Error> {
+        /// Resolve a package using the resolver, returning the root directory of the package,
+        /// and the context for resolving relative package URLs.
+        pub async fn resolve_package(
+            &self,
+            url: &str,
+        ) -> Result<(fio::DirectoryProxy, pkg::ResolutionContext), Error> {
             let resolver = self
                 .resolver
                 ._pkg_resolver
@@ -218,12 +222,12 @@
                 .context("getting resolver")?;
             let (package, package_remote) =
                 fidl::endpoints::create_proxy().context("creating package directory endpoints")?;
-            let () = resolver
+            let resolved_context = resolver
                 .resolve(url, package_remote)
                 .await
                 .unwrap()
                 .map_err(|e| anyhow!("Package resolver error: {:?}", e))?;
-            Ok(package)
+            Ok((package, resolved_context.into()))
         }
     }
 }
@@ -259,7 +263,7 @@
         let resolver = ResolverForTest::new(repo, TEST_REPO_URL.parse().unwrap(), None)
             .await
             .context("launching resolver")?;
-        let root_dir =
+        let (root_dir, _resolved_context) =
             resolver.resolve_package(&format!("{}/{}", TEST_REPO_URL, name)).await.unwrap();
 
         package.verify_contents(&root_dir).await.unwrap();
@@ -291,7 +295,7 @@
         )
         .await
         .context("launching resolver")?;
-        let root_dir =
+        let (root_dir, _resolved_context) =
             resolver.resolve_package(&format!("fuchsia-pkg://fuchsia.com/{}", name)).await.unwrap();
 
         package.verify_contents(&root_dir).await.unwrap();
diff --git a/src/sys/pkg/testing/mock-resolver/src/lib.rs b/src/sys/pkg/testing/mock-resolver/src/lib.rs
index b050e3a..74062ace 100644
--- a/src/sys/pkg/testing/mock-resolver/src/lib.rs
+++ b/src/sys/pkg/testing/mock-resolver/src/lib.rs
@@ -7,7 +7,7 @@
     fidl::endpoints::{Proxy, ServerEnd},
     fidl_fuchsia_io as fio,
     fidl_fuchsia_pkg::{
-        PackageResolverMarker, PackageResolverProxy, PackageResolverRequestStream,
+        self as fpkg, PackageResolverMarker, PackageResolverProxy, PackageResolverRequestStream,
         PackageResolverResolveResponder,
     },
     fuchsia_async as fasync,
@@ -255,6 +255,12 @@
                     dir,
                     responder,
                 } => self.handle_resolve(package_url, dir, responder).await?,
+                fidl_fuchsia_pkg::PackageResolverRequest::ResolveWithContext {
+                    package_url: _,
+                    context: _,
+                    dir: _,
+                    responder: _,
+                } => panic!("ResolveWithContext not implemented"),
                 fidl_fuchsia_pkg::PackageResolverRequest::GetHash {
                     package_url: _,
                     responder: _,
@@ -281,7 +287,7 @@
         ) {
             Expectation::ImmediateConstant(Ok(package)) => {
                 package.serve_on(dir);
-                responder.send(&mut Ok(()))?;
+                responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] }))?;
             }
             Expectation::ImmediateConstant(Err(error)) => {
                 responder.send(&mut Err(*error))?;
@@ -297,7 +303,7 @@
                 match expected_results.remove(0) {
                     Ok(package) => {
                         package.serve_on(dir);
-                        responder.send(&mut Ok(()))?;
+                        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] }))?;
                     }
                     Err(e) => {
                         responder.send(&mut Err(e))?;
@@ -394,7 +400,7 @@
         let PendingResolve { responder, dir_request } = self.into_pending().await;
 
         pkg.serve_on(dir_request);
-        responder.send(&mut Ok(())).unwrap();
+        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] })).unwrap();
     }
 }
 
@@ -414,13 +420,14 @@
     fn do_resolve(
         proxy: &PackageResolverProxy,
         url: &str,
-    ) -> impl Future<Output = Result<fio::DirectoryProxy, ResolveError>> {
+    ) -> impl Future<Output = Result<(fio::DirectoryProxy, fpkg::ResolutionContext), ResolveError>>
+    {
         let (package_dir, package_dir_server_end) = fidl::endpoints::create_proxy().unwrap();
         let fut = proxy.resolve(url, package_dir_server_end);
 
         async move {
-            let () = fut.await.unwrap()?;
-            Ok(package_dir)
+            let resolve_context = fut.await.unwrap()?;
+            Ok((package_dir, resolve_context))
         }
     }
 
@@ -446,7 +453,7 @@
         // We should have no URLs resolved yet.
         assert_eq!(*resolved_urls.lock(), Vec::<String>::new());
 
-        let package_dir =
+        let (package_dir, _resolved_context) =
             do_resolve(&resolver_proxy, "fuchsia-pkg://fuchsia.com/update").await.unwrap();
 
         // Check that we can read from /meta (meta-as-file mode)
@@ -484,7 +491,7 @@
         let pkg = resolver.package("second", "fake merkle");
         handle_first.resolve(&pkg).await;
 
-        let first_pkg = first_fut.await.unwrap();
+        let (first_pkg, _resolved_context) = first_fut.await.unwrap();
         assert_eq!(read_file(&first_pkg, "meta").await, "fake merkle");
     }
 
@@ -505,7 +512,7 @@
         );
 
         // Second resolve should succeed and give us the expected package dir.
-        let package_dir =
+        let (package_dir, _resolved_context) =
             do_resolve(&resolver_proxy, "fuchsia-pkg://fuchsia.com/update").await.unwrap();
         let meta_contents = read_file(&package_dir, "meta").await;
         assert_eq!(meta_contents, "upd4t3");
diff --git a/src/sys/pkg/tests/pkg-resolver/src/base_pinning.rs b/src/sys/pkg/tests/pkg-resolver/src/base_pinning.rs
index 9d7bb15..983d650 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/base_pinning.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/base_pinning.rs
@@ -47,7 +47,7 @@
 
     env.register_repo_at_url(&served_repository, "fuchsia-pkg://fuchsia.com").await;
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{pkg_name}");
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     // Make sure we got the base version, not the repo version.
     base_pkg.verify_contents(&package_dir).await.unwrap();
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
@@ -112,7 +112,7 @@
 
     env.register_repo_at_url(&served_repository, "fuchsia-pkg://fuchsia.com").await;
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{pkg_name}/0");
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     // Make sure we got the static version, not the repo version.
     base_pkg.verify_contents(&package_dir).await.unwrap();
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
@@ -153,7 +153,7 @@
     // Merkle pin the request to the repo version.
     let pkg_url =
         format!("fuchsia-pkg://fuchsia.com/{pkg_name}?hash={}", repo_pkg.meta_far_merkle_root());
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
 
     // Make sure we got the repo (pinned) version, not the static version.
     repo_pkg.verify_contents(&package_dir).await.unwrap();
@@ -186,7 +186,7 @@
     served_repository.stop().await;
 
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{pkg_name}");
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     // Make sure we got the static version.
     base_pkg.verify_contents(&package_dir).await.unwrap();
 
@@ -209,7 +209,7 @@
         .await;
 
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{pkg_name}");
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     // Make sure we got the static version.
     base_pkg.verify_contents(&package_dir).await.unwrap();
 
@@ -256,13 +256,13 @@
     let resolves_fut =
         pkg_urls.into_iter().map(|url| Box::pin(env.resolve_package(&url))).collect::<Vec<_>>();
 
-    let (pkg_dir, i, _) = future::select_all(resolves_fut).await;
-
+    let (res, i, _) = future::select_all(resolves_fut).await;
     // Assert it's the base pinned package which got resolved.
     assert_eq!(i, 5);
 
     // Make sure we got the static version.
-    base_pkg.verify_contents(&pkg_dir.unwrap()).await.unwrap();
+    let (pkg_dir, _resolved_context) = res.unwrap();
+    base_pkg.verify_contents(&pkg_dir).await.unwrap();
 
     env.stop().await;
 }
diff --git a/src/sys/pkg/tests/pkg-resolver/src/eager_updates.rs b/src/sys/pkg/tests/pkg-resolver/src/eager_updates.rs
index 39beec2..d38a4a0 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/eager_updates.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/eager_updates.rs
@@ -88,7 +88,7 @@
 
     let () = env.proxies.repo_manager.add(repo_config.into()).await.unwrap().unwrap();
 
-    let package = env
+    let (package, _resolved_context) = env
         .resolve_package(format!("fuchsia-pkg://test/{}", package_name).as_str())
         .await
         .expect("package to resolve without error");
@@ -138,7 +138,7 @@
         .build()
         .await;
 
-    let package = env
+    let (package, _resolved_context) = env
         .resolve_package(format!("fuchsia-pkg://example.com/{}", pkg_name).as_str())
         .await
         .expect("package to resolve without error");
@@ -258,7 +258,8 @@
     assert_eq!(version, "1.2.3.4");
     assert_eq!(channel, "stable");
 
-    let package = env.resolve_package(&pkg_url.as_unpinned().to_string()).await.unwrap();
+    let (package, _resolved_context) =
+        env.resolve_package(&pkg_url.as_unpinned().to_string()).await.unwrap();
     // Verify the served package directory contains the exact expected contents.
     pkg.verify_contents(&package).await.unwrap();
 
diff --git a/src/sys/pkg/tests/pkg-resolver/src/lib.rs b/src/sys/pkg/tests/pkg-resolver/src/lib.rs
index 8374b20..f2d8b4a 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/lib.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/lib.rs
@@ -20,7 +20,7 @@
         RepositoryManagerMarker, RepositoryManagerProxy, WriteError,
     },
     fidl_fuchsia_pkg_ext::{
-        BlobId, CupData, RepositoryConfig, RepositoryConfigBuilder, RepositoryConfigs,
+        self as pkg, BlobId, CupData, RepositoryConfig, RepositoryConfigBuilder, RepositoryConfigs,
     },
     fidl_fuchsia_pkg_internal::{PersistentEagerPackage, PersistentEagerPackages},
     fidl_fuchsia_pkg_rewrite::{
@@ -950,7 +950,12 @@
     pub fn resolve_package(
         &self,
         url: &str,
-    ) -> impl Future<Output = Result<fio::DirectoryProxy, fidl_fuchsia_pkg::ResolveError>> {
+    ) -> impl Future<
+        Output = Result<
+            (fio::DirectoryProxy, pkg::ResolutionContext),
+            fidl_fuchsia_pkg::ResolveError,
+        >,
+    > {
         resolve_package(&self.proxies.resolver, url)
     }
 
@@ -1087,12 +1092,14 @@
 pub fn resolve_package(
     resolver: &PackageResolverProxy,
     url: &str,
-) -> impl Future<Output = Result<fio::DirectoryProxy, fidl_fuchsia_pkg::ResolveError>> {
+) -> impl Future<
+    Output = Result<(fio::DirectoryProxy, pkg::ResolutionContext), fidl_fuchsia_pkg::ResolveError>,
+> {
     let (package, package_server_end) = fidl::endpoints::create_proxy().unwrap();
     let response_fut = resolver.resolve(url, package_server_end);
     async move {
-        let () = response_fut.await.unwrap()?;
-        Ok(package)
+        let resolved_context = response_fut.await.unwrap()?;
+        Ok((package, resolved_context.into()))
     }
 }
 
diff --git a/src/sys/pkg/tests/pkg-resolver/src/persists_tuf_metadata.rs b/src/sys/pkg/tests/pkg-resolver/src/persists_tuf_metadata.rs
index 3028e72..55add94 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/persists_tuf_metadata.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/persists_tuf_metadata.rs
@@ -46,7 +46,7 @@
 
     // Resolve the package and ensure it's the cached version.
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", pkg_name);
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to resolve the cached version");
 
     // Put a copy of the package with altered contents in the repo to make sure
@@ -68,7 +68,7 @@
     let () = env.proxies.repo_manager.add(repo_config.into()).await.unwrap().unwrap();
 
     // Try to resolve again, make sure we see the new version.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     repo_pkg.verify_contents(&package_dir).await.expect("to resolve the new version");
     assert!(cache_pkg.verify_contents(&package_dir).await.is_err());
 
@@ -77,7 +77,7 @@
 
     // Try a final resolve. If the persisted repo config works, this must resolve the second
     // version of the package that we persisted from when the repo was live.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     repo_pkg.verify_contents(&package_dir).await.expect("to resolve the new version post-restart");
     assert!(cache_pkg.verify_contents(&package_dir).await.is_err());
 
@@ -109,7 +109,7 @@
 
     // Resolve the package and ensure it's the cached version.
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", pkg_name);
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to resolve the cached version");
 
     // Put a copy of the package with altered contents in the repo to make sure
@@ -132,7 +132,7 @@
 
     // Try to resolve again. We expect to resolve the cached version because the pkg-resolver
     // configuration does not allow us to instantiate a persisted repository.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to resolve the cached version again");
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
 
@@ -141,7 +141,7 @@
 
     // Try a final resolve. Because the config lists an empty string, this should result in
     // resolving to the cache_pkg.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to finally resolve the cached version");
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
 
@@ -172,7 +172,7 @@
 
     // Resolve the package and ensure it's the cached version.
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", pkg_name);
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to resolve the cached version");
 
     // Put a copy of the package with altered contents in the repo to make sure
@@ -203,7 +203,7 @@
     // Because dynamic repositories cannot be created in this pkg-resolver configuration, we were
     // unable to install the repository configuration to persist the repo, and we expect to resolve
     // the cached package.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to resolve the cached version again");
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
 
@@ -211,7 +211,7 @@
     env.restart_pkg_resolver().await;
 
     // Try a final resolve. This will again return the cached version.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to finally resolve the cached version");
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
 
@@ -239,7 +239,7 @@
 
     // Resolve the package and ensure it's the cached version.
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", pkg_name);
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to resolve the cached version");
 
     // Put a copy of the package with altered contents in the repo to make sure
@@ -262,7 +262,7 @@
 
     // Try to resolve again. We expect to resolve the cached version because the pkg-resolver
     // configuration does not allow us to instantiate a persisted repository.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to resolve the cached version again");
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
 
@@ -271,7 +271,7 @@
 
     // Try a final resolve. Because the config lists an empty string, this should result in
     // resolving to the cache_pkg.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     cache_pkg.verify_contents(&package_dir).await.expect("to finally resolve the cached version");
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
 
diff --git a/src/sys/pkg/tests/pkg-resolver/src/resolve_recovers_from_http_errors.rs b/src/sys/pkg/tests/pkg-resolver/src/resolve_recovers_from_http_errors.rs
index 66c8fd4..71bdc9c 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/resolve_recovers_from_http_errors.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/resolve_recovers_from_http_errors.rs
@@ -53,7 +53,8 @@
 
     // Disabling the custom responder allows the subsequent resolves to succeed.
     should_fail.unset();
-    let package_dir = env.resolve_package(&pkg_url).await.expect("package to resolve");
+    let (package_dir, _resolved_context) =
+        env.resolve_package(&pkg_url).await.expect("package to resolve");
     pkg.verify_contents(&package_dir).await.expect("correct package contents");
 
     env.stop().await;
diff --git a/src/sys/pkg/tests/pkg-resolver/src/resolve_resumes_blob_gets.rs b/src/sys/pkg/tests/pkg-resolver/src/resolve_resumes_blob_gets.rs
index cd6738d5b..d4dbdc7 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/resolve_resumes_blob_gets.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/resolve_resumes_blob_gets.rs
@@ -74,7 +74,8 @@
 
     let env = TestEnvBuilder::new().build().await;
     env.register_repo(&served_repository).await;
-    let package_dir = env.resolve_package(&pkg_url).await.expect("package to resolve");
+    let (package_dir, _resolved_context) =
+        env.resolve_package(&pkg_url).await.expect("package to resolve");
     pkg.verify_contents(&package_dir).await.expect("correct package contents");
 
     env.assert_count_events(
@@ -140,7 +141,8 @@
 
     let env = TestEnvBuilder::new().build().await;
     env.register_repo(&served_repository).await;
-    let package_dir = env.resolve_package(&pkg_url).await.expect("package to resolve");
+    let (package_dir, _resolved_context) =
+        env.resolve_package(&pkg_url).await.expect("package to resolve");
     pkg.verify_contents(&package_dir).await.expect("correct package contents");
 
     env.assert_count_events(
diff --git a/src/sys/pkg/tests/pkg-resolver/src/resolve_succeeds.rs b/src/sys/pkg/tests/pkg-resolver/src/resolve_succeeds.rs
index cc9e68a..d9285a5 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/resolve_succeeds.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/resolve_succeeds.rs
@@ -59,7 +59,7 @@
 
     let () = env.proxies.repo_manager.add(repo_config.into()).await.unwrap().unwrap();
 
-    let package = env
+    let (package, _resolved_context) = env
         .resolve_package(format!("fuchsia-pkg://test/{}", s).as_str())
         .await
         .expect("package to resolve without error");
@@ -116,7 +116,7 @@
     let () = env.proxies.repo_manager.add(repo_config.into()).await.unwrap().unwrap();
 
     // Verify package installation from the split repo succeeds.
-    let package = env
+    let (package, _resolved_context) = env
         .resolve_package(format!("fuchsia-pkg://test/{}", pkg_name).as_str())
         .await
         .expect("package to resolve without error");
@@ -156,7 +156,7 @@
     alter_env(&env, &pkg);
 
     let pkg_url = format!("fuchsia-pkg://test/{}", pkg.name());
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
 
     pkg.verify_contents(&package_dir).await.unwrap();
 
@@ -267,7 +267,8 @@
     let pkg1_url_with_pkg2_merkle =
         format!("fuchsia-pkg://test/pinned-merkle-foo?hash={}", pkg2.meta_far_merkle_root());
 
-    let package_dir = env.resolve_package(&pkg1_url_with_pkg2_merkle).await.unwrap();
+    let (package_dir, _resolved_context) =
+        env.resolve_package(&pkg1_url_with_pkg2_merkle).await.unwrap();
     pkg2.verify_contents(&package_dir).await.unwrap();
 
     env.stop().await;
@@ -295,7 +296,7 @@
 
     let pkg_url = &"fuchsia-pkg://test/variant-foo/0";
 
-    let package_dir = env.resolve_package(pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(pkg_url).await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
 
     env.stop().await;
@@ -368,7 +369,8 @@
         .start()
         .unwrap();
     env.register_repo(&served_repository).await;
-    let package_dir = env.resolve_package("fuchsia-pkg://test/try-hard").await.unwrap();
+    let (package_dir, _resolved_context) =
+        env.resolve_package("fuchsia-pkg://test/try-hard").await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
 
     let hierarchy = env.pkg_resolver_inspect_hierarchy().await;
@@ -437,9 +439,11 @@
     let pkg2_fut = resolve_package(&proxy2, "fuchsia-pkg://test/rate-limit-content");
 
     // The packages should resolve successfully.
-    let (pkg1_dir, pkg2_dir) = join!(pkg1_fut, pkg2_fut);
-    pkg1.verify_contents(&pkg1_dir.unwrap()).await.unwrap();
-    pkg2.verify_contents(&pkg2_dir.unwrap()).await.unwrap();
+    let (pkg1_res, pkg2_res) = join!(pkg1_fut, pkg2_fut);
+    let (pkg1_dir, _resolved_context) = pkg1_res.unwrap();
+    let (pkg2_dir, _resolved_context) = pkg2_res.unwrap();
+    pkg1.verify_contents(&pkg1_dir).await.unwrap();
+    pkg2.verify_contents(&pkg2_dir).await.unwrap();
 
     // And the inspect data for the package resolver should indicate that it handled 429 responses.
     let hierarchy = env.pkg_resolver_inspect_hierarchy().await;
@@ -507,12 +511,14 @@
 
     // package resolves as expected.
     fail_requests.unset();
-    let package_dir = env.resolve_package("fuchsia-pkg://test/resolve-twice").await.unwrap();
+    let (package_dir, _resolved_context) =
+        env.resolve_package("fuchsia-pkg://test/resolve-twice").await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
 
     // if no mirrors are accessible, the cached package is returned.
     fail_requests.set();
-    let package_dir = env.resolve_package("fuchsia-pkg://test/resolve-twice").await.unwrap();
+    let (package_dir, _resolved_context) =
+        env.resolve_package("fuchsia-pkg://test/resolve-twice").await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
 
     env.stop().await;
@@ -629,11 +635,11 @@
     send_shared_blob_body();
     let ((), ()) = futures::join!(
         async move {
-            let package1_dir = package1_resolution_fut.await.unwrap();
+            let (package1_dir, _resolved_context1) = package1_resolution_fut.await.unwrap();
             pkg1.verify_contents(&package1_dir).await.unwrap();
         },
         async move {
-            let package2_dir = package2_resolution_fut.await.unwrap();
+            let (package2_dir, _resolved_context2) = package2_resolution_fut.await.unwrap();
             pkg2.verify_contents(&package2_dir).await.unwrap();
         },
     );
@@ -726,8 +732,8 @@
         req.unblock();
     }
 
-    let pkg1_dir = pkg1_fut.await.expect("package 1 to resolve");
-    let pkg2_dir = pkg2_fut.await.expect("package 2 to resolve");
+    let (pkg1_dir, _resolved_context) = pkg1_fut.await.expect("package 1 to resolve");
+    let (pkg2_dir, _resolved_context) = pkg2_fut.await.expect("package 2 to resolve");
 
     pkg1.verify_contents(&pkg1_dir).await.unwrap();
     pkg2.verify_contents(&pkg2_dir).await.unwrap();
@@ -760,7 +766,7 @@
 
     env.register_repo(&served_repository).await;
 
-    let package = env
+    let (package, _resolved_context) = env
         .resolve_package(format!("fuchsia-pkg://test/{}", pkg_name).as_str())
         .await
         .expect("package to resolve without error");
@@ -864,7 +870,7 @@
         "fuchsia-pkg://test/merkle-pin-size?hash={}",
         pkg_16k_pinned.meta_far_merkle_root()
     );
-    let resolved_pkg =
+    let (resolved_pkg, _resolved_context) =
         env.resolve_package(&pinned_url).await.expect("package to resolve without error");
     pkg_16k_pinned.verify_contents(&resolved_pkg).await.unwrap();
 
@@ -897,7 +903,7 @@
     env.proxies.repo_manager.add(repo_config.into()).await.unwrap().unwrap();
 
     let pkg_url = format!("fuchsia-pkg://test/{}", pkg.name());
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
 
     pkg.verify_contents(&package_dir).await.unwrap();
     let mut repo_blobs = repo.list_blobs().unwrap();
diff --git a/src/sys/pkg/tests/pkg-resolver/src/resolve_succeeds_with_broken_minfs.rs b/src/sys/pkg/tests/pkg-resolver/src/resolve_succeeds_with_broken_minfs.rs
index 0f51bf8..3cfde59 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/resolve_succeeds_with_broken_minfs.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/resolve_succeeds_with_broken_minfs.rs
@@ -494,7 +494,8 @@
 
     // Verify we can resolve the package with a broken MinFs, and that repo configs do not persist
     let () = env.proxies.repo_manager.add(config.clone().into()).await.unwrap().unwrap();
-    let package_dir = env.resolve_package("fuchsia-pkg://example.com/just_meta_far").await.unwrap();
+    let (package_dir, _resolved_context) =
+        env.resolve_package("fuchsia-pkg://example.com/just_meta_far").await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
     assert_eq!(fail_count_fn(), num_failures_before_first_restart);
     env.restart_pkg_resolver().await;
@@ -506,7 +507,8 @@
     // the failure count doesn't change.
     make_succeed_fn();
     let () = env.proxies.repo_manager.add(config.clone().into()).await.unwrap().unwrap();
-    let package_dir = env.resolve_package("fuchsia-pkg://example.com/just_meta_far").await.unwrap();
+    let (package_dir, _resolved_context) =
+        env.resolve_package("fuchsia-pkg://example.com/just_meta_far").await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
     assert_eq!(fail_count_fn(), num_failures_after_first_restart);
     env.restart_pkg_resolver().await;
@@ -543,7 +545,7 @@
 
     // Verify we can resolve the package with a broken MinFs, and that rewrite rules do not
     // persist
-    let package_dir =
+    let (package_dir, _resolved_context) =
         env.resolve_package("fuchsia-pkg://should-be-rewritten/just_meta_far").await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
     assert_eq!(fail_count_fn(), num_failures_before_first_restart);
@@ -560,7 +562,7 @@
     env.proxies.rewrite_engine.start_edit_transaction(edit_transaction_server).unwrap();
     let () = edit_transaction.add(&mut rule.clone().into()).await.unwrap().unwrap();
     let () = edit_transaction.commit().await.unwrap().unwrap();
-    let package_dir =
+    let (package_dir, _resolved_context) =
         env.resolve_package("fuchsia-pkg://should-be-rewritten/just_meta_far").await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
     assert_eq!(fail_count_fn(), num_failures_after_first_restart);
diff --git a/src/sys/pkg/tests/pkg-resolver/src/system_cache_fallback.rs b/src/sys/pkg/tests/pkg-resolver/src/system_cache_fallback.rs
index c0fffeb..2851da4 100644
--- a/src/sys/pkg/tests/pkg-resolver/src/system_cache_fallback.rs
+++ b/src/sys/pkg/tests/pkg-resolver/src/system_cache_fallback.rs
@@ -59,7 +59,7 @@
     // System cache fallback is only triggered for fuchsia.com repos.
     env.register_repo_at_url(&served_repository, "fuchsia-pkg://fuchsia.com").await;
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", pkg_name);
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     // Make sure we got the cache version, not the repo version.
     cache_pkg.verify_contents(&package_dir).await.unwrap();
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
@@ -101,7 +101,7 @@
 
     let pkg_url =
         format!("fuchsia-pkg://fuchsia.com/{}?hash={}", pkg_name, pkg.meta_far_merkle_root());
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     pkg.verify_contents(&package_dir).await.unwrap();
 
     let hash = env.get_hash(pkg_url).await;
@@ -192,7 +192,7 @@
     // System cache fallback is only triggered for fuchsia.com repos.
     env.register_repo_at_url(&served_repository, "fuchsia-pkg://fuchsia.com").await;
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", pkg_name);
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     // Make sure we got the cache version, not the repo version.
     cache_pkg.verify_contents(&package_dir).await.unwrap();
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
@@ -242,7 +242,7 @@
     let () = edit_transaction.commit().await.unwrap().unwrap();
 
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", pkg_name);
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     // Make sure we got the cache version, not the repo version.
     cache_pkg.verify_contents(&package_dir).await.unwrap();
     assert!(repo_pkg.verify_contents(&package_dir).await.is_err());
@@ -433,7 +433,7 @@
     env.register_repo_at_url(&served_repository, "fuchsia-pkg://fuchsia.com").await;
 
     // Resolving and caching a small package should work fine.
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     small_pkg.verify_contents(&package_dir).await.unwrap();
 
     // Stop the running repository, fire up a new one with a very large package in it,
@@ -526,7 +526,7 @@
     env.register_repo_at_url(&served_repository, "fuchsia-pkg://fuchsia.com").await;
 
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", cache_pkg.name());
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
 
     // Make sure we got the cache version
     cache_pkg.verify_contents(&package_dir).await.unwrap();
@@ -597,7 +597,7 @@
     env.register_repo_at_url(&served_repository, "fuchsia-pkg://fuchsia.com").await;
 
     let pkg_url = format!("fuchsia-pkg://fuchsia.com/{}", pkg_name);
-    let package_dir = env.resolve_package(&pkg_url).await.unwrap();
+    let (package_dir, _resolved_context) = env.resolve_package(&pkg_url).await.unwrap();
     // Make sure we got the repo version, not the cache version.
     repo_pkg.verify_contents(&package_dir).await.unwrap();
     assert!(cache_pkg.verify_contents(&package_dir).await.is_err());
diff --git a/src/sys/pkg/tests/pkgctl/src/lib.rs b/src/sys/pkg/tests/pkgctl/src/lib.rs
index 1a76a11..360feb4 100644
--- a/src/sys/pkg/tests/pkgctl/src/lib.rs
+++ b/src/sys/pkg/tests/pkgctl/src/lib.rs
@@ -8,9 +8,9 @@
     fidl::endpoints::ServerEnd,
     fidl_fuchsia_io as fio,
     fidl_fuchsia_pkg::{
-        PackageCacheRequest, PackageCacheRequestStream, PackageResolverRequest,
+        self as fpkg, PackageCacheRequest, PackageCacheRequestStream, PackageResolverRequest,
         PackageResolverRequestStream, RepositoryIteratorRequest, RepositoryManagerRequest,
-        RepositoryManagerRequestStream,
+        RepositoryManagerRequestStream, ResolveError,
     },
     fidl_fuchsia_pkg_ext::{
         MirrorConfig, MirrorConfigBuilder, RepositoryConfig, RepositoryConfigBuilder,
@@ -364,8 +364,12 @@
 struct MockPackageResolverService {
     captured_args: Mutex<Vec<CapturedPackageResolverRequest>>,
     get_hash_response: Mutex<Option<Result<fidl_fuchsia_pkg::BlobId, Status>>>,
-    resolve_response:
-        Mutex<Option<(Arc<dyn DirectoryEntry>, Result<(), fidl_fuchsia_pkg::ResolveError>)>>,
+    resolve_response: Mutex<
+        Option<(
+            Arc<dyn DirectoryEntry>,
+            Result<fpkg::ResolutionContext, fidl_fuchsia_pkg::ResolveError>,
+        )>,
+    >,
 }
 
 impl MockPackageResolverService {
@@ -397,6 +401,15 @@
                     );
                     responder.send(&mut res).unwrap()
                 }
+                PackageResolverRequest::ResolveWithContext {
+                    package_url: _,
+                    context: _,
+                    dir: _,
+                    responder,
+                } => {
+                    // not implemented
+                    responder.send(&mut Err(ResolveError::Internal)).unwrap()
+                }
                 PackageResolverRequest::GetHash { package_url, responder } => {
                     self.captured_args.lock().push(CapturedPackageResolverRequest::GetHash {
                         package_url: package_url.url,
@@ -893,10 +906,10 @@
 #[fasync::run_singlethreaded(test)]
 async fn test_resolve() {
     let env = TestEnv::new();
-    env.package_resolver
-        .resolve_response
-        .lock()
-        .replace((vfs::pseudo_directory! { "meta" => vfs::pseudo_directory! {} }, Ok(())));
+    env.package_resolver.resolve_response.lock().replace((
+        vfs::pseudo_directory! { "meta" => vfs::pseudo_directory! {} },
+        Ok(fpkg::ResolutionContext { bytes: vec![] }),
+    ));
 
     let output = env.run_pkgctl(vec!["resolve", "the-url"]).await;
 
@@ -910,10 +923,10 @@
 #[fasync::run_singlethreaded(test)]
 async fn test_resolve_verbose() {
     let env = TestEnv::new();
-    env.package_resolver
-        .resolve_response
-        .lock()
-        .replace((vfs::pseudo_directory! { "meta" => vfs::pseudo_directory! {} }, Ok(())));
+    env.package_resolver.resolve_response.lock().replace((
+        vfs::pseudo_directory! { "meta" => vfs::pseudo_directory! {} },
+        Ok(fpkg::ResolutionContext { bytes: vec![] }),
+    ));
 
     let output = env.run_pkgctl(vec!["resolve", "the-url", "--verbose"]).await;
 
diff --git a/src/sys/sysmgr/integration_tests/mock_resolver.cc b/src/sys/sysmgr/integration_tests/mock_resolver.cc
index 9a063ca..4f6aabd 100644
--- a/src/sys/sysmgr/integration_tests/mock_resolver.cc
+++ b/src/sys/sysmgr/integration_tests/mock_resolver.cc
@@ -34,7 +34,15 @@
     callback(fuchsia::pkg::PackageResolver_Resolve_Result::WithResponse({}));
   }
 
-  virtual void GetHash(fuchsia::pkg::PackageUrl package_url, GetHashCallback callback) override {
+  void ResolveWithContext(::std::string package_uri, fuchsia::pkg::ResolutionContext context,
+                          ::fidl::InterfaceRequest<fuchsia::io::Directory> dir,
+                          ResolveWithContextCallback callback) override {
+    // Not implemented
+    callback(fuchsia::pkg::PackageResolver_ResolveWithContext_Result::WithErr(
+        {fuchsia::pkg::ResolveError::INTERNAL}));
+  }
+
+  void GetHash(fuchsia::pkg::PackageUrl package_url, GetHashCallback callback) override {
     callback(fuchsia::pkg::PackageResolver_GetHash_Result::WithErr(ZX_ERR_UNAVAILABLE));
   }
 
diff --git a/src/sys/sysmgr/integration_tests/package_updating_loader_test.cc b/src/sys/sysmgr/integration_tests/package_updating_loader_test.cc
index 8ab41e0..b717879 100644
--- a/src/sys/sysmgr/integration_tests/package_updating_loader_test.cc
+++ b/src/sys/sysmgr/integration_tests/package_updating_loader_test.cc
@@ -55,6 +55,14 @@
     }
   }
 
+  void ResolveWithContext(::std::string package_uri, fuchsia::pkg::ResolutionContext context,
+                          ::fidl::InterfaceRequest<fuchsia::io::Directory> dir,
+                          ResolveWithContextCallback callback) override {
+    // Not implemented
+    callback(fuchsia::pkg::PackageResolver_ResolveWithContext_Result::WithErr(
+        {fuchsia::pkg::ResolveError::INTERNAL}));
+  }
+
   virtual void GetHash(fuchsia::pkg::PackageUrl package_url, GetHashCallback callback) override {
     callback(fuchsia::pkg::PackageResolver_GetHash_Result::WithErr(ZX_ERR_UNAVAILABLE));
   }
diff --git a/src/sys/universe-resolver/src/main.rs b/src/sys/universe-resolver/src/main.rs
index 203e714..fd2598e 100644
--- a/src/sys/universe-resolver/src/main.rs
+++ b/src/sys/universe-resolver/src/main.rs
@@ -245,6 +245,9 @@
             // The proxy call returned (outer result Ok), but it returned an Err (inner result)
             return Ok(Err(err));
         }
+        // TODO(fxbug.dev/100060): When package resolver implements
+        // ResolveWithContext, remove the following call to `fabricate...`
+        // and use the above `result` (and its context) instead.
         let result = fabricate_package_context(package_url.repository(), package_dir)
             .await
             .map_err(|err: anyhow::Error| {
@@ -450,7 +453,7 @@
         fidl_fuchsia_component_config as fconfig, fidl_fuchsia_component_decl as fdecl,
         fidl_fuchsia_component_resolution::ResolverMarker,
         fidl_fuchsia_io as fio, fidl_fuchsia_mem as fmem,
-        fidl_fuchsia_pkg::{PackageResolverRequest, PackageResolverRequestStream},
+        fidl_fuchsia_pkg::{self as fpkg, PackageResolverRequest, PackageResolverRequestStream},
         fuchsia_async as fasync,
         fuchsia_component::server as fserver,
         fuchsia_component_test::{
@@ -631,7 +634,7 @@
                             Path::dot(),
                             ServerEnd::new(dir.into_channel()),
                         );
-                        responder.send(&mut Ok(())).unwrap();
+                        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] })).unwrap();
                     }
                     _ => panic!("unexpected API call"),
                 }
@@ -687,7 +690,7 @@
                             Path::dot(),
                             ServerEnd::new(dir.into_channel()),
                         );
-                        responder.send(&mut Ok(())).unwrap();
+                        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] })).unwrap();
                     }
                     _ => panic!("unexpected API call"),
                 }
@@ -737,7 +740,7 @@
                             Path::dot(),
                             ServerEnd::new(dir.into_channel()),
                         );
-                        responder.send(&mut Ok(())).unwrap();
+                        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] })).unwrap();
                     }
                     _ => panic!("unexpected API call"),
                 }
@@ -776,7 +779,7 @@
                             Path::dot(),
                             ServerEnd::new(dir.into_channel()),
                         );
-                        responder.send(&mut Ok(())).unwrap();
+                        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] })).unwrap();
                     }
                     _ => panic!("unexpected API call"),
                 }
@@ -850,7 +853,7 @@
                             Path::dot(),
                             ServerEnd::new(dir.into_channel()),
                         );
-                        responder.send(&mut Ok(())).unwrap();
+                        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] })).unwrap();
                     }
                     _ => panic!("unexpected API call"),
                 }
@@ -947,7 +950,7 @@
                             Path::dot(),
                             ServerEnd::new(dir.into_channel()),
                         );
-                        responder.send(&mut Ok(())).unwrap();
+                        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] })).unwrap();
                     }
                     _ => panic!("unexpected API call"),
                 }
@@ -985,7 +988,7 @@
                             Path::dot(),
                             ServerEnd::new(dir.into_channel()),
                         );
-                        responder.send(&mut Ok(())).unwrap();
+                        responder.send(&mut Ok(fpkg::ResolutionContext { bytes: vec![] })).unwrap();
                     }
                     _ => panic!("unexpected API call"),
                 }
diff --git a/src/testing/sl4f/BUILD.gn b/src/testing/sl4f/BUILD.gn
index 212ff2f..b6ae673 100644
--- a/src/testing/sl4f/BUILD.gn
+++ b/src/testing/sl4f/BUILD.gn
@@ -43,6 +43,7 @@
     "//sdk/fidl/fuchsia.lowpan.test:fuchsia.lowpan.test-rustc",
     "//sdk/fidl/fuchsia.math:fuchsia.math-rustc",
     "//sdk/fidl/fuchsia.media:fuchsia.media-rustc",
+    "//sdk/fidl/fuchsia.media.sounds:fuchsia.media.sounds-rustc",
     "//sdk/fidl/fuchsia.mem:fuchsia.mem-rustc",
     "//sdk/fidl/fuchsia.modular:fuchsia.modular-rustc",
     "//sdk/fidl/fuchsia.modular.internal:fuchsia.modular.internal-rustc",
diff --git a/src/testing/sl4f/meta/sl4f.cml b/src/testing/sl4f/meta/sl4f.cml
index 95e7cd2..d8d8bc7 100644
--- a/src/testing/sl4f/meta/sl4f.cml
+++ b/src/testing/sl4f/meta/sl4f.cml
@@ -61,6 +61,7 @@
                 "fuchsia.location.position.EmergencyProvider",
                 "fuchsia.lowpan.device.Lookup",
                 "fuchsia.media.ProfileProvider",
+                "fuchsia.media.sounds.Player",
                 "fuchsia.memorypressure.Provider",
                 "fuchsia.metricslogger.test.MetricsLogger",
                 "fuchsia.net.interfaces.State",
diff --git a/src/testing/sl4f/meta/sl4f.core_shard.cml b/src/testing/sl4f/meta/sl4f.core_shard.cml
index f630e91..e351181 100644
--- a/src/testing/sl4f/meta/sl4f.core_shard.cml
+++ b/src/testing/sl4f/meta/sl4f.core_shard.cml
@@ -128,6 +128,11 @@
             to: "#sl4f",
         },
         {
+            protocol: "fuchsia.media.sounds.Player",
+            from: "#soundplayer",
+            to: "#sl4f",
+        },
+        {
             protocol: "fuchsia.metricslogger.test.MetricsLogger",
             from: "#metrics-logger",
             to: "#sl4f",
diff --git a/src/testing/sl4f/src/audio/commands.rs b/src/testing/sl4f/src/audio/commands.rs
index 4162c0a..33bde70 100644
--- a/src/testing/sl4f/src/audio/commands.rs
+++ b/src/testing/sl4f/src/audio/commands.rs
@@ -7,9 +7,12 @@
 use anyhow::{Context, Error};
 use async_trait::async_trait;
 use base64;
+use fidl_fuchsia_media::{AudioRenderUsage, AudioSampleFormat, AudioStreamType};
+use fidl_fuchsia_media_sounds::{PlayerMarker, PlayerProxy};
 use fidl_fuchsia_test_audio_recording::{AudioRecordingControlMarker, AudioRecordingControlProxy};
 use fuchsia_component::client::connect_to_protocol;
 use fuchsia_syslog::macros::fx_log_info;
+use futures::lock::Mutex;
 use serde_json::{to_value, Value};
 use std::convert::TryInto;
 
@@ -23,6 +26,7 @@
             AudioMethod::StartOutputSave => self.start_output_save().await,
             AudioMethod::StopOutputSave => self.stop_output_save().await,
             AudioMethod::GetOutputAudio => self.get_output_audio().await,
+            AudioMethod::PlaySound => self.play_sine_wave().await,
         }
     }
 }
@@ -30,13 +34,18 @@
 #[derive(Debug)]
 pub struct AudioFacade {
     audio_proxy: AudioRecordingControlProxy,
+    player_proxy: PlayerProxy,
+    sound_buffer_id: Mutex<u32>,
 }
 
 impl AudioFacade {
     pub fn new() -> Result<AudioFacade, Error> {
         fx_log_info!("Launching audio_recording component");
         let audio_proxy = connect_to_protocol::<AudioRecordingControlMarker>()?;
-        Ok(AudioFacade { audio_proxy })
+        let player_proxy = connect_to_protocol::<PlayerMarker>()?;
+        let sound_buffer_id = Mutex::new(0u32);
+
+        Ok(AudioFacade { audio_proxy, player_proxy, sound_buffer_id })
     }
 
     pub async fn put_input_audio(&self, args: Value) -> Result<Value, Error> {
@@ -122,4 +131,60 @@
         result.read(&mut buffer, 0)?;
         Ok(to_value(base64::encode(&buffer))?)
     }
+
+    // This will play a 440Hz sine wave to the default sound device.
+    pub async fn play_sine_wave(&self) -> Result<Value, Error> {
+        let mut id = self.sound_buffer_id.lock().await;
+        *(id) += 1;
+        const FREQUENCY: f32 = 399.0;
+        const VOLUME: f32 = 0.1;
+        const DURATION: std::time::Duration = std::time::Duration::from_secs(1);
+        const FRAMES_PER_SECOND: u32 = 44100;
+
+        let (mut buffer, mut stream_type) =
+            self.sound_in_buffer(FREQUENCY, VOLUME, FRAMES_PER_SECOND, DURATION)?;
+
+        match self.player_proxy.add_sound_buffer(*id, &mut buffer, &mut stream_type) {
+            Ok(()) => (),
+            Err(e) => return Err(format_err!("Cannot add sound to buffer: {}", e)),
+        };
+        self.player_proxy
+            .play_sound(*id, AudioRenderUsage::Media)
+            .await?
+            .map_err(|err| format_err!("PlaySound failed: {:?}", err))?;
+        Ok(to_value(true)?)
+    }
+
+    fn sound_in_buffer(
+        &self,
+        frequency: f32,
+        volume: f32,
+        frames_per_second: u32,
+        duration: std::time::Duration,
+    ) -> Result<(fidl_fuchsia_mem::Buffer, AudioStreamType), Error> {
+        let frame_count = (frames_per_second as f32 * duration.as_secs_f32()) as usize;
+
+        let amplitude = volume * (std::i16::MAX as f32);
+        let frames_per_period = (frames_per_second as f32) / (frequency as f32);
+        let mut samples = std::vec::Vec::with_capacity(frame_count);
+        for i in 0..frame_count {
+            let sample_f = f32::sin((i as f32) / frames_per_period * 2.0 * std::f32::consts::PI);
+            samples.push((sample_f * amplitude) as i16);
+        }
+
+        // This is safe since `bytes` will cover the same memory range as `samples`.
+        let bytes =
+            unsafe { std::slice::from_raw_parts(samples.as_ptr() as *const _, samples.len() * 2) };
+        let vmo = fuchsia_zircon::Vmo::create((frame_count * 2) as u64).context("Creating VMO")?;
+        vmo.write(&bytes, 0).context("Writing to VMO")?;
+
+        Ok((
+            fidl_fuchsia_mem::Buffer { vmo: vmo, size: (frame_count * 2) as u64 },
+            AudioStreamType {
+                sample_format: AudioSampleFormat::Signed16,
+                channels: 1,
+                frames_per_second: frames_per_second,
+            },
+        ))
+    }
 }
diff --git a/src/testing/sl4f/src/audio/types.rs b/src/testing/sl4f/src/audio/types.rs
index 220138b..c9d0db8 100644
--- a/src/testing/sl4f/src/audio/types.rs
+++ b/src/testing/sl4f/src/audio/types.rs
@@ -11,6 +11,8 @@
     StartOutputSave,
     StopOutputSave,
     GetOutputAudio,
+
+    PlaySound,
 }
 
 impl std::str::FromStr for AudioMethod {
@@ -25,6 +27,7 @@
             "StartOutputSave" => Ok(AudioMethod::StartOutputSave),
             "StopOutputSave" => Ok(AudioMethod::StopOutputSave),
             "GetOutputAudio" => Ok(AudioMethod::GetOutputAudio),
+            "PlaySound" => Ok(AudioMethod::PlaySound),
             _ => return Err(format_err!("invalid Audio Facade method: {}", method)),
         }
     }
diff --git a/src/tests/fidl/server_suite/BUILD.gn b/src/tests/fidl/server_suite/BUILD.gn
new file mode 100644
index 0000000..2a35c82
--- /dev/null
+++ b/src/tests/fidl/server_suite/BUILD.gn
@@ -0,0 +1,14 @@
+# 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.
+
+group("server_suite") {
+  testonly = true
+  deps = [
+    "cpp",
+    "go",
+    "hlcpp",
+    "llcpp",
+    "rust",
+  ]
+}
diff --git a/src/tests/fidl/server_suite/README.md b/src/tests/fidl/server_suite/README.md
new file mode 100644
index 0000000..a6f5414a
--- /dev/null
+++ b/src/tests/fidl/server_suite/README.md
@@ -0,0 +1,36 @@
+# FIDL Server Test Suite
+
+The server test suite is a framework to test the implementation of servers in
+FIDL bindings, such as how they respond to incorrect ordinals, an unexpected
+channel closure, and other protocol level semantic aspects.
+
+Each test involves:
+- A test harness, which executes the client-side of the test and makes
+assertions.
+- A server - implemented in the binding under test, which implements a
+prescribed set of behaviors.
+
+This test suite uses three main FIDL protocols:
+- Runner - coordinates running the test, starting the test server etc.
+- Target - the protocol implemented by the server under test.
+- Reporter - reports actions to the test harness.
+
+These protocol definitions can be found in the
+[FIDL server suite](/src/test/fidl/server_suite/fidl/serversuite.test.fidl).
+
+The various test cases which leverage the framework are in
+[harness/tests.cc](src/tests/fidl/server_suite/harness/tests.cc).
+
+## Running the tests
+
+To run the server test suite
+
+    fx set core.x64 --with //bundles/fidl:tests
+
+Then
+
+    fx test fidl-server-suite-rust-test   (e.g. for rust)
+
+To run all bindings use
+
+   fx test //src/tests/fidl/server_suite
diff --git a/src/tests/fidl/server_suite/cpp/BUILD.gn b/src/tests/fidl/server_suite/cpp/BUILD.gn
new file mode 100644
index 0000000..cebc850
--- /dev/null
+++ b/src/tests/fidl/server_suite/cpp/BUILD.gn
@@ -0,0 +1,39 @@
+# 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")
+
+executable("bin") {
+  output_name = "server_suite_under_test_cpp"
+  sources = [ "main.cc" ]
+  deps = [
+    "//sdk/lib/sys/component/llcpp",
+    "//src/tests/fidl/server_suite/fidl:fidl.serversuite_cpp",
+    "//zircon/system/ulib/async-loop:async-loop-cpp",
+    "//zircon/system/ulib/async-loop:async-loop-default",
+  ]
+}
+
+fuchsia_component("cpp_server") {
+  component_name = "server"
+  manifest = "meta/server.cml"
+  deps = [ ":bin" ]
+}
+
+fuchsia_component("harness_cpp") {
+  testonly = true
+  component_name = "harness"
+  manifest = "meta/harness_cpp.cml"
+  deps = [ "//src/tests/fidl/server_suite/harness:bin" ]
+}
+
+fuchsia_test_package("fidl-server-suite-cpp-test") {
+  test_components = [ ":harness_cpp" ]
+  deps = [ ":cpp_server" ]
+}
+
+group("cpp") {
+  testonly = true
+  deps = [ ":fidl-server-suite-cpp-test" ]
+}
diff --git a/src/tests/fidl/server_suite/cpp/main.cc b/src/tests/fidl/server_suite/cpp/main.cc
new file mode 100644
index 0000000..83215d4
--- /dev/null
+++ b/src/tests/fidl/server_suite/cpp/main.cc
@@ -0,0 +1,71 @@
+// 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 <fidl/fidl.serversuite/cpp/fidl.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/async-loop/default.h>
+#include <lib/sys/component/llcpp/outgoing_directory.h>
+
+#include <iostream>
+
+class TargetServer : public fidl::Server<fidl_serversuite::Target> {
+ public:
+  explicit TargetServer(fidl::ClientEnd<fidl_serversuite::Reporter> reporter)
+      : reporter_(std::move(reporter)) {}
+
+  void OneWayNoPayload(OneWayNoPayloadRequest& request,
+                       OneWayNoPayloadCompleter::Sync& completer) override {
+    std::cout << "Target.OneWayNoPayload()" << std::endl;
+    auto result = reporter_->ReceivedOneWayNoPayload();
+    ZX_ASSERT(result.is_ok());
+  }
+
+ private:
+  fidl::SyncClient<fidl_serversuite::Reporter> reporter_;
+};
+
+class RunnerServer : public fidl::Server<fidl_serversuite::Runner> {
+ public:
+  explicit RunnerServer(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher) {}
+
+  void Start(StartRequest& request, StartCompleter::Sync& completer) override {
+    std::cout << "Runner.Start()" << std::endl;
+
+    target_server_ = std::make_unique<TargetServer>(std::move(request.reporter()));
+
+    auto endpoints = fidl::CreateEndpoints<fidl_serversuite::Target>();
+    fidl::BindServer(dispatcher_, std::move(endpoints->server), target_server_.get(),
+                     [](auto*, fidl::UnbindInfo info, auto) {
+                       if (!info.is_dispatcher_shutdown() && !info.is_user_initiated() &&
+                           !info.is_peer_closed()) {
+                         std::cout << "Target unbound with error: " << info.FormatDescription()
+                                   << std::endl;
+                       }
+                     });
+
+    completer.Reply(std::move(endpoints->client));
+  }
+
+  void CheckAlive(CheckAliveRequest& request, CheckAliveCompleter::Sync& completer) override {
+    completer.Reply();
+  }
+
+ private:
+  async_dispatcher_t* dispatcher_;
+  std::unique_ptr<TargetServer> target_server_;
+};
+
+int main(int argc, const char** argv) {
+  std::cout << "CPP server: main" << std::endl;
+  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
+
+  auto outgoing = component::OutgoingDirectory::Create(loop.dispatcher());
+  ZX_ASSERT(outgoing.ServeFromStartupInfo().is_ok());
+  RunnerServer runner_server(loop.dispatcher());
+  auto result = outgoing.AddProtocol<fidl_serversuite::Runner>(&runner_server);
+  ZX_ASSERT(result.is_ok());
+
+  std::cout << "CPP server: ready!" << std::endl;
+  return loop.Run();
+}
diff --git a/src/tests/fidl/server_suite/cpp/meta/harness_cpp.cml b/src/tests/fidl/server_suite/cpp/meta/harness_cpp.cml
new file mode 100644
index 0000000..00828bd
--- /dev/null
+++ b/src/tests/fidl/server_suite/cpp/meta/harness_cpp.cml
@@ -0,0 +1,34 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        // gtest runner
+        "//src/sys/test_runners/gtest/default.shard.cml",
+
+        // Enable system logging
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/server_suite_harness",
+    },
+    children: [
+        {
+            name: "cpp",
+            url: "#meta/server.cm",
+        },
+    ],
+    use: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "#cpp",
+        },
+    ],
+    offer: [
+        {
+            protocol: [ "fuchsia.logger.LogSink" ],
+            from: "parent",
+            to: "#cpp",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/cpp/meta/server.cml b/src/tests/fidl/server_suite/cpp/meta/server.cml
new file mode 100644
index 0000000..57dfa14
--- /dev/null
+++ b/src/tests/fidl/server_suite/cpp/meta/server.cml
@@ -0,0 +1,22 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "syslog/client.shard.cml",
+        "syslog/elf_stdio.shard.cml",
+    ],
+    program: {
+        runner: "elf",
+        binary: "bin/server_suite_under_test_cpp",
+    },
+    capabilities: [
+        { protocol: "fidl.serversuite.Runner" },
+    ],
+    expose: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "self",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/fidl/BUILD.gn b/src/tests/fidl/server_suite/fidl/BUILD.gn
new file mode 100644
index 0000000..5ce2c5f
--- /dev/null
+++ b/src/tests/fidl/server_suite/fidl/BUILD.gn
@@ -0,0 +1,10 @@
+# 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/fidl/fidl.gni")
+
+fidl("fidl.serversuite") {
+  sources = [ "serversuite.test.fidl" ]
+  public_deps = [ "//zircon/vdso/zx" ]
+}
diff --git a/src/tests/fidl/server_suite/fidl/serversuite.test.fidl b/src/tests/fidl/server_suite/fidl/serversuite.test.fidl
new file mode 100644
index 0000000..7a55f2b
--- /dev/null
+++ b/src/tests/fidl/server_suite/fidl/serversuite.test.fidl
@@ -0,0 +1,29 @@
+// 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.
+
+library fidl.serversuite;
+
+// The Runner coordinates test activity and is shared by multiple tests.
+@discoverable
+protocol Runner {
+    // Create a Target to run tests against.
+    Start(resource struct {
+        reporter client_end:Reporter;
+    }) -> (resource struct {
+        target client_end:Target;
+    });
+
+    // A two-way function to test that the Runner is still responding.
+    CheckAlive() -> ();
+};
+
+// The Target is the server under test.
+protocol Target {
+    OneWayNoPayload();
+};
+
+// The Reporter sends results of the test to the test harness.
+protocol Reporter {
+    ReceivedOneWayNoPayload();
+};
diff --git a/src/tests/fidl/server_suite/go/BUILD.gn b/src/tests/fidl/server_suite/go/BUILD.gn
new file mode 100644
index 0000000..de74d74
--- /dev/null
+++ b/src/tests/fidl/server_suite/go/BUILD.gn
@@ -0,0 +1,47 @@
+# 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("//build/go/go_binary.gni")
+import("//build/go/go_library.gni")
+import("//build/go/toolchain.gni")
+
+go_binary("bin") {
+  output_name = "server_suite_under_test_go"
+  gopackage = "server_suite_under_test_go"
+  deps = [ ":lib" ]
+}
+
+go_library("lib") {
+  name = "server_suite_under_test_go"
+  deps = [
+    "//sdk/fidl/fuchsia.sys($go_toolchain)",
+    "//src/lib/component",
+    "//src/tests/fidl/server_suite/fidl:fidl.serversuite($go_toolchain)",
+  ]
+  sources = [ "main.go" ]
+}
+
+fuchsia_component("go_server") {
+  component_name = "server"
+  manifest = "meta/server.cml"
+  deps = [ ":bin" ]
+}
+
+fuchsia_component("harness_go") {
+  testonly = true
+  component_name = "harness"
+  manifest = "meta/harness_go.cml"
+  deps = [ "//src/tests/fidl/server_suite/harness:bin" ]
+}
+
+fuchsia_test_package("fidl-server-suite-go-test") {
+  test_components = [ ":harness_go" ]
+  deps = [ ":go_server" ]
+}
+
+group("go") {
+  testonly = true
+  deps = [ ":fidl-server-suite-go-test" ]
+}
diff --git a/src/tests/fidl/server_suite/go/main.go b/src/tests/fidl/server_suite/go/main.go
new file mode 100644
index 0000000..947b050
--- /dev/null
+++ b/src/tests/fidl/server_suite/go/main.go
@@ -0,0 +1,87 @@
+// 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.
+
+//go:build !build_with_native_toolchain
+
+package main
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"syscall/zx"
+	"syscall/zx/fidl"
+
+	"go.fuchsia.dev/fuchsia/src/lib/component"
+
+	"fidl/fidl/serversuite"
+)
+
+type targetImpl struct {
+	reporter serversuite.ReporterWithCtxInterface
+}
+
+var _ serversuite.TargetWithCtx = (*targetImpl)(nil)
+
+func (t *targetImpl) OneWayNoPayload(_ fidl.Context) error {
+	log.Println("serversuite.Target OneWayNoPayload() called")
+	t.reporter.ReceivedOneWayNoPayload(context.Background())
+	return nil
+}
+
+type runnerImpl struct{}
+
+var _ serversuite.RunnerWithCtx = (*runnerImpl)(nil)
+
+func (*runnerImpl) Start(
+	_ fidl.Context,
+	reporter serversuite.ReporterWithCtxInterface) (serversuite.TargetWithCtxInterface, error) {
+
+	clientEnd, serverEnd, err := zx.NewChannel(0)
+	if err != nil {
+		return serversuite.TargetWithCtxInterface{}, err
+	}
+
+	go func() {
+		stub := serversuite.TargetWithCtxStub{
+			Impl: &targetImpl{
+				reporter: reporter,
+			},
+		}
+		component.Serve(context.Background(), &stub, serverEnd, component.ServeOptions{
+			OnError: func(err error) {
+				// Failures are expected as part of tests.
+				log.Printf("serversuite.Target errored: %s", err)
+			},
+		})
+	}()
+
+	return serversuite.TargetWithCtxInterface{Channel: clientEnd}, nil
+}
+
+func (*runnerImpl) CheckAlive(_ fidl.Context) error { return nil }
+
+func main() {
+	log.SetFlags(log.Lshortfile)
+
+	log.Println("Go serversuite server: starting")
+	ctx := component.NewContextFromStartupInfo()
+	ctx.OutgoingService.AddService(
+		serversuite.RunnerName,
+		func(ctx context.Context, c zx.Channel) error {
+			stub := serversuite.RunnerWithCtxStub{
+				Impl: &runnerImpl{},
+			}
+			go component.Serve(ctx, &stub, c, component.ServeOptions{
+				OnError: func(err error) {
+					// Panic because the test runner should never fail.
+					panic(fmt.Sprintf("serversuite.Runner errored: %s", err))
+				},
+			})
+			return nil
+		},
+	)
+	log.Println("Go serversuite server: ready")
+	ctx.BindStartupHandle(context.Background())
+}
diff --git a/src/tests/fidl/server_suite/go/meta/harness_go.cml b/src/tests/fidl/server_suite/go/meta/harness_go.cml
new file mode 100644
index 0000000..ff3b9d4
--- /dev/null
+++ b/src/tests/fidl/server_suite/go/meta/harness_go.cml
@@ -0,0 +1,34 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        // gtest runner
+        "//src/sys/test_runners/gtest/default.shard.cml",
+
+        // Enable system logging
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/server_suite_harness",
+    },
+    children: [
+        {
+            name: "go",
+            url: "#meta/server.cm",
+        },
+    ],
+    use: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "#go",
+        },
+    ],
+    offer: [
+        {
+            protocol: [ "fuchsia.logger.LogSink" ],
+            from: "parent",
+            to: "#go",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/go/meta/server.cml b/src/tests/fidl/server_suite/go/meta/server.cml
new file mode 100644
index 0000000..4b4d39c
--- /dev/null
+++ b/src/tests/fidl/server_suite/go/meta/server.cml
@@ -0,0 +1,22 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "syslog/client.shard.cml",
+        "syslog/elf_stdio.shard.cml",
+    ],
+    program: {
+        runner: "elf",
+        binary: "bin/server_suite_under_test_go",
+    },
+    capabilities: [
+        { protocol: "fidl.serversuite.Runner" },
+    ],
+    expose: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "self",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/harness/BUILD.gn b/src/tests/fidl/server_suite/harness/BUILD.gn
new file mode 100644
index 0000000..a7d372b
--- /dev/null
+++ b/src/tests/fidl/server_suite/harness/BUILD.gn
@@ -0,0 +1,29 @@
+# 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")
+
+executable("bin") {
+  testonly = true
+  output_name = "server_suite_harness"
+  sources = [
+    "harness.cc",
+    "harness.h",
+    "ordinals.h",
+    "tests.cc",
+  ]
+
+  deps = [
+    "//sdk/lib/fdio",
+    "//sdk/lib/fidl",
+    "//src/lib/fxl",
+    "//src/lib/fxl/test:gtest_main",
+    "//src/lib/testing/loop_fixture",
+    "//src/tests/fidl/server_suite/fidl:fidl.serversuite_cpp",
+    "//third_party/googletest:gtest",
+    "//zircon/system/ulib/async-loop:async-loop-cpp",
+    "//zircon/system/ulib/async-loop:async-loop-default",
+    "//zircon/system/ulib/service:service-llcpp",
+  ]
+}
diff --git a/src/tests/fidl/server_suite/harness/harness.cc b/src/tests/fidl/server_suite/harness/harness.cc
new file mode 100644
index 0000000..cff42c5
--- /dev/null
+++ b/src/tests/fidl/server_suite/harness/harness.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 "harness.h"
+
+#include <lib/service/llcpp/service.h>
+
+void Reporter::ReceivedOneWayNoPayload(ReceivedOneWayNoPayloadRequest& request,
+                                       ReceivedOneWayNoPayloadCompleter::Sync& completer) {
+  received_one_way_no_payload_ = true;
+}
+
+void ServerTest::SetUp() {
+  auto runner_service = service::Connect<fidl_serversuite::Runner>();
+  ASSERT_OK(runner_service.status_value());
+  runner_ = fidl::SyncClient<fidl_serversuite::Runner>(std::move(*runner_service));
+
+  // Ensure the process hasn't crashed from a previous iteration.
+  auto checkAliveResult = runner_->CheckAlive();
+  ASSERT_TRUE(checkAliveResult.is_ok()) << checkAliveResult.error_value();
+
+  // Create Reporter, which will allow the binding server to report test progress.
+  auto reporter_endpoints = fidl::CreateEndpoints<fidl_serversuite::Reporter>();
+  ASSERT_OK(reporter_endpoints.status_value());
+  fidl::BindServer(dispatcher(), std::move(reporter_endpoints->server), &reporter_,
+                   [](auto*, fidl::UnbindInfo info, auto) {
+                     ASSERT_TRUE(info.is_dispatcher_shutdown() || info.is_user_initiated() ||
+                                 info.is_peer_closed())
+                         << "server unbound with error: " << info.FormatDescription().c_str();
+                   });
+
+  // Create a Target on the test server, to run tests against.
+  auto startResult =
+      runner_->Start(fidl_serversuite::RunnerStartRequest(std::move(reporter_endpoints->client)));
+  ASSERT_TRUE(startResult.is_ok()) << startResult.error_value();
+  target_ = startResult->target().TakeHandle();
+  ASSERT_OK(target_.get_info(ZX_INFO_HANDLE_VALID, nullptr, 0, nullptr, nullptr));
+}
+
+void ServerTest::TearDown() {
+  // Close the Target channel so it will not continue waiting for requests.
+  target_.reset();
+
+  // Ensure the process hasn't crashed unexpectedly.
+  auto result = runner_->CheckAlive();
+  ASSERT_TRUE(result.is_ok()) << result.error_value();
+}
diff --git a/src/tests/fidl/server_suite/harness/harness.h b/src/tests/fidl/server_suite/harness/harness.h
new file mode 100644
index 0000000..80d147e
--- /dev/null
+++ b/src/tests/fidl/server_suite/harness/harness.h
@@ -0,0 +1,49 @@
+// 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_TESTS_FIDL_SERVER_SUITE_HARNESS_HARNESS_H_
+#define SRC_TESTS_FIDL_SERVER_SUITE_HARNESS_HARNESS_H_
+
+#include <fidl/fidl.serversuite/cpp/fidl.h>
+
+#include <gtest/gtest.h>
+
+#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
+
+#define WAIT_UNTIL(condition) ASSERT_TRUE(_wait_until(condition));
+#define ASSERT_OK(value) ASSERT_EQ(ZX_OK, value)
+
+class Reporter : public fidl::Server<fidl_serversuite::Reporter> {
+ public:
+  void ReceivedOneWayNoPayload(ReceivedOneWayNoPayloadRequest& request,
+                               ReceivedOneWayNoPayloadCompleter::Sync& completer) override;
+
+  bool received_one_way_no_payload() const { return received_one_way_no_payload_; }
+
+ private:
+  bool received_one_way_no_payload_ = false;
+};
+
+class ServerTest : private ::loop_fixture::RealLoop, public ::testing::Test {
+ protected:
+  void SetUp() override;
+  void TearDown() override;
+
+  const Reporter& reporter() { return reporter_; }
+  zx::channel& client_end() { return target_; }
+
+  bool _wait_until(fit::function<bool()> condition) {
+    constexpr zx::duration kTimeoutDuration = zx::sec(5);
+    return RunLoopWithTimeoutOrUntil(std::move(condition), kTimeoutDuration);
+  }
+
+ private:
+  fidl::SyncClient<fidl_serversuite::Runner> runner_;
+
+  zx::channel target_;
+
+  Reporter reporter_;
+};
+
+#endif  // SRC_TESTS_FIDL_SERVER_SUITE_HARNESS_HARNESS_H_
diff --git a/src/tests/fidl/server_suite/harness/ordinals.h b/src/tests/fidl/server_suite/harness/ordinals.h
new file mode 100644
index 0000000..43157e2
--- /dev/null
+++ b/src/tests/fidl/server_suite/harness/ordinals.h
@@ -0,0 +1,20 @@
+// 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_TESTS_FIDL_SERVER_SUITE_HARNESS_ORDINALS_H_
+#define SRC_TESTS_FIDL_SERVER_SUITE_HARNESS_ORDINALS_H_
+
+#include <cstdint>
+
+// To find all ordinals:
+//
+//     cat
+//     out/default/fidling/gen/src/tests/fidl/server_suite/fidl/fidl.serversuite/llcpp/fidl/fidl.serversuite/cpp/wire_messaging.cc
+//     | grep -e 'constexpr.*kTarget.*Ordinal' -A 1
+//
+// While using `jq` would be much nicer, large numbers are mishandled and the
+// displayed ordinal ends up being incorrect.
+static const uint64_t kOrdinalOneWayInteractionNoPayload = 5311082811961759320lu;
+
+#endif  // SRC_TESTS_FIDL_SERVER_SUITE_HARNESS_ORDINALS_H_
diff --git a/src/tests/fidl/server_suite/harness/tests.cc b/src/tests/fidl/server_suite/harness/tests.cc
new file mode 100644
index 0000000..a2c778c
--- /dev/null
+++ b/src/tests/fidl/server_suite/harness/tests.cc
@@ -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.
+
+#include "harness.h"
+#include "ordinals.h"
+
+TEST_F(ServerTest, TestSetUp_Success) {}
+
+TEST_F(ServerTest, OneWayInteraction_Success) {
+  fidl_message_header_t hdr;
+  fidl::InitTxnHeader(&hdr, 0, kOrdinalOneWayInteractionNoPayload,
+                      fidl::MessageDynamicFlags::kStrictMethod);
+  ASSERT_EQ(ZX_OK, client_end().write(0, &hdr, sizeof(fidl_message_header_t), nullptr, 0));
+
+  WAIT_UNTIL([this]() { return reporter().received_one_way_no_payload(); });
+}
+
+TEST_F(ServerTest, WrongOrdinalCausesUnbind_Success) {
+  fidl_message_header_t hdr;
+  fidl::InitTxnHeader(&hdr, 0, /* some wrong ordinal */ 8888888lu,
+                      fidl::MessageDynamicFlags::kStrictMethod);
+  ASSERT_EQ(ZX_OK, client_end().write(0, &hdr, sizeof(fidl_message_header_t), nullptr, 0));
+
+  ASSERT_EQ(ZX_OK,
+            client_end().wait_one(ZX_CHANNEL_PEER_CLOSED, zx::deadline_after(zx::sec(5)), nullptr));
+}
diff --git a/src/tests/fidl/server_suite/hlcpp/BUILD.gn b/src/tests/fidl/server_suite/hlcpp/BUILD.gn
new file mode 100644
index 0000000..d712d6c
--- /dev/null
+++ b/src/tests/fidl/server_suite/hlcpp/BUILD.gn
@@ -0,0 +1,40 @@
+# Copyright 2021 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/components.gni")
+
+executable("bin") {
+  output_name = "server_suite_under_test_hlcpp"
+  sources = [ "main.cc" ]
+  deps = [
+    "//sdk/lib/fidl/cpp",
+    "//sdk/lib/sys/cpp",
+    "//src/tests/fidl/server_suite/fidl:fidl.serversuite",
+    "//zircon/system/ulib/async-loop:async-loop-cpp",
+    "//zircon/system/ulib/async-loop:async-loop-default",
+  ]
+}
+
+fuchsia_component("hlcpp_server") {
+  component_name = "server"
+  manifest = "meta/server.cml"
+  deps = [ ":bin" ]
+}
+
+fuchsia_component("harness_hlcpp") {
+  testonly = true
+  component_name = "harness"
+  manifest = "meta/harness_hlcpp.cml"
+  deps = [ "//src/tests/fidl/server_suite/harness:bin" ]
+}
+
+fuchsia_test_package("fidl-server-suite-hlcpp-test") {
+  test_components = [ ":harness_hlcpp" ]
+  deps = [ ":hlcpp_server" ]
+}
+
+group("hlcpp") {
+  testonly = true
+  deps = [ ":fidl-server-suite-hlcpp-test" ]
+}
diff --git a/src/tests/fidl/server_suite/hlcpp/main.cc b/src/tests/fidl/server_suite/hlcpp/main.cc
new file mode 100644
index 0000000..3118940
--- /dev/null
+++ b/src/tests/fidl/server_suite/hlcpp/main.cc
@@ -0,0 +1,70 @@
+// 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 <fidl/serversuite/cpp/fidl.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/async-loop/default.h>
+#include <lib/async/cpp/task.h>
+#include <lib/async/default.h>
+#include <lib/fidl/cpp/binding.h>
+#include <lib/sys/cpp/component_context.h>
+#include <stdio.h>
+
+#include <iostream>
+
+class TargetServer : public fidl::serversuite::Target {
+ public:
+  explicit TargetServer(fidl::InterfacePtr<fidl::serversuite::Reporter> reporter)
+      : reporter_(std::move(reporter)) {}
+
+  void OneWayNoPayload() override {
+    std::cout << "Target.OneWayNoPayload()" << std::endl;
+    reporter_->ReceivedOneWayNoPayload();
+  }
+
+ private:
+  fidl::InterfacePtr<fidl::serversuite::Reporter> reporter_;
+};
+
+class RunnerServer : public fidl::serversuite::Runner {
+ public:
+  explicit RunnerServer(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher) {}
+
+  void Start(fidl::InterfaceHandle<fidl::serversuite::Reporter> reporter,
+             StartCallback callback) override {
+    target_server_ = std::make_unique<TargetServer>(reporter.Bind());
+    target_binding_ =
+        std::make_unique<fidl::Binding<fidl::serversuite::Target>>(target_server_.get());
+
+    zx::channel client_end, server_end;
+    ZX_ASSERT(ZX_OK == zx::channel::create(0, &client_end, &server_end));
+    target_binding_->Bind(fidl::InterfaceRequest<fidl::serversuite::Target>(std::move(server_end)),
+                          dispatcher_);
+    callback(fidl::InterfaceHandle<fidl::serversuite::Target>(std::move(client_end)));
+  }
+
+  void CheckAlive(CheckAliveCallback callback) override { return callback(); }
+
+ private:
+  async_dispatcher_t* dispatcher_;
+  std::unique_ptr<TargetServer> target_server_;
+  std::unique_ptr<fidl::Binding<fidl::serversuite::Target>> target_binding_;
+};
+
+int main(int argc, const char** argv) {
+  std::cout << "HLCPP server: main" << std::endl;
+  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
+
+  RunnerServer server(loop.dispatcher());
+  fidl::Binding<fidl::serversuite::Runner> binding(&server);
+  fidl::InterfaceRequestHandler<fidl::serversuite::Runner> handler =
+      [&](fidl::InterfaceRequest<fidl::serversuite::Runner> server_end) {
+        binding.Bind(std::move(server_end));
+      };
+  auto context = sys::ComponentContext::CreateAndServeOutgoingDirectory();
+  context->outgoing()->AddPublicService(std::move(handler));
+
+  std::cout << "HLCPP server: ready!" << std::endl;
+  return loop.Run();
+}
diff --git a/src/tests/fidl/server_suite/hlcpp/meta/harness_hlcpp.cml b/src/tests/fidl/server_suite/hlcpp/meta/harness_hlcpp.cml
new file mode 100644
index 0000000..aebf24a
--- /dev/null
+++ b/src/tests/fidl/server_suite/hlcpp/meta/harness_hlcpp.cml
@@ -0,0 +1,34 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        // gtest runner
+        "//src/sys/test_runners/gtest/default.shard.cml",
+
+        // Enable system logging
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/server_suite_harness",
+    },
+    children: [
+        {
+            name: "hlcpp",
+            url: "#meta/server.cm",
+        },
+    ],
+    use: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "#hlcpp",
+        },
+    ],
+    offer: [
+        {
+            protocol: [ "fuchsia.logger.LogSink" ],
+            from: "parent",
+            to: "#hlcpp",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/hlcpp/meta/server.cml b/src/tests/fidl/server_suite/hlcpp/meta/server.cml
new file mode 100644
index 0000000..d051755
--- /dev/null
+++ b/src/tests/fidl/server_suite/hlcpp/meta/server.cml
@@ -0,0 +1,22 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "syslog/client.shard.cml",
+        "syslog/elf_stdio.shard.cml",
+    ],
+    program: {
+        runner: "elf",
+        binary: "bin/server_suite_under_test_hlcpp",
+    },
+    capabilities: [
+        { protocol: "fidl.serversuite.Runner" },
+    ],
+    expose: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "self",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/llcpp/BUILD.gn b/src/tests/fidl/server_suite/llcpp/BUILD.gn
new file mode 100644
index 0000000..81151e3
--- /dev/null
+++ b/src/tests/fidl/server_suite/llcpp/BUILD.gn
@@ -0,0 +1,39 @@
+# 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")
+
+executable("bin") {
+  output_name = "server_suite_under_test_llcpp"
+  sources = [ "main.cc" ]
+  deps = [
+    "//sdk/lib/sys/component/llcpp",
+    "//src/tests/fidl/server_suite/fidl:fidl.serversuite_llcpp",
+    "//zircon/system/ulib/async-loop:async-loop-cpp",
+    "//zircon/system/ulib/async-loop:async-loop-default",
+  ]
+}
+
+fuchsia_component("llcpp_server") {
+  component_name = "server"
+  manifest = "meta/server.cml"
+  deps = [ ":bin" ]
+}
+
+fuchsia_component("harness_llcpp") {
+  testonly = true
+  component_name = "harness"
+  manifest = "meta/harness_llcpp.cml"
+  deps = [ "//src/tests/fidl/server_suite/harness:bin" ]
+}
+
+fuchsia_test_package("fidl-server-suite-llcpp-test") {
+  test_components = [ ":harness_llcpp" ]
+  deps = [ ":llcpp_server" ]
+}
+
+group("llcpp") {
+  testonly = true
+  deps = [ ":fidl-server-suite-llcpp-test" ]
+}
diff --git a/src/tests/fidl/server_suite/llcpp/main.cc b/src/tests/fidl/server_suite/llcpp/main.cc
new file mode 100644
index 0000000..fb16311
--- /dev/null
+++ b/src/tests/fidl/server_suite/llcpp/main.cc
@@ -0,0 +1,71 @@
+// 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 <fidl/fidl.serversuite/cpp/wire_messaging.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/async-loop/default.h>
+#include <lib/sys/component/llcpp/outgoing_directory.h>
+
+#include <iostream>
+
+class TargetServer : public fidl::WireServer<fidl_serversuite::Target> {
+ public:
+  explicit TargetServer(fidl::ClientEnd<fidl_serversuite::Reporter> reporter)
+      : reporter_(std::move(reporter)) {}
+
+  void OneWayNoPayload(OneWayNoPayloadRequestView request,
+                       OneWayNoPayloadCompleter::Sync& completer) override {
+    std::cout << "Target.OneWayNoPayload()" << std::endl;
+    auto result = reporter_->ReceivedOneWayNoPayload();
+    ZX_ASSERT(result.ok());
+  }
+
+ private:
+  fidl::WireSyncClient<fidl_serversuite::Reporter> reporter_;
+};
+
+class RunnerServer : public fidl::WireServer<fidl_serversuite::Runner> {
+ public:
+  explicit RunnerServer(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher) {}
+
+  void Start(StartRequestView request, StartCompleter::Sync& completer) override {
+    std::cout << "Runner.Start()" << std::endl;
+
+    target_server_ = std::make_unique<TargetServer>(std::move(request->reporter));
+
+    auto endpoints = fidl::CreateEndpoints<fidl_serversuite::Target>();
+    fidl::BindServer(dispatcher_, std::move(endpoints->server), target_server_.get(),
+                     [](auto*, fidl::UnbindInfo info, auto) {
+                       if (!info.is_dispatcher_shutdown() && !info.is_user_initiated() &&
+                           !info.is_peer_closed()) {
+                         std::cout << "Target unbound with error: " << info.FormatDescription()
+                                   << std::endl;
+                       }
+                     });
+
+    completer.Reply(std::move(endpoints->client));
+  }
+
+  void CheckAlive(CheckAliveRequestView request, CheckAliveCompleter::Sync& completer) override {
+    completer.Reply();
+  }
+
+ private:
+  async_dispatcher_t* dispatcher_;
+  std::unique_ptr<TargetServer> target_server_;
+};
+
+int main(int argc, const char** argv) {
+  std::cout << "LLCPP server: main" << std::endl;
+  async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
+
+  auto outgoing = component::OutgoingDirectory::Create(loop.dispatcher());
+  ZX_ASSERT(outgoing.ServeFromStartupInfo().is_ok());
+  RunnerServer runner_server(loop.dispatcher());
+  auto result = outgoing.AddProtocol<fidl_serversuite::Runner>(&runner_server);
+  ZX_ASSERT(result.is_ok());
+
+  std::cout << "LLCPP server: ready!" << std::endl;
+  return loop.Run();
+}
diff --git a/src/tests/fidl/server_suite/llcpp/meta/harness_llcpp.cml b/src/tests/fidl/server_suite/llcpp/meta/harness_llcpp.cml
new file mode 100644
index 0000000..0f381a0
--- /dev/null
+++ b/src/tests/fidl/server_suite/llcpp/meta/harness_llcpp.cml
@@ -0,0 +1,34 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        // gtest runner
+        "//src/sys/test_runners/gtest/default.shard.cml",
+
+        // Enable system logging
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/server_suite_harness",
+    },
+    children: [
+        {
+            name: "llcpp",
+            url: "#meta/server.cm",
+        },
+    ],
+    use: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "#llcpp",
+        },
+    ],
+    offer: [
+        {
+            protocol: [ "fuchsia.logger.LogSink" ],
+            from: "parent",
+            to: "#llcpp",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/llcpp/meta/server.cml b/src/tests/fidl/server_suite/llcpp/meta/server.cml
new file mode 100644
index 0000000..e4b992cd
--- /dev/null
+++ b/src/tests/fidl/server_suite/llcpp/meta/server.cml
@@ -0,0 +1,22 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "syslog/client.shard.cml",
+        "syslog/elf_stdio.shard.cml",
+    ],
+    program: {
+        runner: "elf",
+        binary: "bin/server_suite_under_test_llcpp",
+    },
+    capabilities: [
+        { protocol: "fidl.serversuite.Runner" },
+    ],
+    expose: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "self",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/rust/BUILD.gn b/src/tests/fidl/server_suite/rust/BUILD.gn
new file mode 100644
index 0000000..820ce7f
--- /dev/null
+++ b/src/tests/fidl/server_suite/rust/BUILD.gn
@@ -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.
+
+import("//build/components.gni")
+import("//build/rust/rustc_binary.gni")
+
+rustc_binary("server_suite_under_test_rust") {
+  output_name = "server_suite_under_test_rust"
+  sources = [ "src/main.rs" ]
+  edition = "2021"
+  deps = [
+    "//src/lib/fidl/rust/fidl",
+    "//src/lib/fuchsia",
+    "//src/lib/fuchsia-async",
+    "//src/lib/fuchsia-component",
+    "//src/tests/fidl/server_suite/fidl:fidl.serversuite-rustc",
+    "//third_party/rust_crates:anyhow",
+    "//third_party/rust_crates:futures",
+  ]
+}
+
+fuchsia_component("rust_server") {
+  component_name = "server"
+  manifest = "meta/server.cml"
+  deps = [ ":server_suite_under_test_rust" ]
+}
+
+fuchsia_component("harness_rust") {
+  testonly = true
+  component_name = "harness"
+  manifest = "meta/harness_rust.cml"
+  deps = [ "//src/tests/fidl/server_suite/harness:bin" ]
+}
+
+fuchsia_test_package("fidl-server-suite-rust-test") {
+  test_components = [ ":harness_rust" ]
+  deps = [ ":rust_server" ]
+}
+
+group("rust") {
+  testonly = true
+  deps = [ ":fidl-server-suite-rust-test" ]
+}
diff --git a/src/tests/fidl/server_suite/rust/meta/harness_rust.cml b/src/tests/fidl/server_suite/rust/meta/harness_rust.cml
new file mode 100644
index 0000000..85a84e6
--- /dev/null
+++ b/src/tests/fidl/server_suite/rust/meta/harness_rust.cml
@@ -0,0 +1,34 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        // gtest runner
+        "//src/sys/test_runners/gtest/default.shard.cml",
+
+        // Enable system logging
+        "syslog/client.shard.cml",
+    ],
+    program: {
+        binary: "bin/server_suite_harness",
+    },
+    children: [
+        {
+            name: "rust",
+            url: "#meta/server.cm",
+        },
+    ],
+    use: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "#rust",
+        },
+    ],
+    offer: [
+        {
+            protocol: [ "fuchsia.logger.LogSink" ],
+            from: "parent",
+            to: "#rust",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/rust/meta/server.cml b/src/tests/fidl/server_suite/rust/meta/server.cml
new file mode 100644
index 0000000..bfa39dd
--- /dev/null
+++ b/src/tests/fidl/server_suite/rust/meta/server.cml
@@ -0,0 +1,22 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+{
+    include: [
+        "syslog/client.shard.cml",
+        "syslog/elf_stdio.shard.cml",
+    ],
+    program: {
+        runner: "elf",
+        binary: "bin/server_suite_under_test_rust",
+    },
+    capabilities: [
+        { protocol: "fidl.serversuite.Runner" },
+    ],
+    expose: [
+        {
+            protocol: "fidl.serversuite.Runner",
+            from: "self",
+        },
+    ],
+}
diff --git a/src/tests/fidl/server_suite/rust/src/main.rs b/src/tests/fidl/server_suite/rust/src/main.rs
new file mode 100644
index 0000000..bfa5803
--- /dev/null
+++ b/src/tests/fidl/server_suite/rust/src/main.rs
@@ -0,0 +1,77 @@
+// Copyright 2022 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {
+    anyhow::{Context as _, Error},
+    fidl::endpoints::{create_endpoints, ServerEnd},
+    fidl_fidl_serversuite::{
+        ReporterProxy, RunnerRequest, RunnerRequestStream, TargetMarker, TargetRequest,
+    },
+    fuchsia_component::server::ServiceFs,
+    futures::prelude::*,
+};
+
+async fn run_target_server(
+    server_end: ServerEnd<TargetMarker>,
+    reporter_proxy: &ReporterProxy,
+) -> Result<(), Error> {
+    server_end
+        .into_stream()?
+        .map(|result| result.context("failed request"))
+        .try_for_each(|request| async move {
+            match request {
+                TargetRequest::OneWayNoPayload { control_handle: _ } => {
+                    println!("OneWayIteractionNoPayload");
+                    reporter_proxy
+                        .received_one_way_no_payload()
+                        .expect("calling received_one_way_no_payload failed");
+                }
+            }
+            Ok(())
+        })
+        .await
+}
+
+async fn run_runner_server(stream: RunnerRequestStream) -> Result<(), Error> {
+    stream
+        .map(|result| result.context("failed request"))
+        .try_for_each(|request| async move {
+            match request {
+                RunnerRequest::Start { reporter, responder } => {
+                    println!("Runner.Start() called");
+                    let reporter_proxy: &ReporterProxy = &reporter.into_proxy()?;
+                    let (client_end, server_end) = create_endpoints::<TargetMarker>()?;
+                    responder.send(client_end).expect("sending response failed");
+                    run_target_server(server_end, reporter_proxy)
+                        .await
+                        .unwrap_or_else(|e| println!("target server failed {:?}", e));
+                }
+                RunnerRequest::CheckAlive { responder } => {
+                    responder.send().expect("sending response failed");
+                }
+            }
+            Ok(())
+        })
+        .await
+}
+
+enum IncomingService {
+    Runner(RunnerRequestStream),
+}
+
+#[fuchsia::main]
+async fn main() -> Result<(), Error> {
+    let mut fs = ServiceFs::new();
+    fs.dir("svc").add_fidl_service(IncomingService::Runner);
+    fs.take_and_serve_directory_handle().expect("serving directory failed");
+
+    println!("Listening for incoming connections...");
+    const MAX_CONCURRENT: usize = 10_000;
+    fs.for_each_concurrent(MAX_CONCURRENT, |IncomingService::Runner(stream)| {
+        run_runner_server(stream).unwrap_or_else(|e| panic!("runner server failed {:?}", e))
+    })
+    .await;
+
+    Ok(())
+}